Merge git://git.samba.org/sfrench/cifs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 23 Jan 2012 16:59:49 +0000 (08:59 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 23 Jan 2012 16:59:49 +0000 (08:59 -0800)
* git://git.samba.org/sfrench/cifs-2.6:
  CIFS: Rename *UCS* functions to *UTF16*
  [CIFS] ACL and FSCACHE support no longer EXPERIMENTAL
  [CIFS] Fix build break with multiuser patch when LANMAN disabled
  cifs: warn about impending deprecation of legacy MultiuserMount code
  cifs: fetch credentials out of keyring for non-krb5 auth multiuser mounts
  cifs: sanitize username handling
  keys: add a "logon" key type
  cifs: lower default wsize when unix extensions are not used
  cifs: better instrumentation for coalesce_t2
  cifs: integer overflow in parse_dacl()
  cifs: Fix sparse warning when calling cifs_strtoUCS
  CIFS: Add descriptions to the brlock cache functions

2672 files changed:
CREDITS
Documentation/ABI/testing/sysfs-kernel-slab
Documentation/ABI/testing/sysfs-module
Documentation/DocBook/media/constraints.png.b64 [new file with mode: 0644]
Documentation/DocBook/media/dvb/dvbproperty.xml
Documentation/DocBook/media/dvb/frontend.xml
Documentation/DocBook/media/selection.png.b64 [new file with mode: 0644]
Documentation/DocBook/media/v4l/biblio.xml
Documentation/DocBook/media/v4l/common.xml
Documentation/DocBook/media/v4l/compat.xml
Documentation/DocBook/media/v4l/controls.xml
Documentation/DocBook/media/v4l/dev-capture.xml
Documentation/DocBook/media/v4l/dev-codec.xml
Documentation/DocBook/media/v4l/dev-effect.xml
Documentation/DocBook/media/v4l/dev-event.xml
Documentation/DocBook/media/v4l/dev-osd.xml
Documentation/DocBook/media/v4l/dev-output.xml
Documentation/DocBook/media/v4l/dev-overlay.xml
Documentation/DocBook/media/v4l/dev-radio.xml
Documentation/DocBook/media/v4l/dev-raw-vbi.xml
Documentation/DocBook/media/v4l/dev-rds.xml
Documentation/DocBook/media/v4l/dev-sliced-vbi.xml
Documentation/DocBook/media/v4l/dev-teletext.xml
Documentation/DocBook/media/v4l/driver.xml
Documentation/DocBook/media/v4l/func-close.xml
Documentation/DocBook/media/v4l/func-ioctl.xml
Documentation/DocBook/media/v4l/func-mmap.xml
Documentation/DocBook/media/v4l/func-munmap.xml
Documentation/DocBook/media/v4l/func-open.xml
Documentation/DocBook/media/v4l/func-poll.xml
Documentation/DocBook/media/v4l/func-read.xml
Documentation/DocBook/media/v4l/func-select.xml
Documentation/DocBook/media/v4l/func-write.xml
Documentation/DocBook/media/v4l/io.xml
Documentation/DocBook/media/v4l/libv4l.xml
Documentation/DocBook/media/v4l/pixfmt-grey.xml
Documentation/DocBook/media/v4l/pixfmt-m420.xml
Documentation/DocBook/media/v4l/pixfmt-nv12.xml
Documentation/DocBook/media/v4l/pixfmt-nv12m.xml
Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml
Documentation/DocBook/media/v4l/pixfmt-nv16.xml
Documentation/DocBook/media/v4l/pixfmt-nv24.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml
Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml
Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml
Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml
Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml
Documentation/DocBook/media/v4l/pixfmt-uyvy.xml
Documentation/DocBook/media/v4l/pixfmt-vyuy.xml
Documentation/DocBook/media/v4l/pixfmt-y16.xml
Documentation/DocBook/media/v4l/pixfmt-y41p.xml
Documentation/DocBook/media/v4l/pixfmt-yuv410.xml
Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml
Documentation/DocBook/media/v4l/pixfmt-yuv420.xml
Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml
Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml
Documentation/DocBook/media/v4l/pixfmt-yuyv.xml
Documentation/DocBook/media/v4l/pixfmt-yvyu.xml
Documentation/DocBook/media/v4l/pixfmt.xml
Documentation/DocBook/media/v4l/selection-api.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/v4l2.xml
Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml
Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml
Documentation/DocBook/media/v4l/vidioc-enuminput.xml
Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
Documentation/DocBook/media/v4l/vidioc-enumstd.xml
Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml
Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml
Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
Documentation/DocBook/media/v4l/vidioc-g-input.xml
Documentation/DocBook/media/v4l/vidioc-g-modulator.xml
Documentation/DocBook/media/v4l/vidioc-g-output.xml
Documentation/DocBook/media/v4l/vidioc-g-priority.xml
Documentation/DocBook/media/v4l/vidioc-g-selection.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-std.xml
Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
Documentation/DocBook/media/v4l/vidioc-querybuf.xml
Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
Documentation/acpi/apei/einj.txt
Documentation/cgroups/memory.txt
Documentation/coccinelle.txt
Documentation/devices.txt
Documentation/devicetree/bindings/dma/atmel-dma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/omap-i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/mc13xxx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/twl-familly.txt [new file with mode: 0644]
Documentation/devicetree/bindings/resource-names.txt [new file with mode: 0644]
Documentation/dma-buf-sharing.txt
Documentation/dmaengine.txt
Documentation/dvb/get_dvb_firmware
Documentation/fb/api.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/ceph.txt
Documentation/filesystems/nfs/00-INDEX
Documentation/filesystems/nfs/fault_injection.txt [new file with mode: 0644]
Documentation/filesystems/proc.txt
Documentation/filesystems/squashfs.txt
Documentation/hwmon/it87
Documentation/hwmon/lm63
Documentation/hwmon/sysfs-interface
Documentation/ioctl/ioctl-number.txt
Documentation/kbuild/makefiles.txt
Documentation/kernel-parameters.txt
Documentation/kmemleak.txt
Documentation/mmc/mmc-dev-attrs.txt
Documentation/mmc/mmc-dev-parts.txt
Documentation/scsi/ChangeLog.megaraid_sas
Documentation/scsi/LICENSE.qla4xxx
Documentation/sysctl/kernel.txt
Documentation/target/tcm_mod_builder.py
Documentation/video4linux/CARDLIST.au0828
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.saa7164
Documentation/video4linux/gspca.txt
Documentation/video4linux/v4l2-controls.txt
Documentation/video4linux/v4l2-framework.txt
Documentation/vm/slub.txt
MAINTAINERS
Makefile
arch/Kconfig
arch/arm/boot/Makefile
arch/arm/include/asm/gpio.h
arch/arm/include/asm/hwcap.h
arch/arm/include/asm/kprobes.h
arch/arm/include/asm/memblock.h
arch/arm/include/asm/ptrace.h
arch/arm/include/asm/swab.h
arch/arm/include/asm/thread_info.h
arch/arm/include/asm/unified.h
arch/arm/include/asm/unistd.h
arch/arm/kernel/entry-common.S
arch/arm/kernel/head.S
arch/arm/kernel/ptrace.c
arch/arm/mach-ep93xx/include/mach/dma.h
arch/arm/mach-exynos/headsmp.S
arch/arm/mach-exynos/mach-origen.c
arch/arm/mach-exynos/platsmp.c
arch/arm/mach-highbank/highbank.c
arch/arm/mach-imx/mach-mx31_3ds.c
arch/arm/mach-imx/mach-mx31moboard.c
arch/arm/mach-imx/mach-pcm037.c
arch/arm/mach-imx/src.c
arch/arm/mach-msm/headsmp.S
arch/arm/mach-msm/vreg.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-omap4panda.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/display.c
arch/arm/mach-omap2/omap-secure.c
arch/arm/mach-omap2/omap4-common.c
arch/arm/mach-picoxcell/time.c
arch/arm/mach-realview/platsmp.c
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-s3c64xx/include/mach/crag6410.h
arch/arm/mach-s3c64xx/mach-crag6410.c
arch/arm/mach-s3c64xx/pm.c
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/cerf.c
arch/arm/mach-sa1100/collie.c
arch/arm/mach-sa1100/generic.c
arch/arm/mach-sa1100/include/mach/gpio.h
arch/arm/mach-sa1100/include/mach/mcp.h
arch/arm/mach-sa1100/lart.c
arch/arm/mach-sa1100/shannon.c
arch/arm/mach-sa1100/simpad.c
arch/arm/mach-shmobile/board-ag5evm.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/clock-sh73a0.c
arch/arm/mach-shmobile/pm-sh7372.c
arch/arm/mach-shmobile/setup-sh7372.c
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/board-u5500.c
arch/arm/mach-ux500/headsmp.S
arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
arch/arm/mach-vexpress/platsmp.c
arch/arm/mach-w90x900/clksel.c
arch/arm/mach-w90x900/cpu.c
arch/arm/mach-w90x900/dev.c
arch/arm/mach-w90x900/mfp.c
arch/arm/mm/init.c
arch/arm/plat-mxc/include/mach/mx3fb.h
arch/arm/plat-nomadik/include/plat/ste_dma40.h
arch/arm/plat-omap/devices.c
arch/arm/plat-s3c24xx/cpu.c
arch/arm/plat-samsung/dma-ops.c
arch/arm/plat-samsung/include/plat/dma-ops.h
arch/arm/plat-samsung/include/plat/dma.h
arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
arch/arm/plat-samsung/include/plat/sdhci.h
arch/arm/plat-samsung/platformdata.c
arch/arm/plat-versatile/headsmp.S
arch/avr32/include/asm/system.h
arch/avr32/kernel/traps.c
arch/frv/include/asm/param.h
arch/ia64/hp/common/aml_nfw.c
arch/ia64/include/asm/intrinsics.h
arch/ia64/include/asm/processor.h
arch/ia64/include/asm/ptrace.h
arch/ia64/include/asm/unistd.h
arch/ia64/kernel/acpi.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/machine_kexec.c
arch/ia64/kernel/ptrace.c
arch/m32r/include/asm/param.h
arch/m68k/amiga/config.c
arch/microblaze/boot/Makefile
arch/microblaze/include/asm/ptrace.h
arch/microblaze/kernel/ptrace.c
arch/microblaze/kernel/setup.c
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/alchemy/Kconfig
arch/mips/alchemy/Makefile [new file with mode: 0644]
arch/mips/alchemy/Platform
arch/mips/alchemy/board-gpr.c [moved from arch/mips/alchemy/gpr/platform.c with 75% similarity]
arch/mips/alchemy/board-mtx1.c [moved from arch/mips/alchemy/mtx-1/platform.c with 71% similarity]
arch/mips/alchemy/board-xxs1500.c [new file with mode: 0644]
arch/mips/alchemy/common/Makefile
arch/mips/alchemy/common/dbdma.c
arch/mips/alchemy/common/gpiolib.c
arch/mips/alchemy/common/irq.c
arch/mips/alchemy/common/platform.c
arch/mips/alchemy/common/power.c
arch/mips/alchemy/common/sleeper.S
arch/mips/alchemy/common/time.c
arch/mips/alchemy/common/vss.c [new file with mode: 0644]
arch/mips/alchemy/devboards/Makefile
arch/mips/alchemy/devboards/bcsr.c
arch/mips/alchemy/devboards/db1000.c [new file with mode: 0644]
arch/mips/alchemy/devboards/db1200.c [moved from arch/mips/alchemy/devboards/db1200/platform.c with 62% similarity]
arch/mips/alchemy/devboards/db1200/Makefile [deleted file]
arch/mips/alchemy/devboards/db1200/setup.c [deleted file]
arch/mips/alchemy/devboards/db1300.c [new file with mode: 0644]
arch/mips/alchemy/devboards/db1550.c [new file with mode: 0644]
arch/mips/alchemy/devboards/db1x00/Makefile [deleted file]
arch/mips/alchemy/devboards/db1x00/board_setup.c [deleted file]
arch/mips/alchemy/devboards/db1x00/platform.c [deleted file]
arch/mips/alchemy/devboards/pb1000/Makefile [deleted file]
arch/mips/alchemy/devboards/pb1000/board_setup.c [deleted file]
arch/mips/alchemy/devboards/pb1100.c [moved from arch/mips/alchemy/devboards/pb1100/board_setup.c with 55% similarity]
arch/mips/alchemy/devboards/pb1100/Makefile [deleted file]
arch/mips/alchemy/devboards/pb1100/platform.c [deleted file]
arch/mips/alchemy/devboards/pb1200/Makefile [deleted file]
arch/mips/alchemy/devboards/pb1200/board_setup.c [deleted file]
arch/mips/alchemy/devboards/pb1200/platform.c [deleted file]
arch/mips/alchemy/devboards/pb1500.c [moved from arch/mips/alchemy/devboards/pb1500/board_setup.c with 51% similarity]
arch/mips/alchemy/devboards/pb1500/Makefile [deleted file]
arch/mips/alchemy/devboards/pb1500/platform.c [deleted file]
arch/mips/alchemy/devboards/pb1550.c [moved from arch/mips/alchemy/devboards/pb1550/platform.c with 61% similarity]
arch/mips/alchemy/devboards/pb1550/Makefile [deleted file]
arch/mips/alchemy/devboards/pb1550/board_setup.c [deleted file]
arch/mips/alchemy/devboards/platform.c
arch/mips/alchemy/devboards/prom.c
arch/mips/alchemy/gpr/Makefile [deleted file]
arch/mips/alchemy/gpr/board_setup.c [deleted file]
arch/mips/alchemy/gpr/init.c [deleted file]
arch/mips/alchemy/mtx-1/Makefile [deleted file]
arch/mips/alchemy/mtx-1/board_setup.c [deleted file]
arch/mips/alchemy/mtx-1/init.c [deleted file]
arch/mips/alchemy/xxs1500/Makefile [deleted file]
arch/mips/alchemy/xxs1500/board_setup.c [deleted file]
arch/mips/alchemy/xxs1500/init.c [deleted file]
arch/mips/alchemy/xxs1500/platform.c [deleted file]
arch/mips/ar7/gpio.c
arch/mips/ar7/platform.c
arch/mips/ar7/prom.c
arch/mips/ar7/setup.c
arch/mips/ath79/Kconfig
arch/mips/ath79/Makefile
arch/mips/ath79/clock.c
arch/mips/ath79/common.c
arch/mips/ath79/dev-ar913x-wmac.c [deleted file]
arch/mips/ath79/dev-common.c
arch/mips/ath79/dev-usb.c [new file with mode: 0644]
arch/mips/ath79/dev-usb.h [moved from arch/mips/ath79/dev-ar913x-wmac.h with 61% similarity]
arch/mips/ath79/dev-wmac.c [new file with mode: 0644]
arch/mips/ath79/dev-wmac.h [new file with mode: 0644]
arch/mips/ath79/early_printk.c
arch/mips/ath79/gpio.c
arch/mips/ath79/irq.c
arch/mips/ath79/mach-ap121.c [new file with mode: 0644]
arch/mips/ath79/mach-ap81.c
arch/mips/ath79/mach-pb44.c
arch/mips/ath79/mach-ubnt-xm.c [new file with mode: 0644]
arch/mips/ath79/machtypes.h
arch/mips/ath79/setup.c
arch/mips/bcm47xx/setup.c
arch/mips/bcm63xx/Kconfig
arch/mips/bcm63xx/boards/board_bcm963xx.c
arch/mips/bcm63xx/clk.c
arch/mips/bcm63xx/cpu.c
arch/mips/bcm63xx/dev-uart.c
arch/mips/bcm63xx/gpio.c
arch/mips/bcm63xx/irq.c
arch/mips/bcm63xx/prom.c
arch/mips/bcm63xx/setup.c
arch/mips/boot/compressed/uart-alchemy.c
arch/mips/cavium-octeon/Kconfig
arch/mips/cavium-octeon/dma-octeon.c
arch/mips/cavium-octeon/executive/Makefile
arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c [moved from drivers/staging/octeon/cvmx-cmd-queue.c with 98% similarity]
arch/mips/cavium-octeon/executive/cvmx-fpa.c [moved from drivers/staging/octeon/cvmx-fpa.c with 100% similarity]
arch/mips/cavium-octeon/executive/cvmx-helper-board.c [moved from drivers/staging/octeon/cvmx-helper-board.c with 96% similarity]
arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c [moved from drivers/staging/octeon/cvmx-helper-fpa.c with 100% similarity]
arch/mips/cavium-octeon/executive/cvmx-helper-loop.c [moved from drivers/staging/octeon/cvmx-helper-loop.c with 95% similarity]
arch/mips/cavium-octeon/executive/cvmx-helper-npi.c [moved from drivers/staging/octeon/cvmx-helper-npi.c with 96% similarity]
arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c [moved from drivers/staging/octeon/cvmx-helper-rgmii.c with 97% similarity]
arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c [moved from drivers/staging/octeon/cvmx-helper-sgmii.c with 98% similarity]
arch/mips/cavium-octeon/executive/cvmx-helper-spi.c [moved from drivers/staging/octeon/cvmx-helper-spi.c with 94% similarity]
arch/mips/cavium-octeon/executive/cvmx-helper-util.c [moved from drivers/staging/octeon/cvmx-helper-util.c with 97% similarity]
arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c [moved from drivers/staging/octeon/cvmx-helper-xaui.c with 97% similarity]
arch/mips/cavium-octeon/executive/cvmx-helper.c [moved from drivers/staging/octeon/cvmx-helper.c with 93% similarity]
arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c [moved from drivers/staging/octeon/cvmx-interrupt-decodes.c with 98% similarity]
arch/mips/cavium-octeon/executive/cvmx-interrupt-rsl.c [moved from drivers/staging/octeon/cvmx-interrupt-rsl.c with 97% similarity]
arch/mips/cavium-octeon/executive/cvmx-pko.c [moved from drivers/staging/octeon/cvmx-pko.c with 98% similarity]
arch/mips/cavium-octeon/executive/cvmx-spi.c [moved from drivers/staging/octeon/cvmx-spi.c with 99% similarity]
arch/mips/cavium-octeon/executive/octeon-model.c
arch/mips/cavium-octeon/setup.c
arch/mips/cavium-octeon/smp.c
arch/mips/configs/db1000_defconfig
arch/mips/configs/db1100_defconfig [deleted file]
arch/mips/configs/db1300_defconfig [new file with mode: 0644]
arch/mips/configs/db1500_defconfig [deleted file]
arch/mips/configs/db1550_defconfig
arch/mips/configs/nlm_xlp_defconfig [new file with mode: 0644]
arch/mips/configs/nlm_xlr_defconfig
arch/mips/configs/pb1200_defconfig [deleted file]
arch/mips/dec/setup.c
arch/mips/include/asm/Kbuild
arch/mips/include/asm/bmips.h [new file with mode: 0644]
arch/mips/include/asm/bootinfo.h
arch/mips/include/asm/branch.h
arch/mips/include/asm/cpu.h
arch/mips/include/asm/gio_device.h [new file with mode: 0644]
arch/mips/include/asm/hazards.h
arch/mips/include/asm/hugetlb.h
arch/mips/include/asm/kprobes.h
arch/mips/include/asm/mach-ath79/ar71xx_regs.h
arch/mips/include/asm/mach-ath79/ar933x_uart.h [new file with mode: 0644]
arch/mips/include/asm/mach-ath79/ar933x_uart_platform.h [new file with mode: 0644]
arch/mips/include/asm/mach-ath79/ath79.h
arch/mips/include/asm/mach-ath79/irq.h
arch/mips/include/asm/mach-ath79/pci-ath724x.h [new file with mode: 0644]
arch/mips/include/asm/mach-au1x00/au1000.h
arch/mips/include/asm/mach-au1x00/au1100_mmc.h
arch/mips/include/asm/mach-au1x00/au1200fb.h [new file with mode: 0644]
arch/mips/include/asm/mach-au1x00/au1550nd.h [new file with mode: 0644]
arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
arch/mips/include/asm/mach-au1x00/cpu-feature-overrides.h
arch/mips/include/asm/mach-au1x00/gpio-au1300.h [new file with mode: 0644]
arch/mips/include/asm/mach-au1x00/gpio.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_irq.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
arch/mips/include/asm/mach-bcm63xx/ioremap.h [new file with mode: 0644]
arch/mips/include/asm/mach-bcm63xx/irq.h [new file with mode: 0644]
arch/mips/include/asm/mach-db1x00/bcsr.h
arch/mips/include/asm/mach-db1x00/db1200.h
arch/mips/include/asm/mach-db1x00/db1300.h [new file with mode: 0644]
arch/mips/include/asm/mach-db1x00/db1x00.h [deleted file]
arch/mips/include/asm/mach-db1x00/irq.h [new file with mode: 0644]
arch/mips/include/asm/mach-generic/floppy.h
arch/mips/include/asm/mach-jazz/floppy.h
arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h
arch/mips/include/asm/mach-pb1x00/mc146818rtc.h [deleted file]
arch/mips/include/asm/mach-pb1x00/pb1000.h [deleted file]
arch/mips/include/asm/mach-pb1x00/pb1200.h [deleted file]
arch/mips/include/asm/mach-pb1x00/pb1550.h [deleted file]
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/module.h
arch/mips/include/asm/netlogic/common.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/haldefs.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlp-hal/bridge.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlp-hal/iomap.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlp-hal/pic.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlp-hal/sys.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlp-hal/uart.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlp-hal/xlp.h [moved from arch/mips/netlogic/xlr/xlr_console.c with 82% similarity]
arch/mips/include/asm/netlogic/xlr/iomap.h
arch/mips/include/asm/netlogic/xlr/msidef.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlr/pic.h
arch/mips/include/asm/netlogic/xlr/xlr.h
arch/mips/include/asm/octeon/cvmx-address.h [moved from drivers/staging/octeon/cvmx-address.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-asxx-defs.h [moved from drivers/staging/octeon/cvmx-asxx-defs.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-bootinfo.h
arch/mips/include/asm/octeon/cvmx-cmd-queue.h [moved from drivers/staging/octeon/cvmx-cmd-queue.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-config.h [moved from drivers/staging/octeon/cvmx-config.h with 99% similarity]
arch/mips/include/asm/octeon/cvmx-dbg-defs.h [moved from drivers/staging/octeon/cvmx-dbg-defs.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-dpi-defs.h [new file with mode: 0644]
arch/mips/include/asm/octeon/cvmx-fau.h [moved from drivers/staging/octeon/cvmx-fau.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-fpa-defs.h [moved from drivers/staging/octeon/cvmx-fpa-defs.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-fpa.h [moved from drivers/staging/octeon/cvmx-fpa.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-gmxx-defs.h [moved from drivers/staging/octeon/cvmx-gmxx-defs.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-helper-board.h [moved from drivers/staging/octeon/cvmx-helper-board.h with 96% similarity]
arch/mips/include/asm/octeon/cvmx-helper-fpa.h [moved from drivers/staging/octeon/cvmx-helper-fpa.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-helper-loop.h [moved from drivers/staging/octeon/cvmx-helper-loop.h with 96% similarity]
arch/mips/include/asm/octeon/cvmx-helper-npi.h [moved from drivers/staging/octeon/cvmx-helper-npi.h with 96% similarity]
arch/mips/include/asm/octeon/cvmx-helper-rgmii.h [moved from drivers/staging/octeon/cvmx-helper-rgmii.h with 98% similarity]
arch/mips/include/asm/octeon/cvmx-helper-sgmii.h [moved from drivers/staging/octeon/cvmx-helper-sgmii.h with 98% similarity]
arch/mips/include/asm/octeon/cvmx-helper-spi.h [moved from drivers/staging/octeon/cvmx-helper-spi.h with 98% similarity]
arch/mips/include/asm/octeon/cvmx-helper-util.h [moved from drivers/staging/octeon/cvmx-helper-util.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-helper-xaui.h [moved from drivers/staging/octeon/cvmx-helper-xaui.h with 98% similarity]
arch/mips/include/asm/octeon/cvmx-helper.h [moved from drivers/staging/octeon/cvmx-helper.h with 99% similarity]
arch/mips/include/asm/octeon/cvmx-ipd.h [moved from drivers/staging/octeon/cvmx-ipd.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-mdio.h [moved from drivers/staging/octeon/cvmx-mdio.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-mio-defs.h
arch/mips/include/asm/octeon/cvmx-npei-defs.h
arch/mips/include/asm/octeon/cvmx-pciercx-defs.h
arch/mips/include/asm/octeon/cvmx-pcsx-defs.h [moved from drivers/staging/octeon/cvmx-pcsx-defs.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-pcsxx-defs.h [moved from drivers/staging/octeon/cvmx-pcsxx-defs.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-pemx-defs.h [new file with mode: 0644]
arch/mips/include/asm/octeon/cvmx-pexp-defs.h
arch/mips/include/asm/octeon/cvmx-pip-defs.h [moved from drivers/staging/octeon/cvmx-pip-defs.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-pip.h [moved from drivers/staging/octeon/cvmx-pip.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-pko-defs.h [moved from drivers/staging/octeon/cvmx-pko-defs.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-pko.h [moved from drivers/staging/octeon/cvmx-pko.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-pow.h [moved from drivers/staging/octeon/cvmx-pow.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-scratch.h [moved from drivers/staging/octeon/cvmx-scratch.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-sli-defs.h [new file with mode: 0644]
arch/mips/include/asm/octeon/cvmx-spi.h [moved from drivers/staging/octeon/cvmx-spi.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-spxx-defs.h [moved from drivers/staging/octeon/cvmx-spxx-defs.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-sriox-defs.h [new file with mode: 0644]
arch/mips/include/asm/octeon/cvmx-srxx-defs.h [moved from drivers/staging/octeon/cvmx-srxx-defs.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-stxx-defs.h [moved from drivers/staging/octeon/cvmx-stxx-defs.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx-wqe.h [moved from drivers/staging/octeon/cvmx-wqe.h with 100% similarity]
arch/mips/include/asm/octeon/cvmx.h
arch/mips/include/asm/octeon/octeon-feature.h
arch/mips/include/asm/octeon/octeon-model.h
arch/mips/include/asm/octeon/pci-octeon.h
arch/mips/include/asm/page.h
arch/mips/include/asm/pgtable-32.h
arch/mips/include/asm/ptrace.h
arch/mips/include/asm/tlbmisc.h [new file with mode: 0644]
arch/mips/include/asm/traps.h
arch/mips/include/asm/types.h
arch/mips/jazz/irq.c
arch/mips/jazz/setup.c
arch/mips/jz4740/board-qi_lb60.c
arch/mips/kernel/Makefile
arch/mips/kernel/bmips_vec.S [new file with mode: 0644]
arch/mips/kernel/branch.c
arch/mips/kernel/cevt-bcm1480.c
arch/mips/kernel/cevt-ds1287.c
arch/mips/kernel/cevt-gt641xx.c
arch/mips/kernel/cevt-r4k.c
arch/mips/kernel/cevt-sb1250.c
arch/mips/kernel/cevt-txx9.c
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/i8253.c
arch/mips/kernel/kprobes.c
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/rtlx.c
arch/mips/kernel/setup.c
arch/mips/kernel/smp-bmips.c [new file with mode: 0644]
arch/mips/kernel/smtc.c
arch/mips/kernel/traps.c
arch/mips/lantiq/clk.c
arch/mips/lantiq/irq.c
arch/mips/lantiq/xway/dma.c
arch/mips/lantiq/xway/ebu.c
arch/mips/lantiq/xway/pmu.c
arch/mips/lantiq/xway/reset.c
arch/mips/lib/Makefile
arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
arch/mips/math-emu/cp1emu.c
arch/mips/mm/Makefile
arch/mips/mm/c-octeon.c
arch/mips/mm/c-r4k.c
arch/mips/mm/gup.c [new file with mode: 0644]
arch/mips/mm/init.c
arch/mips/mm/tlb-r3k.c
arch/mips/mm/tlb-r4k.c
arch/mips/mti-malta/malta-int.c
arch/mips/netlogic/Kconfig
arch/mips/netlogic/Makefile [new file with mode: 0644]
arch/mips/netlogic/Platform
arch/mips/netlogic/common/Makefile [new file with mode: 0644]
arch/mips/netlogic/common/earlycons.c [new file with mode: 0644]
arch/mips/netlogic/common/irq.c [new file with mode: 0644]
arch/mips/netlogic/common/smp.c [moved from arch/mips/netlogic/xlr/smp.c with 65% similarity]
arch/mips/netlogic/common/smpboot.S [new file with mode: 0644]
arch/mips/netlogic/common/time.c [moved from arch/mips/netlogic/xlr/time.c with 93% similarity]
arch/mips/netlogic/xlp/Makefile [new file with mode: 0644]
arch/mips/netlogic/xlp/nlm_hal.c [new file with mode: 0644]
arch/mips/netlogic/xlp/platform.c [new file with mode: 0644]
arch/mips/netlogic/xlp/setup.c [new file with mode: 0644]
arch/mips/netlogic/xlp/wakeup.c [new file with mode: 0644]
arch/mips/netlogic/xlr/Makefile
arch/mips/netlogic/xlr/irq.c [deleted file]
arch/mips/netlogic/xlr/platform.c
arch/mips/netlogic/xlr/setup.c
arch/mips/netlogic/xlr/wakeup.c [moved from arch/mips/netlogic/xlr/smpboot.S with 60% similarity]
arch/mips/pci/Makefile
arch/mips/pci/msi-octeon.c
arch/mips/pci/ops-pmcmsp.c
arch/mips/pci/ops-tx3927.c
arch/mips/pci/pci-alchemy.c
arch/mips/pci/pci-ath724x.c [new file with mode: 0644]
arch/mips/pci/pci-bcm63xx.c
arch/mips/pci/pci-octeon.c
arch/mips/pci/pci-tx4927.c
arch/mips/pci/pci-tx4938.c
arch/mips/pci/pci-tx4939.c
arch/mips/pci/pci-xlr.c
arch/mips/pci/pci.c
arch/mips/pci/pcie-octeon.c
arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c
arch/mips/pmc-sierra/msp71xx/msp_setup.c
arch/mips/pmc-sierra/msp71xx/msp_smp.c
arch/mips/pnx8550/common/int.c
arch/mips/pnx8550/common/time.c
arch/mips/sgi-ip22/Makefile
arch/mips/sgi-ip22/ip22-gio.c [new file with mode: 0644]
arch/mips/sgi-ip22/ip22-int.c
arch/mips/sgi-ip22/ip22-mc.c
arch/mips/sgi-ip22/ip22-setup.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sgi-ip27/ip27-timer.c
arch/mips/sgi-ip32/ip32-irq.c
arch/mips/sni/irq.c
arch/mips/sni/time.c
arch/mips/txx9/generic/pci.c
arch/mn10300/include/asm/exceptions.h
arch/mn10300/include/asm/param.h
arch/openrisc/boot/Makefile
arch/parisc/include/asm/processor.h
arch/parisc/kernel/process.c
arch/powerpc/boot/Makefile
arch/powerpc/include/asm/ptrace.h
arch/powerpc/kernel/idle.c
arch/powerpc/kernel/machine_kexec_32.c
arch/powerpc/kernel/machine_kexec_64.c
arch/powerpc/kernel/ptrace.c
arch/powerpc/mm/numa.c
arch/powerpc/platforms/pseries/hvCall.S
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/nvram.c
arch/s390/include/asm/chpid.h
arch/s390/include/asm/itcw.h
arch/s390/include/asm/mman.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/ptrace.h
arch/s390/kernel/nmi.c
arch/s390/kernel/ptrace.c
arch/sh/boards/mach-ap325rxa/setup.c
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/boards/mach-kfr2r09/setup.c
arch/sh/boards/mach-migor/setup.c
arch/sh/boards/mach-se/7724/setup.c
arch/sh/include/asm/ptrace_32.h
arch/sh/include/asm/ptrace_64.h
arch/sh/kernel/process_32.c
arch/sh/kernel/process_64.c
arch/sh/kernel/ptrace_32.c
arch/sh/kernel/ptrace_64.c
arch/sparc/include/asm/ptrace.h
arch/sparc/include/asm/siginfo.h
arch/sparc/kernel/ptrace_64.c
arch/tile/include/asm/signal.h
arch/tile/kernel/machine_kexec.c
arch/um/Makefile
arch/um/kernel/ptrace.c
arch/x86/.gitignore
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/Makefile
arch/x86/ia32/Makefile
arch/x86/ia32/ia32entry.S
arch/x86/ia32/nosyscall.c [new file with mode: 0644]
arch/x86/ia32/syscall_ia32.c [new file with mode: 0644]
arch/x86/include/asm/Kbuild
arch/x86/include/asm/atomic64_32.h
arch/x86/include/asm/debugreg.h
arch/x86/include/asm/desc.h
arch/x86/include/asm/ia32_unistd.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/syscall.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/unistd.h
arch/x86/include/asm/unistd_32.h [deleted file]
arch/x86/include/asm/unistd_64.h [deleted file]
arch/x86/include/asm/uv/uv_bau.h
arch/x86/kernel/Makefile
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/asm-offsets_64.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mcheck/mce_amd.c
arch/x86/kernel/e820.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/head_64.S
arch/x86/kernel/nmi.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/syscall_32.c [new file with mode: 0644]
arch/x86/kernel/syscall_64.c
arch/x86/kernel/syscall_table_32.S [deleted file]
arch/x86/kernel/traps.c
arch/x86/kernel/tsc.c
arch/x86/kernel/vm86_32.c
arch/x86/kvm/mmu.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/lguest/boot.c
arch/x86/lib/x86-opcode-map.txt
arch/x86/mm/mmio-mod.c
arch/x86/mm/numa.c
arch/x86/mm/srat.c
arch/x86/platform/geode/alix.c
arch/x86/platform/iris/iris.c
arch/x86/platform/uv/tlb_uv.c
arch/x86/syscalls/Makefile [new file with mode: 0644]
arch/x86/syscalls/syscall_32.tbl [new file with mode: 0644]
arch/x86/syscalls/syscall_64.tbl [new file with mode: 0644]
arch/x86/syscalls/syscallhdr.sh [new file with mode: 0644]
arch/x86/syscalls/syscalltbl.sh [new file with mode: 0644]
arch/x86/um/Kconfig
arch/x86/um/Makefile
arch/x86/um/shared/sysdep/ptrace.h
arch/x86/um/sys_call_table_32.S [deleted file]
arch/x86/um/sys_call_table_32.c [new file with mode: 0644]
arch/x86/um/sys_call_table_64.c
arch/x86/um/user-offsets.c
arch/xtensa/kernel/ptrace.c
block/blk-cgroup.c
block/blk-core.c
block/blk-exec.c
block/blk-ioc.c
block/blk-settings.c
block/blk-sysfs.c
block/blk-throttle.c
block/blk.h
block/bsg.c
block/cfq-iosched.c
block/compat_ioctl.c
block/deadline-iosched.c
block/elevator.c
block/genhd.c
block/ioctl.c
block/noop-iosched.c
block/scsi_ioctl.c
crypto/crypto_user.c
drivers/Makefile
drivers/accessibility/braille/braille_console.c
drivers/acpi/Makefile
drivers/acpi/acpica/Makefile
drivers/acpi/acpica/accommon.h
drivers/acpi/acpica/acconfig.h
drivers/acpi/acpica/acdebug.h
drivers/acpi/acpica/acdispat.h
drivers/acpi/acpica/acevents.h
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/acinterp.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/acmacros.h
drivers/acpi/acpica/acnamesp.h
drivers/acpi/acpica/acobject.h
drivers/acpi/acpica/acopcode.h
drivers/acpi/acpica/acparser.h
drivers/acpi/acpica/acpredef.h
drivers/acpi/acpica/acresrc.h
drivers/acpi/acpica/acstruct.h
drivers/acpi/acpica/actables.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/amlcode.h
drivers/acpi/acpica/amlresrc.h
drivers/acpi/acpica/dsargs.c
drivers/acpi/acpica/dscontrol.c
drivers/acpi/acpica/dsfield.c
drivers/acpi/acpica/dsinit.c
drivers/acpi/acpica/dsmethod.c
drivers/acpi/acpica/dsmthdat.c
drivers/acpi/acpica/dsobject.c
drivers/acpi/acpica/dsopcode.c
drivers/acpi/acpica/dsutils.c
drivers/acpi/acpica/dswexec.c
drivers/acpi/acpica/dswload.c
drivers/acpi/acpica/dswload2.c
drivers/acpi/acpica/dswscope.c
drivers/acpi/acpica/dswstate.c
drivers/acpi/acpica/evevent.c
drivers/acpi/acpica/evglock.c
drivers/acpi/acpica/evgpe.c
drivers/acpi/acpica/evgpeblk.c
drivers/acpi/acpica/evgpeinit.c
drivers/acpi/acpica/evgpeutil.c
drivers/acpi/acpica/evmisc.c
drivers/acpi/acpica/evregion.c
drivers/acpi/acpica/evrgnini.c
drivers/acpi/acpica/evsci.c
drivers/acpi/acpica/evxface.c
drivers/acpi/acpica/evxfevnt.c
drivers/acpi/acpica/evxfgpe.c
drivers/acpi/acpica/evxfregn.c
drivers/acpi/acpica/exconfig.c
drivers/acpi/acpica/exconvrt.c
drivers/acpi/acpica/excreate.c
drivers/acpi/acpica/exdebug.c
drivers/acpi/acpica/exdump.c
drivers/acpi/acpica/exfield.c
drivers/acpi/acpica/exfldio.c
drivers/acpi/acpica/exmisc.c
drivers/acpi/acpica/exmutex.c
drivers/acpi/acpica/exnames.c
drivers/acpi/acpica/exoparg1.c
drivers/acpi/acpica/exoparg2.c
drivers/acpi/acpica/exoparg3.c
drivers/acpi/acpica/exoparg6.c
drivers/acpi/acpica/exprep.c
drivers/acpi/acpica/exregion.c
drivers/acpi/acpica/exresnte.c
drivers/acpi/acpica/exresolv.c
drivers/acpi/acpica/exresop.c
drivers/acpi/acpica/exstore.c
drivers/acpi/acpica/exstoren.c
drivers/acpi/acpica/exstorob.c
drivers/acpi/acpica/exsystem.c
drivers/acpi/acpica/exutils.c
drivers/acpi/acpica/hwacpi.c
drivers/acpi/acpica/hwgpe.c
drivers/acpi/acpica/hwpci.c
drivers/acpi/acpica/hwregs.c
drivers/acpi/acpica/hwsleep.c
drivers/acpi/acpica/hwtimer.c
drivers/acpi/acpica/hwvalid.c
drivers/acpi/acpica/hwxface.c
drivers/acpi/acpica/nsaccess.c
drivers/acpi/acpica/nsalloc.c
drivers/acpi/acpica/nsdump.c
drivers/acpi/acpica/nsdumpdv.c
drivers/acpi/acpica/nseval.c
drivers/acpi/acpica/nsinit.c
drivers/acpi/acpica/nsload.c
drivers/acpi/acpica/nsnames.c
drivers/acpi/acpica/nsobject.c
drivers/acpi/acpica/nsparse.c
drivers/acpi/acpica/nspredef.c
drivers/acpi/acpica/nsrepair.c
drivers/acpi/acpica/nsrepair2.c
drivers/acpi/acpica/nssearch.c
drivers/acpi/acpica/nsutils.c
drivers/acpi/acpica/nswalk.c
drivers/acpi/acpica/nsxfeval.c
drivers/acpi/acpica/nsxfname.c
drivers/acpi/acpica/nsxfobj.c
drivers/acpi/acpica/psargs.c
drivers/acpi/acpica/psloop.c
drivers/acpi/acpica/psopcode.c
drivers/acpi/acpica/psparse.c
drivers/acpi/acpica/psscope.c
drivers/acpi/acpica/pstree.c
drivers/acpi/acpica/psutils.c
drivers/acpi/acpica/pswalk.c
drivers/acpi/acpica/psxface.c
drivers/acpi/acpica/rsaddr.c
drivers/acpi/acpica/rscalc.c
drivers/acpi/acpica/rscreate.c
drivers/acpi/acpica/rsdump.c
drivers/acpi/acpica/rsinfo.c
drivers/acpi/acpica/rsio.c
drivers/acpi/acpica/rsirq.c
drivers/acpi/acpica/rslist.c
drivers/acpi/acpica/rsmemory.c
drivers/acpi/acpica/rsmisc.c
drivers/acpi/acpica/rsserial.c [new file with mode: 0644]
drivers/acpi/acpica/rsutils.c
drivers/acpi/acpica/rsxface.c
drivers/acpi/acpica/tbfadt.c
drivers/acpi/acpica/tbfind.c
drivers/acpi/acpica/tbinstal.c
drivers/acpi/acpica/tbutils.c
drivers/acpi/acpica/tbxface.c
drivers/acpi/acpica/tbxfroot.c
drivers/acpi/acpica/utaddress.c [new file with mode: 0644]
drivers/acpi/acpica/utalloc.c
drivers/acpi/acpica/utcopy.c
drivers/acpi/acpica/utdebug.c
drivers/acpi/acpica/utdecode.c
drivers/acpi/acpica/utdelete.c
drivers/acpi/acpica/uteval.c
drivers/acpi/acpica/utglobal.c
drivers/acpi/acpica/utids.c
drivers/acpi/acpica/utinit.c
drivers/acpi/acpica/utlock.c
drivers/acpi/acpica/utmath.c
drivers/acpi/acpica/utmisc.c
drivers/acpi/acpica/utmutex.c
drivers/acpi/acpica/utobject.c
drivers/acpi/acpica/utosi.c
drivers/acpi/acpica/utresrc.c
drivers/acpi/acpica/utstate.c
drivers/acpi/acpica/utxface.c
drivers/acpi/acpica/utxferror.c
drivers/acpi/acpica/utxfmutex.c [new file with mode: 0644]
drivers/acpi/apei/apei-base.c
drivers/acpi/apei/apei-internal.h
drivers/acpi/apei/einj.c
drivers/acpi/apei/erst.c
drivers/acpi/apei/ghes.c
drivers/acpi/apei/hest.c
drivers/acpi/atomicio.c
drivers/acpi/dock.c
drivers/acpi/numa.c
drivers/acpi/nvs.c
drivers/acpi/osl.c
drivers/acpi/pci_slot.c
drivers/acpi/processor_core.c
drivers/acpi/processor_driver.c
drivers/acpi/video.c
drivers/ata/ata_piix.c
drivers/ata/libata-core.c
drivers/ata/libata-transport.c
drivers/ata/pata_bf54x.c
drivers/ata/sata_fsl.c
drivers/ata/sata_nv.c
drivers/ata/sata_sil24.c
drivers/atm/he.c
drivers/base/Kconfig
drivers/base/memory.c
drivers/base/power/domain.c
drivers/base/power/domain_governor.c
drivers/bcma/bcma_private.h
drivers/bcma/host_pci.c
drivers/bcma/main.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/cciss.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/mtip32xx/Kconfig [new file with mode: 0644]
drivers/block/mtip32xx/Makefile [new file with mode: 0644]
drivers/block/mtip32xx/mtip32xx.c [new file with mode: 0644]
drivers/block/mtip32xx/mtip32xx.h [new file with mode: 0644]
drivers/block/nvme.c [new file with mode: 0644]
drivers/block/paride/bpck6.c
drivers/block/paride/pcd.c
drivers/block/paride/pd.c
drivers/block/paride/pf.c
drivers/block/paride/pg.c
drivers/block/paride/pt.c
drivers/block/rbd.c
drivers/block/sx8.c
drivers/block/ub.c
drivers/block/virtio_blk.c
drivers/block/xd.c
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkback/common.h
drivers/block/xen-blkback/xenbus.c
drivers/block/xen-blkfront.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_bcsp.c
drivers/bluetooth/hci_ldisc.c
drivers/cdrom/cdrom.c
drivers/char/agp/amd64-agp.c
drivers/char/agp/sis-agp.c
drivers/char/hw_random/virtio-rng.c
drivers/char/i8k.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/lp.c
drivers/char/nwflash.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/ramoops.c
drivers/char/random.c
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_tis.c
drivers/char/virtio_console.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/amba-pl08x.c
drivers/dma/at_hdmac.c
drivers/dma/at_hdmac_regs.h
drivers/dma/coh901318.c
drivers/dma/coh901318_lli.c
drivers/dma/coh901318_lli.h
drivers/dma/dmaengine.c
drivers/dma/dw_dmac.c
drivers/dma/dw_dmac_regs.h
drivers/dma/ep93xx_dma.c
drivers/dma/fsldma.c
drivers/dma/imx-dma.c
drivers/dma/imx-sdma.c
drivers/dma/intel_mid_dma.c
drivers/dma/intel_mid_dma_regs.h
drivers/dma/iop-adma.c
drivers/dma/ipu/ipu_idmac.c
drivers/dma/mpc512x_dma.c
drivers/dma/mxs-dma.c
drivers/dma/pch_dma.c
drivers/dma/pl330.c
drivers/dma/shdma.c
drivers/dma/sirf-dma.c [new file with mode: 0644]
drivers/dma/ste_dma40.c
drivers/dma/ste_dma40_ll.h
drivers/dma/timb_dma.c
drivers/dma/txx9dmac.c
drivers/edac/r82600_edac.c
drivers/firewire/sbp2.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/devres.c [new file with mode: 0644]
drivers/gpio/gpio-ml-ioh.c
drivers/gpio/gpio-pch.c
drivers/gpio/gpio-pl061.c
drivers/gpio/gpio-sa1100.c
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpio-tegra.c
drivers/gpio/gpio-tps65910.c
drivers/gpu/drm/gma500/cdv_intel_crt.c
drivers/gpu/drm/gma500/cdv_intel_hdmi.c
drivers/gpu/drm/gma500/oaktrail_hdmi.c
drivers/gpu/drm/gma500/psb_intel_sdvo.c
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/radeon/evergreen_cs.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
drivers/hid/hid-prodikeys.c
drivers/hwmon/Kconfig
drivers/hwmon/abituguru.c
drivers/hwmon/abituguru3.c
drivers/hwmon/acpi_power_meter.c
drivers/hwmon/adm1021.c
drivers/hwmon/adm1031.c
drivers/hwmon/ads7828.c
drivers/hwmon/coretemp.c
drivers/hwmon/dme1737.c
drivers/hwmon/emc2103.c
drivers/hwmon/it87.c
drivers/hwmon/lm63.c
drivers/hwmon/lm90.c
drivers/hwmon/lm93.c
drivers/hwmon/max1111.c
drivers/hwmon/max1668.c
drivers/hwmon/w83627hf.c
drivers/hwmon/w83781d.c
drivers/hwmon/w83791d.c
drivers/hwmon/w83792d.c
drivers/hwmon/w83793.c
drivers/hwmon/w83795.c
drivers/hwmon/w83l786ng.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-ali1535.c
drivers/i2c/busses/i2c-ali1563.c
drivers/i2c/busses/i2c-ali15x3.c
drivers/i2c/busses/i2c-amd756.c
drivers/i2c/busses/i2c-amd8111.c
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-au1550.c
drivers/i2c/busses/i2c-cpm.c
drivers/i2c/busses/i2c-designware-pcidrv.c
drivers/i2c/busses/i2c-eg20t.c
drivers/i2c/busses/i2c-highlander.c
drivers/i2c/busses/i2c-hydra.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-ibm_iic.c
drivers/i2c/busses/i2c-intel-mid.c
drivers/i2c/busses/i2c-iop3xx.c
drivers/i2c/busses/i2c-isch.c
drivers/i2c/busses/i2c-ixp2000.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-nforce2.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-octeon.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-pasemi.c
drivers/i2c/busses/i2c-pca-platform.c
drivers/i2c/busses/i2c-piix4.c
drivers/i2c/busses/i2c-pmcmsp.c
drivers/i2c/busses/i2c-powermac.c
drivers/i2c/busses/i2c-pxa-pci.c
drivers/i2c/busses/i2c-sh7760.c
drivers/i2c/busses/i2c-simtec.c
drivers/i2c/busses/i2c-sis5595.c
drivers/i2c/busses/i2c-sis630.c
drivers/i2c/busses/i2c-sis96x.c
drivers/i2c/busses/i2c-via.c
drivers/i2c/busses/i2c-viapro.c
drivers/i2c/busses/i2c-xiic.c
drivers/i2c/busses/scx200_acb.c
drivers/i2c/i2c-dev.c
drivers/i2c/muxes/gpio-i2cmux.c
drivers/ide/ali14xx.c
drivers/ide/cmd640.c
drivers/ide/dtc2278.c
drivers/ide/gayle.c
drivers/ide/ht6560b.c
drivers/ide/ide-4drives.c
drivers/ide/ide-acpi.c
drivers/ide/ide-floppy_ioctl.c
drivers/ide/ide-pci-generic.c
drivers/ide/qd65xx.c
drivers/ide/umc8672.c
drivers/idle/intel_idle.c
drivers/infiniband/Kconfig
drivers/infiniband/Makefile
drivers/infiniband/hw/ehca/ehca_classes.h
drivers/infiniband/hw/ehca/ehca_main.c
drivers/infiniband/hw/nes/nes.c
drivers/infiniband/ulp/srpt/Kconfig [new file with mode: 0644]
drivers/infiniband/ulp/srpt/Makefile [new file with mode: 0644]
drivers/infiniband/ulp/srpt/ib_dm_mad.h [new file with mode: 0644]
drivers/infiniband/ulp/srpt/ib_srpt.c [new file with mode: 0644]
drivers/infiniband/ulp/srpt/ib_srpt.h [new file with mode: 0644]
drivers/input/joystick/xpad.c
drivers/input/keyboard/amikbd.c
drivers/input/keyboard/davinci_keyscan.c
drivers/input/keyboard/nomadik-ske-keypad.c
drivers/input/misc/ab8500-ponkey.c
drivers/input/misc/twl4030-pwrbutton.c
drivers/input/misc/wistron_btns.c
drivers/input/mouse/amimouse.c
drivers/input/mouse/bcm5974.c
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/synaptics_i2c.c
drivers/input/serio/at32psif.c
drivers/input/serio/hp_sdc.c
drivers/input/serio/serio_raw.c
drivers/input/touchscreen/atmel-wm97xx.c
drivers/input/touchscreen/eeti_ts.c
drivers/input/touchscreen/htcpen.c
drivers/input/touchscreen/mc13783_ts.c
drivers/input/touchscreen/ucb1400_ts.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/isdn/hardware/avm/b1dma.c
drivers/isdn/hardware/avm/c4.c
drivers/isdn/i4l/Kconfig
drivers/isdn/sc/init.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-clevo-mail.c
drivers/leds/leds-max8997.c [new file with mode: 0644]
drivers/leds/leds-ss4200.c
drivers/lguest/Makefile
drivers/lguest/lguest_device.c
drivers/lguest/segments.c
drivers/macintosh/ams/ams-core.c
drivers/macintosh/ams/ams-input.c
drivers/macintosh/therm_adt746x.c
drivers/md/dm-flakey.c
drivers/md/dm-linear.c
drivers/md/dm-mpath.c
drivers/md/dm-table.c
drivers/md/md.c
drivers/media/common/tuners/Kconfig
drivers/media/common/tuners/Makefile
drivers/media/common/tuners/max2165.c
drivers/media/common/tuners/mc44s803.c
drivers/media/common/tuners/mt2060.c
drivers/media/common/tuners/mt2060_priv.h
drivers/media/common/tuners/mt2063.c [new file with mode: 0644]
drivers/media/common/tuners/mt2063.h [new file with mode: 0644]
drivers/media/common/tuners/mt2131.c
drivers/media/common/tuners/mt2131_priv.h
drivers/media/common/tuners/mt2266.c
drivers/media/common/tuners/mxl5005s.c
drivers/media/common/tuners/mxl5007t.c
drivers/media/common/tuners/qt1010.c
drivers/media/common/tuners/qt1010_priv.h
drivers/media/common/tuners/tda18212.c
drivers/media/common/tuners/tda18212.h
drivers/media/common/tuners/tda18218.c
drivers/media/common/tuners/tda18218_priv.h
drivers/media/common/tuners/tda18271-fe.c
drivers/media/common/tuners/tda18271-maps.c
drivers/media/common/tuners/tda18271-priv.h
drivers/media/common/tuners/tda18271.h
drivers/media/common/tuners/tda827x.c
drivers/media/common/tuners/tuner-simple.c
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/common/tuners/xc4000.c
drivers/media/common/tuners/xc5000.c
drivers/media/dvb/b2c2/flexcop.c
drivers/media/dvb/bt8xx/dst.c
drivers/media/dvb/bt8xx/dst_common.h
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/ddbridge/ddbridge-core.c
drivers/media/dvb/dm1105/dm1105.c
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-core/dvb_net.c
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/af9005-fe.c
drivers/media/dvb/dvb-usb/af9005.c
drivers/media/dvb/dvb-usb/af9005.h
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/anysee.h
drivers/media/dvb/dvb-usb/cinergyT2-fe.c
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dib0700.h
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/dtt200u-fe.c
drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/dvb-usb/friio-fe.c
drivers/media/dvb/dvb-usb/gp8psk-fe.c
drivers/media/dvb/dvb-usb/it913x.c
drivers/media/dvb/dvb-usb/lmedm04.c
drivers/media/dvb/dvb-usb/mxl111sf-demod.c
drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
drivers/media/dvb/dvb-usb/mxl111sf.c
drivers/media/dvb/dvb-usb/ttusb2.c
drivers/media/dvb/dvb-usb/vp702x-fe.c
drivers/media/dvb/dvb-usb/vp7045-fe.c
drivers/media/dvb/firewire/firedtv-avc.c
drivers/media/dvb/firewire/firedtv-dvb.c
drivers/media/dvb/firewire/firedtv-fe.c
drivers/media/dvb/firewire/firedtv.h
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/af9013.c
drivers/media/dvb/frontends/af9013.h
drivers/media/dvb/frontends/af9013_priv.h
drivers/media/dvb/frontends/atbm8830.c
drivers/media/dvb/frontends/au8522_dig.c
drivers/media/dvb/frontends/bcm3510.c
drivers/media/dvb/frontends/bsbe1.h
drivers/media/dvb/frontends/bsru6.h
drivers/media/dvb/frontends/cx22700.c
drivers/media/dvb/frontends/cx22702.c
drivers/media/dvb/frontends/cx24110.c
drivers/media/dvb/frontends/cx24113.c
drivers/media/dvb/frontends/cx24116.c
drivers/media/dvb/frontends/cx24123.c
drivers/media/dvb/frontends/cxd2820r.h
drivers/media/dvb/frontends/cxd2820r_c.c
drivers/media/dvb/frontends/cxd2820r_core.c
drivers/media/dvb/frontends/cxd2820r_priv.h
drivers/media/dvb/frontends/cxd2820r_t.c
drivers/media/dvb/frontends/cxd2820r_t2.c
drivers/media/dvb/frontends/dib0070.c
drivers/media/dvb/frontends/dib0090.c
drivers/media/dvb/frontends/dib0090.h
drivers/media/dvb/frontends/dib3000mb.c
drivers/media/dvb/frontends/dib3000mb_priv.h
drivers/media/dvb/frontends/dib3000mc.c
drivers/media/dvb/frontends/dib7000m.c
drivers/media/dvb/frontends/dib7000p.c
drivers/media/dvb/frontends/dib7000p.h
drivers/media/dvb/frontends/dib8000.c
drivers/media/dvb/frontends/dib8000.h
drivers/media/dvb/frontends/dib9000.c
drivers/media/dvb/frontends/dibx000_common.h
drivers/media/dvb/frontends/drxd.h
drivers/media/dvb/frontends/drxd_hard.c
drivers/media/dvb/frontends/drxk.h
drivers/media/dvb/frontends/drxk_hard.c
drivers/media/dvb/frontends/drxk_hard.h
drivers/media/dvb/frontends/ds3000.c
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/dvb_dummy_fe.c
drivers/media/dvb/frontends/ec100.c
drivers/media/dvb/frontends/hd29l2.c [new file with mode: 0644]
drivers/media/dvb/frontends/hd29l2.h [new file with mode: 0644]
drivers/media/dvb/frontends/hd29l2_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/it913x-fe-priv.h
drivers/media/dvb/frontends/it913x-fe.c
drivers/media/dvb/frontends/it913x-fe.h
drivers/media/dvb/frontends/itd1000.c
drivers/media/dvb/frontends/ix2505v.c
drivers/media/dvb/frontends/l64781.c
drivers/media/dvb/frontends/lgdt3305.c
drivers/media/dvb/frontends/lgdt330x.c
drivers/media/dvb/frontends/lgs8gl5.c
drivers/media/dvb/frontends/lgs8gxx.c
drivers/media/dvb/frontends/mb86a16.c
drivers/media/dvb/frontends/mb86a20s.c
drivers/media/dvb/frontends/mt312.c
drivers/media/dvb/frontends/mt352.c
drivers/media/dvb/frontends/nxt200x.c
drivers/media/dvb/frontends/nxt6000.c
drivers/media/dvb/frontends/or51132.c
drivers/media/dvb/frontends/or51211.c
drivers/media/dvb/frontends/s5h1409.c
drivers/media/dvb/frontends/s5h1411.c
drivers/media/dvb/frontends/s5h1420.c
drivers/media/dvb/frontends/s5h1432.c
drivers/media/dvb/frontends/s921.c
drivers/media/dvb/frontends/si21xx.c
drivers/media/dvb/frontends/sp8870.c
drivers/media/dvb/frontends/sp887x.c
drivers/media/dvb/frontends/stb0899_drv.c
drivers/media/dvb/frontends/stb6000.c
drivers/media/dvb/frontends/stb6100.c
drivers/media/dvb/frontends/stv0288.c
drivers/media/dvb/frontends/stv0297.c
drivers/media/dvb/frontends/stv0299.c
drivers/media/dvb/frontends/stv0367.c
drivers/media/dvb/frontends/stv0900_core.c
drivers/media/dvb/frontends/stv090x.c
drivers/media/dvb/frontends/stv6110.c
drivers/media/dvb/frontends/tda10021.c
drivers/media/dvb/frontends/tda10023.c
drivers/media/dvb/frontends/tda10048.c
drivers/media/dvb/frontends/tda1004x.c
drivers/media/dvb/frontends/tda10071.c
drivers/media/dvb/frontends/tda10086.c
drivers/media/dvb/frontends/tda18271c2dd.c
drivers/media/dvb/frontends/tda8083.c
drivers/media/dvb/frontends/tda826x.c
drivers/media/dvb/frontends/tdhd1.h
drivers/media/dvb/frontends/tua6100.c
drivers/media/dvb/frontends/ves1820.c
drivers/media/dvb/frontends/ves1x93.c
drivers/media/dvb/frontends/zl10036.c
drivers/media/dvb/frontends/zl10039.c
drivers/media/dvb/frontends/zl10353.c
drivers/media/dvb/mantis/mantis_vp1033.c
drivers/media/dvb/mantis/mantis_vp2033.c
drivers/media/dvb/mantis/mantis_vp2040.c
drivers/media/dvb/ngene/ngene-cards.c
drivers/media/dvb/pluto2/pluto2.c
drivers/media/dvb/pt1/va1j5jf8007s.c
drivers/media/dvb/pt1/va1j5jf8007t.c
drivers/media/dvb/siano/smsdvb.c
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/av7110.h
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttpci/budget-patch.c
drivers/media/dvb/ttpci/budget.c
drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
drivers/media/dvb/ttusb-dec/ttusbdecfe.c
drivers/media/media-device.c
drivers/media/radio/Kconfig
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-miropcm20.c
drivers/media/radio/radio-si4713.c
drivers/media/radio/radio-timb.c
drivers/media/radio/radio-wl1273.c
drivers/media/radio/tef6862.c
drivers/media/radio/wl128x/Kconfig
drivers/media/radio/wl128x/fmdrv_common.c
drivers/media/radio/wl128x/fmdrv_common.h
drivers/media/radio/wl128x/fmdrv_rx.c
drivers/media/radio/wl128x/fmdrv_rx.h
drivers/media/radio/wl128x/fmdrv_tx.c
drivers/media/radio/wl128x/fmdrv_tx.h
drivers/media/radio/wl128x/fmdrv_v4l2.c
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/ir-nec-decoder.c
drivers/media/rc/ir-raw.c
drivers/media/rc/ir-rc6-decoder.c
drivers/media/rc/ir-sanyo-decoder.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-hauppauge.c
drivers/media/rc/keymaps/rc-videomate-m1f.c
drivers/media/rc/lirc_dev.c
drivers/media/rc/mceusb.c
drivers/media/rc/rc-core-priv.h
drivers/media/rc/rc-main.c
drivers/media/rc/redrat3.c
drivers/media/rc/streamzap.c
drivers/media/rc/winbond-cir.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7170.c
drivers/media/video/as3645a.c [new file with mode: 0644]
drivers/media/video/atmel-isi.c
drivers/media/video/au0828/Kconfig
drivers/media/video/au0828/au0828-i2c.c
drivers/media/video/bt8xx/bt848.h
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-i2c.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/c-qcam.c
drivers/media/video/cs5345.c
drivers/media/video/cs53l32a.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-i2c.c
drivers/media/video/cx18/cx18-i2c.h
drivers/media/video/cx231xx/Kconfig
drivers/media/video/cx231xx/cx231xx-audio.c
drivers/media/video/cx231xx/cx231xx-cards.c
drivers/media/video/cx231xx/cx231xx-core.c
drivers/media/video/cx231xx/cx231xx-dvb.c
drivers/media/video/cx231xx/cx231xx-input.c
drivers/media/video/cx231xx/cx231xx-vbi.c
drivers/media/video/cx231xx/cx231xx-video.c
drivers/media/video/cx231xx/cx231xx.h
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-i2c.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx25821/cx25821-alsa.c
drivers/media/video/cx25821/cx25821-audio-upstream.c
drivers/media/video/cx25821/cx25821-audio.h
drivers/media/video/cx25821/cx25821-cards.c
drivers/media/video/cx25821/cx25821-core.c
drivers/media/video/cx25821/cx25821-i2c.c
drivers/media/video/cx25821/cx25821-medusa-defines.h
drivers/media/video/cx25821/cx25821-medusa-reg.h
drivers/media/video/cx25821/cx25821-medusa-video.c
drivers/media/video/cx25821/cx25821-video-upstream-ch2.c
drivers/media/video/cx25821/cx25821-video-upstream.c
drivers/media/video/cx25821/cx25821-video.c
drivers/media/video/cx25821/cx25821.h
drivers/media/video/cx25840/cx25840-audio.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx88/Kconfig
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88.h
drivers/media/video/davinci/dm355_ccdc.c
drivers/media/video/davinci/dm644x_ccdc.c
drivers/media/video/davinci/isif.c
drivers/media/video/davinci/vpbe.c
drivers/media/video/davinci/vpbe_display.c
drivers/media/video/davinci/vpbe_osd.c
drivers/media/video/davinci/vpbe_venc.c
drivers/media/video/davinci/vpfe_capture.c
drivers/media/video/davinci/vpif_capture.c
drivers/media/video/em28xx/em28xx-audio.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/em28xx/em28xx-reg.h
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/fsl-viu.c
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/benq.c
drivers/media/video/gspca/gl860/gl860.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/jl2005bcd.c [new file with mode: 0644]
drivers/media/video/gspca/konica.c
drivers/media/video/gspca/m5602/m5602_core.c
drivers/media/video/gspca/m5602/m5602_mt9m111.h
drivers/media/video/gspca/m5602/m5602_ov7660.h
drivers/media/video/gspca/m5602/m5602_ov9650.h
drivers/media/video/gspca/m5602/m5602_po1030.h
drivers/media/video/gspca/m5602/m5602_s5k4aa.h
drivers/media/video/gspca/m5602/m5602_s5k83a.h
drivers/media/video/gspca/mars.c
drivers/media/video/gspca/nw80x.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/ov534_9.c
drivers/media/video/gspca/pac207.c
drivers/media/video/gspca/pac7302.c
drivers/media/video/gspca/se401.c
drivers/media/video/gspca/sn9c20x.c
drivers/media/video/gspca/sonixb.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca561.c
drivers/media/video/gspca/stv06xx/stv06xx.c
drivers/media/video/gspca/t613.c
drivers/media/video/gspca/topro.c
drivers/media/video/gspca/vicam.c
drivers/media/video/gspca/xirlink_cit.c
drivers/media/video/gspca/zc3xx.c
drivers/media/video/hdpvr/hdpvr-core.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-i2c.h
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-irq.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-yuv.c
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/m5mols/m5mols.h
drivers/media/video/m5mols/m5mols_capture.c
drivers/media/video/m5mols/m5mols_core.c
drivers/media/video/m5mols/m5mols_reg.h
drivers/media/video/marvell-ccic/mcam-core.c
drivers/media/video/marvell-ccic/mmp-driver.c
drivers/media/video/msp3400-driver.c
drivers/media/video/msp3400-driver.h
drivers/media/video/mt9m001.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9p031.c
drivers/media/video/mt9t001.c
drivers/media/video/mt9t031.c
drivers/media/video/mt9v022.c
drivers/media/video/mt9v032.c
drivers/media/video/mx1_camera.c
drivers/media/video/mx2_camera.c
drivers/media/video/mx3_camera.c
drivers/media/video/omap/omap_vout.c
drivers/media/video/omap/omap_vout_vrfb.c
drivers/media/video/omap/omap_voutdef.h
drivers/media/video/omap1_camera.c
drivers/media/video/omap24xxcam.c
drivers/media/video/omap3isp/isp.c
drivers/media/video/omap3isp/ispccdc.c
drivers/media/video/omap3isp/ispccdc.h
drivers/media/video/omap3isp/ispccp2.c
drivers/media/video/omap3isp/ispccp2.h
drivers/media/video/omap3isp/ispcsi2.c
drivers/media/video/omap3isp/ispcsi2.h
drivers/media/video/omap3isp/isppreview.c
drivers/media/video/omap3isp/isppreview.h
drivers/media/video/omap3isp/ispresizer.c
drivers/media/video/omap3isp/ispresizer.h
drivers/media/video/omap3isp/ispvideo.c
drivers/media/video/omap3isp/ispvideo.h
drivers/media/video/ov7670.c
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pwc/pwc-ctrl.c
drivers/media/video/pwc/pwc-dec1.c
drivers/media/video/pwc/pwc-dec1.h
drivers/media/video/pwc/pwc-dec23.c
drivers/media/video/pwc/pwc-dec23.h
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-kiara.h
drivers/media/video/pwc/pwc-misc.c
drivers/media/video/pwc/pwc-timon.h
drivers/media/video/pwc/pwc-uncompress.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pwc/pwc.h
drivers/media/video/pxa_camera.c
drivers/media/video/s5p-fimc/fimc-capture.c
drivers/media/video/s5p-fimc/fimc-core.c
drivers/media/video/s5p-fimc/fimc-core.h
drivers/media/video/s5p-fimc/fimc-mdevice.c
drivers/media/video/s5p-fimc/fimc-reg.c
drivers/media/video/s5p-fimc/mipi-csis.c
drivers/media/video/s5p-fimc/mipi-csis.h
drivers/media/video/s5p-fimc/regs-fimc.h
drivers/media/video/s5p-g2d/Makefile [new file with mode: 0644]
drivers/media/video/s5p-g2d/g2d-hw.c [new file with mode: 0644]
drivers/media/video/s5p-g2d/g2d-regs.h [new file with mode: 0644]
drivers/media/video/s5p-g2d/g2d.c [new file with mode: 0644]
drivers/media/video/s5p-g2d/g2d.h [new file with mode: 0644]
drivers/media/video/s5p-jpeg/Makefile [new file with mode: 0644]
drivers/media/video/s5p-jpeg/jpeg-core.c [new file with mode: 0644]
drivers/media/video/s5p-jpeg/jpeg-core.h [new file with mode: 0644]
drivers/media/video/s5p-jpeg/jpeg-hw.h [new file with mode: 0644]
drivers/media/video/s5p-jpeg/jpeg-regs.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc.c
drivers/media/video/s5p-mfc/s5p_mfc_dec.c
drivers/media/video/s5p-tv/hdmi_drv.c
drivers/media/video/s5p-tv/mixer.h
drivers/media/video/s5p-tv/mixer_grp_layer.c
drivers/media/video/s5p-tv/mixer_video.c
drivers/media/video/s5p-tv/mixer_vp_layer.c
drivers/media/video/s5p-tv/sdo_drv.c
drivers/media/video/saa7115.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-tvaudio.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa7164/saa7164-bus.c
drivers/media/video/saa7164/saa7164-cards.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sh_mobile_csi2.c
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/soc_camera.c
drivers/media/video/soc_camera_platform.c
drivers/media/video/stk-webcam.c
drivers/media/video/timblogiw.c
drivers/media/video/tlg2300/pd-common.h
drivers/media/video/tlg2300/pd-dvb.c
drivers/media/video/tlg2300/pd-main.c
drivers/media/video/tm6000/Kconfig
drivers/media/video/tm6000/tm6000-alsa.c
drivers/media/video/tm6000/tm6000-cards.c
drivers/media/video/tm6000/tm6000-core.c
drivers/media/video/tm6000/tm6000-dvb.c
drivers/media/video/tm6000/tm6000-i2c.c
drivers/media/video/tm6000/tm6000-input.c
drivers/media/video/tm6000/tm6000-regs.h
drivers/media/video/tm6000/tm6000-stds.c
drivers/media/video/tm6000/tm6000-video.c
drivers/media/video/tm6000/tm6000.h
drivers/media/video/tuner-core.c
drivers/media/video/tvp514x.c
drivers/media/video/tvp5150.c
drivers/media/video/tvp7002.c
drivers/media/video/upd64083.c
drivers/media/video/usbvision/usbvision-i2c.c
drivers/media/video/uvc/Kconfig
drivers/media/video/uvc/Makefile
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_debugfs.c [new file with mode: 0644]
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_isight.c
drivers/media/video/uvc/uvc_queue.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvc_video.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l2-compat-ioctl32.c
drivers/media/video/v4l2-ctrls.c
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-device.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/v4l2-subdev.c
drivers/media/video/via-camera.c
drivers/media/video/videobuf-dvb.c
drivers/media/video/videobuf2-core.c
drivers/media/video/videobuf2-dma-sg.c
drivers/media/video/videobuf2-memops.c
drivers/media/video/videobuf2-vmalloc.c
drivers/media/video/vino.c
drivers/media/video/zoran/zoran_device.c
drivers/media/video/zoran/zoran_driver.c
drivers/media/video/zoran/zr36060.c
drivers/memstick/host/jmb38x_ms.c
drivers/memstick/host/r592.c
drivers/memstick/host/tifm_ms.c
drivers/mfd/88pm860x-i2c.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/aat2870-core.c
drivers/mfd/ab5500-core.c
drivers/mfd/ab5500-debugfs.c
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-debugfs.c
drivers/mfd/ab8500-gpadc.c
drivers/mfd/ab8500-i2c.c
drivers/mfd/ab8500-sysctrl.c
drivers/mfd/cs5535-mfd.c
drivers/mfd/dm355evm_msp.c
drivers/mfd/intel_msic.c
drivers/mfd/janz-cmodio.c
drivers/mfd/jz4740-adc.c
drivers/mfd/lpc_sch.c
drivers/mfd/max8925-i2c.c
drivers/mfd/max8997.c
drivers/mfd/max8998.c
drivers/mfd/mc13xxx-core.c
drivers/mfd/mcp-core.c
drivers/mfd/mcp-sa11x0.c
drivers/mfd/omap-usb-host.c
drivers/mfd/pcf50633-adc.c
drivers/mfd/s5m-core.c [new file with mode: 0644]
drivers/mfd/s5m-irq.c [new file with mode: 0644]
drivers/mfd/sm501.c
drivers/mfd/stmpe-i2c.c [new file with mode: 0644]
drivers/mfd/stmpe-spi.c [new file with mode: 0644]
drivers/mfd/stmpe.c
drivers/mfd/stmpe.h
drivers/mfd/t7l66xb.c
drivers/mfd/tc6387xb.c
drivers/mfd/ti-ssp.c
drivers/mfd/timberdale.c
drivers/mfd/tps65910-irq.c
drivers/mfd/tps65910.c
drivers/mfd/tps65912-spi.c
drivers/mfd/twl-core.c
drivers/mfd/twl4030-audio.c
drivers/mfd/twl4030-irq.c
drivers/mfd/twl4030-madc.c
drivers/mfd/twl4030-power.c
drivers/mfd/twl6040-core.c
drivers/mfd/ucb1x00-core.c
drivers/mfd/ucb1x00-ts.c
drivers/mfd/vx855.c
drivers/mfd/wm831x-core.c
drivers/mfd/wm831x-i2c.c
drivers/mfd/wm831x-irq.c
drivers/mfd/wm831x-spi.c
drivers/mfd/wm8350-core.c
drivers/mfd/wm8350-i2c.c
drivers/mfd/wm8400-core.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/ab8500-pwm.c
drivers/misc/carma/carma-fpga-program.c
drivers/misc/iwmc3200top/main.c
drivers/misc/lis3lv02d/lis3lv02d.c
drivers/misc/max8997-muic.c [new file with mode: 0644]
drivers/mmc/Makefile
drivers/mmc/card/block.c
drivers/mmc/card/mmc_test.c
drivers/mmc/card/queue.c
drivers/mmc/core/Makefile
drivers/mmc/core/bus.c
drivers/mmc/core/cd-gpio.c [new file with mode: 0644]
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/debugfs.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_io.c
drivers/mmc/core/sdio_ops.c
drivers/mmc/host/Makefile
drivers/mmc/host/at91_mci.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/au1xmmc.c
drivers/mmc/host/bfin_sdh.c
drivers/mmc/host/cb710-mmc.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/mmci.c
drivers/mmc/host/msm_sdcc.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/mxs-mmc.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/sdhci-cns3xxx.c
drivers/mmc/host/sdhci-dove.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-esdhc.h
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-of-hlwd.c
drivers/mmc/host/sdhci-pci-data.c [new file with mode: 0644]
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pxav2.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-spear.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mmc/host/tifm_sd.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_dma.c
drivers/mmc/host/tmio_mmc_pio.c
drivers/mmc/host/vub300.c
drivers/mtd/mtdoops.c
drivers/mtd/nand/au1550nd.c
drivers/mtd/nand/gpmi-nand/gpmi-lib.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/r852.c
drivers/mtd/ubi/cdev.c
drivers/mtd/ubi/debug.h
drivers/mtd/ubi/vtbl.c
drivers/net/bonding/bond_alb.c
drivers/net/ethernet/8390/ax88796.c
drivers/net/ethernet/adi/bfin_mac.c
drivers/net/ethernet/amd/au1000_eth.c
drivers/net/ethernet/broadcom/bcm63xx_enet.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
drivers/net/ethernet/broadcom/sb1250-mac.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/dnet.c
drivers/net/ethernet/freescale/fec.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar.h
drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/ibm/ehea/ehea_qmr.c
drivers/net/ethernet/lantiq_etop.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/marvell/pxa168_eth.c
drivers/net/ethernet/micrel/ks8842.c
drivers/net/ethernet/micrel/ksz884x.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/s6gmac.c
drivers/net/ethernet/smsc/smsc911x.c
drivers/net/ethernet/stmicro/stmmac/mmc_core.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/ti/cpmac.c
drivers/net/ethernet/ti/davinci_mdio.c
drivers/net/ethernet/tundra/tsi108_eth.c
drivers/net/ethernet/via/via-rhine.c
drivers/net/ethernet/xscale/ixp4xx_eth.c
drivers/net/irda/Kconfig
drivers/net/irda/au1000_ircc.h [deleted file]
drivers/net/irda/au1k_ir.c
drivers/net/phy/dp83640.c
drivers/net/phy/fixed.c
drivers/net/phy/mdio-gpio.c
drivers/net/phy/mdio-octeon.c
drivers/net/phy/mdio_bus.c
drivers/net/ppp/pptp.c
drivers/net/usb/asix.c
drivers/net/virtio_net.c
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/calib.h
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/srom.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rtlwifi/rtl8192se/fw.c
drivers/of/address.c
drivers/of/irq.c
drivers/parport/parport_ip32.c
drivers/parport/parport_pc.c
drivers/pci/hotplug/acpi_pcihp.c
drivers/pci/hotplug/acpiphp_core.c
drivers/pci/hotplug/acpiphp_ibm.c
drivers/pci/hotplug/cpcihp_zt5550.c
drivers/pci/hotplug/cpqphp_core.c
drivers/pci/hotplug/ibmphp_core.c
drivers/pci/hotplug/pci_hotplug_core.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pcihp_skeleton.c
drivers/pci/hotplug/rpaphp.h
drivers/pci/hotplug/rpaphp_core.c
drivers/pci/hotplug/shpchp.h
drivers/pci/hotplug/shpchp_core.c
drivers/pci/pci-sysfs.c
drivers/pci/pcie/aer/aer_inject.c
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pcmcia/Kconfig
drivers/pcmcia/Makefile
drivers/pcmcia/au1000_generic.c [deleted file]
drivers/pcmcia/au1000_generic.h [deleted file]
drivers/pcmcia/au1000_pb1x00.c [deleted file]
drivers/pcmcia/db1xxx_ss.c
drivers/pcmcia/yenta_socket.c
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/intel_oaktrail.c
drivers/platform/x86/msi-laptop.c
drivers/platform/x86/samsung-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/wmi.c
drivers/power/ds2760_battery.c
drivers/regulator/ab8500.c
drivers/rtc/rtc-ab8500.c
drivers/rtc/rtc-max8925.c
drivers/s390/char/raw3270.c
drivers/s390/char/vmwatchdog.c
drivers/s390/cio/cmf.c
drivers/s390/kvm/kvm_virtio.c
drivers/scsi/Kconfig
drivers/scsi/aha1542.c
drivers/scsi/bfa/bfa_defs_svc.h
drivers/scsi/bfa/bfa_fc.h
drivers/scsi/bfa/bfa_fcpim.c
drivers/scsi/bfa/bfa_fcpim.h
drivers/scsi/bfa/bfa_svc.h
drivers/scsi/bfa/bfad.c
drivers/scsi/bfa/bfad_attr.c
drivers/scsi/bfa/bfad_bsg.c
drivers/scsi/bfa/bfad_drv.h
drivers/scsi/bfa/bfad_im.c
drivers/scsi/bfa/bfad_im.h
drivers/scsi/cxgbi/libcxgbi.c
drivers/scsi/dc395x.c
drivers/scsi/device_handler/scsi_dh_alua.c
drivers/scsi/device_handler/scsi_dh_rdac.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/fcoe.h
drivers/scsi/hpsa.c
drivers/scsi/isci/firmware/Makefile [deleted file]
drivers/scsi/isci/firmware/README [deleted file]
drivers/scsi/isci/firmware/create_fw.c [deleted file]
drivers/scsi/isci/firmware/create_fw.h [deleted file]
drivers/scsi/isci/host.c
drivers/scsi/isci/host.h
drivers/scsi/isci/init.c
drivers/scsi/isci/isci.h
drivers/scsi/isci/phy.c
drivers/scsi/isci/port.c
drivers/scsi/isci/port.h
drivers/scsi/isci/port_config.c
drivers/scsi/isci/probe_roms.c
drivers/scsi/isci/probe_roms.h
drivers/scsi/isci/remote_device.c
drivers/scsi/isci/task.c
drivers/scsi/isci/task.h
drivers/scsi/libfc/fc_disc.c
drivers/scsi/libfc/fc_elsct.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libfc/fc_lport.c
drivers/scsi/libfc/fc_rport.c
drivers/scsi/megaraid.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fp.c
drivers/scsi/nsp32.c
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/qla4xxx/ql4_def.h
drivers/scsi/qla4xxx/ql4_init.c
drivers/scsi/qla4xxx/ql4_mbx.c
drivers/scsi/qla4xxx/ql4_nx.c
drivers/scsi/qla4xxx/ql4_nx.h
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/qla4xxx/ql4_version.h
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_netlink.c
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/sd.c
drivers/scsi/sg.c
drivers/scsi/sym53c8xx_2/sym_glue.c
drivers/spi/Kconfig
drivers/spi/spi-dw-mid.c
drivers/spi/spi-ep93xx.c
drivers/spi/spi-pl022.c
drivers/spi/spi-topcliff-pch.c
drivers/staging/comedi/comedi_fops.c
drivers/staging/comedi/comedi_fops.h
drivers/staging/media/as102/Kconfig
drivers/staging/media/as102/Makefile
drivers/staging/media/as102/as102_drv.c
drivers/staging/media/as102/as102_drv.h
drivers/staging/media/as102/as102_fe.c
drivers/staging/media/as102/as102_fw.c
drivers/staging/media/as102/as102_fw.h
drivers/staging/media/as102/as102_usb_drv.c
drivers/staging/media/as102/as102_usb_drv.h
drivers/staging/media/as102/as10x_cmd.c
drivers/staging/media/as102/as10x_cmd.h
drivers/staging/media/as102/as10x_cmd_cfg.c
drivers/staging/media/as102/as10x_cmd_stream.c
drivers/staging/media/as102/as10x_handle.h
drivers/staging/media/as102/as10x_types.h
drivers/staging/media/dt3155v4l/dt3155v4l.c
drivers/staging/media/easycap/easycap.h
drivers/staging/media/easycap/easycap_ioctl.c
drivers/staging/media/easycap/easycap_low.c
drivers/staging/media/easycap/easycap_main.c
drivers/staging/media/easycap/easycap_settings.c
drivers/staging/media/easycap/easycap_sound.c
drivers/staging/media/go7007/go7007-usb.c
drivers/staging/media/go7007/snd-go7007.c
drivers/staging/media/lirc/lirc_bt829.c
drivers/staging/media/lirc/lirc_igorplugusb.c
drivers/staging/media/lirc/lirc_imon.c
drivers/staging/media/lirc/lirc_parallel.c
drivers/staging/media/lirc/lirc_serial.c
drivers/staging/media/lirc/lirc_sir.c
drivers/staging/media/lirc/lirc_zilog.c
drivers/staging/media/solo6x10/Makefile
drivers/staging/media/solo6x10/solo6x10-jpeg.h [moved from drivers/staging/media/solo6x10/jpeg.h with 100% similarity]
drivers/staging/media/solo6x10/v4l2-enc.c
drivers/staging/octeon/Makefile
drivers/staging/octeon/cvmx-packet.h [deleted file]
drivers/staging/octeon/cvmx-smix-defs.h [deleted file]
drivers/staging/octeon/ethernet-defines.h
drivers/staging/octeon/ethernet-mdio.c
drivers/staging/octeon/ethernet-mem.c
drivers/staging/octeon/ethernet-rgmii.c
drivers/staging/octeon/ethernet-rx.c
drivers/staging/octeon/ethernet-rx.h
drivers/staging/octeon/ethernet-sgmii.c
drivers/staging/octeon/ethernet-spi.c
drivers/staging/octeon/ethernet-tx.c
drivers/staging/octeon/ethernet-xaui.c
drivers/staging/octeon/ethernet.c
drivers/staging/quatech_usb2/quatech_usb2.c
drivers/staging/serqt_usb2/serqt_usb2.c
drivers/staging/speakup/speakup.h
drivers/staging/speakup/synth.c
drivers/staging/vme/bridges/vme_tsi148.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_auth.c
drivers/target/iscsi/iscsi_target_configfs.c
drivers/target/iscsi/iscsi_target_device.c
drivers/target/iscsi/iscsi_target_erl0.c
drivers/target/iscsi/iscsi_target_erl1.c
drivers/target/iscsi/iscsi_target_erl2.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_nodeattrib.c
drivers/target/iscsi/iscsi_target_stat.c
drivers/target/iscsi/iscsi_target_tmr.c
drivers/target/iscsi/iscsi_target_tpg.c
drivers/target/iscsi/iscsi_target_util.c
drivers/target/loopback/tcm_loop.c
drivers/target/loopback/tcm_loop.h
drivers/target/target_core_alua.c
drivers/target/target_core_cdb.c
drivers/target/target_core_cdb.h [deleted file]
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_fabric_configfs.c
drivers/target/target_core_fabric_lib.c
drivers/target/target_core_file.c
drivers/target/target_core_hba.c
drivers/target/target_core_hba.h [deleted file]
drivers/target/target_core_iblock.c
drivers/target/target_core_internal.h [new file with mode: 0644]
drivers/target/target_core_pr.c
drivers/target/target_core_pr.h
drivers/target/target_core_pscsi.c
drivers/target/target_core_rd.c
drivers/target/target_core_stat.c
drivers/target/target_core_stat.h [deleted file]
drivers/target/target_core_tmr.c
drivers/target/target_core_tpg.c
drivers/target/target_core_transport.c
drivers/target/target_core_ua.c
drivers/target/tcm_fc/tfc_cmd.c
drivers/target/tcm_fc/tfc_conf.c
drivers/target/tcm_fc/tfc_io.c
drivers/target/tcm_fc/tfc_sess.c
drivers/tty/rocket.c
drivers/tty/serial/Kconfig
drivers/tty/serial/Makefile
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/ar933x_uart.c [new file with mode: 0644]
drivers/tty/serial/pch_uart.c
drivers/tty/serial/sh-sci.c
drivers/tty/synclink.c
drivers/tty/synclinkmp.c
drivers/usb/atm/speedtch.c
drivers/usb/atm/ueagle-atm.c
drivers/usb/core/devio.c
drivers/usb/core/hub.c
drivers/usb/core/usb.c
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/net2272.c
drivers/usb/gadget/net2280.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/pch_udc.c
drivers/usb/gadget/serial.c
drivers/usb/gadget/zero.c
drivers/usb/host/Kconfig
drivers/usb/host/alchemy-common.c
drivers/usb/host/ehci-ath79.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-xilinx-of.c
drivers/usb/host/ohci-au1xxx.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/oxu210hp-hcd.c
drivers/usb/host/u132-hcd.c
drivers/usb/host/uhci-hcd.c
drivers/usb/misc/ftdi-elan.c
drivers/usb/misc/iowarrior.c
drivers/usb/musb/cppi_dma.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/ux500_dma.c
drivers/usb/otg/ab8500-usb.c
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/serial/aircable.c
drivers/usb/serial/ark3116.c
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/ch341.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/cyberjack.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/empeg.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/funsoft.c
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/ipaq.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/mct_u232.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/navman.c
drivers/usb/serial/omninet.c
drivers/usb/serial/opticon.c
drivers/usb/serial/option.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/qcserial.c
drivers/usb/serial/safe_serial.c
drivers/usb/serial/sierra.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/ssu100.c
drivers/usb/serial/symbolserial.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb_wwan.c
drivers/usb/serial/visor.c
drivers/usb/serial/whiteheat.c
drivers/vhost/net.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/amifb.c
drivers/video/atmel_lcdfb.c
drivers/video/aty/atyfb_base.c
drivers/video/aty/radeon_base.c
drivers/video/au1100fb.c
drivers/video/au1200fb.c
drivers/video/cirrusfb.c
drivers/video/console/newport_con.c
drivers/video/controlfb.c
drivers/video/display/Kconfig [deleted file]
drivers/video/display/Makefile [deleted file]
drivers/video/display/display-sysfs.c [deleted file]
drivers/video/fbmem.c
drivers/video/fsl-diu-fb.c
drivers/video/grvga.c
drivers/video/hgafb.c
drivers/video/i810/i810_main.c
drivers/video/intelfb/intelfbdrv.c
drivers/video/logo/logo.c
drivers/video/matrox/matroxfb_base.c
drivers/video/matrox/matroxfb_crtc2.c
drivers/video/mbx/mbxfb.c
drivers/video/mx3fb.c
drivers/video/mxsfb.c
drivers/video/neofb.c
drivers/video/nuc900fb.c
drivers/video/nvidia/nvidia.c
drivers/video/omap/lcd_ams_delta.c
drivers/video/omap/lcd_h3.c
drivers/video/omap/lcd_htcherald.c
drivers/video/omap/lcd_inn1510.c
drivers/video/omap/lcd_inn1610.c
drivers/video/omap/lcd_mipid.c
drivers/video/omap/lcd_osk.c
drivers/video/omap/lcd_palmte.c
drivers/video/omap/lcd_palmtt.c
drivers/video/omap/lcd_palmz71.c
drivers/video/omap/omapfb_main.c
drivers/video/omap2/displays/Kconfig
drivers/video/omap2/displays/panel-acx565akm.c
drivers/video/omap2/displays/panel-generic-dpi.c
drivers/video/omap2/displays/panel-n8x0.c
drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
drivers/video/omap2/displays/panel-taal.c
drivers/video/omap2/displays/panel-tpo-td043mtea1.c
drivers/video/omap2/dss/Makefile
drivers/video/omap2/dss/apply.c [new file with mode: 0644]
drivers/video/omap2/dss/core.c
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/dispc.h
drivers/video/omap2/dss/dispc_coefs.c [new file with mode: 0644]
drivers/video/omap2/dss/dpi.c
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss.h
drivers/video/omap2/dss/dss_features.c
drivers/video/omap2/dss/dss_features.h
drivers/video/omap2/dss/hdmi.c
drivers/video/omap2/dss/manager.c
drivers/video/omap2/dss/overlay.c
drivers/video/omap2/dss/rfbi.c
drivers/video/omap2/dss/sdi.c
drivers/video/omap2/dss/ti_hdmi.h
drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h
drivers/video/omap2/dss/venc.c
drivers/video/omap2/omapfb/omapfb-ioctl.c
drivers/video/omap2/omapfb/omapfb-main.c
drivers/video/omap2/omapfb/omapfb-sysfs.c
drivers/video/omap2/omapfb/omapfb.h
drivers/video/pm2fb.c
drivers/video/pm3fb.c
drivers/video/pnx4008/pnxrgbfb.c
drivers/video/pnx4008/sdum.c
drivers/video/pxa168fb.c
drivers/video/pxa3xx-gcu.c
drivers/video/riva/fbdev.c
drivers/video/s3c-fb.c
drivers/video/s3c2410fb.c
drivers/video/s3fb.c
drivers/video/sbuslib.c
drivers/video/sh7760fb.c
drivers/video/sh_mipi_dsi.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sh_mobile_meram.c
drivers/video/sm501fb.c
drivers/video/smscufx.c
drivers/video/sstfb.c
drivers/video/tdfxfb.c
drivers/video/udlfb.c
drivers/video/uvesafb.c
drivers/video/vfb.c
drivers/video/vt8500lcdfb.c
drivers/video/w100fb.c
drivers/video/wm8505fb.c
drivers/video/wmt_ge_rops.c
drivers/video/xilinxfb.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_mmio.c
drivers/virtio/virtio_pci.c
drivers/virtio/virtio_ring.c
drivers/watchdog/f71808e_wdt.c
drivers/watchdog/mpc8xxx_wdt.c
drivers/xen/biomerge.c
drivers/xen/xen-balloon.c
drivers/xen/xen-pciback/conf_space.c
drivers/xen/xen-pciback/xenbus.c
firmware/Makefile
firmware/isci/isci_firmware.bin.ihex [deleted file]
fs/aio.c
fs/autofs4/waitq.c
fs/block_dev.c
fs/btrfs/Kconfig
fs/btrfs/Makefile
fs/btrfs/backref.c
fs/btrfs/backref.h
fs/btrfs/btrfs_inode.h
fs/btrfs/check-integrity.c [new file with mode: 0644]
fs/btrfs/check-integrity.h [new file with mode: 0644]
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/delayed-inode.c
fs/btrfs/delayed-ref.c
fs/btrfs/delayed-ref.h
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/export.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode-map.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ioctl.h
fs/btrfs/locking.c
fs/btrfs/relocation.c
fs/btrfs/scrub.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c
fs/btrfs/ulist.c [new file with mode: 0644]
fs/btrfs/ulist.h [new file with mode: 0644]
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/btrfs/xattr.c
fs/ceph/dir.c
fs/ceph/export.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/super.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/compat_ioctl.c
fs/dcache.c
fs/direct-io.c
fs/eventpoll.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/gfs2/glock.c
fs/gfs2/glock.h
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/lock_dlm.c
fs/gfs2/main.c
fs/gfs2/ops_fstype.c
fs/gfs2/recovery.c
fs/gfs2/rgrp.c
fs/gfs2/sys.c
fs/gfs2/sys.h
fs/hugetlbfs/inode.c
fs/inode.c
fs/ioprio.c
fs/lockd/mon.c
fs/mpage.c
fs/namei.c
fs/nfs/blocklayout/blocklayout.c
fs/nfs/blocklayout/blocklayout.h
fs/nfs/blocklayout/extents.c
fs/nfs/callback.h
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4proc.c
fs/nfs/write.c
fs/nfsd/Kconfig
fs/nfsd/Makefile
fs/nfsd/export.c
fs/nfsd/fault_inject.c [new file with mode: 0644]
fs/nfsd/fault_inject.h [new file with mode: 0644]
fs/nfsd/nfs4idmap.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4recover.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsd.h
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/notify/mark.c
fs/ntfs/super.c
fs/pipe.c
fs/proc/array.c
fs/proc/base.c
fs/proc/stat.c
fs/qnx4/inode.c
fs/squashfs/cache.c
fs/squashfs/inode.c
fs/squashfs/squashfs_fs_sb.h
fs/squashfs/super.c
fs/super.c
fs/ubifs/debug.c
fs/ubifs/debug.h
fs/ubifs/journal.c
fs/ubifs/replay.c
fs/ubifs/tnc.c
fs/ubifs/tnc_misc.c
fs/xfs/xfs_aops.c
fs/xfs/xfs_attr.c
fs/xfs/xfs_attr_leaf.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_dfrag.c
fs/xfs/xfs_file.c
fs/xfs/xfs_fs_subr.c
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_qm_syscalls.c
fs/xfs/xfs_super.c
fs/xfs/xfs_sync.c
fs/xfs/xfs_trace.h
fs/xfs/xfs_vnodeops.c
include/acpi/acnames.h
include/acpi/acpi_numa.h
include/acpi/acpiosxf.h
include/acpi/acpixf.h
include/acpi/acrestyp.h
include/acpi/actbl.h
include/acpi/actbl1.h
include/acpi/actbl3.h [new file with mode: 0644]
include/acpi/actypes.h
include/acpi/apei.h
include/asm-generic/gpio.h
include/asm-generic/param.h
include/asm-generic/tlb.h
include/drm/drm_crtc.h
include/linux/acct.h
include/linux/acpi.h
include/linux/acpi_io.h
include/linux/amba/mmci.h
include/linux/amba/pl061.h
include/linux/amba/pl08x.h
include/linux/audit.h
include/linux/bcma/bcma.h
include/linux/bio.h
include/linux/blkdev.h
include/linux/capability.h
include/linux/compiler-gcc.h
include/linux/console.h
include/linux/cpuidle.h
include/linux/crash_dump.h
include/linux/cred.h
include/linux/cuda.h
include/linux/dcache.h
include/linux/digsig.h
include/linux/display.h [deleted file]
include/linux/dmaengine.h
include/linux/dvb/frontend.h
include/linux/dvb/version.h
include/linux/dw_dmac.h
include/linux/elevator.h
include/linux/elf.h
include/linux/eventpoll.h
include/linux/fb.h
include/linux/fs.h
include/linux/ftrace.h
include/linux/fuse.h
include/linux/gfs2_ondisk.h
include/linux/huge_mm.h
include/linux/i2c/twl.h
include/linux/inet_diag.h
include/linux/init.h
include/linux/iocontext.h
include/linux/isdn_divertif.h
include/linux/kernel.h
include/linux/key.h
include/linux/kmemleak.h
include/linux/kmsg_dump.h
include/linux/kref.h
include/linux/linkage.h
include/linux/lockd/lockd.h
include/linux/memcontrol.h
include/linux/mfd/88pm860x.h
include/linux/mfd/abx500/ab5500.h [moved from include/linux/mfd/ab5500/ab5500.h with 100% similarity]
include/linux/mfd/abx500/ab8500-gpadc.h [moved from include/linux/mfd/ab8500/gpadc.h with 100% similarity]
include/linux/mfd/abx500/ab8500-gpio.h [moved from include/linux/mfd/ab8500/gpio.h with 100% similarity]
include/linux/mfd/abx500/ab8500-sysctrl.h [moved from include/linux/mfd/ab8500/sysctrl.h with 100% similarity]
include/linux/mfd/abx500/ab8500.h [moved from include/linux/mfd/ab8500.h with 100% similarity]
include/linux/mfd/max8925.h
include/linux/mfd/max8997.h
include/linux/mfd/mc13xxx.h
include/linux/mfd/mcp.h
include/linux/mfd/s5m87xx/s5m-core.h [new file with mode: 0644]
include/linux/mfd/s5m87xx/s5m-pmic.h [new file with mode: 0644]
include/linux/mfd/s5m87xx/s5m-rtc.h [new file with mode: 0644]
include/linux/mfd/stmpe.h
include/linux/mfd/ucb1x00.h
include/linux/migrate.h
include/linux/miscdevice.h
include/linux/mm_inline.h
include/linux/mm_types.h
include/linux/mmc/card.h
include/linux/mmc/cd-gpio.h [new file with mode: 0644]
include/linux/mmc/core.h
include/linux/mmc/dw_mmc.h
include/linux/mmc/host.h
include/linux/mmc/mmc.h
include/linux/mmc/sdhci-pci-data.h [new file with mode: 0644]
include/linux/mmc/sdhci.h
include/linux/mmc/sdio.h
include/linux/mmzone.h
include/linux/mod_devicetable.h
include/linux/module.h
include/linux/moduleparam.h
include/linux/mroute6.h
include/linux/mtd/gpmi-nand.h [new file with mode: 0644]
include/linux/netfilter/nf_conntrack_common.h
include/linux/netfilter/xt_CT.h
include/linux/nvme.h [new file with mode: 0644]
include/linux/oom.h
include/linux/page_cgroup.h
include/linux/pagevec.h
include/linux/patchkey.h
include/linux/phy.h
include/linux/pkt_sched.h
include/linux/pmu.h
include/linux/prctl.h
include/linux/ptrace.h
include/linux/radix-tree.h
include/linux/rmap.h
include/linux/sched.h
include/linux/security.h
include/linux/serial_core.h
include/linux/sh_dma.h
include/linux/sirfsoc_dma.h [new file with mode: 0644]
include/linux/sound.h
include/linux/soundcard.h
include/linux/sunrpc/svc_xprt.h
include/linux/sunrpc/svcsock.h
include/linux/tty_driver.h
include/linux/videodev2.h
include/linux/virtio.h
include/linux/virtio_ring.h
include/linux/zorro_ids.h
include/media/as3645a.h [new file with mode: 0644]
include/media/atmel-isi.h
include/media/cx25840.h
include/media/davinci/vpbe.h
include/media/davinci/vpbe_venc.h
include/media/media-entity.h
include/media/omap3isp.h
include/media/pwc-ioctl.h [deleted file]
include/media/rc-map.h
include/media/soc_camera.h
include/media/tuner.h
include/media/v4l2-ioctl.h
include/net/bluetooth/hci_core.h
include/net/flow.h
include/net/red.h
include/scsi/libfc.h
include/target/target_core_backend.h [new file with mode: 0644]
include/target/target_core_base.h
include/target/target_core_device.h [deleted file]
include/target/target_core_fabric.h [moved from include/target/target_core_fabric_ops.h with 50% similarity]
include/target/target_core_fabric_lib.h [deleted file]
include/target/target_core_tmr.h [deleted file]
include/target/target_core_tpg.h [deleted file]
include/target/target_core_transport.h [deleted file]
include/trace/events/btrfs.h
include/trace/events/vmscan.h
include/video/edid.h
include/video/omapdss.h
include/video/sh_mipi_dsi.h
include/video/sh_mobile_lcdc.h
include/xen/interface/io/blkif.h
init/Kconfig
init/main.c
kernel/Makefile
kernel/async.c
kernel/audit.c
kernel/audit.h
kernel/auditfilter.c
kernel/auditsc.c
kernel/capability.c
kernel/debug/kdb/kdb_main.c
kernel/exit.c
kernel/fork.c
kernel/irq/internals.h
kernel/irq/spurious.c
kernel/kexec.c
kernel/kprobes.c
kernel/module.c
kernel/panic.c
kernel/params.c
kernel/pid.c
kernel/pid_namespace.c
kernel/power/swap.c
kernel/printk.c
kernel/ptrace.c
kernel/sched/core.c
kernel/seccomp.c
kernel/sys.c
kernel/trace/ftrace.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_stack.c
kernel/tracepoint.c
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/decompress_unlzo.c
lib/mpi/mpicoder.c
lib/radix-tree.c
mm/compaction.c
mm/filemap.c
mm/huge_memory.c
mm/kmemleak.c
mm/ksm.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/migrate.c
mm/oom_kill.c
mm/page_alloc.c
mm/page_cgroup.c
mm/percpu.c
mm/rmap.c
mm/slub.c
mm/swap.c
mm/swap_state.c
mm/swapfile.c
mm/vmalloc.c
mm/vmscan.c
mm/vmstat.c
net/9p/trans_virtio.c
net/bluetooth/af_bluetooth.c
net/bluetooth/hci_event.c
net/bluetooth/hci_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/bridge/br_fdb.c
net/caif/caif_dev.c
net/caif/caif_usb.c
net/ceph/crush/mapper.c
net/ceph/crypto.c
net/ceph/osd_client.c
net/core/dev.c
net/core/net-sysfs.c
net/core/netpoll.c
net/core/rtnetlink.c
net/core/secure_seq.c
net/dccp/diag.c
net/decnet/dn_dev.c
net/decnet/netfilter/dn_rtmsg.c
net/ipv4/devinet.c
net/ipv4/fib_trie.c
net/ipv4/igmp.c
net/ipv4/inet_diag.c
net/ipv4/inetpeer.c
net/ipv4/ipconfig.c
net/ipv4/ipip.c
net/ipv4/ipmr.c
net/ipv4/netfilter/ip_queue.c
net/ipv4/ping.c
net/ipv4/tcp_diag.c
net/ipv4/tcp_memcontrol.c
net/ipv4/udp_diag.c
net/ipv6/addrconf.c
net/ipv6/datagram.c
net/ipv6/ip6_tunnel.c
net/ipv6/netfilter/ip6_queue.c
net/ipv6/proc.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/sit.c
net/mac80211/agg-rx.c
net/mac80211/cfg.c
net/mac80211/ibss.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/tx.c
net/mac80211/wpa.c
net/mac80211/wpa.h
net/netfilter/ipset/ip_set_core.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_ecache.c
net/netfilter/nf_conntrack_extend.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_log.c
net/netfilter/nf_queue.c
net/netfilter/nfnetlink.c
net/netfilter/xt_CT.c
net/netfilter/xt_hashlimit.c
net/netlabel/netlabel_domainhash.c
net/netlabel/netlabel_unlabeled.c
net/netlink/genetlink.c
net/openvswitch/datapath.c
net/openvswitch/datapath.h
net/openvswitch/flow.c
net/openvswitch/vport-internal_dev.c
net/openvswitch/vport.c
net/phonet/af_phonet.c
net/phonet/pn_dev.c
net/phonet/socket.c
net/rds/iw_rdma.c
net/sched/sch_sfq.c
net/socket.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/cache.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcsock.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/wireless/nl80211.c
net/xfrm/xfrm_user.c
scripts/Makefile.headersinst
scripts/Makefile.lib
scripts/checksyscalls.sh
scripts/coccicheck
scripts/coccinelle/api/devm_request_and_ioremap.cocci [new file with mode: 0644]
scripts/coccinelle/api/kstrdup.cocci
scripts/coccinelle/api/memdup.cocci
scripts/coccinelle/api/memdup_user.cocci
scripts/coccinelle/free/devm_free.cocci [new file with mode: 0644]
scripts/coccinelle/free/kfree.cocci
scripts/coccinelle/iterators/fen.cocci
scripts/coccinelle/iterators/itnull.cocci
scripts/coccinelle/locks/call_kern.cocci
scripts/coccinelle/locks/flags.cocci
scripts/coccinelle/locks/mini_lock.cocci
scripts/coccinelle/misc/doubleinit.cocci
scripts/coccinelle/null/eno.cocci
scripts/dtc/dtc.c
scripts/dtc/srcpos.c
scripts/dtc/srcpos.h
scripts/genksyms/Makefile
scripts/kconfig/Makefile
scripts/kconfig/confdata.c
scripts/kconfig/expr.h
scripts/kconfig/gconf.c
scripts/kconfig/lkc.h
scripts/kconfig/mconf.c
scripts/kconfig/merge_config.sh [new file with mode: 0644]
scripts/kconfig/streamline_config.pl
scripts/mod/file2alias.c
scripts/recordmcount.h
scripts/tags.sh
security/apparmor/include/apparmor.h
security/apparmor/lsm.c
security/capability.c
security/commoncap.c
security/integrity/Kconfig
security/integrity/Makefile
security/integrity/ima/ima_audit.c
security/integrity/ima/ima_policy.c
security/integrity/integrity.h
security/keys/encrypted-keys/encrypted.c
security/keys/encrypted-keys/masterkey_trusted.c
security/keys/gc.c
security/keys/keyring.c
security/keys/trusted.c
security/keys/user_defined.c
security/lsm_audit.c
security/security.c
security/selinux/hooks.c
security/tomoyo/util.c
sound/atmel/abdac.c
sound/atmel/ac97c.c
sound/core/Kconfig
sound/pci/au88x0/au88x0.c
sound/pci/au88x0/au88x0.h
sound/pci/au88x0/au88x0_pcm.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_sigmatel.c
sound/pci/intel8x0.c
sound/pci/oxygen/xonar_wm87x6.c
sound/soc/au1x/Kconfig
sound/soc/au1x/db1200.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/wm8993.c
sound/soc/ep93xx/ep93xx-pcm.c
sound/soc/imx/imx-pcm-dma-mx2.c
sound/soc/mxs/mxs-pcm.c
sound/soc/nuc900/nuc900-ac97.c
sound/soc/samsung/dma.c
sound/soc/sh/siu_pcm.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/txx9/txx9aclc.c
tools/lguest/.gitignore [moved from Documentation/virtual/lguest/.gitignore with 100% similarity]
tools/lguest/Makefile [moved from Documentation/virtual/lguest/Makefile with 100% similarity]
tools/lguest/extract [moved from Documentation/virtual/lguest/extract with 100% similarity]
tools/lguest/lguest.c [moved from Documentation/virtual/lguest/lguest.c with 99% similarity]
tools/lguest/lguest.txt [moved from Documentation/virtual/lguest/lguest.txt with 100% similarity]
tools/nfsd/inject_fault.sh [new file with mode: 0755]
tools/perf/Documentation/perf-list.txt
tools/perf/MANIFEST
tools/perf/builtin-annotate.c
tools/perf/builtin-kmem.c
tools/perf/builtin-kvm.c
tools/perf/builtin-script.c
tools/perf/builtin-test.c
tools/perf/builtin-top.c
tools/perf/util/evlist.c
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/parse-events.c
tools/perf/util/trace-event-info.c
tools/perf/util/util.c
tools/perf/util/util.h
tools/power/x86/turbostat/turbostat.c
tools/testing/ktest/compare-ktest-sample.pl
tools/testing/ktest/ktest.pl
tools/testing/ktest/sample.conf
tools/testing/selftests/Makefile [new file with mode: 0644]
tools/testing/selftests/breakpoints/Makefile [new file with mode: 0644]
tools/testing/selftests/breakpoints/breakpoint_test.c [new file with mode: 0644]
tools/testing/selftests/run_tests [new file with mode: 0644]
tools/virtio/linux/virtio.h
tools/virtio/virtio_test.c
virt/kvm/iommu.c

diff --git a/CREDITS b/CREDITS
index 44fce988eaac8cd22bfe5a5e753ae1bb58b3476d..370b4c7da39b2bd45ff098dc0b8062255e478ecb 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -514,6 +514,11 @@ S: Bessemerstraat 21
 S: Amsterdam
 S: The Netherlands
 
+N: NeilBrown
+E: neil@brown.name
+P: 4096R/566281B9 1BC6 29EB D390 D870 7B5F  497A 39EC 9EDD 5662 81B9
+D: NFSD Maintainer 2000-2007
+
 N: Zach Brown
 E: zab@zabbo.net
 D: maestro pci sound
index 8b093f8222d318e411113735f7e841c4b52e7ae0..91bd6ca5440f32dbe724c994728a2bee18060692 100644 (file)
@@ -346,6 +346,10 @@ Description:
                number of objects per slab.  If a slab cannot be allocated
                because of fragmentation, SLUB will retry with the minimum order
                possible depending on its characteristics.
+               When debug_guardpage_minorder=N (N > 0) parameter is specified
+               (see Documentation/kernel-parameters.txt), the minimum possible
+               order is used and this sysfs entry can not be used to change
+               the order at run time.
 
 What:          /sys/kernel/slab/cache/order_fallback
 Date:          April 2008
index 9489ea8e294c0eed0ffdabc27ef543cd32c6884d..47064c2b1f79b3cc4e1039323b7b43e9278735be 100644 (file)
@@ -33,3 +33,19 @@ Description: Maximum time allowed for periodic transfers per microframe (μs)
                Beware, non-standard modes are usually not thoroughly tested by
                hardware designers, and the hardware can malfunction when this
                setting differ from default 100.
+
+What:          /sys/module/*/{coresize,initsize}
+Date:          Jan 2012
+KernelVersion:»·3.3
+Contact:       Kay Sievers <kay.sievers@vrfy.org>
+Description:   Module size in bytes.
+
+What:          /sys/module/*/taint
+Date:          Jan 2012
+KernelVersion:»·3.3
+Contact:       Kay Sievers <kay.sievers@vrfy.org>
+Description:   Module taint flags:
+                       P - proprietary module
+                       O - out-of-tree module
+                       F - force-loaded module
+                       C - staging driver module
diff --git a/Documentation/DocBook/media/constraints.png.b64 b/Documentation/DocBook/media/constraints.png.b64
new file mode 100644 (file)
index 0000000..125b4a9
--- /dev/null
@@ -0,0 +1,59 @@
+iVBORw0KGgoAAAANSUhEUgAAAlQAAAFYCAYAAACVsmLPAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A
+/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9sLCBIAKVtZsMAAAAxxSURBVHja
+7d3ZbqvIAkDRLsv//8v0QytXvpYZap7Wko56OAnE2AXbBSbhOI7jHwAAkr1sAgAAQQUAIKgAAAQV
+AICgAgBAUAEACCoAAEEFACCoAAAQVAAAzb2jvyMEWw0AmFvh37xnhgoAQFABAPT1zvruwtNlAADV
+VLxsyQwVAICgAgAQVAAAggoAQFABACCoYEohuFkugKACsmLq178DIKiAyJgSVQCCCigQU6IKQFAB
+BWJKVAEIKqBgKIkqAEEFFAgkUQUgqIACYSSqAAQViKkwxjIAEFSwbUyJKgBBBWJq8GUCIKhgm5gS
+VQCCCsSUqAIQVMBYoSOqAAQVLOk41lwXAIIKhoqqJyFUYhkACCpYMqpiQqjEMgAQVLBUVKWEUIll
+ACCoYImoygmhEssAQFDBElHVexkACCoAAEEFACCoAAAQVAAAggoAQFABAAgqAAAEFQCAoAIAEFQA
+AIIKAABBBQAgqAAABBUAgKACAOA/b5sAGjsO2wBgMWaoAAAEFQCAoAIAEFQAADtzUXohIQQbAYDi
+Dh9kmYIZKgAAQQUAIKgAAAQVAICgAgAgmU/5VeSTGQDE8InxeZmhAgAQVAAAggoAQFABAAgqAAAE
+FQCAoAIAEFQAAHtyY0/o4O7efe4JCzAXM1QAAIIKAEBQAQAIKgAAQQUAgKACABBUAACCCgBAUAEA
+IKgAAAQVAICgAgAQVAAACCoAAEEFACCoAAAEFVBICGMsAwBBBVPHVE4QlVgGAIIKpo6ps/9utQwA
+BBUsEVMpQVRiGQAIKlgqpmKCqMQyABBUsGRMzbouAAQVNHMca64LAEEFy0WVmAIQVCCqxBSAoAL6
+hI+YAhBUIKrEFICgAvqEkJgCEFQgqo4+3wuAoILto0pMAQgqICOQxBSAoAIyQklMAQgqICOYxBSA
+oAIyokpMAQgqICOqxBTAvN42AYwTVQDMyQwVAICgAgAQVAAAggoAQFABAJDMp/y4FIJtwJx8ehJo
+yQwVAICgAgDoyyk/HnMKhdE5RQ30YoYKAEBQAQAIKgAAQQUAIKgAABBUAACCCgBAUAEACCoAAAQV
+AICgAgAQVAAAggoAAEEFACCoAAAEFQCAoAIAQFABAAgqAABBBQAgqAAAEFQAAIIKAEBQAQAIKgAA
+BBUAgKACABBUAACCCgAAQQUAIKgAAAQVAICgAgBAUAEACCoAAEEFACCoAAAQVAAAggoAQFABAAgq
+AACGCKoQPAs2JQAIquwCUAI2JQAIqowCOPtvbEoAEFQRBaAEbEoAEFQFCkAJ2JQAIKgKFIASsClh
+szEKrDGoXkNuiOPwwim4iezYoc9+39iDfQbVq+mGEFOiCjZ7E23swR6D6tV8Q4gpUQWb7PeNPdhn
+UL26bAgxJapgk/2+sQd7DKr3EDE1y96mUPT1fqgh6Ffosbsz9mDdQfXquiEY/rUKlBtLYgoqDJZB
+Dmjlg8qRWlSBMSSmYLOoKhtUjtCiCowdMQUbRtXLswUgpkBU5XkXf9CmPJZ9nQJrft6Gife9XmC/
+t0mHg9tr3FcJYgrmjilgn8Fa55SfI7WYAvtnYKNBW+8+VLGn/zY6wtd4qDY1iCngx+BtdNCre1G6
+W3gPt7MXUwAwW1CJKjEFCzB2wODtH1SiSkyB/TKw+KB9DfnARJWYAvtnYKLB+m7+AJ+UgL2WTQmT
+jz1jEJVf0ASD7jXck2/vY1PCQscwE+6wfkz1CaqrB6wAbEoQVcBkMdUvqH49cAVgU4KoAiaMqb5B
+9bkBFIBNCaIKmDSm+geVArApYaOxZ4zCuoPq5VkDqL//F1Ow9qASVACV9/9iCtYfVIIKoOL+X0zB
+HoNKUAFU2v+LKdhnUAkqgAZvqoG1B5WgAgAQVAAAggoAQFABAAgqAAAEFQCAoAIAEFQAAIIKAABB
+BQAgqAAABBUAgKACAEBQAQAIKgAAQQUAIKgAABBUAACCCgBAUAEACCoAAAQVAICgAgAY3NsmIEYI
+//3zONK/7u/v/nx+zdPl/1rO0++LWd6vZZ59Xe7jSfnZSq3z6jnJ2ValX09PHj9AD2aoiPJ34Lo6
+wJWKiJQD7N2BN/WAzbNtZTsCuzJDRZeD8XHkH3zPZo5CSJudeTKbdrX+lkE7QkzFbq8VHj/AGTNU
+dDkY1ziw1jjY7nAA/wzKqxnIu5gSPICggoTIuDroXh1YRz3ohuCUlcgESOOUH81iZdR1fJ9+zL1Q
+use1Y6nrvLsearR46rHNAQQVw6l14HtyOurJz5USVqs9LynXt8V+ShBAUMHHQfdzFuMsQGqHSW5M
+PQmrVtdsjRCkOwY5gKBiGne3Okg5WJaMqbuw2uX5+P6aX4H8/f922F4AgorlgyD3hp47z3ycPfZf
+p/FSb00BIKjg4kD8/cm4mFNjKfd/OpsJyb2GJ+V+UzEXSK9wAfuvqGr9s7ooHRiV2yYgDCe8xUOp
+gHny2GNjVdwAOzJDRbUYSfnep8srfdCOWV6tr225ztzt3PpxiTRgdGaoAAAEFQBAX075sbS7C6dH
+OJU0w8/ocQEIKjY2w0F71bAQTMBOnPIDABBUAAB9OeXHY36tCAD8ZoYKAEBQAQD05ZQfl3xSCwDu
+maECABBUAACCCgBAUAEACCqgiRDczwtAUAFZMfXr3wEQVEBkTIkqAEEFFIgpUQUgqIACMSWqAAQV
+UDCURBWAoAIKBJKoAhBUQIEwElUAggrEVBhjGQAIKtg2pkQVgKACMTX4MgEQVLBNTIkqAEEFYkpU
+AQgqYKzQEVUAggqWdBxrrgsAQQVDRdWTECqxDAAEFSwZVTEhVGIZAAgqWCqqUkKoxDIAEFSwRFTl
+hFCJZQAgqGCJqOq9DAAEFQCAoAIAEFQAAAgqAABBBQAwibdNAECqcPKLJo8fH1cNN7+U8up7jpOP
+v6as//PvPr+/xPpTlsEazFABUDSmnsRTie/pvX74ZIYKgKz4+J55+fu7EMLPWZmU2auY9YsjejBD
+BUDRmDk7pdZq/Vf/P2bZT7/2OI7/rU/ICSoAiHIVLS2uFyq5Dtc3kcspPwCairmQvHUghhBOT1U+
+eQx/fyfQBBUALBNrtcPmc/l/QYagAoDqYi9ib/2zPZ2l+hVw7Ms1VAAkKXXbgpIXkH9eIF7r8T15
+bEJLUAHA4wD6FQ5PPoVXc/0ll3/3db/+sCen/ABIio7PU3U5YfIdY0++78n6RzPqxfiUYYYKqh94
+rv/AzFGV8nelouLue3JC5e5XzTx57E777SUcsa+4zxeIo8HlOw/vOgBwLBlqA1drGDNUAACCCgBA
+UAEATM2n/CpyQSIA7MEMFQCAoAIAEFQAAIIKAGBnLkovxI3XAGBfZqgAAAQVAEBfTvlBbXf3I3O6
+GGB6ZqgAAAQVAICgAgAQVAAAggoAAEEFACCoAAAEFQCAoAIAQFABAAgqAABBBQAgqAAAEFQAAIIK
+AEBQAQAIKiBFCGMsAwBBBVPHVE4QlVgGAM29bQIoGFOf/30c7ZcBrV/zd6/Rq6/7fs1/fs3T5Z+9
+AckZO2dvaL6XeffGJ/XxpPxspdZ59ZzkbKve278BM1RQOqaeDvbSy4CW/g5WV6/RUhHRcuwYc2W2
+VY3tP/hzY4YKar5bfLIDeLIMM1WsOnaOI/9AeTZzETt2YmbTrtbfMmhH2PfFbq/Syxxk/2iGCmrF
+1Kzrgplez78OpjUOsDu8qfkMyqsZyLvwSdleNZYpqGASLQe3GSpGHgNXB92r1+6or+sQvInptV+a
+eF/nlB/kDv7aO14xxUpahErqOr7Hc+yF9y3Hbul13l27NPJ+aJBTgYIKRo4qMcXK46b2wTVlHb9m
+3VpcXD/i85Kyb4v9lGCvZQoq2CiqxBQzvfY/ZzHOAqR2mOTG1JOwanXN1ghBunucR3INFYw4qMUU
+K/sLsO9rlXKuXSoZU99jcfXxmPpp5LP7f5W+B9Ukz4GggtGiSkxBn5ja/UL0v3D5/nO1jyq1zWos
+szGn/KDGTinnoliY9TV/FzZnr++U+z+dfcIw93qblPtNxVwUvcIF7N/7uZJRlbLMQS5KN0MFtQ4w
+YgrWGberjs+Y21vExmqN/eDAz0M4jsifrtZ5alh5ZyWmAMbaJxfe75qhgl7veMUUwDIEFfSMKjEF
+sAQXpUOrqJrk5nSwpLvT7yOMxxl+Ro9LUMFQUSWmoP348zN6XIIK7FgAWDWo/DZuAAAXpQMACCoA
+gM7iT/m5BgQA4P+YoQIAEFQAAIIKAEBQAQAIKgAABBUAgKACABBUAAB7+hfHbDX87cMFJQAAAABJ
+RU5ErkJggg==
index 3bc8a61efe301a4b32bd89862efd28219e9315c4..c7a4ca51785980264b37b19b3b63987a3871fe33 100644 (file)
@@ -163,14 +163,16 @@ get/set up to 64 properties. The actual meaning of each property is described on
        <section id="DTV-FREQUENCY">
                <title><constant>DTV_FREQUENCY</constant></title>
 
-               <para>Central frequency of the channel, in HZ.</para>
+               <para>Central frequency of the channel.</para>
 
                <para>Notes:</para>
-               <para>1)For ISDB-T, the channels are usually transmitted with an offset of 143kHz.
+               <para>1)For satellital delivery systems, it is measured in kHz.
+                       For the other ones, it is measured in Hz.</para>
+               <para>2)For ISDB-T, the channels are usually transmitted with an offset of 143kHz.
                        E.g. a valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of
                        the channel which is 6MHz.</para>
 
-               <para>2)As in ISDB-Tsb the channel consists of only one or three segments the
+               <para>3)As in ISDB-Tsb the channel consists of only one or three segments the
                        frequency step is 429kHz, 3*429 respectively. As for ISDB-T the
                        central frequency of the channel is expected.</para>
        </section>
@@ -334,9 +336,10 @@ typedef enum fe_rolloff {
                <title>fe_delivery_system type</title>
                <para>Possible values: </para>
 <programlisting>
+
 typedef enum fe_delivery_system {
        SYS_UNDEFINED,
-       SYS_DVBC_ANNEX_AC,
+       SYS_DVBC_ANNEX_A,
        SYS_DVBC_ANNEX_B,
        SYS_DVBT,
        SYS_DSS,
@@ -353,6 +356,7 @@ typedef enum fe_delivery_system {
        SYS_DAB,
        SYS_DVBT2,
        SYS_TURBO,
+       SYS_DVBC_ANNEX_C,
 } fe_delivery_system_t;
 </programlisting>
                </section>
@@ -647,6 +651,18 @@ 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">
+               <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
+                       any other operation with the frontend. Prior to it's introduction,
+                       FE_GET_INFO was used to determine a frontend type. A frontend which
+                       provides more than a single delivery system, FE_GET_INFO doesn't help much.
+                       Applications which intends to use a multistandard frontend must enumerate
+                       the delivery systems associated with it, rather than trying to use
+                       FE_GET_INFO. In the case of a legacy frontend, the result is just the same
+                       as with FE_GET_INFO, but in a more structured format </para>
+       </section>
 </section>
        <section id="frontend-property-terrestrial-systems">
        <title>Properties used on terrestrial delivery systems</title>
@@ -721,14 +737,10 @@ typedef enum fe_hierarchy {
                        <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
                        <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
                        <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
                        <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
                        <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-CODE-RATE-HP"><constant>DTV_CODE_RATE_HP</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-CODE-RATE-LP"><constant>DTV_CODE_RATE_LP</constant></link></para></listitem>
                        <listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem>
                        <listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-HIERARCHY"><constant>DTV_HIERARCHY</constant></link></para></listitem>
                        <listitem><para><link linkend="DTV-ISDBT-LAYER-ENABLED"><constant>DTV_ISDBT_LAYER_ENABLED</constant></link></para></listitem>
                        <listitem><para><link linkend="DTV-ISDBT-PARTIAL-RECEPTION"><constant>DTV_ISDBT_PARTIAL_RECEPTION</constant></link></para></listitem>
                        <listitem><para><link linkend="DTV-ISDBT-SOUND-BROADCASTING"><constant>DTV_ISDBT_SOUND_BROADCASTING</constant></link></para></listitem>
@@ -767,7 +779,8 @@ typedef enum fe_hierarchy {
        <title>Properties used on cable delivery systems</title>
        <section id="dvbc-params">
                <title>DVB-C delivery system</title>
-               <para>The DVB-C Annex-A/C is the widely used cable standard. Transmission uses QAM modulation.</para>
+               <para>The DVB-C Annex-A is the widely used cable standard. Transmission uses QAM modulation.</para>
+               <para>The DVB-C Annex-C is optimized for 6MHz, and is used in Japan. It supports a subset of the Annex A modulation types, and a roll-off of 0.13, instead of 0.15</para>
                <para>The following parameters are valid for DVB-C Annex A/C:</para>
                <itemizedlist mark='opencircle'>
                        <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
index 61407eaba020342b40d6ba8d5588d4c30e07beb9..aeaed59d0f1f5d3d9baeff4af53eb803a7b50355 100644 (file)
@@ -45,8 +45,8 @@ transmission. The fontend types are given by fe_type_t type, defined as:</para>
   </row>
   <row>
      <entry id="FE_QAM"><constant>FE_QAM</constant></entry>
-     <entry>For DVB-C annex A/C standard</entry>
-     <entry><constant>SYS_DVBC_ANNEX_AC</constant></entry>
+     <entry>For DVB-C annex A standard</entry>
+     <entry><constant>SYS_DVBC_ANNEX_A</constant></entry>
   </row>
   <row>
      <entry id="FE_OFDM"><constant>FE_OFDM</constant></entry>
@@ -63,6 +63,10 @@ transmission. The fontend types are given by fe_type_t type, defined as:</para>
 <para>Newer formats like DVB-S2, ISDB-T, ISDB-S and DVB-T2 are not described at the above, as they're
 supported via the new <link linkend="FE_GET_SET_PROPERTY">FE_GET_PROPERTY/FE_GET_SET_PROPERTY</link> ioctl's, using the <link linkend="DTV-DELIVERY-SYSTEM">DTV_DELIVERY_SYSTEM</link> parameter.
 </para>
+
+<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>
 </section>
 
 <section id="fe-caps-t">
diff --git a/Documentation/DocBook/media/selection.png.b64 b/Documentation/DocBook/media/selection.png.b64
new file mode 100644 (file)
index 0000000..4161865
--- /dev/null
@@ -0,0 +1,206 @@
+iVBORw0KGgoAAAANSUhEUgAABIsAAAHpCAYAAAACi7yYAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A
+/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9sLCBAiCLMGMtAAACAASURBVHja
+7d3rkds4FgZQaMohTBY7ObRCV+fgyWJy4P6wJavVIgmSAIjHOVWu3bElPkBSAj5dgpdpmqYAAAAA
+ACGEvzQBAAAAAHfCIgAAAAAehEUAAAAAPAiLAAAAAHgQFgEAAADwICwCAAAA4EFYBAAAAMDDD00A
+21wul9XXTNN0aHnP749Z39o2rK0jRzssLX/pvVve9+61S69Jdey2bn/sMTx6TAAA/cIW+oVb+2tb
+3p+izwioLIJsHYe9X+a979vae89ut6Pb1+txBwD0C3vZN0ERrFNZBAct/ZJxuVx2Vdg8v+/oLyEx
+69j7xbq2/1u2e0u75Th2Mevf8ytVzDkDAOgXjtYv3LquVP0nQRHEUVkEBTsJve/r0hfu2hdz7e0W
+27HQ4QAA9Avr7BcJiiCesAhO+GKK/YIt8SV+RscoNmippUPl1jIAQL/w3PUc7Y8JimAbYRGc9KVY
+Yu6b3OsYNUTRuQAA9AvL9AtT9LsERbCdOYsAX74ZOiVbO1M6LQCAfmH7/TzohcoiqOhLK+eXV4p1
+xP4y1krF0X1bn7dXBwIA0C+ss19oagAoR1gEJ4j9osv5iPq965imKUk59eidwNc/AIB+oX7h/HpK
+tzeMzm1oQJIv7Ra/eO/7sOWxtgAAtN0v1N+DdcIiyPQFlPP1JbZpTyehl19q1joQOhgAgH7hOf3C
+Pct9tz36c7DMbWhQwPMXUYkOQ6517P3Sj/216axJEdfWoyMBAOgXpukX5uqv7Xm/W9JgnsoiSGxr
+4FHiiyvlOu7v21pu/PqLzuuvOTHtlmIZW/bz+f1r6177ewBAv1C/8FwqjCCesAgSdwK2dAh63e+5
+fX8XuBxtt1SdkZhy6djt37vNOioAoF84Sr8wV39tzzIERvCd29Agg7knQ8T+unTk15mc64j5El17
+KsbRW75inrqR6glj79rELWsAgH5hmn7hmcckpt8HI7tMRjYAAAAA/KayCAAAAIAHYREAAAAAD8Ii
+AAAAAB6ERQAAAAA8CIsAAAAAeBAWAQAAAPAgLAIAAADgQVgEAAAAwIOwCAAAAIAHYREAAAAADz80
+AQAAqVwuF40AABWbpmn1NbvDIh0BAKDGzg3n0T8EgD7sCot0BAAAmDNNUwj6iwBQlS3fzIduQ7vd
+blobAMjuer1qhKZ6o4IiAGiZOYsAAMji0w+LAHC6jx0/unkaGgAAAAAPwiIAAAAAHoRFAAAAADwI
+iwAAAAB4EBYBAAAA8OBpaAAAFDf3ZJa5J6htef3za5eeyDb3urWnxsQuM/V7jmxX7Dr3HIMUbfj6
++qXjurZ977Zja1vuaVOAnqgsAgCgqKWB+rt/2/r6s7Z/z3aesf0x+1fjdgFQjsoiALpyfRng3J5+
+Fb7/2+3NL8Xv/m1pWa/veX7t/XXXN4OtuWXs+fe59c/t45H2erd/Mdu/9XX0b63q5zWkWHr9/d8+
+rtfFapOY9byz9L7X5e7ZzqVKmT2VP3ts2cc966+1MmfuGKkkAvhFZREA3XgON94FNnMhzlJQNLes
+1/ffX/f62ue/fw1d3r3m9d/nlhu7/rX22rv8LW20d/voT8ztYbEBzNJrS4YMubbzzNCidLs+BzX3
+datsAjiXsAiALrwLfPYGE1uXtaVK5l2YNLes2OXurdI5svwtbaSKiFdbg5Cl18f821y1UupAZu92
+1njblwobgLG5DQ0AZqSofjkSnOSuvsmxf2fsB5SUMtT5vN2+LC82xNoziXaJNthyO11MBdHS7YUA
+5CUsAmAo91u97rdGLc1jdKQi5t08QiH8uSVrTcwcSkekWv7avuTeD1hzD2TuwcOWqqIS8wa9C01G
+nD/neV9fQzQAyhMWAUAma5NVA23KEeLMhUZHJ5g+e/9jXyscAqiLOYsA6MK7+XLW5gWK/fdnsYHP
+2uvWJtveu969ti5/bxsJzNgTDOx5JP2z1yAmNsC4T7j8+ifXdj6vs7VjlGsdQiSAc6gsAqAbz7eY
+Pf9dqmVtWd7cbWivE0LPbe/rv80tL1Vb7Vl+TBvl3g/a8nx70dIj7e9/v/b6mKer1bBfc9tZ65w8
+pdt1bh1zQdFaGwNw3GWapmnzmy6XQx1wAIAt7gHTjm4LJTuWv/uI084QYC482Pv6LfMSvXtc/Nag
+pNR+xb7+yLYeXX9MG669ZunYpN7mEeeJAsZx/4y7/P7vmP6U29AAAChq6yPm9z6S3n7t34/c648J
+Z97N49TKuQDQOpVFAED1VBY10rGMrCwCAMpRWQQAAADAIcIiAAAAAB48DQ0AADqSciJsAMYkLAIA
+gI4IgwA4SlgEAADAZh9/X9/+/ed/t8Ovf37t3PKWXje3rq3LTP2eI9sVs961969t59r2LbX16zJi
+t+Xzv1vyduE4YVHpD9SZsuDnX4COlA7HLD/Ferase2lZW7Zh6/a+vn6pDda27912rK0vVbsCAEB1
+45qFwf3H39dNIcm715fY/rWQKsV7Wj5me93Dn6VlxgZKnEdYVPLiXAgTPq7X6BBh7rWpln/kPWv7
+LigBAIDGxzUrVT+vocTS6+//thYs7A1plt73utw927kUeixt3xnhWEybzO13qe0VHtVDWFTq4nwK
+cmKDni2B0NLy7/82F/4srWdPYLRneVvWUWvgNNfuAjIAALoZ10TcHhYbwNz/LiYwStpvf3PbU47t
+zL0v727/WqvqijlmEEIIf2mCAh+oK0HR0UBhbflbbuVKsT1ry4vdhhRt/nm7PdZdYr0AADCCreHC
+0utj/m0u3EkdcuzdzntQ09MxS7Gud23iFrQ2qCwqeXFmrjBZWv7n7XZ6WFLDNgAAAGNLGeq8Vilt
+ndz53fKO7sMZc0DlPjaCpfKERTVfKBsmqy617hr2de21qeduAgAAzvM6YfKWypQS8wa9q6IpVT3z
+vPyYp4pBLGERu55i1sSXytO2q2oCAAAe44MMIc5caDQ3B1KSsVzF4dC7p6KthWgqiOohLKr5A2zj
+RNW511/LurY8NQ4AAEhv661OMY9RXxwDPAUP9/+OGjtsDB+ObufzOnMFOTHLnZvoWhhDLBNcl/xA
+PRherIUka7dfLS333Z/a9j/VOoRIAACwc0wy86SzL/3tmadvLU12/Pra2vZryz6V3OZ3f44eMwhB
+ZVGZi/jpFqi5qqAj1UJry495Gltupbdhbh1zQdFauwEAAL/72i+PkU/x+hoeRb93O/fMi1R6Iuet
+xyz1emNDQRNc10NYVOoieQl0jnoNN2KWXyoo2jMH0lnbfKTdzm5nAAA4bXyzMJnyXHVLC0FA7fsV
+cxveu7mCWjoG1EFYVPKDZ2GS5diAYW0ZtQYYJZ/gtrSuexs9h201txsAAFQ7vtkYMGx5/dHXHgk/
+atmvI+9PNYF0ioqvGqrG2O4yTdO0+U2XSwghhJuBNABQwPV3qL+j20LJjuXvPuL9KPnRBWCbtVvE
+hCrsOq9+96Muv/87pj+lsggAAKDFAeBLsCBIaJ9jSC2ERQAAAB0QHgGpCIuI++JZmZRbmTkAAFTW
+h98QHn1cPzQYFPR5+6x6+4RFRJ7IN40AAAA19dGfwp+Yx6HHPr4cQFgEAADQuNfwZy08inkEOzAu
+YREAAECjYiqKdvl50bg04Ujg+Xr7Ze5bw1q63VNYlPzgXzUCAP13zNyeDJB/bJErCAKKB0WtERYB
+AACcNWA9IRBy6xnDX3eColXCoowUbgLQk0kTAMQPRguFQItPOHuzDXuCoss/jieV9Ul+Hrg2TwqK
+WnvioLAIAABgy6CvgiBoz/apKGL4a1dQFE1YBAAA8DywK3hrWOoAJ1U1EXR3XQuKNhEWAQAAYwwW
+Gw6B9u6foAgERXsIiwAAgLYHgoUnia4tgBESwcL1UUlQ9Hn7bCo8EhYBAAB1DvJOenR860GLoAh+
+f4ZUFBS1RlgEAACUH8R5ZLx9hJyfMYKiQ4RFAABAuoGSEMj+w9mfQ4Kiw4RFAADA+iBICAS08Fkl
+KEpCWAQAACMPrMwLBPTyeSYoSkZYBAAAPQ6ahEDASJ95gqKkhEUAANDaoMgtYQB/PhMFRckJiwAA
+oJYBjxAIYNvnpqAoC2ERAADkHlQIgQDyf+4JipIRFgEAwN4Bg3mBAKogKEpLWAQAAK+DASEQQDME
+RekJiwAAGIpbwgD6ISjKQ1gEAEAXhEAAZPl+GSwoCkFYBABA7Z10IRAAZ30HDRgUhSAsAgDgrA64
+eYEAqPl7atCgKARhEQAAR/17CSGEMP186WSHa9HNEAIB70zTNMy+Xi4XBzyRkYOiEIRFAAAs+ff8
+gYcQCICSRg+KQhAWAQCMSQgE0J25KioVR/EERb8IiwAAenJGCPS/6ctgZHp0sG+OB0AFXkMk4dF7
+gqI/hEUAAC04qxLof5O2B6B7gqKvhEUAAGcSAgFQ2HOlkSojQdE7wiIAgFxOvCUMAFgnKHpPWAQA
+sJUQCIBOjFxlJCiaJywCALgTAgHAEARFy4RFAED/zAsEAKvuVUa9VxgJitYJi6DmD+uf7//+8s/6
+a969ds/yU6xn636uLWttu9e2dakdX5cRuy2Xf/K2ETBDCAQAbHBWUPS63toJi6BSS8HD9DM+eJh7
+barlH3nPme2y5h7+LC0zNlACdnaq/r5+v/Zzh0NCIADotsJIUBRPWAQ1fjg/BSKxQc+WQGhp+fd/
+mwtJltaTOzCKbZe5fSoV6giPYKXD9BQCFSMEAoCx+x+Cok2ERVCZtUBk6e9TLP/5dqrY8CfmFqy1
+7Xm+/evdenO3C5CgMyQEAoC+xibT1EV1kaBoO2ERVCp38LG0/CPhT+vt8q4dlsIrARVDdBTffB58
+hGv29X7+d3v8/+v1+ui0AgDEqiUo+rx9NhUeCYug48FcCOfPI7T3faXmQOrtWECJa/eo5xAIAKi8
+v9Dw/EU1BUWtERYByQaXe8OQ5/fVXNUEvVyruQiBAIBaCIqOERZBJ7ZOVJ17/bUParfs1+utaGu3
+oKkgIqczrpfHuf+l43NzMABgpD5IQ/MXCYqOExZBxQPCI6HDWoVOzCPhlwaNJQa8c3MFCWPo9Zov
+zbUEAPRGUJSGsAgqE/M0siOBydryY546VmKw+jpwzt0ukMtZlXOuBQAgeb+m8uoiQVE6wiKo0Gsw
+kmKwOjcvUEuTMadul63rjQ3STHA9SGdJCAQAUA1BUVrCIqjU0m1ksYPFtWWcFWrEPHZ+7rH1Z243
+43BLGADATD+pwuoiQVF6wiKoWMzgce01a4HMGQPZLWFXim3J3Y4G+w11boRAAABdERTlISwCoHlC
+IACAgn2v6dczUmurMBIUpSMsAqDejoh5gQAAiCAoSktYBBQf4BuIIwQCACAVQVF6wiLAgJyk3BIG
+AEApgqI8hEUARBECAQDwpX9Y4ZPRchgtKApBWATgS14IBAAAb40YFIUgLALolnmBAADI3ufsuLpo
+1KAoBGERQHtfyEIgAADIauSgKARhEUBV3BIGAEBzfdjOqotGD4pCEBYBlPkCFQIBAED1BEW/CIsA
+DhACAQCMpbYKmmmaqtmO1quLBEV/CIsA3n3ZmRcIAACGISj6SlgEDEUIBABAT16reWqpNGqJoOg7
+YRHQDbeEAQAAWwiK3hMWAdUTAgEAQGQ/9qnSqHSVUWvzFgmK5gmLgNMIgQAAgDMIipYJi4DkzAsE
+AADnu1f5mMfoK0HROmEREE0IBAAAtOysoOh1vbUTFgEhBLeEAQBAr0pWGNU8b5GgKJ6wCDonBAIA
+AEYnKNpGWASNEgIBAACb+vODzmEkKNpOWASVMS8QAABAGrUERZ+3z6bCI2ERFCIEAgAAanC5XLJW
+F9Uyb1FNQVFrhEWQ+oOxUCgkBAIAAHaPJzIHRmcTFB0jLILaPrSFQAAAALsJio4TFkEhQiAAAKCq
+MUqH1UWCojSERZD6A1coBAAAUJygKJ2/nE4AAABASqUrlgRFaaksghQfhD+1Af1QHQcAQEsERemp
+LAIAAIBB1fCI+yMERXkIiwAAAIDmCYrScRsaJOYWHlrkVkoAgIHHMB08FU1QlJbKIgAAAKBZgqL0
+hEUAAABAkwRFeQiLAAAAAGaMFhSFICwCAAAAeGvEoCgEYREAAADAN6MGRSEIiwAAAGB4l8sl+TJb
+fsLayEFRCCH8cEkAQJkOTo5OGAAAaY0eFIUgLAJgcCV/8VpalyAJAOB8gqJfhEUADKPmUuh32yZA
+AgAoR1D0h7CIrgduBlp9DqqdM4xyHj9vv3MTACAfQdFXwiKAmcH5K4P19o9hT/vlfAQASENQ9J2w
+iO4HjQZUGKyPeXxG2V/nIQCQyuVyGa5PJSh6T1iEgR0kOIcN2H2OOA8BANoiKJonLAIwYG+6vfne
+Ls5BAIBlgqJlf2kCeh/oGVRyxvntvNO22gkAoE6ConUqiwAyDthDUOWRsi1xDgIAHHFWUPS63tqp
+LAIoMGAXdhxrP5yDAABHCYriCYsYYuBnkIQBu/ZCmwIA4xIUbSMsAjhhwI42Ort9tTEAMApB0XbC
+IoYZABoY4Vpoo120jfMQACCVWoKi1ibRFhYBGKhrD+0OANAdQdF+wiKAkwfqBusCCwAA0hIUHSMs
+YqjBoAEp1Pe54LoEACAlQdFxP5xGAOebpilcLpfh9rkVKY6NUAwAID9BURrCIoBKjBQY1Rqc5Gz/
+uWULkQAA0hAUpSMsYriB4YgVHLR1rfR+ftb0eVBDW79ug/AIAGA7QVFawiJgqIH5O7UNznsOjGpo
+69rb9nn7BEcAAOsERekJixhuIN77YJxjg3OD9D4/C1q93gVHAADLBEV5CIsAKhyk9xZonhV09NSG
+giMAgGWConSERQCRg3QD9PaOmXMSAGAMgqJkHc0Qpin85ZQip5oHMgZZ7BmglwwhejlHS+/HSLeY
+lj4nAQBqJChK2nkPIQRhEW0NisAAvbXvmslxse8AgDFcNoKiPIRFGMhCxV9+LZ+jpYMitAMAQA6j
+BUUhCItoZKB4HwAZCGFwPt71v9b+joE2AQDa6sO1ZMSgKARhEUCSwTnaXfsAAPRl1KAoBGERmbSU
+SEvPcY62t72CkPh20lYAANuNHBSFICyikcGOQSKtnaejEhQ5PwEAWjd6UBSCsAjAgFwbD9N22g8A
+YJmg6BdhEcnlmNi6pW0G134egg7tCACQk6DoD2ERBjuAa157AgAMTVD0lbCIpFqu0FFdRM2D8NrP
+z5zbJ9jQrgBAe/25lvoagqLvhEU0O5Ax0IE+OxbU8zkLANA7QdF7wiIAqiXM0MYAALkIiuYJi0im
+xYmtc+4DBt+ue+0IAECdBEXLhEUYlAMAAAxstB/NBUXrhEUAVNepEAQDAJDDWUHR63prJyyiukHj
+1kFi6kGlW9HgXIIiAAD9uRwERfGERQAAAEDXBEXbCIs4rMdKHNVFcM41oqoIAMDYJzVB0XbCIqqy
+d6BogAkAAMCrWoKi1ibRFhYBsImqIgAA/boW+nSCov2ERVTz4VLbQNGtaAAAAG0SFB0jLKIbqhLA
+9QsAQJyefxwXFB0nLIJBP0BpSy1himsCAICaCYrSEBZRxaAx1UBYdQK9XRsAANBKf/Xs8ZigKB1h
+EQCnEvICAHCUoCgtYRG79Dyxdc59Bdc9AABn9ud67NMJitITFtEdVQoAAABjEBTl8cOpBZBOjl9q
+eg5AhbsAAG32UWvs1wmK0lFZxKkfNLk+UFIv1+03AAAA9RIUpaWyCCCRnkNFgSkAgD7cnLOrigRF
+6akswoDRvlMxt2kBAMA8QVEeKovodhB8uVwEPBTjXKvvMwAAQL9Uny6F0YKiEFQWAVT7hSxMAQCA
+c40YFIWgsoiTBsSlBsGpq4umaTKAJ9t1AQAALfVHex8bjRoUhaCyCKDKL+aavngFYgAAjGbkoCgE
+lUUAmwlPjlOhBwDoC+rP1Wr0oCgElUWc8IFY+kMl9fp8OYx9HZQ4/oIUAAA4h6DoF5VFACtKBoSC
+IgAAatdrn1VQ9IewiKID5V4+VEx07bz3pQsAAP0QFH0lLGIIqZ+KRl9qODcERQAAtDK26o2g6Dth
+EVCMwG6cL1wAAGiBoOg9E1xTbHB/9oDYRNfUSFAEAEAr/dbe+q6ConnCIoATv3BrJxQFAKBHgqJl
+bkMDKGz0aiLVVAAA+m5nEhStU1nErB6fguZWNM4+/wQlAABwnrOCotf11k5lEUBmAiIAAPRjzyco
+iqeyiLd6rCrKtT2qi5g7z1QSAQBAHQRF26gsAjhIIAQAgL5tvQRF26ksAjhomqYvfwAAgDrUEhS1
+Nom2yiLeDnxTqTWVvlwuBvUUuYZUHQEAUKve+6qCov2ERQAZCY4AAGihr9pbf1VQdIzb0Fj8sDjC
+wBi+X18q2gAAIC9B0XHCIoYlzOIsQiMAAGrup7bcVxUUpSEsAjjxyxgAAEhDUJSOsIgsA9dWqnZU
+F1HDdSc0AgBAP/UYQVFawiKASr6MAQCA7QRF6QmLACohMAIAoMY+as39VEFRHj+c+qQepLZ2a9fl
+ckm6/9M0ub2t4XPj7C9C5w8AAOwjKEpHWATw5F1QUzpAEhgBAFCbe5+41n6qoCgtt6ExdFVRru12
+O1FfLpfL40+L1yUAAPRMUJSesAhgg5LBkcAIAIDa1NZHFRTlISwC2KlEaCQwAgCAc40WFIUgLBqe
+W9Dybb9B/jgERgAAjDaOHKWPOmJQFIKwCCCJ0nMaAQAAeY0aFIUgLCLhQBnIdy2oLgIAoDY991FH
+DopCEBa5sMk60NfGzqPWz6cc++K6AACgZqMHRSEIiwCyUG0HAMAIevshUFD0i7DIBW1QnHl/VFHg
+fAIAgPoJiv744XQAyONyuQh3AIDmTdOkavqlj1fzsXKO7CMo+kplEUBjnQkBFAAApCMo+k5YNCC3
+oJXfL4N7AACgxDjm+U+r48ySBEXvCYsACnxp+zIGAIC6CIrmCYsGo6rovP0zuAfXAwD47qb0mKZk
+lVFL54mgaJkJrvGFAax2MlzvAAD0QlC0TmURQAGeIAIAwNn90RJVRrX/yHhWUPS63toJiwaiMsAx
+wPkEAACjEhTFExYBcAphFwDAOXJXGNXYzxMUbSMsAgAAALolKNpOWDQIv+A7Fpyv5XmLzLkEAOjH
+6p+2eL7UEhS1Nom2sAgAAADojqBoP2HRAPwC4JjgXLL9AAC8U+IJaWcQFB0jLAIAAAC6ISg6TlgE
+QBTzFgEA6OttcUYVuaAoDWFR59zi4diAawEAgBEIitIRFgEAABDFjzx9a7m6SFCUlrAIgFM7EAAA
+cISgKD1hUcek/o4RuBYAANiitR8HBUV5CIsAAACA5gmK0hEWdcqv9I4V5JLr1ybXAgDov+Kc2UtQ
+lJawCAAAAGiWoCi9H04rYpjU9iu/puAz4ZLlOpimyecNAECnfb0cBEV5qCzqkCDDMcNxBgAA0hgt
+KApBWEQEv/IDJQnVAACMA2sxYlAUgrDIIItqPjgdO1wHrgcAMO6AeowaFIUgLAJoml98AAAgvZGD
+ohCERRiIahuK6PXXN9VFAAD01rcbPSgKQVjk4sMxBNeENgYAIIQgKLoTFjFL5Qzgs6JvgiIAfI/A
+H4KiP4RFYJCMjpT2064AAEMTFH0lLNLpx7GkUTWFlbm3xXWhPQEAchEUfScsovpBKBiU+9wYrS21
+IwBAGYKi94RFOv5UOEB2TF2baNMcbaf9AICzxzo1ERTNExYB+OJuarsEHtoMAOAoQdEyYRHNDELB
+4NxniPbVVgD4nsH5cpSgaJ2wyMWGY4tjp507bR9tBADw1VlB0et6aycsAkg8QM+theq/UtsoENEm
+AACxBEXxhEU0NwgFA3SfJ+/aH+0AADBHULSNsMigAMeYho5Ta4Fu6cBo1GtGWAkAME9QtJ2wiGYH
+oWCA7rNl7rg4BwEACKGeoKi1SbSFRQ0PEHCsOW9wfsZxEehuP072DwD0Vxm3Dyoo2u+HUx+g/g5Q
+60HR5XI5pR3v6+whaNMRBwCIJyg6RlhENwMpMCCv/3PmrPZ9Xm9rn3fOSQCAbQRFxwmLDGZpYEA8
+TZPKiMHPKddHnvOwxrZ1nQAA7CcoSkNYBFCxHqv+agiM7l6344z2Fg4B0INeftyk7XNFUJSOsAgf
+6uDaPGXfagxJ5rYpxbEQCgEA5CMoSktY1BiDjXEHwn6tGe8ccp347AUAYJ2gKL2/nFYGpIDr8sx9
+9TkEAMBegqI8hEUN8cu2Ab9zwHljv9H2AADvCYrSERYBGLTbf20OANA0QVFa5iwySABci1W1hQo6
+5xwAwBaCovRUFjXC4MmAzLngHBmpTbSLcw4AIIagKA+VRQAG7FW3kYDUOQcAcKbRgqIQVBY1IcdA
+yaDBOcF5A3bXn88r5xwAQBtGDIpCUFkERQZqwh0M1tO0n2vJOQcAUMqoQVEIwiIAA/YG21No5JwD
+AMhp5KAoBLehVc8taAZvJc8N0h1vt/6UaWO0CQB9j13gDKMHRSGoLAJINlDn3HYfsYPqvAMASEtQ
+9IuwyMACcB11dVxGCI2cgwAA6QmK/hAWVUwZZ3+Du9THdJomg0aDcRaOXS+fo85HAIC8BEVfCYsM
+DnBMnX8Mc821FB65BgFokR8zaZGg6DthEaT+gvypDaBW7zqvNQRIOtUAAOcQFL0nLAJgaEtBTcog
+SSAEAFAXQdE8YREAzBDwAAD0SVC0TFgEKQaU//z637lb0O7/DgAAwLkEReuERVBAzDxGAiUAAIC8
+zgqKXtdbO2ERVGItUBImAQDQRL/WE9G6O569EBTFExZBQnOBToonpKlOAgAA2EdQtI2wCAqICXEE
+SgAAAOkJirYTFkEl1kKcFGFS7HIESgAAHOpzuhWNStQSFH3ePpsKj4RF0IhS1UkxyxEmAQAAtasp
+KGqNsAg64nY3AACg6jFLoYozQdExwiIY7cPZ7W4AAEDHBEXHCYuAL2q63S12ewAAgPSmaWpumwVF
+aQiLgM3MnwQAANRGUJSOsAjIwvxJAABj80Q0ShIUpSUsAk5j/iQA8i3Z/QAADThJREFUAOAoQVF6
+wiKgWm53AwAAlgiK8hAWAU1zuxsAABCCoCglYRHQPYESAAD0TVCUlrAIIJg/CQAAWiUoSk9YBBDB
+/EkAADv6NZ6IxnM/NsO5ICjKQ1gEkOrLz+1uAADQndGCohCERQBFCZQAAGjBNE0aIYwZFIUgLAKo
+jvmTAADgfKMGRSEIiwCaY/4kAKAl5i1q85iNbuSgKARhEUCX3O4GAAD7jB4UhSAsAhiW290AACjW
+92ykukxQ9IuwCID3X+gV3e4Wuz0AALCXoOgPYREAu5k/CQCgL6POVyQo+kpYBEBW5k8CAKBmgqLv
+hEUAnM78SQDQN09Ea+c4jUZQ9J6wCIDqmT8JAIDUBEXzhEUAdMH8SQAAB/o3g1UVCYqWCYsAGIb5
+kwAAEBStExYBwBPzJwEAI1FR9HnKemsnLAKADdzuBgDQJkFRPGERACTmdjcAePO95YloVR6TIn2j
+Co67oGgbYREAnECgBABQhqBoO2ERAFTK/EkAQA4jzVNUS1D0eftsKjwSFgFAo86cP+kjXL92gP67
+OSAAQFVqCopaIywCgI6VCpQ+/r6uvkagBIB5i85t+1P6Iicdb0HRMcIiABhcqdvdBEoAQAmCouOE
+RQDAonuYNH3p/Ny+do4igqCoTtbMch6B1b+XEP43OSgAEOHsuYnOqCoSFKUhLAIADoupCEoVKIV/
+VzqewiQAGJKgKB1hEQBQRLFA6d+IXzEFSgB0aKSnnH3rQwiKkhIWAQDVmAuUrtfrr05wovmTBEoA
+0A9BUXrCIgCgHTEBzr+J5kcQKAGEEH7NO5OyYqX1J6KNXL2z9bwpQVCUh7AIAOhLTYGSMAkAihEU
+pSMsAgDGUypQUp0EwIDOqBwTFKUlLAIAeGctxHG7GwBUQVCUnrAIAGAPt7sBwDelq4oERXkIiwAA
+cnG7G9BRAGCSa2LOkx6NFhSFICwCADiXQAkAqjViUBSCsAgAoH7mTwKgcj1WFY0aFIUgLAIAaF8l
+8ydNP0O4/ONwANC+kYOiEIRFAABjKBQoTT+fOtrhGvWez/9ujg80wLxFLJ0bPRk9KApBWAQAwF2p
+291eO+V/X1dfI1ACoARB0S/CIgAA4qyESZfL5UtlUdLOu0AJoEo9VRUJiv4QFgEAkG7Q8E8I06OT
+fYvrnEcEQSmWI0wCYPY7RFD0hbAIAIBTxYQ4KQIl1UkA6ago6puwCACA6q2FOKWqk2K2BYB2CIre
+ExYBANC8UtVJscsRKNErT0Tjfh70QFA0T1gEAMAQagqUhEkA5xIULRMWAQDAfbBg/iSAWSqKxiEs
+AgCADcyfBNCus4Ki1/XWTlgEAAAJud0NtjFvUf1UFKVdbwuERQAAUJjb3QDKEhRtIywCAIAKCZSo
+VeonolH3se6BoGg7YREAADTK/EkAK59flQRFn7fPpsIjYREAAHTK/EnAXj1UFdUUFLVGWAQAAANz
+uxvQI0HRMcIiAABgkUCJV6nnLfJEtHqOaw8ERccJiwAAgMPMnwTUQFCUhrAIAADIzvxJUKeeKroE
+RekIiwAAgCq43S3xAPZpPwVk9E5QlJawCAAAaEYNt7u1GLx8/H0VGNHtvFCCovSERQAAQDdKVCe1
+WpkkMKJHgqI8hEUAAMBQSlQn1TBv0ud/t2/bkTIw8kS0Oo3choKidIRFAAAAzwO/CsKkmO2I3Zec
+gRFUc90KipISFgEAAGwZlJ44b9KekCdnYNRCFYtqpQGuSUFRcsIiAACAlAPXjPMm7b29TYUR3V5v
+gqIshEUAAAClB7iZAqWt74kJjKafjhdjGy0oCkFYBAAAUKV3IU6qW9y+L3PS4PDu+hgwKApBWAQA
+ANCMUvMlAeMGRSEIiwAAALqR6va2PXMZnTWwtl7r7Wm9tRAWAQAADCBn1ZEgwXqtty/Coozc9QsA
+AJwt5glqHwb01mu9p663NsIiAACAzsQERAb01mu9day3RsIiAACATpQKiUYc0Fuv9Y5EWJTY5+2m
+EQAAgHrGKAkDolEH9NZrvaMRFgEAAHQoR0g04oDeeq13RMIiAACATuQKiEYd0Fuv9Y7qL00AAACA
+Ab31Wi93wiIAAAAM6K3XenkQFgEAAGBAb73WW3C9tRMWAQAAYEBvvdZbaL0tEBYBAABgQG+91ltg
+va0QFgEAAGBAb73Wm3m9LREWAQAAMEuQYL3W2856UxEWAQAA8JYBvfVabzvrTekyTdO0+U2XSwgh
+hNvt5tMTAMjuer2GEELY0W2hZMfydx9xenSO9RWhFS3fLgMtKhkgffzuR11+/3dMf0plEQAAAAAP
+wiIAAAAAHn5oAgAAgLG1OKcKkI/KIgAAAAAehEUAAAAAPAiLAAAAAHgQFgEAAADwYIJrAAAAivq4
+frz9+7mJtre8/vm1SxN3z71ubl1bl5n6PUe2K3adW4/DWvsfPb5737PlmJrc/T2VRQAAABSzNHB/
+929bX3/W9u/ZzjO2/+gxOrrcrcve856alt8qlUUAAAAUsVb18zpoX3r9/d8+rh+L1Sdbq19itu91
+uXu28/73qapz9tiyjyWWneo9Z+xvb1QWAQAAkF3M7WGxAczSa3Pac9vbnu08M7RYu+3r8/b5eM3W
+dj/aFjmO8xnnUQuERQAAABSzNQhZen3Mv81VK6UOZPZu52i3Qe1p99zhmYqi79yGBgAAABFShjqf
+t88vy4sNsfZMon10H9fmYzozbMndHqMSFgEAANCleyBzDzS2VBWVmDfoXfVTrsqnFPv4/HevYRd9
+ERYBAABApBwhzlxodHRC59T7WGM4pIIoD2ERAAAAxWy9bWntaWdrnquL7v8dY2sIcXQ7n9d55oTd
+e7Z9yzHds2+520OF1HcmuAYAACC7mKdOzT1ZbG0enVqeHrZlO1sLKO5PQXv9s8WeY5b7ONdyHtVG
+ZREAAABFPM9zs6UqaOn1MQP8Ek/T2rOde+ZFamVC55T7lqo9SsxD1QuVRQAAABSz9RHzex9Jb7+O
+i7l1b8utc3uqkfa8p6blt+oyTdO0+U2XSwghhNvtpgUBgOyu12sIIYQd3RZKdix/9xGnRwdcXxEA
+zvbxux91+f3fMf0plUUAAAAAPJizCACA09yrxl7NVbBvef3za5cq4udeN7eurctM/Z4j2xW7ztT7
+eH/t2nGda//YZS7tz1q77DlmAL1SWQQAwCmWBvbv/m3r68/a/j3becb2x+5jDccixTLn9qXm9oc9
+Pq4fi38gRrHKopikvvQvG3vWs+fLxS8yfpEBAOb7DDH9taXX3//ter0u9pP29AvXtu91uXu2c6mP
+d6RftsWWdR89FiXsOWZ7zw+ojcmaSaFIZVGqXx5S/nqzd3v37r9fZAAA1sOGd3+/9votPz6msue2
+tz3bWWvgcsaxOLq81tof4EzZK4u2/mq05XVry1/7ZWPLLw4pvlBTbXcNHQS/yAAAOfoae19/u90W
+K5zvP3jN9V9S9lf2budaFXlpe6uacrRnquW11P4AZ8paWbT1V6PUy6/h1wO/yPjCBQD6kzNcWqrk
+fve61z9792duOTX05e7bkONHyL3tD9CzIreh5f6CWftlo9aORMntzn1Puy9XAKBmr2HDliqSEkHK
+7XYTWpx8fmh/gD9+1LhRZ06SfOQLodQEhEe+BN+VYKdc9mtbqCoCAHqVo5/zroJmy5QKqfclV9+x
+tr7snvYH6NmPkXe+9nCn1Q6T0AgAiO2LbekjrD3tLKav8lwtErvuPU/KPbKdc/2qVo5diW0+crtd
+D+0PkNtfNW7UvQz0tRz0zKdb7Nnu5+2v5YumxPbMlfECALz2tbY+DGTtCbO1PBxky3a21E86eiy2
+PiE4VT+9l/YHKKVIZdHR0s21JyDs/WWjhvmM/CIDAIzouX+3pSpo6fUxfbsSc2nu2c49fdaUUzds
+DWy27mOq45dif1K1P0DPslYWbf3VKPXya3uKQ6rt9osMANCDrQ/7qPmhJr3u17uK8b3bnGo/j94F
+0Op5BVDSZZqmafObLpdNH55rQcJrBcrWx83HLv/19ak+/Pc+Qn7rdqfc19flbA1+UuwLAGz9rt3R
+baFkx/J3H/F+lD59/wPA6T5+96Muv/87pj9VZM6iFGn93mXU8uQGv8gAAAAALShSWQQAcITKokY6
+liqLAKA6eyqLfmg2AADoj2kCANhLWAQAAB0SBgGwl7BohV9kAAAAgJEIi1YIgwAAAICRCIsAAMji
+Y6VCGwCo01+aAAAAAIA7lUUAACR10QQA0PZ3+TRN0+Y3XXQBAIDydnRbKNmx1EcEgC76UyqLAAAo
+1vkEAOq3KyzSEQAAAADokwmuAQAAAHgQFgEAAADwICwCAAAA4EFYBAAAAMCDsAgAAACAB2ERAAAA
+AA/CIgAAAAAehEUAAAAAPAiLAAAAAHgQFgEAAADwICwCAAAA4EFYBAAAAMCDsAgAAACAB2ERAAAA
+AA/CIgAAAAAehEUAAAAAPAiLAAAAAHgQFgEAAADwICwCAAAA4EFYBAAAAMCDsAgAAACAB2ERAAAA
+AA/CIgAAAAAe/g/10lQlA3JSSwAAAABJRU5ErkJggg==
index afc8a0dd2601d47425205c67977c793cc2f9bbd6..cea6fd3ed4289281bf8942485ad0923a59b84bc2 100644 (file)
@@ -178,11 +178,3 @@ in the frequency range from 87,5 to 108,0 MHz</title>
     </biblioentry>
 
   </bibliography>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index a86f7a04552914a5a460096703cc721dcdebc055..c79278acfb0ec6c1942808b788b1fe25b65fa726 100644 (file)
@@ -1168,6 +1168,8 @@ dheight = format.fmt.pix.height;
     </section>
   </section>
 
+  &sub-selection-api;
+
   <section id="streaming-par">
     <title>Streaming Parameters</title>
 
@@ -1195,11 +1197,3 @@ separate parameters for input and output devices.</para>
     <para>These ioctls are optional, drivers need not implement
 them. If so, they return the &EINVAL;.</para>
   </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index b68698f96e7f723b07c0005a2a1f955df724a73b..c736380b4647acc649f2203b09c394802cd6180e 100644 (file)
@@ -1082,7 +1082,7 @@ until the time in the timestamp field has arrived. I would like to
 follow SGI's lead, and adopt a multimedia timestamping system like
 their UST (Unadjusted System Time). See
 http://web.archive.org/web/*/http://reality.sgi.com
-/cpirazzi_engr/lg/time/intro.html. 
+/cpirazzi_engr/lg/time/intro.html.
 UST uses timestamps that are 64-bit signed integers
 (not struct timeval's) and given in nanosecond units. The UST clock
 starts at zero when the system is booted and runs continuously and
@@ -2376,6 +2376,23 @@ that used it. It was originally scheduled for removal in 2.6.35.
         <listitem>
          <para>V4L2_CTRL_FLAG_VOLATILE was added to signal volatile controls to userspace.</para>
         </listitem>
+        <listitem>
+         <para>Add selection API for extended control over cropping and
+composing. Does not affect the compatibility of current drivers and
+applications.  See <link linkend="selection-api"> selection API </link> for
+details.</para>
+        </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 3.3</title>
+      <orderedlist>
+        <listitem>
+         <para>Added <constant>V4L2_CID_ALPHA_COMPONENT</constant> control
+           to the <link linkend="control">User controls class</link>.
+         </para>
+        </listitem>
       </orderedlist>
     </section>
 
@@ -2489,6 +2506,9 @@ ioctls.</para>
         <listitem>
          <para>&VIDIOC-CREATE-BUFS; and &VIDIOC-PREPARE-BUF; ioctls.</para>
         </listitem>
+        <listitem>
+         <para>Selection API. <xref linkend="selection-api" /></para>
+        </listitem>
       </itemizedlist>
     </section>
 
@@ -2507,11 +2527,3 @@ interfaces and should not be implemented in new drivers.</para>
       </itemizedlist>
     </section>
   </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 3bc5ee8b2c749ced60196d119e35b07295a42c45..a1be37897ad72682234a8aea99fdcc3fb172f9b8 100644 (file)
@@ -323,12 +323,6 @@ minimum value disables backlight compensation.</entry>
            <entry>Switch on or off the illuminator 1 or 2 of the device
                (usually a microscope).</entry>
          </row>
-         <row>
-           <entry><constant>V4L2_CID_LASTP1</constant></entry>
-           <entry></entry>
-           <entry>End of the predefined control IDs (currently
-<constant>V4L2_CID_ILLUMINATORS_2</constant> + 1).</entry>
-         </row>
          <row>
            <entry><constant>V4L2_CID_MIN_BUFFERS_FOR_CAPTURE</constant></entry>
            <entry>integer</entry>
@@ -345,6 +339,25 @@ and used as a hint to determine the number of OUTPUT buffers to pass to REQBUFS.
 The value is the minimum number of OUTPUT buffers that is necessary for hardware
 to work.</entry>
          </row>
+         <row id="v4l2-alpha-component">
+           <entry><constant>V4L2_CID_ALPHA_COMPONENT</constant></entry>
+           <entry>integer</entry>
+           <entry> Sets the alpha color component on the capture device or on
+           the capture buffer queue of a mem-to-mem device. When a mem-to-mem
+           device produces frame format that includes an alpha component
+           (e.g. <link linkend="rgb-formats">packed RGB image formats</link>)
+           and the alpha value is not defined by the mem-to-mem input data
+           this control lets you select the alpha component value of all
+           pixels. It is applicable to any pixel format that contains an alpha
+           component.
+           </entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_LASTP1</constant></entry>
+           <entry></entry>
+           <entry>End of the predefined control IDs (currently
+             <constant>V4L2_CID_ALPHA_COMPONENT</constant> + 1).</entry>
+         </row>
          <row>
            <entry><constant>V4L2_CID_PRIVATE_BASE</constant></entry>
            <entry></entry>
@@ -3329,6 +3342,16 @@ interface and may change in the future.</para>
                  <entry>The short circuit protection of the flash
                  controller has been triggered.</entry>
                </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_FAULT_OVER_CURRENT</constant></entry>
+                 <entry>Current in the LED power supply has exceeded the limit
+                 specific to the flash controller.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_FAULT_INDICATOR</constant></entry>
+                 <entry>The flash controller has detected a short or open
+                 circuit condition on the indicator LED.</entry>
+               </row>
              </tbody>
            </entrytbl>
          </row>
@@ -3357,11 +3380,3 @@ interface and may change in the future.</para>
 
     </section>
 </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "common.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 2237c661f26aceb3a65ec5992bc0dc8e542c7752..e1c5f9406d6ac21208840e53b7648849416e8411 100644 (file)
@@ -108,11 +108,3 @@ linkend="mmap">memory mapping</link> or <link
 linkend="userp">user pointer</link>) I/O. See <xref
 linkend="io" /> for details.</para>
   </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 6e156dc45b94dd9d0cf74466ae3166a2d41d28fd..dca0ecd54dc699fa92e1cab272e665423712cd45 100644 (file)
@@ -16,11 +16,3 @@ Applications send data to be converted to the driver through a
 I/O.</para>
 
   <para>[to do]</para>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 9c243beba0e609556ae9d0c17d570554cdbce59a..2350a67c0710480470fc8693d407d51db18aca2e 100644 (file)
@@ -15,11 +15,3 @@ receive the result data either with &func-read; and &func-write;
 functions, or through the streaming I/O mechanism.</para>
 
   <para>[to do]</para>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index f14ae3fe107cf364b8c7d409eb7230f93257a73b..19f4becfae34bac8e377c92ca273d1776c148921 100644 (file)
@@ -41,11 +41,3 @@ intermediate step leading up to that information. See the documentation for the
 event you want to subscribe to whether this is applicable for that event or not.</para>
        </listitem>
       </orderedlist></para>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index c9a68a2ccd33bc840616854ac6f3194b6bd1751a..479d9433869aff1e18fdc12d3c2aa1d0bbee772b 100644 (file)
@@ -154,11 +154,3 @@ data flow. For more information see <xref linkend="crop" />.</para>
 however the framebuffer interface of the driver may support the
 <constant>FBIOBLANK</constant> ioctl.</para>
   </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 919e22c538542c001747b69a9c9639c511044f60..9130a3dc7880e4f906642f248c2de554d4b17752 100644 (file)
@@ -104,11 +104,3 @@ linkend="mmap">memory mapping</link> or <link
 linkend="userp">user pointer</link>) I/O. See <xref
 linkend="io" /> for details.</para>
   </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 92513cf791503aa4ddbb6771314a1f8102423aa7..40d1d76814394815f5067785dd31a5d5fb957b35 100644 (file)
@@ -369,11 +369,3 @@ reasons. <!-- video4linux-list@redhat.com on 22 Oct 2002 subject
     <para>To start or stop the frame buffer overlay applications call
 the &VIDIOC-OVERLAY; ioctl.</para>
   </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 73aa90b45b34f6b256676b4e9992ec8e7e261116..3e6ac73b36af5155b8716715a8005b3b8e6d7934 100644 (file)
@@ -47,11 +47,3 @@ depending on the selected frequency. The &VIDIOC-G-TUNER; or
 &VIDIOC-G-MODULATOR; ioctl
 reports the supported frequency range.</para>
   </section>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
- -->
index c5a70bdfaf27a5f7aacf697e1a3fd6471c0bb9cb..b788c72c885e04f16109ea17b2026061fdeb0e9f 100644 (file)
@@ -337,11 +337,3 @@ an &EBUSY; if the required hardware resources are temporarily
 unavailable, for example the device is already in use by another
 process.</para>
   </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 2427f54397e7a28b45d8836befdaee9f8f00d323..38883a419e65674092aa4265ac4f637ff80211a4 100644 (file)
@@ -29,10 +29,10 @@ returned by the &VIDIOC-QUERYCAP; ioctl.  Any tuner that supports RDS
 will set the <constant>V4L2_TUNER_CAP_RDS</constant> flag in
 the <structfield>capability</structfield> field of &v4l2-tuner;.  If
 the driver only passes RDS blocks without interpreting the data
-the <constant>V4L2_TUNER_SUB_RDS_BLOCK_IO</constant> flag has to be
+the <constant>V4L2_TUNER_CAP_RDS_BLOCK_IO</constant> flag has to be
 set, see <link linkend="reading-rds-data">Reading RDS data</link>.
 For future use the
-flag <constant>V4L2_TUNER_SUB_RDS_CONTROLS</constant> has also been
+flag <constant>V4L2_TUNER_CAP_RDS_CONTROLS</constant> has also been
 defined. However, a driver for a radio tuner with this capability does
 not yet exist, so if you are planning to write such a driver you
 should discuss this on the linux-media mailing list: &v4l-ml;.</para>
@@ -52,9 +52,9 @@ field of &v4l2-modulator;.
 In order to enable the RDS transmission one must set the <constant>V4L2_TUNER_SUB_RDS</constant>
 bit in the <structfield>txsubchans</structfield> field of &v4l2-modulator;.
 If the driver only passes RDS blocks without interpreting the data
-the <constant>V4L2_TUNER_SUB_RDS_BLOCK_IO</constant> flag has to be set. If the
+the <constant>V4L2_TUNER_CAP_RDS_BLOCK_IO</constant> flag has to be set. If the
 tuner is capable of handling RDS entities like program identification codes and radio
-text, the flag <constant>V4L2_TUNER_SUB_RDS_CONTROLS</constant> should be set,
+text, the flag <constant>V4L2_TUNER_CAP_RDS_CONTROLS</constant> should be set,
 see <link linkend="writing-rds-data">Writing RDS data</link> and
 <link linkend="fm-tx-controls">FM Transmitter Control Reference</link>.</para>
   </section>
@@ -194,11 +194,3 @@ as follows:</para>
       </tgroup>
     </table>
   </section>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
- -->
index 69e789fa7f7b450cd4d01f86ff36691dfa76ee43..548f8ea28dee97862c1c07a4e39947d7ee790160 100644 (file)
@@ -697,12 +697,3 @@ Sliced VBI services</link> for a description of the line payload.</entry>
 
   </section>
   </section>
-
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
- -->
index 414b1cfff9f48f50d27cd2784eb433c8fa4ef400..bd21c64d70f3dfc0a310bf2271028ae6d0af03d4 100644 (file)
@@ -27,11 +27,3 @@ kernel 2.6.37.</para>
 
   <para>Modern devices all use the <link linkend="raw-vbi">raw</link> or
 <link linkend="sliced">sliced</link> VBI API.</para>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 1f7eea5c4ec35de5ec6a5dbc56a80889b62743b3..eacafe312cd26e4cad3bcdbcc9bb398d50546f66 100644 (file)
@@ -198,11 +198,3 @@ devices with the videodev module.</para>
     <para>to do</para>
   </section>
 -->
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index dfb41cbbbec3dea5a98dd12d59f47b7dfc03a40c..232920d2f3c64c2f68a081fcc9f37173fe587cef 100644 (file)
@@ -60,11 +60,3 @@ descriptor.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 2de64be706f59fce8e1cabe42459b1bbbf196a60..4394184a1a6db2fb0653dd3974d9a6adf835c13f 100644 (file)
@@ -69,11 +69,3 @@ their respective function and parameters are specified in <xref
     the parameter remains unmodified.</para>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 786732b64bbde3b2aef4e087aae0ab01933b3bc1..f31ad71bf301adf19ebe656afca04305c9858337 100644 (file)
@@ -181,11 +181,3 @@ complete the request.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index e2c4190f9bb609a623a7f11994c138b66aee3ffc..860d49ca54a5c18af62d98229414f41b693777f6 100644 (file)
@@ -74,11 +74,3 @@ mapped yet.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 7595d07a8c72d4be090c982dc902ff96ab9357db..cf64e207c3ee36252a91fa0ad18ded5404c52c3b 100644 (file)
@@ -111,11 +111,3 @@ system has been reached.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index ec3c718f59631fc1afe0acd412e1ebe0b9c869a6..85cad8bff5ba79aecec18c721650d5994137bbc7 100644 (file)
@@ -117,11 +117,3 @@ than <constant>OPEN_MAX</constant>.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index a5089bf8873d88304798211e06152eed1fd5a894..e218bbfbd362ae7bc247913df8c478fa1002dbcd 100644 (file)
@@ -179,11 +179,3 @@ type of device.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index b6713623181f1fb396b8df3c2bbc08b4d5f3de94..e12a60d9bd85b079c857d2f31485d3f4f387de5a 100644 (file)
@@ -128,11 +128,3 @@ zero or greater than <constant>FD_SETSIZE</constant>.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 2c09c09371c3bc33555211e15ec677b96b12ee28..575207885726b4584e3234a0070acdec0f8e6614 100644 (file)
@@ -126,11 +126,3 @@ type of device.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 3f47df1aa54aba5d9c46ab57533a2ddfe9fe3461..b815929b5bbaf30ee62a7b2f987c54141a384702 100644 (file)
@@ -1282,11 +1282,3 @@ line, top field first. The bottom field is transmitted first.</entry>
        </mediaobject>
     </figure>
   </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 3cb10ec5192947fd731831b00cc7e2b5fcb5c4df..d3b71e20003c354994d609b191146561c6578cb6 100644 (file)
@@ -158,10 +158,3 @@ still don't use libv4l.</para>
        </section>
 
 </section>
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 3b72bc6b2de7a29e1351e2814cc0edeb4326bb91..bee970d3f76d42553fdaca13798e59825b998d4e 100644 (file)
@@ -60,11 +60,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index ce4bc019e5c0351ee86ec12abff513571c9bf32f..aadae92c5d049369c8169d0725b5c9dccef95a43 100644 (file)
@@ -137,11 +137,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 873f670351819cff59b519b2955eb11fe9d6c4f4..84dd4fd7cb80bb76219c18484d8ca07f0d890653 100644 (file)
@@ -141,11 +141,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index c9e166d9ded8385f6bd7c4372d7dc0978bab3368..3fd3ce5df270563a7e9e1bfc26fa968498e9b1f4 100644 (file)
@@ -144,11 +144,3 @@ CbCr plane has as many pad bytes after its rows.</para>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 7a2855a526c1119a734a5c5a6d1b30f4de66c0c5..2f82b1da8dfed50185c33e2bd36d6e11800234d0 100644 (file)
@@ -64,11 +64,3 @@ layout of macroblocks</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 26094035fc04b1c13a3630979e3ae2b58fd5f86b..8ae1f8a810d0d1963f93d3311aa9baee12c90c0a 100644 (file)
@@ -164,11 +164,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv24.xml b/Documentation/DocBook/media/v4l/pixfmt-nv24.xml
new file mode 100644 (file)
index 0000000..fb255f2
--- /dev/null
@@ -0,0 +1,121 @@
+    <refentry>
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_NV24 ('NV24'), V4L2_PIX_FMT_NV42 ('NV42')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname id="V4L2-PIX-FMT-NV24"><constant>V4L2_PIX_FMT_NV24</constant></refname>
+       <refname id="V4L2-PIX-FMT-NV42"><constant>V4L2_PIX_FMT_NV42</constant></refname>
+       <refpurpose>Formats with full horizontal and vertical
+chroma resolutions, also known as YUV 4:4:4. One luminance and one
+chrominance plane with alternating chroma samples as opposed to
+<constant>V4L2_PIX_FMT_YVU420</constant></refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>These are two-plane versions of the YUV 4:4:4 format. The three
+       components are separated into two sub-images or planes. The Y plane is
+       first, with each Y sample stored in one byte per pixel. For
+       <constant>V4L2_PIX_FMT_NV24</constant>, a combined CbCr plane
+       immediately follows the Y plane in memory. The CbCr plane has the same
+       width and height, in pixels, as the Y plane (and the image). Each line
+       contains one CbCr pair per pixel, with each Cb and Cr sample stored in
+       one byte. <constant>V4L2_PIX_FMT_NV42</constant> is the same except that
+       the Cb and Cr samples are swapped, the CrCb plane starts with a Cr
+       sample.</para>
+
+       <para>If the Y plane has pad bytes after each row, then the CbCr plane
+       has twice as many pad bytes after its rows.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_NV24</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="9" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;16:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                     <entry>Cb<subscript>02</subscript></entry>
+                     <entry>Cr<subscript>02</subscript></entry>
+                     <entry>Cb<subscript>03</subscript></entry>
+                     <entry>Cr<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;24:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                     <entry>Cb<subscript>12</subscript></entry>
+                     <entry>Cr<subscript>12</subscript></entry>
+                     <entry>Cb<subscript>13</subscript></entry>
+                     <entry>Cr<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;32:</entry>
+                     <entry>Cb<subscript>20</subscript></entry>
+                     <entry>Cr<subscript>20</subscript></entry>
+                     <entry>Cb<subscript>21</subscript></entry>
+                     <entry>Cr<subscript>21</subscript></entry>
+                     <entry>Cb<subscript>22</subscript></entry>
+                     <entry>Cr<subscript>22</subscript></entry>
+                     <entry>Cb<subscript>23</subscript></entry>
+                     <entry>Cr<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;40:</entry>
+                     <entry>Cb<subscript>30</subscript></entry>
+                     <entry>Cr<subscript>30</subscript></entry>
+                     <entry>Cb<subscript>31</subscript></entry>
+                     <entry>Cr<subscript>31</subscript></entry>
+                     <entry>Cb<subscript>32</subscript></entry>
+                     <entry>Cr<subscript>32</subscript></entry>
+                     <entry>Cb<subscript>33</subscript></entry>
+                     <entry>Cr<subscript>33</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
index 4db272b8a0d33305c1f9c785755dd4addf27b1d8..166c8d65e4f72ced74e3c359203f157316b62235 100644 (file)
@@ -428,8 +428,11 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
     <para>Bit 7 is the most significant bit. The value of a = alpha
 bits is undefined when reading from the driver, ignored when writing
 to the driver, except when alpha blending has been negotiated for a
-<link linkend="overlay">Video Overlay</link> or <link
-linkend="osd">Video Output Overlay</link>.</para>
+<link linkend="overlay">Video Overlay</link> or <link linkend="osd">
+Video Output Overlay</link> or when alpha component has been configured
+for a <link linkend="capture">Video Capture</link> by means of <link
+linkend="v4l2-alpha-component"> <constant>V4L2_CID_ALPHA_COMPONENT
+</constant> </link> control.</para>
 
     <example>
       <title><constant>V4L2_PIX_FMT_BGR24</constant> 4 &times; 4 pixel
@@ -930,11 +933,3 @@ See &v4l-dvb; for access instructions.</para>
 
   </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 3cab5d0ca75df71e6bc9e658ca50a541e1e4a138..33fa5a47a865f6c0ea8727ef6dd44fd2ba801baa 100644 (file)
@@ -234,11 +234,3 @@ linkend="osd">Video Output Overlay</link>.</para>
 
   </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 519a9efbac108b0ca61957027204dc2f2d4286f4..6494b05d84a147f4ddb1ee1d91e4fcfcee1b662b 100644 (file)
@@ -81,11 +81,3 @@ pixel image</title>
     </example>
   </refsect1>
 </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 5fe84ecc2ebeb77927e6bed6263d64e3518b15ec..5eaf2b42d3f7069d296c8760f6e9c08ddc555be8 100644 (file)
@@ -65,11 +65,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index d67a472b0880b45e61a420b57854e6f0a41b9c26..fee65dca79c5209a2b29288388c5c8e1eb574faf 100644 (file)
@@ -65,11 +65,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 0cdf13b8ac1ca71a3a70b8bd3e1284ed3cf14c93..19727ab4c75752035bc59c89b693a0a3242c95cf 100644 (file)
@@ -65,11 +65,3 @@ columns and rows.</para>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 816c8d467c16b0d657abe3118f0cf00643426918..b1f6801a17ff7cde887aee7775c77c1acd0fc901 100644 (file)
@@ -118,11 +118,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 61f12a5e68d92dba5a9b3b88ec24c2cb2caf263f..82803408b38923cab052208e830c6434e266d329 100644 (file)
@@ -118,11 +118,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index d584040150784472191303f413bdcd9315e74d7c..ff4f727d56242c26e1c547bfb1356f36992b63f1 100644 (file)
@@ -79,11 +79,3 @@ pixel image</title>
     </example>
   </refsect1>
 </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 73c8536efb05b8e868208786611501d8f6f394df..98dcb91d29172af0e6aa7d2100a79637b9740245 100644 (file)
@@ -147,11 +147,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 8eb4a193d7707c6ab6cd9aa5a9ddc33ad4fad5cf..0869dce5f92c76e49217e6824685ad81ef44e6a5 100644 (file)
@@ -131,11 +131,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 00e0960a986902bb2e467a4ab2ae6c3b51a62845..086dc731bf0251a5096b66330bd4d9b3e832670e 100644 (file)
@@ -145,11 +145,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 42d7de5e456d77a22d3911f1c85c5149b7ff8d82..48649fac15969e2ff756e4ee30682c7aa43a4afa 100644 (file)
@@ -147,11 +147,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index f5d8f57495c840e9117b480ac68dc3dc5ab8c1b8..9957863daf18d4a4627a74b52fbfe3bd1141b87e 100644 (file)
@@ -152,11 +152,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 4348bd9f0d01ff015eb29527094cade95289c81c..4ce6463fe0a57f226f22ea4788a9bbd70c5aec28 100644 (file)
@@ -151,11 +151,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index bdb2ffacbbccaf7b500600750efaea0a839cdb31..58384092251a4dcf8bf2e4210f2ded56ad7bd5c1 100644 (file)
@@ -118,11 +118,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 40d17ae39dde0cd399c54d35d96cccce25149f4b..bfffdc76d3daffbaa4e58828ba1cfb7f3e5f18e5 100644 (file)
@@ -118,11 +118,3 @@ pixel image</title>
        </example>
       </refsect1>
     </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
index 2ff6b7776d7fe9f483ae4a00e713292fdb1d751d..31eaae2469f9b4ee48f1f13b1fbcf956f8fb9f54 100644 (file)
@@ -714,6 +714,7 @@ information.</para>
     &sub-nv12m;
     &sub-nv12mt;
     &sub-nv16;
+    &sub-nv24;
     &sub-m420;
   </section>
 
@@ -890,6 +891,11 @@ kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.hm
            <entry>'M310'</entry>
            <entry>Compressed BGGR Bayer format used by the gspca driver.</entry>
          </row>
+         <row id="V4L2-PIX-FMT-JL2005BCD">
+           <entry><constant>V4L2_PIX_FMT_JL2005BCD</constant></entry>
+           <entry>'JL20'</entry>
+           <entry>JPEG compressed RGGB Bayer format used by the gspca driver.</entry>
+         </row>
          <row id="V4L2-PIX-FMT-OV511">
            <entry><constant>V4L2_PIX_FMT_OV511</constant></entry>
            <entry>'O511'</entry>
@@ -997,11 +1003,3 @@ the other bits are set to 0.</entry>
       </tgroup>
     </table>
   </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/media/v4l/selection-api.xml b/Documentation/DocBook/media/v4l/selection-api.xml
new file mode 100644 (file)
index 0000000..2f0bdb4
--- /dev/null
@@ -0,0 +1,321 @@
+<section id="selection-api">
+
+  <title>Experimental API for cropping, composing and scaling</title>
+
+      <note>
+       <title>Experimental</title>
+
+       <para>This is an <link linkend="experimental">experimental</link>
+interface and may change in the future.</para>
+      </note>
+
+  <section>
+    <title>Introduction</title>
+
+<para>Some video capture devices can sample a subsection of a picture and
+shrink or enlarge it to an image of arbitrary size. Next, the devices can
+insert the image into larger one. Some video output devices can crop part of an
+input image, scale it up or down and insert it at an arbitrary scan line and
+horizontal offset into a video signal. We call these abilities cropping,
+scaling and composing.</para>
+
+<para>On a video <emphasis>capture</emphasis> device the source is a video
+signal, and the cropping target determine the area actually sampled. The sink
+is an image stored in a memory buffer.  The composing area specifies which part
+of the buffer is actually written to by the hardware. </para>
+
+<para>On a video <emphasis>output</emphasis> device the source is an image in a
+memory buffer, and the cropping target is a part of an image to be shown on a
+display. The sink is the display or the graphics screen. The application may
+select the part of display where the image should be displayed. The size and
+position of such a window is controlled by the compose target.</para>
+
+<para>Rectangles for all cropping and composing targets are defined even if the
+device does supports neither cropping nor composing. Their size and position
+will be fixed in such a case. If the device does not support scaling then the
+cropping and composing rectangles have the same size.</para>
+
+  </section>
+
+    <section>
+      <title>Selection targets</title>
+
+      <figure id="sel-targets-capture">
+       <title>Cropping and composing targets</title>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="selection.png" format="PNG" />
+         </imageobject>
+         <textobject>
+           <phrase>Targets used by a cropping, composing and scaling
+            process</phrase>
+         </textobject>
+       </mediaobject>
+      </figure>
+    </section>
+
+  <section>
+
+  <title>Configuration</title>
+
+<para>Applications can use the <link linkend="vidioc-g-selection">selection
+API</link> to select an area in a video signal or a buffer, and to query for
+default settings and hardware limits.</para>
+
+<para>Video hardware can have various cropping, composing and scaling
+limitations. It may only scale up or down, support only discrete scaling
+factors, or have different scaling abilities in the horizontal and vertical
+directions. Also it may not support scaling at all. At the same time the
+cropping/composing rectangles may have to be aligned, and both the source and
+the sink may have arbitrary upper and lower size limits. Therefore, as usual,
+drivers are expected to adjust the requested parameters and return the actual
+values selected. An application can control the rounding behaviour using <link
+linkend="v4l2-sel-flags"> constraint flags </link>.</para>
+
+   <section>
+
+   <title>Configuration of video capture</title>
+
+<para>See figure <xref linkend="sel-targets-capture" /> for examples of the
+selection targets available for a video capture device.  It is recommended to
+configure the cropping targets before to the composing targets.</para>
+
+<para>The range of coordinates of the top left corner, width and height of
+areas that can be sampled is given by the <constant> V4L2_SEL_TGT_CROP_BOUNDS
+</constant> target. It is recommended for the driver developers to put the
+top/left corner at position <constant> (0,0) </constant>.  The rectangle's
+coordinates are expressed in pixels.</para>
+
+<para>The top left corner, width and height of the source rectangle, that is
+the area actually sampled, is given by the <constant> V4L2_SEL_TGT_CROP_ACTIVE
+</constant> target. It uses the same coordinate system as <constant>
+V4L2_SEL_TGT_CROP_BOUNDS </constant>. The active cropping area must lie
+completely inside the capture boundaries. The driver may further adjust the
+requested size and/or position according to hardware limitations.</para>
+
+<para>Each capture device has a default source rectangle, given by the
+<constant> V4L2_SEL_TGT_CROP_DEFAULT </constant> target. This rectangle shall
+over what the driver writer considers the complete picture.  Drivers shall set
+the active crop rectangle to the default when the driver is first loaded, but
+not later.</para>
+
+<para>The composing targets refer to a memory buffer. The limits of composing
+coordinates are obtained using <constant> V4L2_SEL_TGT_COMPOSE_BOUNDS
+</constant>.  All coordinates are expressed in pixels. The rectangle's top/left
+corner must be located at position <constant> (0,0) </constant>. The width and
+height are equal to the image size set by <constant> VIDIOC_S_FMT </constant>.
+</para>
+
+<para>The part of a buffer into which the image is inserted by the hardware is
+controlled by the <constant> V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target.
+The rectangle's coordinates are also expressed in the same coordinate system as
+the bounds rectangle. The composing rectangle must lie completely inside bounds
+rectangle. The driver must adjust the composing rectangle to fit to the
+bounding limits. Moreover, the driver can perform other adjustments according
+to hardware limitations. The application can control rounding behaviour using
+<link linkend="v4l2-sel-flags"> constraint flags </link>.</para>
+
+<para>For capture devices the default composing rectangle is queried using
+<constant> V4L2_SEL_TGT_COMPOSE_DEFAULT </constant>. It is usually equal to the
+bounding rectangle.</para>
+
+<para>The part of a buffer that is modified by the hardware is given by
+<constant> V4L2_SEL_TGT_COMPOSE_PADDED </constant>. It contains all pixels
+defined using <constant> V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> plus all
+padding data modified by hardware during insertion process. All pixels outside
+this rectangle <emphasis>must not</emphasis> be changed by the hardware. The
+content of pixels that lie inside the padded area but outside active area is
+undefined. The application can use the padded and active rectangles to detect
+where the rubbish pixels are located and remove them if needed.</para>
+
+   </section>
+
+   <section>
+
+   <title>Configuration of video output</title>
+
+<para>For output devices targets and ioctls are used similarly to the video
+capture case. The <emphasis> composing </emphasis> rectangle refers to the
+insertion of an image into a video signal. The cropping rectangles refer to a
+memory buffer. It is recommended to configure the composing targets before to
+the cropping targets.</para>
+
+<para>The cropping targets refer to the memory buffer that contains an image to
+be inserted into a video signal or graphical screen. The limits of cropping
+coordinates are obtained using <constant> V4L2_SEL_TGT_CROP_BOUNDS </constant>.
+All coordinates are expressed in pixels. The top/left corner is always point
+<constant> (0,0) </constant>.  The width and height is equal to the image size
+specified using <constant> VIDIOC_S_FMT </constant> ioctl.</para>
+
+<para>The top left corner, width and height of the source rectangle, that is
+the area from which image date are processed by the hardware, is given by the
+<constant> V4L2_SEL_TGT_CROP_ACTIVE </constant>. Its coordinates are expressed
+in in the same coordinate system as the bounds rectangle. The active cropping
+area must lie completely inside the crop boundaries and the driver may further
+adjust the requested size and/or position according to hardware
+limitations.</para>
+
+<para>For output devices the default cropping rectangle is queried using
+<constant> V4L2_SEL_TGT_CROP_DEFAULT </constant>. It is usually equal to the
+bounding rectangle.</para>
+
+<para>The part of a video signal or graphics display where the image is
+inserted by the hardware is controlled by <constant>
+V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target.  The rectangle's coordinates
+are expressed in pixels. The composing rectangle must lie completely inside the
+bounds rectangle.  The driver must adjust the area to fit to the bounding
+limits.  Moreover, the driver can perform other adjustments according to
+hardware limitations. </para>
+
+<para>The device has a default composing rectangle, given by the <constant>
+V4L2_SEL_TGT_COMPOSE_DEFAULT </constant> target. This rectangle shall cover what
+the driver writer considers the complete picture. It is recommended for the
+driver developers to put the top/left corner at position <constant> (0,0)
+</constant>. Drivers shall set the active composing rectangle to the default
+one when the driver is first loaded.</para>
+
+<para>The devices may introduce additional content to video signal other than
+an image from memory buffers.  It includes borders around an image. However,
+such a padded area is driver-dependent feature not covered by this document.
+Driver developers are encouraged to keep padded rectangle equal to active one.
+The padded target is accessed by the <constant> V4L2_SEL_TGT_COMPOSE_PADDED
+</constant> identifier.  It must contain all pixels from the <constant>
+V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target.</para>
+
+   </section>
+
+   <section>
+
+     <title>Scaling control.</title>
+
+<para>An application can detect if scaling is performed by comparing the width
+and the height of rectangles obtained using <constant> V4L2_SEL_TGT_CROP_ACTIVE
+</constant> and <constant> V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> targets. If
+these are not equal then the scaling is applied. The application can compute
+the scaling ratios using these values.</para>
+
+   </section>
+
+  </section>
+
+  <section>
+
+    <title>Comparison with old cropping API.</title>
+
+<para>The selection API was introduced to cope with deficiencies of previous
+<link linkend="crop"> API </link>, that was designed to control simple capture
+devices. Later the cropping API was adopted by video output drivers. The ioctls
+are used to select a part of the display were the video signal is inserted. It
+should be considered as an API abuse because the described operation is
+actually the composing.  The selection API makes a clear distinction between
+composing and cropping operations by setting the appropriate targets.  The V4L2
+API lacks any support for composing to and cropping from an image inside a
+memory buffer.  The application could configure a capture device to fill only a
+part of an image by abusing V4L2 API.  Cropping a smaller image from a larger
+one is achieved by setting the field <structfield>
+&v4l2-pix-format;::bytesperline </structfield>.  Introducing an image offsets
+could be done by modifying field <structfield> &v4l2-buffer;::m:userptr
+</structfield> before calling <constant> VIDIOC_QBUF </constant>. Those
+operations should be avoided because they are not portable (endianness), and do
+not work for macroblock and Bayer formats and mmap buffers.  The selection API
+deals with configuration of buffer cropping/composing in a clear, intuitive and
+portable way.  Next, with the selection API the concepts of the padded target
+and constraints flags are introduced.  Finally, <structname> &v4l2-crop;
+</structname> and <structname> &v4l2-cropcap; </structname> have no reserved
+fields. Therefore there is no way to extend their functionality.  The new
+<structname> &v4l2-selection; </structname> provides a lot of place for future
+extensions.  Driver developers are encouraged to implement only selection API.
+The former cropping API would be simulated using the new one. </para>
+
+  </section>
+
+   <section>
+      <title>Examples</title>
+      <example>
+       <title>Resetting the cropping parameters</title>
+
+       <para>(A video capture device is assumed; change <constant>
+V4L2_BUF_TYPE_VIDEO_CAPTURE </constant> for other devices; change target to
+<constant> V4L2_SEL_TGT_COMPOSE_* </constant> family to configure composing
+area)</para>
+
+       <programlisting>
+
+       &v4l2-selection; sel = {
+               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               .target = V4L2_SEL_TGT_CROP_DEFAULT,
+       };
+       ret = ioctl(fd, &VIDIOC-G-SELECTION;, &amp;sel);
+       if (ret)
+               exit(-1);
+       sel.target = V4L2_SEL_TGT_CROP_ACTIVE;
+       ret = ioctl(fd, &VIDIOC-S-SELECTION;, &amp;sel);
+       if (ret)
+               exit(-1);
+
+        </programlisting>
+      </example>
+
+      <example>
+       <title>Simple downscaling</title>
+       <para>Setting a composing area on output of size of <emphasis> at most
+</emphasis> half of limit placed at a center of a display.</para>
+       <programlisting>
+
+       &v4l2-selection; sel = {
+               .type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               .target = V4L2_SEL_TGT_COMPOSE_BOUNDS,
+       };
+       struct v4l2_rect r;
+
+       ret = ioctl(fd, &VIDIOC-G-SELECTION;, &amp;sel);
+       if (ret)
+               exit(-1);
+       /* setting smaller compose rectangle */
+       r.width = sel.r.width / 2;
+       r.height = sel.r.height / 2;
+       r.left = sel.r.width / 4;
+       r.top = sel.r.height / 4;
+       sel.r = r;
+       sel.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
+       sel.flags = V4L2_SEL_FLAG_LE;
+       ret = ioctl(fd, &VIDIOC-S-SELECTION;, &amp;sel);
+       if (ret)
+               exit(-1);
+
+        </programlisting>
+      </example>
+
+      <example>
+       <title>Querying for scaling factors</title>
+       <para>A video output device is assumed; change <constant>
+V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> for other devices</para>
+       <programlisting>
+
+       &v4l2-selection; compose = {
+               .type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               .target = V4L2_SEL_TGT_COMPOSE_ACTIVE,
+       };
+       &v4l2-selection; crop = {
+               .type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               .target = V4L2_SEL_TGT_CROP_ACTIVE,
+       };
+       double hscale, vscale;
+
+       ret = ioctl(fd, &VIDIOC-G-SELECTION;, &amp;compose);
+       if (ret)
+               exit(-1);
+       ret = ioctl(fd, &VIDIOC-G-SELECTION;, &amp;crop);
+       if (ret)
+               exit(-1);
+
+       /* computing scaling factors */
+       hscale = (double)compose.r.width / crop.r.width;
+       vscale = (double)compose.r.height / crop.r.height;
+
+       </programlisting>
+      </example>
+
+   </section>
+
+</section>
index 2ab365c10fb91083b9defe3e57d215cae8688450..e97c512861bb352320d8be206945a2bb5c82d8b7 100644 (file)
@@ -501,6 +501,7 @@ and discussions on the V4L mailing list.</revremark>
     &sub-g-output;
     &sub-g-parm;
     &sub-g-priority;
+    &sub-g-selection;
     &sub-g-sliced-vbi-cap;
     &sub-g-std;
     &sub-g-tuner;
index 1d31427edd1b8510b01f5fdce56216c82f6f751d..0be17c232d3a6a30cf2b8b0099fd3a9ce3907151 100644 (file)
@@ -228,11 +228,3 @@ is out of bounds.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 71d373b6d36a31ac50bed40aaebf0c67a51eff23..347d142e74313230518224aba7d69f7368fcf53d 100644 (file)
@@ -156,11 +156,3 @@ bounds.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 476fe1d2bba0f52db78753e3a39eeaf79333a20a..9b8efcd6e947058e2f8cb1f8b55cf363bea7c8a2 100644 (file)
@@ -311,11 +311,3 @@ out of bounds.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index a281d26a195fbb501fcd96059080b8965ff7a69f..a64d5ef103faf959dfd2c71398f00f0aa162eef7 100644 (file)
@@ -196,11 +196,3 @@ is out of bounds.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 95803fe2c8e4336a8e110d87a0570d1de98ef378..3a5fc5405f96a869f0ff93262211c430dcbd4123 100644 (file)
@@ -381,11 +381,3 @@ is out of bounds.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 5146d00782e339468763cc853849ee12879bafb2..12b1d0503e261ecabd76c370b8d6498306535ac4 100644 (file)
@@ -127,11 +127,3 @@ this control belongs to.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 5122ce87e0b806a490175bec8600662b7f2a0cd5..b17a7aac6997482379e1b43c8b0d7e5cf914e1f0 100644 (file)
@@ -183,7 +183,12 @@ applications must set the array to zero.</entry>
            <entry>__u32</entry>
            <entry><structfield>ctrl_class</structfield></entry>
            <entry>The control class to which all controls belong, see
-<xref linkend="ctrl-class" />.</entry>
+<xref linkend="ctrl-class" />. Drivers that use a kernel framework for handling
+controls will also accept a value of 0 here, meaning that the controls can
+belong to any control class. Whether drivers support this can be tested by setting
+<structfield>ctrl_class</structfield> to 0 and calling <constant>VIDIOC_TRY_EXT_CTRLS</constant>
+with a <structfield>count</structfield> of 0. If that succeeds, then the driver
+supports this feature.</entry>
          </row>
          <row>
            <entry>__u32</entry>
@@ -194,10 +199,13 @@ also be zero.</entry>
          <row>
            <entry>__u32</entry>
            <entry><structfield>error_idx</structfield></entry>
-           <entry>Set by the driver in case of an error. It is the
-index of the control causing the error or equal to 'count' when the
-error is not associated with a particular control. Undefined when the
-ioctl returns 0 (success).</entry>
+           <entry>Set by the driver in case of an error. If it is equal
+to <structfield>count</structfield>, then no actual changes were made to
+controls. In other words, the error was not associated with setting a particular
+control. If it is another value, then only the controls up to <structfield>error_idx-1</structfield>
+were modified and control <structfield>error_idx</structfield> is the one that
+caused the error. The <structfield>error_idx</structfield> value is undefined
+if the ioctl returned 0 (success).</entry>
          </row>
          <row>
            <entry>__u32</entry>
@@ -312,10 +320,3 @@ to store the payload and this error code is returned.</para>
   </refsect1>
 </refentry>
 
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 055718231bc18ce81ddb9287d5633a5ab412388c..7c63815e7afd0eb964a1848513dea5be14eb677e 100644 (file)
@@ -295,7 +295,8 @@ set this field to zero.</entry>
            <entry>The device is capable of non-destructive overlays.
 When the driver clears this flag, only destructive overlays are
 supported. There are no drivers yet which support both destructive and
-non-destructive overlays.</entry>
+non-destructive overlays. Video Output Overlays are in practice always
+non-destructive.</entry>
          </row>
          <row>
            <entry><constant>V4L2_FBUF_CAP_CHROMAKEY</constant></entry>
@@ -339,8 +340,8 @@ blending makes no sense for destructive overlays.</entry>
          <row>
            <entry><constant>V4L2_FBUF_CAP_SRC_CHROMAKEY</constant></entry>
            <entry>0x0080</entry>
-           <entry>The device supports Source Chroma-keying. Framebuffer pixels
-with the chroma-key colors are replaced by video pixels, which is exactly opposite of
+           <entry>The device supports Source Chroma-keying. Video pixels
+with the chroma-key colors are replaced by framebuffer pixels, which is exactly opposite of
 <constant>V4L2_FBUF_CAP_CHROMAKEY</constant></entry>
          </row>
        </tbody>
@@ -356,21 +357,27 @@ with the chroma-key colors are replaced by video pixels, which is exactly opposi
            <entry><constant>V4L2_FBUF_FLAG_PRIMARY</constant></entry>
            <entry>0x0001</entry>
            <entry>The framebuffer is the primary graphics surface.
-In other words, the overlay is destructive. [?]</entry>
+In other words, the overlay is destructive. This flag is typically set by any
+driver that doesn't have the <constant>V4L2_FBUF_CAP_EXTERNOVERLAY</constant>
+capability and it is cleared otherwise.</entry>
          </row>
          <row>
            <entry><constant>V4L2_FBUF_FLAG_OVERLAY</constant></entry>
            <entry>0x0002</entry>
-           <entry>The frame buffer is an overlay surface the same
-size as the capture. [?]</entry>
-         </row>
-         <row>
-           <entry spanname="hspan">The purpose of
-<constant>V4L2_FBUF_FLAG_PRIMARY</constant> and
-<constant>V4L2_FBUF_FLAG_OVERLAY</constant> was never quite clear.
-Most drivers seem to ignore these flags. For compatibility with the
-<wordasword>bttv</wordasword> driver applications should set the
-<constant>V4L2_FBUF_FLAG_OVERLAY</constant> flag.</entry>
+           <entry>If this flag is set for a video capture device, then the
+driver will set the initial overlay size to cover the full framebuffer size,
+otherwise the existing overlay size (as set by &VIDIOC-S-FMT;) will be used.
+
+Only one video capture driver (bttv) supports this flag. The use of this flag
+for capture devices is deprecated. There is no way to detect which drivers
+support this flag, so the only reliable method of setting the overlay size is
+through &VIDIOC-S-FMT;.
+
+If this flag is set for a video output device, then the video output overlay
+window is relative to the top-left corner of the framebuffer and restricted
+to the size of the framebuffer. If it is cleared, then the video output
+overlay window is relative to the video output display.
+            </entry>
          </row>
          <row>
            <entry><constant>V4L2_FBUF_FLAG_CHROMAKEY</constant></entry>
index 062d720690906b3993327e88fdd05db47f249037..66e9a5257861ab1c5f65b197e3bc7e52304659e6 100644 (file)
@@ -98,8 +98,11 @@ the &v4l2-output; <structfield>modulator</structfield> field and the
            <entry>&v4l2-tuner-type;</entry>
            <entry><structfield>type</structfield></entry>
            <entry>The tuner type. This is the same value as in the
-&v4l2-tuner; <structfield>type</structfield> field. The field is not
-applicable to modulators, &ie; ignored by drivers.</entry>
+&v4l2-tuner; <structfield>type</structfield> field. The type must be set
+to <constant>V4L2_TUNER_RADIO</constant> for <filename>/dev/radioX</filename>
+device nodes, and to <constant>V4L2_TUNER_ANALOG_TV</constant>
+for all others. The field is not applicable to modulators, &ie; ignored
+by drivers.</entry>
          </row>
          <row>
            <entry>__u32</entry>
@@ -135,11 +138,3 @@ wrong.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 08ae82f131f2b952df2a0f5488b49d0747776153..1d43065090dd1087be1c26a8f54804ac8a4ee2c2 100644 (file)
@@ -61,8 +61,8 @@ desired input in an integer and call the
 <constant>VIDIOC_S_INPUT</constant> ioctl with a pointer to this
 integer. Side effects are possible. For example inputs may support
 different video standards, so the driver may implicitly switch the
-current standard. It is good practice to select an input before
-querying or negotiating any other parameters.</para>
+current standard. Because of these possible side effects applications
+must select an input before querying or negotiating any other parameters.</para>
 
     <para>Information about video inputs is available using the
 &VIDIOC-ENUMINPUT; ioctl.</para>
index 15ce660f0f5a6d47dadb062c3754fb502adfc54d..7f4ac7e41fa8765d709794a130a2f11091b7c98a 100644 (file)
@@ -236,11 +236,3 @@ mode.</entry>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index fd45f1c13ccf445b89e582036b40c3a7a94ab86c..4533068ecb8ad5dd221512d5f6dc8a7266b66ecb 100644 (file)
@@ -61,8 +61,9 @@ desired output in an integer and call the
 <constant>VIDIOC_S_OUTPUT</constant> ioctl with a pointer to this integer.
 Side effects are possible. For example outputs may support different
 video standards, so the driver may implicitly switch the current
-standard. It is good practice to select an output before querying or
-negotiating any other parameters.</para>
+standard.
+standard. Because of these possible side effects applications
+must select an output before querying or negotiating any other parameters.</para>
 
     <para>Information about video outputs is available using the
 &VIDIOC-ENUMOUTPUT; ioctl.</para>
index 8f5e3da7002fee8a68279dd1ee4a30939d6776e3..6a81b4fe95383eebb7f7d5288fc21adbb8b16032 100644 (file)
@@ -133,11 +133,3 @@ priority.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
new file mode 100644 (file)
index 0000000..a9d36e0
--- /dev/null
@@ -0,0 +1,304 @@
+<refentry id="vidioc-g-selection">
+
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_SELECTION, VIDIOC_S_SELECTION</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_SELECTION</refname>
+    <refname>VIDIOC_S_SELECTION</refname>
+    <refpurpose>Get or set one of the selection rectangles</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_selection *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_SELECTION, VIDIOC_S_SELECTION</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental"> experimental </link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>The ioctls are used to query and configure selection rectangles.</para>
+
+<para> To query the cropping (composing) rectangle set <structfield>
+&v4l2-selection;::type </structfield> to the respective buffer type.  Do not
+use multiplanar buffers.  Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
+</constant> instead of <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
+</constant>.  Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of
+<constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>.  The next step is
+setting <structfield> &v4l2-selection;::target </structfield> to value
+<constant> V4L2_SEL_TGT_CROP_ACTIVE </constant> (<constant>
+V4L2_SEL_TGT_COMPOSE_ACTIVE </constant>).  Please refer to table <xref
+linkend="v4l2-sel-target" /> or <xref linkend="selection-api" /> for additional
+targets.  Fields <structfield> &v4l2-selection;::flags </structfield> and
+<structfield> &v4l2-selection;::reserved </structfield> are ignored and they
+must be filled with zeros.  The driver fills the rest of the structure or
+returns &EINVAL; if incorrect buffer type or target was used. If cropping
+(composing) is not supported then the active rectangle is not mutable and it is
+always equal to the bounds rectangle.  Finally, structure <structfield>
+&v4l2-selection;::r </structfield> is filled with the current cropping
+(composing) coordinates. The coordinates are expressed in driver-dependent
+units. The only exception are rectangles for images in raw formats, whose
+coordinates are always expressed in pixels.  </para>
+
+<para> To change the cropping (composing) rectangle set <structfield>
+&v4l2-selection;::type </structfield> to the respective buffer type.  Do not
+use multiplanar buffers.  Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
+</constant> instead of <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
+</constant>.  Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of
+<constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>.  The next step is
+setting <structfield> &v4l2-selection;::target </structfield> to value
+<constant> V4L2_SEL_TGT_CROP_ACTIVE </constant> (<constant>
+V4L2_SEL_TGT_COMPOSE_ACTIVE </constant>). Please refer to table <xref
+linkend="v4l2-sel-target" /> or <xref linkend="selection-api" /> for additional
+targets.  Set desired active area into the field <structfield>
+&v4l2-selection;::r </structfield>.  Field <structfield>
+&v4l2-selection;::reserved </structfield> is ignored and must be filled with
+zeros.  The driver may adjust the rectangle coordinates. An application may
+introduce constraints to control rounding behaviour. Set the field
+<structfield> &v4l2-selection;::flags </structfield> to one of values:
+
+<itemizedlist>
+  <listitem>
+<para><constant>0</constant> - The driver can adjust the rectangle size freely
+and shall choose a crop/compose rectangle as close as possible to the requested
+one.</para>
+  </listitem>
+  <listitem>
+<para><constant>V4L2_SEL_FLAG_GE</constant> - The driver is not allowed to
+shrink the rectangle.  The original rectangle must lay inside the adjusted
+one.</para>
+  </listitem>
+  <listitem>
+<para><constant>V4L2_SEL_FLAG_LE</constant> - The driver is not allowed to
+enlarge the rectangle.  The adjusted rectangle must lay inside the original
+one.</para>
+  </listitem>
+  <listitem>
+<para><constant>V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE</constant> - The driver
+must choose the size exactly the same as in the requested rectangle.</para>
+  </listitem>
+</itemizedlist>
+
+Please refer to <xref linkend="sel-const-adjust" />.
+
+</para>
+
+<para> The driver may have to adjusts the requested dimensions against hardware
+limits and other parts as the pipeline, i.e. the bounds given by the
+capture/output window or TV display. The closest possible values of horizontal
+and vertical offset and sizes are chosen according to following priority:
+
+<orderedlist>
+  <listitem>
+    <para>Satisfy constraints from <structfield>&v4l2-selection;::flags</structfield>.</para>
+  </listitem>
+  <listitem>
+    <para>Adjust width, height, left, and top to hardware limits and alignments.</para>
+  </listitem>
+  <listitem>
+    <para>Keep center of adjusted rectangle as close as possible to the original one.</para>
+  </listitem>
+  <listitem>
+    <para>Keep width and height as close as possible to original ones.</para>
+  </listitem>
+  <listitem>
+    <para>Keep horizontal and vertical offset as close as possible to original ones.</para>
+  </listitem>
+</orderedlist>
+
+On success the field <structfield> &v4l2-selection;::r </structfield> contains
+the adjusted rectangle. When the parameters are unsuitable the application may
+modify the cropping (composing) or image parameters and repeat the cycle until
+satisfactory parameters have been negotiated. If constraints flags have to be
+violated at then ERANGE is returned. The error indicates that <emphasis> there
+exist no rectangle </emphasis> that satisfies the constraints.</para>
+
+  </refsect1>
+
+  <refsect1>
+    <table frame="none" pgwide="1" id="v4l2-sel-target">
+      <title>Selection targets.</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+            <entry><constant>V4L2_SEL_TGT_CROP_ACTIVE</constant></entry>
+            <entry>0</entry>
+            <entry>area that is currently cropped by hardware</entry>
+         </row>
+         <row>
+            <entry><constant>V4L2_SEL_TGT_CROP_DEFAULT</constant></entry>
+            <entry>1</entry>
+            <entry>suggested cropping rectangle that covers the "whole picture"</entry>
+         </row>
+         <row>
+            <entry><constant>V4L2_SEL_TGT_CROP_BOUNDS</constant></entry>
+            <entry>2</entry>
+            <entry>limits for the cropping rectangle</entry>
+         </row>
+         <row>
+            <entry><constant>V4L2_SEL_TGT_COMPOSE_ACTIVE</constant></entry>
+            <entry>256</entry>
+            <entry>area to which data are composed by hardware</entry>
+         </row>
+         <row>
+            <entry><constant>V4L2_SEL_TGT_COMPOSE_DEFAULT</constant></entry>
+            <entry>257</entry>
+            <entry>suggested composing rectangle that covers the "whole picture"</entry>
+         </row>
+         <row>
+            <entry><constant>V4L2_SEL_TGT_COMPOSE_BOUNDS</constant></entry>
+            <entry>258</entry>
+            <entry>limits for the composing rectangle</entry>
+         </row>
+         <row>
+            <entry><constant>V4L2_SEL_TGT_COMPOSE_PADDED</constant></entry>
+            <entry>259</entry>
+            <entry>the active area and all padding pixels that are inserted or modified by the hardware</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    <table frame="none" pgwide="1" id="v4l2-sel-flags">
+      <title>Selection constraint flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+            <entry><constant>V4L2_SEL_FLAG_GE</constant></entry>
+            <entry>0x00000001</entry>
+            <entry>indicate that adjusted rectangle must contain a rectangle from <structfield>&v4l2-selection;::r</structfield></entry>
+         </row>
+         <row>
+            <entry><constant>V4L2_SEL_FLAG_LE</constant></entry>
+            <entry>0x00000002</entry>
+            <entry>indicate that adjusted rectangle must be inside a rectangle from <structfield>&v4l2-selection;::r</structfield></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+    <section>
+      <figure id="sel-const-adjust">
+       <title>Size adjustments with constraint flags.</title>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="constraints.png" format="PNG" />
+         </imageobject>
+         <textobject>
+           <phrase>Behaviour of rectangle adjustment for different constraint
+            flags.</phrase>
+         </textobject>
+       </mediaobject>
+      </figure>
+    </section>
+
+  <refsect1>
+    <table pgwide="1" frame="none" id="v4l2-selection">
+      <title>struct <structname>v4l2_selection</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>Type of the buffer (from &v4l2-buf-type;)</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>target</structfield></entry>
+            <entry>used to select between <link linkend="v4l2-sel-target"> cropping and composing rectangles </link></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+            <entry>control over coordinates adjustments, refer to <link linkend="v4l2-sel-flags">selection flags</link></entry>
+         </row>
+         <row>
+           <entry>&v4l2-rect;</entry>
+           <entry><structfield>r</structfield></entry>
+           <entry>selection rectangle</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved[9]</structfield></entry>
+           <entry>Reserved fields for future use</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The buffer <structfield> &v4l2-selection;::type </structfield>
+or <structfield> &v4l2-selection;::target </structfield> is not supported, or
+the <structfield> &v4l2-selection;::flags </structfield> are invalid.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ERANGE</errorcode></term>
+       <listitem>
+         <para>it is not possible to adjust a rectangle <structfield>
+&v4l2-selection;::r </structfield> that satisfies all contraints from
+<structfield> &v4l2-selection;::flags </structfield>.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>it is not possible to apply change of selection rectangle at the moment.
+Usually because streaming is in progress.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+</refentry>
index 37996f25b5d406bd237048c5bb77589d68dc1413..99ff1a016220aee8461cddf088de122057c29ecf 100644 (file)
@@ -88,11 +88,3 @@ standards.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index bd98c734c06b68f34be7a1ce40c426fb2befdd23..91ec2fb658f875dbe76e76465994dcaba9cbb455 100644 (file)
@@ -318,6 +318,16 @@ standard.</para><!-- FIXME what if PAL+NTSC and Bi but not SAP? --></entry>
        <entry>RDS capture is supported. This capability is only valid for
 radio tuners.</entry>
          </row>
+         <row>
+       <entry><constant>V4L2_TUNER_CAP_RDS_BLOCK_IO</constant></entry>
+       <entry>0x0100</entry>
+       <entry>The RDS data is passed as unparsed RDS blocks.</entry>
+         </row>
+         <row>
+       <entry><constant>V4L2_TUNER_CAP_RDS_CONTROLS</constant></entry>
+       <entry>0x0200</entry>
+       <entry>The RDS data is parsed by the hardware and set via controls.</entry>
+         </row>
        </tbody>
       </tgroup>
     </table>
@@ -525,11 +535,3 @@ out of bounds.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 5c104d42d31cd9b3dd2860c1bf3db221ed911f2c..6e414d7b6df759f83f45ad34256c5ace012a6543 100644 (file)
@@ -100,11 +100,3 @@ supported, or the <structfield>index</structfield> is out of bounds.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 0ac0057a51c4c9cb47da092159b955eb1ff11ad9..36660d311b5129d21f3690cbe292394bb457c38d 100644 (file)
@@ -443,11 +443,3 @@ or this particular menu item is not supported by the driver.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index c30dcc4232c0597faaa9f33a970eafe345cd5e75..e013da845b1192c7f4dca179814e4a4d41eeb81d 100644 (file)
@@ -125,11 +125,3 @@ wrong.</para>
     </variablelist>
   </refsect1>
 </refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
index 5cc699ba5453479ea13a028236f0d568063edb1e..e7cc363972173ca0177de6bfb7ce3f38de89bde2 100644 (file)
@@ -47,20 +47,53 @@ directory apei/einj. The following files are provided.
 
 - param1
   This file is used to set the first error parameter value. Effect of
-  parameter depends on error_type specified. For memory error, this is
-  physical memory address.  Only available if param_extension module
-  parameter is specified.
+  parameter depends on error_type specified.
 
 - param2
   This file is used to set the second error parameter value. Effect of
-  parameter depends on error_type specified. For memory error, this is
-  physical memory address mask.  Only available if param_extension
-  module parameter is specified.
+  parameter depends on error_type specified.
+
+BIOS versions based in the ACPI 4.0 specification have limited options
+to control where the errors are injected.  Your BIOS may support an
+extension (enabled with the param_extension=1 module parameter, or
+boot command line einj.param_extension=1). This allows the address
+and mask for memory injections to be specified by the param1 and
+param2 files in apei/einj.
+
+BIOS versions using the ACPI 5.0 specification have more control over
+the target of the injection. For processor related errors (type 0x1,
+0x2 and 0x4) the APICID of the target should be provided using the
+param1 file in apei/einj. For memory errors (type 0x8, 0x10 and 0x20)
+the address is set using param1 with a mask in param2 (0x0 is equivalent
+to all ones). For PCI express errors (type 0x40, 0x80 and 0x100) the
+segment, bus, device and function are specified using param1:
+
+         31     24 23    16 15    11 10      8  7        0
+       +-------------------------------------------------+
+       | segment |   bus  | device | function | reserved |
+       +-------------------------------------------------+
+
+An ACPI 5.0 BIOS may also allow vendor specific errors to be injected.
+In this case a file named vendor will contain identifying information
+from the BIOS that hopefully will allow an application wishing to use
+the vendor specific extension to tell that they are running on a BIOS
+that supports it. All vendor extensions have the 0x80000000 bit set in
+error_type. A file vendor_flags controls the interpretation of param1
+and param2 (1 = PROCESSOR, 2 = MEMORY, 4 = PCI). See your BIOS vendor
+documentation for details (and expect changes to this API if vendors
+creativity in using this feature expands beyond our expectations).
+
+Example:
+# cd /sys/kernel/debug/apei/einj
+# cat available_error_type             # See which errors can be injected
+0x00000002     Processor Uncorrectable non-fatal
+0x00000008     Memory Correctable
+0x00000010     Memory Uncorrectable non-fatal
+# echo 0x12345000 > param1             # Set memory address for injection
+# echo 0xfffffffffffff000 > param2     # Mask - anywhere in this page
+# echo 0x8 > error_type                        # Choose correctable memory error
+# echo 1 > error_inject                        # Inject now
 
-Injecting parameter support is a BIOS version specific extension, that
-is, it only works on some BIOS version.  If you want to use it, please
-make sure your BIOS version has the proper support and specify
-"param_extension=y" in module parameter.
 
 For more information about EINJ, please refer to ACPI specification
-version 4.0, section 17.5.
+version 4.0, section 17.5 and ACPI 5.0, section 18.6.
index 4d8774f6f48abd7aaf59e48335a1d0b9415832cd..4c95c0034a4bbbffdae12a99ff2ddbd0798ca09c 100644 (file)
@@ -61,7 +61,7 @@ Brief summary of control files.
  memory.failcnt                         # show the number of memory usage hits limits
  memory.memsw.failcnt           # show the number of memory+Swap hits limits
  memory.max_usage_in_bytes      # show max memory usage recorded
- memory.memsw.usage_in_bytes    # show max memory+Swap usage recorded
+ memory.memsw.max_usage_in_bytes # show max memory+Swap usage recorded
  memory.soft_limit_in_bytes     # set/show soft limit of memory usage
  memory.stat                    # show various statistics
  memory.use_hierarchy           # set/show hierarchical account enabled
@@ -410,8 +410,11 @@ memory.stat file includes following statistics
 cache          - # of bytes of page cache memory.
 rss            - # of bytes of anonymous and swap cache memory.
 mapped_file    - # of bytes of mapped file (includes tmpfs/shmem)
-pgpgin         - # of pages paged in (equivalent to # of charging events).
-pgpgout                - # of pages paged out (equivalent to # of uncharging events).
+pgpgin         - # of charging events to the memory cgroup. The charging
+               event happens each time a page is accounted as either mapped
+               anon page(RSS) or cache page(Page Cache) to the cgroup.
+pgpgout                - # of uncharging events to the memory cgroup. The uncharging
+               event happens each time a page is unaccounted from the cgroup.
 swap           - # of bytes of swap usage
 inactive_anon  - # of bytes of anonymous memory and swap cache memory on
                LRU list.
index 96b690348ba14290f10235b94d6e13e4cc2d329d..cf44eb6499b418c3fd28339b52d53b3467cbfe23 100644 (file)
@@ -102,9 +102,15 @@ or
        make coccicheck COCCI=<my_SP.cocci> MODE=report
 
 
- Using Coccinelle on (modified) files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Controlling Which Files are Processed by Coccinelle
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+By default the entire kernel source tree is checked.
+
+To apply Coccinelle to a specific directory, M= can be used.
+For example, to check drivers/net/wireless/ one may write:
 
+    make coccicheck M=drivers/net/wireless/
+    
 To apply Coccinelle on a file basis, instead of a directory basis, the
 following command may be used:
 
index cec8864ce4e8cbb4089b68279255c51645938554..00383186d8fb3e2c0fc4d5a12852844cb5b2721f 100644 (file)
@@ -447,6 +447,9 @@ Your cooperation is appreciated.
                234 = /dev/btrfs-control        Btrfs control device
                235 = /dev/autofs       Autofs control device
                236 = /dev/mapper/control       Device-Mapper control device
+               237 = /dev/loop-control Loopback control device
+               238 = /dev/vhost-net    Host kernel accelerator for virtio net
+
                240-254                 Reserved for local use
                255                     Reserved for MISC_DYNAMIC_MINOR
 
diff --git a/Documentation/devicetree/bindings/dma/atmel-dma.txt b/Documentation/devicetree/bindings/dma/atmel-dma.txt
new file mode 100644 (file)
index 0000000..3c046ee
--- /dev/null
@@ -0,0 +1,14 @@
+* Atmel Direct Memory Access Controller (DMA)
+
+Required properties:
+- compatible: Should be "atmel,<chip>-dma"
+- reg: Should contain DMA registers location and length
+- interrupts: Should contain DMA interrupt
+
+Examples:
+
+dma@ffffec00 {
+       compatible = "atmel,at91sam9g45-dma";
+       reg = <0xffffec00 0x200>;
+       interrupts = <21>;
+};
diff --git a/Documentation/devicetree/bindings/i2c/omap-i2c.txt b/Documentation/devicetree/bindings/i2c/omap-i2c.txt
new file mode 100644 (file)
index 0000000..56564aa
--- /dev/null
@@ -0,0 +1,30 @@
+I2C for OMAP platforms
+
+Required properties :
+- compatible : Must be "ti,omap3-i2c" or "ti,omap4-i2c"
+- ti,hwmods : Must be "i2c<n>", n being the instance number (1-based)
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Recommended properties :
+- clock-frequency : Desired I2C bus clock frequency in Hz. Otherwise
+  the default 100 kHz frequency will be used.
+
+Optional properties:
+- Child nodes conforming to i2c bus binding
+
+Note: Current implementation will fetch base address, irq and dma
+from 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 :
+
+i2c1: i2c@0 {
+    compatible = "ti,omap3-i2c";
+    #address-cells = <1>;
+    #size-cells = <0>;
+    ti,hwmods = "i2c1";
+    clock-frequency = <400000>;
+};
diff --git a/Documentation/devicetree/bindings/mfd/mc13xxx.txt b/Documentation/devicetree/bindings/mfd/mc13xxx.txt
new file mode 100644 (file)
index 0000000..19f6af4
--- /dev/null
@@ -0,0 +1,78 @@
+* Freescale MC13783/MC13892 Power Management Integrated Circuit (PMIC)
+
+Required properties:
+- compatible : Should be "fsl,mc13783" or "fsl,mc13892"
+
+Optional properties:
+- fsl,mc13xxx-uses-adc : Indicate the ADC is being used
+- fsl,mc13xxx-uses-codec : Indicate the Audio Codec is being used
+- fsl,mc13xxx-uses-rtc : Indicate the RTC is being used
+- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
+
+Sub-nodes:
+- regulators : Contain the regulator nodes.  The MC13892 regulators are
+  bound using their names as listed below with their registers and bits
+  for enabling.
+
+    vcoincell : regulator VCOINCELL (register 13, bit 23)
+    sw1       : regulator SW1      (register 24, bit 0)
+    sw2       : regulator SW2      (register 25, bit 0)
+    sw3       : regulator SW3      (register 26, bit 0)
+    sw4       : regulator SW4      (register 27, bit 0)
+    swbst     : regulator SWBST            (register 29, bit 20)
+    vgen1     : regulator VGEN1            (register 32, bit 0)
+    viohi     : regulator VIOHI            (register 32, bit 3)
+    vdig      : regulator VDIG     (register 32, bit 9)
+    vgen2     : regulator VGEN2            (register 32, bit 12)
+    vpll      : regulator VPLL     (register 32, bit 15)
+    vusb2     : regulator VUSB2            (register 32, bit 18)
+    vgen3     : regulator VGEN3            (register 33, bit 0)
+    vcam      : regulator VCAM     (register 33, bit 6)
+    vvideo    : regulator VVIDEO    (register 33, bit 12)
+    vaudio    : regulator VAUDIO    (register 33, bit 15)
+    vsd       : regulator VSD      (register 33, bit 18)
+    gpo1      : regulator GPO1     (register 34, bit 6)
+    gpo2      : regulator GPO2     (register 34, bit 8)
+    gpo3      : regulator GPO3     (register 34, bit 10)
+    gpo4      : regulator GPO4     (register 34, bit 12)
+    pwgt1spi  : regulator PWGT1SPI  (register 34, bit 15)
+    pwgt2spi  : regulator PWGT2SPI  (register 34, bit 16)
+    vusb      : regulator VUSB     (register 50, bit 3)
+
+  The bindings details of individual regulator device can be found in:
+  Documentation/devicetree/bindings/regulator/regulator.txt
+
+Examples:
+
+ecspi@70010000 { /* ECSPI1 */
+       fsl,spi-num-chipselects = <2>;
+       cs-gpios = <&gpio3 24 0>, /* GPIO4_24 */
+                  <&gpio3 25 0>; /* GPIO4_25 */
+       status = "okay";
+
+       pmic: mc13892@0 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mc13892";
+               spi-max-frequency = <6000000>;
+               reg = <0>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <8>;
+
+               regulators {
+                       sw1_reg: mc13892__sw1 {
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <1375000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw2_reg: mc13892__sw2 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <1850000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/mfd/twl-familly.txt b/Documentation/devicetree/bindings/mfd/twl-familly.txt
new file mode 100644 (file)
index 0000000..a66fcf9
--- /dev/null
@@ -0,0 +1,47 @@
+Texas Instruments TWL family
+
+The TWLs are Integrated Power Management Chips.
+Some version might contain much more analog function like
+USB transceiver or Audio amplifier.
+These chips are connected to an i2c bus.
+
+
+Required properties:
+- compatible : Must be "ti,twl4030";
+  For Integrated power-management/audio CODEC device used in OMAP3
+  based boards
+- compatible : Must be "ti,twl6030";
+  For Integrated power-management used in OMAP4 based boards
+- interrupts : This i2c device has an IRQ line connected to the main SoC
+- interrupt-controller : Since the twl support several interrupts internally,
+  it is considered as an interrupt controller cascaded to the SoC one.
+- #interrupt-cells = <1>;
+- interrupt-parent : The parent interrupt controller.
+
+Optional node:
+- Child nodes contain in the twl. The twl family is made of several variants
+  that support a different number of features.
+  The children nodes will thus depend of the capability of the variant.
+
+
+Example:
+/*
+ * Integrated Power Management Chip
+ * http://www.ti.com/lit/ds/symlink/twl6030.pdf
+ */
+twl@48 {
+    compatible = "ti,twl6030";
+    reg = <0x48>;
+    interrupts = <39>; /* IRQ_SYS_1N cascaded to gic */
+    interrupt-controller;
+    #interrupt-cells = <1>;
+    interrupt-parent = <&gic>;
+    #address-cells = <1>;
+    #size-cells = <0>;
+
+    twl_rtc {
+        compatible = "ti,twl_rtc";
+        interrupts = <11>;
+        reg = <0>;
+    };
+};
diff --git a/Documentation/devicetree/bindings/resource-names.txt b/Documentation/devicetree/bindings/resource-names.txt
new file mode 100644 (file)
index 0000000..e280fef
--- /dev/null
@@ -0,0 +1,54 @@
+Some properties contain an ordered list of 1 or more datum which are
+normally accessed by index.  However, some devices will have multiple
+values which are more naturally accessed by name.  Device nodes can
+include a supplemental property for assigning names to each of the list
+items.  The names property consists of a list of strings in the same
+order as the data in the resource property.
+
+The following supplemental names properties are defined.
+
+Resource Property      Supplemental Names Property
+-----------------      ---------------------------
+reg                    reg-names
+clocks                 clock-names
+interrupts             interrupt-names
+
+Usage:
+
+The -names property must be used in conjunction with the normal resource
+property. If not it will be ignored.
+
+Examples:
+
+l4-abe {
+       compatible = "simple-bus";
+       #address-cells = <2>;
+       #size-cells = <1>;
+       ranges = <0 0 0x48000000 0x00001000>, /* MPU path */
+                <1 0 0x49000000 0x00001000>; /* L3 path */
+       mcasp {
+               compatible = "ti,mcasp";
+               reg = <0 0x10 0x10>, <0 0x20 0x10>,
+                     <1 0x10 0x10>, <1 0x20 0x10>;
+               reg-names = "mpu", "dat",
+                           "dma", "dma_dat";
+               interrupts = <11>, <12>;
+               interrupt-names = "rx", "tx";
+       };
+
+       timer {
+               compatible = "ti,timer";
+               reg = <0 0x40 0x10>, <1 0x40 0x10>;
+               reg-names = "mpu", "dma";
+       };
+};
+
+
+usb {
+       compatible = "ti,usb-host";
+       reg = <0x4a064000 0x800>, <0x4a064800 0x200>,
+             <0x4a064c00 0x200>;
+       reg-names = "config", "ohci", "ehci";
+       interrupts = <14>, <15>;
+       interrupt-names = "ohci", "ehci";
+};
index 510eab32f392066233fba702b83a123ec6e2d9c4..225f96d88f55e055ff3f3c089f24b5f93d6d275b 100644 (file)
@@ -219,6 +219,10 @@ NOTES:
    If the exporter chooses not to allow an attach() operation once a
    map_dma_buf() API has been called, it simply returns an error.
 
+Miscellaneous notes:
+- Any exporters or users of the dma-buf buffer sharing framework must have
+  a 'select DMA_SHARED_BUFFER' in their respective Kconfigs.
+
 References:
 [1] struct dma_buf_ops in include/linux/dma-buf.h
 [2] All interfaces mentioned above defined in include/linux/dma-buf.h
index 94b7e0f96b38fa8086ea14f7cd88718b45e84d70..bbe6cb3d1856b8943dd04d3449af9d39d5c1e7dc 100644 (file)
@@ -75,6 +75,10 @@ The slave DMA usage consists of following steps:
    slave_sg    - DMA a list of scatter gather buffers from/to a peripheral
    dma_cyclic  - Perform a cyclic DMA operation from/to a peripheral till the
                  operation is explicitly stopped.
+   interleaved_dma - This is common to Slave as well as M2M clients. For slave
+                address of devices' fifo could be already known to the driver.
+                Various types of operations could be expressed by setting
+                appropriate values to the 'dma_interleaved_template' members.
 
    A non-NULL return of this transfer API represents a "descriptor" for
    the given transaction.
@@ -89,6 +93,10 @@ The slave DMA usage consists of following steps:
                struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
                size_t period_len, enum dma_data_direction direction);
 
+       struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)(
+               struct dma_chan *chan, struct dma_interleaved_template *xt,
+               unsigned long flags);
+
    The peripheral driver is expected to have mapped the scatterlist for
    the DMA operation prior to calling device_prep_slave_sg, and must
    keep the scatterlist mapped until the DMA operation has completed.
index e67be7afc78b481d4dc42553bc555690e34c898e..d1d4a179a38221a5d0da86ecc8d5d44c68c1f1fc 100755 (executable)
@@ -27,8 +27,8 @@ use IO::Handle;
                "or51211", "or51132_qam", "or51132_vsb", "bluebird",
                "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
                "af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
-               "lme2510c_s7395_old", "drxk", "drxk_terratec_h5", "tda10071",
-               "it9135" );
+               "lme2510c_s7395_old", "drxk", "drxk_terratec_h5",
+               "drxk_hauppauge_hvr930c", "tda10071", "it9135", "it9137");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -644,6 +644,24 @@ sub drxk {
     "$fwfile"
 }
 
+sub drxk_hauppauge_hvr930c {
+    my $url = "http://www.wintvcd.co.uk/drivers/";
+    my $zipfile = "HVR-9x0_5_10_325_28153_SIGNED.zip";
+    my $hash = "83ab82e7e9480ec8bf1ae0155ca63c88";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+    my $drvfile = "HVR-900/emOEM.sys";
+    my $fwfile = "dvb-usb-hauppauge-hvr930c-drxk.fw";
+
+    checkstandard();
+
+    wgetfile($zipfile, $url . $zipfile);
+    verify($zipfile, $hash);
+    unzip($zipfile, $tmpdir);
+    extract("$tmpdir/$drvfile", 0x117b0, 42692, "$fwfile");
+
+    "$fwfile"
+}
+
 sub drxk_terratec_h5 {
     my $url = "http://www.linuxtv.org/downloads/firmware/";
     my $hash = "19000dada8e2741162ccc50cc91fa7f1";
@@ -658,6 +676,26 @@ sub drxk_terratec_h5 {
 }
 
 sub it9135 {
+       my $sourcefile = "dvb-usb-it9135.zip";
+       my $url = "http://www.ite.com.tw/uploads/firmware/v3.6.0.0/$sourcefile";
+       my $hash = "1e55f6c8833f1d0ae067c2bb2953e6a9";
+       my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
+       my $outfile = "dvb-usb-it9135.fw";
+       my $fwfile1 = "dvb-usb-it9135-01.fw";
+       my $fwfile2 = "dvb-usb-it9135-02.fw";
+
+       checkstandard();
+
+       wgetfile($sourcefile, $url);
+       unzip($sourcefile, $tmpdir);
+       verify("$tmpdir/$outfile", $hash);
+       extract("$tmpdir/$outfile", 64, 8128, "$fwfile1");
+       extract("$tmpdir/$outfile", 12866, 5817, "$fwfile2");
+
+       "$fwfile1 $fwfile2"
+}
+
+sub it9137 {
     my $url = "http://kworld.server261.com/kworld/CD/ITE_TiVme/V1.00/";
     my $zipfile = "Driver_V10.323.1.0412.100412.zip";
     my $hash = "79b597dc648698ed6820845c0c9d0d37";
diff --git a/Documentation/fb/api.txt b/Documentation/fb/api.txt
new file mode 100644 (file)
index 0000000..d4ff7de
--- /dev/null
@@ -0,0 +1,306 @@
+                       The Frame Buffer Device API
+                       ---------------------------
+
+Last revised: June 21, 2011
+
+
+0. Introduction
+---------------
+
+This document describes the frame buffer API used by applications to interact
+with frame buffer devices. In-kernel APIs between device drivers and the frame
+buffer core are not described.
+
+Due to a lack of documentation in the original frame buffer API, drivers
+behaviours differ in subtle (and not so subtle) ways. This document describes
+the recommended API implementation, but applications should be prepared to
+deal with different behaviours.
+
+
+1. Capabilities
+---------------
+
+Device and driver capabilities are reported in the fixed screen information
+capabilities field.
+
+struct fb_fix_screeninfo {
+       ...
+       __u16 capabilities;             /* see FB_CAP_*                 */
+       ...
+};
+
+Application should use those capabilities to find out what features they can
+expect from the device and driver.
+
+- FB_CAP_FOURCC
+
+The driver supports the four character code (FOURCC) based format setting API.
+When supported, formats are configured using a FOURCC instead of manually
+specifying color components layout.
+
+
+2. Types and visuals
+--------------------
+
+Pixels are stored in memory in hardware-dependent formats. Applications need
+to be aware of the pixel storage format in order to write image data to the
+frame buffer memory in the format expected by the hardware.
+
+Formats are described by frame buffer types and visuals. Some visuals require
+additional information, which are stored in the variable screen information
+bits_per_pixel, grayscale, red, green, blue and transp fields.
+
+Visuals describe how color information is encoded and assembled to create
+macropixels. Types describe how macropixels are stored in memory. The following
+types and visuals are supported.
+
+- FB_TYPE_PACKED_PIXELS
+
+Macropixels are stored contiguously in a single plane. If the number of bits
+per macropixel is not a multiple of 8, whether macropixels are padded to the
+next multiple of 8 bits or packed together into bytes depends on the visual.
+
+Padding at end of lines may be present and is then reported through the fixed
+screen information line_length field.
+
+- FB_TYPE_PLANES
+
+Macropixels are split across multiple planes. The number of planes is equal to
+the number of bits per macropixel, with plane i'th storing i'th bit from all
+macropixels.
+
+Planes are located contiguously in memory.
+
+- FB_TYPE_INTERLEAVED_PLANES
+
+Macropixels are split across multiple planes. The number of planes is equal to
+the number of bits per macropixel, with plane i'th storing i'th bit from all
+macropixels.
+
+Planes are interleaved in memory. The interleave factor, defined as the
+distance in bytes between the beginning of two consecutive interleaved blocks
+belonging to different planes, is stored in the fixed screen information
+type_aux field.
+
+- FB_TYPE_FOURCC
+
+Macropixels are stored in memory as described by the format FOURCC identifier
+stored in the variable screen information grayscale field.
+
+- FB_VISUAL_MONO01
+
+Pixels are black or white and stored on a number of bits (typically one)
+specified by the variable screen information bpp field.
+
+Black pixels are represented by all bits set to 1 and white pixels by all bits
+set to 0. When the number of bits per pixel is smaller than 8, several pixels
+are packed together in a byte.
+
+FB_VISUAL_MONO01 is currently used with FB_TYPE_PACKED_PIXELS only.
+
+- FB_VISUAL_MONO10
+
+Pixels are black or white and stored on a number of bits (typically one)
+specified by the variable screen information bpp field.
+
+Black pixels are represented by all bits set to 0 and white pixels by all bits
+set to 1. When the number of bits per pixel is smaller than 8, several pixels
+are packed together in a byte.
+
+FB_VISUAL_MONO01 is currently used with FB_TYPE_PACKED_PIXELS only.
+
+- FB_VISUAL_TRUECOLOR
+
+Pixels are broken into red, green and blue components, and each component
+indexes a read-only lookup table for the corresponding value. Lookup tables
+are device-dependent, and provide linear or non-linear ramps.
+
+Each component is stored in a macropixel according to the variable screen
+information red, green, blue and transp fields.
+
+- FB_VISUAL_PSEUDOCOLOR and FB_VISUAL_STATIC_PSEUDOCOLOR
+
+Pixel values are encoded as indices into a colormap that stores red, green and
+blue components. The colormap is read-only for FB_VISUAL_STATIC_PSEUDOCOLOR
+and read-write for FB_VISUAL_PSEUDOCOLOR.
+
+Each pixel value is stored in the number of bits reported by the variable
+screen information bits_per_pixel field.
+
+- FB_VISUAL_DIRECTCOLOR
+
+Pixels are broken into red, green and blue components, and each component
+indexes a programmable lookup table for the corresponding value.
+
+Each component is stored in a macropixel according to the variable screen
+information red, green, blue and transp fields.
+
+- FB_VISUAL_FOURCC
+
+Pixels are encoded and  interpreted as described by the format FOURCC
+identifier stored in the variable screen information grayscale field.
+
+
+3. Screen information
+---------------------
+
+Screen information are queried by applications using the FBIOGET_FSCREENINFO
+and FBIOGET_VSCREENINFO ioctls. Those ioctls take a pointer to a
+fb_fix_screeninfo and fb_var_screeninfo structure respectively.
+
+struct fb_fix_screeninfo stores device independent unchangeable information
+about the frame buffer device and the current format. Those information can't
+be directly modified by applications, but can be changed by the driver when an
+application modifies the format.
+
+struct fb_fix_screeninfo {
+       char id[16];                    /* identification string eg "TT Builtin" */
+       unsigned long smem_start;       /* Start of frame buffer mem */
+                                       /* (physical address) */
+       __u32 smem_len;                 /* Length of frame buffer mem */
+       __u32 type;                     /* see FB_TYPE_*                */
+       __u32 type_aux;                 /* Interleave for interleaved Planes */
+       __u32 visual;                   /* see FB_VISUAL_*              */
+       __u16 xpanstep;                 /* zero if no hardware panning  */
+       __u16 ypanstep;                 /* zero if no hardware panning  */
+       __u16 ywrapstep;                /* zero if no hardware ywrap    */
+       __u32 line_length;              /* length of a line in bytes    */
+       unsigned long mmio_start;       /* Start of Memory Mapped I/O   */
+                                       /* (physical address) */
+       __u32 mmio_len;                 /* Length of Memory Mapped I/O  */
+       __u32 accel;                    /* Indicate to driver which     */
+                                       /*  specific chip/card we have  */
+       __u16 capabilities;             /* see FB_CAP_*                 */
+       __u16 reserved[2];              /* Reserved for future compatibility */
+};
+
+struct fb_var_screeninfo stores device independent changeable information
+about a frame buffer device, its current format and video mode, as well as
+other miscellaneous parameters.
+
+struct fb_var_screeninfo {
+       __u32 xres;                     /* visible resolution           */
+       __u32 yres;
+       __u32 xres_virtual;             /* virtual resolution           */
+       __u32 yres_virtual;
+       __u32 xoffset;                  /* offset from virtual to visible */
+       __u32 yoffset;                  /* resolution                   */
+
+       __u32 bits_per_pixel;           /* guess what                   */
+       __u32 grayscale;                /* 0 = color, 1 = grayscale,    */
+                                       /* >1 = FOURCC                  */
+       struct fb_bitfield red;         /* bitfield in fb mem if true color, */
+       struct fb_bitfield green;       /* else only length is significant */
+       struct fb_bitfield blue;
+       struct fb_bitfield transp;      /* transparency                 */
+
+       __u32 nonstd;                   /* != 0 Non standard pixel format */
+
+       __u32 activate;                 /* see FB_ACTIVATE_*            */
+
+       __u32 height;                   /* height of picture in mm    */
+       __u32 width;                    /* width of picture in mm     */
+
+       __u32 accel_flags;              /* (OBSOLETE) see fb_info.flags */
+
+       /* Timing: All values in pixclocks, except pixclock (of course) */
+       __u32 pixclock;                 /* pixel clock in ps (pico seconds) */
+       __u32 left_margin;              /* time from sync to picture    */
+       __u32 right_margin;             /* time from picture to sync    */
+       __u32 upper_margin;             /* time from sync to picture    */
+       __u32 lower_margin;
+       __u32 hsync_len;                /* length of horizontal sync    */
+       __u32 vsync_len;                /* length of vertical sync      */
+       __u32 sync;                     /* see FB_SYNC_*                */
+       __u32 vmode;                    /* see FB_VMODE_*               */
+       __u32 rotate;                   /* angle we rotate counter clockwise */
+       __u32 colorspace;               /* colorspace for FOURCC-based modes */
+       __u32 reserved[4];              /* Reserved for future compatibility */
+};
+
+To modify variable information, applications call the FBIOPUT_VSCREENINFO
+ioctl with a pointer to a fb_var_screeninfo structure. If the call is
+successful, the driver will update the fixed screen information accordingly.
+
+Instead of filling the complete fb_var_screeninfo structure manually,
+applications should call the FBIOGET_VSCREENINFO ioctl and modify only the
+fields they care about.
+
+
+4. Format configuration
+-----------------------
+
+Frame buffer devices offer two ways to configure the frame buffer format: the
+legacy API and the FOURCC-based API.
+
+
+The legacy API has been the only frame buffer format configuration API for a
+long time and is thus widely used by application. It is the recommended API
+for applications when using RGB and grayscale formats, as well as legacy
+non-standard formats.
+
+To select a format, applications set the fb_var_screeninfo bits_per_pixel field
+to the desired frame buffer depth. Values up to 8 will usually map to
+monochrome, grayscale or pseudocolor visuals, although this is not required.
+
+- For grayscale formats, applications set the grayscale field to one. The red,
+  blue, green and transp fields must be set to 0 by applications and ignored by
+  drivers. Drivers must fill the red, blue and green offsets to 0 and lengths
+  to the bits_per_pixel value.
+
+- For pseudocolor formats, applications set the grayscale field to zero. The
+  red, blue, green and transp fields must be set to 0 by applications and
+  ignored by drivers. Drivers must fill the red, blue and green offsets to 0
+  and lengths to the bits_per_pixel value.
+
+- For truecolor and directcolor formats, applications set the grayscale field
+  to zero, and the red, blue, green and transp fields to describe the layout of
+  color components in memory.
+
+struct fb_bitfield {
+       __u32 offset;                   /* beginning of bitfield        */
+       __u32 length;                   /* length of bitfield           */
+       __u32 msb_right;                /* != 0 : Most significant bit is */
+                                       /* right */
+};
+
+  Pixel values are bits_per_pixel wide and are split in non-overlapping red,
+  green, blue and alpha (transparency) components. Location and size of each
+  component in the pixel value are described by the fb_bitfield offset and
+  length fields. Offset are computed from the right.
+
+  Pixels are always stored in an integer number of bytes. If the number of
+  bits per pixel is not a multiple of 8, pixel values are padded to the next
+  multiple of 8 bits.
+
+Upon successful format configuration, drivers update the fb_fix_screeninfo
+type, visual and line_length fields depending on the selected format.
+
+
+The FOURCC-based API replaces format descriptions by four character codes
+(FOURCC). FOURCCs are abstract identifiers that uniquely define a format
+without explicitly describing it. This is the only API that supports YUV
+formats. Drivers are also encouraged to implement the FOURCC-based API for RGB
+and grayscale formats.
+
+Drivers that support the FOURCC-based API report this capability by setting
+the FB_CAP_FOURCC bit in the fb_fix_screeninfo capabilities field.
+
+FOURCC definitions are located in the linux/videodev2.h header. However, and
+despite starting with the V4L2_PIX_FMT_prefix, they are not restricted to V4L2
+and don't require usage of the V4L2 subsystem. FOURCC documentation is
+available in Documentation/DocBook/v4l/pixfmt.xml.
+
+To select a format, applications set the grayscale field to the desired FOURCC.
+For YUV formats, they should also select the appropriate colorspace by setting
+the colorspace field to one of the colorspaces listed in linux/videodev2.h and
+documented in Documentation/DocBook/v4l/colorspaces.xml.
+
+The red, green, blue and transp fields are not used with the FOURCC-based API.
+For forward compatibility reasons applications must zero those fields, and
+drivers must ignore them. Values other than 0 may get a meaning in future
+extensions.
+
+Upon successful format configuration, drivers update the fb_fix_screeninfo
+type, visual and line_length fields depending on the selected format. The type
+and visual fields are set to FB_TYPE_FOURCC and FB_VISUAL_FOURCC respectively.
index d49c2ec72d12762ee01c2c9474bc573efb53c26a..1bea46a54b1ca252b5390c422f291dafe41a7c32 100644 (file)
@@ -439,52 +439,6 @@ Who:       Jean Delvare <khali@linux-fr.org>
 
 ----------------------------
 
-What:  Support for driver specific ioctls in the pwc driver (everything
-       defined in media/pwc-ioctl.h)
-When:  3.3
-Why:   This stems from the v4l1 era, with v4l2 everything can be done with
-       standardized v4l2 API calls
-Who:   Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:  Driver specific sysfs API in the pwc driver
-When:  3.3
-Why:   Setting pan/tilt should be done with v4l2 controls, like with other
-       cams. The button is available as a standard input device
-Who:   Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:  Driver specific use of pixfmt.priv in the pwc driver
-When:  3.3
-Why:   The .priv field never was intended for this, setting a framerate is
-       support using the standardized S_PARM ioctl
-Who:   Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:  Software emulation of arbritary resolutions in the pwc driver
-When:  3.3
-Why:   The pwc driver claims to support any resolution between 160x120
-       and 640x480, but emulates this by simply drawing a black border
-       around the image. Userspace can draw its own black border if it
-       really wants one.
-Who:   Hans de Goede <hdegoede@redhat.com>
-
-----------------------------
-
-What:  For VIDIOC_S_FREQUENCY the type field must match the device node's type.
-       If not, return -EINVAL.
-When:  3.2
-Why:   It makes no sense to switch the tuner to radio mode by calling
-       VIDIOC_S_FREQUENCY on a video node, or to switch the tuner to tv mode by
-       calling VIDIOC_S_FREQUENCY on a radio node. This is the first step of a
-       move to more consistent handling of tv and radio tuners.
-Who:   Hans Verkuil <hans.verkuil@cisco.com>
-
-----------------------------
-
 What:  Opening a radio device node will no longer automatically switch the
        tuner mode from tv to radio.
 When:  3.3
index 763d8ebbbebdeb59129742daa5f5b7a105ac8fbb..d6030aa3337605e7550397a303820952c8666bc8 100644 (file)
@@ -119,12 +119,20 @@ Mount Options
        must rely on TCP's error correction to detect data corruption
        in the data payload.
 
-  noasyncreaddir
-       Disable client's use its local cache to satisfy readdir
-       requests.  (This does not change correctness; the client uses
-       cached metadata only when a lease or capability ensures it is
-       valid.)
+  dcache
+        Use the dcache contents to perform negative lookups and
+        readdir when the client has the entire directory contents in
+        its cache.  (This does not change correctness; the client uses
+        cached metadata only when a lease or capability ensures it is
+        valid.)
+
+  nodcache
+        Do not use the dcache as above.  This avoids a significant amount of
+        complex code, sacrificing performance without affecting correctness,
+        and is useful for tracking down bugs.
 
+  noasyncreaddir
+       Do not use the dcache as above for readdir.
 
 More Information
 ================
index a57e12411d2a2570511df65500989110121e476e..1716874a651e1c574e7ca9719dfb4e3521b0a5e9 100644 (file)
@@ -2,6 +2,8 @@
        - this file (nfs-related documentation).
 Exporting
        - explanation of how to make filesystems exportable.
+fault_injection.txt
+       - information for using fault injection on the server
 knfsd-stats.txt
        - statistics which the NFS server makes available to user space.
 nfs.txt
diff --git a/Documentation/filesystems/nfs/fault_injection.txt b/Documentation/filesystems/nfs/fault_injection.txt
new file mode 100644 (file)
index 0000000..426d166
--- /dev/null
@@ -0,0 +1,69 @@
+
+Fault Injection
+===============
+Fault injection is a method for forcing errors that may not normally occur, or
+may be difficult to reproduce.  Forcing these errors in a controlled environment
+can help the developer find and fix bugs before their code is shipped in a
+production system.  Injecting an error on the Linux NFS server will allow us to
+observe how the client reacts and if it manages to recover its state correctly.
+
+NFSD_FAULT_INJECTION must be selected when configuring the kernel to use this
+feature.
+
+
+Using Fault Injection
+=====================
+On the client, mount the fault injection server through NFS v4.0+ and do some
+work over NFS (open files, take locks, ...).
+
+On the server, mount the debugfs filesystem to <debug_dir> and ls
+<debug_dir>/nfsd.  This will show a list of files that will be used for
+injecting faults on the NFS server.  As root, write a number n to the file
+corresponding to the action you want the server to take.  The server will then
+process the first n items it finds.  So if you want to forget 5 locks, echo '5'
+to <debug_dir>/nfsd/forget_locks.  A value of 0 will tell the server to forget
+all corresponding items.  A log message will be created containing the number
+of items forgotten (check dmesg).
+
+Go back to work on the client and check if the client recovered from the error
+correctly.
+
+
+Available Faults
+================
+forget_clients:
+     The NFS server keeps a list of clients that have placed a mount call.  If
+     this list is cleared, the server will have no knowledge of who the client
+     is, forcing the client to reauthenticate with the server.
+
+forget_openowners:
+     The NFS server keeps a list of what files are currently opened and who
+     they were opened by.  Clearing this list will force the client to reopen
+     its files.
+
+forget_locks:
+     The NFS server keeps a list of what files are currently locked in the VFS.
+     Clearing this list will force the client to reclaim its locks (files are
+     unlocked through the VFS as they are cleared from this list).
+
+forget_delegations:
+     A delegation is used to assure the client that a file, or part of a file,
+     has not changed since the delegation was awarded.  Clearing this list will
+     force the client to reaquire its delegation before accessing the file
+     again.
+
+recall_delegations:
+     Delegations can be recalled by the server when another client attempts to
+     access a file.  This test will notify the client that its delegation has
+     been revoked, forcing the client to reaquire the delegation before using
+     the file again.
+
+
+tools/nfs/inject_faults.sh script
+=================================
+This script has been created to ease the fault injection process.  This script
+will detect the mounted debugfs directory and write to the files located there
+based on the arguments passed by the user.  For example, running
+`inject_faults.sh forget_locks 1` as root will instruct the server to forget
+one lock.  Running `inject_faults forget_locks` will instruct the server to
+forgetall locks.
index 12fee132fbe2e37da5a7441cb281120d367099a2..a76a26a1db8a6fe855b0eeea32dee251296c0c8a 100644 (file)
@@ -307,6 +307,9 @@ Table 1-4: Contents of the stat files (as of 2.6.30-rc7)
   blkio_ticks   time spent waiting for block IO
   gtime         guest time of the task in jiffies
   cgtime        guest time of the task children in jiffies
+  start_data    address above which program data+bss is placed
+  end_data      address below which program data+bss is placed
+  start_brk     address above which program heap can be expanded with brk()
 ..............................................................................
 
 The /proc/PID/maps file containing the currently mapped memory regions and
index 7db3ebda5a4c9afdbd1c4a7baffd039ad220933e..403c090aca39954d378809b55b0585f74085422c 100644 (file)
@@ -93,8 +93,8 @@ byte alignment:
 
 Compressed data blocks are written to the filesystem as files are read from
 the source directory, and checked for duplicates.  Once all file data has been
-written the completed inode, directory, fragment, export and uid/gid lookup
-tables are written.
+written the completed inode, directory, fragment, export, uid/gid lookup and
+xattr tables are written.
 
 3.1 Compression options
 -----------------------
@@ -151,7 +151,7 @@ in each metadata block.  Directories are sorted in alphabetical order,
 and at lookup the index is scanned linearly looking for the first filename
 alphabetically larger than the filename being looked up.  At this point the
 location of the metadata block the filename is in has been found.
-The general idea of the index is ensure only one metadata block needs to be
+The general idea of the index is to ensure only one metadata block needs to be
 decompressed to do a lookup irrespective of the length of the directory.
 This scheme has the advantage that it doesn't require extra memory overhead
 and doesn't require much extra storage on disk.
index 6f496a5867324cc5750f90ecd0fd91d3547b554d..23b7def21ba8bc5fe9e797e2b4cce1b94245d969 100644 (file)
@@ -26,6 +26,10 @@ Supported chips:
     Prefix: 'it8721'
     Addresses scanned: from Super I/O config space (8 I/O ports)
     Datasheet: Not publicly available
+  * IT8728F
+    Prefix: 'it8728'
+    Addresses scanned: from Super I/O config space (8 I/O ports)
+    Datasheet: Not publicly available
   * SiS950   [clone of IT8705F]
     Prefix: 'it87'
     Addresses scanned: from Super I/O config space (8 I/O ports)
@@ -71,7 +75,7 @@ Description
 -----------
 
 This driver implements support for the IT8705F, IT8712F, IT8716F,
-IT8718F, IT8720F, IT8721F, IT8726F, IT8758E and SiS950 chips.
+IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E and SiS950 chips.
 
 These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
 joysticks and other miscellaneous stuff. For hardware monitoring, they
@@ -105,6 +109,9 @@ The IT8726F is just bit enhanced IT8716F with additional hardware
 for AMD power sequencing. Therefore the chip will appear as IT8716F
 to userspace applications.
 
+The IT8728F is considered compatible with the IT8721F, until a datasheet
+becomes available (hopefully.)
+
 Temperatures are measured in degrees Celsius. An alarm is triggered once
 when the Overtemperature Shutdown limit is crossed.
 
@@ -121,8 +128,8 @@ alarm is triggered if the voltage has crossed a programmable minimum or
 maximum limit. Note that minimum in this case always means 'closest to
 zero'; this is important for negative voltage measurements. All voltage
 inputs can measure voltages between 0 and 4.08 volts, with a resolution of
-0.016 volt (except IT8721F/IT8758E: 0.012 volt.) The battery voltage in8 does
-not have limit registers.
+0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery
+voltage in8 does not have limit registers.
 
 On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside
 the chip (in7, in8 and optionally in3). The driver handles this transparently
index b9843eab1afb107d6ffb13239b6df435bd7c8c54..4d30d209881a2861ad95c07208a7179ead236b03 100644 (file)
@@ -12,6 +12,11 @@ Supported chips:
     Addresses scanned: I2C 0x18 and 0x4e
     Datasheet: Publicly available at the National Semiconductor website
                http://www.national.com/pf/LM/LM64.html
+  * National Semiconductor LM96163
+    Prefix: 'lm96163'
+    Addresses scanned: I2C 0x4c
+    Datasheet: Publicly available at the National Semiconductor website
+               http://www.national.com/pf/LM/LM96163.html
 
 Author: Jean Delvare <khali@linux-fr.org>
 
@@ -49,16 +54,24 @@ value for measuring the speed of the fan. It can measure fan speeds down to
 Note that the pin used for fan monitoring is shared with an alert out
 function. Depending on how the board designer wanted to use the chip, fan
 speed monitoring will or will not be possible. The proper chip configuration
-is left to the BIOS, and the driver will blindly trust it.
+is left to the BIOS, and the driver will blindly trust it. Only the original
+LM63 suffers from this limitation, the LM64 and LM96163 have separate pins
+for fan monitoring and alert out. On the LM64, monitoring is always enabled;
+on the LM96163 it can be disabled.
 
 A PWM output can be used to control the speed of the fan. The LM63 has two
 PWM modes: manual and automatic. Automatic mode is not fully implemented yet
 (you cannot define your custom PWM/temperature curve), and mode change isn't
 supported either.
 
-The lm63 driver will not update its values more frequently than every
-second; reading them more often will do no harm, but will return 'old'
-values.
+The lm63 driver will not update its values more frequently than configured with
+the update_interval sysfs attribute; reading them more often will do no harm,
+but will return 'old' values. Values in the automatic fan control lookup table
+(attributes pwm1_auto_*) have their own independent lifetime of 5 seconds.
 
 The LM64 is effectively an LM63 with GPIO lines. The driver does not
 support these GPIO lines at present.
+
+The LM96163 is an enhanced version of LM63 with improved temperature accuracy
+and better PWM resolution. For LM96163, the external temperature sensor type is
+configurable as CPU embedded diode(1) or 3904 transistor(2).
index a4aa8f600e09643beb6a2b505c9c08d00f28166a..1f4dd855a299350ec707fc9ec34630baef29c689 100644 (file)
@@ -304,7 +304,7 @@ value (fastest fan speed) wins.
 temp[1-*]_type Sensor type selection.
                Integers 1 to 6
                RW
-               1: PII/Celeron Diode
+               1: CPU embedded diode
                2: 3904 transistor
                3: thermal diode
                4: thermistor
index 54078ed96b3751724acaf0bd3fdab95df962480f..4840334ea97b30705df13a2c642e976a83621800 100644 (file)
@@ -149,6 +149,7 @@ Code  Seq#(hex)     Include File            Comments
 'M'    01-03   drivers/scsi/megaraid/megaraid_sas.h
 'M'    00-0F   drivers/video/fsl-diu-fb.h      conflict!
 'N'    00-1F   drivers/usb/scanner.h
+'N'    40-7F   drivers/block/nvme.c
 'O'     00-06   mtd/ubi-user.h         UBI
 'P'    all     linux/soundcard.h       conflict!
 'P'    60-6F   sound/sscape_ioctl.h    conflict!
index f47cdefb4d1efc17d4e515df31996f134674649e..ab0a984530d87848435571d857b201484591f73c 100644 (file)
@@ -33,14 +33,15 @@ This document describes the Linux kernel Makefiles.
 
        === 6 Architecture Makefiles
           --- 6.1 Set variables to tweak the build to the architecture
-          --- 6.2 Add prerequisites to archprepare:
-          --- 6.3 List directories to visit when descending
-          --- 6.4 Architecture-specific boot images
-          --- 6.5 Building non-kbuild targets
-          --- 6.6 Commands useful for building a boot image
-          --- 6.7 Custom kbuild commands
-          --- 6.8 Preprocessing linker scripts
-          --- 6.9 Generic header files
+          --- 6.2 Add prerequisites to archheaders:
+          --- 6.3 Add prerequisites to archprepare:
+          --- 6.4 List directories to visit when descending
+          --- 6.5 Architecture-specific boot images
+          --- 6.6 Building non-kbuild targets
+          --- 6.7 Commands useful for building a boot image
+          --- 6.8 Custom kbuild commands
+          --- 6.9 Preprocessing linker scripts
+          --- 6.10 Generic header files
 
        === 7 Kbuild syntax for exported headers
                --- 7.1 header-y
@@ -252,7 +253,7 @@ more details, with real examples.
        This will create a library lib.a based on delay.o. For kbuild to
        actually recognize that there is a lib.a being built, the directory
        shall be listed in libs-y.
-       See also "6.3 List directories to visit when descending".
+       See also "6.4 List directories to visit when descending".
 
        Use of lib-y is normally restricted to lib/ and arch/*/lib.
 
@@ -974,7 +975,20 @@ When kbuild executes, the following steps are followed (roughly):
        $(KBUILD_ARFLAGS) set by the top level Makefile to "D" (deterministic
        mode) if this option is supported by $(AR).
 
---- 6.2 Add prerequisites to archprepare:
+--- 6.2 Add prerequisites to archheaders:
+
+       The archheaders: rule is used to generate header files that
+       may be installed into user space by "make header_install" or
+       "make headers_install_all".  In order to support
+       "make headers_install_all", this target has to be able to run
+       on an unconfigured tree, or a tree configured for another
+       architecture.
+
+       It is run before "make archprepare" when run on the
+       architecture itself.
+
+
+--- 6.3 Add prerequisites to archprepare:
 
        The archprepare: rule is used to list prerequisites that need to be
        built before starting to descend down in the subdirectories.
@@ -990,7 +1004,7 @@ When kbuild executes, the following steps are followed (roughly):
        generating offset header files.
 
 
---- 6.3 List directories to visit when descending
+--- 6.4 List directories to visit when descending
 
        An arch Makefile cooperates with the top Makefile to define variables
        which specify how to build the vmlinux file.  Note that there is no
@@ -1019,7 +1033,7 @@ When kbuild executes, the following steps are followed (roughly):
                drivers-$(CONFIG_OPROFILE)  += arch/sparc64/oprofile/
 
 
---- 6.4 Architecture-specific boot images
+--- 6.5 Architecture-specific boot images
 
        An arch Makefile specifies goals that take the vmlinux file, compress
        it, wrap it in bootstrapping code, and copy the resulting files
@@ -1070,7 +1084,7 @@ When kbuild executes, the following steps are followed (roughly):
 
        When "make" is executed without arguments, bzImage will be built.
 
---- 6.5 Building non-kbuild targets
+--- 6.6 Building non-kbuild targets
 
     extra-y
 
@@ -1090,7 +1104,7 @@ When kbuild executes, the following steps are followed (roughly):
        shall be built, but shall not be linked as part of built-in.o.
 
 
---- 6.6 Commands useful for building a boot image
+--- 6.7 Commands useful for building a boot image
 
        Kbuild provides a few macros that are useful when building a
        boot image.
@@ -1112,7 +1126,7 @@ When kbuild executes, the following steps are followed (roughly):
        always be built.
        Assignments to $(targets) are without $(obj)/ prefix.
        if_changed may be used in conjunction with custom commands as
-       defined in 6.7 "Custom kbuild commands".
+       defined in 6.8 "Custom kbuild commands".
 
        Note: It is a typical mistake to forget the FORCE prerequisite.
        Another common pitfall is that whitespace is sometimes
@@ -1171,7 +1185,7 @@ When kbuild executes, the following steps are followed (roughly):
                $(obj)/%.dtb: $(src)/%.dts
                        $(call cmd,dtc)
 
---- 6.7 Custom kbuild commands
+--- 6.8 Custom kbuild commands
 
        When kbuild is executing with KBUILD_VERBOSE=0, then only a shorthand
        of a command is normally displayed.
@@ -1198,7 +1212,7 @@ When kbuild executes, the following steps are followed (roughly):
        will be displayed with "make KBUILD_VERBOSE=0".
 
 
---- 6.8 Preprocessing linker scripts
+--- 6.9 Preprocessing linker scripts
 
        When the vmlinux image is built, the linker script
        arch/$(ARCH)/kernel/vmlinux.lds is used.
@@ -1228,7 +1242,7 @@ When kbuild executes, the following steps are followed (roughly):
        The kbuild infrastructure for *lds file are used in several
        architecture-specific files.
 
---- 6.9 Generic header files
+--- 6.10 Generic header files
 
        The directory include/asm-generic contains the header files
        that may be shared between individual architectures.
index eb93fd0ec734760224a16e87c2be8b391f604b55..033d4e69b43b107d9780ec959105823e6cefd07c 100644 (file)
@@ -1059,6 +1059,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        By default, super page will be supported if Intel IOMMU
                        has the capability. With this option, super page will
                        not be supported.
+
+       intel_idle.max_cstate=  [KNL,HW,ACPI,X86]
+                       0       disables intel_idle and fall back on acpi_idle.
+                       1 to 6  specify maximum depth of C-state.
+
        intremap=       [X86-64, Intel-IOMMU]
                        on      enable Interrupt Remapping (default)
                        off     disable Interrupt Remapping
@@ -2475,6 +2480,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        stacktrace      [FTRACE]
                        Enabled the stack tracer on boot up.
 
+       stacktrace_filter=[function-list]
+                       [FTRACE] Limit the functions that the stack tracer
+                       will trace at boot up. function-list is a comma separated
+                       list of functions. This list can be changed at run
+                       time by the stack_trace_filter file in the debugfs
+                       tracing directory. Note, this enables stack tracing
+                       and the stacktrace above is not needed.
+
        sti=            [PARISC,HW]
                        Format: <num>
                        Set the STI (builtin display/keyboard on the HP-PARISC
index 51063e681ca4f8cc0b628d2a46503ad1762aeaf5..b6e39739a36d01e2da283e806de131a4bc18890d 100644 (file)
@@ -127,7 +127,10 @@ See the include/linux/kmemleak.h header for the functions prototype.
 
 kmemleak_init           - initialize kmemleak
 kmemleak_alloc          - notify of a memory block allocation
+kmemleak_alloc_percpu   - notify of a percpu memory block allocation
 kmemleak_free           - notify of a memory block freeing
+kmemleak_free_part      - notify of a partial memory block freeing
+kmemleak_free_percpu    - notify of a percpu memory block freeing
 kmemleak_not_leak       - mark an object as not a leak
 kmemleak_ignore                 - do not scan or report an object as leak
 kmemleak_scan_area      - add scan areas inside a memory block
index 8898a95b41e5ee1b277cd64697870726b11bc2fa..22ae8441489fcef3fe8f21ff4322dc3a8b85e5e6 100644 (file)
@@ -64,3 +64,13 @@ Note on Erase Size and Preferred Erase Size:
        size specified by the card.
 
        "preferred_erase_size" is in bytes.
+
+SD/MMC/SDIO Clock Gating Attribute
+==================================
+
+Read and write access is provided to following attribute.
+This attribute appears only if CONFIG_MMC_CLKGATE is enabled.
+
+       clkgate_delay   Tune the clock gating delay with desired value in milliseconds.
+
+echo <desired delay> > /sys/class/mmc_host/mmcX/clkgate_delay
index 2db28b8e662fc870a0f63066c39ff24b1666eafa..f08d078d43cff58e7ab939dae1f1108f7c3a517b 100644 (file)
@@ -25,3 +25,16 @@ echo 0 > /sys/block/mmcblkXbootY/force_ro
 To re-enable read-only access:
 
 echo 1 > /sys/block/mmcblkXbootY/force_ro
+
+The boot partitions can also be locked read only until the next power on,
+with:
+
+echo 1 > /sys/block/mmcblkXbootY/ro_lock_until_next_power_on
+
+This is a feature of the card and not of the kernel. If the card does
+not support boot partition locking, the file will not exist. If the
+feature has been disabled on the card, the file will be read-only.
+
+The boot partitions can also be locked permanently, but this feature is
+not accessible through sysfs in order to avoid accidental or malicious
+bricking.
index 64adb98b181c717f763bff24109bc8bf9aff104a..57566bacb4c56c8182f0e9b16bafe74c9b1233ab 100644 (file)
@@ -1,3 +1,13 @@
+Release Date    : Fri. Jan 6, 2012 17:00:00 PST 2010 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Adam Radford
+Current Version : 00.00.06.14-rc1
+Old Version     : 00.00.06.12-rc1
+    1. Fix reglockFlags for degraded raid5/6 for MR 9360/9380.
+    2. Mask off flags in ioctl path to prevent memory scribble with older
+       MegaCLI versions.
+    3. Remove poll_mode_io module paramater, sysfs node, and associated code.
+-------------------------------------------------------------------------------
 Release Date    : Wed. Oct 5, 2011 17:00:00 PST 2010 -
                        (emaild-id:megaraidlinux@lsi.com)
                        Adam Radford
index 494980e404912a861a238423e9189708549eaa66..ab899591ecb7a93dfe6c8b936042c3b8f400bd42 100644 (file)
@@ -1,32 +1,11 @@
 Copyright (c) 2003-2011 QLogic Corporation
-QLogic Linux iSCSI HBA Driver
+QLogic Linux iSCSI Driver
 
 This program includes a device driver for Linux 3.x.
 You may modify and redistribute the device driver code under the
 GNU General Public License (a copy of which is attached hereto as
 Exhibit A) published by the Free Software Foundation (version 2).
 
-REGARDLESS OF WHAT LICENSING MECHANISM IS USED OR APPLICABLE,
-THIS PROGRAM IS PROVIDED BY QLOGIC CORPORATION "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 THE AUTHOR
-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.
-
-USER ACKNOWLEDGES AND AGREES THAT USE OF THIS PROGRAM WILL NOT
-CREATE OR GIVE GROUNDS FOR A LICENSE BY IMPLICATION, ESTOPPEL, OR
-OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS (PATENT, COPYRIGHT,
-TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT) EMBODIED IN
-ANY OTHER QLOGIC HARDWARE OR SOFTWARE EITHER SOLELY OR IN
-COMBINATION WITH THIS PROGRAM.
-
 
 EXHIBIT A
 
index 6d8cd8b2c30d9d6104d05654e22fd85ed1e7032d..8c20fbd8b42dd922daa92f223bbefa9ffcc4f8e3 100644 (file)
@@ -415,6 +415,14 @@ PIDs of value pid_max or larger are not allocated.
 
 ==============================================================
 
+ns_last_pid:
+
+The last pid allocated in the current (the one task using this sysctl
+lives in) pid namespace. When selecting a pid for a next task on fork
+kernel tries to allocate a number starting from this one.
+
+==============================================================
+
 powersave-nap: (PPC only)
 
 If set, Linux-PPC will use the 'nap' mode of powersaving,
index 7ef9b843d529a5fadbe05eb19ad6c34fd8293cd5..6e21b8b52638a1f0ab014cd46b532d341ba17619 100755 (executable)
@@ -230,14 +230,9 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "#include <linux/ctype.h>\n"
        buf += "#include <asm/unaligned.h>\n\n"
        buf += "#include <target/target_core_base.h>\n"
-       buf += "#include <target/target_core_transport.h>\n"
-       buf += "#include <target/target_core_fabric_ops.h>\n"
+       buf += "#include <target/target_core_fabric.h>\n"
        buf += "#include <target/target_core_fabric_configfs.h>\n"
-       buf += "#include <target/target_core_fabric_lib.h>\n"
-       buf += "#include <target/target_core_device.h>\n"
-       buf += "#include <target/target_core_tpg.h>\n"
        buf += "#include <target/target_core_configfs.h>\n"
-       buf += "#include <target/target_core_base.h>\n"
        buf += "#include <target/configfs_macros.h>\n\n"
        buf += "#include \"" + fabric_mod_name + "_base.h\"\n"
        buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n"
@@ -260,7 +255,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        /* " + fabric_mod_name + "_parse_wwn(name, &wwpn, 1) < 0)\n"
        buf += "                return ERR_PTR(-EINVAL); */\n"
        buf += "        se_nacl_new = " + fabric_mod_name + "_alloc_fabric_acl(se_tpg);\n"
-       buf += "        if (!(se_nacl_new))\n"
+       buf += "        if (!se_nacl_new)\n"
        buf += "                return ERR_PTR(-ENOMEM);\n"
        buf += "//#warning FIXME: Hardcoded nexus depth in " + fabric_mod_name + "_make_nodeacl()\n"
        buf += "        nexus_depth = 1;\n"
@@ -308,7 +303,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        if (strict_strtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)\n"
        buf += "                return ERR_PTR(-EINVAL);\n\n"
        buf += "        tpg = kzalloc(sizeof(struct " + fabric_mod_name + "_tpg), GFP_KERNEL);\n"
-       buf += "        if (!(tpg)) {\n"
+       buf += "        if (!tpg) {\n"
        buf += "                printk(KERN_ERR \"Unable to allocate struct " + fabric_mod_name + "_tpg\");\n"
        buf += "                return ERR_PTR(-ENOMEM);\n"
        buf += "        }\n"
@@ -344,7 +339,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        /* if (" + fabric_mod_name + "_parse_wwn(name, &wwpn, 1) < 0)\n"
        buf += "                return ERR_PTR(-EINVAL); */\n\n"
        buf += "        " + fabric_mod_port + " = kzalloc(sizeof(struct " + fabric_mod_name + "_" + fabric_mod_port + "), GFP_KERNEL);\n"
-       buf += "        if (!(" + fabric_mod_port + ")) {\n"
+       buf += "        if (!" + fabric_mod_port + ") {\n"
        buf += "                printk(KERN_ERR \"Unable to allocate struct " + fabric_mod_name + "_" + fabric_mod_port + "\");\n"
        buf += "                return ERR_PTR(-ENOMEM);\n"
        buf += "        }\n"
@@ -352,7 +347,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        if proto_ident == "FC" or proto_ident == "SAS":
                buf += "        " + fabric_mod_port + "->" + fabric_mod_port + "_wwpn = wwpn;\n"
 
-       buf += "        /* " + fabric_mod_name + "_format_wwn(&" + fabric_mod_port + "->" + fabric_mod_port + "_name[0], " + fabric_mod_name.upper() + "__NAMELEN, wwpn); */\n\n"
+       buf += "        /* " + fabric_mod_name + "_format_wwn(&" + fabric_mod_port + "->" + fabric_mod_port + "_name[0], " + fabric_mod_name.upper() + "_NAMELEN, wwpn); */\n\n"
        buf += "        return &" + fabric_mod_port + "->" + fabric_mod_port + "_wwn;\n"
        buf += "}\n\n"
        buf += "static void " + fabric_mod_name + "_drop_" + fabric_mod_port + "(struct se_wwn *wwn)\n"
@@ -391,8 +386,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        .tpg_alloc_fabric_acl           = " + fabric_mod_name + "_alloc_fabric_acl,\n"
        buf += "        .tpg_release_fabric_acl         = " + fabric_mod_name + "_release_fabric_acl,\n"
        buf += "        .tpg_get_inst_index             = " + fabric_mod_name + "_tpg_get_inst_index,\n"
-       buf += "        .release_cmd_to_pool            = " + fabric_mod_name + "_release_cmd,\n"
-       buf += "        .release_cmd_direct             = " + fabric_mod_name + "_release_cmd,\n"
+       buf += "        .release_cmd                    = " + fabric_mod_name + "_release_cmd,\n"
        buf += "        .shutdown_session               = " + fabric_mod_name + "_shutdown_session,\n"
        buf += "        .close_session                  = " + fabric_mod_name + "_close_session,\n"
        buf += "        .stop_session                   = " + fabric_mod_name + "_stop_session,\n"
@@ -405,14 +399,12 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        .set_default_node_attributes    = " + fabric_mod_name + "_set_default_node_attrs,\n"
        buf += "        .get_task_tag                   = " + fabric_mod_name + "_get_task_tag,\n"
        buf += "        .get_cmd_state                  = " + fabric_mod_name + "_get_cmd_state,\n"
-       buf += "        .new_cmd_failure                = " + fabric_mod_name + "_new_cmd_failure,\n"
        buf += "        .queue_data_in                  = " + fabric_mod_name + "_queue_data_in,\n"
        buf += "        .queue_status                   = " + fabric_mod_name + "_queue_status,\n"
        buf += "        .queue_tm_rsp                   = " + fabric_mod_name + "_queue_tm_rsp,\n"
        buf += "        .get_fabric_sense_len           = " + fabric_mod_name + "_get_fabric_sense_len,\n"
        buf += "        .set_fabric_sense_len           = " + fabric_mod_name + "_set_fabric_sense_len,\n"
        buf += "        .is_state_remove                = " + fabric_mod_name + "_is_state_remove,\n"
-       buf += "        .pack_lun                       = " + fabric_mod_name + "_pack_lun,\n"
        buf += "        /*\n"
        buf += "         * Setup function pointers for generic logic in target_core_fabric_configfs.c\n"
        buf += "         */\n"
@@ -439,9 +431,9 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "         * Register the top level struct config_item_type with TCM core\n"
        buf += "         */\n"
        buf += "        fabric = target_fabric_configfs_init(THIS_MODULE, \"" + fabric_mod_name[4:] + "\");\n"
-       buf += "        if (!(fabric)) {\n"
+       buf += "        if (IS_ERR(fabric)) {\n"
        buf += "                printk(KERN_ERR \"target_fabric_configfs_init() failed\\n\");\n"
-       buf += "                return -ENOMEM;\n"
+       buf += "                return PTR_ERR(fabric);\n"
        buf += "        }\n"
        buf += "        /*\n"
        buf += "         * Setup fabric->tf_ops from our local " + fabric_mod_name + "_ops\n"
@@ -475,9 +467,9 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        printk(KERN_INFO \"" +  fabric_mod_name.upper() + "[0] - Set fabric -> " + fabric_mod_name + "_fabric_configfs\\n\");\n"
        buf += "        return 0;\n"
        buf += "};\n\n"
-       buf += "static void " + fabric_mod_name + "_deregister_configfs(void)\n"
+       buf += "static void __exit " + fabric_mod_name + "_deregister_configfs(void)\n"
        buf += "{\n"
-       buf += "        if (!(" + fabric_mod_name + "_fabric_configfs))\n"
+       buf += "        if (!" + fabric_mod_name + "_fabric_configfs)\n"
        buf += "                return;\n\n"
        buf += "        target_fabric_configfs_deregister(" + fabric_mod_name + "_fabric_configfs);\n"
        buf += "        " + fabric_mod_name + "_fabric_configfs = NULL;\n"
@@ -492,17 +484,15 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "                return ret;\n\n"
        buf += "        return 0;\n"
        buf += "};\n\n"
-       buf += "static void " + fabric_mod_name + "_exit(void)\n"
+       buf += "static void __exit " + fabric_mod_name + "_exit(void)\n"
        buf += "{\n"
        buf += "        " + fabric_mod_name + "_deregister_configfs();\n"
        buf += "};\n\n"
 
-       buf += "#ifdef MODULE\n"
        buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n"
        buf += "MODULE_LICENSE(\"GPL\");\n"
        buf += "module_init(" + fabric_mod_name + "_init);\n"
        buf += "module_exit(" + fabric_mod_name + "_exit);\n"
-       buf += "#endif\n"
 
        ret = p.write(buf)
        if ret:
@@ -514,7 +504,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
 
 def tcm_mod_scan_fabric_ops(tcm_dir):
 
-       fabric_ops_api = tcm_dir + "include/target/target_core_fabric_ops.h"
+       fabric_ops_api = tcm_dir + "include/target/target_core_fabric.h"
 
        print "Using tcm_mod_scan_fabric_ops: " + fabric_ops_api
        process_fo = 0;
@@ -579,11 +569,7 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "#include <scsi/scsi_cmnd.h>\n"
        buf += "#include <scsi/libfc.h>\n\n"
        buf += "#include <target/target_core_base.h>\n"
-       buf += "#include <target/target_core_transport.h>\n"
-       buf += "#include <target/target_core_fabric_ops.h>\n"
-       buf += "#include <target/target_core_fabric_lib.h>\n"
-       buf += "#include <target/target_core_device.h>\n"
-       buf += "#include <target/target_core_tpg.h>\n"
+       buf += "#include <target/target_core_fabric.h>\n"
        buf += "#include <target/target_core_configfs.h>\n\n"
        buf += "#include \"" + fabric_mod_name + "_base.h\"\n"
        buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n"
@@ -788,7 +774,7 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name):
                        buf += "{\n"
                        buf += "        struct " + fabric_mod_name + "_nacl *nacl;\n\n"
                        buf += "        nacl = kzalloc(sizeof(struct " + fabric_mod_name + "_nacl), GFP_KERNEL);\n"
-                       buf += "        if (!(nacl)) {\n"
+                       buf += "        if (!nacl) {\n"
                        buf += "                printk(KERN_ERR \"Unable to alocate struct " + fabric_mod_name + "_nacl\\n\");\n"
                        buf += "                return NULL;\n"
                        buf += "        }\n\n"
@@ -815,7 +801,7 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name):
                        buf += "}\n\n"
                        bufi += "u32 " + fabric_mod_name + "_tpg_get_inst_index(struct se_portal_group *);\n"
 
-               if re.search('release_cmd_to_pool', fo):
+               if re.search('\*release_cmd\)\(', fo):
                        buf += "void " + fabric_mod_name + "_release_cmd(struct se_cmd *se_cmd)\n"
                        buf += "{\n"
                        buf += "        return;\n"
@@ -899,13 +885,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name):
                        buf += "}\n\n"
                        bufi += "int " + fabric_mod_name + "_get_cmd_state(struct se_cmd *);\n"
 
-               if re.search('new_cmd_failure\)\(', fo):
-                       buf += "void " + fabric_mod_name + "_new_cmd_failure(struct se_cmd *se_cmd)\n"
-                       buf += "{\n"
-                       buf += "        return;\n"
-                       buf += "}\n\n"
-                       bufi += "void " + fabric_mod_name + "_new_cmd_failure(struct se_cmd *);\n"
-
                if re.search('queue_data_in\)\(', fo):
                        buf += "int " + fabric_mod_name + "_queue_data_in(struct se_cmd *se_cmd)\n"
                        buf += "{\n"
@@ -948,15 +927,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name):
                        buf += "}\n\n"
                        bufi += "int " + fabric_mod_name + "_is_state_remove(struct se_cmd *);\n"
 
-               if re.search('pack_lun\)\(', fo):
-                       buf += "u64 " + fabric_mod_name + "_pack_lun(unsigned int lun)\n"
-                       buf += "{\n"
-                       buf += "        WARN_ON(lun >= 256);\n"
-                       buf += "        /* Caller wants this byte-swapped */\n"
-                       buf += "        return cpu_to_le64((lun & 0xff) << 8);\n"
-                       buf += "}\n\n"
-                       bufi += "u64 " + fabric_mod_name + "_pack_lun(unsigned int);\n"
-
 
        ret = p.write(buf)
        if ret:
index d5cb4ea287b21dff9086d1d43c77a1874c033931..7b59e953c4bfe8673b7d65314fe9e65feb3676ef 100644 (file)
@@ -1,5 +1,5 @@
   0 -> Unknown board                            (au0828)
-  1 -> Hauppauge HVR950Q                        (au0828)        [2040:7200,2040:7210,2040:7217,2040:721b,2040:721e,2040:721f,2040:7280,0fd9:0008]
+  1 -> Hauppauge HVR950Q                        (au0828)        [2040:7200,2040:7210,2040:7217,2040:721b,2040:721e,2040:721f,2040:7280,0fd9:0008,2040:7260,2040:7213]
   2 -> Hauppauge HVR850                         (au0828)        [2040:7240]
   3 -> DViCO FusionHDTV USB                     (au0828)        [0fe9:d620]
   4 -> Hauppauge HVR950Q rev xxF8               (au0828)        [2040:7201,2040:7211,2040:7281]
index 4739d568430599002d61d163be47a4be9e7a9f23..b753906c71830b892d95b623c857a767ba885571 100644 (file)
@@ -71,7 +71,7 @@
  70 -> Prolink Pixelview PV-BT878P+ (Rev.4C,8E)
  71 -> Lifeview FlyVideo 98EZ (capture only) LR51          [1851:1851]
  72 -> Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM) [1554:4011]
- 73 -> Sensoray 311                                        [6000:0311]
+ 73 -> Sensoray 311/611                                    [6000:0311,6000:0611]
  74 -> RemoteVision MX (RV605)
  75 -> Powercolor MTV878/ MTV878R/ MTV878F
  76 -> Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP) [0e11:0079]
 157 -> Geovision GV-800(S) (master)                        [800a:763d]
 158 -> Geovision GV-800(S) (slave)                         [800b:763d,800c:763d,800d:763d]
 159 -> ProVideo PV183                                      [1830:1540,1831:1540,1832:1540,1833:1540,1834:1540,1835:1540,1836:1540,1837:1540]
+160 -> Tongwei Video Technology TD-3116                    [f200:3116]
index 8910449d23a8e355cc1fc86dd400638224166fc4..23584d0c6a753fddd12f5ee3fbd213c8d78665db 100644 (file)
@@ -29,3 +29,6 @@
  28 -> LEADTEK WinFast PxTV1200                            [107d:6f22]
  29 -> GoTView X5 3D Hybrid                                [5654:2390]
  30 -> NetUP Dual DVB-T/C-CI RF                            [1b55:e2e4]
+ 31 -> Leadtek Winfast PxDVR3200 H XC4000                  [107d:6f39]
+ 32 -> MPX-885
+ 33 -> Mygica X8507                                        [14f1:8502]
index d9c0f119196d0f2ef15dc1f3a70e40fd46e3524b..eee18e6962b6c9ae54a830dbcf8ad14b54bc742b 100644 (file)
@@ -85,3 +85,5 @@
  84 -> Samsung SMT 7020 DVB-S                              [18ac:dc00,18ac:dccd]
  85 -> Twinhan VP-1027 DVB-S                               [1822:0023]
  86 -> TeVii S464 DVB-S/S2                                 [d464:9022]
+ 87 -> Leadtek WinFast DTV2000 H PLUS                      [107d:6f42]
+ 88 -> Leadtek WinFast DTV1800 H (XC4000)                  [107d:6f38]
index 4a7b3df6d8bd7695a0cee2417d3d849b43912345..e7be3ac49ead4d9c72fa64b9f259f8215f85cd29 100644 (file)
@@ -11,7 +11,7 @@
  10 -> Hauppauge WinTV HVR 900                  (em2880)        [2040:6500]
  11 -> Terratec Hybrid XS                       (em2880)
  12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
- 13 -> Terratec Prodigy XS                      (em2880)        [0ccd:0047]
+ 13 -> Terratec Prodigy XS                      (em2880)
  14 -> SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0 (em2820/em2840)
  15 -> V-Gear PocketTV                          (em2800)
  16 -> Hauppauge WinTV HVR 950                  (em2883)        [2040:6513,2040:6517,2040:651b]
@@ -40,7 +40,7 @@
  39 -> KWorld PVRTV 300U                        (em2861)        [eb1a:e300]
  40 -> Plextor ConvertX PX-TV100U               (em2861)        [093b:a005]
  41 -> Kworld 350 U DVB-T                       (em2870)        [eb1a:e350]
- 42 -> Kworld 355 U DVB-T                       (em2870)        [eb1a:e355,eb1a:e357]
+ 42 -> Kworld 355 U DVB-T                       (em2870)        [eb1a:e355,eb1a:e357,eb1a:e359]
  43 -> Terratec Cinergy T XS                    (em2870)        [0ccd:0043]
  44 -> Terratec Cinergy T XS (MT2060)           (em2870)
  45 -> Pinnacle PCTV DVB-T                      (em2870)
@@ -64,7 +64,7 @@
  64 -> Easy Cap Capture DC-60                   (em2860)
  65 -> IO-DATA GV-MVP/SZ                        (em2820/em2840) [04bb:0515]
  66 -> Empire dual TV                           (em2880)
- 67 -> Terratec Grabby                          (em2860)        [0ccd:0096]
+ 67 -> Terratec Grabby                          (em2860)        [0ccd:0096,0ccd:10AF]
  68 -> Terratec AV350                           (em2860)        [0ccd:0084]
  69 -> KWorld ATSC 315U HDTV TV Box             (em2882)        [eb1a:a313]
  70 -> Evga inDtube                             (em2882)
@@ -76,3 +76,7 @@
  76 -> KWorld PlusTV 340U or UB435-Q (ATSC)     (em2870)        [1b80:a340]
  77 -> EM2874 Leadership ISDBT                  (em2874)
  78 -> PCTV nanoStick T2 290e                   (em28174)
+ 79 -> Terratec Cinergy H5                      (em2884)        [0ccd:10a2,0ccd:10ad]
+ 80 -> PCTV DVB-S2 Stick (460e)                 (em28174)
+ 81 -> Hauppauge WinTV HVR 930C                 (em2884)        [2040:1605]
+ 82 -> Terratec Cinergy HTC Stick               (em2884)        [0ccd:00b2]
index 7efae9bd73eda9445ce6db29c079a20510d53a49..e7ef38a19859964f922aef707ab4f254b9ab8a22 100644 (file)
 185 -> MagicPro ProHDTV Pro2 DMB-TH/Hybrid      [17de:d136]
 186 -> Beholder BeholdTV 501                    [5ace:5010]
 187 -> Beholder BeholdTV 503 FM                 [5ace:5030]
+188 -> Sensoray 811/911                         [6000:0811,6000:0911]
index 152bd7b781ca51b5ceded74bb121642c50f8783b..2205e8d55537ccaf69395eed7540ae46149cec9e 100644 (file)
@@ -7,3 +7,5 @@
   6 -> Hauppauge WinTV-HVR2200                             [0070:8901]
   7 -> Hauppauge WinTV-HVR2250                             [0070:8891,0070:8851]
   8 -> Hauppauge WinTV-HVR2250                             [0070:88A1]
+  9 -> Hauppauge WinTV-HVR2200                             [0070:8940]
+ 10 -> Hauppauge WinTV-HVR2200                             [0070:8953]
index b15e29f3112113416f238cb686047430caf17eeb..f2060f0dc02c055b0f380174aa99a140b1cb1615 100644 (file)
@@ -189,6 +189,7 @@ ov519               05a9:0511       Video Blaster WebCam 3/WebCam Plus, D-Link USB Digital Video Ca
 ov519          05a9:0518       Creative WebCam
 ov519          05a9:0519       OV519 Microphone
 ov519          05a9:0530       OmniVision
+ov534_9                05a9:1550       OmniVision VEHO Filmscanner
 ov519          05a9:2800       OmniVision SuperCAM
 ov519          05a9:4519       Webcam Classic
 ov534_9                05a9:8065       OmniVision test kit ov538+ov9712
@@ -278,6 +279,7 @@ pac7302             093a:2628       Genius iLook 300
 pac7302                093a:2629       Genious iSlim 300
 pac7302                093a:262a       Webcam 300k
 pac7302                093a:262c       Philips SPC 230 NC
+jl2005bcd      0979:0227       Various brands, 19 known cameras supported
 jeilinj                0979:0280       Sakar 57379
 jeilinj                0979:0280       Sportscam DV15
 zc3xx          0ac8:0302       Z-star Vimicro zc0302
index 26aa0573933e8f5f970f7f18b3f53f0afd37eb6d..e2492a9d1027b95be62b9fde675b043643a7f01c 100644 (file)
@@ -666,27 +666,6 @@ a control of this type whenever the first control belonging to a new control
 class is added.
 
 
-Differences from the Spec
-=========================
-
-There are a few places where the framework acts slightly differently from the
-V4L2 Specification. Those differences are described in this section. We will
-have to see whether we need to adjust the spec or not.
-
-1) It is no longer required to have all controls contained in a
-v4l2_ext_control array be from the same control class. The framework will be
-able to handle any type of control in the array. You need to set ctrl_class
-to 0 in order to enable this. If ctrl_class is non-zero, then it will still
-check that all controls belong to that control class.
-
-If you set ctrl_class to 0 and count to 0, then it will only return an error
-if there are no controls at all.
-
-2) Clarified the way error_idx works. For get and set it will be equal to
-count if nothing was done yet. If it is less than count then only the controls
-up to error_idx-1 were successfully applied.
-
-
 Proposals for Extensions
 ========================
 
index f8dcabf7852cfa1f26ef5103703083539e14f7ab..659b2ba12a4fd69297073c0e68c69ec992d83b1f 100644 (file)
@@ -612,6 +612,12 @@ You can set a pointer to a mutex_lock in struct video_device. Usually this
 will be either a top-level mutex or a mutex per device node. If you want
 finer-grained locking then you have to set it to NULL and do you own locking.
 
+It is up to the driver developer to decide which method to use. However, if
+your driver has high-latency operations (for example, changing the exposure
+of a USB webcam might take a long time), then you might be better off with
+doing your own locking if you want to allow the user to do other things with
+the device while waiting for the high-latency command to finish.
+
 If a lock is specified then all file operations will be serialized on that
 lock. If you use videobuf then you must pass the same lock to the videobuf
 queue initialize function: if videobuf has to wait for a frame to arrive, then
@@ -619,6 +625,11 @@ it will temporarily unlock the lock and relock it afterwards. If your driver
 also waits in the code, then you should do the same to allow other processes
 to access the device node while the first process is waiting for something.
 
+In the case of videobuf2 you will need to implement the wait_prepare and
+wait_finish callbacks to unlock/lock if applicable. In particular, if you use
+the lock in struct video_device then you must unlock/lock this mutex in
+wait_prepare and wait_finish.
+
 The implementation of a hotplug disconnect should also take the lock before
 calling v4l2_device_disconnect.
 
index 2acdda9601b097958ad4ea732ba784a1ed4fffce..6752870c4970d73721c48a041b15aa36af929ab5 100644 (file)
@@ -131,7 +131,10 @@ slub_min_objects.
 slub_max_order specified the order at which slub_min_objects should no
 longer be checked. This is useful to avoid SLUB trying to generate
 super large order pages to fit slub_min_objects of a slab cache with
-large object sizes into one high order page.
+large object sizes into one high order page. Setting command line
+parameter debug_guardpage_minorder=N (N > 0), forces setting
+slub_max_order to 0, what cause minimum possible order of slabs
+allocation.
 
 SLUB Debug output
 -----------------
index 1094edf0da173d2e77a34b7515cfa9b81d939f0a..89b70df91f4f66d01e728ef4346f7cf6d598f121 100644 (file)
@@ -745,6 +745,7 @@ M:  Barry Song <baohua.song@csr.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-prima2/
+F:     drivers/dma/sirf-dma*
 
 ARM/EBSA110 MACHINE SUPPORT
 M:     Russell King <linux@arm.linux.org.uk>
@@ -1411,6 +1412,7 @@ F:        net/ax25/
 B43 WIRELESS DRIVER
 M:     Stefano Brivio <stefano.brivio@polimi.it>
 L:     linux-wireless@vger.kernel.org
+L:     b43-dev@lists.infradead.org (moderated for non-subscribers)
 W:     http://linuxwireless.org/en/users/Drivers/b43
 S:     Maintained
 F:     drivers/net/wireless/b43/
@@ -1587,6 +1589,13 @@ L:       linux-scsi@vger.kernel.org
 S:     Supported
 F:     drivers/scsi/bnx2fc/
 
+BROADCOM SPECIFIC AMBA DRIVER (BCMA)
+M:     RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>
+L:     linux-wireless@vger.kernel.org
+S:     Maintained
+F:     drivers/bcma/
+F:     include/linux/bcma/
+
 BROCADE BFA FC SCSI DRIVER
 M:     Jing Huang <huangj@brocade.com>
 L:     linux-scsi@vger.kernel.org
@@ -2821,6 +2830,14 @@ L:       platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     drivers/platform/x86/fujitsu-laptop.c
 
+FUJITSU M-5MO LS CAMERA ISP DRIVER
+M:     Kyungmin Park <kyungmin.park@samsung.com>
+M:     Heungjun Kim <riverful.kim@samsung.com>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     drivers/media/video/m5mols/
+F:     include/media/m5mols.h
+
 FUSE: FILESYSTEM IN USERSPACE
 M:     Miklos Szeredi <miklos@szeredi.hu>
 L:     fuse-devel@lists.sourceforge.net
@@ -3193,6 +3210,7 @@ F:        drivers/i2c/busses/i2c-stub.c
 I2C SUBSYSTEM
 M:     "Jean Delvare (PC drivers, core)" <khali@linux-fr.org>
 M:     "Ben Dooks (embedded platforms)" <ben-linux@fluff.org>
+M:     "Wolfram Sang (embedded platforms)" <w.sang@pengutronix.de>
 L:     linux-i2c@vger.kernel.org
 W:     http://i2c.wiki.kernel.org/
 T:     quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/
@@ -3774,7 +3792,6 @@ S:        Odd Fixes
 
 KERNEL NFSD, SUNRPC, AND LOCKD SERVERS
 M:     "J. Bruce Fields" <bfields@fieldses.org>
-M:     Neil Brown <neilb@suse.de>
 L:     linux-nfs@vger.kernel.org
 W:     http://nfs.sourceforge.net/
 S:     Supported
@@ -4683,6 +4700,8 @@ Q:        http://patchwork.kernel.org/project/linux-omap/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git
 S:     Maintained
 F:     arch/arm/*omap*/
+F:     drivers/i2c/busses/i2c-omap.c
+F:     include/linux/i2c-omap.h
 
 OMAP CLOCK FRAMEWORK SUPPORT
 M:     Paul Walmsley <paul@pwsan.com>
@@ -5667,6 +5686,12 @@ L:       alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
 F:     sound/soc/samsung
 
+SAMSUNG FRAMEBUFFER DRIVER
+M:     Jingoo Han <jg1.han@samsung.com>
+L:     linux-fbdev@vger.kernel.org
+S:     Maintained
+F:     drivers/video/s3c-fb.c
+
 SERIAL DRIVERS
 M:     Alan Cox <alan@linux.intel.com>
 L:     linux-serial@vger.kernel.org
@@ -5830,7 +5855,7 @@ F:        drivers/mmc/host/sdhci-spear.c
 SECURITY SUBSYSTEM
 M:     James Morris <jmorris@namei.org>
 L:     linux-security-module@vger.kernel.org (suggested Cc:)
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git
 W:     http://security.wiki.kernel.org/
 S:     Supported
 F:     security/
@@ -5956,6 +5981,7 @@ L:        davinci-linux-open-source@linux.davincidsp.com (subscribers-only)
 Q:     http://patchwork.kernel.org/project/linux-davinci/list/
 S:     Supported
 F:     arch/arm/mach-davinci
+F:     drivers/i2c/busses/i2c-davinci.c
 
 SIS 190 ETHERNET DRIVER
 M:     Francois Romieu <romieu@fr.zoreil.com>
@@ -6099,13 +6125,6 @@ S:       Maintained
 F:     drivers/ssb/
 F:     include/linux/ssb/
 
-BROADCOM SPECIFIC AMBA DRIVER (BCMA)
-M:     RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>
-L:     linux-wireless@vger.kernel.org
-S:     Maintained
-F:     drivers/bcma/
-F:     include/linux/bcma/
-
 SONY VAIO CONTROL DEVICE DRIVER
 M:     Mattia Dongili <malattia@linux.it>
 L:     platform-driver-x86@vger.kernel.org
@@ -7181,7 +7200,7 @@ S:        Maintained
 F:     drivers/net/vmxnet3/
 
 VMware PVSCSI driver
-M:     Alok Kataria <akataria@vmware.com>
+M:     Arvind Kumar <arvindkumar@vmware.com>
 M:     VMware PV-Drivers <pv-drivers@vmware.com>
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
index adddd11c3b3b8a2827dc4f591b573b1fde5768a9..71e6ed21dd1525fd098081f01062e26239b36e0c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
-PATCHLEVEL = 2
+PATCHLEVEL = 3
 SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION = -rc1
 NAME = Saber-toothed Squirrel
 
 # *DOCUMENTATION*
@@ -312,7 +312,7 @@ endif
 # If the user is running make -s (silent mode), suppress echoing of
 # commands
 
-ifneq ($(findstring s,$(MAKEFLAGS)),)
+ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
   quiet=silent_
 endif
 
@@ -442,7 +442,7 @@ asm-generic:
 
 no-dot-config-targets := clean mrproper distclean \
                         cscope gtags TAGS tags help %docs check% coccicheck \
-                        include/linux/version.h headers_% \
+                        include/linux/version.h headers_% archheaders \
                         kernelversion %src-pkg
 
 config-targets := 0
@@ -979,7 +979,7 @@ prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h \
                    include/config/auto.conf
        $(cmd_crmodverdir)
 
-archprepare: prepare1 scripts_basic
+archprepare: archheaders prepare1 scripts_basic
 
 prepare0: archprepare FORCE
        $(Q)$(MAKE) $(build)=.
@@ -1046,8 +1046,11 @@ hdr-inst := -rR -f $(srctree)/scripts/Makefile.headersinst obj
 # If we do an all arch process set dst to asm-$(hdr-arch)
 hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
 
+PHONY += archheaders
+archheaders:
+
 PHONY += __headers
-__headers: include/linux/version.h scripts_basic asm-generic FORCE
+__headers: include/linux/version.h scripts_basic asm-generic archheaders FORCE
        $(Q)$(MAKE) $(build)=scripts build_unifdef
 
 PHONY += headers_install_all
index 2505740b81d2e24696ff4420f2f9af86713b817b..4f55c736be11ea3aa3ac6762b0ec3d1371b872ce 100644 (file)
@@ -185,4 +185,18 @@ config HAVE_RCU_TABLE_FREE
 config ARCH_HAVE_NMI_SAFE_CMPXCHG
        bool
 
+config HAVE_ALIGNED_STRUCT_PAGE
+       bool
+       help
+         This makes sure that struct pages are double word aligned and that
+         e.g. the SLUB allocator can perform double word atomic operations
+         on a struct page for better performance. However selecting this
+         might increase the size of a struct page by a word.
+
+config HAVE_CMPXCHG_LOCAL
+       bool
+
+config HAVE_CMPXCHG_DOUBLE
+       bool
+
 source "kernel/gcov/Kconfig"
index 5df26a9976a26c10ddfcf0f788302dd2caeb8769..fc871e719aae8bd6e94d5602591f2948f568f8e9 100644 (file)
@@ -59,9 +59,11 @@ $(obj)/zImage:       $(obj)/compressed/vmlinux FORCE
 
 endif
 
+targets += $(dtb-y)
+
 # Rule to build device tree blobs
-$(obj)/%.dtb: $(src)/dts/%.dts
-       $(call cmd,dtc)
+$(obj)/%.dtb: $(src)/dts/%.dts FORCE
+       $(call if_changed_dep,dtc)
 
 $(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y))
 
index 7151753b0989f922c5a0e9d29fce5e057ae2ad5e..c402e9b31f4c61148ee5466b29f9ec176f11b78f 100644 (file)
@@ -2,7 +2,7 @@
 #define _ARCH_ARM_GPIO_H
 
 #if CONFIG_ARCH_NR_GPIO > 0
-#define ARCH_NR_GPIO CONFIG_ARCH_NR_GPIO
+#define ARCH_NR_GPIOS CONFIG_ARCH_NR_GPIO
 #endif
 
 /* not all ARM platforms necessarily support this API ... */
index c93a22a8b924737730edaf17ef3e5ceb7b94afc5..917626128a1da7d326f6816ae63c1495a0290bc3 100644 (file)
@@ -25,7 +25,8 @@
 #define HWCAP_IDIVT    (1 << 18)
 #define HWCAP_IDIV     (HWCAP_IDIVA | HWCAP_IDIVT)
 
-#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+#if defined(__KERNEL__)
+#if !defined(__ASSEMBLY__)
 /*
  * This yields a mask that user programs can use to figure out what
  * instruction set this cpu supports.
@@ -33,5 +34,6 @@
 #define ELF_HWCAP      (elf_hwcap)
 extern unsigned int elf_hwcap;
 #endif
+#endif
 
 #endif
index feec86768f9c967c946a74ff23ed898d6207543c..f82ec22eeb1174a3ba0b431da119868cd8a1d36d 100644 (file)
@@ -24,7 +24,6 @@
 #define MAX_INSN_SIZE                  2
 #define MAX_STACK_SIZE                 64      /* 32 would probably be OK */
 
-#define regs_return_value(regs)                ((regs)->ARM_r0)
 #define flush_insn_slot(p)             do { } while (0)
 #define kretprobe_blacklist_size       0
 
index b8da2e415e4eb21a870cbb52333b5400a50ad163..00ca5f92648ea56616afe8bfbd4a25ff8f0b0e27 100644 (file)
@@ -6,4 +6,6 @@ struct machine_desc;
 
 extern void arm_memblock_init(struct meminfo *, struct machine_desc *);
 
+phys_addr_t arm_memblock_steal(phys_addr_t size, phys_addr_t align);
+
 #endif
index 96187ff58c247cf61953ff8d06922412f0acaca2..451808ba1211f2a547af60b35545b220d69886a9 100644 (file)
@@ -189,6 +189,11 @@ static inline int valid_user_regs(struct pt_regs *regs)
        return 0;
 }
 
+static inline long regs_return_value(struct pt_regs *regs)
+{
+       return regs->ARM_r0;
+}
+
 #define instruction_pointer(regs)      (regs)->ARM_pc
 
 #ifdef CONFIG_SMP
index 32ee164a2f6bb73e066dd34debd6b1355f118f2a..b859d82e30cafb5489fdb0297319a570f8362df3 100644 (file)
@@ -22,7 +22,8 @@
 #  define __SWAB_64_THRU_32__
 #endif
 
-#if defined(__KERNEL__) && __LINUX_ARM_ARCH__ >= 6
+#if defined(__KERNEL__)
+#if __LINUX_ARM_ARCH__ >= 6
 
 static inline __attribute_const__ __u32 __arch_swahb32(__u32 x)
 {
@@ -39,8 +40,10 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
 }
 #define __arch_swab32 __arch_swab32
 
-#else
+#endif
+#endif
 
+#if !defined(__KERNEL__) || __LINUX_ARM_ARCH__ < 6
 static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
 {
        __u32 t;
index 0f30c3a78fc10815668b56c2ae5789ea38b4fdd9..d4c24d412a8ddbdaba9f11a6217cd6a8b592c22c 100644 (file)
@@ -129,6 +129,7 @@ extern void vfp_flush_hwstate(struct thread_info *);
 /*
  * thread information flags:
  *  TIF_SYSCALL_TRACE  - syscall trace active
+ *  TIF_SYSCAL_AUDIT   - syscall auditing active
  *  TIF_SIGPENDING     - signal pending
  *  TIF_NEED_RESCHED   - rescheduling necessary
  *  TIF_NOTIFY_RESUME  - callback before returning to user
@@ -139,6 +140,7 @@ extern void vfp_flush_hwstate(struct thread_info *);
 #define TIF_NEED_RESCHED       1
 #define TIF_NOTIFY_RESUME      2       /* callback before returning to user */
 #define TIF_SYSCALL_TRACE      8
+#define TIF_SYSCALL_AUDIT      9
 #define TIF_POLLING_NRFLAG     16
 #define TIF_USING_IWMMXT       17
 #define TIF_MEMDIE             18      /* is terminating due to OOM killer */
@@ -149,11 +151,15 @@ extern void vfp_flush_hwstate(struct thread_info *);
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
 #define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
 #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
+#define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
 #define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
 #define _TIF_USING_IWMMXT      (1 << TIF_USING_IWMMXT)
 #define _TIF_RESTORE_SIGMASK   (1 << TIF_RESTORE_SIGMASK)
 #define _TIF_SECCOMP           (1 << TIF_SECCOMP)
 
+/* Checks for any syscall work in entry-common.S */
+#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
+
 /*
  * Change these and you break ASM code in entry-common.S
  */
index bc631161e9c6d29eb0f9e73d408da4ae4c13da0e..f5989f46b4d2d450f18b24faa946de750394ec13 100644 (file)
@@ -37,8 +37,8 @@
 #define THUMB(x...)    x
 #ifdef __ASSEMBLY__
 #define W(instr)       instr.w
-#endif
 #define BSYM(sym)      sym + 1
+#endif
 
 #else  /* !CONFIG_THUMB2_KERNEL */
 
@@ -49,8 +49,8 @@
 #define THUMB(x...)
 #ifdef __ASSEMBLY__
 #define W(instr)       instr
-#endif
 #define BSYM(sym)      sym
+#endif
 
 #endif /* CONFIG_THUMB2_KERNEL */
 
index 4a1123783806b79ef559ed51a093353feb67070e..512cd1473454c9ba26eaf51fbb659a313aad96b0 100644 (file)
 /*
  * The following syscalls are obsolete and no longer available for EABI.
  */
-#if defined(__ARM_EABI__) && !defined(__KERNEL__)
+#if !defined(__KERNEL__)
+#if defined(__ARM_EABI__)
 #undef __NR_time
 #undef __NR_umount
 #undef __NR_stime
 #undef __NR_syscall
 #undef __NR_ipc
 #endif
+#endif
 
 #ifdef __KERNEL__
 
index b2a27b6b0046ee6c1e0f0928c3269ab5f6c63cd2..520889cf1b5bfd6d1ff3d4eac603e9ba9de3d7e4 100644 (file)
@@ -87,7 +87,7 @@ ENTRY(ret_from_fork)
        get_thread_info tsk
        ldr     r1, [tsk, #TI_FLAGS]            @ check for syscall tracing
        mov     why, #1
-       tst     r1, #_TIF_SYSCALL_TRACE         @ are we tracing syscalls?
+       tst     r1, #_TIF_SYSCALL_WORK          @ are we tracing syscalls?
        beq     ret_slow_syscall
        mov     r1, sp
        mov     r0, #1                          @ trace exit [IP = 1]
@@ -443,7 +443,7 @@ ENTRY(vector_swi)
 1:
 #endif
 
-       tst     r10, #_TIF_SYSCALL_TRACE                @ are we tracing syscalls?
+       tst     r10, #_TIF_SYSCALL_WORK         @ are we tracing syscalls?
        bne     __sys_trace
 
        cmp     scno, #NR_syscalls              @ check upper syscall limit
index 14e277d2ff911ec7690c4223c5acea4b602e3450..6d579114406673fd1b97c09f0cdcbb7263b044da 100644 (file)
@@ -99,6 +99,14 @@ ENTRY(stext)
  THUMB( it     eq )            @ force fixup-able long branch encoding
        beq     __error_p                       @ yes, error 'p'
 
+#ifdef CONFIG_ARM_LPAE
+       mrc     p15, 0, r3, c0, c1, 4           @ read ID_MMFR0
+       and     r3, r3, #0xf                    @ extract VMSA support
+       cmp     r3, #5                          @ long-descriptor translation table format?
+ THUMB( it     lo )                            @ force fixup-able long branch encoding
+       blo     __error_p                       @ only classic page table format
+#endif
+
 #ifndef CONFIG_XIP_KERNEL
        adr     r3, 2f
        ldmia   r3, {r4, r8}
index 483727ad68923a3e27af6d693c9132db0148af7f..e1d5e1929fbd6a36e9266a2c4d254cba5060e438 100644 (file)
@@ -906,11 +906,6 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
 {
        unsigned long ip;
 
-       if (!test_thread_flag(TIF_SYSCALL_TRACE))
-               return scno;
-       if (!(current->ptrace & PT_PTRACED))
-               return scno;
-
        /*
         * Save IP.  IP is used to denote syscall entry/exit:
         *  IP = 0 -> entry, = 1 -> exit
@@ -918,6 +913,17 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
        ip = regs->ARM_ip;
        regs->ARM_ip = why;
 
+       if (!ip)
+               audit_syscall_exit(regs);
+       else
+               audit_syscall_entry(AUDIT_ARCH_ARMEB, scno, regs->ARM_r0,
+                                   regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
+
+       if (!test_thread_flag(TIF_SYSCALL_TRACE))
+               return scno;
+       if (!(current->ptrace & PT_PTRACED))
+               return scno;
+
        current_thread_info()->syscall = scno;
 
        /* the 0x80 provides a way for the tracing parent to distinguish
index 46d4d876e6fb853e9cf051ed3f88edc852c8a57d..e82c642fa53cd49ac88afc412b4194319fc3303f 100644 (file)
@@ -37,7 +37,7 @@
  */
 struct ep93xx_dma_data {
        int                             port;
-       enum dma_data_direction         direction;
+       enum dma_transfer_direction     direction;
        const char                      *name;
 };
 
@@ -80,14 +80,14 @@ static inline bool ep93xx_dma_chan_is_m2p(struct dma_chan *chan)
  * channel supports given DMA direction. Only M2P channels have such
  * limitation, for M2M channels the direction is configurable.
  */
-static inline enum dma_data_direction
+static inline enum dma_transfer_direction
 ep93xx_dma_chan_direction(struct dma_chan *chan)
 {
        if (!ep93xx_dma_chan_is_m2p(chan))
                return DMA_NONE;
 
        /* even channels are for TX, odd for RX */
-       return (chan->chan_id % 2 == 0) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+       return (chan->chan_id % 2 == 0) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
 }
 
 #endif /* __ASM_ARCH_DMA_H */
index 3cdeb3647542592a4a62f98e0c6b647da358b0d4..5364d4bfa8bc79efe6d51b27ff361811d98b8227 100644 (file)
@@ -36,6 +36,8 @@ pen:  ldr     r7, [r6]
         * should now contain the SVC stack for this core
         */
        b       secondary_startup
+ENDPROC(exynos4_secondary_startup)
 
+       .align 2
 1:     .long   .
        .long   pen_release
index 2b11e046d3919dc393a2875b528abf34e3664d85..0679b8ad2d1e1a4263521f805d7afd246334a037 100644 (file)
@@ -597,7 +597,8 @@ static struct s3c_fb_pd_win origen_fb_win0 = {
 static struct s3c_fb_platdata origen_lcd_pdata __initdata = {
        .win[0]         = &origen_fb_win0,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
-       .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+       .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
+                               VIDCON1_INV_VCLK,
        .setup_gpio     = exynos4_fimd0_gpio_setup_24bpp,
 };
 
index 60bc45e3e7099045560f71bf4aaf29664341e488..683aec786b78975bd8a791923134b1e0958de215 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/cacheflush.h>
 #include <asm/hardware/gic.h>
 #include <asm/smp_scu.h>
-#include <asm/unified.h>
 
 #include <mach/hardware.h>
 #include <mach/regs-clock.h>
@@ -137,7 +136,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
        while (time_before(jiffies, timeout)) {
                smp_rmb();
 
-               __raw_writel(BSYM(virt_to_phys(exynos4_secondary_startup)),
+               __raw_writel(virt_to_phys(exynos4_secondary_startup),
                        CPU1_BOOT_REG);
                gic_raise_softirq(cpumask_of(cpu), 1);
 
@@ -192,6 +191,6 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
         * until it receives a soft interrupt, and then the
         * secondary CPU branches to this address.
         */
-       __raw_writel(BSYM(virt_to_phys(exynos4_secondary_startup)),
+       __raw_writel(virt_to_phys(exynos4_secondary_startup),
                        CPU1_BOOT_REG);
 }
index 804c4a55f8038c75cbf0731168ee6d0d36de004a..7afbe1e55bebe710f926b01dbb84846de4ca0e9d 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/smp.h>
 
 #include <asm/cacheflush.h>
-#include <asm/unified.h>
 #include <asm/smp_scu.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/timer-sp.h>
@@ -76,7 +75,7 @@ void highbank_set_cpu_jump(int cpu, void *jump_addr)
 #ifdef CONFIG_SMP
        cpu = cpu_logical_map(cpu);
 #endif
-       writel(BSYM(virt_to_phys(jump_addr)), HB_JUMP_TABLE_VIRT(cpu));
+       writel(virt_to_phys(jump_addr), HB_JUMP_TABLE_VIRT(cpu));
        __cpuc_flush_dcache_area(HB_JUMP_TABLE_VIRT(cpu), 16);
        outer_clean_range(HB_JUMP_TABLE_PHYS(cpu),
                          HB_JUMP_TABLE_PHYS(cpu) + 15);
index 89c33258639f89a9b075a2f9bf6ca0bf41b7a0e8..4d1aab154400fb43e4e0de2ea38e49c932d278e0 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/mach/time.h>
 #include <asm/memory.h>
 #include <asm/mach/map.h>
+#include <asm/memblock.h>
 #include <mach/common.h>
 #include <mach/iomux-mx3.h>
 #include <mach/3ds_debugboard.h>
@@ -754,10 +755,8 @@ static struct sys_timer mx31_3ds_timer = {
 static void __init mx31_3ds_reserve(void)
 {
        /* reserve MX31_3DS_CAMERA_BUF_SIZE bytes for mx3-camera */
-       mx3_camera_base = memblock_alloc(MX31_3DS_CAMERA_BUF_SIZE,
+       mx3_camera_base = arm_memblock_steal(MX31_3DS_CAMERA_BUF_SIZE,
                                         MX31_3DS_CAMERA_BUF_SIZE);
-       memblock_free(mx3_camera_base, MX31_3DS_CAMERA_BUF_SIZE);
-       memblock_remove(mx3_camera_base, MX31_3DS_CAMERA_BUF_SIZE);
 }
 
 MACHINE_START(MX31_3DS, "Freescale MX31PDK (3DS)")
index b95981dacb2bcef2ff8138b59d32f58d85d3a394..f225262b5c38551cb6ec424e01cb71139f9a551f 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
+#include <asm/memblock.h>
 #include <mach/board-mx31moboard.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
@@ -584,10 +585,8 @@ struct sys_timer mx31moboard_timer = {
 static void __init mx31moboard_reserve(void)
 {
        /* reserve 4 MiB for mx3-camera */
-       mx3_camera_base = memblock_alloc(MX3_CAMERA_BUF_SIZE,
+       mx3_camera_base = arm_memblock_steal(MX3_CAMERA_BUF_SIZE,
                        MX3_CAMERA_BUF_SIZE);
-       memblock_free(mx3_camera_base, MX3_CAMERA_BUF_SIZE);
-       memblock_remove(mx3_camera_base, MX3_CAMERA_BUF_SIZE);
 }
 
 MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard")
index d7e151669ed347591e1687de4c628156aa56820d..e48854b9d9907a7c76095b5531c3a9f63eb0db23 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
+#include <asm/memblock.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
 #include <mach/iomux-mx3.h>
@@ -680,10 +681,8 @@ struct sys_timer pcm037_timer = {
 static void __init pcm037_reserve(void)
 {
        /* reserve 4 MiB for mx3-camera */
-       mx3_camera_base = memblock_alloc(MX3_CAMERA_BUF_SIZE,
+       mx3_camera_base = arm_memblock_steal(MX3_CAMERA_BUF_SIZE,
                        MX3_CAMERA_BUF_SIZE);
-       memblock_free(mx3_camera_base, MX3_CAMERA_BUF_SIZE);
-       memblock_remove(mx3_camera_base, MX3_CAMERA_BUF_SIZE);
 }
 
 MACHINE_START(PCM037, "Phytec Phycore pcm037")
index 4bde04f99e38ceda85fd4cb43f89bf2eb080ead7..29bd1243781ede5156ca622de5fccbba82160947 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/smp.h>
-#include <asm/unified.h>
 
 #define SRC_SCR                                0x000
 #define SRC_GPR1                       0x020
@@ -43,7 +42,7 @@ void imx_enable_cpu(int cpu, bool enable)
 void imx_set_cpu_jump(int cpu, void *jump_addr)
 {
        cpu = cpu_logical_map(cpu);
-       writel_relaxed(BSYM(virt_to_phys(jump_addr)),
+       writel_relaxed(virt_to_phys(jump_addr),
                       src_base + SRC_GPR1 + cpu * 8);
 }
 
index 0c631a9f8647f5b8ec35dd5998da65bc937860d0..bcd5af223deabaf48451bf3a4d67cea23c82566e 100644 (file)
@@ -34,6 +34,7 @@ pen:  ldr     r7, [r6]
         * should now contain the SVC stack for this core
         */
        b       secondary_startup
+ENDPROC(msm_secondary_startup)
 
        .align
 1:     .long   .
index a9103bc6615f01ac526d8b085939fb4f20433ffb..bd66ed04d6dc0edfdc489a56a7f1e9fb84dbafc1 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/debugfs.h>
+#include <linux/module.h>
 #include <linux/string.h>
 #include <mach/vreg.h>
 
index 904bd1dfcd2e26b194f24ebe62eee9a377a05016..a8ba7b96dcd1c3177b11e634e5e8e4608dc7a4d4 100644 (file)
@@ -366,8 +366,8 @@ config OMAP3_SDRC_AC_TIMING
          going on could result in system crashes;
 
 config OMAP4_ERRATA_I688
-       bool "OMAP4 errata: Async Bridge Corruption"
-       depends on ARCH_OMAP4
+       bool "OMAP4 errata: Async Bridge Corruption (BROKEN)"
+       depends on ARCH_OMAP4 && BROKEN
        select ARCH_HAS_BARRIERS
        help
          If a data is stalled inside asynchronous bridge because of back
index 2ceb75d21eb2fdfb12073ba57579acb38a6aedf0..39fba9df17fba3209396cba2d8be2d59553c8ab5 100644 (file)
@@ -602,20 +602,6 @@ static void __init omap_sfh7741prox_init(void)
                        __func__, OMAP4_SFH7741_ENABLE_GPIO, error);
 }
 
-static void sdp4430_hdmi_mux_init(void)
-{
-       /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */
-       omap_mux_init_signal("hdmi_hpd",
-                       OMAP_PIN_INPUT_PULLUP);
-       omap_mux_init_signal("hdmi_cec",
-                       OMAP_PIN_INPUT_PULLUP);
-       /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */
-       omap_mux_init_signal("hdmi_ddc_scl",
-                       OMAP_PIN_INPUT_PULLUP);
-       omap_mux_init_signal("hdmi_ddc_sda",
-                       OMAP_PIN_INPUT_PULLUP);
-}
-
 static struct gpio sdp4430_hdmi_gpios[] = {
        { HDMI_GPIO_HPD,        GPIOF_OUT_INIT_HIGH,    "hdmi_gpio_hpd"   },
        { HDMI_GPIO_LS_OE,      GPIOF_OUT_INIT_HIGH,    "hdmi_gpio_ls_oe" },
@@ -833,9 +819,16 @@ static void omap_4430sdp_display_init(void)
                pr_err("%s: Could not get display_sel GPIO\n", __func__);
 
        sdp4430_lcd_init();
-       sdp4430_hdmi_mux_init();
        sdp4430_picodlp_init();
        omap_display_init(&sdp4430_dss_data);
+       /*
+        * OMAP4460SDP/Blaze and OMAP4430 ES2.3 SDP/Blaze boards and
+        * later have external pull up on the HDMI I2C lines
+        */
+       if (cpu_is_omap446x() || omap_rev() > OMAP4430_REV_ES2_2)
+               omap_hdmi_init(OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP);
+       else
+               omap_hdmi_init(0);
 }
 
 #ifdef CONFIG_OMAP_MUX
index e96a2e7ad36f527b81b321ce5f01fe5488c88f5f..30ad40db2cf39558bdefc6bf40169114919ed6e7 100644 (file)
@@ -412,21 +412,6 @@ int __init omap4_panda_dvi_init(void)
        return r;
 }
 
-
-static void omap4_panda_hdmi_mux_init(void)
-{
-       /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */
-       omap_mux_init_signal("hdmi_hpd",
-                       OMAP_PIN_INPUT_PULLUP);
-       omap_mux_init_signal("hdmi_cec",
-                       OMAP_PIN_INPUT_PULLUP);
-       /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */
-       omap_mux_init_signal("hdmi_ddc_scl",
-                       OMAP_PIN_INPUT_PULLUP);
-       omap_mux_init_signal("hdmi_ddc_sda",
-                       OMAP_PIN_INPUT_PULLUP);
-}
-
 static struct gpio panda_hdmi_gpios[] = {
        { HDMI_GPIO_HPD,        GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd"   },
        { HDMI_GPIO_LS_OE,      GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
@@ -478,8 +463,16 @@ void omap4_panda_display_init(void)
        if (r)
                pr_err("error initializing panda DVI\n");
 
-       omap4_panda_hdmi_mux_init();
        omap_display_init(&omap4_panda_dss_data);
+
+       /*
+        * OMAP4460SDP/Blaze and OMAP4430 ES2.3 SDP/Blaze boards and
+        * later have external pull up on the HDMI I2C lines
+        */
+       if (cpu_is_omap446x() || omap_rev() > OMAP4430_REV_ES2_2)
+               omap_hdmi_init(OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP);
+       else
+               omap_hdmi_init(0);
 }
 
 static void __init omap4_panda_init(void)
index 46dfd1ae8f71a6001f90ecdcea237103f906dcc4..0b510ad01a00b5a7ad4ae224f17447e8bba6301f 100644 (file)
@@ -28,7 +28,6 @@
 #include <plat/board.h>
 #include <plat/mcbsp.h>
 #include <plat/mmc.h>
-#include <plat/iommu.h>
 #include <plat/dma.h>
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
@@ -128,6 +127,10 @@ static struct platform_device omap2cam_device = {
 };
 #endif
 
+#if defined(CONFIG_IOMMU_API)
+
+#include <plat/iommu.h>
+
 static struct resource omap3isp_resources[] = {
        {
                .start          = OMAP3430_ISP_BASE,
@@ -224,6 +227,15 @@ int omap3_init_camera(struct isp_platform_data *pdata)
        return platform_device_register(&omap3isp_device);
 }
 
+#else /* !CONFIG_IOMMU_API */
+
+int omap3_init_camera(struct isp_platform_data *pdata)
+{
+       return 0;
+}
+
+#endif
+
 static inline void omap_init_camera(void)
 {
 #if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
index bc6cf863a563bcf51f76240598ca6424b92939fe..3c446d1a1781fe3d819b2732ea28e2426c2a1348 100644 (file)
@@ -30,6 +30,7 @@
 #include <plat/omap-pm.h>
 #include "common.h"
 
+#include "mux.h"
 #include "control.h"
 #include "display.h"
 
@@ -97,6 +98,36 @@ static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initdata = {
        { "dss_hdmi", "omapdss_hdmi", -1 },
 };
 
+static void omap4_hdmi_mux_pads(enum omap_hdmi_flags flags)
+{
+       u32 reg;
+       u16 control_i2c_1;
+
+       /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */
+       omap_mux_init_signal("hdmi_hpd",
+                       OMAP_PIN_INPUT_PULLUP);
+       omap_mux_init_signal("hdmi_cec",
+                       OMAP_PIN_INPUT_PULLUP);
+       /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */
+       omap_mux_init_signal("hdmi_ddc_scl",
+                       OMAP_PIN_INPUT_PULLUP);
+       omap_mux_init_signal("hdmi_ddc_sda",
+                       OMAP_PIN_INPUT_PULLUP);
+
+       /*
+        * CONTROL_I2C_1: HDMI_DDC_SDA_PULLUPRESX (bit 28) and
+        * HDMI_DDC_SCL_PULLUPRESX (bit 24) are set to disable
+        * internal pull up resistor.
+        */
+       if (flags & OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP) {
+               control_i2c_1 = OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_1;
+               reg = omap4_ctrl_pad_readl(control_i2c_1);
+               reg |= (OMAP4_HDMI_DDC_SDA_PULLUPRESX_MASK |
+                       OMAP4_HDMI_DDC_SCL_PULLUPRESX_MASK);
+                       omap4_ctrl_pad_writel(reg, control_i2c_1);
+       }
+}
+
 static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes)
 {
        u32 enable_mask, enable_shift;
@@ -130,6 +161,14 @@ static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes)
        return 0;
 }
 
+int omap_hdmi_init(enum omap_hdmi_flags flags)
+{
+       if (cpu_is_omap44xx())
+               omap4_hdmi_mux_pads(flags);
+
+       return 0;
+}
+
 static int omap_dsi_enable_pads(int dsi_id, unsigned lane_mask)
 {
        if (cpu_is_omap44xx())
index 69f3c72d959b61e6cefe7c62462fc30f05a0b15f..d8f8ef40290f4dc4c803e69ce87fe5111baed499 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/memblock.h>
 
 #include <asm/cacheflush.h>
+#include <asm/memblock.h>
 
 #include <mach/omap-secure.h>
 
@@ -57,20 +58,10 @@ u32 omap_secure_dispatcher(u32 idx, u32 flag, u32 nargs, u32 arg1, u32 arg2,
 /* Allocate the memory to save secure ram */
 int __init omap_secure_ram_reserve_memblock(void)
 {
-       phys_addr_t paddr;
        u32 size = OMAP_SECURE_RAM_STORAGE;
 
        size = ALIGN(size, SZ_1M);
-       paddr = memblock_alloc(size, SZ_1M);
-       if (!paddr) {
-               pr_err("%s: failed to reserve %x bytes\n",
-                               __func__, size);
-               return -ENOMEM;
-       }
-       memblock_free(paddr, size);
-       memblock_remove(paddr, size);
-
-       omap_secure_memblock_base = paddr;
+       omap_secure_memblock_base = arm_memblock_steal(size, SZ_1M);
 
        return 0;
 }
index bc16c818c6b72e77ae276976c887b7a85647a9df..40a8fbc07e4b766717b35e8b69f88794c1335df7 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/mach/map.h>
+#include <asm/memblock.h>
 
 #include <plat/irqs.h>
 #include <plat/sram.h>
@@ -61,13 +62,8 @@ static int __init omap_barriers_init(void)
                return -ENODEV;
 
        size = ALIGN(PAGE_SIZE, SZ_1M);
-       paddr = memblock_alloc(size, SZ_1M);
-       if (!paddr) {
-               pr_err("%s: failed to reserve 4 Kbytes\n", __func__);
-               return -ENOMEM;
-       }
-       memblock_free(paddr, size);
-       memblock_remove(paddr, size);
+       paddr = arm_memblock_steal(size, SZ_1M);
+
        dram_io_desc[0].virtual = OMAP4_DRAM_BARRIER_VA;
        dram_io_desc[0].pfn = __phys_to_pfn(paddr);
        dram_io_desc[0].length = size;
index 6c89cf8ab22eece43dd765896bf0e53824f8753e..2ecba6743b8e66b050f7bb79665878a34878484b 100644 (file)
@@ -67,7 +67,7 @@ static void picoxcell_add_clocksource(struct device_node *source_timer)
 
 static void __iomem *sched_io_base;
 
-unsigned u32 notrace picoxcell_read_sched_clock(void)
+static u32 picoxcell_read_sched_clock(void)
 {
        return __raw_readl(sched_io_base);
 }
index e83c654a58d0f4540445840e1b7f1af377c12bff..17c878ddbc70d1da5a63b31a6d1bba663841c704 100644 (file)
@@ -17,7 +17,6 @@
 #include <asm/hardware/gic.h>
 #include <asm/mach-types.h>
 #include <asm/smp_scu.h>
-#include <asm/unified.h>
 
 #include <mach/board-eb.h>
 #include <mach/board-pb11mp.h>
@@ -75,6 +74,6 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
         * until it receives a soft interrupt, and then the
         * secondary CPU branches to this address.
         */
-       __raw_writel(BSYM(virt_to_phys(versatile_secondary_startup)),
+       __raw_writel(virt_to_phys(versatile_secondary_startup),
                     __io_address(REALVIEW_SYS_FLAGSSET));
 }
index 0069561464f9b0d6c0b2b259e151d711e8219dcb..e62962117763879cb469c172d7f464b6339608d3 100644 (file)
@@ -117,17 +117,14 @@ static void __init realview_eb_map_io(void)
 
 static struct pl061_platform_data gpio0_plat_data = {
        .gpio_base      = 0,
-       .irq_base       = -1,
 };
 
 static struct pl061_platform_data gpio1_plat_data = {
        .gpio_base      = 8,
-       .irq_base       = -1,
 };
 
 static struct pl061_platform_data gpio2_plat_data = {
        .gpio_base      = 16,
-       .irq_base       = -1,
 };
 
 static struct pl022_ssp_controller ssp0_plat_data = {
index 8fe395568a47eb8fa0070b4f8e7c8d2494b41ac0..e4abe94fb11ab4b0f0969bc565d8359aafeb17f2 100644 (file)
@@ -113,17 +113,14 @@ static void __init realview_pb1176_map_io(void)
 
 static struct pl061_platform_data gpio0_plat_data = {
        .gpio_base      = 0,
-       .irq_base       = -1,
 };
 
 static struct pl061_platform_data gpio1_plat_data = {
        .gpio_base      = 8,
-       .irq_base       = -1,
 };
 
 static struct pl061_platform_data gpio2_plat_data = {
        .gpio_base      = 16,
-       .irq_base       = -1,
 };
 
 static struct pl022_ssp_controller ssp0_plat_data = {
index 34a26011bb89aa3067fb948e84588d18c2d2b76b..127a3fd42ab13db2e8430b55166a66df9b46cfae 100644 (file)
@@ -112,17 +112,14 @@ static void __init realview_pb11mp_map_io(void)
 
 static struct pl061_platform_data gpio0_plat_data = {
        .gpio_base      = 0,
-       .irq_base       = -1,
 };
 
 static struct pl061_platform_data gpio1_plat_data = {
        .gpio_base      = 8,
-       .irq_base       = -1,
 };
 
 static struct pl061_platform_data gpio2_plat_data = {
        .gpio_base      = 16,
-       .irq_base       = -1,
 };
 
 static struct pl022_ssp_controller ssp0_plat_data = {
index d26a6def1d65af974788348614e885da0a716993..25b2e59296f8d7a5721595f2523b152e69a0034e 100644 (file)
@@ -102,17 +102,14 @@ static void __init realview_pba8_map_io(void)
 
 static struct pl061_platform_data gpio0_plat_data = {
        .gpio_base      = 0,
-       .irq_base       = -1,
 };
 
 static struct pl061_platform_data gpio1_plat_data = {
        .gpio_base      = 8,
-       .irq_base       = -1,
 };
 
 static struct pl061_platform_data gpio2_plat_data = {
        .gpio_base      = 16,
-       .irq_base       = -1,
 };
 
 static struct pl022_ssp_controller ssp0_plat_data = {
index a250fb4124bf6b5460643b56d5bc04c2124fccd4..ac715645b8606aeee172fee74ee555823881b009 100644 (file)
@@ -124,17 +124,14 @@ static void __init realview_pbx_map_io(void)
 
 static struct pl061_platform_data gpio0_plat_data = {
        .gpio_base      = 0,
-       .irq_base       = -1,
 };
 
 static struct pl061_platform_data gpio1_plat_data = {
        .gpio_base      = 8,
-       .irq_base       = -1,
 };
 
 static struct pl061_platform_data gpio2_plat_data = {
        .gpio_base      = 16,
-       .irq_base       = -1,
 };
 
 static struct pl022_ssp_controller ssp0_plat_data = {
index 5d55ab018b6b3f74b1946a67d0efd84a534e3caf..4cb2f951f1e9155d9b4434fac10ff4ea330e9039 100644 (file)
@@ -21,5 +21,6 @@
 #define CODEC_GPIO_BASE                        (GPIO_BOARD_START + 8)
 #define GLENFARCLAS_PMIC_GPIO_BASE     (GPIO_BOARD_START + 32)
 #define BANFF_PMIC_GPIO_BASE           (GPIO_BOARD_START + 64)
+#define MMGPIO_GPIO_BASE               (GPIO_BOARD_START + 96)
 
 #endif
index 1cc91d794c973e538e52a9678bff72fa4e1b8d0e..8077f650eb0e6c291ac607aff70a02b35dfa62b8 100644 (file)
@@ -260,6 +260,7 @@ static struct platform_device crag6410_dm9k_device = {
 
 static struct resource crag6410_mmgpio_resource[] = {
        [0] = {
+               .name   = "dat",
                .start  = S3C64XX_PA_XM0CSN4 + 1,
                .end    = S3C64XX_PA_XM0CSN4 + 1,
                .flags  = IORESOURCE_MEM,
@@ -272,7 +273,7 @@ static struct platform_device crag6410_mmgpio = {
        .resource       = crag6410_mmgpio_resource,
        .num_resources  = ARRAY_SIZE(crag6410_mmgpio_resource),
        .dev.platform_data = &(struct bgpio_pdata) {
-               .base   = -1,
+               .base   = MMGPIO_GPIO_BASE,
        },
 };
 
@@ -328,7 +329,6 @@ static struct platform_device wallvdd_device = {
 
 static struct platform_device *crag6410_devices[] __initdata = {
        &s3c_device_hsmmc0,
-       &s3c_device_hsmmc1,
        &s3c_device_hsmmc2,
        &s3c_device_i2c0,
        &s3c_device_i2c1,
@@ -355,7 +355,7 @@ static struct platform_device *crag6410_devices[] __initdata = {
 
 static struct pca953x_platform_data crag6410_pca_data = {
        .gpio_base      = PCA935X_GPIO_BASE,
-       .irq_base       = 0,
+       .irq_base       = -1,
 };
 
 /* VDDARM is controlled by DVS1 connected to GPK(0) */
@@ -683,12 +683,6 @@ static struct s3c_sdhci_platdata crag6410_hsmmc2_pdata = {
        .cd_type                = S3C_SDHCI_CD_PERMANENT,
 };
 
-static struct s3c_sdhci_platdata crag6410_hsmmc1_pdata = {
-       .max_width              = 4,
-       .cd_type                = S3C_SDHCI_CD_GPIO,
-       .ext_cd_gpio            = S3C64XX_GPF(11),
-};
-
 static void crag6410_cfg_sdhci0(struct platform_device *dev, int width)
 {
        /* Set all the necessary GPG pins to special-function 2 */
@@ -723,7 +717,6 @@ static void __init crag6410_machine_init(void)
        gpio_direction_output(S3C64XX_GPF(10), 1);
 
        s3c_sdhci0_set_platdata(&crag6410_hsmmc0_pdata);
-       s3c_sdhci1_set_platdata(&crag6410_hsmmc1_pdata);
        s3c_sdhci2_set_platdata(&crag6410_hsmmc2_pdata);
 
        s3c_i2c0_set_platdata(&i2c0_pdata);
index 055dac90e0e247c95258ecd412e47bb2297de1cc..7d3e81b9dd06229034603aa260064384d8d44a5d 100644 (file)
@@ -346,23 +346,10 @@ int __init s3c64xx_pm_init(void)
 
 static __init int s3c64xx_pm_initcall(void)
 {
-       u32 val;
-
        pm_cpu_prep = s3c64xx_pm_prepare;
        pm_cpu_sleep = s3c64xx_cpu_suspend;
        pm_uart_udivslot = 1;
 
-       /*
-        * Unconditionally disable power domains that contain only
-        * blocks which have no mainline driver support.
-        */
-       val = __raw_readl(S3C64XX_NORMAL_CFG);
-       val &= ~(S3C64XX_NORMALCFG_DOMAIN_G_ON |
-                S3C64XX_NORMALCFG_DOMAIN_V_ON |
-                S3C64XX_NORMALCFG_DOMAIN_I_ON |
-                S3C64XX_NORMALCFG_DOMAIN_P_ON);
-       __raw_writel(val, S3C64XX_NORMAL_CFG);
-
 #ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
        gpio_request(S3C64XX_GPN(12), "DEBUG_LED0");
        gpio_request(S3C64XX_GPN(13), "DEBUG_LED1");
index 6b93e200bcaceecec1bdc18c27929480b860066b..ebafe8aa8956e1d9f7e24987e777ce7d87f27369 100644 (file)
@@ -202,6 +202,7 @@ static struct irda_platform_data assabet_irda_data = {
 static struct mcp_plat_data assabet_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
+       .codec          = "ucb1x00",
 };
 
 static void __init assabet_init(void)
@@ -252,6 +253,17 @@ static void __init assabet_init(void)
        sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources,
                            ARRAY_SIZE(assabet_flash_resources));
        sa11x0_register_irda(&assabet_irda_data);
+
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
+       ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
        sa11x0_register_mcp(&assabet_mcp_data);
 }
 
@@ -268,7 +280,7 @@ static void __init map_sa1100_gpio_regs( void )
        int prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO);
        pmd_t *pmd;
 
-       pmd = pmd_offset(pgd_offset_k(virt), virt);
+       pmd = pmd_offset(pud_offset(pgd_offset_k(virt), virt), virt);
        *pmd = __pmd(phys | prot);
        flush_pmd_entry(pmd);
 }
index 11bb6d0b9be377b6c926f3e759a03a21d2e9ffff..d12d0f48b1dc4bec59f9a9939edc6c93e5f3ddcb 100644 (file)
@@ -124,12 +124,23 @@ static void __init cerf_map_io(void)
 static struct mcp_plat_data cerf_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
+       .codec          = "ucb1x00",
 };
 
 static void __init cerf_init(void)
 {
        platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
        sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
+
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
        sa11x0_register_mcp(&cerf_mcp_data);
 }
 
index b9060e236def9e90204fa2be99734ea3a4fc6417..c483912d08af4535ce964992a19d66f511c80c21 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/timer.h>
 #include <linux/gpio.h>
 #include <linux/pda_power.h>
+#include <linux/mfd/ucb1x00.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -85,10 +86,15 @@ static struct scoop_pcmcia_config collie_pcmcia_config = {
        .num_devs       = 1,
 };
 
+static struct ucb1x00_plat_data collie_ucb1x00_data = {
+       .gpio_base      = COLLIE_TC35143_GPIO_BASE,
+};
+
 static struct mcp_plat_data collie_mcp_data = {
        .mccr0          = MCCR0_ADM | MCCR0_ExtClk,
        .sclk_rate      = 9216000,
-       .gpio_base      = COLLIE_TC35143_GPIO_BASE,
+       .codec          = "ucb1x00",
+       .codec_pdata    = &collie_ucb1x00_data,
 };
 
 /*
@@ -351,6 +357,16 @@ static void __init collie_init(void)
 
        sa11x0_register_mtd(&collie_flash_data, collie_flash_resources,
                            ARRAY_SIZE(collie_flash_resources));
+
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
        sa11x0_register_mcp(&collie_mcp_data);
 
        sharpsl_save_param();
index 480d2ea46b000a9f862c7bef28280a31730b47d9..e3a28ca2a7b754fff9b095eb5c58e113525b16df 100644 (file)
@@ -217,10 +217,15 @@ static struct platform_device sa11x0uart3_device = {
 static struct resource sa11x0mcp_resources[] = {
        [0] = {
                .start  = __PREG(Ser4MCCR0),
-               .end    = __PREG(Ser4MCCR0) + 0xffff,
+               .end    = __PREG(Ser4MCCR0) + 0x1C - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
+               .start  = __PREG(Ser4MCCR1),
+               .end    = __PREG(Ser4MCCR1) + 0x4 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [2] = {
                .start  = IRQ_Ser4MCP,
                .end    = IRQ_Ser4MCP,
                .flags  = IORESOURCE_IRQ,
index 703631887c94ae0de4bb66ada4913ce7e05ea4a4..a38fc4f5424166bc587dd9ec664321bb3fb1ded6 100644 (file)
@@ -51,7 +51,4 @@ static inline void gpio_set_value(unsigned gpio, int value)
 
 #define gpio_cansleep  __gpio_cansleep
 
-#define gpio_to_irq(gpio)      ((gpio < 11) ? (IRQ_GPIO0 + gpio) : \
-                                       (IRQ_GPIO11 - 11 + gpio))
-
 #endif
index ed1a331508a754bf2e802f537689a97ee2b524c5..586cec898b35ae8578025727e3ec4e2b679964e0 100644 (file)
@@ -17,6 +17,8 @@ struct mcp_plat_data {
        u32 mccr1;
        unsigned int sclk_rate;
        int gpio_base;
+       const char *codec;
+       void *codec_pdata;
 };
 
 #endif
index af4e2761f3dbf4a6254bfab53f98080334e5f387..d117ceab6215c4f8d814504aa313bacf17460b45 100644 (file)
 static struct mcp_plat_data lart_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
+       .codec          = "ucb1x00",
 };
 
 static void __init lart_init(void)
 {
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
        sa11x0_register_mcp(&lart_mcp_data);
 }
 
index 318b2b766a0b3ee7b8921c2904b65c0fdd551c8c..748d34435b3f070000f2afcfc420253d85ccb060 100644 (file)
@@ -55,11 +55,22 @@ static struct resource shannon_flash_resource = {
 static struct mcp_plat_data shannon_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
+       .codec          = "ucb1x00",
 };
 
 static void __init shannon_init(void)
 {
        sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1);
+
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
        sa11x0_register_mcp(&shannon_mcp_data);
 }
 
index e17c04d6e32428af6aa7c8eb1fbc35ca6d7a02d8..458ececefa58a122332de40798d3df7aae3d1ea2 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/mfd/ucb1x00.h>
 
 #include <asm/irq.h>
 #include <mach/hardware.h>
@@ -187,10 +188,15 @@ static struct resource simpad_flash_resources [] = {
        }
 };
 
+static struct ucb1x00_plat_data simpad_ucb1x00_data = {
+       .gpio_base      = SIMPAD_UCB1X00_GPIO_BASE,
+};
+
 static struct mcp_plat_data simpad_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
-       .gpio_base      = SIMPAD_UCB1X00_GPIO_BASE,
+       .codec          = "ucb1300",
+       .codec_pdata    = &simpad_ucb1x00_data,
 };
 
 
@@ -378,6 +384,16 @@ static int __init simpad_init(void)
 
        sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources,
                              ARRAY_SIZE(simpad_flash_resources));
+
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
        sa11x0_register_mcp(&simpad_mcp_data);
 
        ret = platform_add_devices(devices, ARRAY_SIZE(devices));
index a4e6ca04e319534dfc4a0a94fa2a8fd7bb3e5caa..eff8a96c75ee558298827e5c15a34fbf7af56ae9 100644 (file)
@@ -271,7 +271,7 @@ static struct sh_mobile_lcdc_info lcdc0_info = {
                .flags = LCDC_FLAGS_DWPOL,
                .lcd_size_cfg.width = 44,
                .lcd_size_cfg.height = 79,
-               .bpp = 16,
+               .fourcc = V4L2_PIX_FMT_RGB565,
                .lcd_cfg = lcdc0_modes,
                .num_cfg = ARRAY_SIZE(lcdc0_modes),
                .board_cfg = {
@@ -321,12 +321,46 @@ static struct resource mipidsi0_resources[] = {
        },
 };
 
+#define DSI0PHYCR      0xe615006c
+static int sh_mipi_set_dot_clock(struct platform_device *pdev,
+                                void __iomem *base,
+                                int enable)
+{
+       struct clk *pck;
+       int ret;
+
+       pck = clk_get(&pdev->dev, "dsip_clk");
+       if (IS_ERR(pck)) {
+               ret = PTR_ERR(pck);
+               goto sh_mipi_set_dot_clock_pck_err;
+       }
+
+       if (enable) {
+               clk_set_rate(pck, clk_round_rate(pck,  24000000));
+               __raw_writel(0x2a809010, DSI0PHYCR);
+               clk_enable(pck);
+       } else {
+               clk_disable(pck);
+       }
+
+       ret = 0;
+
+       clk_put(pck);
+
+sh_mipi_set_dot_clock_pck_err:
+       return ret;
+}
+
 static struct sh_mipi_dsi_info mipidsi0_info = {
        .data_format    = MIPI_RGB888,
        .lcd_chan       = &lcdc0_info.ch[0],
+       .lane           = 2,
        .vsynw_offset   = 20,
        .clksrc         = 1,
-       .flags          = SH_MIPI_DSI_HSABM,
+       .flags          = SH_MIPI_DSI_HSABM             |
+                         SH_MIPI_DSI_SYNC_PULSES_MODE  |
+                         SH_MIPI_DSI_HSbyteCLK,
+       .set_dot_clock  = sh_mipi_set_dot_clock,
 };
 
 static struct platform_device mipidsi0_device = {
@@ -472,8 +506,6 @@ static void __init ag5evm_map_io(void)
        shmobile_setup_console();
 }
 
-#define DSI0PHYCR      0xe615006c
-
 static void __init ag5evm_init(void)
 {
        sh73a0_pinmux_init();
@@ -554,9 +586,6 @@ static void __init ag5evm_init(void)
        gpio_direction_output(GPIO_PORT235, 0);
        lcd_backlight_reset();
 
-       /* MIPI-DSI clock setup */
-       __raw_writel(0x2a809010, DSI0PHYCR);
-
        /* enable SDHI0 on CN15 [SD I/F] */
        gpio_request(GPIO_FN_SDHICD0, NULL);
        gpio_request(GPIO_FN_SDHIWP0, NULL);
index d2e7b73aa9b6418dce567e6be2216e07961fdb0c..aab0a349f759baaa6469373270539cab35b9cee4 100644 (file)
@@ -491,7 +491,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
        .meram_dev = &meram_info,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
-               .bpp = 16,
+               .fourcc = V4L2_PIX_FMT_RGB565,
                .lcd_cfg = ap4evb_lcdc_modes,
                .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes),
                .meram_cfg = &lcd_meram_cfg,
@@ -564,6 +564,30 @@ static struct platform_device keysc_device = {
 };
 
 /* MIPI-DSI */
+#define PHYCTRL                0x0070
+static int sh_mipi_set_dot_clock(struct platform_device *pdev,
+                                void __iomem *base,
+                                int enable)
+{
+       struct clk *pck = clk_get(&pdev->dev, "dsip_clk");
+       void __iomem *phy =  base + PHYCTRL;
+
+       if (IS_ERR(pck))
+               return PTR_ERR(pck);
+
+       if (enable) {
+               clk_set_rate(pck, clk_round_rate(pck, 24000000));
+               iowrite32(ioread32(phy) | (0xb << 8), phy);
+               clk_enable(pck);
+       } else {
+               clk_disable(pck);
+       }
+
+       clk_put(pck);
+
+       return 0;
+}
+
 static struct resource mipidsi0_resources[] = {
        [0] = {
                .start  = 0xffc60000,
@@ -580,7 +604,11 @@ static struct resource mipidsi0_resources[] = {
 static struct sh_mipi_dsi_info mipidsi0_info = {
        .data_format    = MIPI_RGB888,
        .lcd_chan       = &lcdc_info.ch[0],
+       .lane           = 2,
        .vsynw_offset   = 17,
+       .flags          = SH_MIPI_DSI_SYNC_PULSES_MODE |
+                         SH_MIPI_DSI_HSbyteCLK,
+       .set_dot_clock  = sh_mipi_set_dot_clock,
 };
 
 static struct platform_device mipidsi0_device = {
@@ -798,7 +826,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = {
        .meram_dev = &meram_info,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
-               .bpp = 16,
+               .fourcc = V4L2_PIX_FMT_RGB565,
                .interface_type = RGB24,
                .clock_divider = 1,
                .flags = LCDC_FLAGS_DWPOL,
index cbc5934ae03f0f0fa26057ee42c7d275ae7500fe..9b42fbd10f8edf2873dbfba0bf6399305c8603db 100644 (file)
@@ -388,7 +388,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
        .clock_source = LCDC_CLK_BUS,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
-               .bpp = 16,
+               .fourcc = V4L2_PIX_FMT_RGB565,
                .lcd_cfg = mackerel_lcdc_modes,
                .num_cfg = ARRAY_SIZE(mackerel_lcdc_modes),
                .interface_type         = RGB24,
@@ -451,7 +451,7 @@ static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
        .clock_source = LCDC_CLK_EXTERNAL,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
-               .bpp = 16,
+               .fourcc = V4L2_PIX_FMT_RGB565,
                .interface_type = RGB24,
                .clock_divider = 1,
                .flags = LCDC_FLAGS_DWPOL,
index e349c22a0d71c93c54e49466549814795c80b77b..293456d8dcfddac245745cd27b54d126bda7ce7d 100644 (file)
@@ -612,8 +612,8 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("hdmi_clk", &div6_reparent_clks[DIV6_HDMI]),
        CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]),
        CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]),
-       CLKDEV_ICK_ID("dsi0p_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]),
-       CLKDEV_ICK_ID("dsi1p_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]),
+       CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]),
+       CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]),
 
        /* MSTP32 clocks */
        CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */
index 34944d01bf1ed99db00a49f4b9845271ddce3a3e..afbead6a6e1728d51a653f8bca52dcdc01276fbe 100644 (file)
@@ -427,8 +427,8 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("sdhi2_clk", &div6_clks[DIV6_SDHI2]),
        CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]),
        CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]),
-       CLKDEV_ICK_ID("dsi0p_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]),
-       CLKDEV_ICK_ID("dsi1p_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]),
+       CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]),
+       CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]),
 
        /* MSTP32 clocks */
        CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* I2C2 */
index 77b8fc12fc2f1ab0000ae734fff09624ba7cbf44..fcf8b1761aef723c6f3e5f3bd1f2b42cf436e04a 100644 (file)
@@ -276,7 +276,7 @@ static int sh7372_a3sp_suspend(void)
         * Serial consoles make use of SCIF hardware located in A3SP,
         * keep such power domain on if "no_console_suspend" is set.
         */
-       return console_suspend_enabled ? -EBUSY : 0;
+       return console_suspend_enabled ? 0 : -EBUSY;
 }
 
 struct sh7372_pm_domain sh7372_a3sp = {
index 1ea89be63e29e1d13e7783d0d7f2ff31f64057a9..6fcf304d3cdf53869f4d7b64d701e4d5e92345ce 100644 (file)
@@ -445,31 +445,39 @@ static const struct sh_dmae_slave_config sh7372_dmae_slaves[] = {
        },
 };
 
+#define SH7372_CHCLR 0x220
+
 static const struct sh_dmae_channel sh7372_dmae_channels[] = {
        {
                .offset = 0,
                .dmars = 0,
                .dmars_bit = 0,
+               .chclr_offset = SH7372_CHCLR + 0,
        }, {
                .offset = 0x10,
                .dmars = 0,
                .dmars_bit = 8,
+               .chclr_offset = SH7372_CHCLR + 0x10,
        }, {
                .offset = 0x20,
                .dmars = 4,
                .dmars_bit = 0,
+               .chclr_offset = SH7372_CHCLR + 0x20,
        }, {
                .offset = 0x30,
                .dmars = 4,
                .dmars_bit = 8,
+               .chclr_offset = SH7372_CHCLR + 0x30,
        }, {
                .offset = 0x50,
                .dmars = 8,
                .dmars_bit = 0,
+               .chclr_offset = SH7372_CHCLR + 0x50,
        }, {
                .offset = 0x60,
                .dmars = 8,
                .dmars_bit = 8,
+               .chclr_offset = SH7372_CHCLR + 0x60,
        }
 };
 
@@ -487,6 +495,7 @@ static struct sh_dmae_pdata dma_platform_data = {
        .ts_shift       = ts_shift,
        .ts_shift_num   = ARRAY_SIZE(ts_shift),
        .dmaor_init     = DMAOR_DME,
+       .chclr_present  = 1,
 };
 
 /* Resource order important! */
@@ -494,7 +503,7 @@ static struct resource sh7372_dmae0_resources[] = {
        {
                /* Channel registers and DMAOR */
                .start  = 0xfe008020,
-               .end    = 0xfe00808f,
+               .end    = 0xfe00828f,
                .flags  = IORESOURCE_MEM,
        },
        {
@@ -522,7 +531,7 @@ static struct resource sh7372_dmae1_resources[] = {
        {
                /* Channel registers and DMAOR */
                .start  = 0xfe018020,
-               .end    = 0xfe01808f,
+               .end    = 0xfe01828f,
                .flags  = IORESOURCE_MEM,
        },
        {
@@ -550,7 +559,7 @@ static struct resource sh7372_dmae2_resources[] = {
        {
                /* Channel registers and DMAOR */
                .start  = 0xfe028020,
-               .end    = 0xfe02808f,
+               .end    = 0xfe02828f,
                .flags  = IORESOURCE_MEM,
        },
        {
index 9361a5290177d11a26d9190e328147e497ec686a..5c00712907d18ef715a74fa3caa27b38fba095f6 100644 (file)
 #include <linux/amba/pl022.h>
 #include <linux/amba/serial.h>
 #include <linux/spi/spi.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/regulator/ab8500.h>
 #include <linux/mfd/tc3589x.h>
 #include <linux/mfd/tps6105x.h>
-#include <linux/mfd/ab8500/gpio.h>
+#include <linux/mfd/abx500/ab8500-gpio.h>
 #include <linux/leds-lp5521.h>
 #include <linux/input.h>
 #include <linux/smsc911x.h>
index fe1569b67c9182cea704dab1fc4ddd1145388dbe..9de9e9c4dbbbcf2322e0fbaf3140537e31b89d4a 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/amba/bus.h>
 #include <linux/irq.h>
 #include <linux/i2c.h>
-#include <linux/mfd/ab5500/ab5500.h>
+#include <linux/mfd/abx500/ab5500.h>
 
 #include <asm/hardware/gic.h>
 #include <asm/mach/arch.h>
index 64fa451edcfd486bdbaa0163f55e93399597d8ed..08da5589bcd8a60179cc458dba05f735ea6f919f 100644 (file)
@@ -32,6 +32,8 @@ pen:  ldr     r7, [r6]
         * should now contain the SVC stack for this core
         */
        b       secondary_startup
+ENDPROC(u8500_secondary_startup)
 
+       .align 2
 1:     .long   .
        .long   pen_release
index 47969909836c9bb1441b7143dc5c4e156915267f..d2d4131435a680b61fcb6f84f6b092affe72f5cd 100644 (file)
@@ -9,7 +9,7 @@
 #define __MACH_IRQS_BOARD_MOP500_H
 
 /* Number of AB8500 irqs is taken from header file */
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 
 #define MOP500_AB8500_IRQ_BASE         IRQ_BOARD_START
 #define MOP500_AB8500_IRQ_END          (MOP500_AB8500_IRQ_BASE \
index 2b5f7ac001a3326a160c346b9a3a0706d9e3c858..124ffb16909382f1383673783812fd5a1354f70c 100644 (file)
@@ -13,8 +13,6 @@
 #include <linux/smp.h>
 #include <linux/io.h>
 
-#include <asm/unified.h>
-
 #include <mach/motherboard.h>
 #define V2M_PA_CS7 0x10000000
 
@@ -46,6 +44,6 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
         * secondary CPU branches to this address.
         */
        writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR));
-       writel(BSYM(virt_to_phys(versatile_secondary_startup)),
+       writel(virt_to_phys(versatile_secondary_startup),
                MMIO_P2V(V2M_SYS_FLAGSSET));
 }
index 3de4a5211c3b1702ac0aa1fb126c4b69f6e918c4..06d867dce55161df7d0ab34dfd11d0027e64795c 100644 (file)
@@ -48,7 +48,7 @@ static void clock_source_select(const char *dev_id, unsigned int clkval)
                offset = ATAOFFSET;
        else if (strcmp(dev_id, "nuc900-lcd") == 0)
                offset = LCDOFFSET;
-       else if (strcmp(dev_id, "nuc900-audio") == 0)
+       else if (strcmp(dev_id, "nuc900-ac97") == 0)
                offset = AUDOFFSET;
        else
                offset = CPUOFFSET;
index 604e1db266e8402d5f85c018c3870e15794c8bef..9a06619929090c43dd4993bfeeb3878319ac901b 100644 (file)
@@ -79,7 +79,7 @@ static DEFINE_CLK(timer4, 23);
 
 static struct clk_lookup nuc900_clkregs[] = {
        DEF_CLKLOOK(&clk_lcd, "nuc900-lcd", NULL),
-       DEF_CLKLOOK(&clk_audio, "nuc900-audio", NULL),
+       DEF_CLKLOOK(&clk_audio, "nuc900-ac97", NULL),
        DEF_CLKLOOK(&clk_fmi, "nuc900-fmi", NULL),
        DEF_CLKLOOK(&clk_ms, "nuc900-fmi", "MS"),
        DEF_CLKLOOK(&clk_sd, "nuc900-fmi", "SD"),
index 5b0c38abacc107a7eae8bd35ec8f03666f3422e7..78110befb7a9132d6da3353fdec6721b421894ed 100644 (file)
@@ -501,8 +501,8 @@ static struct resource nuc900_ac97_resource[] = {
 
 };
 
-struct platform_device nuc900_device_audio = {
-       .name           = "nuc900-audio",
+struct platform_device nuc900_device_ac97 = {
+       .name           = "nuc900-ac97",
        .id             = -1,
        .num_resources  = ARRAY_SIZE(nuc900_ac97_resource),
        .resource       = nuc900_ac97_resource,
@@ -523,7 +523,7 @@ static struct platform_device *nuc900_public_dev[] __initdata = {
        &nuc900_device_emc,
        &nuc900_device_spi,
        &nuc900_device_wdt,
-       &nuc900_device_audio,
+       &nuc900_device_ac97,
 };
 
 /* Provide adding specific CPU platform devices API */
index 9dd74612bb8707560abd06e6adc250f7ecd54bf2..c58d142b8a467134d193d2252ce52a361e314fcf 100644 (file)
@@ -155,7 +155,7 @@ void mfp_set_groupg(struct device *dev, const char *subname)
        } else if (strcmp(dev_id, "nuc900-i2c1") == 0) {
                mfpen &= ~(GPIOG2TO3);
                mfpen |= ENI2C1;/*enable i2c1*/
-       } else if (strcmp(dev_id, "nuc900-audio") == 0) {
+       } else if (strcmp(dev_id, "nuc900-ac97") == 0) {
                mfpen &= ~(GPIOG22TO23);
                mfpen |= ENAC97;/*enable AC97*/
        } else if (strcmp(dev_id, "nuc900-mmc-port1") == 0) {
index e34ea8adc1f928fe8ebeadc677aba06fbd8b4f47..6ec1226fc62d2fc58caa6c795614455c0f7e8ed7 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/memblock.h>
 
 #include <asm/mach-types.h>
+#include <asm/memblock.h>
 #include <asm/prom.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
@@ -307,6 +308,21 @@ static void arm_memory_present(void)
 }
 #endif
 
+static bool arm_memblock_steal_permitted = true;
+
+phys_addr_t arm_memblock_steal(phys_addr_t size, phys_addr_t align)
+{
+       phys_addr_t phys;
+
+       BUG_ON(!arm_memblock_steal_permitted);
+
+       phys = memblock_alloc(size, align);
+       memblock_free(phys, size);
+       memblock_remove(phys, size);
+
+       return phys;
+}
+
 void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
 {
        int i;
@@ -349,6 +365,7 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
        if (mdesc->reserve)
                mdesc->reserve();
 
+       arm_memblock_steal_permitted = false;
        memblock_allow_resize();
        memblock_dump_all();
 }
index ac24c5c4bc83c48cfe005fb2cea0e9bd7d2fc89e..fdbe60001542615595b5f178f6856d8d5c0455bb 100644 (file)
 #define FB_SYNC_SWAP_RGB       0x04000000
 #define FB_SYNC_CLK_SEL_EN     0x02000000
 
+/*
+ * Specify the way your display is connected. The IPU can arbitrarily
+ * map the internal colors to the external data lines. We only support
+ * the following mappings at the moment.
+ */
+enum disp_data_mapping {
+       /* blue -> d[0..5], green -> d[6..11], red -> d[12..17] */
+       IPU_DISP_DATA_MAPPING_RGB666,
+       /* blue -> d[0..4], green -> d[5..10], red -> d[11..15] */
+       IPU_DISP_DATA_MAPPING_RGB565,
+       /* blue -> d[0..7], green -> d[8..15], red -> d[16..23] */
+       IPU_DISP_DATA_MAPPING_RGB888,
+};
+
 /**
  * struct mx3fb_platform_data - mx3fb platform data
  *
@@ -33,6 +47,7 @@ struct mx3fb_platform_data {
        const char                      *name;
        const struct fb_videomode       *mode;
        int                             num_modes;
+       enum disp_data_mapping          disp_data_fmt;
 };
 
 #endif
index 685c78716d95234d1cb955b69d23a0bd929d107b..fd0ee84c45d1bc66b51e0a5527f75d9981040eeb 100644 (file)
@@ -113,7 +113,8 @@ struct stedma40_half_channel_info {
  * @dst_dev_type: Dst device type
  * @src_info: Parameters for dst half channel
  * @dst_info: Parameters for dst half channel
- *
+ * @use_fixed_channel: if true, use physical channel specified by phy_channel
+ * @phy_channel: physical channel to use, only if use_fixed_channel is true
  *
  * This structure has to be filled by the client drivers.
  * It is recommended to do all dma configurations for clients in the machine.
@@ -129,6 +130,9 @@ struct stedma40_chan_cfg {
        int                                      dst_dev_type;
        struct stedma40_half_channel_info        src_info;
        struct stedma40_half_channel_info        dst_info;
+
+       bool                                     use_fixed_channel;
+       int                                      phy_channel;
 };
 
 /**
@@ -153,6 +157,7 @@ struct stedma40_platform_data {
        struct stedma40_chan_cfg        *memcpy_conf_phy;
        struct stedma40_chan_cfg        *memcpy_conf_log;
        int                              disabled_channels[STEDMA40_MAX_PHYS];
+       bool                             use_esram_lcla;
 };
 
 #ifdef CONFIG_STE_DMA40
@@ -187,7 +192,7 @@ static inline struct
 dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan,
                                            dma_addr_t addr,
                                            unsigned int size,
-                                           enum dma_data_direction direction,
+                                           enum dma_transfer_direction direction,
                                            unsigned long flags)
 {
        struct scatterlist sg;
@@ -209,7 +214,7 @@ static inline struct
 dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan,
                                            dma_addr_t addr,
                                            unsigned int size,
-                                           enum dma_data_direction direction,
+                                           enum dma_transfer_direction direction,
                                            unsigned long flags)
 {
        return NULL;
index 19719329a47b0fb96a4b75e42f8103f505c00c84..60278f47c0bdd71953cc5c1483a68a7a02a0b50f 100644 (file)
@@ -20,6 +20,7 @@
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
+#include <asm/memblock.h>
 
 #include <plat/tc.h>
 #include <plat/board.h>
@@ -164,14 +165,12 @@ void __init omap_dsp_reserve_sdram_memblock(void)
        if (!size)
                return;
 
-       paddr = memblock_alloc(size, SZ_1M);
+       paddr = arm_memblock_steal(size, SZ_1M);
        if (!paddr) {
                pr_err("%s: failed to reserve %x bytes\n",
                                __func__, size);
                return;
        }
-       memblock_free(paddr, size);
-       memblock_remove(paddr, size);
 
        omap_dsp_phys_mempool_base = paddr;
 }
index 1121df13e15f52de91d7d30ee41399950e60ee72..21f1fda8b661ee7021782921b98b6cb637547284 100644 (file)
@@ -38,8 +38,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <mach/system-reset.h>
-
 #include <mach/regs-gpio.h>
 #include <plat/regs-serial.h>
 
index 2cded872f22b3debd634282a408d67169ceff981..0747c77a2fd53d0d2a66a1f1f2377b3d7e7722f6 100644 (file)
@@ -37,14 +37,14 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
                                (void *)dma_ch;
        chan = dma_request_channel(mask, pl330_filter, filter_param);
 
-       if (info->direction == DMA_FROM_DEVICE) {
+       if (info->direction == DMA_DEV_TO_MEM) {
                memset(&slave_config, 0, sizeof(struct dma_slave_config));
                slave_config.direction = info->direction;
                slave_config.src_addr = info->fifo;
                slave_config.src_addr_width = info->width;
                slave_config.src_maxburst = 1;
                dmaengine_slave_config(chan, &slave_config);
-       } else if (info->direction == DMA_TO_DEVICE) {
+       } else if (info->direction == DMA_MEM_TO_DEV) {
                memset(&slave_config, 0, sizeof(struct dma_slave_config));
                slave_config.direction = info->direction;
                slave_config.dst_addr = info->fifo;
index 22eafc310bd7858a8fb10b39087fc6064e78e04c..71a6827c7706b21e10200bd834b5dbaad1fa9e45 100644 (file)
 #define __SAMSUNG_DMA_OPS_H_ __FILE__
 
 #include <linux/dmaengine.h>
+#include <mach/dma.h>
 
 struct samsung_dma_prep_info {
        enum dma_transaction_type cap;
-       enum dma_data_direction direction;
+       enum dma_transfer_direction direction;
        dma_addr_t buf;
        unsigned long period;
        unsigned long len;
@@ -27,7 +28,7 @@ struct samsung_dma_prep_info {
 
 struct samsung_dma_info {
        enum dma_transaction_type cap;
-       enum dma_data_direction direction;
+       enum dma_transfer_direction direction;
        enum dma_slave_buswidth width;
        dma_addr_t fifo;
        struct s3c2410_dma_client *client;
index b9061128abdef3bcf76a2e9cdd4bab76732b4fd5..7b02143ccd9a2236b1ba0f32cc47dfb54d8b3d54 100644 (file)
@@ -10,6 +10,9 @@
  * published by the Free Software Foundation.
 */
 
+#ifndef __PLAT_DMA_H
+#define __PLAT_DMA_H
+
 #include <linux/dma-mapping.h>
 
 enum s3c2410_dma_buffresult {
@@ -122,5 +125,6 @@ extern int s3c2410_dma_getposition(enum dma_ch channel,
 extern int s3c2410_dma_set_opfn(enum dma_ch, s3c2410_dma_opfn_t rtn);
 extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn);
 
-
 #include <plat/dma-ops.h>
+
+#endif
index aea68b60ef98af7bac8c5841536c8150d803888f..fa95e9a009729f41ddd1c39174e4f6908f515226 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef __S3C64XX_PLAT_SPI_H
 #define __S3C64XX_PLAT_SPI_H
 
+struct platform_device;
+
 /**
  * struct s3c64xx_spi_csinfo - ChipSelect description
  * @fb_delay: Slave specific feedback delay.
index 656dc00d30edde87d8d44ed6dada500672355394..f82f888b91a95bb0a238975b4c575408728eb1e9 100644 (file)
@@ -63,6 +63,7 @@ enum clk_types {
 struct s3c_sdhci_platdata {
        unsigned int    max_width;
        unsigned int    host_caps;
+       unsigned int    pm_caps;
        enum cd_types   cd_type;
        enum clk_types  clk_type;
 
index ceb9fa3a80c0768a10411740547a42dd0fbcceb1..0f707184eae0b0d07cb7cecc2e3d5464182ee4ce 100644 (file)
@@ -53,6 +53,8 @@ void s3c_sdhci_set_platdata(struct s3c_sdhci_platdata *pd,
                set->cfg_gpio = pd->cfg_gpio;
        if (pd->host_caps)
                set->host_caps |= pd->host_caps;
+       if (pd->pm_caps)
+               set->pm_caps |= pd->pm_caps;
        if (pd->clk_type)
                set->clk_type = pd->clk_type;
 }
index d397a1fb2f5414ac7337d9aca3e8d328bf39f4c8..dd703ef09b8d9d623d83e4a131c12e87e329e838 100644 (file)
@@ -38,3 +38,4 @@ pen:  ldr     r7, [r6]
        .align
 1:     .long   .
        .long   pen_release
+ENDPROC(versatile_secondary_startup)
index 9702c2213e1e74d979fb914b286cfbfac8c1609d..62d9ded016357bc6e6a6534d56cd154694b9692a 100644 (file)
@@ -169,7 +169,7 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
 #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
 
 struct pt_regs;
-void NORET_TYPE die(const char *str, struct pt_regs *regs, long err);
+void die(const char *str, struct pt_regs *regs, long err);
 void _exception(long signr, struct pt_regs *regs, int code,
                unsigned long addr);
 
index 7aa25756412f16299b69cccfcd1d1c9851aaaec7..3d760c06f02481851e6ab27e57e819a376dcb6d5 100644 (file)
@@ -24,7 +24,7 @@
 
 static DEFINE_SPINLOCK(die_lock);
 
-void NORET_TYPE die(const char *str, struct pt_regs *regs, long err)
+void die(const char *str, struct pt_regs *regs, long err)
 {
        static int die_counter;
 
index 6859dd503ed366910cfe0fa85e7c0acf53e7f525..a52dca9a956660eb1656ad201cbed950db4f305c 100644 (file)
@@ -1,22 +1,8 @@
 #ifndef _ASM_PARAM_H
 #define _ASM_PARAM_H
 
-#ifdef __KERNEL__
-#define HZ             CONFIG_HZ       /* Internal kernel timer frequency */
-#define USER_HZ                100             /* .. some user interfaces are in "ticks" */
-#define CLOCKS_PER_SEC (USER_HZ)       /* like times() */
-#endif
-
-#ifndef HZ
-#define HZ 100
-#endif
-
 #define EXEC_PAGESIZE  16384
 
-#ifndef NOGROUP
-#define NOGROUP                (-1)
-#endif
-
-#define MAXHOSTNAMELEN         64      /* max length of hostname */
+#include <asm-generic/param.h>
 
 #endif /* _ASM_PARAM_H */
index 22078486d35da9bcb96fe66a35524f4fe31193c1..6192f7188654e0549c01d934e7073a68890c7f7a 100644 (file)
@@ -31,7 +31,7 @@ MODULE_AUTHOR("Bjorn Helgaas <bjorn.helgaas@hp.com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("ACPI opregion handler for native firmware calls");
 
-static int force_register;
+static bool force_register;
 module_param_named(force, force_register, bool, 0);
 MODULE_PARM_DESC(force, "Install opregion handler even without HPQ5001 device");
 
index 111ed52228921cac226a8994e404e3100defb73c..e4076b511829572ad590d36e362f463f93e813d6 100644 (file)
@@ -201,16 +201,21 @@ extern long ia64_cmpxchg_called_with_bad_pointer (void);
 #endif
 
 #ifndef __ASSEMBLY__
-#if defined(CONFIG_PARAVIRT) && defined(__KERNEL__)
-#ifdef ASM_SUPPORTED
-# define IA64_INTRINSIC_API(name)      paravirt_ ## name
-#else
-# define IA64_INTRINSIC_API(name)      pv_cpu_ops.name
-#endif
-#define IA64_INTRINSIC_MACRO(name)     paravirt_ ## name
-#else
+
 #define IA64_INTRINSIC_API(name)       ia64_native_ ## name
 #define IA64_INTRINSIC_MACRO(name)     ia64_native_ ## name
+
+#if defined(__KERNEL__)
+#if defined(CONFIG_PARAVIRT)
+# undef IA64_INTRINSIC_API
+# undef IA64_INTRINSIC_MACRO
+# ifdef ASM_SUPPORTED
+#  define IA64_INTRINSIC_API(name)     paravirt_ ## name
+# else
+#  define IA64_INTRINSIC_API(name)     pv_cpu_ops.name
+# endif
+#define IA64_INTRINSIC_MACRO(name)     paravirt_ ## name
+#endif
 #endif
 
 /************************************************/
index d9f397fae03eb7e89712aa7cedef3b8d11082b4e..691be0b95c1e0fb280721cde45e9d1f88d08af77 100644 (file)
@@ -309,7 +309,6 @@ struct thread_struct {
 }
 
 #define start_thread(regs,new_ip,new_sp) do {                                                  \
-       set_fs(USER_DS);                                                                        \
        regs->cr_ipsr = ((regs->cr_ipsr | (IA64_PSR_BITS_TO_SET | IA64_PSR_CPL))                \
                         & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_RI | IA64_PSR_IS));              \
        regs->cr_iip = new_ip;                                                                  \
index f5cb27614e35df7c4027094e7ac1d6626091021c..68c98f5b3ca625aaca9f342addd31c68c48c27af 100644 (file)
@@ -246,7 +246,18 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
        return regs->ar_bspstore;
 }
 
-#define regs_return_value(regs) ((regs)->r8)
+static inline int is_syscall_success(struct pt_regs *regs)
+{
+       return regs->r10 != -1;
+}
+
+static inline long regs_return_value(struct pt_regs *regs)
+{
+       if (is_syscall_success(regs))
+               return regs->r8;
+       else
+               return -regs->r8;
+}
 
 /* Conserve space in histogram by encoding slot bits in address
  * bits 2 and 3 rather than bits 0 and 1.
index 7617248f0d11e9d906d82d88d582ed3c2626c558..7a3bd252494468dcc5f4da779a62fc4500d65805 100644 (file)
 #define __NR_sendmmsg                  1331
 #define __NR_process_vm_readv          1332
 #define __NR_process_vm_writev         1333
+#define __NR_accept4                   1334
 
 #ifdef __KERNEL__
 
 
-#define NR_syscalls                    310 /* length of syscall table */
+#define NR_syscalls                    311 /* length of syscall table */
 
 /*
  * The following defines stop scripts/checksyscalls.sh from complaining about
index bfb4d01e0e519ed74a2a941214b4426627307134..5207035dc061bb5c567275efa0e0b58d2149a54d 100644 (file)
@@ -429,22 +429,24 @@ static u32 __devinitdata pxm_flag[PXM_FLAG_LEN];
 static struct acpi_table_slit __initdata *slit_table;
 cpumask_t early_cpu_possible_map = CPU_MASK_NONE;
 
-static int get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa)
+static int __init
+get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa)
 {
        int pxm;
 
        pxm = pa->proximity_domain_lo;
-       if (ia64_platform_is("sn2"))
+       if (ia64_platform_is("sn2") || acpi_srat_revision >= 2)
                pxm += pa->proximity_domain_hi[0] << 8;
        return pxm;
 }
 
-static int get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma)
+static int __init
+get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma)
 {
        int pxm;
 
        pxm = ma->proximity_domain;
-       if (!ia64_platform_is("sn2"))
+       if (!ia64_platform_is("sn2") && acpi_srat_revision <= 1)
                pxm &= 0xff;
 
        return pxm;
index 5b31d46aff67b10e31c35bb6ea273549247613b5..1ccbe12a4d84fe6585455a45b367647b1fa2c240 100644 (file)
@@ -1779,6 +1779,7 @@ sys_call_table:
        data8 sys_sendmmsg
        data8 sys_process_vm_readv
        data8 sys_process_vm_writev
+       data8 sys_accept4
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
 #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
index 3d3aeef469476a85ed4d149608ebd891e72c5f6c..4eed35814994ebfed9c6e5d5dcca527cc327daba 100644 (file)
 #include <asm/sal.h>
 #include <asm/mca.h>
 
-typedef NORET_TYPE void (*relocate_new_kernel_t)(
+typedef void (*relocate_new_kernel_t)(
                                        unsigned long indirection_page,
                                        unsigned long start_address,
                                        struct ia64_boot_param *boot_param,
-                                       unsigned long pal_addr) ATTRIB_NORET;
+                                       unsigned long pal_addr) __noreturn;
 
 struct kimage *ia64_kimage;
 
index 8848f43d819e55ba91bf07fc6ae8756f88e7ad36..dad91661ddf96e8b54aa4fbeafb9190879a65ccf 100644 (file)
@@ -1246,15 +1246,8 @@ syscall_trace_enter (long arg0, long arg1, long arg2, long arg3,
        if (test_thread_flag(TIF_RESTORE_RSE))
                ia64_sync_krbs();
 
-       if (unlikely(current->audit_context)) {
-               long syscall;
-               int arch;
 
-               syscall = regs.r15;
-               arch = AUDIT_ARCH_IA64;
-
-               audit_syscall_entry(arch, syscall, arg0, arg1, arg2, arg3);
-       }
+       audit_syscall_entry(AUDIT_ARCH_IA64, regs.r15, arg0, arg1, arg2, arg3);
 
        return 0;
 }
@@ -1268,14 +1261,7 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3,
 {
        int step;
 
-       if (unlikely(current->audit_context)) {
-               int success = AUDITSC_RESULT(regs.r10);
-               long result = regs.r8;
-
-               if (success != AUDITSC_SUCCESS)
-                       result = -result;
-               audit_syscall_exit(success, result);
-       }
+       audit_syscall_exit(&regs);
 
        step = test_thread_flag(TIF_SINGLESTEP);
        if (step || test_thread_flag(TIF_SYSCALL_TRACE))
index 94c770196048335767a40f9fd8fd649d11f1effb..fa207bdf96e75eb444f8e4687a8e6f2185211479 100644 (file)
@@ -1,23 +1,7 @@
 #ifndef _ASM_M32R_PARAM_H
 #define _ASM_M32R_PARAM_H
 
-#ifdef __KERNEL__
-# define HZ            CONFIG_HZ       /* Internal kernel timer frequency */
-# define USER_HZ       100             /* .. some user interfaces are in "ticks" */
-# define CLOCKS_PER_SEC        (USER_HZ)       /* like times() */
-#endif
-
-#ifndef HZ
-#define HZ 100
-#endif
-
-#define EXEC_PAGESIZE  4096
-
-#ifndef NOGROUP
-#define NOGROUP                (-1)
-#endif
-
-#define MAXHOSTNAMELEN 64      /* max length of hostname */
+#include <asm-generic/param.h>
 
 #endif /* _ASM_M32R_PARAM_H */
 
index 82a4bb51d5d85b4f6271b7f4a830f1150bea5b59..b95a451b1c3ae6292092efcf4ea24fc103e69eda 100644 (file)
@@ -511,8 +511,7 @@ static unsigned long amiga_gettimeoffset(void)
        return ticks + offset;
 }
 
-static NORET_TYPE void amiga_reset(void)
-    ATTRIB_NORET;
+static void amiga_reset(void)  __noreturn;
 
 static void amiga_reset(void)
 {
index 4c4e58ef0cb628ed3ca0f542536872036f93da02..0c796cf8158629abf23adb530c17ba2a8ceb9be5 100644 (file)
@@ -53,6 +53,6 @@ $(obj)/simpleImage.%: vmlinux FORCE
 DTC_FLAGS := -p 1024
 
 $(obj)/%.dtb: $(src)/dts/%.dts FORCE
-       $(call cmd,dtc)
+       $(call if_changed_dep,dtc)
 
 clean-files += *.dtb simpleImage.*.unstrip linux.bin.ub
index 816bee64b1961d202f35a1aa9c4d2be0fc1d640e..94e92c8058592f786cfd6fac942c90b308664e85 100644 (file)
@@ -61,6 +61,11 @@ struct pt_regs {
 #define instruction_pointer(regs)      ((regs)->pc)
 #define profile_pc(regs)               instruction_pointer(regs)
 
+static inline long regs_return_value(struct pt_regs *regs)
+{
+       return regs->r3;
+}
+
 #else /* __KERNEL__ */
 
 /* pt_regs offsets used by gdbserver etc in ptrace syscalls */
index 043cb58f9c443e72843fa44a9ebd399442a965b5..6eb2aa927d8966b842f388b219ae19b8dadd7309 100644 (file)
@@ -147,10 +147,8 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
                 */
                ret = -1L;
 
-       if (unlikely(current->audit_context))
-               audit_syscall_entry(EM_MICROBLAZE, regs->r12,
-                                   regs->r5, regs->r6,
-                                   regs->r7, regs->r8);
+       audit_syscall_entry(EM_MICROBLAZE, regs->r12, regs->r5, regs->r6,
+                           regs->r7, regs->r8);
 
        return ret ?: regs->r12;
 }
@@ -159,8 +157,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
 {
        int step;
 
-       if (unlikely(current->audit_context))
-               audit_syscall_exit(AUDITSC_RESULT(regs->r3), regs->r3);
+       audit_syscall_exit(regs);
 
        step = test_thread_flag(TIF_SINGLESTEP);
        if (step || test_thread_flag(TIF_SYSCALL_TRACE))
index 604cd9dd133362712e5220510be83be134d96ec1..d4fc1a9717796610623cefa50c0ffd706225087e 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/cache.h>
 #include <linux/of_platform.h>
 #include <linux/dma-mapping.h>
+#include <linux/cpu.h>
 #include <asm/cacheflush.h>
 #include <asm/entry.h>
 #include <asm/cpuinfo.h>
@@ -226,5 +227,23 @@ static int __init setup_bus_notifier(void)
 
        return 0;
 }
-
 arch_initcall(setup_bus_notifier);
+
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
+
+static int __init topology_init(void)
+{
+       int i, ret;
+
+       for_each_present_cpu(i) {
+               struct cpu *c = &per_cpu(cpu_devices, i);
+
+               ret = register_cpu(c, i);
+               if (ret)
+                       printk(KERN_WARNING "topology_init: register_cpu %d "
+                                               "failed (%d)\n", i, ret);
+       }
+
+       return 0;
+}
+subsys_initcall(topology_init);
index 29d92187ff3019914c5fea55f317108dc5745958..c4c1312473fbf6cd9104cc3d206846bcd38b1b4b 100644 (file)
@@ -719,7 +719,6 @@ config CAVIUM_OCTEON_SIMULATOR
        select DMA_COHERENT
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
-       select SYS_SUPPORTS_HIGHMEM
        select SYS_SUPPORTS_HOTPLUG_CPU
        select SYS_HAS_CPU_CAVIUM_OCTEON
        select HOLES_IN_ZONE
@@ -735,7 +734,6 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
        select DMA_COHERENT
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
-       select SYS_SUPPORTS_HIGHMEM
        select SYS_SUPPORTS_HOTPLUG_CPU
        select SYS_HAS_EARLY_PRINTK
        select SYS_HAS_CPU_CAVIUM_OCTEON
@@ -764,7 +762,6 @@ config NLM_XLR_BOARD
        depends on EXPERIMENTAL
        select BOOT_ELF32
        select NLM_COMMON
-       select NLM_XLR
        select SYS_HAS_CPU_XLR
        select SYS_SUPPORTS_SMP
        select HW_HAS_PCI
@@ -779,6 +776,7 @@ config NLM_XLR_BOARD
        select CEVT_R4K
        select CSRC_R4K
        select IRQ_CPU
+       select ARCH_SUPPORTS_MSI
        select ZONE_DMA if 64BIT
        select SYNC_R4K
        select SYS_HAS_EARLY_PRINTK
@@ -786,6 +784,33 @@ config NLM_XLR_BOARD
          Support for systems based on Netlogic XLR and XLS processors.
          Say Y here if you have a XLR or XLS based board.
 
+config NLM_XLP_BOARD
+       bool "Netlogic XLP based systems"
+       depends on EXPERIMENTAL
+       select BOOT_ELF32
+       select NLM_COMMON
+       select SYS_HAS_CPU_XLP
+       select SYS_SUPPORTS_SMP
+       select HW_HAS_PCI
+       select SWAP_IO_SPACE
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
+       select 64BIT_PHYS_ADDR
+       select SYS_SUPPORTS_BIG_ENDIAN
+       select SYS_SUPPORTS_LITTLE_ENDIAN
+       select SYS_SUPPORTS_HIGHMEM
+       select DMA_COHERENT
+       select NR_CPUS_DEFAULT_32
+       select CEVT_R4K
+       select CSRC_R4K
+       select IRQ_CPU
+       select ZONE_DMA if 64BIT
+       select SYNC_R4K
+       select SYS_HAS_EARLY_PRINTK
+       help
+         This board is based on Netlogic XLP Processor.
+         Say Y here if you have a XLP based board.
+
 endchoice
 
 source "arch/mips/alchemy/Kconfig"
@@ -1416,51 +1441,36 @@ config CPU_CAVIUM_OCTEON
 config CPU_BMIPS3300
        bool "BMIPS3300"
        depends on SYS_HAS_CPU_BMIPS3300
-       select DMA_NONCOHERENT
-       select IRQ_CPU
-       select SWAP_IO_SPACE
-       select SYS_SUPPORTS_32BIT_KERNEL
-       select WEAK_ORDERING
+       select CPU_BMIPS
        help
          Broadcom BMIPS3300 processors.
 
 config CPU_BMIPS4350
        bool "BMIPS4350"
        depends on SYS_HAS_CPU_BMIPS4350
-       select CPU_SUPPORTS_32BIT_KERNEL
-       select DMA_NONCOHERENT
-       select IRQ_CPU
-       select SWAP_IO_SPACE
+       select CPU_BMIPS
        select SYS_SUPPORTS_SMP
        select SYS_SUPPORTS_HOTPLUG_CPU
-       select WEAK_ORDERING
        help
          Broadcom BMIPS4350 ("VIPER") processors.
 
 config CPU_BMIPS4380
        bool "BMIPS4380"
        depends on SYS_HAS_CPU_BMIPS4380
-       select CPU_SUPPORTS_32BIT_KERNEL
-       select DMA_NONCOHERENT
-       select IRQ_CPU
-       select SWAP_IO_SPACE
+       select CPU_BMIPS
        select SYS_SUPPORTS_SMP
        select SYS_SUPPORTS_HOTPLUG_CPU
-       select WEAK_ORDERING
        help
          Broadcom BMIPS4380 processors.
 
 config CPU_BMIPS5000
        bool "BMIPS5000"
        depends on SYS_HAS_CPU_BMIPS5000
-       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_BMIPS
        select CPU_SUPPORTS_HIGHMEM
-       select DMA_NONCOHERENT
-       select IRQ_CPU
-       select SWAP_IO_SPACE
+       select MIPS_CPU_SCACHE
        select SYS_SUPPORTS_SMP
        select SYS_SUPPORTS_HOTPLUG_CPU
-       select WEAK_ORDERING
        help
          Broadcom BMIPS5000 processors.
 
@@ -1475,6 +1485,19 @@ config CPU_XLR
        select CPU_SUPPORTS_HUGEPAGES
        help
          Netlogic Microsystems XLR/XLS processors.
+
+config CPU_XLP
+       bool "Netlogic XLP SoC"
+       depends on SYS_HAS_CPU_XLP
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_64BIT_KERNEL
+       select CPU_SUPPORTS_HIGHMEM
+       select CPU_HAS_LLSC
+       select WEAK_ORDERING
+       select WEAK_REORDERING_BEYOND_LLSC
+       select CPU_HAS_PREFETCH
+       help
+         Netlogic Microsystems XLP processors.
 endchoice
 
 if CPU_LOONGSON2F
@@ -1521,6 +1544,15 @@ config CPU_LOONGSON2
        select CPU_SUPPORTS_64BIT_KERNEL
        select CPU_SUPPORTS_HIGHMEM
 
+config CPU_BMIPS
+       bool
+       select CPU_MIPS32
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select DMA_NONCOHERENT
+       select IRQ_CPU
+       select SWAP_IO_SPACE
+       select WEAK_ORDERING
+
 config SYS_HAS_CPU_LOONGSON2E
        bool
 
@@ -1608,6 +1640,9 @@ config SYS_HAS_CPU_BMIPS5000
 config SYS_HAS_CPU_XLR
        bool
 
+config SYS_HAS_CPU_XLP
+       bool
+
 #
 # CPU may reorder R->R, R->W, W->R, W->W
 # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
@@ -1995,6 +2030,9 @@ config CPU_HAS_SMARTMIPS
 config CPU_HAS_WB
        bool
 
+config XKS01
+       bool
+
 #
 # Vectored interrupt mode is an R2 feature
 #
index 0be318609fc62832c44fa6a47b1c9670c1e9b2b7..4fedf5a51d965ab9cea3798ab1d2ed3c5298a10b 100644 (file)
@@ -157,6 +157,7 @@ ifeq (,$(findstring march=octeon, $(cflags-$(CONFIG_CPU_CAVIUM_OCTEON))))
 cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -Wa,-march=octeon
 endif
 cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1
+cflags-$(CONFIG_CPU_BMIPS)     += -march=mips32 -Wa,-mips32 -Wa,--trap
 
 cflags-$(CONFIG_CPU_R4000_WORKAROUNDS) += $(call cc-option,-mfix-r4000,)
 cflags-$(CONFIG_CPU_R4400_WORKAROUNDS) += $(call cc-option,-mfix-r4400,)
index 2a68be6a1b97ed953bdfe619d6ab16d5d924d320..0faaab24376e5ca60e78d0405f2534a32b94735d 100644 (file)
@@ -2,6 +2,10 @@
 config ALCHEMY_GPIOINT_AU1000
        bool
 
+# au1300-style GPIO/INT controller
+config ALCHEMY_GPIOINT_AU1300
+       bool
+
 # select this in your board config if you don't want to use the gpio
 # namespace as documented in the manuals.  In this case however you need
 # to create the necessary gpio_* functions in your board code/headers!
@@ -22,43 +26,29 @@ config MIPS_MTX1
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_HAS_EARLY_PRINTK
 
-config MIPS_BOSPORUS
-       bool "Alchemy Bosporus board"
-       select ALCHEMY_GPIOINT_AU1000
-       select DMA_NONCOHERENT
-       select SYS_SUPPORTS_LITTLE_ENDIAN
-       select SYS_HAS_EARLY_PRINTK
-
 config MIPS_DB1000
-       bool "Alchemy DB1000 board"
+       bool "Alchemy DB1000/DB1500/DB1100 boards"
        select ALCHEMY_GPIOINT_AU1000
        select DMA_NONCOHERENT
        select HW_HAS_PCI
-       select SYS_SUPPORTS_LITTLE_ENDIAN
-       select SYS_HAS_EARLY_PRINTK
-
-config MIPS_DB1100
-       bool "Alchemy DB1100 board"
-       select ALCHEMY_GPIOINT_AU1000
-       select DMA_NONCOHERENT
+       select MIPS_DISABLE_OBSOLETE_IDE
+       select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_HAS_EARLY_PRINTK
 
 config MIPS_DB1200
-       bool "Alchemy DB1200 board"
+       bool "Alchemy DB1200/PB1200 board"
        select ALCHEMY_GPIOINT_AU1000
        select DMA_COHERENT
        select MIPS_DISABLE_OBSOLETE_IDE
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_HAS_EARLY_PRINTK
 
-config MIPS_DB1500
-       bool "Alchemy DB1500 board"
-       select ALCHEMY_GPIOINT_AU1000
-       select DMA_NONCOHERENT
-       select HW_HAS_PCI
+config MIPS_DB1300
+       bool "NetLogic DB1300 board"
+       select ALCHEMY_GPIOINT_AU1300
+       select DMA_COHERENT
        select MIPS_DISABLE_OBSOLETE_IDE
-       select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_HAS_EARLY_PRINTK
 
@@ -66,27 +56,11 @@ config MIPS_DB1550
        bool "Alchemy DB1550 board"
        select ALCHEMY_GPIOINT_AU1000
        select HW_HAS_PCI
-       select DMA_NONCOHERENT
+       select DMA_COHERENT
        select MIPS_DISABLE_OBSOLETE_IDE
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_HAS_EARLY_PRINTK
 
-config MIPS_MIRAGE
-       bool "Alchemy Mirage board"
-       select DMA_NONCOHERENT
-       select ALCHEMY_GPIOINT_AU1000
-       select SYS_SUPPORTS_LITTLE_ENDIAN
-       select SYS_HAS_EARLY_PRINTK
-
-config MIPS_PB1000
-       bool "Alchemy PB1000 board"
-       select ALCHEMY_GPIOINT_AU1000
-       select DMA_NONCOHERENT
-       select HW_HAS_PCI
-       select SWAP_IO_SPACE
-       select SYS_SUPPORTS_LITTLE_ENDIAN
-       select SYS_HAS_EARLY_PRINTK
-
 config MIPS_PB1100
        bool "Alchemy PB1100 board"
        select ALCHEMY_GPIOINT_AU1000
@@ -96,14 +70,6 @@ config MIPS_PB1100
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_HAS_EARLY_PRINTK
 
-config MIPS_PB1200
-       bool "Alchemy PB1200 board"
-       select ALCHEMY_GPIOINT_AU1000
-       select DMA_NONCOHERENT
-       select MIPS_DISABLE_OBSOLETE_IDE
-       select SYS_SUPPORTS_LITTLE_ENDIAN
-       select SYS_HAS_EARLY_PRINTK
-
 config MIPS_PB1500
        bool "Alchemy PB1500 board"
        select ALCHEMY_GPIOINT_AU1000
diff --git a/arch/mips/alchemy/Makefile b/arch/mips/alchemy/Makefile
new file mode 100644 (file)
index 0000000..aac3b17
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_MIPS_GPR) += board-gpr.o
+obj-$(CONFIG_MIPS_MTX1) += board-mtx1.o
+obj-$(CONFIG_MIPS_XXS1500) += board-xxs1500.o
index 96e9e41f1b2afd4354776d7772eae0d9a9580df1..7956274de15fc0df3ca3af6eb27bf698914bb45d 100644 (file)
@@ -4,62 +4,31 @@
 platform-$(CONFIG_MIPS_ALCHEMY)        += alchemy/common/
 
 
-#
-# AMD Alchemy Pb1000 eval board
-#
-platform-$(CONFIG_MIPS_PB1000) += alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1000)   += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
-load-$(CONFIG_MIPS_PB1000)     += 0xffffffff80100000
-
 #
 # AMD Alchemy Pb1100 eval board
 #
 platform-$(CONFIG_MIPS_PB1100) += alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1100)   += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
 load-$(CONFIG_MIPS_PB1100)     += 0xffffffff80100000
 
 #
 # AMD Alchemy Pb1500 eval board
 #
 platform-$(CONFIG_MIPS_PB1500) += alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1500)   += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
 load-$(CONFIG_MIPS_PB1500)     += 0xffffffff80100000
 
 #
 # AMD Alchemy Pb1550 eval board
 #
 platform-$(CONFIG_MIPS_PB1550) += alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1550)   += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
 load-$(CONFIG_MIPS_PB1550)     += 0xffffffff80100000
 
 #
-# AMD Alchemy Pb1200 eval board
-#
-platform-$(CONFIG_MIPS_PB1200) += alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1200)   += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
-load-$(CONFIG_MIPS_PB1200)     += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1000 eval board
+# AMD Alchemy Db1000/Db1500/Db1100 eval boards
 #
 platform-$(CONFIG_MIPS_DB1000) += alchemy/devboards/
 cflags-$(CONFIG_MIPS_DB1000)   += -I$(srctree)/arch/mips/include/asm/mach-db1x00
 load-$(CONFIG_MIPS_DB1000)     += 0xffffffff80100000
 
-#
-# AMD Alchemy Db1100 eval board
-#
-platform-$(CONFIG_MIPS_DB1100) += alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1100)   += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1100)     += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1500 eval board
-#
-platform-$(CONFIG_MIPS_DB1500) += alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1500)   += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1500)     += 0xffffffff80100000
-
 #
 # AMD Alchemy Db1550 eval board
 #
@@ -68,42 +37,35 @@ cflags-$(CONFIG_MIPS_DB1550)        += -I$(srctree)/arch/mips/include/asm/mach-db1x00
 load-$(CONFIG_MIPS_DB1550)     += 0xffffffff80100000
 
 #
-# AMD Alchemy Db1200 eval board
+# AMD Alchemy Db1200/Pb1200 eval boards
 #
 platform-$(CONFIG_MIPS_DB1200) += alchemy/devboards/
 cflags-$(CONFIG_MIPS_DB1200)   += -I$(srctree)/arch/mips/include/asm/mach-db1x00
 load-$(CONFIG_MIPS_DB1200)     += 0xffffffff80100000
 
 #
-# AMD Alchemy Bosporus eval board
-#
-platform-$(CONFIG_MIPS_BOSPORUS) += alchemy/devboards/
-cflags-$(CONFIG_MIPS_BOSPORUS)  += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_BOSPORUS)    += 0xffffffff80100000
-
-#
-# AMD Alchemy Mirage eval board
+# NetLogic DBAu1300 development platform
 #
-platform-$(CONFIG_MIPS_MIRAGE) += alchemy/devboards/
-cflags-$(CONFIG_MIPS_MIRAGE)   += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_MIRAGE)     += 0xffffffff80100000
+platform-$(CONFIG_MIPS_DB1300) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1300)   += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1300)     += 0xffffffff80100000
 
 #
-# 4G-Systems eval board
+# 4G-Systems MTX-1 "MeshCube" wireless router
 #
-platform-$(CONFIG_MIPS_MTX1)   += alchemy/mtx-1/
+platform-$(CONFIG_MIPS_MTX1)   += alchemy/
 load-$(CONFIG_MIPS_MTX1)       += 0xffffffff80100000
 
 #
 # MyCable eval board
 #
-platform-$(CONFIG_MIPS_XXS1500)        += alchemy/xxs1500/
+platform-$(CONFIG_MIPS_XXS1500)        += alchemy/
 load-$(CONFIG_MIPS_XXS1500)    += 0xffffffff80100000
 
 #
 # Trapeze ITS GRP board
 #
-platform-$(CONFIG_MIPS_GPR)    += alchemy/gpr/
+platform-$(CONFIG_MIPS_GPR)    += alchemy/
 load-$(CONFIG_MIPS_GPR)                += 0xffffffff80100000
 
 # boards can specify their own <gpio.h> in one of their include dirs.
similarity index 75%
rename from arch/mips/alchemy/gpr/platform.c
rename to arch/mips/alchemy/board-gpr.c
index 982ce85db60de51d15f05f908f5960594f106726..ba3259086b9db602cc189845491ab448febf9ee3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * GPR board platform device registration
+ * GPR board platform device registration (Au1550)
  *
  * Copyright (C) 2010 Wolfgang Grandegger <wg@denx.de>
  *
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/leds.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
-
+#include <asm/bootinfo.h>
+#include <asm/reboot.h>
 #include <asm/mach-au1x00/au1000.h>
+#include <prom.h>
+
+const char *get_system_type(void)
+{
+       return "GPR";
+}
+
+void __init prom_init(void)
+{
+       unsigned char *memsize_str;
+       unsigned long memsize;
+
+       prom_argc = fw_arg0;
+       prom_argv = (char **)fw_arg1;
+       prom_envp = (char **)fw_arg2;
+
+       prom_init_cmdline();
+
+       memsize_str = prom_getenv("memsize");
+       if (!memsize_str)
+               memsize = 0x04000000;
+       else
+               strict_strtoul(memsize_str, 0, &memsize);
+       add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
+void prom_putchar(unsigned char c)
+{
+       alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
+}
+
+static void gpr_reset(char *c)
+{
+       /* switch System-LED to orange (red# and green# on) */
+       alchemy_gpio_direction_output(4, 0);
+       alchemy_gpio_direction_output(5, 0);
+
+       /* trigger watchdog to reset board in 200ms */
+       printk(KERN_EMERG "Triggering watchdog soft reset...\n");
+       raw_local_irq_disable();
+       alchemy_gpio_direction_output(1, 0);
+       udelay(1);
+       alchemy_gpio_set_value(1, 1);
+       while (1)
+               cpu_wait();
+}
+
+static void gpr_power_off(void)
+{
+       while (1)
+               cpu_wait();
+}
+
+void __init board_setup(void)
+{
+       printk(KERN_INFO "Trapeze ITS GPR board\n");
+
+       pm_power_off = gpr_power_off;
+       _machine_halt = gpr_power_off;
+       _machine_restart = gpr_reset;
+
+       /* Enable UART1/3 */
+       alchemy_uart_enable(AU1000_UART3_PHYS_ADDR);
+       alchemy_uart_enable(AU1000_UART1_PHYS_ADDR);
+
+       /* Take away Reset of UMTS-card */
+       alchemy_gpio_direction_output(215, 1);
+}
 
 /*
  * Watchdog
@@ -152,7 +225,7 @@ static struct i2c_gpio_platform_data gpr_i2c_data = {
        .scl_is_open_drain      = 1,
        .udelay                 = 2,            /* ~100 kHz */
        .timeout                = HZ,
- };
+};
 
 static struct platform_device gpr_i2c_device = {
        .name                   = "i2c-gpio",
@@ -184,7 +257,7 @@ static int gpr_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
        else if ((slot == 0) && (pin == 2))
                return AU1550_PCI_INTB;
 
-       return -1;
+       return 0xff;
 }
 
 static struct alchemy_pci_platdata gpr_pci_pd = {
similarity index 71%
rename from arch/mips/alchemy/mtx-1/platform.c
rename to arch/mips/alchemy/board-mtx1.c
index cc47b6868ca3f845fb851f2885862024ba96e86d..295f1a95f7451e2bdaa7f5e8171c5dd06622fcaf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * MTX-1 platform devices registration
+ * MTX-1 platform devices registration (Au1500)
  *
  * Copyright (C) 2007-2009, Florian Fainelli <florian@openwrt.org>
  *
@@ -19,6 +19,8 @@
  */
 
 #include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <linux/gpio.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <mtd/mtd-abi.h>
-
+#include <asm/bootinfo.h>
+#include <asm/reboot.h>
+#include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1xxx_eth.h>
+#include <prom.h>
+
+const char *get_system_type(void)
+{
+       return "MTX-1";
+}
+
+void __init prom_init(void)
+{
+       unsigned char *memsize_str;
+       unsigned long memsize;
+
+       prom_argc = fw_arg0;
+       prom_argv = (char **)fw_arg1;
+       prom_envp = (char **)fw_arg2;
+
+       prom_init_cmdline();
+
+       memsize_str = prom_getenv("memsize");
+       if (!memsize_str)
+               memsize = 0x04000000;
+       else
+               strict_strtoul(memsize_str, 0, &memsize);
+       add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
+void prom_putchar(unsigned char c)
+{
+       alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
+}
+
+static void mtx1_reset(char *c)
+{
+       /* Jump to the reset vector */
+       __asm__ __volatile__("jr\t%0" : : "r"(0xbfc00000));
+}
+
+static void mtx1_power_off(void)
+{
+       while (1)
+               asm volatile (
+               "       .set    mips32                                  \n"
+               "       wait                                            \n"
+               "       .set    mips0                                   \n");
+}
+
+void __init board_setup(void)
+{
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+       /* Enable USB power switch */
+       alchemy_gpio_direction_output(204, 0);
+#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */
+
+       /* Initialize sys_pinfunc */
+       au_writel(SYS_PF_NI2, SYS_PINFUNC);
+
+       /* Initialize GPIO */
+       au_writel(~0, KSEG1ADDR(AU1000_SYS_PHYS_ADDR) + SYS_TRIOUTCLR);
+       alchemy_gpio_direction_output(0, 0);    /* Disable M66EN (PCI 66MHz) */
+       alchemy_gpio_direction_output(3, 1);    /* Disable PCI CLKRUN# */
+       alchemy_gpio_direction_output(1, 1);    /* Enable EXT_IO3 */
+       alchemy_gpio_direction_output(5, 0);    /* Disable eth PHY TX_ER */
+
+       /* Enable LED and set it to green */
+       alchemy_gpio_direction_output(211, 1);  /* green on */
+       alchemy_gpio_direction_output(212, 0);  /* red off */
+
+       pm_power_off = mtx1_power_off;
+       _machine_halt = mtx1_power_off;
+       _machine_restart = mtx1_reset;
+
+       printk(KERN_INFO "4G Systems MTX-1 Board\n");
+}
+
+/******************************************************************************/
 
 static struct gpio_keys_button mtx1_gpio_button[] = {
        {
@@ -195,7 +274,6 @@ static struct platform_device mtx1_pci_host = {
        .resource       = alchemy_pci_host_res,
 };
 
-
 static struct __initdata platform_device * mtx1_devs[] = {
        &mtx1_pci_host,
        &mtx1_gpio_leds,
@@ -206,13 +284,19 @@ static struct __initdata platform_device * mtx1_devs[] = {
 
 static struct au1000_eth_platform_data mtx1_au1000_eth0_pdata = {
        .phy_search_highest_addr        = 1,
-       .phy1_search_mac0               = 1,
+       .phy1_search_mac0               = 1,
 };
 
 static int __init mtx1_register_devices(void)
 {
        int rc;
 
+       irq_set_irq_type(AU1500_GPIO204_INT, IRQ_TYPE_LEVEL_HIGH);
+       irq_set_irq_type(AU1500_GPIO201_INT, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(AU1500_GPIO202_INT, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(AU1500_GPIO203_INT, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(AU1500_GPIO205_INT, IRQ_TYPE_LEVEL_LOW);
+
        au1xxx_override_eth_cfg(0, &mtx1_au1000_eth0_pdata);
 
        rc = gpio_request(mtx1_gpio_button[0].gpio,
@@ -226,5 +310,4 @@ static int __init mtx1_register_devices(void)
 out:
        return platform_add_devices(mtx1_devs, ARRAY_SIZE(mtx1_devs));
 }
-
 arch_initcall(mtx1_register_devices);
diff --git a/arch/mips/alchemy/board-xxs1500.c b/arch/mips/alchemy/board-xxs1500.c
new file mode 100644 (file)
index 0000000..bd55136
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *     MyCable XXS1500 board support
+ *
+ * Copyright 2003, 2008 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc. <source@mvista.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <asm/bootinfo.h>
+#include <asm/reboot.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <prom.h>
+
+const char *get_system_type(void)
+{
+       return "XXS1500";
+}
+
+void __init prom_init(void)
+{
+       unsigned char *memsize_str;
+       unsigned long memsize;
+
+       prom_argc = fw_arg0;
+       prom_argv = (char **)fw_arg1;
+       prom_envp = (char **)fw_arg2;
+
+       prom_init_cmdline();
+
+       memsize_str = prom_getenv("memsize");
+       if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize))
+               memsize = 0x04000000;
+
+       add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
+void prom_putchar(unsigned char c)
+{
+       alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
+}
+
+static void xxs1500_reset(char *c)
+{
+       /* Jump to the reset vector */
+       __asm__ __volatile__("jr\t%0" : : "r"(0xbfc00000));
+}
+
+static void xxs1500_power_off(void)
+{
+       while (1)
+               asm volatile (
+               "       .set    mips32                                  \n"
+               "       wait                                            \n"
+               "       .set    mips0                                   \n");
+}
+
+void __init board_setup(void)
+{
+       u32 pin_func;
+
+       pm_power_off = xxs1500_power_off;
+       _machine_halt = xxs1500_power_off;
+       _machine_restart = xxs1500_reset;
+
+       alchemy_gpio1_input_enable();
+       alchemy_gpio2_enable();
+
+       /* Set multiple use pins (UART3/GPIO) to UART (it's used as UART too) */
+       pin_func  = au_readl(SYS_PINFUNC) & ~SYS_PF_UR3;
+       pin_func |= SYS_PF_UR3;
+       au_writel(pin_func, SYS_PINFUNC);
+
+       /* Enable UART */
+       alchemy_uart_enable(AU1000_UART3_PHYS_ADDR);
+       /* Enable DTR (MCR bit 0) = USB power up */
+       __raw_writel(1, (void __iomem *)KSEG1ADDR(AU1000_UART3_PHYS_ADDR + 0x18));
+       wmb();
+}
+
+/******************************************************************************/
+
+static struct resource xxs1500_pcmcia_res[] = {
+       {
+               .name   = "pcmcia-io",
+               .flags  = IORESOURCE_MEM,
+               .start  = AU1000_PCMCIA_IO_PHYS_ADDR,
+               .end    = AU1000_PCMCIA_IO_PHYS_ADDR + 0x000400000 - 1,
+       },
+       {
+               .name   = "pcmcia-attr",
+               .flags  = IORESOURCE_MEM,
+               .start  = AU1000_PCMCIA_ATTR_PHYS_ADDR,
+               .end    = AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
+       },
+       {
+               .name   = "pcmcia-mem",
+               .flags  = IORESOURCE_MEM,
+               .start  = AU1000_PCMCIA_MEM_PHYS_ADDR,
+               .end    = AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
+       },
+};
+
+static struct platform_device xxs1500_pcmcia_dev = {
+       .name           = "xxs1500_pcmcia",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(xxs1500_pcmcia_res),
+       .resource       = xxs1500_pcmcia_res,
+};
+
+static struct platform_device *xxs1500_devs[] __initdata = {
+       &xxs1500_pcmcia_dev,
+};
+
+static int __init xxs1500_dev_init(void)
+{
+       irq_set_irq_type(AU1500_GPIO204_INT, IRQ_TYPE_LEVEL_HIGH);
+       irq_set_irq_type(AU1500_GPIO201_INT, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(AU1500_GPIO202_INT, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(AU1500_GPIO203_INT, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(AU1500_GPIO205_INT, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(AU1500_GPIO207_INT, IRQ_TYPE_LEVEL_LOW);
+
+       irq_set_irq_type(AU1500_GPIO0_INT, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(AU1500_GPIO1_INT, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(AU1500_GPIO2_INT, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(AU1500_GPIO3_INT, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(AU1500_GPIO4_INT, IRQ_TYPE_LEVEL_LOW); /* CF irq */
+       irq_set_irq_type(AU1500_GPIO5_INT, IRQ_TYPE_LEVEL_LOW);
+
+       return platform_add_devices(xxs1500_devs,
+                                   ARRAY_SIZE(xxs1500_devs));
+}
+device_initcall(xxs1500_dev_init);
index 811ece7b22e304fd9d04a8f38c1c6a241267b058..407ebc00e661f974bbaec96a345afcea8f6b6409 100644 (file)
@@ -6,9 +6,7 @@
 #
 
 obj-y += prom.o time.o clocks.o platform.o power.o setup.o \
-       sleeper.o dma.o dbdma.o
-
-obj-$(CONFIG_ALCHEMY_GPIOINT_AU1000) += irq.o
+       sleeper.o dma.o dbdma.o vss.o irq.o
 
 # optional gpiolib support
 ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),)
index 0e63ee487d6d1315b6f06c069631cb383c932eb7..cf02d7dc2df0abbc24cd14f6a6de6ebb1800e03c 100644 (file)
@@ -148,6 +148,50 @@ static dbdev_tab_t au1200_dbdev_tab[] __initdata = {
        { DSCR_CMD0_ALWAYS,   DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
 };
 
+static dbdev_tab_t au1300_dbdev_tab[] __initdata = {
+       { AU1300_DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8,  0x10100004, 0, 0 },
+       { AU1300_DSCR_CMD0_UART0_RX, DEV_FLAGS_IN,  0, 8,  0x10100000, 0, 0 },
+       { AU1300_DSCR_CMD0_UART1_TX, DEV_FLAGS_OUT, 0, 8,  0x10101004, 0, 0 },
+       { AU1300_DSCR_CMD0_UART1_RX, DEV_FLAGS_IN,  0, 8,  0x10101000, 0, 0 },
+       { AU1300_DSCR_CMD0_UART2_TX, DEV_FLAGS_OUT, 0, 8,  0x10102004, 0, 0 },
+       { AU1300_DSCR_CMD0_UART2_RX, DEV_FLAGS_IN,  0, 8,  0x10102000, 0, 0 },
+       { AU1300_DSCR_CMD0_UART3_TX, DEV_FLAGS_OUT, 0, 8,  0x10103004, 0, 0 },
+       { AU1300_DSCR_CMD0_UART3_RX, DEV_FLAGS_IN,  0, 8,  0x10103000, 0, 0 },
+
+       { AU1300_DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8,  0x10600000, 0, 0 },
+       { AU1300_DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN,  4, 8,  0x10600004, 0, 0 },
+       { AU1300_DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 8, 8,  0x10601000, 0, 0 },
+       { AU1300_DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN,  8, 8,  0x10601004, 0, 0 },
+
+       { AU1300_DSCR_CMD0_AES_RX, DEV_FLAGS_IN ,   4, 32, 0x10300008, 0, 0 },
+       { AU1300_DSCR_CMD0_AES_TX, DEV_FLAGS_OUT,   4, 32, 0x10300004, 0, 0 },
+
+       { AU1300_DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0001c, 0, 0 },
+       { AU1300_DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN,   0, 16, 0x10a0001c, 0, 0 },
+       { AU1300_DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0101c, 0, 0 },
+       { AU1300_DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN,   0, 16, 0x10a0101c, 0, 0 },
+       { AU1300_DSCR_CMD0_PSC2_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0201c, 0, 0 },
+       { AU1300_DSCR_CMD0_PSC2_RX, DEV_FLAGS_IN,   0, 16, 0x10a0201c, 0, 0 },
+       { AU1300_DSCR_CMD0_PSC3_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0301c, 0, 0 },
+       { AU1300_DSCR_CMD0_PSC3_RX, DEV_FLAGS_IN,   0, 16, 0x10a0301c, 0, 0 },
+
+       { AU1300_DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE,   0, 0,  0x00000000, 0, 0 },
+       { AU1300_DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+
+       { AU1300_DSCR_CMD0_SDMS_TX2, DEV_FLAGS_OUT, 4, 8,  0x10602000, 0, 0 },
+       { AU1300_DSCR_CMD0_SDMS_RX2, DEV_FLAGS_IN,  4, 8,  0x10602004, 0, 0 },
+
+       { AU1300_DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+
+       { AU1300_DSCR_CMD0_UDMA, DEV_FLAGS_ANYUSE,  0, 32, 0x14001810, 0, 0 },
+
+       { AU1300_DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 },
+       { AU1300_DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 },
+
+       { DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+       { DSCR_CMD0_ALWAYS,   DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+};
+
 /* 32 predefined plus 32 custom */
 #define DBDEV_TAB_SIZE         64
 
@@ -1019,8 +1063,7 @@ static int __init dbdma_setup(unsigned int irq, dbdev_tab_t *idtable)
        dbdma_gptr->ddma_inten = 0xffff;
        au_sync();
 
-       ret = request_irq(irq, dbdma_interrupt, IRQF_DISABLED, "dbdma",
-                         (void *)dbdma_gptr);
+       ret = request_irq(irq, dbdma_interrupt, 0, "dbdma", (void *)dbdma_gptr);
        if (ret)
                printk(KERN_ERR "Cannot grab DBDMA interrupt!\n");
        else {
@@ -1038,6 +1081,8 @@ static int __init alchemy_dbdma_init(void)
                return dbdma_setup(AU1550_DDMA_INT, au1550_dbdev_tab);
        case ALCHEMY_CPU_AU1200:
                return dbdma_setup(AU1200_DDMA_INT, au1200_dbdev_tab);
+       case ALCHEMY_CPU_AU1300:
+               return dbdma_setup(AU1300_DDMA_INT, au1300_dbdev_tab);
        }
        return 0;
 }
index 91fb4d9e30fd819e382368f22af586271bb23a5c..f1b50f0c01db470ce008f74c1855532ded04c4be 100644 (file)
@@ -27,6 +27,7 @@
  *      CONFIG_ALCHEMY_GPIO_INDIRECT=n, otherwise compilation will fail!
  *     au1000 SoC have only one GPIO block : GPIO1
  *     Au1100, Au15x0, Au12x0 have a second one : GPIO2
+ *     Au1300 is totally different: 1 block with up to 128 GPIOs
  */
 
 #include <linux/init.h>
@@ -35,6 +36,7 @@
 #include <linux/types.h>
 #include <linux/gpio.h>
 #include <asm/mach-au1x00/gpio-au1000.h>
+#include <asm/mach-au1x00/gpio-au1300.h>
 
 static int gpio2_get(struct gpio_chip *chip, unsigned offset)
 {
@@ -115,6 +117,43 @@ struct gpio_chip alchemy_gpio_chip[] = {
        },
 };
 
+static int alchemy_gpic_get(struct gpio_chip *chip, unsigned int off)
+{
+       return au1300_gpio_get_value(off + AU1300_GPIO_BASE);
+}
+
+static void alchemy_gpic_set(struct gpio_chip *chip, unsigned int off, int v)
+{
+       au1300_gpio_set_value(off + AU1300_GPIO_BASE, v);
+}
+
+static int alchemy_gpic_dir_input(struct gpio_chip *chip, unsigned int off)
+{
+       return au1300_gpio_direction_input(off + AU1300_GPIO_BASE);
+}
+
+static int alchemy_gpic_dir_output(struct gpio_chip *chip, unsigned int off,
+                                  int v)
+{
+       return au1300_gpio_direction_output(off + AU1300_GPIO_BASE, v);
+}
+
+static int alchemy_gpic_gpio_to_irq(struct gpio_chip *chip, unsigned int off)
+{
+       return au1300_gpio_to_irq(off + AU1300_GPIO_BASE);
+}
+
+static struct gpio_chip au1300_gpiochip = {
+       .label                  = "alchemy-gpic",
+       .direction_input        = alchemy_gpic_dir_input,
+       .direction_output       = alchemy_gpic_dir_output,
+       .get                    = alchemy_gpic_get,
+       .set                    = alchemy_gpic_set,
+       .to_irq                 = alchemy_gpic_gpio_to_irq,
+       .base                   = AU1300_GPIO_BASE,
+       .ngpio                  = AU1300_GPIO_NUM,
+};
+
 static int __init alchemy_gpiochip_init(void)
 {
        int ret = 0;
@@ -127,6 +166,9 @@ static int __init alchemy_gpiochip_init(void)
                ret = gpiochip_add(&alchemy_gpio_chip[0]);
                ret |= gpiochip_add(&alchemy_gpio_chip[1]);
                break;
+       case ALCHEMY_CPU_AU1300:
+               ret = gpiochip_add(&au1300_gpiochip);
+               break;
        }
        return ret;
 }
index 8b60ba0675e2f0f47c78b0908c53f93565f68fbb..94fbcd19eb9ca9631425a6cf20c055c3807e72ac 100644 (file)
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/bitops.h>
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/irq.h>
 #include <linux/slab.h>
 #include <linux/syscore_ops.h>
 
 #include <asm/irq_cpu.h>
-#include <asm/mipsregs.h>
 #include <asm/mach-au1x00/au1000.h>
-#ifdef CONFIG_MIPS_PB1000
-#include <asm/mach-pb1x00/pb1000.h>
-#endif
+#include <asm/mach-au1x00/gpio-au1300.h>
 
 /* Interrupt Controller register offsets */
 #define IC_CFG0RD      0x40
 #define IC_FALLINGCLR  0x7C
 #define IC_TESTBIT     0x80
 
-static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type);
+/* per-processor fixed function irqs */
+struct alchemy_irqmap {
+       int irq;        /* linux IRQ number */
+       int type;       /* IRQ_TYPE_ */
+       int prio;       /* irq priority, 0 highest, 3 lowest */
+       int internal;   /* GPIC: internal source (no ext. pin)? */
+};
+
+static int au1x_ic_settype(struct irq_data *d, unsigned int type);
+static int au1300_gpic_settype(struct irq_data *d, unsigned int type);
+
 
 /* NOTE on interrupt priorities: The original writers of this code said:
  *
@@ -77,176 +83,207 @@ static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type);
  * the USB devices-side packet complete interrupt (USB_DEV_REQ_INT)
  * needs the highest priority.
  */
-
-/* per-processor fixed function irqs */
-struct au1xxx_irqmap {
-       int im_irq;
-       int im_type;
-       int im_request;         /* set 1 to get higher priority */
+struct alchemy_irqmap au1000_irqmap[] __initdata = {
+       { AU1000_UART0_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_UART1_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_UART2_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_UART3_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_SSI0_INT,        IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_SSI1_INT,        IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_DMA_INT_BASE,    IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_TOY_INT,         IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1000_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1000_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1000_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1000_RTC_INT,         IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1000_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1000_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1000_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0, 0 },
+       { AU1000_IRDA_TX_INT,     IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_IRDA_RX_INT,     IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  0, 0 },
+       { AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1000_USB_HOST_INT,    IRQ_TYPE_LEVEL_LOW,   1, 0 },
+       { AU1000_ACSYNC_INT,      IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1000_MAC0_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_MAC1_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1000_AC97C_INT,       IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { -1, },
 };
 
-struct au1xxx_irqmap au1000_irqmap[] __initdata = {
-       { AU1000_UART0_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_UART1_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_UART2_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_UART3_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_SSI0_INT,        IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_SSI1_INT,        IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_DMA_INT_BASE,    IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_TOY_INT,         IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1000_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1000_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1000_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1000_RTC_INT,         IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1000_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1000_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1000_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 },
-       { AU1000_IRDA_TX_INT,     IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_IRDA_RX_INT,     IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  1 },
-       { AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1000_USB_HOST_INT,    IRQ_TYPE_LEVEL_LOW,   0 },
-       { AU1000_ACSYNC_INT,      IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1000_MAC0_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_MAC1_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1000_AC97C_INT,       IRQ_TYPE_EDGE_RISING, 0 },
+struct alchemy_irqmap au1500_irqmap[] __initdata = {
+       { AU1500_UART0_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1500_PCI_INTA,        IRQ_TYPE_LEVEL_LOW,   1, 0 },
+       { AU1500_PCI_INTB,        IRQ_TYPE_LEVEL_LOW,   1, 0 },
+       { AU1500_UART3_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1500_PCI_INTC,        IRQ_TYPE_LEVEL_LOW,   1, 0 },
+       { AU1500_PCI_INTD,        IRQ_TYPE_LEVEL_LOW,   1, 0 },
+       { AU1500_DMA_INT_BASE,    IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1500_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1500_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1500_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1500_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1500_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1500_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1500_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1500_TOY_INT,         IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1500_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1500_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1500_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1500_RTC_INT,         IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1500_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1500_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1500_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0, 0 },
+       { AU1500_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  0, 0 },
+       { AU1500_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1500_USB_HOST_INT,    IRQ_TYPE_LEVEL_LOW,   1, 0 },
+       { AU1500_ACSYNC_INT,      IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1500_MAC0_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1500_MAC1_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1500_AC97C_INT,       IRQ_TYPE_EDGE_RISING, 1, 0 },
        { -1, },
 };
 
-struct au1xxx_irqmap au1500_irqmap[] __initdata = {
-       { AU1500_UART0_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1500_PCI_INTA,        IRQ_TYPE_LEVEL_LOW,   0 },
-       { AU1500_PCI_INTB,        IRQ_TYPE_LEVEL_LOW,   0 },
-       { AU1500_UART3_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1500_PCI_INTC,        IRQ_TYPE_LEVEL_LOW,   0 },
-       { AU1500_PCI_INTD,        IRQ_TYPE_LEVEL_LOW,   0 },
-       { AU1500_DMA_INT_BASE,    IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1500_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1500_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1500_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1500_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1500_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1500_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1500_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1500_TOY_INT,         IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1500_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1500_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1500_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1500_RTC_INT,         IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1500_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1500_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1500_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 },
-       { AU1500_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  1 },
-       { AU1500_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1500_USB_HOST_INT,    IRQ_TYPE_LEVEL_LOW,   0 },
-       { AU1500_ACSYNC_INT,      IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1500_MAC0_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1500_MAC1_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1500_AC97C_INT,       IRQ_TYPE_EDGE_RISING, 0 },
+struct alchemy_irqmap au1100_irqmap[] __initdata = {
+       { AU1100_UART0_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_UART1_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_SD_INT,          IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_UART3_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_SSI0_INT,        IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_SSI1_INT,        IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_DMA_INT_BASE,    IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_TOY_INT,         IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1100_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1100_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1100_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1100_RTC_INT,         IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1100_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1100_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1100_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0, 0 },
+       { AU1100_IRDA_TX_INT,     IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_IRDA_RX_INT,     IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  0, 0 },
+       { AU1100_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1100_USB_HOST_INT,    IRQ_TYPE_LEVEL_LOW,   1, 0 },
+       { AU1100_ACSYNC_INT,      IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1100_MAC0_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_LCD_INT,         IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1100_AC97C_INT,       IRQ_TYPE_EDGE_RISING, 1, 0 },
        { -1, },
 };
 
-struct au1xxx_irqmap au1100_irqmap[] __initdata = {
-       { AU1100_UART0_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_UART1_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_SD_INT,          IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_UART3_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_SSI0_INT,        IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_SSI1_INT,        IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_DMA_INT_BASE,    IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_TOY_INT,         IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1100_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1100_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1100_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1100_RTC_INT,         IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1100_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1100_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1100_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 },
-       { AU1100_IRDA_TX_INT,     IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_IRDA_RX_INT,     IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  1 },
-       { AU1100_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1100_USB_HOST_INT,    IRQ_TYPE_LEVEL_LOW,   0 },
-       { AU1100_ACSYNC_INT,      IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1100_MAC0_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_LCD_INT,         IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1100_AC97C_INT,       IRQ_TYPE_EDGE_RISING, 0 },
+struct alchemy_irqmap au1550_irqmap[] __initdata = {
+       { AU1550_UART0_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1550_PCI_INTA,        IRQ_TYPE_LEVEL_LOW,   1, 0 },
+       { AU1550_PCI_INTB,        IRQ_TYPE_LEVEL_LOW,   1, 0 },
+       { AU1550_DDMA_INT,        IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1550_CRYPTO_INT,      IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1550_PCI_INTC,        IRQ_TYPE_LEVEL_LOW,   1, 0 },
+       { AU1550_PCI_INTD,        IRQ_TYPE_LEVEL_LOW,   1, 0 },
+       { AU1550_PCI_RST_INT,     IRQ_TYPE_LEVEL_LOW,   1, 0 },
+       { AU1550_UART1_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1550_UART3_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1550_PSC0_INT,        IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1550_PSC1_INT,        IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1550_PSC2_INT,        IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1550_PSC3_INT,        IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1550_TOY_INT,         IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1550_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1550_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1550_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1550_RTC_INT,         IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1550_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1550_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1550_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0, 0 },
+       { AU1550_NAND_INT,        IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  0, 0 },
+       { AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1550_USB_HOST_INT,    IRQ_TYPE_LEVEL_LOW,   1, 0 },
+       { AU1550_MAC0_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1550_MAC1_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  1, 0 },
        { -1, },
 };
 
-struct au1xxx_irqmap au1550_irqmap[] __initdata = {
-       { AU1550_UART0_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1550_PCI_INTA,        IRQ_TYPE_LEVEL_LOW,   0 },
-       { AU1550_PCI_INTB,        IRQ_TYPE_LEVEL_LOW,   0 },
-       { AU1550_DDMA_INT,        IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1550_CRYPTO_INT,      IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1550_PCI_INTC,        IRQ_TYPE_LEVEL_LOW,   0 },
-       { AU1550_PCI_INTD,        IRQ_TYPE_LEVEL_LOW,   0 },
-       { AU1550_PCI_RST_INT,     IRQ_TYPE_LEVEL_LOW,   0 },
-       { AU1550_UART1_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1550_UART3_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1550_PSC0_INT,        IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1550_PSC1_INT,        IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1550_PSC2_INT,        IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1550_PSC3_INT,        IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1550_TOY_INT,         IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1550_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1550_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1550_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1550_RTC_INT,         IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1550_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1550_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1550_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 },
-       { AU1550_NAND_INT,        IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  1 },
-       { AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1550_USB_HOST_INT,    IRQ_TYPE_LEVEL_LOW,   0 },
-       { AU1550_MAC0_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1550_MAC1_DMA_INT,    IRQ_TYPE_LEVEL_HIGH,  0 },
+struct alchemy_irqmap au1200_irqmap[] __initdata = {
+       { AU1200_UART0_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1200_SWT_INT,         IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1200_SD_INT,          IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1200_DDMA_INT,        IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1200_MAE_BE_INT,      IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1200_UART1_INT,       IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1200_MAE_FE_INT,      IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1200_PSC0_INT,        IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1200_PSC1_INT,        IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1200_AES_INT,         IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1200_CAMERA_INT,      IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1200_TOY_INT,         IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1200_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1200_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1200_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1200_RTC_INT,         IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1200_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1200_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1200_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0, 0 },
+       { AU1200_NAND_INT,        IRQ_TYPE_EDGE_RISING, 1, 0 },
+       { AU1200_USB_INT,         IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1200_LCD_INT,         IRQ_TYPE_LEVEL_HIGH,  1, 0 },
+       { AU1200_MAE_BOTH_INT,    IRQ_TYPE_LEVEL_HIGH,  1, 0 },
        { -1, },
 };
 
-struct au1xxx_irqmap au1200_irqmap[] __initdata = {
-       { AU1200_UART0_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1200_SWT_INT,         IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1200_SD_INT,          IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1200_DDMA_INT,        IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1200_MAE_BE_INT,      IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1200_UART1_INT,       IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1200_MAE_FE_INT,      IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1200_PSC0_INT,        IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1200_PSC1_INT,        IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1200_AES_INT,         IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1200_CAMERA_INT,      IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1200_TOY_INT,         IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1200_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1200_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1200_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1200_RTC_INT,         IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1200_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1200_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1200_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 },
-       { AU1200_NAND_INT,        IRQ_TYPE_EDGE_RISING, 0 },
-       { AU1200_USB_INT,         IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1200_LCD_INT,         IRQ_TYPE_LEVEL_HIGH,  0 },
-       { AU1200_MAE_BOTH_INT,    IRQ_TYPE_LEVEL_HIGH,  0 },
-       { -1, },
+static struct alchemy_irqmap au1300_irqmap[] __initdata = {
+       /* multifunction: gpio pin or device */
+       { AU1300_UART1_INT,      IRQ_TYPE_LEVEL_HIGH,   1, 0, },
+       { AU1300_UART2_INT,      IRQ_TYPE_LEVEL_HIGH,   1, 0, },
+       { AU1300_UART3_INT,      IRQ_TYPE_LEVEL_HIGH,   1, 0, },
+       { AU1300_SD1_INT,        IRQ_TYPE_LEVEL_HIGH,   1, 0, },
+       { AU1300_SD2_INT,        IRQ_TYPE_LEVEL_HIGH,   1, 0, },
+       { AU1300_PSC0_INT,       IRQ_TYPE_LEVEL_HIGH,   1, 0, },
+       { AU1300_PSC1_INT,       IRQ_TYPE_LEVEL_HIGH,   1, 0, },
+       { AU1300_PSC2_INT,       IRQ_TYPE_LEVEL_HIGH,   1, 0, },
+       { AU1300_PSC3_INT,       IRQ_TYPE_LEVEL_HIGH,   1, 0, },
+       { AU1300_NAND_INT,       IRQ_TYPE_LEVEL_HIGH,   1, 0, },
+       /* au1300 internal */
+       { AU1300_DDMA_INT,       IRQ_TYPE_LEVEL_HIGH,   1, 1, },
+       { AU1300_MMU_INT,        IRQ_TYPE_LEVEL_HIGH,   1, 1, },
+       { AU1300_MPU_INT,        IRQ_TYPE_LEVEL_HIGH,   1, 1, },
+       { AU1300_GPU_INT,        IRQ_TYPE_LEVEL_HIGH,   1, 1, },
+       { AU1300_UDMA_INT,       IRQ_TYPE_LEVEL_HIGH,   1, 1, },
+       { AU1300_TOY_INT,        IRQ_TYPE_EDGE_RISING,  1, 1, },
+       { AU1300_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING,  1, 1, },
+       { AU1300_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING,  1, 1, },
+       { AU1300_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING,  1, 1, },
+       { AU1300_RTC_INT,        IRQ_TYPE_EDGE_RISING,  1, 1, },
+       { AU1300_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING,  1, 1, },
+       { AU1300_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING,  1, 1, },
+       { AU1300_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING,  0, 1, },
+       { AU1300_UART0_INT,      IRQ_TYPE_LEVEL_HIGH,   1, 1, },
+       { AU1300_SD0_INT,        IRQ_TYPE_LEVEL_HIGH,   1, 1, },
+       { AU1300_USB_INT,        IRQ_TYPE_LEVEL_HIGH,   1, 1, },
+       { AU1300_LCD_INT,        IRQ_TYPE_LEVEL_HIGH,   1, 1, },
+       { AU1300_BSA_INT,        IRQ_TYPE_LEVEL_HIGH,   1, 1, },
+       { AU1300_MPE_INT,        IRQ_TYPE_EDGE_RISING,  1, 1, },
+       { AU1300_ITE_INT,        IRQ_TYPE_LEVEL_HIGH,   1, 1, },
+       { AU1300_AES_INT,        IRQ_TYPE_LEVEL_HIGH,   1, 1, },
+       { AU1300_CIM_INT,        IRQ_TYPE_LEVEL_HIGH,   1, 1, },
+       { -1, },        /* terminator */
 };
 
+/******************************************************************************/
 
 static void au1x_ic0_unmask(struct irq_data *d)
 {
@@ -265,14 +302,6 @@ static void au1x_ic1_unmask(struct irq_data *d)
 
        __raw_writel(1 << bit, base + IC_MASKSET);
        __raw_writel(1 << bit, base + IC_WAKESET);
-
-/* very hacky. does the pb1000 cpld auto-disable this int?
- * nowhere in the current kernel sources is it disabled.       --mlau
- */
-#if defined(CONFIG_MIPS_PB1000)
-       if (d->irq == AU1000_GPIO15_INT)
-               __raw_writel(0x4000, (void __iomem *)PB1000_MDR); /* enable int */
-#endif
        wmb();
 }
 
@@ -470,40 +499,219 @@ static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type)
        return ret;
 }
 
-asmlinkage void plat_irq_dispatch(void)
+/******************************************************************************/
+
+/*
+ * au1300_gpic_chgcfg - change PIN configuration.
+ * @gpio:      pin to change (0-based GPIO number from datasheet).
+ * @clr:       clear all bits set in 'clr'.
+ * @set:       set these bits.
+ *
+ * modifies a pins' configuration register, bits set in @clr will
+ * be cleared in the register, bits in @set will be set.
+ */
+static inline void au1300_gpic_chgcfg(unsigned int gpio,
+                                     unsigned long clr,
+                                     unsigned long set)
+{
+       void __iomem *r = AU1300_GPIC_ADDR;
+       unsigned long l;
+
+       r += gpio * 4;  /* offset into pin config array */
+       l = __raw_readl(r + AU1300_GPIC_PINCFG);
+       l &= ~clr;
+       l |= set;
+       __raw_writel(l, r + AU1300_GPIC_PINCFG);
+       wmb();
+}
+
+/*
+ * au1300_pinfunc_to_gpio - assign a pin as GPIO input (GPIO ctrl).
+ * @pin:       pin (0-based GPIO number from datasheet).
+ *
+ * Assigns a GPIO pin to the GPIO controller, so its level can either
+ * be read or set through the generic GPIO functions.
+ * If you need a GPOUT, use au1300_gpio_set_value(pin, 0/1).
+ * REVISIT: is this function really necessary?
+ */
+void au1300_pinfunc_to_gpio(enum au1300_multifunc_pins gpio)
+{
+       au1300_gpio_direction_input(gpio + AU1300_GPIO_BASE);
+}
+EXPORT_SYMBOL_GPL(au1300_pinfunc_to_gpio);
+
+/*
+ * au1300_pinfunc_to_dev - assign a pin to the device function.
+ * @pin:       pin (0-based GPIO number from datasheet).
+ *
+ * Assigns a GPIO pin to its associated device function; the pin will be
+ * driven by the device and not through GPIO functions.
+ */
+void au1300_pinfunc_to_dev(enum au1300_multifunc_pins gpio)
+{
+       void __iomem *r = AU1300_GPIC_ADDR;
+       unsigned long bit;
+
+       r += GPIC_GPIO_BANKOFF(gpio);
+       bit = GPIC_GPIO_TO_BIT(gpio);
+       __raw_writel(bit, r + AU1300_GPIC_DEVSEL);
+       wmb();
+}
+EXPORT_SYMBOL_GPL(au1300_pinfunc_to_dev);
+
+/*
+ * au1300_set_irq_priority -  set internal priority of IRQ.
+ * @irq:       irq to set priority (linux irq number).
+ * @p:         priority (0 = highest, 3 = lowest).
+ */
+void au1300_set_irq_priority(unsigned int irq, int p)
 {
-       unsigned int pending = read_c0_status() & read_c0_cause();
-       unsigned long s, off;
-
-       if (pending & CAUSEF_IP7) {
-               off = MIPS_CPU_IRQ_BASE + 7;
-               goto handle;
-       } else if (pending & CAUSEF_IP2) {
-               s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ0INT;
-               off = AU1000_INTC0_INT_BASE;
-       } else if (pending & CAUSEF_IP3) {
-               s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ1INT;
-               off = AU1000_INTC0_INT_BASE;
-       } else if (pending & CAUSEF_IP4) {
-               s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ0INT;
-               off = AU1000_INTC1_INT_BASE;
-       } else if (pending & CAUSEF_IP5) {
-               s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ1INT;
-               off = AU1000_INTC1_INT_BASE;
-       } else
-               goto spurious;
-
-       s = __raw_readl((void __iomem *)s);
-       if (unlikely(!s)) {
-spurious:
-               spurious_interrupt();
-               return;
+       irq -= ALCHEMY_GPIC_INT_BASE;
+       au1300_gpic_chgcfg(irq, GPIC_CFG_IL_MASK, GPIC_CFG_IL_SET(p));
+}
+EXPORT_SYMBOL_GPL(au1300_set_irq_priority);
+
+/*
+ * au1300_set_dbdma_gpio - assign a gpio to one of the DBDMA triggers.
+ * @dchan:     dbdma trigger select (0, 1).
+ * @gpio:      pin to assign as trigger.
+ *
+ * DBDMA controller has 2 external trigger sources; this function
+ * assigns a GPIO to the selected trigger.
+ */
+void au1300_set_dbdma_gpio(int dchan, unsigned int gpio)
+{
+       unsigned long r;
+
+       if ((dchan >= 0) && (dchan <= 1)) {
+               r = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL);
+               r &= ~(0xff << (8 * dchan));
+               r |= (gpio & 0x7f) << (8 * dchan);
+               __raw_writel(r, AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL);
+               wmb();
        }
-       off += __ffs(s);
-handle:
-       do_IRQ(off);
 }
 
+static inline void gpic_pin_set_idlewake(unsigned int gpio, int allow)
+{
+       au1300_gpic_chgcfg(gpio, GPIC_CFG_IDLEWAKE,
+                          allow ? GPIC_CFG_IDLEWAKE : 0);
+}
+
+static void au1300_gpic_mask(struct irq_data *d)
+{
+       void __iomem *r = AU1300_GPIC_ADDR;
+       unsigned long bit, irq = d->irq;
+
+       irq -= ALCHEMY_GPIC_INT_BASE;
+       r += GPIC_GPIO_BANKOFF(irq);
+       bit = GPIC_GPIO_TO_BIT(irq);
+       __raw_writel(bit, r + AU1300_GPIC_IDIS);
+       wmb();
+
+       gpic_pin_set_idlewake(irq, 0);
+}
+
+static void au1300_gpic_unmask(struct irq_data *d)
+{
+       void __iomem *r = AU1300_GPIC_ADDR;
+       unsigned long bit, irq = d->irq;
+
+       irq -= ALCHEMY_GPIC_INT_BASE;
+
+       gpic_pin_set_idlewake(irq, 1);
+
+       r += GPIC_GPIO_BANKOFF(irq);
+       bit = GPIC_GPIO_TO_BIT(irq);
+       __raw_writel(bit, r + AU1300_GPIC_IEN);
+       wmb();
+}
+
+static void au1300_gpic_maskack(struct irq_data *d)
+{
+       void __iomem *r = AU1300_GPIC_ADDR;
+       unsigned long bit, irq = d->irq;
+
+       irq -= ALCHEMY_GPIC_INT_BASE;
+       r += GPIC_GPIO_BANKOFF(irq);
+       bit = GPIC_GPIO_TO_BIT(irq);
+       __raw_writel(bit, r + AU1300_GPIC_IPEND);       /* ack */
+       __raw_writel(bit, r + AU1300_GPIC_IDIS);        /* mask */
+       wmb();
+
+       gpic_pin_set_idlewake(irq, 0);
+}
+
+static void au1300_gpic_ack(struct irq_data *d)
+{
+       void __iomem *r = AU1300_GPIC_ADDR;
+       unsigned long bit, irq = d->irq;
+
+       irq -= ALCHEMY_GPIC_INT_BASE;
+       r += GPIC_GPIO_BANKOFF(irq);
+       bit = GPIC_GPIO_TO_BIT(irq);
+       __raw_writel(bit, r + AU1300_GPIC_IPEND);       /* ack */
+       wmb();
+}
+
+static struct irq_chip au1300_gpic = {
+       .name           = "GPIOINT",
+       .irq_ack        = au1300_gpic_ack,
+       .irq_mask       = au1300_gpic_mask,
+       .irq_mask_ack   = au1300_gpic_maskack,
+       .irq_unmask     = au1300_gpic_unmask,
+       .irq_set_type   = au1300_gpic_settype,
+};
+
+static int au1300_gpic_settype(struct irq_data *d, unsigned int type)
+{
+       unsigned long s;
+       unsigned char *name = NULL;
+       irq_flow_handler_t hdl = NULL;
+
+       switch (type) {
+       case IRQ_TYPE_LEVEL_HIGH:
+               s = GPIC_CFG_IC_LEVEL_HIGH;
+               name = "high";
+               hdl = handle_level_irq;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               s = GPIC_CFG_IC_LEVEL_LOW;
+               name = "low";
+               hdl = handle_level_irq;
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               s = GPIC_CFG_IC_EDGE_RISE;
+               name = "posedge";
+               hdl = handle_edge_irq;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               s = GPIC_CFG_IC_EDGE_FALL;
+               name = "negedge";
+               hdl = handle_edge_irq;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               s = GPIC_CFG_IC_EDGE_BOTH;
+               name = "bothedge";
+               hdl = handle_edge_irq;
+               break;
+       case IRQ_TYPE_NONE:
+               s = GPIC_CFG_IC_OFF;
+               name = "disabled";
+               hdl = handle_level_irq;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       __irq_set_chip_handler_name_locked(d->irq, &au1300_gpic, hdl, name);
+
+       au1300_gpic_chgcfg(d->irq - ALCHEMY_GPIC_INT_BASE, GPIC_CFG_IC_MASK, s);
+
+       return 0;
+}
+
+/******************************************************************************/
 
 static inline void ic_init(void __iomem *base)
 {
@@ -521,13 +729,159 @@ static inline void ic_init(void __iomem *base)
        wmb();
 }
 
-static void __init au1000_init_irq(struct au1xxx_irqmap *map)
+static unsigned long alchemy_gpic_pmdata[ALCHEMY_GPIC_INT_NUM + 6];
+
+static inline void alchemy_ic_suspend_one(void __iomem *base, unsigned long *d)
+{
+       d[0] = __raw_readl(base + IC_CFG0RD);
+       d[1] = __raw_readl(base + IC_CFG1RD);
+       d[2] = __raw_readl(base + IC_CFG2RD);
+       d[3] = __raw_readl(base + IC_SRCRD);
+       d[4] = __raw_readl(base + IC_ASSIGNRD);
+       d[5] = __raw_readl(base + IC_WAKERD);
+       d[6] = __raw_readl(base + IC_MASKRD);
+       ic_init(base);          /* shut it up too while at it */
+}
+
+static inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d)
+{
+       ic_init(base);
+
+       __raw_writel(d[0], base + IC_CFG0SET);
+       __raw_writel(d[1], base + IC_CFG1SET);
+       __raw_writel(d[2], base + IC_CFG2SET);
+       __raw_writel(d[3], base + IC_SRCSET);
+       __raw_writel(d[4], base + IC_ASSIGNSET);
+       __raw_writel(d[5], base + IC_WAKESET);
+       wmb();
+
+       __raw_writel(d[6], base + IC_MASKSET);
+       wmb();
+}
+
+static int alchemy_ic_suspend(void)
+{
+       alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR),
+                              alchemy_gpic_pmdata);
+       alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR),
+                              &alchemy_gpic_pmdata[7]);
+       return 0;
+}
+
+static void alchemy_ic_resume(void)
+{
+       alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR),
+                             &alchemy_gpic_pmdata[7]);
+       alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR),
+                             alchemy_gpic_pmdata);
+}
+
+static int alchemy_gpic_suspend(void)
+{
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR);
+       int i;
+
+       /* save 4 interrupt mask status registers */
+       alchemy_gpic_pmdata[0] = __raw_readl(base + AU1300_GPIC_IEN + 0x0);
+       alchemy_gpic_pmdata[1] = __raw_readl(base + AU1300_GPIC_IEN + 0x4);
+       alchemy_gpic_pmdata[2] = __raw_readl(base + AU1300_GPIC_IEN + 0x8);
+       alchemy_gpic_pmdata[3] = __raw_readl(base + AU1300_GPIC_IEN + 0xc);
+
+       /* save misc register(s) */
+       alchemy_gpic_pmdata[4] = __raw_readl(base + AU1300_GPIC_DMASEL);
+
+       /* molto silenzioso */
+       __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0);
+       __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4);
+       __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8);
+       __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc);
+       wmb();
+
+       /* save pin/int-type configuration */
+       base += AU1300_GPIC_PINCFG;
+       for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++)
+               alchemy_gpic_pmdata[i + 5] = __raw_readl(base + (i << 2));
+
+       wmb();
+
+       return 0;
+}
+
+static void alchemy_gpic_resume(void)
+{
+       void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR);
+       int i;
+
+       /* disable all first */
+       __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0);
+       __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4);
+       __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8);
+       __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc);
+       wmb();
+
+       /* restore pin/int-type configurations */
+       base += AU1300_GPIC_PINCFG;
+       for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++)
+               __raw_writel(alchemy_gpic_pmdata[i + 5], base + (i << 2));
+       wmb();
+
+       /* restore misc register(s) */
+       base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR);
+       __raw_writel(alchemy_gpic_pmdata[4], base + AU1300_GPIC_DMASEL);
+       wmb();
+
+       /* finally restore masks */
+       __raw_writel(alchemy_gpic_pmdata[0], base + AU1300_GPIC_IEN + 0x0);
+       __raw_writel(alchemy_gpic_pmdata[1], base + AU1300_GPIC_IEN + 0x4);
+       __raw_writel(alchemy_gpic_pmdata[2], base + AU1300_GPIC_IEN + 0x8);
+       __raw_writel(alchemy_gpic_pmdata[3], base + AU1300_GPIC_IEN + 0xc);
+       wmb();
+}
+
+static struct syscore_ops alchemy_ic_pmops = {
+       .suspend        = alchemy_ic_suspend,
+       .resume         = alchemy_ic_resume,
+};
+
+static struct syscore_ops alchemy_gpic_pmops = {
+       .suspend        = alchemy_gpic_suspend,
+       .resume         = alchemy_gpic_resume,
+};
+
+/******************************************************************************/
+
+/* create chained handlers for the 4 IC requests to the MIPS IRQ ctrl */
+#define DISP(name, base, addr)                                               \
+static void au1000_##name##_dispatch(unsigned int irq, struct irq_desc *d)    \
+{                                                                            \
+       unsigned long r = __raw_readl((void __iomem *)KSEG1ADDR(addr));       \
+       if (likely(r))                                                        \
+               generic_handle_irq(base + __ffs(r));                          \
+       else                                                                  \
+               spurious_interrupt();                                         \
+}
+
+DISP(ic0r0, AU1000_INTC0_INT_BASE, AU1000_IC0_PHYS_ADDR + IC_REQ0INT)
+DISP(ic0r1, AU1000_INTC0_INT_BASE, AU1000_IC0_PHYS_ADDR + IC_REQ1INT)
+DISP(ic1r0, AU1000_INTC1_INT_BASE, AU1000_IC1_PHYS_ADDR + IC_REQ0INT)
+DISP(ic1r1, AU1000_INTC1_INT_BASE, AU1000_IC1_PHYS_ADDR + IC_REQ1INT)
+
+static void alchemy_gpic_dispatch(unsigned int irq, struct irq_desc *d)
+{
+       int i = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_PRIENC);
+       generic_handle_irq(ALCHEMY_GPIC_INT_BASE + i);
+}
+
+/******************************************************************************/
+
+static void __init au1000_init_irq(struct alchemy_irqmap *map)
 {
        unsigned int bit, irq_nr;
        void __iomem *base;
 
        ic_init((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR));
        ic_init((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR));
+       register_syscore_ops(&alchemy_ic_pmops);
        mips_cpu_irq_init();
 
        /* register all 64 possible IC0+IC1 irq sources as type "none".
@@ -544,8 +898,8 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map)
        /*
         * Initialize IC0, which is fixed per processor.
         */
-       while (map->im_irq != -1) {
-               irq_nr = map->im_irq;
+       while (map->irq != -1) {
+               irq_nr = map->irq;
 
                if (irq_nr >= AU1000_INTC1_INT_BASE) {
                        bit = irq_nr - AU1000_INTC1_INT_BASE;
@@ -554,16 +908,61 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map)
                        bit = irq_nr - AU1000_INTC0_INT_BASE;
                        base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
                }
-               if (map->im_request)
+               if (map->prio == 0)
                        __raw_writel(1 << bit, base + IC_ASSIGNSET);
 
-               au1x_ic_settype(irq_get_irq_data(irq_nr), map->im_type);
+               au1x_ic_settype(irq_get_irq_data(irq_nr), map->type);
                ++map;
        }
 
-       set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3);
+       irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 2, au1000_ic0r0_dispatch);
+       irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 3, au1000_ic0r1_dispatch);
+       irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 4, au1000_ic1r0_dispatch);
+       irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 5, au1000_ic1r1_dispatch);
+}
+
+static void __init alchemy_gpic_init_irq(const struct alchemy_irqmap *dints)
+{
+       int i;
+       void __iomem *bank_base;
+
+       register_syscore_ops(&alchemy_gpic_pmops);
+       mips_cpu_irq_init();
+
+       /* disable & ack all possible interrupt sources */
+       for (i = 0; i < 4; i++) {
+               bank_base = AU1300_GPIC_ADDR + (i * 4);
+               __raw_writel(~0UL, bank_base + AU1300_GPIC_IDIS);
+               wmb();
+               __raw_writel(~0UL, bank_base + AU1300_GPIC_IPEND);
+               wmb();
+       }
+
+       /* register an irq_chip for them, with 2nd highest priority */
+       for (i = ALCHEMY_GPIC_INT_BASE; i <= ALCHEMY_GPIC_INT_LAST; i++) {
+               au1300_set_irq_priority(i, 1);
+               au1300_gpic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE);
+       }
+
+       /* setup known on-chip sources */
+       while ((i = dints->irq) != -1) {
+               au1300_gpic_settype(irq_get_irq_data(i), dints->type);
+               au1300_set_irq_priority(i, dints->prio);
+
+               if (dints->internal)
+                       au1300_pinfunc_to_dev(i - ALCHEMY_GPIC_INT_BASE);
+
+               dints++;
+       }
+
+       irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 2, alchemy_gpic_dispatch);
+       irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 3, alchemy_gpic_dispatch);
+       irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 4, alchemy_gpic_dispatch);
+       irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 5, alchemy_gpic_dispatch);
 }
 
+/******************************************************************************/
+
 void __init arch_init_irq(void)
 {
        switch (alchemy_get_cputype()) {
@@ -582,65 +981,17 @@ void __init arch_init_irq(void)
        case ALCHEMY_CPU_AU1200:
                au1000_init_irq(au1200_irqmap);
                break;
+       case ALCHEMY_CPU_AU1300:
+               alchemy_gpic_init_irq(au1300_irqmap);
+               break;
+       default:
+               pr_err("unknown Alchemy IRQ core\n");
+               break;
        }
 }
 
-
-static unsigned long alchemy_ic_pmdata[7 * 2];
-
-static inline void alchemy_ic_suspend_one(void __iomem *base, unsigned long *d)
-{
-       d[0] = __raw_readl(base + IC_CFG0RD);
-       d[1] = __raw_readl(base + IC_CFG1RD);
-       d[2] = __raw_readl(base + IC_CFG2RD);
-       d[3] = __raw_readl(base + IC_SRCRD);
-       d[4] = __raw_readl(base + IC_ASSIGNRD);
-       d[5] = __raw_readl(base + IC_WAKERD);
-       d[6] = __raw_readl(base + IC_MASKRD);
-       ic_init(base);          /* shut it up too while at it */
-}
-
-static inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d)
-{
-       ic_init(base);
-
-       __raw_writel(d[0], base + IC_CFG0SET);
-       __raw_writel(d[1], base + IC_CFG1SET);
-       __raw_writel(d[2], base + IC_CFG2SET);
-       __raw_writel(d[3], base + IC_SRCSET);
-       __raw_writel(d[4], base + IC_ASSIGNSET);
-       __raw_writel(d[5], base + IC_WAKESET);
-       wmb();
-
-       __raw_writel(d[6], base + IC_MASKSET);
-       wmb();
-}
-
-static int alchemy_ic_suspend(void)
-{
-       alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR),
-                              alchemy_ic_pmdata);
-       alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR),
-                              &alchemy_ic_pmdata[7]);
-       return 0;
-}
-
-static void alchemy_ic_resume(void)
-{
-       alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR),
-                             &alchemy_ic_pmdata[7]);
-       alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR),
-                             alchemy_ic_pmdata);
-}
-
-static struct syscore_ops alchemy_ic_syscore_ops = {
-       .suspend        = alchemy_ic_suspend,
-       .resume         = alchemy_ic_resume,
-};
-
-static int __init alchemy_ic_pm_init(void)
+asmlinkage void plat_irq_dispatch(void)
 {
-       register_syscore_ops(&alchemy_ic_syscore_ops);
-       return 0;
+       unsigned long r = (read_c0_status() & read_c0_cause()) >> 8;
+       do_IRQ(MIPS_CPU_IRQ_BASE + __ffs(r & 0xff));
 }
-device_initcall(alchemy_ic_pm_init);
index c8e5d72a582684ff79e022a0c0b9b3313a700034..95cb9113b12c8302ee9ea60e56e86af8c36da067 100644 (file)
@@ -82,6 +82,12 @@ static struct plat_serial8250_port au1x00_uart_data[][4] __initdata = {
                PORT(AU1000_UART0_PHYS_ADDR, AU1200_UART0_INT),
                PORT(AU1000_UART1_PHYS_ADDR, AU1200_UART1_INT),
        },
+       [ALCHEMY_CPU_AU1300] = {
+               PORT(AU1300_UART0_PHYS_ADDR, AU1300_UART0_INT),
+               PORT(AU1300_UART1_PHYS_ADDR, AU1300_UART1_INT),
+               PORT(AU1300_UART2_PHYS_ADDR, AU1300_UART2_INT),
+               PORT(AU1300_UART3_PHYS_ADDR, AU1300_UART3_INT),
+       },
 };
 
 static struct platform_device au1xx0_uart_device = {
@@ -122,10 +128,12 @@ static unsigned long alchemy_ohci_data[][2] __initdata = {
        [ALCHEMY_CPU_AU1100] = { AU1000_USB_OHCI_PHYS_ADDR, AU1100_USB_HOST_INT },
        [ALCHEMY_CPU_AU1550] = { AU1550_USB_OHCI_PHYS_ADDR, AU1550_USB_HOST_INT },
        [ALCHEMY_CPU_AU1200] = { AU1200_USB_OHCI_PHYS_ADDR, AU1200_USB_INT },
+       [ALCHEMY_CPU_AU1300] = { AU1300_USB_OHCI0_PHYS_ADDR, AU1300_USB_INT },
 };
 
 static unsigned long alchemy_ehci_data[][2] __initdata = {
        [ALCHEMY_CPU_AU1200] = { AU1200_USB_EHCI_PHYS_ADDR, AU1200_USB_INT },
+       [ALCHEMY_CPU_AU1300] = { AU1300_USB_EHCI_PHYS_ADDR, AU1300_USB_INT },
 };
 
 static int __init _new_usbres(struct resource **r, struct platform_device **d)
@@ -169,8 +177,8 @@ static void __init alchemy_setup_usb(int ctype)
                printk(KERN_INFO "Alchemy USB: cannot add OHCI0\n");
 
 
-       /* setup EHCI0: Au1200 */
-       if (ctype == ALCHEMY_CPU_AU1200) {
+       /* setup EHCI0: Au1200/Au1300 */
+       if ((ctype == ALCHEMY_CPU_AU1200) || (ctype == ALCHEMY_CPU_AU1300)) {
                if (_new_usbres(&res, &pdev))
                        return;
 
@@ -187,6 +195,25 @@ static void __init alchemy_setup_usb(int ctype)
                if (platform_device_register(pdev))
                        printk(KERN_INFO "Alchemy USB: cannot add EHCI0\n");
        }
+
+       /* Au1300: OHCI1 */
+       if (ctype == ALCHEMY_CPU_AU1300) {
+               if (_new_usbres(&res, &pdev))
+                       return;
+
+               res[0].start = AU1300_USB_OHCI1_PHYS_ADDR;
+               res[0].end = res[0].start + 0x100 - 1;
+               res[0].flags = IORESOURCE_MEM;
+               res[1].start = AU1300_USB_INT;
+               res[1].end = res[1].start;
+               res[1].flags = IORESOURCE_IRQ;
+               pdev->name = "au1xxx-ohci";
+               pdev->id = 1;
+               pdev->dev.dma_mask = &alchemy_ohci_dmamask;
+
+               if (platform_device_register(pdev))
+                       printk(KERN_INFO "Alchemy USB: cannot add OHCI1\n");
+       }
 }
 
 /* Macro to help defining the Ethernet MAC resources */
index bdd6651e9a4f3d4f0f7fc59f5f38be6e79b1a738..0c7fce2a3c12f0e6d4f7bea9cedf1a17fe0ea271 100644 (file)
@@ -126,6 +126,9 @@ void au_sleep(void)
        case ALCHEMY_CPU_AU1200:
                alchemy_sleep_au1550();
                break;
+       case ALCHEMY_CPU_AU1300:
+               alchemy_sleep_au1300();
+               break;
        }
 
        restore_core_regs();
index 77f3c743b716428c106066042c4f926ef900f7af..c7bcc7e5c822bb571164e27fcfa284838cc92c38 100644 (file)
@@ -153,6 +153,79 @@ LEAF(alchemy_sleep_au1550)
 
 END(alchemy_sleep_au1550)
 
+/* sleepcode for Au1300 memory controller type */
+LEAF(alchemy_sleep_au1300)
+
+       SETUP_SLEEP
+
+       /* cache following instructions, as memory gets put to sleep */
+       la      t0, 2f
+       la      t1, 4f
+       subu    t2, t1, t0
+
+       .set    mips3
+
+1:     cache   0x14, 0(t0)
+       subu    t2, t2, 32
+       bgez    t2, 1b
+        addu   t0, t0, 32
+
+       .set    mips0
+
+2:     lui     a0, 0xb400              /* mem_xxx */
+
+       /* disable all ports in mem_sdportcfga */
+       sw      zero, 0x868(a0)         /* mem_sdportcfga */
+       sync
+
+       /* disable ODT */
+       li      t0, 0x03010000
+       sw      t0, 0x08d8(a0)          /* mem_sdcmd0 */
+       sw      t0, 0x08dc(a0)          /* mem_sdcmd1 */
+       sync
+
+       /* precharge */
+       li      t0, 0x23000400
+       sw      t0, 0x08dc(a0)          /* mem_sdcmd1 */
+       sw      t0, 0x08d8(a0)          /* mem_sdcmd0 */
+       sync
+
+       /* auto refresh */
+       sw      zero, 0x08c8(a0)        /* mem_sdautoref */
+       sync
+
+       /* block access to the DDR */
+       lw      t0, 0x0848(a0)          /* mem_sdconfigb */
+       li      t1, (1 << 7 | 0x3F)
+       or      t0, t0, t1
+       sw      t0, 0x0848(a0)          /* mem_sdconfigb */
+       sync
+
+       /* issue the Self Refresh command */
+       li      t0, 0x10000000
+       sw      t0, 0x08dc(a0)          /* mem_sdcmd1 */
+       sw      t0, 0x08d8(a0)          /* mem_sdcmd0 */
+       sync
+
+       /* wait for sdram to enter self-refresh mode */
+       lui     t0, 0x0300
+3:     lw      t1, 0x0850(a0)          /* mem_sdstat */
+       and     t2, t1, t0
+       bne     t2, t0, 3b
+        nop
+
+       /* disable SDRAM clocks */
+       li      t0, ~(3<<28)
+       lw      t1, 0x0840(a0)          /* mem_sdconfiga */
+       and     t1, t1, t0              /* clear CE[1:0] */
+       sw      t1, 0x0840(a0)          /* mem_sdconfiga */
+       sync
+
+       DO_SLEEP
+4:
+
+END(alchemy_sleep_au1300)
+
 
        /* This is where we return upon wakeup.
         * Reload all of the registers and return.
index d5da6adbf63491566330f9a22309c69274d132ad..7da4d0081487b73f341cd4a51f6ef5efe33141ae 100644 (file)
@@ -92,7 +92,7 @@ static struct clock_event_device au1x_rtcmatch2_clockdev = {
 
 static struct irqaction au1x_rtcmatch2_irqaction = {
        .handler        = au1x_rtcmatch2_irq,
-       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .flags          = IRQF_TIMER,
        .name           = "timer",
        .dev_id         = &au1x_rtcmatch2_clockdev,
 };
@@ -178,6 +178,7 @@ static int alchemy_m2inttab[] __initdata = {
        AU1100_RTC_MATCH2_INT,
        AU1550_RTC_MATCH2_INT,
        AU1200_RTC_MATCH2_INT,
+       AU1300_RTC_MATCH2_INT,
 };
 
 void __init plat_time_init(void)
diff --git a/arch/mips/alchemy/common/vss.c b/arch/mips/alchemy/common/vss.c
new file mode 100644 (file)
index 0000000..d23b144
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Au1300 media block power gating (VSS)
+ *
+ * This is a stop-gap solution until I have the clock framework integration
+ * ready. This stuff here really must be handled transparently when clocks
+ * for various media blocks are enabled/disabled.
+ */
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#define VSS_GATE       0x00    /* gate wait timers */
+#define VSS_CLKRST     0x04    /* clock/block control */
+#define VSS_FTR                0x08    /* footers */
+
+#define VSS_ADDR(blk)  (KSEG1ADDR(AU1300_VSS_PHYS_ADDR) + (blk * 0x0c))
+
+static DEFINE_SPINLOCK(au1300_vss_lock);
+
+/* enable a block as outlined in the databook */
+static inline void __enable_block(int block)
+{
+       void __iomem *base = (void __iomem *)VSS_ADDR(block);
+
+       __raw_writel(3, base + VSS_CLKRST);     /* enable clock, assert reset */
+       wmb();
+
+       __raw_writel(0x01fffffe, base + VSS_GATE); /* maximum setup time */
+       wmb();
+
+       /* enable footers in sequence */
+       __raw_writel(0x01, base + VSS_FTR);
+       wmb();
+       __raw_writel(0x03, base + VSS_FTR);
+       wmb();
+       __raw_writel(0x07, base + VSS_FTR);
+       wmb();
+       __raw_writel(0x0f, base + VSS_FTR);
+       wmb();
+
+       __raw_writel(0x01ffffff, base + VSS_GATE); /* start FSM too */
+       wmb();
+
+       __raw_writel(2, base + VSS_CLKRST);     /* deassert reset */
+       wmb();
+
+       __raw_writel(0x1f, base + VSS_FTR);     /* enable isolation cells */
+       wmb();
+}
+
+/* disable a block as outlined in the databook */
+static inline void __disable_block(int block)
+{
+       void __iomem *base = (void __iomem *)VSS_ADDR(block);
+
+       __raw_writel(0x0f, base + VSS_FTR);     /* disable isolation cells */
+       wmb();
+       __raw_writel(0, base + VSS_GATE);       /* disable FSM */
+       wmb();
+       __raw_writel(3, base + VSS_CLKRST);     /* assert reset */
+       wmb();
+       __raw_writel(1, base + VSS_CLKRST);     /* disable clock */
+       wmb();
+       __raw_writel(0, base + VSS_FTR);        /* disable all footers */
+       wmb();
+}
+
+void au1300_vss_block_control(int block, int enable)
+{
+       unsigned long flags;
+
+       if (alchemy_get_cputype() != ALCHEMY_CPU_AU1300)
+               return;
+
+       /* only one block at a time */
+       spin_lock_irqsave(&au1300_vss_lock, flags);
+       if (enable)
+               __enable_block(block);
+       else
+               __disable_block(block);
+       spin_unlock_irqrestore(&au1300_vss_lock, flags);
+}
+EXPORT_SYMBOL_GPL(au1300_vss_block_control);
index 826449c817c3acef53919a17b4d73b60e449f8d3..3c37fb3033640e05eb39fa21496a938634e2c38c 100644 (file)
@@ -4,15 +4,10 @@
 
 obj-y += prom.o bcsr.o platform.o
 obj-$(CONFIG_PM)               += pm.o
-obj-$(CONFIG_MIPS_PB1000)      += pb1000/
-obj-$(CONFIG_MIPS_PB1100)      += pb1100/
-obj-$(CONFIG_MIPS_PB1200)      += pb1200/
-obj-$(CONFIG_MIPS_PB1500)      += pb1500/
-obj-$(CONFIG_MIPS_PB1550)      += pb1550/
-obj-$(CONFIG_MIPS_DB1000)      += db1x00/
-obj-$(CONFIG_MIPS_DB1100)      += db1x00/
-obj-$(CONFIG_MIPS_DB1200)      += db1200/
-obj-$(CONFIG_MIPS_DB1500)      += db1x00/
-obj-$(CONFIG_MIPS_DB1550)      += db1x00/
-obj-$(CONFIG_MIPS_BOSPORUS)    += db1x00/
-obj-$(CONFIG_MIPS_MIRAGE)      += db1x00/
+obj-$(CONFIG_MIPS_PB1100)      += pb1100.o
+obj-$(CONFIG_MIPS_PB1500)      += pb1500.o
+obj-$(CONFIG_MIPS_PB1550)      += pb1550.o
+obj-$(CONFIG_MIPS_DB1000)      += db1000.o
+obj-$(CONFIG_MIPS_DB1200)      += db1200.o
+obj-$(CONFIG_MIPS_DB1300)      += db1300.o
+obj-$(CONFIG_MIPS_DB1550)      += db1550.o
index 463d2c4d9441f9592ce6abf85d27b1e8c38694af..1e83ce2e1147fb4e71bc893630849ee147530198 100644 (file)
@@ -97,14 +97,9 @@ static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d)
        enable_irq(irq);
 }
 
-/* NOTE: both the enable and mask bits must be cleared, otherwise the
- * CPLD generates tons of spurious interrupts (at least on my DB1200).
- *     -- mlau
- */
 static void bcsr_irq_mask(struct irq_data *d)
 {
        unsigned short v = 1 << (d->irq - bcsr_csc_base);
-       __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR);
        __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
        wmb();
 }
@@ -112,7 +107,6 @@ static void bcsr_irq_mask(struct irq_data *d)
 static void bcsr_irq_maskack(struct irq_data *d)
 {
        unsigned short v = 1 << (d->irq - bcsr_csc_base);
-       __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR);
        __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
        __raw_writew(v, bcsr_virt + BCSR_REG_INTSTAT);  /* ack */
        wmb();
@@ -121,7 +115,6 @@ static void bcsr_irq_maskack(struct irq_data *d)
 static void bcsr_irq_unmask(struct irq_data *d)
 {
        unsigned short v = 1 << (d->irq - bcsr_csc_base);
-       __raw_writew(v, bcsr_virt + BCSR_REG_INTSET);
        __raw_writew(v, bcsr_virt + BCSR_REG_MASKSET);
        wmb();
 }
@@ -137,9 +130,9 @@ void __init bcsr_init_irq(int csc_start, int csc_end, int hook_irq)
 {
        unsigned int irq;
 
-       /* mask & disable & ack all */
-       __raw_writew(0xffff, bcsr_virt + BCSR_REG_INTCLR);
+       /* mask & enable & ack all */
        __raw_writew(0xffff, bcsr_virt + BCSR_REG_MASKCLR);
+       __raw_writew(0xffff, bcsr_virt + BCSR_REG_INTSET);
        __raw_writew(0xffff, bcsr_virt + BCSR_REG_INTSTAT);
        wmb();
 
diff --git a/arch/mips/alchemy/devboards/db1000.c b/arch/mips/alchemy/devboards/db1000.c
new file mode 100644 (file)
index 0000000..1b81dbf
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ * DBAu1000/1500/1100 board support
+ *
+ * Copyright 2000, 2008 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc. <source@mvista.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/leds.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+#include <linux/spi/ads7846.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1000_dma.h>
+#include <asm/mach-au1x00/au1100_mmc.h>
+#include <asm/mach-db1x00/bcsr.h>
+#include <asm/reboot.h>
+#include <prom.h>
+#include "platform.h"
+
+#define F_SWAPPED (bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT)
+
+struct pci_dev;
+
+static const char *board_type_str(void)
+{
+       switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
+       case BCSR_WHOAMI_DB1000:
+               return "DB1000";
+       case BCSR_WHOAMI_DB1500:
+               return "DB1500";
+       case BCSR_WHOAMI_DB1100:
+               return "DB1100";
+       default:
+               return "(unknown)";
+       }
+}
+
+const char *get_system_type(void)
+{
+       return board_type_str();
+}
+
+void __init board_setup(void)
+{
+       /* initialize board register space */
+       bcsr_init(DB1000_BCSR_PHYS_ADDR,
+                 DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS);
+
+       printk(KERN_INFO "AMD Alchemy %s Board\n", board_type_str());
+}
+
+
+static int db1500_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
+{
+       if ((slot < 12) || (slot > 13) || pin == 0)
+               return -1;
+       if (slot == 12)
+               return (pin == 1) ? AU1500_PCI_INTA : 0xff;
+       if (slot == 13) {
+               switch (pin) {
+               case 1: return AU1500_PCI_INTA;
+               case 2: return AU1500_PCI_INTB;
+               case 3: return AU1500_PCI_INTC;
+               case 4: return AU1500_PCI_INTD;
+               }
+       }
+       return -1;
+}
+
+static struct resource alchemy_pci_host_res[] = {
+       [0] = {
+               .start  = AU1500_PCI_PHYS_ADDR,
+               .end    = AU1500_PCI_PHYS_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct alchemy_pci_platdata db1500_pci_pd = {
+       .board_map_irq  = db1500_map_pci_irq,
+};
+
+static struct platform_device db1500_pci_host_dev = {
+       .dev.platform_data = &db1500_pci_pd,
+       .name           = "alchemy-pci",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(alchemy_pci_host_res),
+       .resource       = alchemy_pci_host_res,
+};
+
+static int __init db1500_pci_init(void)
+{
+       if (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)) == BCSR_WHOAMI_DB1500)
+               return platform_device_register(&db1500_pci_host_dev);
+       return 0;
+}
+/* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */
+arch_initcall(db1500_pci_init);
+
+
+static struct resource au1100_lcd_resources[] = {
+       [0] = {
+               .start  = AU1100_LCD_PHYS_ADDR,
+               .end    = AU1100_LCD_PHYS_ADDR + 0x800 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1100_LCD_INT,
+               .end    = AU1100_LCD_INT,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device au1100_lcd_device = {
+       .name           = "au1100-lcd",
+       .id             = 0,
+       .dev = {
+               .dma_mask               = &au1100_lcd_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .num_resources  = ARRAY_SIZE(au1100_lcd_resources),
+       .resource       = au1100_lcd_resources,
+};
+
+static struct resource alchemy_ac97c_res[] = {
+       [0] = {
+               .start  = AU1000_AC97_PHYS_ADDR,
+               .end    = AU1000_AC97_PHYS_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DMA_ID_AC97C_TX,
+               .end    = DMA_ID_AC97C_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start  = DMA_ID_AC97C_RX,
+               .end    = DMA_ID_AC97C_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device alchemy_ac97c_dev = {
+       .name           = "alchemy-ac97c",
+       .id             = -1,
+       .resource       = alchemy_ac97c_res,
+       .num_resources  = ARRAY_SIZE(alchemy_ac97c_res),
+};
+
+static struct platform_device alchemy_ac97c_dma_dev = {
+       .name           = "alchemy-pcm-dma",
+       .id             = 0,
+};
+
+static struct platform_device db1x00_codec_dev = {
+       .name           = "ac97-codec",
+       .id             = -1,
+};
+
+static struct platform_device db1x00_audio_dev = {
+       .name           = "db1000-audio",
+};
+
+/******************************************************************************/
+
+static irqreturn_t db1100_mmc_cd(int irq, void *ptr)
+{
+       void (*mmc_cd)(struct mmc_host *, unsigned long);
+       /* link against CONFIG_MMC=m */
+       mmc_cd = symbol_get(mmc_detect_change);
+       mmc_cd(ptr, msecs_to_jiffies(500));
+       symbol_put(mmc_detect_change);
+
+       return IRQ_HANDLED;
+}
+
+static int db1100_mmc_cd_setup(void *mmc_host, int en)
+{
+       int ret = 0;
+
+       if (en) {
+               irq_set_irq_type(AU1100_GPIO19_INT, IRQ_TYPE_EDGE_BOTH);
+               ret = request_irq(AU1100_GPIO19_INT, db1100_mmc_cd, 0,
+                                 "sd0_cd", mmc_host);
+       } else
+               free_irq(AU1100_GPIO19_INT, mmc_host);
+       return ret;
+}
+
+static int db1100_mmc1_cd_setup(void *mmc_host, int en)
+{
+       int ret = 0;
+
+       if (en) {
+               irq_set_irq_type(AU1100_GPIO20_INT, IRQ_TYPE_EDGE_BOTH);
+               ret = request_irq(AU1100_GPIO20_INT, db1100_mmc_cd, 0,
+                                 "sd1_cd", mmc_host);
+       } else
+               free_irq(AU1100_GPIO20_INT, mmc_host);
+       return ret;
+}
+
+static int db1100_mmc_card_readonly(void *mmc_host)
+{
+       /* testing suggests that this bit is inverted */
+       return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP) ? 0 : 1;
+}
+
+static int db1100_mmc_card_inserted(void *mmc_host)
+{
+       return !alchemy_gpio_get_value(19);
+}
+
+static void db1100_mmc_set_power(void *mmc_host, int state)
+{
+       if (state) {
+               bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD0PWR);
+               msleep(400);    /* stabilization time */
+       } else
+               bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD0PWR, 0);
+}
+
+static void db1100_mmcled_set(struct led_classdev *led, enum led_brightness b)
+{
+       if (b != LED_OFF)
+               bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0);
+       else
+               bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0);
+}
+
+static struct led_classdev db1100_mmc_led = {
+       .brightness_set = db1100_mmcled_set,
+};
+
+static int db1100_mmc1_card_readonly(void *mmc_host)
+{
+       return (bcsr_read(BCSR_BOARD) & BCSR_BOARD_SD1WP) ? 1 : 0;
+}
+
+static int db1100_mmc1_card_inserted(void *mmc_host)
+{
+       return !alchemy_gpio_get_value(20);
+}
+
+static void db1100_mmc1_set_power(void *mmc_host, int state)
+{
+       if (state) {
+               bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD1PWR);
+               msleep(400);    /* stabilization time */
+       } else
+               bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD1PWR, 0);
+}
+
+static void db1100_mmc1led_set(struct led_classdev *led, enum led_brightness b)
+{
+       if (b != LED_OFF)
+               bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0);
+       else
+               bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1);
+}
+
+static struct led_classdev db1100_mmc1_led = {
+       .brightness_set = db1100_mmc1led_set,
+};
+
+static struct au1xmmc_platform_data db1100_mmc_platdata[2] = {
+       [0] = {
+               .cd_setup       = db1100_mmc_cd_setup,
+               .set_power      = db1100_mmc_set_power,
+               .card_inserted  = db1100_mmc_card_inserted,
+               .card_readonly  = db1100_mmc_card_readonly,
+               .led            = &db1100_mmc_led,
+       },
+       [1] = {
+               .cd_setup       = db1100_mmc1_cd_setup,
+               .set_power      = db1100_mmc1_set_power,
+               .card_inserted  = db1100_mmc1_card_inserted,
+               .card_readonly  = db1100_mmc1_card_readonly,
+               .led            = &db1100_mmc1_led,
+       },
+};
+
+static struct resource au1100_mmc0_resources[] = {
+       [0] = {
+               .start  = AU1100_SD0_PHYS_ADDR,
+               .end    = AU1100_SD0_PHYS_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1100_SD_INT,
+               .end    = AU1100_SD_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = DMA_ID_SD0_TX,
+               .end    = DMA_ID_SD0_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = DMA_ID_SD0_RX,
+               .end    = DMA_ID_SD0_RX,
+               .flags  = IORESOURCE_DMA,
+       }
+};
+
+static u64 au1xxx_mmc_dmamask =  DMA_BIT_MASK(32);
+
+static struct platform_device db1100_mmc0_dev = {
+       .name           = "au1xxx-mmc",
+       .id             = 0,
+       .dev = {
+               .dma_mask               = &au1xxx_mmc_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &db1100_mmc_platdata[0],
+       },
+       .num_resources  = ARRAY_SIZE(au1100_mmc0_resources),
+       .resource       = au1100_mmc0_resources,
+};
+
+static struct resource au1100_mmc1_res[] = {
+       [0] = {
+               .start  = AU1100_SD1_PHYS_ADDR,
+               .end    = AU1100_SD1_PHYS_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1100_SD_INT,
+               .end    = AU1100_SD_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = DMA_ID_SD1_TX,
+               .end    = DMA_ID_SD1_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = DMA_ID_SD1_RX,
+               .end    = DMA_ID_SD1_RX,
+               .flags  = IORESOURCE_DMA,
+       }
+};
+
+static struct platform_device db1100_mmc1_dev = {
+       .name           = "au1xxx-mmc",
+       .id             = 1,
+       .dev = {
+               .dma_mask               = &au1xxx_mmc_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &db1100_mmc_platdata[1],
+       },
+       .num_resources  = ARRAY_SIZE(au1100_mmc1_res),
+       .resource       = au1100_mmc1_res,
+};
+
+/******************************************************************************/
+
+static void db1000_irda_set_phy_mode(int mode)
+{
+       unsigned short mask = BCSR_RESETS_IRDA_MODE_MASK | BCSR_RESETS_FIR_SEL;
+
+       switch (mode) {
+       case AU1000_IRDA_PHY_MODE_OFF:
+               bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_OFF);
+               break;
+       case AU1000_IRDA_PHY_MODE_SIR:
+               bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_FULL);
+               break;
+       case AU1000_IRDA_PHY_MODE_FIR:
+               bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_FULL |
+                                           BCSR_RESETS_FIR_SEL);
+               break;
+       }
+}
+
+static struct au1k_irda_platform_data db1000_irda_platdata = {
+       .set_phy_mode   = db1000_irda_set_phy_mode,
+};
+
+static struct resource au1000_irda_res[] = {
+       [0] = {
+               .start  = AU1000_IRDA_PHYS_ADDR,
+               .end    = AU1000_IRDA_PHYS_ADDR + 0x0fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1000_IRDA_TX_INT,
+               .end    = AU1000_IRDA_TX_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = AU1000_IRDA_RX_INT,
+               .end    = AU1000_IRDA_RX_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device db1000_irda_dev = {
+       .name   = "au1000-irda",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &db1000_irda_platdata,
+       },
+       .resource       = au1000_irda_res,
+       .num_resources  = ARRAY_SIZE(au1000_irda_res),
+};
+
+/******************************************************************************/
+
+static struct ads7846_platform_data db1100_touch_pd = {
+       .model          = 7846,
+       .vref_mv        = 3300,
+       .gpio_pendown   = 21,
+};
+
+static struct spi_gpio_platform_data db1100_spictl_pd = {
+       .sck            = 209,
+       .mosi           = 208,
+       .miso           = 207,
+       .num_chipselect = 1,
+};
+
+static struct spi_board_info db1100_spi_info[] __initdata = {
+       [0] = {
+               .modalias        = "ads7846",
+               .max_speed_hz    = 3250000,
+               .bus_num         = 0,
+               .chip_select     = 0,
+               .mode            = 0,
+               .irq             = AU1100_GPIO21_INT,
+               .platform_data   = &db1100_touch_pd,
+               .controller_data = (void *)210, /* for spi_gpio: CS# GPIO210 */
+       },
+};
+
+static struct platform_device db1100_spi_dev = {
+       .name           = "spi_gpio",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &db1100_spictl_pd,
+       },
+};
+
+
+static struct platform_device *db1x00_devs[] = {
+       &db1x00_codec_dev,
+       &alchemy_ac97c_dma_dev,
+       &alchemy_ac97c_dev,
+       &db1x00_audio_dev,
+};
+
+static struct platform_device *db1000_devs[] = {
+       &db1000_irda_dev,
+};
+
+static struct platform_device *db1100_devs[] = {
+       &au1100_lcd_device,
+       &db1100_mmc0_dev,
+       &db1100_mmc1_dev,
+       &db1000_irda_dev,
+       &db1100_spi_dev,
+};
+
+static int __init db1000_dev_init(void)
+{
+       int board = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
+       int c0, c1, d0, d1, s0, s1;
+       unsigned long pfc;
+
+       if (board == BCSR_WHOAMI_DB1500) {
+               c0 = AU1500_GPIO2_INT;
+               c1 = AU1500_GPIO5_INT;
+               d0 = AU1500_GPIO0_INT;
+               d1 = AU1500_GPIO3_INT;
+               s0 = AU1500_GPIO1_INT;
+               s1 = AU1500_GPIO4_INT;
+       } else if (board == BCSR_WHOAMI_DB1100) {
+               c0 = AU1100_GPIO2_INT;
+               c1 = AU1100_GPIO5_INT;
+               d0 = AU1100_GPIO0_INT;
+               d1 = AU1100_GPIO3_INT;
+               s0 = AU1100_GPIO1_INT;
+               s1 = AU1100_GPIO4_INT;
+
+               gpio_direction_input(19);       /* sd0 cd# */
+               gpio_direction_input(20);       /* sd1 cd# */
+               gpio_direction_input(21);       /* touch pendown# */
+               gpio_direction_input(207);      /* SPI MISO */
+               gpio_direction_output(208, 0);  /* SPI MOSI */
+               gpio_direction_output(209, 1);  /* SPI SCK */
+               gpio_direction_output(210, 1);  /* SPI CS# */
+
+               /* spi_gpio on SSI0 pins */
+               pfc = __raw_readl((void __iomem *)SYS_PINFUNC);
+               pfc |= (1 << 0);        /* SSI0 pins as GPIOs */
+               __raw_writel(pfc, (void __iomem *)SYS_PINFUNC);
+               wmb();
+
+               spi_register_board_info(db1100_spi_info,
+                                       ARRAY_SIZE(db1100_spi_info));
+
+               platform_add_devices(db1100_devs, ARRAY_SIZE(db1100_devs));
+       } else if (board == BCSR_WHOAMI_DB1000) {
+               c0 = AU1000_GPIO2_INT;
+               c1 = AU1000_GPIO5_INT;
+               d0 = AU1000_GPIO0_INT;
+               d1 = AU1000_GPIO3_INT;
+               s0 = AU1000_GPIO1_INT;
+               s1 = AU1000_GPIO4_INT;
+               platform_add_devices(db1000_devs, ARRAY_SIZE(db1000_devs));
+       } else
+               return 0; /* unknown board, no further dev setup to do */
+
+       irq_set_irq_type(d0, IRQ_TYPE_EDGE_BOTH);
+       irq_set_irq_type(d1, IRQ_TYPE_EDGE_BOTH);
+       irq_set_irq_type(c0, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(c1, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(s0, IRQ_TYPE_LEVEL_LOW);
+       irq_set_irq_type(s1, IRQ_TYPE_LEVEL_LOW);
+
+       db1x_register_pcmcia_socket(
+               AU1000_PCMCIA_ATTR_PHYS_ADDR,
+               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
+               AU1000_PCMCIA_MEM_PHYS_ADDR,
+               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
+               AU1000_PCMCIA_IO_PHYS_ADDR,
+               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
+               c0, d0, /*s0*/0, 0, 0);
+
+       db1x_register_pcmcia_socket(
+               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
+               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
+               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x004000000,
+               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x004400000 - 1,
+               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004000000,
+               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004010000 - 1,
+               c1, d1, /*s1*/0, 0, 1);
+
+       platform_add_devices(db1x00_devs, ARRAY_SIZE(db1x00_devs));
+       db1x_register_norflash(32 << 20, 4 /* 32bit */, F_SWAPPED);
+       return 0;
+}
+device_initcall(db1000_dev_init);
similarity index 62%
rename from arch/mips/alchemy/devboards/db1200/platform.c
rename to arch/mips/alchemy/devboards/db1200.c
index c61867c93c4ab49c44c6c9b7df8387cc2f2adac3..a83302b96c0163187b6f87710a34da57ada23a47 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * DBAu1200 board platform device registration
+ * DBAu1200/PBAu1200 board platform device registration
  *
- * Copyright (C) 2008-2009 Manuel Lauss
+ * Copyright (C) 2008-2011 Manuel Lauss
  *
  * 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
@@ -22,6 +22,7 @@
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/leds.h>
 #include <linux/mmc/host.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #include <linux/smc91x.h>
-
+#include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1100_mmc.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-au1x00/au1200fb.h>
 #include <asm/mach-au1x00/au1550_spi.h>
 #include <asm/mach-db1x00/bcsr.h>
 #include <asm/mach-db1x00/db1200.h>
 
-#include "../platform.h"
+#include "platform.h"
+
+static const char *board_type_str(void)
+{
+       switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
+       case BCSR_WHOAMI_PB1200_DDR1:
+       case BCSR_WHOAMI_PB1200_DDR2:
+               return "PB1200";
+       case BCSR_WHOAMI_DB1200:
+               return "DB1200";
+       default:
+               return "(unknown)";
+       }
+}
+
+const char *get_system_type(void)
+{
+       return board_type_str();
+}
+
+static int __init detect_board(void)
+{
+       int bid;
+
+       /* try the DB1200 first */
+       bcsr_init(DB1200_BCSR_PHYS_ADDR,
+                 DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS);
+       if (BCSR_WHOAMI_DB1200 == BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
+               unsigned short t = bcsr_read(BCSR_HEXLEDS);
+               bcsr_write(BCSR_HEXLEDS, ~t);
+               if (bcsr_read(BCSR_HEXLEDS) != t) {
+                       bcsr_write(BCSR_HEXLEDS, t);
+                       return 0;
+               }
+       }
+
+       /* okay, try the PB1200 then */
+       bcsr_init(PB1200_BCSR_PHYS_ADDR,
+                 PB1200_BCSR_PHYS_ADDR + PB1200_BCSR_HEXLED_OFS);
+       bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
+       if ((bid == BCSR_WHOAMI_PB1200_DDR1) ||
+           (bid == BCSR_WHOAMI_PB1200_DDR2)) {
+               unsigned short t = bcsr_read(BCSR_HEXLEDS);
+               bcsr_write(BCSR_HEXLEDS, ~t);
+               if (bcsr_read(BCSR_HEXLEDS) != t) {
+                       bcsr_write(BCSR_HEXLEDS, t);
+                       return 0;
+               }
+       }
+
+       return 1;       /* it's neither */
+}
+
+void __init board_setup(void)
+{
+       unsigned long freq0, clksrc, div, pfc;
+       unsigned short whoami;
+
+       if (detect_board()) {
+               printk(KERN_ERR "NOT running on a DB1200/PB1200 board!\n");
+               return;
+       }
+
+       whoami = bcsr_read(BCSR_WHOAMI);
+       printk(KERN_INFO "Alchemy/AMD/RMI %s Board, CPLD Rev %d"
+               "  Board-ID %d  Daughtercard ID %d\n", board_type_str(),
+               (whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf);
+
+       /* SMBus/SPI on PSC0, Audio on PSC1 */
+       pfc = __raw_readl((void __iomem *)SYS_PINFUNC);
+       pfc &= ~(SYS_PINFUNC_P0A | SYS_PINFUNC_P0B);
+       pfc &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B | SYS_PINFUNC_FS3);
+       pfc |= SYS_PINFUNC_P1C; /* SPI is configured later */
+       __raw_writel(pfc, (void __iomem *)SYS_PINFUNC);
+       wmb();
+
+       /* Clock configurations: PSC0: ~50MHz via Clkgen0, derived from
+        * CPU clock; all other clock generators off/unused.
+        */
+       div = (get_au1x00_speed() + 25000000) / 50000000;
+       if (div & 1)
+               div++;
+       div = ((div >> 1) - 1) & 0xff;
+
+       freq0 = div << SYS_FC_FRDIV0_BIT;
+       __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0);
+       wmb();
+       freq0 |= SYS_FC_FE0;    /* enable F0 */
+       __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0);
+       wmb();
+
+       /* psc0_intclk comes 1:1 from F0 */
+       clksrc = SYS_CS_MUX_FQ0 << SYS_CS_ME0_BIT;
+       __raw_writel(clksrc, (void __iomem *)SYS_CLKSRC);
+       wmb();
+}
+
+/******************************************************************************/
 
 static struct mtd_partition db1200_spiflash_parts[] = {
        {
-               .name   = "DB1200 SPI flash",
+               .name   = "spi_flash",
                .offset = 0,
                .size   = MTDPART_SIZ_FULL,
        },
@@ -78,18 +177,9 @@ static struct spi_board_info db1200_spi_devs[] __initdata = {
 };
 
 static struct i2c_board_info db1200_i2c_devs[] __initdata = {
-       {
-               /* AT24C04-10 I2C eeprom */
-               I2C_BOARD_INFO("24c04", 0x52),
-       },
-       {
-               /* Philips NE1619 temp/voltage sensor (adm1025 drv) */
-               I2C_BOARD_INFO("ne1619", 0x2d),
-       },
-       {
-               /* I2S audio codec WM8731 */
-               I2C_BOARD_INFO("wm8731", 0x1b),
-       },
+       { I2C_BOARD_INFO("24c04", 0x52),  }, /* AT24C04-10 I2C eeprom */
+       { I2C_BOARD_INFO("ne1619", 0x2d), }, /* adm1025-compat hwmon */
+       { I2C_BOARD_INFO("wm8731", 0x1b), }, /* I2S audio codec WM8731 */
 };
 
 /**********************************************************************/
@@ -206,7 +296,7 @@ static struct platform_device db1200_eth_dev = {
 static struct resource db1200_ide_res[] = {
        [0] = {
                .start  = DB1200_IDE_PHYS_ADDR,
-               .end    = DB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1,
+               .end    = DB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -221,13 +311,13 @@ static struct resource db1200_ide_res[] = {
        },
 };
 
-static u64 ide_dmamask = DMA_BIT_MASK(32);
+static u64 au1200_ide_dmamask = DMA_BIT_MASK(32);
 
 static struct platform_device db1200_ide_dev = {
        .name           = "au1200-ide",
        .id             = 0,
        .dev = {
-               .dma_mask               = &ide_dmamask,
+               .dma_mask               = &au1200_ide_dmamask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
        },
        .num_resources  = ARRAY_SIZE(db1200_ide_res),
@@ -236,13 +326,6 @@ static struct platform_device db1200_ide_dev = {
 
 /**********************************************************************/
 
-static struct platform_device db1200_rtc_dev = {
-       .name   = "rtc-au1xxx",
-       .id     = -1,
-};
-
-/**********************************************************************/
-
 /* SD carddetects:  they're supposed to be edge-triggered, but ack
  * doesn't seem to work (CPLD Rev 2).  Instead, the screaming one
  * is disabled and its counterpart enabled.  The 500ms timeout is
@@ -276,12 +359,12 @@ static int db1200_mmc_cd_setup(void *mmc_host, int en)
 
        if (en) {
                ret = request_irq(DB1200_SD0_INSERT_INT, db1200_mmc_cd,
-                                 IRQF_DISABLED, "sd_insert", mmc_host);
+                                 0, "sd_insert", mmc_host);
                if (ret)
                        goto out;
 
                ret = request_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd,
-                                 IRQF_DISABLED, "sd_eject", mmc_host);
+                                 0, "sd_eject", mmc_host);
                if (ret) {
                        free_irq(DB1200_SD0_INSERT_INT, mmc_host);
                        goto out;
@@ -333,12 +416,109 @@ static struct led_classdev db1200_mmc_led = {
        .brightness_set = db1200_mmcled_set,
 };
 
-static struct au1xmmc_platform_data db1200mmc_platdata = {
-       .cd_setup       = db1200_mmc_cd_setup,
-       .set_power      = db1200_mmc_set_power,
-       .card_inserted  = db1200_mmc_card_inserted,
-       .card_readonly  = db1200_mmc_card_readonly,
-       .led            = &db1200_mmc_led,
+/* -- */
+
+static irqreturn_t pb1200_mmc1_cd(int irq, void *ptr)
+{
+       void(*mmc_cd)(struct mmc_host *, unsigned long);
+
+       if (irq == PB1200_SD1_INSERT_INT) {
+               disable_irq_nosync(PB1200_SD1_INSERT_INT);
+               enable_irq(PB1200_SD1_EJECT_INT);
+       } else {
+               disable_irq_nosync(PB1200_SD1_EJECT_INT);
+               enable_irq(PB1200_SD1_INSERT_INT);
+       }
+
+       /* link against CONFIG_MMC=m */
+       mmc_cd = symbol_get(mmc_detect_change);
+       if (mmc_cd) {
+               mmc_cd(ptr, msecs_to_jiffies(500));
+               symbol_put(mmc_detect_change);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int pb1200_mmc1_cd_setup(void *mmc_host, int en)
+{
+       int ret;
+
+       if (en) {
+               ret = request_irq(PB1200_SD1_INSERT_INT, pb1200_mmc1_cd, 0,
+                                 "sd1_insert", mmc_host);
+               if (ret)
+                       goto out;
+
+               ret = request_irq(PB1200_SD1_EJECT_INT, pb1200_mmc1_cd, 0,
+                                 "sd1_eject", mmc_host);
+               if (ret) {
+                       free_irq(PB1200_SD1_INSERT_INT, mmc_host);
+                       goto out;
+               }
+
+               if (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD1INSERT)
+                       enable_irq(PB1200_SD1_EJECT_INT);
+               else
+                       enable_irq(PB1200_SD1_INSERT_INT);
+
+       } else {
+               free_irq(PB1200_SD1_INSERT_INT, mmc_host);
+               free_irq(PB1200_SD1_EJECT_INT, mmc_host);
+       }
+       ret = 0;
+out:
+       return ret;
+}
+
+static void pb1200_mmc1led_set(struct led_classdev *led,
+                       enum led_brightness brightness)
+{
+       if (brightness != LED_OFF)
+                       bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0);
+       else
+                       bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1);
+}
+
+static struct led_classdev pb1200_mmc1_led = {
+       .brightness_set = pb1200_mmc1led_set,
+};
+
+static void pb1200_mmc1_set_power(void *mmc_host, int state)
+{
+       if (state) {
+               bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD1PWR);
+               msleep(400);    /* stabilization time */
+       } else
+               bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD1PWR, 0);
+}
+
+static int pb1200_mmc1_card_readonly(void *mmc_host)
+{
+       return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD1WP) ? 1 : 0;
+}
+
+static int pb1200_mmc1_card_inserted(void *mmc_host)
+{
+       return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD1INSERT) ? 1 : 0;
+}
+
+
+static struct au1xmmc_platform_data db1200_mmc_platdata[2] = {
+       [0] = {
+               .cd_setup       = db1200_mmc_cd_setup,
+               .set_power      = db1200_mmc_set_power,
+               .card_inserted  = db1200_mmc_card_inserted,
+               .card_readonly  = db1200_mmc_card_readonly,
+               .led            = &db1200_mmc_led,
+       },
+       [1] = {
+               .cd_setup       = pb1200_mmc1_cd_setup,
+               .set_power      = pb1200_mmc1_set_power,
+               .card_inserted  = pb1200_mmc1_card_inserted,
+               .card_readonly  = pb1200_mmc1_card_readonly,
+               .led            = &pb1200_mmc1_led,
+       },
 };
 
 static struct resource au1200_mmc0_resources[] = {
@@ -372,14 +552,76 @@ static struct platform_device db1200_mmc0_dev = {
        .dev = {
                .dma_mask               = &au1xxx_mmc_dmamask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
-               .platform_data          = &db1200mmc_platdata,
+               .platform_data          = &db1200_mmc_platdata[0],
        },
        .num_resources  = ARRAY_SIZE(au1200_mmc0_resources),
        .resource       = au1200_mmc0_resources,
 };
 
+static struct resource au1200_mmc1_res[] = {
+       [0] = {
+               .start  = AU1100_SD1_PHYS_ADDR,
+               .end    = AU1100_SD1_PHYS_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1200_SD_INT,
+               .end    = AU1200_SD_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = AU1200_DSCR_CMD0_SDMS_TX1,
+               .end    = AU1200_DSCR_CMD0_SDMS_TX1,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = AU1200_DSCR_CMD0_SDMS_RX1,
+               .end    = AU1200_DSCR_CMD0_SDMS_RX1,
+               .flags  = IORESOURCE_DMA,
+       }
+};
+
+static struct platform_device pb1200_mmc1_dev = {
+       .name           = "au1xxx-mmc",
+       .id             = 1,
+       .dev = {
+               .dma_mask               = &au1xxx_mmc_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &db1200_mmc_platdata[1],
+       },
+       .num_resources  = ARRAY_SIZE(au1200_mmc1_res),
+       .resource       = au1200_mmc1_res,
+};
+
 /**********************************************************************/
 
+static int db1200fb_panel_index(void)
+{
+       return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f;
+}
+
+static int db1200fb_panel_init(void)
+{
+       /* Apply power */
+       bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
+                               BCSR_BOARD_LCDBL);
+       return 0;
+}
+
+static int db1200fb_panel_shutdown(void)
+{
+       /* Remove power */
+       bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
+                            BCSR_BOARD_LCDBL, 0);
+       return 0;
+}
+
+static struct au1200fb_platdata db1200fb_pd = {
+       .panel_index    = db1200fb_panel_index,
+       .panel_init     = db1200fb_panel_init,
+       .panel_shutdown = db1200fb_panel_shutdown,
+};
+
 static struct resource au1200_lcd_res[] = {
        [0] = {
                .start  = AU1200_LCD_PHYS_ADDR,
@@ -401,6 +643,7 @@ static struct platform_device au1200_lcd_dev = {
        .dev = {
                .dma_mask               = &au1200_lcd_dmamask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &db1200fb_pd,
        },
        .num_resources  = ARRAY_SIZE(au1200_lcd_res),
        .resource       = au1200_lcd_res,
@@ -519,7 +762,6 @@ static struct platform_device *db1200_devs[] __initdata = {
        &db1200_mmc0_dev,
        &au1200_lcd_dev,
        &db1200_eth_dev,
-       &db1200_rtc_dev,
        &db1200_nand_dev,
        &db1200_audiodma_dev,
        &db1200_audio_dev,
@@ -527,11 +769,62 @@ static struct platform_device *db1200_devs[] __initdata = {
        &db1200_sound_dev,
 };
 
+static struct platform_device *pb1200_devs[] __initdata = {
+       &pb1200_mmc1_dev,
+};
+
+/* Some peripheral base addresses differ on the PB1200 */
+static int __init pb1200_res_fixup(void)
+{
+       /* CPLD Revs earlier than 4 cause problems */
+       if (BCSR_WHOAMI_CPLD(bcsr_read(BCSR_WHOAMI)) <= 3) {
+               printk(KERN_ERR "WARNING!!!\n");
+               printk(KERN_ERR "WARNING!!!\n");
+               printk(KERN_ERR "PB1200 must be at CPLD rev 4. Please have\n");
+               printk(KERN_ERR "the board updated to latest revisions.\n");
+               printk(KERN_ERR "This software will not work reliably\n");
+               printk(KERN_ERR "on anything older than CPLD rev 4.!\n");
+               printk(KERN_ERR "WARNING!!!\n");
+               printk(KERN_ERR "WARNING!!!\n");
+               return 1;
+       }
+
+       db1200_nand_res[0].start = PB1200_NAND_PHYS_ADDR;
+       db1200_nand_res[0].end   = PB1200_NAND_PHYS_ADDR + 0xff;
+       db1200_ide_res[0].start = PB1200_IDE_PHYS_ADDR;
+       db1200_ide_res[0].end   = PB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1;
+       db1200_eth_res[0].start = PB1200_ETH_PHYS_ADDR;
+       db1200_eth_res[0].end   = PB1200_ETH_PHYS_ADDR + 0xff;
+       return 0;
+}
+
 static int __init db1200_dev_init(void)
 {
        unsigned long pfc;
        unsigned short sw;
-       int swapped;
+       int swapped, bid;
+
+       bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
+       if ((bid == BCSR_WHOAMI_PB1200_DDR1) ||
+           (bid == BCSR_WHOAMI_PB1200_DDR2)) {
+               if (pb1200_res_fixup())
+                       return -ENODEV;
+       }
+
+       /* GPIO7 is low-level triggered CPLD cascade */
+       irq_set_irq_type(AU1200_GPIO7_INT, IRQ_TYPE_LEVEL_LOW);
+       bcsr_init_irq(DB1200_INT_BEGIN, DB1200_INT_END, AU1200_GPIO7_INT);
+
+       /* insert/eject pairs: one of both is always screaming.  To avoid
+        * issues they must not be automatically enabled when initially
+        * requested.
+        */
+       irq_set_status_flags(DB1200_SD0_INSERT_INT, IRQ_NOAUTOEN);
+       irq_set_status_flags(DB1200_SD0_EJECT_INT, IRQ_NOAUTOEN);
+       irq_set_status_flags(DB1200_PC0_INSERT_INT, IRQ_NOAUTOEN);
+       irq_set_status_flags(DB1200_PC0_EJECT_INT, IRQ_NOAUTOEN);
+       irq_set_status_flags(DB1200_PC1_INSERT_INT, IRQ_NOAUTOEN);
+       irq_set_status_flags(DB1200_PC1_EJECT_INT, IRQ_NOAUTOEN);
 
        i2c_register_board_info(0, db1200_i2c_devs,
                                ARRAY_SIZE(db1200_i2c_devs));
@@ -540,6 +833,7 @@ static int __init db1200_dev_init(void)
 
        /* SWITCHES:    S6.8 I2C/SPI selector  (OFF=I2C  ON=SPI)
         *              S6.7 AC97/I2S selector (OFF=AC97 ON=I2S)
+        *              or S12 on the PB1200.
         */
 
        /* NOTE: GPIO215 controls OTG VBUS supply.  In SPI mode however
@@ -554,7 +848,7 @@ static int __init db1200_dev_init(void)
        gpio_request(215, "otg-vbus");
        gpio_direction_output(215, 1);
 
-       printk(KERN_INFO "DB1200 device configuration:\n");
+       printk(KERN_INFO "%s device configuration:\n", board_type_str());
 
        sw = bcsr_read(BCSR_SWITCHES);
        if (sw & BCSR_SWITCHES_DIP_8) {
@@ -595,7 +889,7 @@ static int __init db1200_dev_init(void)
 
        /* Audio PSC clock is supplied externally. (FIXME: platdata!!) */
        __raw_writel(PSC_SEL_CLK_SERCLK,
-               (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
+           (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
        wmb();
 
        db1x_register_pcmcia_socket(
@@ -621,28 +915,13 @@ static int __init db1200_dev_init(void)
        swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT;
        db1x_register_norflash(64 << 20, 2, swapped);
 
-       return platform_add_devices(db1200_devs, ARRAY_SIZE(db1200_devs));
-}
-device_initcall(db1200_dev_init);
-
-/* au1200fb calls these: STERBT EINEN TRAGISCHEN TOD!!! */
-int board_au1200fb_panel(void)
-{
-       return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f;
-}
+       platform_add_devices(db1200_devs, ARRAY_SIZE(db1200_devs));
 
-int board_au1200fb_panel_init(void)
-{
-       /* Apply power */
-       bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
-                               BCSR_BOARD_LCDBL);
-       return 0;
-}
+       /* PB1200 is a DB1200 with a 2nd MMC and Camera connector */
+       if ((bid == BCSR_WHOAMI_PB1200_DDR1) ||
+           (bid == BCSR_WHOAMI_PB1200_DDR2))
+               platform_add_devices(pb1200_devs, ARRAY_SIZE(pb1200_devs));
 
-int board_au1200fb_panel_shutdown(void)
-{
-       /* Remove power */
-       bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
-                            BCSR_BOARD_LCDBL, 0);
        return 0;
 }
+device_initcall(db1200_dev_init);
diff --git a/arch/mips/alchemy/devboards/db1200/Makefile b/arch/mips/alchemy/devboards/db1200/Makefile
deleted file mode 100644 (file)
index 17840a5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-y += setup.o platform.o
diff --git a/arch/mips/alchemy/devboards/db1200/setup.c b/arch/mips/alchemy/devboards/db1200/setup.c
deleted file mode 100644 (file)
index 4a89800..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Alchemy/AMD/RMI DB1200 board setup.
- *
- * Licensed under the terms outlined in the file COPYING in the root of
- * this source archive.
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-db1x00/bcsr.h>
-#include <asm/mach-db1x00/db1200.h>
-
-const char *get_system_type(void)
-{
-       return "Alchemy Db1200";
-}
-
-void __init board_setup(void)
-{
-       unsigned long freq0, clksrc, div, pfc;
-       unsigned short whoami;
-
-       bcsr_init(DB1200_BCSR_PHYS_ADDR,
-                 DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS);
-
-       whoami = bcsr_read(BCSR_WHOAMI);
-       printk(KERN_INFO "Alchemy/AMD/RMI DB1200 Board, CPLD Rev %d"
-               "  Board-ID %d  Daughtercard ID %d\n",
-               (whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf);
-
-       /* SMBus/SPI on PSC0, Audio on PSC1 */
-       pfc = __raw_readl((void __iomem *)SYS_PINFUNC);
-       pfc &= ~(SYS_PINFUNC_P0A | SYS_PINFUNC_P0B);
-       pfc &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B | SYS_PINFUNC_FS3);
-       pfc |= SYS_PINFUNC_P1C; /* SPI is configured later */
-       __raw_writel(pfc, (void __iomem *)SYS_PINFUNC);
-       wmb();
-
-       /* Clock configurations: PSC0: ~50MHz via Clkgen0, derived from
-        * CPU clock; all other clock generators off/unused.
-        */
-       div = (get_au1x00_speed() + 25000000) / 50000000;
-       if (div & 1)
-               div++;
-       div = ((div >> 1) - 1) & 0xff;
-
-       freq0 = div << SYS_FC_FRDIV0_BIT;
-       __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0);
-       wmb();
-       freq0 |= SYS_FC_FE0;    /* enable F0 */
-       __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0);
-       wmb();
-
-       /* psc0_intclk comes 1:1 from F0 */
-       clksrc = SYS_CS_MUX_FQ0 << SYS_CS_ME0_BIT;
-       __raw_writel(clksrc, (void __iomem *)SYS_CLKSRC);
-       wmb();
-}
-
-static int __init db1200_arch_init(void)
-{
-       /* GPIO7 is low-level triggered CPLD cascade */
-       irq_set_irq_type(AU1200_GPIO7_INT, IRQF_TRIGGER_LOW);
-       bcsr_init_irq(DB1200_INT_BEGIN, DB1200_INT_END, AU1200_GPIO7_INT);
-
-       /* insert/eject pairs: one of both is always screaming.  To avoid
-        * issues they must not be automatically enabled when initially
-        * requested.
-        */
-       irq_set_status_flags(DB1200_SD0_INSERT_INT, IRQ_NOAUTOEN);
-       irq_set_status_flags(DB1200_SD0_EJECT_INT, IRQ_NOAUTOEN);
-       irq_set_status_flags(DB1200_PC0_INSERT_INT, IRQ_NOAUTOEN);
-       irq_set_status_flags(DB1200_PC0_EJECT_INT, IRQ_NOAUTOEN);
-       irq_set_status_flags(DB1200_PC1_INSERT_INT, IRQ_NOAUTOEN);
-       irq_set_status_flags(DB1200_PC1_EJECT_INT, IRQ_NOAUTOEN);
-       return 0;
-}
-arch_initcall(db1200_arch_init);
diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c
new file mode 100644 (file)
index 0000000..0893f2a
--- /dev/null
@@ -0,0 +1,785 @@
+/*
+ * DBAu1300 init and platform device setup.
+ *
+ * (c) 2009 Manuel Lauss <manuel.lauss@googlemail.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/init.h>
+#include <linux/input.h>       /* KEY_* codes */
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/ata_platform.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/smsc911x.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1100_mmc.h>
+#include <asm/mach-au1x00/au1200fb.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+#include <asm/mach-db1x00/db1300.h>
+#include <asm/mach-db1x00/bcsr.h>
+#include <asm/mach-au1x00/prom.h>
+
+#include "platform.h"
+
+static struct i2c_board_info db1300_i2c_devs[] __initdata = {
+       { I2C_BOARD_INFO("wm8731", 0x1b), },    /* I2S audio codec */
+       { I2C_BOARD_INFO("ne1619", 0x2d), },    /* adm1025-compat hwmon */
+};
+
+/* multifunction pins to assign to GPIO controller */
+static int db1300_gpio_pins[] __initdata = {
+       AU1300_PIN_LCDPWM0, AU1300_PIN_PSC2SYNC1, AU1300_PIN_WAKE1,
+       AU1300_PIN_WAKE2, AU1300_PIN_WAKE3, AU1300_PIN_FG3AUX,
+       AU1300_PIN_EXTCLK1,
+       -1,     /* terminator */
+};
+
+/* multifunction pins to assign to device functions */
+static int db1300_dev_pins[] __initdata = {
+       /* wake-from-str pins 0-3 */
+       AU1300_PIN_WAKE0,
+       /* external clock sources for PSC0 */
+       AU1300_PIN_EXTCLK0,
+       /* 8bit MMC interface on SD0: 6-9 */
+       AU1300_PIN_SD0DAT4, AU1300_PIN_SD0DAT5, AU1300_PIN_SD0DAT6,
+       AU1300_PIN_SD0DAT7,
+       /* UART1 pins: 11-18 */
+       AU1300_PIN_U1RI, AU1300_PIN_U1DCD, AU1300_PIN_U1DSR,
+       AU1300_PIN_U1CTS, AU1300_PIN_U1RTS, AU1300_PIN_U1DTR,
+       AU1300_PIN_U1RX, AU1300_PIN_U1TX,
+       /* UART0 pins: 19-24 */
+       AU1300_PIN_U0RI, AU1300_PIN_U0DCD, AU1300_PIN_U0DSR,
+       AU1300_PIN_U0CTS, AU1300_PIN_U0RTS, AU1300_PIN_U0DTR,
+       /* UART2: 25-26 */
+       AU1300_PIN_U2RX, AU1300_PIN_U2TX,
+       /* UART3: 27-28 */
+       AU1300_PIN_U3RX, AU1300_PIN_U3TX,
+       /* LCD controller PWMs, ext pixclock: 30-31 */
+       AU1300_PIN_LCDPWM1, AU1300_PIN_LCDCLKIN,
+       /* SD1 interface: 32-37 */
+       AU1300_PIN_SD1DAT0, AU1300_PIN_SD1DAT1, AU1300_PIN_SD1DAT2,
+       AU1300_PIN_SD1DAT3, AU1300_PIN_SD1CMD, AU1300_PIN_SD1CLK,
+       /* SD2 interface: 38-43 */
+       AU1300_PIN_SD2DAT0, AU1300_PIN_SD2DAT1, AU1300_PIN_SD2DAT2,
+       AU1300_PIN_SD2DAT3, AU1300_PIN_SD2CMD, AU1300_PIN_SD2CLK,
+       /* PSC0/1 clocks: 44-45 */
+       AU1300_PIN_PSC0CLK, AU1300_PIN_PSC1CLK,
+       /* PSCs: 46-49/50-53/54-57/58-61 */
+       AU1300_PIN_PSC0SYNC0, AU1300_PIN_PSC0SYNC1, AU1300_PIN_PSC0D0,
+       AU1300_PIN_PSC0D1,
+       AU1300_PIN_PSC1SYNC0, AU1300_PIN_PSC1SYNC1, AU1300_PIN_PSC1D0,
+       AU1300_PIN_PSC1D1,
+       AU1300_PIN_PSC2SYNC0,                       AU1300_PIN_PSC2D0,
+       AU1300_PIN_PSC2D1,
+       AU1300_PIN_PSC3SYNC0, AU1300_PIN_PSC3SYNC1, AU1300_PIN_PSC3D0,
+       AU1300_PIN_PSC3D1,
+       /* PCMCIA interface: 62-70 */
+       AU1300_PIN_PCE2, AU1300_PIN_PCE1, AU1300_PIN_PIOS16,
+       AU1300_PIN_PIOR, AU1300_PIN_PWE, AU1300_PIN_PWAIT,
+       AU1300_PIN_PREG, AU1300_PIN_POE, AU1300_PIN_PIOW,
+       /* camera interface H/V sync inputs: 71-72 */
+       AU1300_PIN_CIMLS, AU1300_PIN_CIMFS,
+       /* PSC2/3 clocks: 73-74 */
+       AU1300_PIN_PSC2CLK, AU1300_PIN_PSC3CLK,
+       -1,     /* terminator */
+};
+
+static void __init db1300_gpio_config(void)
+{
+       int *i;
+
+       i = &db1300_dev_pins[0];
+       while (*i != -1)
+               au1300_pinfunc_to_dev(*i++);
+
+       i = &db1300_gpio_pins[0];
+       while (*i != -1)
+               au1300_gpio_direction_input(*i++);/* implies pin_to_gpio */
+
+       au1300_set_dbdma_gpio(1, AU1300_PIN_FG3AUX);
+}
+
+char *get_system_type(void)
+{
+       return "DB1300";
+}
+
+/**********************************************************************/
+
+static void au1300_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+                                unsigned int ctrl)
+{
+       struct nand_chip *this = mtd->priv;
+       unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
+
+       ioaddr &= 0xffffff00;
+
+       if (ctrl & NAND_CLE) {
+               ioaddr += MEM_STNAND_CMD;
+       } else if (ctrl & NAND_ALE) {
+               ioaddr += MEM_STNAND_ADDR;
+       } else {
+               /* assume we want to r/w real data  by default */
+               ioaddr += MEM_STNAND_DATA;
+       }
+       this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr;
+       if (cmd != NAND_CMD_NONE) {
+               __raw_writeb(cmd, this->IO_ADDR_W);
+               wmb();
+       }
+}
+
+static int au1300_nand_device_ready(struct mtd_info *mtd)
+{
+       return __raw_readl((void __iomem *)MEM_STSTAT) & 1;
+}
+
+static const char *db1300_part_probes[] = { "cmdlinepart", NULL };
+
+static struct mtd_partition db1300_nand_parts[] = {
+       {
+               .name   = "NAND FS 0",
+               .offset = 0,
+               .size   = 8 * 1024 * 1024,
+       },
+       {
+               .name   = "NAND FS 1",
+               .offset = MTDPART_OFS_APPEND,
+               .size   = MTDPART_SIZ_FULL
+       },
+};
+
+struct platform_nand_data db1300_nand_platdata = {
+       .chip = {
+               .nr_chips       = 1,
+               .chip_offset    = 0,
+               .nr_partitions  = ARRAY_SIZE(db1300_nand_parts),
+               .partitions     = db1300_nand_parts,
+               .chip_delay     = 20,
+               .part_probe_types = db1300_part_probes,
+       },
+       .ctrl = {
+               .dev_ready      = au1300_nand_device_ready,
+               .cmd_ctrl       = au1300_nand_cmd_ctrl,
+       },
+};
+
+static struct resource db1300_nand_res[] = {
+       [0] = {
+               .start  = DB1300_NAND_PHYS_ADDR,
+               .end    = DB1300_NAND_PHYS_ADDR + 0xff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device db1300_nand_dev = {
+       .name           = "gen_nand",
+       .num_resources  = ARRAY_SIZE(db1300_nand_res),
+       .resource       = db1300_nand_res,
+       .id             = -1,
+       .dev            = {
+               .platform_data = &db1300_nand_platdata,
+       }
+};
+
+/**********************************************************************/
+
+static struct resource db1300_eth_res[] = {
+       [0] = {
+               .start          = DB1300_ETH_PHYS_ADDR,
+               .end            = DB1300_ETH_PHYS_END,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = DB1300_ETH_INT,
+               .end            = DB1300_ETH_INT,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct smsc911x_platform_config db1300_eth_config = {
+       .phy_interface          = PHY_INTERFACE_MODE_MII,
+       .irq_polarity           = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type               = SMSC911X_IRQ_TYPE_PUSH_PULL,
+       .flags                  = SMSC911X_USE_32BIT,
+};
+
+static struct platform_device db1300_eth_dev = {
+       .name                   = "smsc911x",
+       .id                     = -1,
+       .num_resources          = ARRAY_SIZE(db1300_eth_res),
+       .resource               = db1300_eth_res,
+       .dev = {
+               .platform_data  = &db1300_eth_config,
+       },
+};
+
+/**********************************************************************/
+
+static struct resource au1300_psc1_res[] = {
+       [0] = {
+               .start  = AU1300_PSC1_PHYS_ADDR,
+               .end    = AU1300_PSC1_PHYS_ADDR + 0x0fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1300_PSC1_INT,
+               .end    = AU1300_PSC1_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = AU1300_DSCR_CMD0_PSC1_TX,
+               .end    = AU1300_DSCR_CMD0_PSC1_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = AU1300_DSCR_CMD0_PSC1_RX,
+               .end    = AU1300_DSCR_CMD0_PSC1_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device db1300_ac97_dev = {
+       .name           = "au1xpsc_ac97",
+       .id             = 1,    /* PSC ID. match with AC97 codec ID! */
+       .num_resources  = ARRAY_SIZE(au1300_psc1_res),
+       .resource       = au1300_psc1_res,
+};
+
+/**********************************************************************/
+
+static struct resource au1300_psc2_res[] = {
+       [0] = {
+               .start  = AU1300_PSC2_PHYS_ADDR,
+               .end    = AU1300_PSC2_PHYS_ADDR + 0x0fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1300_PSC2_INT,
+               .end    = AU1300_PSC2_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = AU1300_DSCR_CMD0_PSC2_TX,
+               .end    = AU1300_DSCR_CMD0_PSC2_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = AU1300_DSCR_CMD0_PSC2_RX,
+               .end    = AU1300_DSCR_CMD0_PSC2_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device db1300_i2s_dev = {
+       .name           = "au1xpsc_i2s",
+       .id             = 2,    /* PSC ID */
+       .num_resources  = ARRAY_SIZE(au1300_psc2_res),
+       .resource       = au1300_psc2_res,
+};
+
+/**********************************************************************/
+
+static struct resource au1300_psc3_res[] = {
+       [0] = {
+               .start  = AU1300_PSC3_PHYS_ADDR,
+               .end    = AU1300_PSC3_PHYS_ADDR + 0x0fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1300_PSC3_INT,
+               .end    = AU1300_PSC3_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = AU1300_DSCR_CMD0_PSC3_TX,
+               .end    = AU1300_DSCR_CMD0_PSC3_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = AU1300_DSCR_CMD0_PSC3_RX,
+               .end    = AU1300_DSCR_CMD0_PSC3_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device db1300_i2c_dev = {
+       .name           = "au1xpsc_smbus",
+       .id             = 0,    /* bus number */
+       .num_resources  = ARRAY_SIZE(au1300_psc3_res),
+       .resource       = au1300_psc3_res,
+};
+
+/**********************************************************************/
+
+/* proper key assignments when facing the LCD panel.  For key assignments
+ * according to the schematics swap up with down and left with right.
+ * I chose to use it to emulate the arrow keys of a keyboard.
+ */
+static struct gpio_keys_button db1300_5waysw_arrowkeys[] = {
+       {
+               .code                   = KEY_DOWN,
+               .gpio                   = AU1300_PIN_LCDPWM0,
+               .type                   = EV_KEY,
+               .debounce_interval      = 1,
+               .active_low             = 1,
+               .desc                   = "5waysw-down",
+       },
+       {
+               .code                   = KEY_UP,
+               .gpio                   = AU1300_PIN_PSC2SYNC1,
+               .type                   = EV_KEY,
+               .debounce_interval      = 1,
+               .active_low             = 1,
+               .desc                   = "5waysw-up",
+       },
+       {
+               .code                   = KEY_RIGHT,
+               .gpio                   = AU1300_PIN_WAKE3,
+               .type                   = EV_KEY,
+               .debounce_interval      = 1,
+               .active_low             = 1,
+               .desc                   = "5waysw-right",
+       },
+       {
+               .code                   = KEY_LEFT,
+               .gpio                   = AU1300_PIN_WAKE2,
+               .type                   = EV_KEY,
+               .debounce_interval      = 1,
+               .active_low             = 1,
+               .desc                   = "5waysw-left",
+       },
+       {
+               .code                   = KEY_ENTER,
+               .gpio                   = AU1300_PIN_WAKE1,
+               .type                   = EV_KEY,
+               .debounce_interval      = 1,
+               .active_low             = 1,
+               .desc                   = "5waysw-push",
+       },
+};
+
+static struct gpio_keys_platform_data db1300_5waysw_data = {
+       .buttons        = db1300_5waysw_arrowkeys,
+       .nbuttons       = ARRAY_SIZE(db1300_5waysw_arrowkeys),
+       .rep            = 1,
+       .name           = "db1300-5wayswitch",
+};
+
+static struct platform_device db1300_5waysw_dev = {
+       .name           = "gpio-keys",
+       .dev    = {
+               .platform_data  = &db1300_5waysw_data,
+       },
+};
+
+/**********************************************************************/
+
+static struct pata_platform_info db1300_ide_info = {
+       .ioport_shift   = DB1300_IDE_REG_SHIFT,
+};
+
+#define IDE_ALT_START  (14 << DB1300_IDE_REG_SHIFT)
+static struct resource db1300_ide_res[] = {
+       [0] = {
+               .start  = DB1300_IDE_PHYS_ADDR,
+               .end    = DB1300_IDE_PHYS_ADDR + IDE_ALT_START - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DB1300_IDE_PHYS_ADDR + IDE_ALT_START,
+               .end    = DB1300_IDE_PHYS_ADDR + DB1300_IDE_PHYS_LEN - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start  = DB1300_IDE_INT,
+               .end    = DB1300_IDE_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device db1300_ide_dev = {
+       .dev    = {
+               .platform_data  = &db1300_ide_info,
+       },
+       .name           = "pata_platform",
+       .resource       = db1300_ide_res,
+       .num_resources  = ARRAY_SIZE(db1300_ide_res),
+};
+
+/**********************************************************************/
+
+static irqreturn_t db1300_mmc_cd(int irq, void *ptr)
+{
+       void(*mmc_cd)(struct mmc_host *, unsigned long);
+
+       /* disable the one currently screaming. No other way to shut it up */
+       if (irq == DB1300_SD1_INSERT_INT) {
+               disable_irq_nosync(DB1300_SD1_INSERT_INT);
+               enable_irq(DB1300_SD1_EJECT_INT);
+       } else {
+               disable_irq_nosync(DB1300_SD1_EJECT_INT);
+               enable_irq(DB1300_SD1_INSERT_INT);
+       }
+
+       /* link against CONFIG_MMC=m.  We can only be called once MMC core has
+        * initialized the controller, so symbol_get() should always succeed.
+        */
+       mmc_cd = symbol_get(mmc_detect_change);
+       mmc_cd(ptr, msecs_to_jiffies(500));
+       symbol_put(mmc_detect_change);
+
+       return IRQ_HANDLED;
+}
+
+static int db1300_mmc_card_readonly(void *mmc_host)
+{
+       /* it uses SD1 interface, but the DB1200's SD0 bit in the CPLD */
+       return bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP;
+}
+
+static int db1300_mmc_card_inserted(void *mmc_host)
+{
+       return bcsr_read(BCSR_SIGSTAT) & (1 << 12); /* insertion irq signal */
+}
+
+static int db1300_mmc_cd_setup(void *mmc_host, int en)
+{
+       int ret;
+
+       if (en) {
+               ret = request_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd, 0,
+                                 "sd_insert", mmc_host);
+               if (ret)
+                       goto out;
+
+               ret = request_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd, 0,
+                                 "sd_eject", mmc_host);
+               if (ret) {
+                       free_irq(DB1300_SD1_INSERT_INT, mmc_host);
+                       goto out;
+               }
+
+               if (db1300_mmc_card_inserted(mmc_host))
+                       enable_irq(DB1300_SD1_EJECT_INT);
+               else
+                       enable_irq(DB1300_SD1_INSERT_INT);
+
+       } else {
+               free_irq(DB1300_SD1_INSERT_INT, mmc_host);
+               free_irq(DB1300_SD1_EJECT_INT, mmc_host);
+       }
+       ret = 0;
+out:
+       return ret;
+}
+
+static void db1300_mmcled_set(struct led_classdev *led,
+                             enum led_brightness brightness)
+{
+       if (brightness != LED_OFF)
+               bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0);
+       else
+               bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0);
+}
+
+static struct led_classdev db1300_mmc_led = {
+       .brightness_set = db1300_mmcled_set,
+};
+
+struct au1xmmc_platform_data db1300_sd1_platdata = {
+       .cd_setup       = db1300_mmc_cd_setup,
+       .card_inserted  = db1300_mmc_card_inserted,
+       .card_readonly  = db1300_mmc_card_readonly,
+       .led            = &db1300_mmc_led,
+};
+
+static struct resource au1300_sd1_res[] = {
+       [0] = {
+               .start  = AU1300_SD1_PHYS_ADDR,
+               .end    = AU1300_SD1_PHYS_ADDR,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1300_SD1_INT,
+               .end    = AU1300_SD1_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = AU1300_DSCR_CMD0_SDMS_TX1,
+               .end    = AU1300_DSCR_CMD0_SDMS_TX1,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = AU1300_DSCR_CMD0_SDMS_RX1,
+               .end    = AU1300_DSCR_CMD0_SDMS_RX1,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device db1300_sd1_dev = {
+       .dev = {
+               .platform_data  = &db1300_sd1_platdata,
+       },
+       .name           = "au1xxx-mmc",
+       .id             = 1,
+       .resource       = au1300_sd1_res,
+       .num_resources  = ARRAY_SIZE(au1300_sd1_res),
+};
+
+/**********************************************************************/
+
+static int db1300_movinand_inserted(void *mmc_host)
+{
+       return 0; /* disable for now, it doesn't work yet */
+}
+
+static int db1300_movinand_readonly(void *mmc_host)
+{
+       return 0;
+}
+
+static void db1300_movinand_led_set(struct led_classdev *led,
+                                   enum led_brightness brightness)
+{
+       if (brightness != LED_OFF)
+               bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0);
+       else
+               bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1);
+}
+
+static struct led_classdev db1300_movinand_led = {
+       .brightness_set         = db1300_movinand_led_set,
+};
+
+struct au1xmmc_platform_data db1300_sd0_platdata = {
+       .card_inserted          = db1300_movinand_inserted,
+       .card_readonly          = db1300_movinand_readonly,
+       .led                    = &db1300_movinand_led,
+       .mask_host_caps         = MMC_CAP_NEEDS_POLL,
+};
+
+static struct resource au1300_sd0_res[] = {
+       [0] = {
+               .start  = AU1100_SD0_PHYS_ADDR,
+               .end    = AU1100_SD0_PHYS_ADDR,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1300_SD0_INT,
+               .end    = AU1300_SD0_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = AU1300_DSCR_CMD0_SDMS_TX0,
+               .end    = AU1300_DSCR_CMD0_SDMS_TX0,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = AU1300_DSCR_CMD0_SDMS_RX0,
+               .end    = AU1300_DSCR_CMD0_SDMS_RX0,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device db1300_sd0_dev = {
+       .dev = {
+               .platform_data  = &db1300_sd0_platdata,
+       },
+       .name           = "au1xxx-mmc",
+       .id             = 0,
+       .resource       = au1300_sd0_res,
+       .num_resources  = ARRAY_SIZE(au1300_sd0_res),
+};
+
+/**********************************************************************/
+
+static struct platform_device db1300_wm9715_dev = {
+       .name           = "wm9712-codec",
+       .id             = 1,    /* ID of PSC for AC97 audio, see asoc glue! */
+};
+
+static struct platform_device db1300_ac97dma_dev = {
+       .name           = "au1xpsc-pcm",
+       .id             = 1,    /* PSC ID */
+};
+
+static struct platform_device db1300_i2sdma_dev = {
+       .name           = "au1xpsc-pcm",
+       .id             = 2,    /* PSC ID */
+};
+
+static struct platform_device db1300_sndac97_dev = {
+       .name           = "db1300-ac97",
+};
+
+static struct platform_device db1300_sndi2s_dev = {
+       .name           = "db1300-i2s",
+};
+
+/**********************************************************************/
+
+static int db1300fb_panel_index(void)
+{
+       return 9;       /* DB1300_800x480 */
+}
+
+static int db1300fb_panel_init(void)
+{
+       /* Apply power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */
+       bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD,
+                            BCSR_BOARD_LCDBL);
+       return 0;
+}
+
+static int db1300fb_panel_shutdown(void)
+{
+       /* Remove power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */
+       bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDBL,
+                            BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD);
+       return 0;
+}
+
+static struct au1200fb_platdata db1300fb_pd = {
+       .panel_index    = db1300fb_panel_index,
+       .panel_init     = db1300fb_panel_init,
+       .panel_shutdown = db1300fb_panel_shutdown,
+};
+
+static struct resource au1300_lcd_res[] = {
+       [0] = {
+               .start  = AU1200_LCD_PHYS_ADDR,
+               .end    = AU1200_LCD_PHYS_ADDR + 0x800 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1300_LCD_INT,
+               .end    = AU1300_LCD_INT,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+static u64 au1300_lcd_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device db1300_lcd_dev = {
+       .name           = "au1200-lcd",
+       .id             = 0,
+       .dev = {
+               .dma_mask               = &au1300_lcd_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &db1300fb_pd,
+       },
+       .num_resources  = ARRAY_SIZE(au1300_lcd_res),
+       .resource       = au1300_lcd_res,
+};
+
+/**********************************************************************/
+
+static struct platform_device *db1300_dev[] __initdata = {
+       &db1300_eth_dev,
+       &db1300_i2c_dev,
+       &db1300_5waysw_dev,
+       &db1300_nand_dev,
+       &db1300_ide_dev,
+       &db1300_sd0_dev,
+       &db1300_sd1_dev,
+       &db1300_lcd_dev,
+       &db1300_ac97_dev,
+       &db1300_i2s_dev,
+       &db1300_wm9715_dev,
+       &db1300_ac97dma_dev,
+       &db1300_i2sdma_dev,
+       &db1300_sndac97_dev,
+       &db1300_sndi2s_dev,
+};
+
+static int __init db1300_device_init(void)
+{
+       int swapped, cpldirq;
+
+       /* setup CPLD IRQ muxer */
+       cpldirq = au1300_gpio_to_irq(AU1300_PIN_EXTCLK1);
+       irq_set_irq_type(cpldirq, IRQ_TYPE_LEVEL_HIGH);
+       bcsr_init_irq(DB1300_FIRST_INT, DB1300_LAST_INT, cpldirq);
+
+       /* insert/eject IRQs: one always triggers so don't enable them
+        * when doing request_irq() on them.  DB1200 has this bug too.
+        */
+       irq_set_status_flags(DB1300_SD1_INSERT_INT, IRQ_NOAUTOEN);
+       irq_set_status_flags(DB1300_SD1_EJECT_INT, IRQ_NOAUTOEN);
+       irq_set_status_flags(DB1300_CF_INSERT_INT, IRQ_NOAUTOEN);
+       irq_set_status_flags(DB1300_CF_EJECT_INT, IRQ_NOAUTOEN);
+
+       /*
+        * setup board
+        */
+       prom_get_ethernet_addr(&db1300_eth_config.mac[0]);
+
+       i2c_register_board_info(0, db1300_i2c_devs,
+                               ARRAY_SIZE(db1300_i2c_devs));
+
+       /* Audio PSC clock is supplied by codecs (PSC1, 2) */
+       __raw_writel(PSC_SEL_CLK_SERCLK,
+           (void __iomem *)KSEG1ADDR(AU1300_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
+       wmb();
+       __raw_writel(PSC_SEL_CLK_SERCLK,
+           (void __iomem *)KSEG1ADDR(AU1300_PSC2_PHYS_ADDR) + PSC_SEL_OFFSET);
+       wmb();
+       /* I2C uses internal 48MHz EXTCLK1 */
+       __raw_writel(PSC_SEL_CLK_INTCLK,
+           (void __iomem *)KSEG1ADDR(AU1300_PSC3_PHYS_ADDR) + PSC_SEL_OFFSET);
+       wmb();
+
+       /* enable power to USB ports */
+       bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_USBHPWR | BCSR_RESETS_OTGPWR);
+
+       /* although it is socket #0, it uses the CPLD bits which previous boards
+        * have used for socket #1.
+        */
+       db1x_register_pcmcia_socket(
+               AU1000_PCMCIA_ATTR_PHYS_ADDR,
+               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x00400000 - 1,
+               AU1000_PCMCIA_MEM_PHYS_ADDR,
+               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x00400000 - 1,
+               AU1000_PCMCIA_IO_PHYS_ADDR,
+               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x00010000 - 1,
+               DB1300_CF_INT, DB1300_CF_INSERT_INT, 0, DB1300_CF_EJECT_INT, 1);
+
+       swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT;
+       db1x_register_norflash(64 << 20, 2, swapped);
+
+       return platform_add_devices(db1300_dev, ARRAY_SIZE(db1300_dev));
+}
+device_initcall(db1300_device_init);
+
+
+void __init board_setup(void)
+{
+       unsigned short whoami;
+
+       db1300_gpio_config();
+       bcsr_init(DB1300_BCSR_PHYS_ADDR,
+                 DB1300_BCSR_PHYS_ADDR + DB1300_BCSR_HEXLED_OFS);
+
+       whoami = bcsr_read(BCSR_WHOAMI);
+       printk(KERN_INFO "NetLogic DBAu1300 Development Platform.\n\t"
+               "BoardID %d   CPLD Rev %d   DaughtercardID %d\n",
+               BCSR_WHOAMI_BOARD(whoami), BCSR_WHOAMI_CPLD(whoami),
+               BCSR_WHOAMI_DCID(whoami));
+
+       /* enable UARTs, YAMON only enables #2 */
+       alchemy_uart_enable(AU1300_UART0_PHYS_ADDR);
+       alchemy_uart_enable(AU1300_UART1_PHYS_ADDR);
+       alchemy_uart_enable(AU1300_UART3_PHYS_ADDR);
+}
diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c
new file mode 100644 (file)
index 0000000..6815d07
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * Alchemy Db1550 board support
+ *
+ * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_eth.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+#include <asm/mach-au1x00/au1550_spi.h>
+#include <asm/mach-db1x00/bcsr.h>
+#include <prom.h>
+#include "platform.h"
+
+
+const char *get_system_type(void)
+{
+       return "DB1550";
+}
+
+static void __init db1550_hw_setup(void)
+{
+       void __iomem *base;
+
+       alchemy_gpio_direction_output(203, 0);  /* red led on */
+
+       /* complete SPI setup: link psc0_intclk to a 48MHz source,
+        * and assign GPIO16 to PSC0_SYNC1 (SPI cs# line)
+        */
+       base = (void __iomem *)SYS_CLKSRC;
+       __raw_writel(__raw_readl(base) | 0x000001e0, base);
+       base = (void __iomem *)SYS_PINFUNC;
+       __raw_writel(__raw_readl(base) | 1, base);
+       wmb();
+
+       /* reset the AC97 codec now, the reset time in the psc-ac97 driver
+        * is apparently too short although it's ridiculous as it is.
+        */
+       base = (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR);
+       __raw_writel(PSC_SEL_CLK_SERCLK | PSC_SEL_PS_AC97MODE,
+                    base + PSC_SEL_OFFSET);
+       __raw_writel(PSC_CTRL_DISABLE, base + PSC_CTRL_OFFSET);
+       wmb();
+       __raw_writel(PSC_AC97RST_RST, base + PSC_AC97RST_OFFSET);
+       wmb();
+
+       alchemy_gpio_direction_output(202, 0);  /* green led on */
+}
+
+void __init board_setup(void)
+{
+       unsigned short whoami;
+
+       bcsr_init(DB1550_BCSR_PHYS_ADDR,
+                 DB1550_BCSR_PHYS_ADDR + DB1550_BCSR_HEXLED_OFS);
+
+       whoami = bcsr_read(BCSR_WHOAMI);
+       printk(KERN_INFO "Alchemy/AMD DB1550 Board, CPLD Rev %d"
+               "  Board-ID %d  Daughtercard ID %d\n",
+               (whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf);
+
+       db1550_hw_setup();
+}
+
+/*****************************************************************************/
+
+static struct mtd_partition db1550_spiflash_parts[] = {
+       {
+               .name   = "spi_flash",
+               .offset = 0,
+               .size   = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct flash_platform_data db1550_spiflash_data = {
+       .name           = "s25fl010",
+       .parts          = db1550_spiflash_parts,
+       .nr_parts       = ARRAY_SIZE(db1550_spiflash_parts),
+       .type           = "m25p10",
+};
+
+static struct spi_board_info db1550_spi_devs[] __initdata = {
+       {
+               /* TI TMP121AIDBVR temp sensor */
+               .modalias       = "tmp121",
+               .max_speed_hz   = 2400000,
+               .bus_num        = 0,
+               .chip_select    = 0,
+               .mode           = SPI_MODE_0,
+       },
+       {
+               /* Spansion S25FL001D0FMA SPI flash */
+               .modalias       = "m25p80",
+               .max_speed_hz   = 2400000,
+               .bus_num        = 0,
+               .chip_select    = 1,
+               .mode           = SPI_MODE_0,
+               .platform_data  = &db1550_spiflash_data,
+       },
+};
+
+static struct i2c_board_info db1550_i2c_devs[] __initdata = {
+       { I2C_BOARD_INFO("24c04",  0x52),}, /* AT24C04-10 I2C eeprom */
+       { I2C_BOARD_INFO("ne1619", 0x2d),}, /* adm1025-compat hwmon */
+       { I2C_BOARD_INFO("wm8731", 0x1b),}, /* I2S audio codec WM8731 */
+};
+
+/**********************************************************************/
+
+static void au1550_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+                                unsigned int ctrl)
+{
+       struct nand_chip *this = mtd->priv;
+       unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;
+
+       ioaddr &= 0xffffff00;
+
+       if (ctrl & NAND_CLE) {
+               ioaddr += MEM_STNAND_CMD;
+       } else if (ctrl & NAND_ALE) {
+               ioaddr += MEM_STNAND_ADDR;
+       } else {
+               /* assume we want to r/w real data  by default */
+               ioaddr += MEM_STNAND_DATA;
+       }
+       this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr;
+       if (cmd != NAND_CMD_NONE) {
+               __raw_writeb(cmd, this->IO_ADDR_W);
+               wmb();
+       }
+}
+
+static int au1550_nand_device_ready(struct mtd_info *mtd)
+{
+       return __raw_readl((void __iomem *)MEM_STSTAT) & 1;
+}
+
+static const char *db1550_part_probes[] = { "cmdlinepart", NULL };
+
+static struct mtd_partition db1550_nand_parts[] = {
+       {
+               .name   = "NAND FS 0",
+               .offset = 0,
+               .size   = 8 * 1024 * 1024,
+       },
+       {
+               .name   = "NAND FS 1",
+               .offset = MTDPART_OFS_APPEND,
+               .size   = MTDPART_SIZ_FULL
+       },
+};
+
+struct platform_nand_data db1550_nand_platdata = {
+       .chip = {
+               .nr_chips       = 1,
+               .chip_offset    = 0,
+               .nr_partitions  = ARRAY_SIZE(db1550_nand_parts),
+               .partitions     = db1550_nand_parts,
+               .chip_delay     = 20,
+               .part_probe_types = db1550_part_probes,
+       },
+       .ctrl = {
+               .dev_ready      = au1550_nand_device_ready,
+               .cmd_ctrl       = au1550_nand_cmd_ctrl,
+       },
+};
+
+static struct resource db1550_nand_res[] = {
+       [0] = {
+               .start  = 0x20000000,
+               .end    = 0x200000ff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device db1550_nand_dev = {
+       .name           = "gen_nand",
+       .num_resources  = ARRAY_SIZE(db1550_nand_res),
+       .resource       = db1550_nand_res,
+       .id             = -1,
+       .dev            = {
+               .platform_data = &db1550_nand_platdata,
+       }
+};
+
+/**********************************************************************/
+
+static struct resource au1550_psc0_res[] = {
+       [0] = {
+               .start  = AU1550_PSC0_PHYS_ADDR,
+               .end    = AU1550_PSC0_PHYS_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1550_PSC0_INT,
+               .end    = AU1550_PSC0_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = AU1550_DSCR_CMD0_PSC0_TX,
+               .end    = AU1550_DSCR_CMD0_PSC0_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = AU1550_DSCR_CMD0_PSC0_RX,
+               .end    = AU1550_DSCR_CMD0_PSC0_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static void db1550_spi_cs_en(struct au1550_spi_info *spi, int cs, int pol)
+{
+       if (cs)
+               bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SPISEL);
+       else
+               bcsr_mod(BCSR_BOARD, BCSR_BOARD_SPISEL, 0);
+}
+
+static struct au1550_spi_info db1550_spi_platdata = {
+       .mainclk_hz     = 48000000,     /* PSC0 clock: max. 2.4MHz SPI clk */
+       .num_chipselect = 2,
+       .activate_cs    = db1550_spi_cs_en,
+};
+
+static u64 spi_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device db1550_spi_dev = {
+       .dev    = {
+               .dma_mask               = &spi_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &db1550_spi_platdata,
+       },
+       .name           = "au1550-spi",
+       .id             = 0,    /* bus number */
+       .num_resources  = ARRAY_SIZE(au1550_psc0_res),
+       .resource       = au1550_psc0_res,
+};
+
+/**********************************************************************/
+
+static struct resource au1550_psc1_res[] = {
+       [0] = {
+               .start  = AU1550_PSC1_PHYS_ADDR,
+               .end    = AU1550_PSC1_PHYS_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1550_PSC1_INT,
+               .end    = AU1550_PSC1_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = AU1550_DSCR_CMD0_PSC1_TX,
+               .end    = AU1550_DSCR_CMD0_PSC1_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = AU1550_DSCR_CMD0_PSC1_RX,
+               .end    = AU1550_DSCR_CMD0_PSC1_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device db1550_ac97_dev = {
+       .name           = "au1xpsc_ac97",
+       .id             = 1,    /* PSC ID */
+       .num_resources  = ARRAY_SIZE(au1550_psc1_res),
+       .resource       = au1550_psc1_res,
+};
+
+
+static struct resource au1550_psc2_res[] = {
+       [0] = {
+               .start  = AU1550_PSC2_PHYS_ADDR,
+               .end    = AU1550_PSC2_PHYS_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1550_PSC2_INT,
+               .end    = AU1550_PSC2_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = AU1550_DSCR_CMD0_PSC2_TX,
+               .end    = AU1550_DSCR_CMD0_PSC2_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = AU1550_DSCR_CMD0_PSC2_RX,
+               .end    = AU1550_DSCR_CMD0_PSC2_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device db1550_i2c_dev = {
+       .name           = "au1xpsc_smbus",
+       .id             = 0,    /* bus number */
+       .num_resources  = ARRAY_SIZE(au1550_psc2_res),
+       .resource       = au1550_psc2_res,
+};
+
+/**********************************************************************/
+
+static struct resource au1550_psc3_res[] = {
+       [0] = {
+               .start  = AU1550_PSC3_PHYS_ADDR,
+               .end    = AU1550_PSC3_PHYS_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1550_PSC3_INT,
+               .end    = AU1550_PSC3_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = AU1550_DSCR_CMD0_PSC3_TX,
+               .end    = AU1550_DSCR_CMD0_PSC3_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = AU1550_DSCR_CMD0_PSC3_RX,
+               .end    = AU1550_DSCR_CMD0_PSC3_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device db1550_i2s_dev = {
+       .name           = "au1xpsc_i2s",
+       .id             = 3,    /* PSC ID */
+       .num_resources  = ARRAY_SIZE(au1550_psc3_res),
+       .resource       = au1550_psc3_res,
+};
+
+/**********************************************************************/
+
+static struct platform_device db1550_stac_dev = {
+       .name           = "ac97-codec",
+       .id             = 1,    /* on PSC1 */
+};
+
+static struct platform_device db1550_ac97dma_dev = {
+       .name           = "au1xpsc-pcm",
+       .id             = 1,    /* on PSC3 */
+};
+
+static struct platform_device db1550_i2sdma_dev = {
+       .name           = "au1xpsc-pcm",
+       .id             = 3,    /* on PSC3 */
+};
+
+static struct platform_device db1550_sndac97_dev = {
+       .name           = "db1550-ac97",
+};
+
+static struct platform_device db1550_sndi2s_dev = {
+       .name           = "db1550-i2s",
+};
+
+/**********************************************************************/
+
+static int db1550_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
+{
+       if ((slot < 11) || (slot > 13) || pin == 0)
+               return -1;
+       if (slot == 11)
+               return (pin == 1) ? AU1550_PCI_INTC : 0xff;
+       if (slot == 12) {
+               switch (pin) {
+               case 1: return AU1550_PCI_INTB;
+               case 2: return AU1550_PCI_INTC;
+               case 3: return AU1550_PCI_INTD;
+               case 4: return AU1550_PCI_INTA;
+               }
+       }
+       if (slot == 13) {
+               switch (pin) {
+               case 1: return AU1550_PCI_INTA;
+               case 2: return AU1550_PCI_INTB;
+               case 3: return AU1550_PCI_INTC;
+               case 4: return AU1550_PCI_INTD;
+               }
+       }
+       return -1;
+}
+
+static struct resource alchemy_pci_host_res[] = {
+       [0] = {
+               .start  = AU1500_PCI_PHYS_ADDR,
+               .end    = AU1500_PCI_PHYS_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct alchemy_pci_platdata db1550_pci_pd = {
+       .board_map_irq  = db1550_map_pci_irq,
+};
+
+static struct platform_device db1550_pci_host_dev = {
+       .dev.platform_data = &db1550_pci_pd,
+       .name           = "alchemy-pci",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(alchemy_pci_host_res),
+       .resource       = alchemy_pci_host_res,
+};
+
+/**********************************************************************/
+
+static struct platform_device *db1550_devs[] __initdata = {
+       &db1550_nand_dev,
+       &db1550_i2c_dev,
+       &db1550_ac97_dev,
+       &db1550_spi_dev,
+       &db1550_i2s_dev,
+       &db1550_stac_dev,
+       &db1550_ac97dma_dev,
+       &db1550_i2sdma_dev,
+       &db1550_sndac97_dev,
+       &db1550_sndi2s_dev,
+};
+
+/* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */
+static int __init db1550_pci_init(void)
+{
+       return platform_device_register(&db1550_pci_host_dev);
+}
+arch_initcall(db1550_pci_init);
+
+static int __init db1550_dev_init(void)
+{
+       int swapped;
+
+       irq_set_irq_type(AU1550_GPIO0_INT, IRQ_TYPE_EDGE_BOTH);  /* CD0# */
+       irq_set_irq_type(AU1550_GPIO1_INT, IRQ_TYPE_EDGE_BOTH);  /* CD1# */
+       irq_set_irq_type(AU1550_GPIO3_INT, IRQ_TYPE_LEVEL_LOW);  /* CARD0# */
+       irq_set_irq_type(AU1550_GPIO5_INT, IRQ_TYPE_LEVEL_LOW);  /* CARD1# */
+       irq_set_irq_type(AU1550_GPIO21_INT, IRQ_TYPE_LEVEL_LOW); /* STSCHG0# */
+       irq_set_irq_type(AU1550_GPIO22_INT, IRQ_TYPE_LEVEL_LOW); /* STSCHG1# */
+
+       i2c_register_board_info(0, db1550_i2c_devs,
+                               ARRAY_SIZE(db1550_i2c_devs));
+       spi_register_board_info(db1550_spi_devs,
+                               ARRAY_SIZE(db1550_i2c_devs));
+
+       /* Audio PSC clock is supplied by codecs (PSC1, 3) FIXME: platdata!! */
+       __raw_writel(PSC_SEL_CLK_SERCLK,
+           (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
+       wmb();
+       __raw_writel(PSC_SEL_CLK_SERCLK,
+           (void __iomem *)KSEG1ADDR(AU1550_PSC3_PHYS_ADDR) + PSC_SEL_OFFSET);
+       wmb();
+       /* SPI/I2C use internally supplied 50MHz source */
+       __raw_writel(PSC_SEL_CLK_INTCLK,
+           (void __iomem *)KSEG1ADDR(AU1550_PSC0_PHYS_ADDR) + PSC_SEL_OFFSET);
+       wmb();
+       __raw_writel(PSC_SEL_CLK_INTCLK,
+           (void __iomem *)KSEG1ADDR(AU1550_PSC2_PHYS_ADDR) + PSC_SEL_OFFSET);
+       wmb();
+
+       db1x_register_pcmcia_socket(
+               AU1000_PCMCIA_ATTR_PHYS_ADDR,
+               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
+               AU1000_PCMCIA_MEM_PHYS_ADDR,
+               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
+               AU1000_PCMCIA_IO_PHYS_ADDR,
+               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
+               AU1550_GPIO3_INT, AU1550_GPIO0_INT,
+               /*AU1550_GPIO21_INT*/0, 0, 0);
+
+       db1x_register_pcmcia_socket(
+               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
+               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
+               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x004000000,
+               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x004400000 - 1,
+               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004000000,
+               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004010000 - 1,
+               AU1550_GPIO5_INT, AU1550_GPIO1_INT,
+               /*AU1550_GPIO22_INT*/0, 0, 1);
+
+       swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT;
+       db1x_register_norflash(128 << 20, 4, swapped);
+
+       return platform_add_devices(db1550_devs, ARRAY_SIZE(db1550_devs));
+}
+device_initcall(db1550_dev_init);
diff --git a/arch/mips/alchemy/devboards/db1x00/Makefile b/arch/mips/alchemy/devboards/db1x00/Makefile
deleted file mode 100644 (file)
index 613c0c0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-#  Copyright 2000, 2008 MontaVista Software Inc.
-#  Author: MontaVista Software, Inc. <source@mvista.com>
-#
-# Makefile for the Alchemy Semiconductor DBAu1xx0 boards.
-#
-
-obj-y := board_setup.o platform.o
diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c
deleted file mode 100644 (file)
index 7cd36e6..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- *     Alchemy Db1x00 board setup.
- *
- * Copyright 2000, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.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  SOFTWARE  IS PROVIDED   ``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   THE AUTHOR  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.
- *
- *  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/gpio.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/pm.h>
-
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1xxx_eth.h>
-#include <asm/mach-db1x00/db1x00.h>
-#include <asm/mach-db1x00/bcsr.h>
-#include <asm/reboot.h>
-
-#include <prom.h>
-
-#ifdef CONFIG_MIPS_BOSPORUS
-char irq_tab_alchemy[][5] __initdata = {
-       [11] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 11 - miniPCI  */
-       [12] = { -1, AU1500_PCI_INTA, 0xff, 0xff, 0xff }, /* IDSEL 12 - SN1741   */
-       [13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot */
-};
-
-/*
- * Micrel/Kendin 5 port switch attached to MAC0,
- * MAC0 is associated with PHY address 5 (== WAN port)
- * MAC1 is not associated with any PHY, since it's connected directly
- * to the switch.
- * no interrupts are used
- */
-static struct au1000_eth_platform_data eth0_pdata = {
-       .phy_static_config      = 1,
-       .phy_addr               = 5,
-};
-
-static void bosporus_power_off(void)
-{
-       while (1)
-               asm volatile (".set mips3 ; wait ; .set mips0");
-}
-
-const char *get_system_type(void)
-{
-       return "Alchemy Bosporus Gateway Reference";
-}
-#endif
-
-
-#ifdef CONFIG_MIPS_MIRAGE
-static void mirage_power_off(void)
-{
-       alchemy_gpio_direction_output(210, 1);
-}
-
-const char *get_system_type(void)
-{
-       return "Alchemy Mirage";
-}
-#endif
-
-
-#if defined(CONFIG_MIPS_BOSPORUS) || defined(CONFIG_MIPS_MIRAGE)
-static void mips_softreset(void)
-{
-       asm volatile ("jr\t%0" : : "r"(0xbfc00000));
-}
-
-#else
-
-const char *get_system_type(void)
-{
-       return "Alchemy Db1x00";
-}
-#endif
-
-
-void __init board_setup(void)
-{
-       unsigned long bcsr1, bcsr2;
-
-       bcsr1 = DB1000_BCSR_PHYS_ADDR;
-       bcsr2 = DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS;
-
-#ifdef CONFIG_MIPS_DB1000
-       printk(KERN_INFO "AMD Alchemy Au1000/Db1000 Board\n");
-#endif
-#ifdef CONFIG_MIPS_DB1500
-       printk(KERN_INFO "AMD Alchemy Au1500/Db1500 Board\n");
-#endif
-#ifdef CONFIG_MIPS_DB1100
-       printk(KERN_INFO "AMD Alchemy Au1100/Db1100 Board\n");
-#endif
-#ifdef CONFIG_MIPS_BOSPORUS
-       au1xxx_override_eth_cfg(0, &eth0_pdata);
-
-       printk(KERN_INFO "AMD Alchemy Bosporus Board\n");
-#endif
-#ifdef CONFIG_MIPS_MIRAGE
-       printk(KERN_INFO "AMD Alchemy Mirage Board\n");
-#endif
-#ifdef CONFIG_MIPS_DB1550
-       printk(KERN_INFO "AMD Alchemy Au1550/Db1550 Board\n");
-
-       bcsr1 = DB1550_BCSR_PHYS_ADDR;
-       bcsr2 = DB1550_BCSR_PHYS_ADDR + DB1550_BCSR_HEXLED_OFS;
-#endif
-
-       /* initialize board register space */
-       bcsr_init(bcsr1, bcsr2);
-
-#if defined(CONFIG_IRDA) && defined(CONFIG_AU1000_FIR)
-       {
-               u32 pin_func;
-
-               /* Set IRFIRSEL instead of GPIO15 */
-               pin_func = au_readl(SYS_PINFUNC) | SYS_PF_IRF;
-               au_writel(pin_func, SYS_PINFUNC);
-               /* Power off until the driver is in use */
-               bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK,
-                        BCSR_RESETS_IRDA_MODE_OFF);
-       }
-#endif
-       bcsr_write(BCSR_PCMCIA, 0);     /* turn off PCMCIA power */
-
-       /* Enable GPIO[31:0] inputs */
-       alchemy_gpio1_input_enable();
-
-#ifdef CONFIG_MIPS_MIRAGE
-       {
-               u32 pin_func;
-
-               /* GPIO[20] is output */
-               alchemy_gpio_direction_output(20, 0);
-
-               /* Set GPIO[210:208] instead of SSI_0 */
-               pin_func = au_readl(SYS_PINFUNC) | SYS_PF_S0;
-
-               /* Set GPIO[215:211] for LEDs */
-               pin_func |= 5 << 2;
-
-               /* Set GPIO[214:213] for more LEDs */
-               pin_func |= 5 << 12;
-
-               /* Set GPIO[207:200] instead of PCMCIA/LCD */
-               pin_func |= SYS_PF_LCD | SYS_PF_PC;
-               au_writel(pin_func, SYS_PINFUNC);
-
-               /*
-                * Enable speaker amplifier.  This should
-                * be part of the audio driver.
-                */
-               alchemy_gpio_direction_output(209, 1);
-
-               pm_power_off = mirage_power_off;
-               _machine_halt = mirage_power_off;
-               _machine_restart = (void(*)(char *))mips_softreset;
-       }
-#endif
-
-#ifdef CONFIG_MIPS_BOSPORUS
-       pm_power_off = bosporus_power_off;
-       _machine_halt = bosporus_power_off;
-       _machine_restart = (void(*)(char *))mips_softreset;
-#endif
-       au_sync();
-}
-
-static int __init db1x00_init_irq(void)
-{
-#if defined(CONFIG_MIPS_MIRAGE)
-       irq_set_irq_type(AU1500_GPIO7_INT, IRQF_TRIGGER_RISING); /* TS pendown */
-#elif defined(CONFIG_MIPS_DB1550)
-       irq_set_irq_type(AU1550_GPIO0_INT, IRQF_TRIGGER_LOW);  /* CD0# */
-       irq_set_irq_type(AU1550_GPIO1_INT, IRQF_TRIGGER_LOW);  /* CD1# */
-       irq_set_irq_type(AU1550_GPIO3_INT, IRQF_TRIGGER_LOW);  /* CARD0# */
-       irq_set_irq_type(AU1550_GPIO5_INT, IRQF_TRIGGER_LOW);  /* CARD1# */
-       irq_set_irq_type(AU1550_GPIO21_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */
-       irq_set_irq_type(AU1550_GPIO22_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */
-#elif defined(CONFIG_MIPS_DB1500)
-       irq_set_irq_type(AU1500_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */
-       irq_set_irq_type(AU1500_GPIO3_INT, IRQF_TRIGGER_LOW); /* CD1# */
-       irq_set_irq_type(AU1500_GPIO2_INT, IRQF_TRIGGER_LOW); /* CARD0# */
-       irq_set_irq_type(AU1500_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */
-       irq_set_irq_type(AU1500_GPIO1_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */
-       irq_set_irq_type(AU1500_GPIO4_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */
-#elif defined(CONFIG_MIPS_DB1100)
-       irq_set_irq_type(AU1100_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */
-       irq_set_irq_type(AU1100_GPIO3_INT, IRQF_TRIGGER_LOW); /* CD1# */
-       irq_set_irq_type(AU1100_GPIO2_INT, IRQF_TRIGGER_LOW); /* CARD0# */
-       irq_set_irq_type(AU1100_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */
-       irq_set_irq_type(AU1100_GPIO1_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */
-       irq_set_irq_type(AU1100_GPIO4_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */
-#elif defined(CONFIG_MIPS_DB1000)
-       irq_set_irq_type(AU1000_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */
-       irq_set_irq_type(AU1000_GPIO3_INT, IRQF_TRIGGER_LOW); /* CD1# */
-       irq_set_irq_type(AU1000_GPIO2_INT, IRQF_TRIGGER_LOW); /* CARD0# */
-       irq_set_irq_type(AU1000_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */
-       irq_set_irq_type(AU1000_GPIO1_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */
-       irq_set_irq_type(AU1000_GPIO4_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */
-#endif
-       return 0;
-}
-arch_initcall(db1x00_init_irq);
diff --git a/arch/mips/alchemy/devboards/db1x00/platform.c b/arch/mips/alchemy/devboards/db1x00/platform.c
deleted file mode 100644 (file)
index 9e6b3d4..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * DBAu1xxx board platform device registration
- *
- * Copyright (C) 2009 Manuel Lauss
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1000_dma.h>
-#include <asm/mach-db1x00/bcsr.h>
-#include "../platform.h"
-
-struct pci_dev;
-
-/* DB1xxx PCMCIA interrupt sources:
- * CD0/1       GPIO0/3
- * STSCHG0/1   GPIO1/4
- * CARD0/1     GPIO2/5
- * Db1550:     0/1, 21/22, 3/5
- */
-
-#define DB1XXX_HAS_PCMCIA
-#define F_SWAPPED (bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT)
-
-#if defined(CONFIG_MIPS_DB1000)
-#define DB1XXX_PCMCIA_CD0      AU1000_GPIO0_INT
-#define DB1XXX_PCMCIA_STSCHG0  AU1000_GPIO1_INT
-#define DB1XXX_PCMCIA_CARD0    AU1000_GPIO2_INT
-#define DB1XXX_PCMCIA_CD1      AU1000_GPIO3_INT
-#define DB1XXX_PCMCIA_STSCHG1  AU1000_GPIO4_INT
-#define DB1XXX_PCMCIA_CARD1    AU1000_GPIO5_INT
-#define BOARD_FLASH_SIZE       0x02000000 /* 32MB */
-#define BOARD_FLASH_WIDTH      4 /* 32-bits */
-#elif defined(CONFIG_MIPS_DB1100)
-#define DB1XXX_PCMCIA_CD0      AU1100_GPIO0_INT
-#define DB1XXX_PCMCIA_STSCHG0  AU1100_GPIO1_INT
-#define DB1XXX_PCMCIA_CARD0    AU1100_GPIO2_INT
-#define DB1XXX_PCMCIA_CD1      AU1100_GPIO3_INT
-#define DB1XXX_PCMCIA_STSCHG1  AU1100_GPIO4_INT
-#define DB1XXX_PCMCIA_CARD1    AU1100_GPIO5_INT
-#define BOARD_FLASH_SIZE       0x02000000 /* 32MB */
-#define BOARD_FLASH_WIDTH      4 /* 32-bits */
-#elif defined(CONFIG_MIPS_DB1500)
-#define DB1XXX_PCMCIA_CD0      AU1500_GPIO0_INT
-#define DB1XXX_PCMCIA_STSCHG0  AU1500_GPIO1_INT
-#define DB1XXX_PCMCIA_CARD0    AU1500_GPIO2_INT
-#define DB1XXX_PCMCIA_CD1      AU1500_GPIO3_INT
-#define DB1XXX_PCMCIA_STSCHG1  AU1500_GPIO4_INT
-#define DB1XXX_PCMCIA_CARD1    AU1500_GPIO5_INT
-#define BOARD_FLASH_SIZE       0x02000000 /* 32MB */
-#define BOARD_FLASH_WIDTH      4 /* 32-bits */
-#elif defined(CONFIG_MIPS_DB1550)
-#define DB1XXX_PCMCIA_CD0      AU1550_GPIO0_INT
-#define DB1XXX_PCMCIA_STSCHG0  AU1550_GPIO21_INT
-#define DB1XXX_PCMCIA_CARD0    AU1550_GPIO3_INT
-#define DB1XXX_PCMCIA_CD1      AU1550_GPIO1_INT
-#define DB1XXX_PCMCIA_STSCHG1  AU1550_GPIO22_INT
-#define DB1XXX_PCMCIA_CARD1    AU1550_GPIO5_INT
-#define BOARD_FLASH_SIZE       0x08000000 /* 128MB */
-#define BOARD_FLASH_WIDTH      4 /* 32-bits */
-#else
-/* other board: no PCMCIA */
-#undef DB1XXX_HAS_PCMCIA
-#undef F_SWAPPED
-#define F_SWAPPED 0
-#if defined(CONFIG_MIPS_BOSPORUS)
-#define BOARD_FLASH_SIZE       0x01000000 /* 16MB */
-#define BOARD_FLASH_WIDTH      2 /* 16-bits */
-#elif defined(CONFIG_MIPS_MIRAGE)
-#define BOARD_FLASH_SIZE       0x04000000 /* 64MB */
-#define BOARD_FLASH_WIDTH      4 /* 32-bits */
-#endif
-#endif
-
-#ifdef CONFIG_PCI
-#ifdef CONFIG_MIPS_DB1500
-static int db1xxx_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
-{
-       if ((slot < 12) || (slot > 13) || pin == 0)
-               return -1;
-       if (slot == 12)
-               return (pin == 1) ? AU1500_PCI_INTA : 0xff;
-       if (slot == 13) {
-               switch (pin) {
-               case 1: return AU1500_PCI_INTA;
-               case 2: return AU1500_PCI_INTB;
-               case 3: return AU1500_PCI_INTC;
-               case 4: return AU1500_PCI_INTD;
-               }
-       }
-       return -1;
-}
-#endif
-
-#ifdef CONFIG_MIPS_DB1550
-static int db1xxx_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
-{
-       if ((slot < 11) || (slot > 13) || pin == 0)
-               return -1;
-       if (slot == 11)
-               return (pin == 1) ? AU1550_PCI_INTC : 0xff;
-       if (slot == 12) {
-               switch (pin) {
-               case 1: return AU1550_PCI_INTB;
-               case 2: return AU1550_PCI_INTC;
-               case 3: return AU1550_PCI_INTD;
-               case 4: return AU1550_PCI_INTA;
-               }
-       }
-       if (slot == 13) {
-               switch (pin) {
-               case 1: return AU1550_PCI_INTA;
-               case 2: return AU1550_PCI_INTB;
-               case 3: return AU1550_PCI_INTC;
-               case 4: return AU1550_PCI_INTD;
-               }
-       }
-       return -1;
-}
-#endif
-
-#ifdef CONFIG_MIPS_BOSPORUS
-static int db1xxx_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
-{
-       if ((slot < 11) || (slot > 13) || pin == 0)
-               return -1;
-       if (slot == 12)
-               return (pin == 1) ? AU1500_PCI_INTA : 0xff;
-       if (slot == 11) {
-               switch (pin) {
-               case 1: return AU1500_PCI_INTA;
-               case 2: return AU1500_PCI_INTB;
-               default: return 0xff;
-               }
-       }
-       if (slot == 13) {
-               switch (pin) {
-               case 1: return AU1500_PCI_INTA;
-               case 2: return AU1500_PCI_INTB;
-               case 3: return AU1500_PCI_INTC;
-               case 4: return AU1500_PCI_INTD;
-               }
-       }
-       return -1;
-}
-#endif
-
-#ifdef CONFIG_MIPS_MIRAGE
-static int db1xxx_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
-{
-       if ((slot < 11) || (slot > 13) || pin == 0)
-               return -1;
-       if (slot == 11)
-               return (pin == 1) ? AU1500_PCI_INTD : 0xff;
-       if (slot == 12)
-               return (pin == 3) ? AU1500_PCI_INTC : 0xff;
-       if (slot == 13) {
-               switch (pin) {
-               case 1: return AU1500_PCI_INTA;
-               case 2: return AU1500_PCI_INTB;
-               default: return 0xff;
-               }
-       }
-       return -1;
-}
-#endif
-
-static struct resource alchemy_pci_host_res[] = {
-       [0] = {
-               .start  = AU1500_PCI_PHYS_ADDR,
-               .end    = AU1500_PCI_PHYS_ADDR + 0xfff,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct alchemy_pci_platdata db1xxx_pci_pd = {
-       .board_map_irq  = db1xxx_map_pci_irq,
-};
-
-static struct platform_device db1xxx_pci_host_dev = {
-       .dev.platform_data = &db1xxx_pci_pd,
-       .name           = "alchemy-pci",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(alchemy_pci_host_res),
-       .resource       = alchemy_pci_host_res,
-};
-
-static int __init db15x0_pci_init(void)
-{
-       return platform_device_register(&db1xxx_pci_host_dev);
-}
-/* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */
-arch_initcall(db15x0_pci_init);
-#endif
-
-#ifdef CONFIG_MIPS_DB1100
-static struct resource au1100_lcd_resources[] = {
-       [0] = {
-               .start  = AU1100_LCD_PHYS_ADDR,
-               .end    = AU1100_LCD_PHYS_ADDR + 0x800 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AU1100_LCD_INT,
-               .end    = AU1100_LCD_INT,
-               .flags  = IORESOURCE_IRQ,
-       }
-};
-
-static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device au1100_lcd_device = {
-       .name           = "au1100-lcd",
-       .id             = 0,
-       .dev = {
-               .dma_mask               = &au1100_lcd_dmamask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .num_resources  = ARRAY_SIZE(au1100_lcd_resources),
-       .resource       = au1100_lcd_resources,
-};
-#endif
-
-static struct resource alchemy_ac97c_res[] = {
-       [0] = {
-               .start  = AU1000_AC97_PHYS_ADDR,
-               .end    = AU1000_AC97_PHYS_ADDR + 0xfff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = DMA_ID_AC97C_TX,
-               .end    = DMA_ID_AC97C_TX,
-               .flags  = IORESOURCE_DMA,
-       },
-       [2] = {
-               .start  = DMA_ID_AC97C_RX,
-               .end    = DMA_ID_AC97C_RX,
-               .flags  = IORESOURCE_DMA,
-       },
-};
-
-static struct platform_device alchemy_ac97c_dev = {
-       .name           = "alchemy-ac97c",
-       .id             = -1,
-       .resource       = alchemy_ac97c_res,
-       .num_resources  = ARRAY_SIZE(alchemy_ac97c_res),
-};
-
-static struct platform_device alchemy_ac97c_dma_dev = {
-       .name           = "alchemy-pcm-dma",
-       .id             = 0,
-};
-
-static struct platform_device db1x00_codec_dev = {
-       .name           = "ac97-codec",
-       .id             = -1,
-};
-
-static struct platform_device db1x00_audio_dev = {
-       .name           = "db1000-audio",
-};
-
-static int __init db1xxx_dev_init(void)
-{
-#ifdef DB1XXX_HAS_PCMCIA
-       db1x_register_pcmcia_socket(
-               AU1000_PCMCIA_ATTR_PHYS_ADDR,
-               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
-               AU1000_PCMCIA_MEM_PHYS_ADDR,
-               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
-               AU1000_PCMCIA_IO_PHYS_ADDR,
-               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
-               DB1XXX_PCMCIA_CARD0, DB1XXX_PCMCIA_CD0,
-               /*DB1XXX_PCMCIA_STSCHG0*/0, 0, 0);
-
-       db1x_register_pcmcia_socket(
-               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
-               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
-               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x004000000,
-               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x004400000 - 1,
-               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004000000,
-               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004010000 - 1,
-               DB1XXX_PCMCIA_CARD1, DB1XXX_PCMCIA_CD1,
-               /*DB1XXX_PCMCIA_STSCHG1*/0, 0, 1);
-#endif
-#ifdef CONFIG_MIPS_DB1100
-       platform_device_register(&au1100_lcd_device);
-#endif
-       db1x_register_norflash(BOARD_FLASH_SIZE, BOARD_FLASH_WIDTH, F_SWAPPED);
-
-       platform_device_register(&db1x00_codec_dev);
-       platform_device_register(&alchemy_ac97c_dma_dev);
-       platform_device_register(&alchemy_ac97c_dev);
-       platform_device_register(&db1x00_audio_dev);
-
-       return 0;
-}
-device_initcall(db1xxx_dev_init);
diff --git a/arch/mips/alchemy/devboards/pb1000/Makefile b/arch/mips/alchemy/devboards/pb1000/Makefile
deleted file mode 100644 (file)
index 97c6615..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-#  Copyright 2000, 2008 MontaVista Software Inc.
-#  Author: MontaVista Software, Inc. <source@mvista.com>
-#
-# Makefile for the Alchemy Semiconductor Pb1000 board.
-#
-
-obj-y := board_setup.o
diff --git a/arch/mips/alchemy/devboards/pb1000/board_setup.c b/arch/mips/alchemy/devboards/pb1000/board_setup.c
deleted file mode 100644 (file)
index e64fdcb..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright 2000, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.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  SOFTWARE  IS PROVIDED   ``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   THE AUTHOR  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.
- *
- *  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/delay.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/pm.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-pb1x00/pb1000.h>
-#include <asm/reboot.h>
-#include <prom.h>
-
-#include "../platform.h"
-
-const char *get_system_type(void)
-{
-       return "Alchemy Pb1000";
-}
-
-static void board_reset(char *c)
-{
-       asm volatile ("jr %0" : : "r" (0xbfc00000));
-}
-
-static void board_power_off(void)
-{
-       while (1)
-               asm volatile (
-               "       .set    mips32                                  \n"
-               "       wait                                            \n"
-               "       .set    mips0                                   \n");
-}
-
-void __init board_setup(void)
-{
-       u32 pin_func, static_cfg0;
-       u32 sys_freqctrl, sys_clksrc;
-       u32 prid = read_c0_prid();
-
-       sys_freqctrl = 0;
-       sys_clksrc = 0;
-
-       /* Set AUX clock to 12 MHz * 8 = 96 MHz */
-       au_writel(8, SYS_AUXPLL);
-       alchemy_gpio1_input_enable();
-       udelay(100);
-
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-       /* Zero and disable FREQ2 */
-       sys_freqctrl = au_readl(SYS_FREQCTRL0);
-       sys_freqctrl &= ~0xFFF00000;
-       au_writel(sys_freqctrl, SYS_FREQCTRL0);
-
-       /* Zero and disable USBH/USBD clocks */
-       sys_clksrc = au_readl(SYS_CLKSRC);
-       sys_clksrc &= ~(SYS_CS_CUD | SYS_CS_DUD | SYS_CS_MUD_MASK |
-                       SYS_CS_CUH | SYS_CS_DUH | SYS_CS_MUH_MASK);
-       au_writel(sys_clksrc, SYS_CLKSRC);
-
-       sys_freqctrl = au_readl(SYS_FREQCTRL0);
-       sys_freqctrl &= ~0xFFF00000;
-
-       sys_clksrc = au_readl(SYS_CLKSRC);
-       sys_clksrc &= ~(SYS_CS_CUD | SYS_CS_DUD | SYS_CS_MUD_MASK |
-                       SYS_CS_CUH | SYS_CS_DUH | SYS_CS_MUH_MASK);
-
-       switch (prid & 0x000000FF) {
-       case 0x00: /* DA */
-       case 0x01: /* HA */
-       case 0x02: /* HB */
-               /* CPU core freq to 48 MHz to slow it way down... */
-               au_writel(4, SYS_CPUPLL);
-
-               /*
-                * Setup 48 MHz FREQ2 from CPUPLL for USB Host
-                * FRDIV2 = 3 -> div by 8 of 384 MHz -> 48 MHz
-                */
-               sys_freqctrl |= (3 << SYS_FC_FRDIV2_BIT) | SYS_FC_FE2;
-               au_writel(sys_freqctrl, SYS_FREQCTRL0);
-
-               /* CPU core freq to 384 MHz */
-               au_writel(0x20, SYS_CPUPLL);
-
-               printk(KERN_INFO "Au1000: 48 MHz OHCI workaround enabled\n");
-               break;
-
-       default: /* HC and newer */
-               /* FREQ2 = aux / 2 = 48 MHz */
-               sys_freqctrl |= (0 << SYS_FC_FRDIV2_BIT) |
-                                SYS_FC_FE2 | SYS_FC_FS2;
-               au_writel(sys_freqctrl, SYS_FREQCTRL0);
-               break;
-       }
-
-       /*
-        * Route 48 MHz FREQ2 into USB Host and/or Device
-        */
-       sys_clksrc |= SYS_CS_MUX_FQ2 << SYS_CS_MUH_BIT;
-       au_writel(sys_clksrc, SYS_CLKSRC);
-
-       /* Configure pins GPIO[14:9] as GPIO */
-       pin_func = au_readl(SYS_PINFUNC) & ~(SYS_PF_UR3 | SYS_PF_USB);
-
-       /* 2nd USB port is USB host */
-       pin_func |= SYS_PF_USB;
-
-       au_writel(pin_func, SYS_PINFUNC);
-
-       alchemy_gpio_direction_input(11);
-       alchemy_gpio_direction_input(13);
-       alchemy_gpio_direction_output(4, 0);
-       alchemy_gpio_direction_output(5, 0);
-#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */
-
-       /* Make GPIO 15 an input (for interrupt line) */
-       pin_func = au_readl(SYS_PINFUNC) & ~SYS_PF_IRF;
-       /* We don't need I2S, so make it available for GPIO[31:29] */
-       pin_func |= SYS_PF_I2S;
-       au_writel(pin_func, SYS_PINFUNC);
-
-       alchemy_gpio_direction_input(15);
-
-       static_cfg0 = au_readl(MEM_STCFG0) & ~0xc00;
-       au_writel(static_cfg0, MEM_STCFG0);
-
-       /* configure RCE2* for LCD */
-       au_writel(0x00000004, MEM_STCFG2);
-
-       /* MEM_STTIME2 */
-       au_writel(0x09000000, MEM_STTIME2);
-
-       /* Set 32-bit base address decoding for RCE2* */
-       au_writel(0x10003ff0, MEM_STADDR2);
-
-       /*
-        * PCI CPLD setup
-        * Expand CE0 to cover PCI
-        */
-       au_writel(0x11803e40, MEM_STADDR1);
-
-       /* Burst visibility on */
-       au_writel(au_readl(MEM_STCFG0) | 0x1000, MEM_STCFG0);
-
-       au_writel(0x83, MEM_STCFG1);         /* ewait enabled, flash timing */
-       au_writel(0x33030a10, MEM_STTIME1);  /* slower timing for FPGA */
-
-       /* Setup the static bus controller */
-       au_writel(0x00000002, MEM_STCFG3);  /* type = PCMCIA */
-       au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */
-       au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */
-
-       /*
-        * Enable Au1000 BCLK switching - note: sed1356 must not use
-        * its BCLK (Au1000 LCLK) for any timings
-        */
-       switch (prid & 0x000000FF) {
-       case 0x00: /* DA */
-       case 0x01: /* HA */
-       case 0x02: /* HB */
-               break;
-       default:  /* HC and newer */
-               /*
-                * Enable sys bus clock divider when IDLE state or no bus
-                * activity.
-                */
-               au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL);
-               break;
-       }
-
-       pm_power_off = board_power_off;
-       _machine_halt = board_power_off;
-       _machine_restart = board_reset;
-}
-
-static int __init pb1000_init_irq(void)
-{
-       irq_set_irq_type(AU1000_GPIO15_INT, IRQF_TRIGGER_LOW);
-       return 0;
-}
-arch_initcall(pb1000_init_irq);
-
-static int __init pb1000_device_init(void)
-{
-       return db1x_register_norflash(8 * 1024 * 1024, 4, 0);
-}
-device_initcall(pb1000_device_init);
similarity index 55%
rename from arch/mips/alchemy/devboards/pb1100/board_setup.c
rename to arch/mips/alchemy/devboards/pb1100.c
index d108fd573aaf0eb75d7a2d25abb9a62cbb38eba2..cff50d05ddd4136e954917509ffdbedfb6e444c6 100644 (file)
@@ -1,42 +1,37 @@
 /*
- * Copyright 2002, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.com>
+ * Pb1100 board platform device registration
  *
- *  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.
+ * Copyright (C) 2009 Manuel Lauss
  *
- *  THIS  SOFTWARE  IS PROVIDED   ``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   THE AUTHOR  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.
+ * 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.
  *
- *  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.
+ * 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/delay.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
-#include <linux/delay.h>
 #include <linux/interrupt.h>
-
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-db1x00/bcsr.h>
-
 #include <prom.h>
-
+#include "platform.h"
 
 const char *get_system_type(void)
 {
-       return "Alchemy Pb1100";
+       return "PB1100";
 }
 
 void __init board_setup(void)
@@ -115,13 +110,58 @@ void __init board_setup(void)
        }
 }
 
-static int __init pb1100_init_irq(void)
+/******************************************************************************/
+
+static struct resource au1100_lcd_resources[] = {
+       [0] = {
+               .start  = AU1100_LCD_PHYS_ADDR,
+               .end    = AU1100_LCD_PHYS_ADDR + 0x800 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AU1100_LCD_INT,
+               .end    = AU1100_LCD_INT,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device au1100_lcd_device = {
+       .name           = "au1100-lcd",
+       .id             = 0,
+       .dev = {
+               .dma_mask               = &au1100_lcd_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .num_resources  = ARRAY_SIZE(au1100_lcd_resources),
+       .resource       = au1100_lcd_resources,
+};
+
+static int __init pb1100_dev_init(void)
 {
+       int swapped;
+
        irq_set_irq_type(AU1100_GPIO9_INT, IRQF_TRIGGER_LOW); /* PCCD# */
        irq_set_irq_type(AU1100_GPIO10_INT, IRQF_TRIGGER_LOW); /* PCSTSCHG# */
        irq_set_irq_type(AU1100_GPIO11_INT, IRQF_TRIGGER_LOW); /* PCCard# */
        irq_set_irq_type(AU1100_GPIO13_INT, IRQF_TRIGGER_LOW); /* DC_IRQ# */
 
+       /* PCMCIA. single socket, identical to Pb1500 */
+       db1x_register_pcmcia_socket(
+               AU1000_PCMCIA_ATTR_PHYS_ADDR,
+               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
+               AU1000_PCMCIA_MEM_PHYS_ADDR,
+               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
+               AU1000_PCMCIA_IO_PHYS_ADDR,
+               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
+               AU1100_GPIO11_INT, AU1100_GPIO9_INT,     /* card / insert */
+               /*AU1100_GPIO10_INT*/0, 0, 0); /* stschg / eject / id */
+
+       swapped = bcsr_read(BCSR_STATUS) &  BCSR_STATUS_DB1000_SWAPBOOT;
+       db1x_register_norflash(64 * 1024 * 1024, 4, swapped);
+       platform_device_register(&au1100_lcd_device);
+
        return 0;
 }
-arch_initcall(pb1100_init_irq);
+device_initcall(pb1100_dev_init);
diff --git a/arch/mips/alchemy/devboards/pb1100/Makefile b/arch/mips/alchemy/devboards/pb1100/Makefile
deleted file mode 100644 (file)
index 7e3756c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-#  Copyright 2000, 2001, 2008 MontaVista Software Inc.
-#  Author: MontaVista Software, Inc. <source@mvista.com>
-#
-# Makefile for the Alchemy Semiconductor Pb1100 board.
-#
-
-obj-y := board_setup.o platform.o
diff --git a/arch/mips/alchemy/devboards/pb1100/platform.c b/arch/mips/alchemy/devboards/pb1100/platform.c
deleted file mode 100644 (file)
index 9c57c01..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Pb1100 board platform device registration
- *
- * Copyright (C) 2009 Manuel Lauss
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/init.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-db1x00/bcsr.h>
-
-#include "../platform.h"
-
-static struct resource au1100_lcd_resources[] = {
-       [0] = {
-               .start  = AU1100_LCD_PHYS_ADDR,
-               .end    = AU1100_LCD_PHYS_ADDR + 0x800 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AU1100_LCD_INT,
-               .end    = AU1100_LCD_INT,
-               .flags  = IORESOURCE_IRQ,
-       }
-};
-
-static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device au1100_lcd_device = {
-       .name           = "au1100-lcd",
-       .id             = 0,
-       .dev = {
-               .dma_mask               = &au1100_lcd_dmamask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .num_resources  = ARRAY_SIZE(au1100_lcd_resources),
-       .resource       = au1100_lcd_resources,
-};
-
-static int __init pb1100_dev_init(void)
-{
-       int swapped;
-
-       /* PCMCIA. single socket, identical to Pb1500 */
-       db1x_register_pcmcia_socket(
-               AU1000_PCMCIA_ATTR_PHYS_ADDR,
-               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
-               AU1000_PCMCIA_MEM_PHYS_ADDR,
-               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
-               AU1000_PCMCIA_IO_PHYS_ADDR,
-               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
-               AU1100_GPIO11_INT, AU1100_GPIO9_INT,     /* card / insert */
-               /*AU1100_GPIO10_INT*/0, 0, 0); /* stschg / eject / id */
-
-       swapped = bcsr_read(BCSR_STATUS) &  BCSR_STATUS_DB1000_SWAPBOOT;
-       db1x_register_norflash(64 * 1024 * 1024, 4, swapped);
-       platform_device_register(&au1100_lcd_device);
-
-       return 0;
-}
-device_initcall(pb1100_dev_init);
diff --git a/arch/mips/alchemy/devboards/pb1200/Makefile b/arch/mips/alchemy/devboards/pb1200/Makefile
deleted file mode 100644 (file)
index 18c1bd5..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the Alchemy Semiconductor Pb1200/DBAu1200 boards.
-#
-
-obj-y := board_setup.o platform.o
diff --git a/arch/mips/alchemy/devboards/pb1200/board_setup.c b/arch/mips/alchemy/devboards/pb1200/board_setup.c
deleted file mode 100644 (file)
index 6d06b07..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- *     Alchemy Pb1200/Db1200 board setup.
- *
- *  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  SOFTWARE  IS PROVIDED   ``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   THE AUTHOR  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.
- *
- *  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/init.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-db1x00/bcsr.h>
-
-#ifdef CONFIG_MIPS_PB1200
-#include <asm/mach-pb1x00/pb1200.h>
-#endif
-
-#ifdef CONFIG_MIPS_DB1200
-#include <asm/mach-db1x00/db1200.h>
-#define PB1200_INT_BEGIN DB1200_INT_BEGIN
-#define PB1200_INT_END DB1200_INT_END
-#endif
-
-#include <prom.h>
-
-const char *get_system_type(void)
-{
-       return "Alchemy Pb1200";
-}
-
-void __init board_setup(void)
-{
-       printk(KERN_INFO "AMD Alchemy Pb1200 Board\n");
-       bcsr_init(PB1200_BCSR_PHYS_ADDR,
-                 PB1200_BCSR_PHYS_ADDR + PB1200_BCSR_HEXLED_OFS);
-
-#if 0
-       {
-               u32 pin_func;
-
-               /*
-                * Enable PSC1 SYNC for AC97.  Normaly done in audio driver,
-                * but it is board specific code, so put it here.
-                */
-               pin_func = au_readl(SYS_PINFUNC);
-               au_sync();
-               pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1;
-               au_writel(pin_func, SYS_PINFUNC);
-
-               au_writel(0, (u32)bcsr | 0x10); /* turn off PCMCIA power */
-               au_sync();
-       }
-#endif
-
-#if defined(CONFIG_I2C_AU1550)
-       {
-               u32 freq0, clksrc;
-               u32 pin_func;
-
-               /* Select SMBus in CPLD */
-               bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC0MUX, 0);
-
-               pin_func = au_readl(SYS_PINFUNC);
-               au_sync();
-               pin_func &= ~(SYS_PINFUNC_P0A | SYS_PINFUNC_P0B);
-               /* Set GPIOs correctly */
-               pin_func |= 2 << 17;
-               au_writel(pin_func, SYS_PINFUNC);
-               au_sync();
-
-               /* The I2C driver depends on 50 MHz clock */
-               freq0 = au_readl(SYS_FREQCTRL0);
-               au_sync();
-               freq0 &= ~(SYS_FC_FRDIV1_MASK | SYS_FC_FS1 | SYS_FC_FE1);
-               freq0 |= 3 << SYS_FC_FRDIV1_BIT;
-               /* 396 MHz / (3 + 1) * 2 == 49.5 MHz */
-               au_writel(freq0, SYS_FREQCTRL0);
-               au_sync();
-               freq0 |= SYS_FC_FE1;
-               au_writel(freq0, SYS_FREQCTRL0);
-               au_sync();
-
-               clksrc = au_readl(SYS_CLKSRC);
-               au_sync();
-               clksrc &= ~(SYS_CS_CE0 | SYS_CS_DE0 | SYS_CS_ME0_MASK);
-               /* Bit 22 is EXTCLK0 for PSC0 */
-               clksrc |= SYS_CS_MUX_FQ1 << SYS_CS_ME0_BIT;
-               au_writel(clksrc, SYS_CLKSRC);
-               au_sync();
-       }
-#endif
-
-       /*
-        * The Pb1200 development board uses external MUX for PSC0 to
-        * support SMB/SPI. bcsr_resets bit 12: 0=SMB 1=SPI
-        */
-#ifdef CONFIG_I2C_AU1550
-       bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC0MUX, 0);
-#endif
-       au_sync();
-}
-
-static int __init pb1200_init_irq(void)
-{
-       /* We have a problem with CPLD rev 3. */
-       if (BCSR_WHOAMI_CPLD(bcsr_read(BCSR_WHOAMI)) <= 3) {
-               printk(KERN_ERR "WARNING!!!\n");
-               printk(KERN_ERR "WARNING!!!\n");
-               printk(KERN_ERR "WARNING!!!\n");
-               printk(KERN_ERR "WARNING!!!\n");
-               printk(KERN_ERR "WARNING!!!\n");
-               printk(KERN_ERR "WARNING!!!\n");
-               printk(KERN_ERR "Pb1200 must be at CPLD rev 4. Please have Pb1200\n");
-               printk(KERN_ERR "updated to latest revision. This software will\n");
-               printk(KERN_ERR "not work on anything less than CPLD rev 4.\n");
-               printk(KERN_ERR "WARNING!!!\n");
-               printk(KERN_ERR "WARNING!!!\n");
-               printk(KERN_ERR "WARNING!!!\n");
-               printk(KERN_ERR "WARNING!!!\n");
-               printk(KERN_ERR "WARNING!!!\n");
-               printk(KERN_ERR "WARNING!!!\n");
-               panic("Game over.  Your score is 0.");
-       }
-
-       irq_set_irq_type(AU1200_GPIO7_INT, IRQF_TRIGGER_LOW);
-       bcsr_init_irq(PB1200_INT_BEGIN, PB1200_INT_END, AU1200_GPIO7_INT);
-
-       return 0;
-}
-arch_initcall(pb1200_init_irq);
-
-
-int board_au1200fb_panel(void)
-{
-       return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f;
-}
-
-int board_au1200fb_panel_init(void)
-{
-       /* Apply power */
-       bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
-                               BCSR_BOARD_LCDBL);
-       /* printk(KERN_DEBUG "board_au1200fb_panel_init()\n"); */
-       return 0;
-}
-
-int board_au1200fb_panel_shutdown(void)
-{
-       /* Remove power */
-       bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
-                            BCSR_BOARD_LCDBL, 0);
-       /* printk(KERN_DEBUG "board_au1200fb_panel_shutdown()\n"); */
-       return 0;
-}
diff --git a/arch/mips/alchemy/devboards/pb1200/platform.c b/arch/mips/alchemy/devboards/pb1200/platform.c
deleted file mode 100644 (file)
index 54f7f7b..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * Pb1200/DBAu1200 board platform device registration
- *
- * Copyright (C) 2008 MontaVista Software Inc. <source@mvista.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/leds.h>
-#include <linux/platform_device.h>
-#include <linux/smc91x.h>
-
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1100_mmc.h>
-#include <asm/mach-au1x00/au1xxx_dbdma.h>
-#include <asm/mach-db1x00/bcsr.h>
-#include <asm/mach-pb1x00/pb1200.h>
-
-#include "../platform.h"
-
-static int mmc_activity;
-
-static void pb1200mmc0_set_power(void *mmc_host, int state)
-{
-       if (state)
-               bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD0PWR);
-       else
-               bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD0PWR, 0);
-
-       msleep(1);
-}
-
-static int pb1200mmc0_card_readonly(void *mmc_host)
-{
-       return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP) ? 1 : 0;
-}
-
-static int pb1200mmc0_card_inserted(void *mmc_host)
-{
-       return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD0INSERT) ? 1 : 0;
-}
-
-static void pb1200_mmcled_set(struct led_classdev *led,
-                       enum led_brightness brightness)
-{
-       if (brightness != LED_OFF) {
-               if (++mmc_activity == 1)
-                       bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0);
-       } else {
-               if (--mmc_activity == 0)
-                       bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0);
-       }
-}
-
-static struct led_classdev pb1200mmc_led = {
-       .brightness_set = pb1200_mmcled_set,
-};
-
-static void pb1200mmc1_set_power(void *mmc_host, int state)
-{
-       if (state)
-               bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD1PWR);
-       else
-               bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD1PWR, 0);
-
-       msleep(1);
-}
-
-static int pb1200mmc1_card_readonly(void *mmc_host)
-{
-       return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD1WP) ? 1 : 0;
-}
-
-static int pb1200mmc1_card_inserted(void *mmc_host)
-{
-       return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD1INSERT) ? 1 : 0;
-}
-
-static struct au1xmmc_platform_data pb1200mmc_platdata[2] = {
-       [0] = {
-               .set_power      = pb1200mmc0_set_power,
-               .card_inserted  = pb1200mmc0_card_inserted,
-               .card_readonly  = pb1200mmc0_card_readonly,
-               .cd_setup       = NULL,         /* use poll-timer in driver */
-               .led            = &pb1200mmc_led,
-       },
-       [1] = {
-               .set_power      = pb1200mmc1_set_power,
-               .card_inserted  = pb1200mmc1_card_inserted,
-               .card_readonly  = pb1200mmc1_card_readonly,
-               .cd_setup       = NULL,         /* use poll-timer in driver */
-               .led            = &pb1200mmc_led,
-       },
-};
-
-static u64 au1xxx_mmc_dmamask =  DMA_BIT_MASK(32);
-
-static struct resource au1200_mmc0_res[] = {
-       [0] = {
-               .start  = AU1100_SD0_PHYS_ADDR,
-               .end    = AU1100_SD0_PHYS_ADDR + 0xfff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AU1200_SD_INT,
-               .end    = AU1200_SD_INT,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = AU1200_DSCR_CMD0_SDMS_TX0,
-               .end    = AU1200_DSCR_CMD0_SDMS_TX0,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               .start  = AU1200_DSCR_CMD0_SDMS_RX0,
-               .end    = AU1200_DSCR_CMD0_SDMS_RX0,
-               .flags  = IORESOURCE_DMA,
-       }
-};
-
-static struct platform_device pb1200_mmc0_dev = {
-       .name           = "au1xxx-mmc",
-       .id             = 0,
-       .dev = {
-               .dma_mask               = &au1xxx_mmc_dmamask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-               .platform_data          = &pb1200mmc_platdata[0],
-       },
-       .num_resources  = ARRAY_SIZE(au1200_mmc0_res),
-       .resource       = au1200_mmc0_res,
-};
-
-static struct resource au1200_mmc1_res[] = {
-       [0] = {
-               .start  = AU1100_SD1_PHYS_ADDR,
-               .end    = AU1100_SD1_PHYS_ADDR + 0xfff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AU1200_SD_INT,
-               .end    = AU1200_SD_INT,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = AU1200_DSCR_CMD0_SDMS_TX1,
-               .end    = AU1200_DSCR_CMD0_SDMS_TX1,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               .start  = AU1200_DSCR_CMD0_SDMS_RX1,
-               .end    = AU1200_DSCR_CMD0_SDMS_RX1,
-               .flags  = IORESOURCE_DMA,
-       }
-};
-
-static struct platform_device pb1200_mmc1_dev = {
-       .name           = "au1xxx-mmc",
-       .id             = 1,
-       .dev = {
-               .dma_mask               = &au1xxx_mmc_dmamask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-               .platform_data          = &pb1200mmc_platdata[1],
-       },
-       .num_resources  = ARRAY_SIZE(au1200_mmc1_res),
-       .resource       = au1200_mmc1_res,
-};
-
-
-static struct resource ide_resources[] = {
-       [0] = {
-               .start  = IDE_PHYS_ADDR,
-               .end    = IDE_PHYS_ADDR + IDE_PHYS_LEN - 1,
-               .flags  = IORESOURCE_MEM
-       },
-       [1] = {
-               .start  = IDE_INT,
-               .end    = IDE_INT,
-               .flags  = IORESOURCE_IRQ
-       },
-       [2] = {
-               .start  = AU1200_DSCR_CMD0_DMA_REQ1,
-               .end    = AU1200_DSCR_CMD0_DMA_REQ1,
-               .flags  = IORESOURCE_DMA,
-       },
-};
-
-static u64 ide_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device ide_device = {
-       .name           = "au1200-ide",
-       .id             = 0,
-       .dev = {
-               .dma_mask               = &ide_dmamask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .num_resources  = ARRAY_SIZE(ide_resources),
-       .resource       = ide_resources
-};
-
-static struct smc91x_platdata smc_data = {
-       .flags  = SMC91X_NOWAIT | SMC91X_USE_16BIT,
-       .leda   = RPC_LED_100_10,
-       .ledb   = RPC_LED_TX_RX,
-};
-
-static struct resource smc91c111_resources[] = {
-       [0] = {
-               .name   = "smc91x-regs",
-               .start  = SMC91C111_PHYS_ADDR,
-               .end    = SMC91C111_PHYS_ADDR + 0xf,
-               .flags  = IORESOURCE_MEM
-       },
-       [1] = {
-               .start  = SMC91C111_INT,
-               .end    = SMC91C111_INT,
-               .flags  = IORESOURCE_IRQ
-       },
-};
-
-static struct platform_device smc91c111_device = {
-       .dev    = {
-               .platform_data  = &smc_data,
-       },
-       .name           = "smc91x",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(smc91c111_resources),
-       .resource       = smc91c111_resources
-};
-
-static struct resource au1200_psc0_res[] = {
-       [0] = {
-               .start  = AU1550_PSC0_PHYS_ADDR,
-               .end    = AU1550_PSC0_PHYS_ADDR + 0xfff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AU1200_PSC0_INT,
-               .end    = AU1200_PSC0_INT,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = AU1200_DSCR_CMD0_PSC0_TX,
-               .end    = AU1200_DSCR_CMD0_PSC0_TX,
-               .flags  = IORESOURCE_DMA,
-       },
-       [3] = {
-               .start  = AU1200_DSCR_CMD0_PSC0_RX,
-               .end    = AU1200_DSCR_CMD0_PSC0_RX,
-               .flags  = IORESOURCE_DMA,
-       },
-};
-
-static struct platform_device pb1200_i2c_dev = {
-       .name           = "au1xpsc_smbus",
-       .id             = 0,    /* bus number */
-       .num_resources  = ARRAY_SIZE(au1200_psc0_res),
-       .resource       = au1200_psc0_res,
-};
-
-static struct resource au1200_lcd_res[] = {
-       [0] = {
-               .start  = AU1200_LCD_PHYS_ADDR,
-               .end    = AU1200_LCD_PHYS_ADDR + 0x800 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AU1200_LCD_INT,
-               .end    = AU1200_LCD_INT,
-               .flags  = IORESOURCE_IRQ,
-       }
-};
-
-static u64 au1200_lcd_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device au1200_lcd_dev = {
-       .name           = "au1200-lcd",
-       .id             = 0,
-       .dev = {
-               .dma_mask               = &au1200_lcd_dmamask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .num_resources  = ARRAY_SIZE(au1200_lcd_res),
-       .resource       = au1200_lcd_res,
-};
-
-static struct platform_device *board_platform_devices[] __initdata = {
-       &ide_device,
-       &smc91c111_device,
-       &pb1200_i2c_dev,
-       &pb1200_mmc0_dev,
-       &pb1200_mmc1_dev,
-       &au1200_lcd_dev,
-};
-
-static int __init board_register_devices(void)
-{
-       int swapped;
-
-       db1x_register_pcmcia_socket(
-               AU1000_PCMCIA_ATTR_PHYS_ADDR,
-               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
-               AU1000_PCMCIA_MEM_PHYS_ADDR,
-               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
-               AU1000_PCMCIA_IO_PHYS_ADDR,
-               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
-               PB1200_PC0_INT, PB1200_PC0_INSERT_INT,
-               /*PB1200_PC0_STSCHG_INT*/0, PB1200_PC0_EJECT_INT, 0);
-
-       db1x_register_pcmcia_socket(
-               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x008000000,
-               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x008400000 - 1,
-               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x008000000,
-               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x008400000 - 1,
-               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x008000000,
-               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x008010000 - 1,
-               PB1200_PC1_INT, PB1200_PC1_INSERT_INT,
-               /*PB1200_PC1_STSCHG_INT*/0, PB1200_PC1_EJECT_INT, 1);
-
-       swapped = bcsr_read(BCSR_STATUS) &  BCSR_STATUS_DB1200_SWAPBOOT;
-       db1x_register_norflash(128 * 1024 * 1024, 2, swapped);
-
-       return platform_add_devices(board_platform_devices,
-                                   ARRAY_SIZE(board_platform_devices));
-}
-device_initcall(board_register_devices);
similarity index 51%
rename from arch/mips/alchemy/devboards/pb1500/board_setup.c
rename to arch/mips/alchemy/devboards/pb1500.c
index 37c1883b5ea99af433727ddbe170df23ec97ff62..e7b807b3ec51b9ecbdb850349e0646aa14193744 100644 (file)
@@ -1,41 +1,37 @@
 /*
- * Copyright 2000, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.com>
+ * Pb1500 board support.
  *
- *  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.
+ * Copyright (C) 2009 Manuel Lauss
  *
- *  THIS  SOFTWARE  IS PROVIDED   ``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   THE AUTHOR  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.
+ * 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.
  *
- *  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.
+ * 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/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-
+#include <linux/platform_device.h>
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-db1x00/bcsr.h>
-
 #include <prom.h>
+#include "platform.h"
 
 const char *get_system_type(void)
 {
-       return "Alchemy Pb1500";
+       return "PB1500";
 }
 
 void __init board_setup(void)
@@ -123,17 +119,80 @@ void __init board_setup(void)
        }
 }
 
-static int __init pb1500_init_irq(void)
+/******************************************************************************/
+
+static int pb1500_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
 {
-       irq_set_irq_type(AU1500_GPIO9_INT, IRQF_TRIGGER_LOW);   /* CD0# */
-       irq_set_irq_type(AU1500_GPIO10_INT, IRQF_TRIGGER_LOW);  /* CARD0 */
-       irq_set_irq_type(AU1500_GPIO11_INT, IRQF_TRIGGER_LOW);  /* STSCHG0# */
+       if ((slot < 12) || (slot > 13) || pin == 0)
+               return -1;
+       if (slot == 12)
+               return (pin == 1) ? AU1500_PCI_INTA : 0xff;
+       if (slot == 13) {
+               switch (pin) {
+               case 1: return AU1500_PCI_INTA;
+               case 2: return AU1500_PCI_INTB;
+               case 3: return AU1500_PCI_INTC;
+               case 4: return AU1500_PCI_INTD;
+               }
+       }
+       return -1;
+}
+
+static struct resource alchemy_pci_host_res[] = {
+       [0] = {
+               .start  = AU1500_PCI_PHYS_ADDR,
+               .end    = AU1500_PCI_PHYS_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct alchemy_pci_platdata pb1500_pci_pd = {
+       .board_map_irq  = pb1500_map_pci_irq,
+       .pci_cfg_set    = PCI_CONFIG_AEN | PCI_CONFIG_R2H | PCI_CONFIG_R1H |
+                         PCI_CONFIG_CH |
+#if defined(__MIPSEB__)
+                         PCI_CONFIG_SIC_HWA_DAT | PCI_CONFIG_SM,
+#else
+                         0,
+#endif
+};
+
+static struct platform_device pb1500_pci_host = {
+       .dev.platform_data = &pb1500_pci_pd,
+       .name           = "alchemy-pci",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(alchemy_pci_host_res),
+       .resource       = alchemy_pci_host_res,
+};
+
+static int __init pb1500_dev_init(void)
+{
+       int swapped;
+
+       irq_set_irq_type(AU1500_GPIO9_INT,   IRQF_TRIGGER_LOW);   /* CD0# */
+       irq_set_irq_type(AU1500_GPIO10_INT,  IRQF_TRIGGER_LOW);  /* CARD0 */
+       irq_set_irq_type(AU1500_GPIO11_INT,  IRQF_TRIGGER_LOW);  /* STSCHG0# */
        irq_set_irq_type(AU1500_GPIO204_INT, IRQF_TRIGGER_HIGH);
        irq_set_irq_type(AU1500_GPIO201_INT, IRQF_TRIGGER_LOW);
        irq_set_irq_type(AU1500_GPIO202_INT, IRQF_TRIGGER_LOW);
        irq_set_irq_type(AU1500_GPIO203_INT, IRQF_TRIGGER_LOW);
        irq_set_irq_type(AU1500_GPIO205_INT, IRQF_TRIGGER_LOW);
 
+       /* PCMCIA. single socket, identical to Pb1100 */
+       db1x_register_pcmcia_socket(
+               AU1000_PCMCIA_ATTR_PHYS_ADDR,
+               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
+               AU1000_PCMCIA_MEM_PHYS_ADDR,
+               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
+               AU1000_PCMCIA_IO_PHYS_ADDR,
+               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
+               AU1500_GPIO11_INT, AU1500_GPIO9_INT,     /* card / insert */
+               /*AU1500_GPIO10_INT*/0, 0, 0); /* stschg / eject / id */
+
+       swapped = bcsr_read(BCSR_STATUS) &  BCSR_STATUS_DB1000_SWAPBOOT;
+       db1x_register_norflash(64 * 1024 * 1024, 4, swapped);
+       platform_device_register(&pb1500_pci_host);
+
        return 0;
 }
-arch_initcall(pb1500_init_irq);
+arch_initcall(pb1500_dev_init);
diff --git a/arch/mips/alchemy/devboards/pb1500/Makefile b/arch/mips/alchemy/devboards/pb1500/Makefile
deleted file mode 100644 (file)
index e83b151..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-#  Copyright 2000, 2001, 2008 MontaVista Software Inc.
-#  Author: MontaVista Software, Inc. <source@mvista.com>
-#
-# Makefile for the Alchemy Semiconductor Pb1500 board.
-#
-
-obj-y := board_setup.o platform.o
diff --git a/arch/mips/alchemy/devboards/pb1500/platform.c b/arch/mips/alchemy/devboards/pb1500/platform.c
deleted file mode 100644 (file)
index 1e52a01..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Pb1500 board platform device registration
- *
- * Copyright (C) 2009 Manuel Lauss
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-db1x00/bcsr.h>
-
-#include "../platform.h"
-
-static int pb1500_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
-{
-       if ((slot < 12) || (slot > 13) || pin == 0)
-               return -1;
-       if (slot == 12)
-               return (pin == 1) ? AU1500_PCI_INTA : 0xff;
-       if (slot == 13) {
-               switch (pin) {
-               case 1: return AU1500_PCI_INTA;
-               case 2: return AU1500_PCI_INTB;
-               case 3: return AU1500_PCI_INTC;
-               case 4: return AU1500_PCI_INTD;
-               }
-       }
-       return -1;
-}
-
-static struct resource alchemy_pci_host_res[] = {
-       [0] = {
-               .start  = AU1500_PCI_PHYS_ADDR,
-               .end    = AU1500_PCI_PHYS_ADDR + 0xfff,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct alchemy_pci_platdata pb1500_pci_pd = {
-       .board_map_irq  = pb1500_map_pci_irq,
-       .pci_cfg_set    = PCI_CONFIG_AEN | PCI_CONFIG_R2H | PCI_CONFIG_R1H |
-                         PCI_CONFIG_CH |
-#if defined(__MIPSEB__)
-                         PCI_CONFIG_SIC_HWA_DAT | PCI_CONFIG_SM,
-#else
-                         0,
-#endif
-};
-
-static struct platform_device pb1500_pci_host = {
-       .dev.platform_data = &pb1500_pci_pd,
-       .name           = "alchemy-pci",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(alchemy_pci_host_res),
-       .resource       = alchemy_pci_host_res,
-};
-
-static int __init pb1500_dev_init(void)
-{
-       int swapped;
-
-       /* PCMCIA. single socket, identical to Pb1100 */
-       db1x_register_pcmcia_socket(
-               AU1000_PCMCIA_ATTR_PHYS_ADDR,
-               AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
-               AU1000_PCMCIA_MEM_PHYS_ADDR,
-               AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
-               AU1000_PCMCIA_IO_PHYS_ADDR,
-               AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
-               AU1500_GPIO11_INT, AU1500_GPIO9_INT,     /* card / insert */
-               /*AU1500_GPIO10_INT*/0, 0, 0); /* stschg / eject / id */
-
-       swapped = bcsr_read(BCSR_STATUS) &  BCSR_STATUS_DB1000_SWAPBOOT;
-       db1x_register_norflash(64 * 1024 * 1024, 4, swapped);
-       platform_device_register(&pb1500_pci_host);
-
-       return 0;
-}
-arch_initcall(pb1500_dev_init);
similarity index 61%
rename from arch/mips/alchemy/devboards/pb1550/platform.c
rename to arch/mips/alchemy/devboards/pb1550.c
index a4604b8a349ef222d7a7d2a5c83ab0536f524ed0..b37e7de8d9209682a4191f86eb69316bd4fdc2de 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Pb1550 board platform device registration
+ * Pb1550 board support.
  *
- * Copyright (C) 2009 Manuel Lauss
+ * Copyright (C) 2009-2011 Manuel Lauss
  *
  * 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 <linux/dma-mapping.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
-#include <asm/mach-pb1x00/pb1550.h>
+#include <asm/mach-au1x00/au1550nd.h>
+#include <asm/mach-au1x00/gpio.h>
 #include <asm/mach-db1x00/bcsr.h>
+#include "platform.h"
 
-#include "../platform.h"
+const char *get_system_type(void)
+{
+       return "PB1550";
+}
+
+void __init board_setup(void)
+{
+       u32 pin_func;
+
+       bcsr_init(PB1550_BCSR_PHYS_ADDR,
+                 PB1550_BCSR_PHYS_ADDR + PB1550_BCSR_HEXLED_OFS);
+
+       alchemy_gpio2_enable();
+
+       /*
+        * Enable PSC1 SYNC for AC'97.  Normaly done in audio driver,
+        * but it is board specific code, so put it here.
+        */
+       pin_func = au_readl(SYS_PINFUNC);
+       au_sync();
+       pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1;
+       au_writel(pin_func, SYS_PINFUNC);
+
+       bcsr_write(BCSR_PCMCIA, 0);     /* turn off PCMCIA power */
+
+       printk(KERN_INFO "AMD Alchemy Pb1550 Board\n");
+}
+
+/******************************************************************************/
 
 static int pb1550_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
 {
@@ -101,10 +132,79 @@ static struct platform_device pb1550_i2c_dev = {
        .resource       = au1550_psc2_res,
 };
 
+static struct mtd_partition pb1550_nand_parts[] = {
+       [0] = {
+               .name   = "NAND FS 0",
+               .offset = 0,
+               .size   = 8 * 1024 * 1024,
+       },
+       [1] = {
+               .name   = "NAND FS 1",
+               .offset = MTDPART_OFS_APPEND,
+               .size   = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct au1550nd_platdata pb1550_nand_pd = {
+       .parts          = pb1550_nand_parts,
+       .num_parts      = ARRAY_SIZE(pb1550_nand_parts),
+       .devwidth       = 0,    /* x8 NAND default, needs fixing up */
+};
+
+static struct resource pb1550_nand_res[] = {
+       [0] = {
+               .start  = 0x20000000,
+               .end    = 0x20000fff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device pb1550_nand_dev = {
+       .name           = "au1550-nand",
+       .id             = -1,
+       .resource       = pb1550_nand_res,
+       .num_resources  = ARRAY_SIZE(pb1550_nand_res),
+       .dev            = {
+               .platform_data  = &pb1550_nand_pd,
+       },
+};
+
+static void __init pb1550_nand_setup(void)
+{
+       int boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) |
+                           ((bcsr_read(BCSR_STATUS) >> 6) & 0x1);
+
+       switch (boot_swapboot) {
+       case 0:
+       case 2:
+       case 8:
+       case 0xC:
+       case 0xD:
+               /* x16 NAND Flash */
+               pb1550_nand_pd.devwidth = 1;
+               /* fallthrough */
+       case 1:
+       case 9:
+       case 3:
+       case 0xE:
+       case 0xF:
+               /* x8 NAND, already set up */
+               platform_device_register(&pb1550_nand_dev);
+       }
+}
+
 static int __init pb1550_dev_init(void)
 {
        int swapped;
 
+       irq_set_irq_type(AU1550_GPIO0_INT, IRQF_TRIGGER_LOW);
+       irq_set_irq_type(AU1550_GPIO1_INT, IRQF_TRIGGER_LOW);
+       irq_set_irq_type(AU1550_GPIO201_205_INT, IRQF_TRIGGER_HIGH);
+
+       /* enable both PCMCIA card irqs in the shared line */
+       alchemy_gpio2_enable_int(201);
+       alchemy_gpio2_enable_int(202);
+
        /* Pb1550, like all others, also has statuschange irqs; however they're
        * wired up on one of the Au1550's shared GPIO201_205 line, which also
        * services the PCMCIA card interrupts.  So we ignore statuschange and
@@ -130,6 +230,10 @@ static int __init pb1550_dev_init(void)
                AU1000_PCMCIA_IO_PHYS_ADDR   + 0x008010000 - 1,
                AU1550_GPIO201_205_INT, AU1550_GPIO1_INT, 0, 0, 1);
 
+       /* NAND setup */
+       gpio_direction_input(206);      /* GPIO206 high */
+       pb1550_nand_setup();
+
        swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_PB1550_SWAPBOOT;
        db1x_register_norflash(128 * 1024 * 1024, 4, swapped);
        platform_device_register(&pb1550_pci_host);
diff --git a/arch/mips/alchemy/devboards/pb1550/Makefile b/arch/mips/alchemy/devboards/pb1550/Makefile
deleted file mode 100644 (file)
index 9661b6e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-#  Copyright 2000, 2008 MontaVista Software Inc.
-#  Author: MontaVista Software, Inc. <source@mvista.com>
-#
-# Makefile for the Alchemy Semiconductor Pb1550 board.
-#
-
-obj-y := board_setup.o platform.o
diff --git a/arch/mips/alchemy/devboards/pb1550/board_setup.c b/arch/mips/alchemy/devboards/pb1550/board_setup.c
deleted file mode 100644 (file)
index 0f62d1e..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- *     Alchemy Pb1550 board setup.
- *
- * Copyright 2000, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.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  SOFTWARE  IS PROVIDED   ``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   THE AUTHOR  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.
- *
- *  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/init.h>
-#include <linux/interrupt.h>
-
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-pb1x00/pb1550.h>
-#include <asm/mach-db1x00/bcsr.h>
-#include <asm/mach-au1x00/gpio.h>
-
-#include <prom.h>
-
-const char *get_system_type(void)
-{
-       return "Alchemy Pb1550";
-}
-
-void __init board_setup(void)
-{
-       u32 pin_func;
-
-       bcsr_init(PB1550_BCSR_PHYS_ADDR,
-                 PB1550_BCSR_PHYS_ADDR + PB1550_BCSR_HEXLED_OFS);
-
-       alchemy_gpio2_enable();
-
-       /*
-        * Enable PSC1 SYNC for AC'97.  Normaly done in audio driver,
-        * but it is board specific code, so put it here.
-        */
-       pin_func = au_readl(SYS_PINFUNC);
-       au_sync();
-       pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1;
-       au_writel(pin_func, SYS_PINFUNC);
-
-       bcsr_write(BCSR_PCMCIA, 0);     /* turn off PCMCIA power */
-
-       printk(KERN_INFO "AMD Alchemy Pb1550 Board\n");
-}
-
-static int __init pb1550_init_irq(void)
-{
-       irq_set_irq_type(AU1550_GPIO0_INT, IRQF_TRIGGER_LOW);
-       irq_set_irq_type(AU1550_GPIO1_INT, IRQF_TRIGGER_LOW);
-       irq_set_irq_type(AU1550_GPIO201_205_INT, IRQF_TRIGGER_HIGH);
-
-       /* enable both PCMCIA card irqs in the shared line */
-       alchemy_gpio2_enable_int(201);
-       alchemy_gpio2_enable_int(202);
-
-       return 0;
-}
-arch_initcall(pb1550_init_irq);
index 49a4b3244d8e1ad792f701b2f3b550617078c5f8..621f70afb63a10189751b8123a6ed04b1e5c78c9 100644 (file)
 #include <asm/reboot.h>
 #include <asm/mach-db1x00/bcsr.h>
 
+
+static struct platform_device db1x00_rtc_dev = {
+       .name   = "rtc-au1xxx",
+       .id     = -1,
+};
+
+
 static void db1x_power_off(void)
 {
        bcsr_write(BCSR_RESETS, 0);
@@ -25,7 +32,7 @@ static void db1x_reset(char *c)
        bcsr_write(BCSR_SYSTEM, 0);
 }
 
-static int __init db1x_poweroff_setup(void)
+static int __init db1x_late_setup(void)
 {
        if (!pm_power_off)
                pm_power_off = db1x_power_off;
@@ -34,9 +41,11 @@ static int __init db1x_poweroff_setup(void)
        if (!_machine_restart)
                _machine_restart = db1x_reset;
 
+       platform_device_register(&db1x00_rtc_dev);
+
        return 0;
 }
-late_initcall(db1x_poweroff_setup);
+device_initcall(db1x_late_setup);
 
 /* register a pcmcia socket */
 int __init db1x_register_pcmcia_socket(phys_addr_t pcmcia_attr_start,
index e5306b56da6d011face7e6072c93eb82ed3ab0fc..93a22107cc41fc2d39fdf2c000ce25b47b84ead6 100644 (file)
 #include <asm/mach-au1x00/au1000.h>
 #include <prom.h>
 
-#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_DB1000) || \
-    defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100) || \
-    defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_DB1500) || \
-    defined(CONFIG_MIPS_BOSPORUS) || defined(CONFIG_MIPS_MIRAGE)
+#if defined(CONFIG_MIPS_DB1000) || \
+    defined(CONFIG_MIPS_PB1100) || \
+    defined(CONFIG_MIPS_PB1500)
 #define ALCHEMY_BOARD_DEFAULT_MEMSIZE  0x04000000
 
 #else  /* Au1550/Au1200-based develboards */
@@ -62,5 +61,9 @@ void __init prom_init(void)
 
 void prom_putchar(unsigned char c)
 {
+#ifdef CONFIG_MIPS_DB1300
+       alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c);
+#else
        alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
+#endif
 }
diff --git a/arch/mips/alchemy/gpr/Makefile b/arch/mips/alchemy/gpr/Makefile
deleted file mode 100644 (file)
index cb73fe2..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-#  Copyright 2003 MontaVista Software Inc.
-#  Author: MontaVista Software, Inc. <source@mvista.com>
-#
-# Makefile for Trapeze ITS GPR board.
-#
-
-obj-y += board_setup.o init.o platform.o
diff --git a/arch/mips/alchemy/gpr/board_setup.c b/arch/mips/alchemy/gpr/board_setup.c
deleted file mode 100644 (file)
index dea45c7..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2010 Wolfgang Grandegger <wg@denx.de>
- *
- * Copyright 2000-2003, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.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  SOFTWARE  IS PROVIDED   ``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   THE AUTHOR  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.
- *
- *  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/gpio.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-
-#include <asm/reboot.h>
-#include <asm/mach-au1x00/au1000.h>
-
-#include <prom.h>
-
-static void gpr_reset(char *c)
-{
-       /* switch System-LED to orange (red# and green# on) */
-       alchemy_gpio_direction_output(4, 0);
-       alchemy_gpio_direction_output(5, 0);
-
-       /* trigger watchdog to reset board in 200ms */
-       printk(KERN_EMERG "Triggering watchdog soft reset...\n");
-       raw_local_irq_disable();
-       alchemy_gpio_direction_output(1, 0);
-       udelay(1);
-       alchemy_gpio_set_value(1, 1);
-       while (1)
-               cpu_wait();
-}
-
-static void gpr_power_off(void)
-{
-       while (1)
-               cpu_wait();
-}
-
-void __init board_setup(void)
-{
-       printk(KERN_INFO "Trapeze ITS GPR board\n");
-
-       pm_power_off = gpr_power_off;
-       _machine_halt = gpr_power_off;
-       _machine_restart = gpr_reset;
-
-       /* Enable UART1/3 */
-       alchemy_uart_enable(AU1000_UART3_PHYS_ADDR);
-       alchemy_uart_enable(AU1000_UART1_PHYS_ADDR);
-
-       /* Take away Reset of UMTS-card */
-       alchemy_gpio_direction_output(215, 1);
-}
diff --git a/arch/mips/alchemy/gpr/init.c b/arch/mips/alchemy/gpr/init.c
deleted file mode 100644 (file)
index 229aafa..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2010 Wolfgang Grandegger <wg@denx.de>
- *
- * Copyright 2003, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.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  SOFTWARE  IS PROVIDED   ``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   THE AUTHOR  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.
- *
- *  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/init.h>
-#include <linux/kernel.h>
-
-#include <asm/bootinfo.h>
-#include <asm/mach-au1x00/au1000.h>
-
-#include <prom.h>
-
-const char *get_system_type(void)
-{
-       return "GPR";
-}
-
-void __init prom_init(void)
-{
-       unsigned char *memsize_str;
-       unsigned long memsize;
-
-       prom_argc = fw_arg0;
-       prom_argv = (char **)fw_arg1;
-       prom_envp = (char **)fw_arg2;
-
-       prom_init_cmdline();
-
-       memsize_str = prom_getenv("memsize");
-       if (!memsize_str)
-               memsize = 0x04000000;
-       else
-               strict_strtoul(memsize_str, 0, &memsize);
-       add_memory_region(0, memsize, BOOT_MEM_RAM);
-}
-
-void prom_putchar(unsigned char c)
-{
-       alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
-}
diff --git a/arch/mips/alchemy/mtx-1/Makefile b/arch/mips/alchemy/mtx-1/Makefile
deleted file mode 100644 (file)
index 81b540c..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-#  Copyright 2003 MontaVista Software Inc.
-#  Author: MontaVista Software, Inc. <source@mvista.com>
-#       Bruno Randolf <bruno.randolf@4g-systems.biz>
-#
-# Makefile for 4G Systems MTX-1 board.
-#
-
-obj-y += init.o board_setup.o platform.o
diff --git a/arch/mips/alchemy/mtx-1/board_setup.c b/arch/mips/alchemy/mtx-1/board_setup.c
deleted file mode 100644 (file)
index 851a5ab..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- *     4G Systems MTX-1 board setup.
- *
- * Copyright 2003, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.com>
- *         Bruno Randolf <bruno.randolf@4g-systems.biz>
- *
- *  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  SOFTWARE  IS PROVIDED   ``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   THE AUTHOR  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.
- *
- *  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/gpio.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/pm.h>
-
-#include <asm/reboot.h>
-#include <asm/mach-au1x00/au1000.h>
-
-#include <prom.h>
-
-static void mtx1_reset(char *c)
-{
-       /* Jump to the reset vector */
-       __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
-}
-
-static void mtx1_power_off(void)
-{
-       while (1)
-               asm volatile (
-               "       .set    mips32                                  \n"
-               "       wait                                            \n"
-               "       .set    mips0                                   \n");
-}
-
-void __init board_setup(void)
-{
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-       /* Enable USB power switch */
-       alchemy_gpio_direction_output(204, 0);
-#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */
-
-       /* Initialize sys_pinfunc */
-       au_writel(SYS_PF_NI2, SYS_PINFUNC);
-
-       /* Initialize GPIO */
-       au_writel(~0, KSEG1ADDR(AU1000_SYS_PHYS_ADDR) + SYS_TRIOUTCLR);
-       alchemy_gpio_direction_output(0, 0);    /* Disable M66EN (PCI 66MHz) */
-       alchemy_gpio_direction_output(3, 1);    /* Disable PCI CLKRUN# */
-       alchemy_gpio_direction_output(1, 1);    /* Enable EXT_IO3 */
-       alchemy_gpio_direction_output(5, 0);    /* Disable eth PHY TX_ER */
-
-       /* Enable LED and set it to green */
-       alchemy_gpio_direction_output(211, 1);  /* green on */
-       alchemy_gpio_direction_output(212, 0);  /* red off */
-
-       pm_power_off = mtx1_power_off;
-       _machine_halt = mtx1_power_off;
-       _machine_restart = mtx1_reset;
-
-       printk(KERN_INFO "4G Systems MTX-1 Board\n");
-}
-
-static int __init mtx1_init_irq(void)
-{
-       irq_set_irq_type(AU1500_GPIO204_INT, IRQF_TRIGGER_HIGH);
-       irq_set_irq_type(AU1500_GPIO201_INT, IRQF_TRIGGER_LOW);
-       irq_set_irq_type(AU1500_GPIO202_INT, IRQF_TRIGGER_LOW);
-       irq_set_irq_type(AU1500_GPIO203_INT, IRQF_TRIGGER_LOW);
-       irq_set_irq_type(AU1500_GPIO205_INT, IRQF_TRIGGER_LOW);
-
-       return 0;
-}
-arch_initcall(mtx1_init_irq);
diff --git a/arch/mips/alchemy/mtx-1/init.c b/arch/mips/alchemy/mtx-1/init.c
deleted file mode 100644 (file)
index 2e81cc7..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- *     4G Systems MTX-1 board setup
- *
- * Copyright 2003, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.com>
- *         Bruno Randolf <bruno.randolf@4g-systems.biz>
- *
- *  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  SOFTWARE  IS PROVIDED   ``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   THE AUTHOR  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.
- *
- *  You should have received a copy of the  GNU General Public License along
- *  with this program; if not, write  to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/bootinfo.h>
-#include <asm/mach-au1x00/au1000.h>
-
-#include <prom.h>
-
-const char *get_system_type(void)
-{
-       return "MTX-1";
-}
-
-void __init prom_init(void)
-{
-       unsigned char *memsize_str;
-       unsigned long memsize;
-
-       prom_argc = fw_arg0;
-       prom_argv = (char **)fw_arg1;
-       prom_envp = (char **)fw_arg2;
-
-       prom_init_cmdline();
-
-       memsize_str = prom_getenv("memsize");
-       if (!memsize_str)
-               memsize = 0x04000000;
-       else
-               strict_strtoul(memsize_str, 0, &memsize);
-       add_memory_region(0, memsize, BOOT_MEM_RAM);
-}
-
-void prom_putchar(unsigned char c)
-{
-       alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
-}
diff --git a/arch/mips/alchemy/xxs1500/Makefile b/arch/mips/alchemy/xxs1500/Makefile
deleted file mode 100644 (file)
index 91defcf..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-#  Copyright 2003 MontaVista Software Inc.
-#  Author: MontaVista Software, Inc. <source@mvista.com>
-#
-# Makefile for MyCable XXS1500 board.
-#
-
-obj-y += init.o board_setup.o platform.o
diff --git a/arch/mips/alchemy/xxs1500/board_setup.c b/arch/mips/alchemy/xxs1500/board_setup.c
deleted file mode 100644 (file)
index 3fa83f7..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2000-2003, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.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  SOFTWARE  IS PROVIDED   ``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   THE AUTHOR  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.
- *
- *  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/gpio.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-
-#include <asm/reboot.h>
-#include <asm/mach-au1x00/au1000.h>
-
-#include <prom.h>
-
-static void xxs1500_reset(char *c)
-{
-       /* Jump to the reset vector */
-       __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
-}
-
-static void xxs1500_power_off(void)
-{
-       while (1)
-               asm volatile (
-               "       .set    mips32                                  \n"
-               "       wait                                            \n"
-               "       .set    mips0                                   \n");
-}
-
-void __init board_setup(void)
-{
-       u32 pin_func;
-
-       pm_power_off = xxs1500_power_off;
-       _machine_halt = xxs1500_power_off;
-       _machine_restart = xxs1500_reset;
-
-       alchemy_gpio1_input_enable();
-       alchemy_gpio2_enable();
-
-       /* Set multiple use pins (UART3/GPIO) to UART (it's used as UART too) */
-       pin_func  = au_readl(SYS_PINFUNC) & ~SYS_PF_UR3;
-       pin_func |= SYS_PF_UR3;
-       au_writel(pin_func, SYS_PINFUNC);
-
-       /* Enable UART */
-       alchemy_uart_enable(AU1000_UART3_PHYS_ADDR);
-       /* Enable DTR (MCR bit 0) = USB power up */
-       __raw_writel(1, (void __iomem *)KSEG1ADDR(AU1000_UART3_PHYS_ADDR + 0x18));
-       wmb();
-}
-
-static int __init xxs1500_init_irq(void)
-{
-       irq_set_irq_type(AU1500_GPIO204_INT, IRQF_TRIGGER_HIGH);
-       irq_set_irq_type(AU1500_GPIO201_INT, IRQF_TRIGGER_LOW);
-       irq_set_irq_type(AU1500_GPIO202_INT, IRQF_TRIGGER_LOW);
-       irq_set_irq_type(AU1500_GPIO203_INT, IRQF_TRIGGER_LOW);
-       irq_set_irq_type(AU1500_GPIO205_INT, IRQF_TRIGGER_LOW);
-       irq_set_irq_type(AU1500_GPIO207_INT, IRQF_TRIGGER_LOW);
-
-       irq_set_irq_type(AU1500_GPIO0_INT, IRQF_TRIGGER_LOW);
-       irq_set_irq_type(AU1500_GPIO1_INT, IRQF_TRIGGER_LOW);
-       irq_set_irq_type(AU1500_GPIO2_INT, IRQF_TRIGGER_LOW);
-       irq_set_irq_type(AU1500_GPIO3_INT, IRQF_TRIGGER_LOW);
-       irq_set_irq_type(AU1500_GPIO4_INT, IRQF_TRIGGER_LOW); /* CF irq */
-       irq_set_irq_type(AU1500_GPIO5_INT, IRQF_TRIGGER_LOW);
-
-       return 0;
-}
-arch_initcall(xxs1500_init_irq);
diff --git a/arch/mips/alchemy/xxs1500/init.c b/arch/mips/alchemy/xxs1500/init.c
deleted file mode 100644 (file)
index 0ee02cf..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- *     XXS1500 board setup
- *
- * Copyright 2003, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.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  SOFTWARE  IS PROVIDED   ``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   THE AUTHOR  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.
- *
- *  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/init.h>
-#include <linux/kernel.h>
-
-#include <asm/bootinfo.h>
-#include <asm/mach-au1x00/au1000.h>
-
-#include <prom.h>
-
-const char *get_system_type(void)
-{
-       return "XXS1500";
-}
-
-void __init prom_init(void)
-{
-       unsigned char *memsize_str;
-       unsigned long memsize;
-
-       prom_argc = fw_arg0;
-       prom_argv = (char **)fw_arg1;
-       prom_envp = (char **)fw_arg2;
-
-       prom_init_cmdline();
-
-       memsize_str = prom_getenv("memsize");
-       if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize))
-               memsize = 0x04000000;
-
-       add_memory_region(0, memsize, BOOT_MEM_RAM);
-}
-
-void prom_putchar(unsigned char c)
-{
-       alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
-}
diff --git a/arch/mips/alchemy/xxs1500/platform.c b/arch/mips/alchemy/xxs1500/platform.c
deleted file mode 100644 (file)
index 06a3a45..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * XXS1500 board platform device registration
- *
- * Copyright (C) 2009 Manuel Lauss
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-
-#include <asm/mach-au1x00/au1000.h>
-
-static struct resource xxs1500_pcmcia_res[] = {
-       {
-               .name   = "pcmcia-io",
-               .flags  = IORESOURCE_MEM,
-               .start  = AU1000_PCMCIA_IO_PHYS_ADDR,
-               .end    = AU1000_PCMCIA_IO_PHYS_ADDR + 0x000400000 - 1,
-       },
-       {
-               .name   = "pcmcia-attr",
-               .flags  = IORESOURCE_MEM,
-               .start  = AU1000_PCMCIA_ATTR_PHYS_ADDR,
-               .end    = AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
-       },
-       {
-               .name   = "pcmcia-mem",
-               .flags  = IORESOURCE_MEM,
-               .start  = AU1000_PCMCIA_MEM_PHYS_ADDR,
-               .end    = AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
-       },
-};
-
-static struct platform_device xxs1500_pcmcia_dev = {
-       .name           = "xxs1500_pcmcia",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(xxs1500_pcmcia_res),
-       .resource       = xxs1500_pcmcia_res,
-};
-
-static struct platform_device *xxs1500_devs[] __initdata = {
-       &xxs1500_pcmcia_dev,
-};
-
-static int __init xxs1500_dev_init(void)
-{
-       return platform_add_devices(xxs1500_devs,
-                                   ARRAY_SIZE(xxs1500_devs));
-}
-device_initcall(xxs1500_dev_init);
index bb571bcdb8f2f06d5d2cb8b2d787591f35b4e66d..d8dbd8f0c1d2924308da51f309e4b4f16a9c7111 100644 (file)
@@ -217,7 +217,7 @@ struct titan_gpio_cfg {
        u32 func;
 };
 
-static struct titan_gpio_cfg titan_gpio_table[] = {
+static const struct titan_gpio_cfg titan_gpio_table[] = {
        /* reg, start bit, mux value */
        {4, 24, 1},
        {4, 26, 1},
index 33ffecf6a6d662403cc8cd3fb24de1737dc3e39b..1a24d317e7a3a5d52e11724e93bf2400db78a4a1 100644 (file)
@@ -462,6 +462,40 @@ static struct gpio_led fb_fon_leds[] = {
        },
 };
 
+static struct gpio_led gt701_leds[] = {
+       {
+               .name                   = "inet:green",
+               .gpio                   = 13,
+               .active_low             = 1,
+       },
+       {
+               .name                   = "usb",
+               .gpio                   = 12,
+               .active_low             = 1,
+       },
+       {
+               .name                   = "inet:red",
+               .gpio                   = 9,
+               .active_low             = 1,
+       },
+       {
+               .name                   = "power:red",
+               .gpio                   = 7,
+               .active_low             = 1,
+       },
+       {
+               .name                   = "power:green",
+               .gpio                   = 8,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+        {
+                .name                   = "ethernet",
+                .gpio                   = 10,
+                .active_low             = 1,
+        },
+};
+
 static struct gpio_led_platform_data ar7_led_data;
 
 static struct platform_device ar7_gpio_leds = {
@@ -503,6 +537,9 @@ static void __init detect_leds(void)
        } else if (strstr(prid, "CYWM") || strstr(prid, "CYWL")) {
                ar7_led_data.num_leds = ARRAY_SIZE(titan_leds);
                ar7_led_data.leds = titan_leds;
+       } else if (strstr(prid, "GT701")) {
+               ar7_led_data.num_leds = ARRAY_SIZE(gt701_leds);
+               ar7_led_data.leds = gt701_leds;
        }
 }
 
@@ -536,7 +573,7 @@ static int __init ar7_register_uarts(void)
 
        bus_clk = clk_get(NULL, "bus");
        if (IS_ERR(bus_clk))
-               panic("unable to get bus clk\n");
+               panic("unable to get bus clk");
 
        uart_port.type          = PORT_AR7;
        uart_port.uartclk       = clk_get_rate(bus_clk) / 2;
index 8088c6fdb83ed7e0a2b1689373569dbd3a526988..a23adc49d50fa2348ac4788d4feb38211318989d 100644 (file)
@@ -69,7 +69,7 @@ struct psbl_rec {
        u32     ffs_size;
 };
 
-static __initdata char psp_env_version[] = "TIENV0.8";
+static const char psp_env_version[] __initconst = "TIENV0.8";
 
 struct psp_env_chunk {
        u8      num;
@@ -84,7 +84,7 @@ struct psp_var_map_entry {
        char    *value;
 };
 
-static struct psp_var_map_entry psp_var_map[] = {
+static const struct psp_var_map_entry psp_var_map[] = {
        {  1,   "cpufrequency" },
        {  2,   "memsize" },
        {  3,   "flashsize" },
index f20b53e597c42fca192bc40866da920452c36cb9..9a357fffcfbe0a0c6767e5b12d70d22f23e5b1b7 100644 (file)
@@ -96,7 +96,7 @@ void __init plat_mem_setup(void)
 
        io_base = (unsigned long)ioremap(AR7_REGS_BASE, 0x10000);
        if (!io_base)
-               panic("Can't remap IO base!\n");
+               panic("Can't remap IO base!");
        set_io_port_base(io_base);
 
        prom_meminit();
index 47707410582cc3a584b21ec9547cba937a17fa3c..e0fae8f4442b792dbb86bcbbf15a260edf91b2ce 100644 (file)
@@ -2,13 +2,26 @@ if ATH79
 
 menu "Atheros AR71XX/AR724X/AR913X machine selection"
 
+config ATH79_MACH_AP121
+       bool "Atheros AP121 reference board"
+       select SOC_AR933X
+       select ATH79_DEV_GPIO_BUTTONS
+       select ATH79_DEV_LEDS_GPIO
+       select ATH79_DEV_SPI
+       select ATH79_DEV_USB
+       select ATH79_DEV_WMAC
+       help
+         Say 'Y' here if you want your kernel to support the
+         Atheros AP121 reference board.
+
 config ATH79_MACH_AP81
        bool "Atheros AP81 reference board"
        select SOC_AR913X
-       select ATH79_DEV_AR913X_WMAC
        select ATH79_DEV_GPIO_BUTTONS
        select ATH79_DEV_LEDS_GPIO
        select ATH79_DEV_SPI
+       select ATH79_DEV_USB
+       select ATH79_DEV_WMAC
        help
          Say 'Y' here if you want your kernel to support the
          Atheros AP81 reference board.
@@ -19,10 +32,21 @@ config ATH79_MACH_PB44
        select ATH79_DEV_GPIO_BUTTONS
        select ATH79_DEV_LEDS_GPIO
        select ATH79_DEV_SPI
+       select ATH79_DEV_USB
        help
          Say 'Y' here if you want your kernel to support the
          Atheros PB44 reference board.
 
+config ATH79_MACH_UBNT_XM
+       bool "Ubiquiti Networks XM (rev 1.0) board"
+       select SOC_AR724X
+       select ATH79_DEV_GPIO_BUTTONS
+       select ATH79_DEV_LEDS_GPIO
+       select ATH79_DEV_SPI
+       help
+         Say 'Y' here if you want your kernel to support the
+         Ubiquiti Networks XM (rev 1.0) board.
+
 endmenu
 
 config SOC_AR71XX
@@ -33,14 +57,15 @@ config SOC_AR71XX
 config SOC_AR724X
        select USB_ARCH_HAS_EHCI
        select USB_ARCH_HAS_OHCI
+       select HW_HAS_PCI
        def_bool n
 
 config SOC_AR913X
        select USB_ARCH_HAS_EHCI
        def_bool n
 
-config ATH79_DEV_AR913X_WMAC
-       depends on SOC_AR913X
+config SOC_AR933X
+       select USB_ARCH_HAS_EHCI
        def_bool n
 
 config ATH79_DEV_GPIO_BUTTONS
@@ -52,4 +77,11 @@ config ATH79_DEV_LEDS_GPIO
 config ATH79_DEV_SPI
        def_bool n
 
+config ATH79_DEV_USB
+       def_bool n
+
+config ATH79_DEV_WMAC
+       depends on (SOC_AR913X || SOC_AR933X)
+       def_bool n
+
 endif
index c33d4653007c3cd1545873fc2e151e1cf04f2e48..3b911e09dbecb5386136b4872affb515a8438caa 100644 (file)
@@ -16,13 +16,16 @@ obj-$(CONFIG_EARLY_PRINTK)          += early_printk.o
 # Devices
 #
 obj-y                                  += dev-common.o
-obj-$(CONFIG_ATH79_DEV_AR913X_WMAC)    += dev-ar913x-wmac.o
 obj-$(CONFIG_ATH79_DEV_GPIO_BUTTONS)   += dev-gpio-buttons.o
 obj-$(CONFIG_ATH79_DEV_LEDS_GPIO)      += dev-leds-gpio.o
 obj-$(CONFIG_ATH79_DEV_SPI)            += dev-spi.o
+obj-$(CONFIG_ATH79_DEV_USB)            += dev-usb.o
+obj-$(CONFIG_ATH79_DEV_WMAC)           += dev-wmac.o
 
 #
 # Machines
 #
+obj-$(CONFIG_ATH79_MACH_AP121)         += mach-ap121.o
 obj-$(CONFIG_ATH79_MACH_AP81)          += mach-ap81.o
 obj-$(CONFIG_ATH79_MACH_PB44)          += mach-pb44.o
+obj-$(CONFIG_ATH79_MACH_UBNT_XM)       += mach-ubnt-xm.o
index 680bde99a26c3bf8ad314549b8d7ee16cbcdbfe0..54d0eb4db987266657f1ac5fa58085015d820f4c 100644 (file)
@@ -110,6 +110,59 @@ static void __init ar913x_clocks_init(void)
        ath79_uart_clk.rate = ath79_ahb_clk.rate;
 }
 
+static void __init ar933x_clocks_init(void)
+{
+       u32 clock_ctrl;
+       u32 cpu_config;
+       u32 freq;
+       u32 t;
+
+       t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
+       if (t & AR933X_BOOTSTRAP_REF_CLK_40)
+               ath79_ref_clk.rate = (40 * 1000 * 1000);
+       else
+               ath79_ref_clk.rate = (25 * 1000 * 1000);
+
+       clock_ctrl = ath79_pll_rr(AR933X_PLL_CLOCK_CTRL_REG);
+       if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) {
+               ath79_cpu_clk.rate = ath79_ref_clk.rate;
+               ath79_ahb_clk.rate = ath79_ref_clk.rate;
+               ath79_ddr_clk.rate = ath79_ref_clk.rate;
+       } else {
+               cpu_config = ath79_pll_rr(AR933X_PLL_CPU_CONFIG_REG);
+
+               t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
+                   AR933X_PLL_CPU_CONFIG_REFDIV_MASK;
+               freq = ath79_ref_clk.rate / t;
+
+               t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) &
+                   AR933X_PLL_CPU_CONFIG_NINT_MASK;
+               freq *= t;
+
+               t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
+                   AR933X_PLL_CPU_CONFIG_OUTDIV_MASK;
+               if (t == 0)
+                       t = 1;
+
+               freq >>= t;
+
+               t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) &
+                    AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1;
+               ath79_cpu_clk.rate = freq / t;
+
+               t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) &
+                     AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1;
+               ath79_ddr_clk.rate = freq / t;
+
+               t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) &
+                    AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1;
+               ath79_ahb_clk.rate = freq / t;
+       }
+
+       ath79_wdt_clk.rate = ath79_ref_clk.rate;
+       ath79_uart_clk.rate = ath79_ref_clk.rate;
+}
+
 void __init ath79_clocks_init(void)
 {
        if (soc_is_ar71xx())
@@ -118,6 +171,8 @@ void __init ath79_clocks_init(void)
                ar724x_clocks_init();
        else if (soc_is_ar913x())
                ar913x_clocks_init();
+       else if (soc_is_ar933x())
+               ar933x_clocks_init();
        else
                BUG();
 
index 58f60e722a0340e01338dc50863194eb6fc19eee..f0fda982b9650698c6b641aeeb6c38d9ea16f060 100644 (file)
@@ -30,6 +30,7 @@ u32 ath79_ddr_freq;
 EXPORT_SYMBOL_GPL(ath79_ddr_freq);
 
 enum ath79_soc_type ath79_soc;
+unsigned int ath79_soc_rev;
 
 void __iomem *ath79_pll_base;
 void __iomem *ath79_reset_base;
@@ -64,6 +65,8 @@ void ath79_device_reset_set(u32 mask)
                reg = AR724X_RESET_REG_RESET_MODULE;
        else if (soc_is_ar913x())
                reg = AR913X_RESET_REG_RESET_MODULE;
+       else if (soc_is_ar933x())
+               reg = AR933X_RESET_REG_RESET_MODULE;
        else
                BUG();
 
@@ -86,6 +89,8 @@ void ath79_device_reset_clear(u32 mask)
                reg = AR724X_RESET_REG_RESET_MODULE;
        else if (soc_is_ar913x())
                reg = AR913X_RESET_REG_RESET_MODULE;
+       else if (soc_is_ar933x())
+               reg = AR933X_RESET_REG_RESET_MODULE;
        else
                BUG();
 
diff --git a/arch/mips/ath79/dev-ar913x-wmac.c b/arch/mips/ath79/dev-ar913x-wmac.c
deleted file mode 100644 (file)
index 48f425a..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *  Atheros AR913X SoC built-in WMAC device support
- *
- *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
- *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License version 2 as published
- *  by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/platform_device.h>
-#include <linux/ath9k_platform.h>
-
-#include <asm/mach-ath79/ath79.h>
-#include <asm/mach-ath79/ar71xx_regs.h>
-#include "dev-ar913x-wmac.h"
-
-static struct ath9k_platform_data ar913x_wmac_data;
-
-static struct resource ar913x_wmac_resources[] = {
-       {
-               .start  = AR913X_WMAC_BASE,
-               .end    = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = ATH79_CPU_IRQ_IP2,
-               .end    = ATH79_CPU_IRQ_IP2,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device ar913x_wmac_device = {
-       .name           = "ath9k",
-       .id             = -1,
-       .resource       = ar913x_wmac_resources,
-       .num_resources  = ARRAY_SIZE(ar913x_wmac_resources),
-       .dev = {
-               .platform_data = &ar913x_wmac_data,
-       },
-};
-
-void __init ath79_register_ar913x_wmac(u8 *cal_data)
-{
-       if (cal_data)
-               memcpy(ar913x_wmac_data.eeprom_data, cal_data,
-                      sizeof(ar913x_wmac_data.eeprom_data));
-
-       /* reset the WMAC */
-       ath79_device_reset_set(AR913X_RESET_AMBA2WMAC);
-       mdelay(10);
-
-       ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC);
-       mdelay(10);
-
-       platform_device_register(&ar913x_wmac_device);
-}
index 3b82e325bebfbe552e07cedb1b30a66ba6eb90be..f4956f809072e37f975ee1dd2ac9d3885c425422 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <asm/mach-ath79/ath79.h>
 #include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ar933x_uart_platform.h>
 #include "common.h"
 #include "dev-common.h"
 
@@ -54,6 +55,30 @@ static struct platform_device ath79_uart_device = {
        },
 };
 
+static struct resource ar933x_uart_resources[] = {
+       {
+               .start  = AR933X_UART_BASE,
+               .end    = AR933X_UART_BASE + AR71XX_UART_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = ATH79_MISC_IRQ_UART,
+               .end    = ATH79_MISC_IRQ_UART,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct ar933x_uart_platform_data ar933x_uart_data;
+static struct platform_device ar933x_uart_device = {
+       .name           = "ar933x-uart",
+       .id             = -1,
+       .resource       = ar933x_uart_resources,
+       .num_resources  = ARRAY_SIZE(ar933x_uart_resources),
+       .dev = {
+               .platform_data  = &ar933x_uart_data,
+       },
+};
+
 void __init ath79_register_uart(void)
 {
        struct clk *clk;
@@ -62,8 +87,17 @@ void __init ath79_register_uart(void)
        if (IS_ERR(clk))
                panic("unable to get UART clock, err=%ld", PTR_ERR(clk));
 
-       ath79_uart_data[0].uartclk = clk_get_rate(clk);
-       platform_device_register(&ath79_uart_device);
+       if (soc_is_ar71xx() ||
+           soc_is_ar724x() ||
+           soc_is_ar913x()) {
+               ath79_uart_data[0].uartclk = clk_get_rate(clk);
+               platform_device_register(&ath79_uart_device);
+       } else if (soc_is_ar933x()) {
+               ar933x_uart_data.uartclk = clk_get_rate(clk);
+               platform_device_register(&ar933x_uart_device);
+       } else {
+               BUG();
+       }
 }
 
 static struct platform_device ath79_wdt_device = {
diff --git a/arch/mips/ath79/dev-usb.c b/arch/mips/ath79/dev-usb.c
new file mode 100644 (file)
index 0000000..002d6d2
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ *  Atheros AR7XXX/AR9XXX USB Host Controller device
+ *
+ *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ *  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/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "common.h"
+#include "dev-usb.h"
+
+static struct resource ath79_ohci_resources[] = {
+       [0] = {
+               /* .start and .end fields are filled dynamically */
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = ATH79_MISC_IRQ_OHCI,
+               .end    = ATH79_MISC_IRQ_OHCI,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static u64 ath79_ohci_dmamask = DMA_BIT_MASK(32);
+static struct platform_device ath79_ohci_device = {
+       .name           = "ath79-ohci",
+       .id             = -1,
+       .resource       = ath79_ohci_resources,
+       .num_resources  = ARRAY_SIZE(ath79_ohci_resources),
+       .dev = {
+               .dma_mask               = &ath79_ohci_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+};
+
+static struct resource ath79_ehci_resources[] = {
+       [0] = {
+               /* .start and .end fields are filled dynamically */
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = ATH79_CPU_IRQ_USB,
+               .end    = ATH79_CPU_IRQ_USB,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static u64 ath79_ehci_dmamask = DMA_BIT_MASK(32);
+static struct platform_device ath79_ehci_device = {
+       .name           = "ath79-ehci",
+       .id             = -1,
+       .resource       = ath79_ehci_resources,
+       .num_resources  = ARRAY_SIZE(ath79_ehci_resources),
+       .dev = {
+               .dma_mask               = &ath79_ehci_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+};
+
+#define AR71XX_USB_RESET_MASK  (AR71XX_RESET_USB_HOST | \
+                                AR71XX_RESET_USB_PHY | \
+                                AR71XX_RESET_USB_OHCI_DLL)
+
+static void __init ath79_usb_setup(void)
+{
+       void __iomem *usb_ctrl_base;
+
+       ath79_device_reset_set(AR71XX_USB_RESET_MASK);
+       mdelay(1000);
+       ath79_device_reset_clear(AR71XX_USB_RESET_MASK);
+
+       usb_ctrl_base = ioremap(AR71XX_USB_CTRL_BASE, AR71XX_USB_CTRL_SIZE);
+
+       /* Turning on the Buff and Desc swap bits */
+       __raw_writel(0xf0000, usb_ctrl_base + AR71XX_USB_CTRL_REG_CONFIG);
+
+       /* WAR for HW bug. Here it adjusts the duration between two SOFS */
+       __raw_writel(0x20c00, usb_ctrl_base + AR71XX_USB_CTRL_REG_FLADJ);
+
+       iounmap(usb_ctrl_base);
+
+       mdelay(900);
+
+       ath79_ohci_resources[0].start = AR71XX_OHCI_BASE;
+       ath79_ohci_resources[0].end = AR71XX_OHCI_BASE + AR71XX_OHCI_SIZE - 1;
+       platform_device_register(&ath79_ohci_device);
+
+       ath79_ehci_resources[0].start = AR71XX_EHCI_BASE;
+       ath79_ehci_resources[0].end = AR71XX_EHCI_BASE + AR71XX_EHCI_SIZE - 1;
+       ath79_ehci_device.name = "ar71xx-ehci";
+       platform_device_register(&ath79_ehci_device);
+}
+
+static void __init ar7240_usb_setup(void)
+{
+       void __iomem *usb_ctrl_base;
+
+       ath79_device_reset_clear(AR7240_RESET_OHCI_DLL);
+       ath79_device_reset_set(AR7240_RESET_USB_HOST);
+
+       mdelay(1000);
+
+       ath79_device_reset_set(AR7240_RESET_OHCI_DLL);
+       ath79_device_reset_clear(AR7240_RESET_USB_HOST);
+
+       usb_ctrl_base = ioremap(AR7240_USB_CTRL_BASE, AR7240_USB_CTRL_SIZE);
+
+       /* WAR for HW bug. Here it adjusts the duration between two SOFS */
+       __raw_writel(0x3, usb_ctrl_base + AR71XX_USB_CTRL_REG_FLADJ);
+
+       iounmap(usb_ctrl_base);
+
+       ath79_ohci_resources[0].start = AR7240_OHCI_BASE;
+       ath79_ohci_resources[0].end = AR7240_OHCI_BASE + AR7240_OHCI_SIZE - 1;
+       platform_device_register(&ath79_ohci_device);
+}
+
+static void __init ar724x_usb_setup(void)
+{
+       ath79_device_reset_set(AR724X_RESET_USBSUS_OVERRIDE);
+       mdelay(10);
+
+       ath79_device_reset_clear(AR724X_RESET_USB_HOST);
+       mdelay(10);
+
+       ath79_device_reset_clear(AR724X_RESET_USB_PHY);
+       mdelay(10);
+
+       ath79_ehci_resources[0].start = AR724X_EHCI_BASE;
+       ath79_ehci_resources[0].end = AR724X_EHCI_BASE + AR724X_EHCI_SIZE - 1;
+       ath79_ehci_device.name = "ar724x-ehci";
+       platform_device_register(&ath79_ehci_device);
+}
+
+static void __init ar913x_usb_setup(void)
+{
+       ath79_device_reset_set(AR913X_RESET_USBSUS_OVERRIDE);
+       mdelay(10);
+
+       ath79_device_reset_clear(AR913X_RESET_USB_HOST);
+       mdelay(10);
+
+       ath79_device_reset_clear(AR913X_RESET_USB_PHY);
+       mdelay(10);
+
+       ath79_ehci_resources[0].start = AR913X_EHCI_BASE;
+       ath79_ehci_resources[0].end = AR913X_EHCI_BASE + AR913X_EHCI_SIZE - 1;
+       ath79_ehci_device.name = "ar913x-ehci";
+       platform_device_register(&ath79_ehci_device);
+}
+
+static void __init ar933x_usb_setup(void)
+{
+       ath79_device_reset_set(AR933X_RESET_USBSUS_OVERRIDE);
+       mdelay(10);
+
+       ath79_device_reset_clear(AR933X_RESET_USB_HOST);
+       mdelay(10);
+
+       ath79_device_reset_clear(AR933X_RESET_USB_PHY);
+       mdelay(10);
+
+       ath79_ehci_resources[0].start = AR933X_EHCI_BASE;
+       ath79_ehci_resources[0].end = AR933X_EHCI_BASE + AR933X_EHCI_SIZE - 1;
+       ath79_ehci_device.name = "ar933x-ehci";
+       platform_device_register(&ath79_ehci_device);
+}
+
+void __init ath79_register_usb(void)
+{
+       if (soc_is_ar71xx())
+               ath79_usb_setup();
+       else if (soc_is_ar7240())
+               ar7240_usb_setup();
+       else if (soc_is_ar7241() || soc_is_ar7242())
+               ar724x_usb_setup();
+       else if (soc_is_ar913x())
+               ar913x_usb_setup();
+       else if (soc_is_ar933x())
+               ar933x_usb_setup();
+       else
+               BUG();
+}
similarity index 61%
rename from arch/mips/ath79/dev-ar913x-wmac.h
rename to arch/mips/ath79/dev-usb.h
index 579d562bbda86955207f4b7a925f850c5870f8e0..4b86a69ca0804ee66dd0cb996c1780b8886d9ac8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Atheros AR913X SoC built-in WMAC device support
+ *  Atheros AR71XX/AR724X/AR913X USB Host Controller support
  *
  *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
  *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
@@ -9,9 +9,9 @@
  *  by the Free Software Foundation.
  */
 
-#ifndef _ATH79_DEV_AR913X_WMAC_H
-#define _ATH79_DEV_AR913X_WMAC_H
+#ifndef _ATH79_DEV_USB_H
+#define _ATH79_DEV_USB_H
 
-void ath79_register_ar913x_wmac(u8 *cal_data);
+void ath79_register_usb(void);
 
-#endif /* _ATH79_DEV_AR913X_WMAC_H */
+#endif /* _ATH79_DEV_USB_H */
diff --git a/arch/mips/ath79/dev-wmac.c b/arch/mips/ath79/dev-wmac.c
new file mode 100644 (file)
index 0000000..24f5469
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ *  Atheros AR913X/AR933X SoC built-in WMAC device support
+ *
+ *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "dev-wmac.h"
+
+static struct ath9k_platform_data ath79_wmac_data;
+
+static struct resource ath79_wmac_resources[] = {
+       {
+               /* .start and .end fields are filled dynamically */
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = ATH79_CPU_IRQ_IP2,
+               .end    = ATH79_CPU_IRQ_IP2,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device ath79_wmac_device = {
+       .name           = "ath9k",
+       .id             = -1,
+       .resource       = ath79_wmac_resources,
+       .num_resources  = ARRAY_SIZE(ath79_wmac_resources),
+       .dev = {
+               .platform_data = &ath79_wmac_data,
+       },
+};
+
+static void __init ar913x_wmac_setup(void)
+{
+       /* reset the WMAC */
+       ath79_device_reset_set(AR913X_RESET_AMBA2WMAC);
+       mdelay(10);
+
+       ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC);
+       mdelay(10);
+
+       ath79_wmac_resources[0].start = AR913X_WMAC_BASE;
+       ath79_wmac_resources[0].end = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1;
+}
+
+
+static int ar933x_wmac_reset(void)
+{
+       ath79_device_reset_clear(AR933X_RESET_WMAC);
+       ath79_device_reset_set(AR933X_RESET_WMAC);
+
+       return 0;
+}
+
+static int ar933x_r1_get_wmac_revision(void)
+{
+       return ath79_soc_rev;
+}
+
+static void __init ar933x_wmac_setup(void)
+{
+       u32 t;
+
+       ar933x_wmac_reset();
+
+       ath79_wmac_device.name = "ar933x_wmac";
+
+       ath79_wmac_resources[0].start = AR933X_WMAC_BASE;
+       ath79_wmac_resources[0].end = AR933X_WMAC_BASE + AR933X_WMAC_SIZE - 1;
+
+       t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
+       if (t & AR933X_BOOTSTRAP_REF_CLK_40)
+               ath79_wmac_data.is_clk_25mhz = false;
+       else
+               ath79_wmac_data.is_clk_25mhz = true;
+
+       if (ath79_soc_rev == 1)
+               ath79_wmac_data.get_mac_revision = ar933x_r1_get_wmac_revision;
+
+       ath79_wmac_data.external_reset = ar933x_wmac_reset;
+}
+
+void __init ath79_register_wmac(u8 *cal_data)
+{
+       if (soc_is_ar913x())
+               ar913x_wmac_setup();
+       if (soc_is_ar933x())
+               ar933x_wmac_setup();
+       else
+               BUG();
+
+       if (cal_data)
+               memcpy(ath79_wmac_data.eeprom_data, cal_data,
+                      sizeof(ath79_wmac_data.eeprom_data));
+
+       platform_device_register(&ath79_wmac_device);
+}
diff --git a/arch/mips/ath79/dev-wmac.h b/arch/mips/ath79/dev-wmac.h
new file mode 100644 (file)
index 0000000..c9cd870
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ *  Atheros AR913X/AR933X SoC built-in WMAC device support
+ *
+ *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+
+#ifndef _ATH79_DEV_WMAC_H
+#define _ATH79_DEV_WMAC_H
+
+void ath79_register_wmac(u8 *cal_data);
+
+#endif /* _ATH79_DEV_WMAC_H */
index 7499b0e9df263e38b00181323da58debd0ae00b6..6a51ced7a293fe840351d1e7b0ff5f467784a334 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  Atheros AR71XX/AR724X/AR913X SoC early printk support
+ *  Atheros AR7XXX/AR9XXX SoC early printk support
  *
- *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
  *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
  *
  *  This program is free software; you can redistribute it and/or modify it
  */
 
 #include <linux/io.h>
+#include <linux/errno.h>
 #include <linux/serial_reg.h>
 #include <asm/addrspace.h>
 
+#include <asm/mach-ath79/ath79.h>
 #include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ar933x_uart.h>
 
-static inline void prom_wait_thre(void __iomem *base)
+static void (*_prom_putchar) (unsigned char);
+
+static inline void prom_putchar_wait(void __iomem *reg, u32 mask, u32 val)
 {
-       u32 lsr;
+       u32 t;
 
        do {
-               lsr = __raw_readl(base + UART_LSR * 4);
-               if (lsr & UART_LSR_THRE)
+               t = __raw_readl(reg);
+               if ((t & mask) == val)
                        break;
        } while (1);
 }
 
-void prom_putchar(unsigned char ch)
+static void prom_putchar_ar71xx(unsigned char ch)
 {
        void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE));
 
-       prom_wait_thre(base);
+       prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE);
        __raw_writel(ch, base + UART_TX * 4);
-       prom_wait_thre(base);
+       prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE);
+}
+
+static void prom_putchar_ar933x(unsigned char ch)
+{
+       void __iomem *base = (void __iomem *)(KSEG1ADDR(AR933X_UART_BASE));
+
+       prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR,
+                         AR933X_UART_DATA_TX_CSR);
+       __raw_writel(AR933X_UART_DATA_TX_CSR | ch, base + AR933X_UART_DATA_REG);
+       prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR,
+                         AR933X_UART_DATA_TX_CSR);
+}
+
+static void prom_putchar_dummy(unsigned char ch)
+{
+       /* nothing to do */
+}
+
+static void prom_putchar_init(void)
+{
+       void __iomem *base;
+       u32 id;
+
+       base = (void __iomem *)(KSEG1ADDR(AR71XX_RESET_BASE));
+       id = __raw_readl(base + AR71XX_RESET_REG_REV_ID);
+       id &= REV_ID_MAJOR_MASK;
+
+       switch (id) {
+       case REV_ID_MAJOR_AR71XX:
+       case REV_ID_MAJOR_AR7240:
+       case REV_ID_MAJOR_AR7241:
+       case REV_ID_MAJOR_AR7242:
+       case REV_ID_MAJOR_AR913X:
+               _prom_putchar = prom_putchar_ar71xx;
+               break;
+
+       case REV_ID_MAJOR_AR9330:
+       case REV_ID_MAJOR_AR9331:
+               _prom_putchar = prom_putchar_ar933x;
+               break;
+
+       default:
+               _prom_putchar = prom_putchar_dummy;
+               break;
+       }
+}
+
+void prom_putchar(unsigned char ch)
+{
+       if (!_prom_putchar)
+               prom_putchar_init();
+
+       _prom_putchar(ch);
 }
index a0c426b82123ae2c8e67b20f082a8fecf09b9b48..a2f8ca630ed667bb49c2144129f2232c7c047fc1 100644 (file)
@@ -153,6 +153,8 @@ void __init ath79_gpio_init(void)
                ath79_gpio_count = AR724X_GPIO_COUNT;
        else if (soc_is_ar913x())
                ath79_gpio_count = AR913X_GPIO_COUNT;
+       else if (soc_is_ar933x())
+               ath79_gpio_count = AR933X_GPIO_COUNT;
        else
                BUG();
 
index ac610d5fe3bab415ef649872072bacce58718c19..1b073de44680ea0fdba8c95f84cf6f214f394448 100644 (file)
@@ -46,6 +46,15 @@ static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc)
        else if (pending & MISC_INT_TIMER)
                generic_handle_irq(ATH79_MISC_IRQ_TIMER);
 
+       else if (pending & MISC_INT_TIMER2)
+               generic_handle_irq(ATH79_MISC_IRQ_TIMER2);
+
+       else if (pending & MISC_INT_TIMER3)
+               generic_handle_irq(ATH79_MISC_IRQ_TIMER3);
+
+       else if (pending & MISC_INT_TIMER4)
+               generic_handle_irq(ATH79_MISC_IRQ_TIMER4);
+
        else if (pending & MISC_INT_OHCI)
                generic_handle_irq(ATH79_MISC_IRQ_OHCI);
 
@@ -58,6 +67,9 @@ static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc)
        else if (pending & MISC_INT_WDOG)
                generic_handle_irq(ATH79_MISC_IRQ_WDOG);
 
+       else if (pending & MISC_INT_ETHSW)
+               generic_handle_irq(ATH79_MISC_IRQ_ETHSW);
+
        else
                spurious_interrupt();
 }
@@ -117,7 +129,7 @@ static void __init ath79_misc_irq_init(void)
 
        if (soc_is_ar71xx() || soc_is_ar913x())
                ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
-       else if (soc_is_ar724x())
+       else if (soc_is_ar724x() || soc_is_ar933x())
                ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
        else
                BUG();
@@ -174,6 +186,9 @@ void __init arch_init_irq(void)
        } else if (soc_is_ar913x()) {
                ath79_ip2_flush_reg = AR913X_DDR_REG_FLUSH_WMAC;
                ath79_ip3_flush_reg = AR913X_DDR_REG_FLUSH_USB;
+       } else if (soc_is_ar933x()) {
+               ath79_ip2_flush_reg = AR933X_DDR_REG_FLUSH_WMAC;
+               ath79_ip3_flush_reg = AR933X_DDR_REG_FLUSH_USB;
        } else
                BUG();
 
diff --git a/arch/mips/ath79/mach-ap121.c b/arch/mips/ath79/mach-ap121.c
new file mode 100644 (file)
index 0000000..4c20200
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  Atheros AP121 board support
+ *
+ *  Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+
+#include "machtypes.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+
+#define AP121_GPIO_LED_WLAN            0
+#define AP121_GPIO_LED_USB             1
+
+#define AP121_GPIO_BTN_JUMPSTART       11
+#define AP121_GPIO_BTN_RESET           12
+
+#define AP121_KEYS_POLL_INTERVAL       20      /* msecs */
+#define AP121_KEYS_DEBOUNCE_INTERVAL   (3 * AP121_KEYS_POLL_INTERVAL)
+
+#define AP121_CAL_DATA_ADDR    0x1fff1000
+
+static struct gpio_led ap121_leds_gpio[] __initdata = {
+       {
+               .name           = "ap121:green:usb",
+               .gpio           = AP121_GPIO_LED_USB,
+               .active_low     = 0,
+       },
+       {
+               .name           = "ap121:green:wlan",
+               .gpio           = AP121_GPIO_LED_WLAN,
+               .active_low     = 0,
+       },
+};
+
+static struct gpio_keys_button ap121_gpio_keys[] __initdata = {
+       {
+               .desc           = "jumpstart button",
+               .type           = EV_KEY,
+               .code           = KEY_WPS_BUTTON,
+               .debounce_interval = AP121_KEYS_DEBOUNCE_INTERVAL,
+               .gpio           = AP121_GPIO_BTN_JUMPSTART,
+               .active_low     = 1,
+       },
+       {
+               .desc           = "reset button",
+               .type           = EV_KEY,
+               .code           = KEY_RESTART,
+               .debounce_interval = AP121_KEYS_DEBOUNCE_INTERVAL,
+               .gpio           = AP121_GPIO_BTN_RESET,
+               .active_low     = 1,
+       }
+};
+
+static struct spi_board_info ap121_spi_info[] = {
+       {
+               .bus_num        = 0,
+               .chip_select    = 0,
+               .max_speed_hz   = 25000000,
+               .modalias       = "mx25l1606e",
+       }
+};
+
+static struct ath79_spi_platform_data ap121_spi_data = {
+       .bus_num        = 0,
+       .num_chipselect = 1,
+};
+
+static void __init ap121_setup(void)
+{
+       u8 *cal_data = (u8 *) KSEG1ADDR(AP121_CAL_DATA_ADDR);
+
+       ath79_register_leds_gpio(-1, ARRAY_SIZE(ap121_leds_gpio),
+                                ap121_leds_gpio);
+       ath79_register_gpio_keys_polled(-1, AP121_KEYS_POLL_INTERVAL,
+                                       ARRAY_SIZE(ap121_gpio_keys),
+                                       ap121_gpio_keys);
+
+       ath79_register_spi(&ap121_spi_data, ap121_spi_info,
+                          ARRAY_SIZE(ap121_spi_info));
+       ath79_register_usb();
+       ath79_register_wmac(cal_data);
+}
+
+MIPS_MACHINE(ATH79_MACH_AP121, "AP121", "Atheros AP121 reference board",
+            ap121_setup);
index eee4c121deb4297ca756d131a2d2908fa9eacbea..abe19836331c531448c17aba798181a952a66f8a 100644 (file)
  */
 
 #include "machtypes.h"
-#include "dev-ar913x-wmac.h"
+#include "dev-wmac.h"
 #include "dev-gpio-buttons.h"
 #include "dev-leds-gpio.h"
 #include "dev-spi.h"
+#include "dev-usb.h"
 
 #define AP81_GPIO_LED_STATUS   1
 #define AP81_GPIO_LED_AOSS     3
@@ -91,7 +92,8 @@ static void __init ap81_setup(void)
                                        ap81_gpio_keys);
        ath79_register_spi(&ap81_spi_data, ap81_spi_info,
                           ARRAY_SIZE(ap81_spi_info));
-       ath79_register_ar913x_wmac(cal_data);
+       ath79_register_wmac(cal_data);
+       ath79_register_usb();
 }
 
 MIPS_MACHINE(ATH79_MACH_AP81, "AP81", "Atheros AP81 reference board",
index ec7b7a135d53c57063b66c4fff52e3572e9902c6..fe9701a322916bbb946b2cc037aa57fd02d6329f 100644 (file)
@@ -18,6 +18,7 @@
 #include "dev-gpio-buttons.h"
 #include "dev-leds-gpio.h"
 #include "dev-spi.h"
+#include "dev-usb.h"
 
 #define PB44_GPIO_I2C_SCL      0
 #define PB44_GPIO_I2C_SDA      1
@@ -112,6 +113,7 @@ static void __init pb44_init(void)
                                        pb44_gpio_keys);
        ath79_register_spi(&pb44_spi_data, pb44_spi_info,
                           ARRAY_SIZE(pb44_spi_info));
+       ath79_register_usb();
 }
 
 MIPS_MACHINE(ATH79_MACH_PB44, "PB44", "Atheros PB44 reference board",
diff --git a/arch/mips/ath79/mach-ubnt-xm.c b/arch/mips/ath79/mach-ubnt-xm.c
new file mode 100644 (file)
index 0000000..3c311a5
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ *  Ubiquiti Networks XM (rev 1.0) board support
+ *
+ *  Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com>
+ *
+ *  Derived from: mach-pb44.c
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#ifdef CONFIG_PCI
+#include <linux/ath9k_platform.h>
+#include <asm/mach-ath79/pci-ath724x.h>
+#endif /* CONFIG_PCI */
+
+#include "machtypes.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-spi.h"
+
+#define UBNT_XM_GPIO_LED_L1            0
+#define UBNT_XM_GPIO_LED_L2            1
+#define UBNT_XM_GPIO_LED_L3            11
+#define UBNT_XM_GPIO_LED_L4            7
+
+#define UBNT_XM_GPIO_BTN_RESET         12
+
+#define UBNT_XM_KEYS_POLL_INTERVAL     20
+#define UBNT_XM_KEYS_DEBOUNCE_INTERVAL (3 * UBNT_XM_KEYS_POLL_INTERVAL)
+
+#define UBNT_XM_PCI_IRQ                        48
+#define UBNT_XM_EEPROM_ADDR            (u8 *) KSEG1ADDR(0x1fff1000)
+
+static struct gpio_led ubnt_xm_leds_gpio[] __initdata = {
+       {
+               .name           = "ubnt-xm:red:link1",
+               .gpio           = UBNT_XM_GPIO_LED_L1,
+               .active_low     = 0,
+       }, {
+               .name           = "ubnt-xm:orange:link2",
+               .gpio           = UBNT_XM_GPIO_LED_L2,
+               .active_low     = 0,
+       }, {
+               .name           = "ubnt-xm:green:link3",
+               .gpio           = UBNT_XM_GPIO_LED_L3,
+               .active_low     = 0,
+       }, {
+               .name           = "ubnt-xm:green:link4",
+               .gpio           = UBNT_XM_GPIO_LED_L4,
+               .active_low     = 0,
+       },
+};
+
+static struct gpio_keys_button ubnt_xm_gpio_keys[] __initdata = {
+       {
+               .desc                   = "reset",
+               .type                   = EV_KEY,
+               .code                   = KEY_RESTART,
+               .debounce_interval      = UBNT_XM_KEYS_DEBOUNCE_INTERVAL,
+               .gpio                   = UBNT_XM_GPIO_BTN_RESET,
+               .active_low             = 1,
+       }
+};
+
+static struct spi_board_info ubnt_xm_spi_info[] = {
+       {
+               .bus_num        = 0,
+               .chip_select    = 0,
+               .max_speed_hz   = 25000000,
+               .modalias       = "mx25l6405d",
+       }
+};
+
+static struct ath79_spi_platform_data ubnt_xm_spi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 1,
+};
+
+#ifdef CONFIG_PCI
+static struct ath9k_platform_data ubnt_xm_eeprom_data;
+
+static struct ath724x_pci_data ubnt_xm_pci_data[] = {
+       {
+               .irq    = UBNT_XM_PCI_IRQ,
+               .pdata  = &ubnt_xm_eeprom_data,
+       },
+};
+#endif /* CONFIG_PCI */
+
+static void __init ubnt_xm_init(void)
+{
+       ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_xm_leds_gpio),
+                                ubnt_xm_leds_gpio);
+
+       ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL,
+                                       ARRAY_SIZE(ubnt_xm_gpio_keys),
+                                       ubnt_xm_gpio_keys);
+
+       ath79_register_spi(&ubnt_xm_spi_data, ubnt_xm_spi_info,
+                          ARRAY_SIZE(ubnt_xm_spi_info));
+
+#ifdef CONFIG_PCI
+       memcpy(ubnt_xm_eeprom_data.eeprom_data, UBNT_XM_EEPROM_ADDR,
+              sizeof(ubnt_xm_eeprom_data.eeprom_data));
+
+       ath724x_pci_add_data(ubnt_xm_pci_data, ARRAY_SIZE(ubnt_xm_pci_data));
+#endif /* CONFIG_PCI */
+
+}
+
+MIPS_MACHINE(ATH79_MACH_UBNT_XM,
+            "UBNT-XM",
+            "Ubiquiti Networks XM (rev 1.0) board",
+            ubnt_xm_init);
index 3940fe470b2dfaf2bbaea81b7f6c1ae928802ea3..9a1f3826626e13703c24abc17b05a930f7528558 100644 (file)
 
 enum ath79_mach_type {
        ATH79_MACH_GENERIC = 0,
+       ATH79_MACH_AP121,               /* Atheros AP121 reference board */
        ATH79_MACH_AP81,                /* Atheros AP81 reference board */
        ATH79_MACH_PB44,                /* Atheros PB44 reference board */
+       ATH79_MACH_UBNT_XM,             /* Ubiquiti Networks XM board rev 1.0 */
 };
 
 #endif /* _ATH79_MACHTYPE_H */
index 159b42f106b098185b908eae7efc85b245f8bb52..80a7d4023d7ffbd872ce76ed62bbe8b496d7e6bc 100644 (file)
@@ -101,19 +101,31 @@ static void __init ath79_detect_sys_type(void)
        case REV_ID_MAJOR_AR7240:
                ath79_soc = ATH79_SOC_AR7240;
                chip = "7240";
-               rev = (id & AR724X_REV_ID_REVISION_MASK);
+               rev = id & AR724X_REV_ID_REVISION_MASK;
                break;
 
        case REV_ID_MAJOR_AR7241:
                ath79_soc = ATH79_SOC_AR7241;
                chip = "7241";
-               rev = (id & AR724X_REV_ID_REVISION_MASK);
+               rev = id & AR724X_REV_ID_REVISION_MASK;
                break;
 
        case REV_ID_MAJOR_AR7242:
                ath79_soc = ATH79_SOC_AR7242;
                chip = "7242";
-               rev = (id & AR724X_REV_ID_REVISION_MASK);
+               rev = id & AR724X_REV_ID_REVISION_MASK;
+               break;
+
+       case REV_ID_MAJOR_AR9330:
+               ath79_soc = ATH79_SOC_AR9330;
+               chip = "9330";
+               rev = id & AR933X_REV_ID_REVISION_MASK;
+               break;
+
+       case REV_ID_MAJOR_AR9331:
+               ath79_soc = ATH79_SOC_AR9331;
+               chip = "9331";
+               rev = id & AR933X_REV_ID_REVISION_MASK;
                break;
 
        case REV_ID_MAJOR_AR913X:
@@ -134,9 +146,11 @@ static void __init ath79_detect_sys_type(void)
                break;
 
        default:
-               panic("ath79: unknown SoC, id:0x%08x\n", id);
+               panic("ath79: unknown SoC, id:0x%08x", id);
        }
 
+       ath79_soc_rev = rev;
+
        sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev);
        pr_info("SoC: %s\n", ath79_sys_type);
 }
index 1cfdda03546a8dc5819d682107e3c52289231e24..aab6b0c40a7569b54767c5e473e75da5ba5b8563 100644 (file)
@@ -289,7 +289,7 @@ static void __init bcm47xx_register_ssb(void)
        err = ssb_bus_ssbbus_register(&(bcm47xx_bus.ssb), SSB_ENUM_BASE,
                                      bcm47xx_get_invariants);
        if (err)
-               panic("Failed to initialize SSB bus (err %d)\n", err);
+               panic("Failed to initialize SSB bus (err %d)", err);
 
        mcore = &bcm47xx_bus.ssb.mipscore;
        if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
@@ -314,7 +314,7 @@ static void __init bcm47xx_register_bcma(void)
 
        err = bcma_host_soc_register(&bcm47xx_bus.bcma);
        if (err)
-               panic("Failed to initialize BCMA bus (err %d)\n", err);
+               panic("Failed to initialize BCMA bus (err %d)", err);
 }
 #endif
 
index fb177d6df0665388e749e3f2ec078d29343d2b24..6b1b9ad8d857d01df1254657635c641a53a09148 100644 (file)
@@ -20,6 +20,10 @@ config BCM63XX_CPU_6348
 config BCM63XX_CPU_6358
        bool "support 6358 CPU"
        select HW_HAS_PCI
+
+config BCM63XX_CPU_6368
+       bool "support 6368 CPU"
+       select HW_HAS_PCI
 endmenu
 
 source "arch/mips/bcm63xx/boards/Kconfig"
index c22385400fc979cbeb1d6d9d249f2cab3404f48b..2f1773f3fb7a5594872ddc8b604be143f3127a38 100644 (file)
@@ -709,15 +709,9 @@ void __init board_prom_init(void)
        char cfe_version[32];
        u32 val;
 
-       /* read base address of boot chip select (0)
-        * 6345 does not have MPI but boots from standard
-        * MIPS Flash address */
-       if (BCMCPU_IS_6345())
-               val = 0x1fc00000;
-       else {
-               val = bcm_mpi_readl(MPI_CSBASE_REG(0));
-               val &= MPI_CSBASE_BASE_MASK;
-       }
+       /* read base address of boot chip select (0) */
+       val = bcm_mpi_readl(MPI_CSBASE_REG(0));
+       val &= MPI_CSBASE_BASE_MASK;
        boot_addr = (u8 *)KSEG1ADDR(val);
 
        /* dump cfe version */
@@ -797,18 +791,6 @@ void __init board_prom_init(void)
        }
 
        bcm_gpio_writel(val, GPIO_MODE_REG);
-
-       /* Generate MAC address for WLAN and
-        * register our SPROM */
-#ifdef CONFIG_SSB_PCIHOST
-       if (!board_get_mac_address(bcm63xx_sprom.il0mac)) {
-               memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN);
-               memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN);
-               if (ssb_arch_register_fallback_sprom(
-                               &bcm63xx_get_fallback_sprom) < 0)
-                       printk(KERN_ERR PFX "failed to register fallback SPROM\n");
-       }
-#endif
 }
 
 /*
@@ -895,13 +877,23 @@ int __init board_register_devices(void)
        if (board.has_dsp)
                bcm63xx_dsp_register(&board.dsp);
 
-       /* read base address of boot chip select (0) */
-       if (BCMCPU_IS_6345())
-               val = 0x1fc00000;
-       else {
-               val = bcm_mpi_readl(MPI_CSBASE_REG(0));
-               val &= MPI_CSBASE_BASE_MASK;
+       /* Generate MAC address for WLAN and register our SPROM,
+        * do this after registering enet devices
+        */
+#ifdef CONFIG_SSB_PCIHOST
+       if (!board_get_mac_address(bcm63xx_sprom.il0mac)) {
+               memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN);
+               memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN);
+               if (ssb_arch_register_fallback_sprom(
+                               &bcm63xx_get_fallback_sprom) < 0)
+                       pr_err(PFX "failed to register fallback SPROM\n");
        }
+#endif
+
+       /* read base address of boot chip select (0) */
+       val = bcm_mpi_readl(MPI_CSBASE_REG(0));
+       val &= MPI_CSBASE_BASE_MASK;
+
        mtd_resources[0].start = val;
        mtd_resources[0].end = 0x1FFFFFFF;
 
index 2c68ee9ccee2b3fa3ebfcbd72ee044688bc06765..9d57c71b7b582cc9c24f664df6ae156bc9752522 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/mutex.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <bcm63xx_cpu.h>
 #include <bcm63xx_io.h>
 #include <bcm63xx_regs.h>
@@ -112,6 +113,34 @@ static struct clk clk_ephy = {
        .set    = ephy_set,
 };
 
+/*
+ * Ethernet switch clock
+ */
+static void enetsw_set(struct clk *clk, int enable)
+{
+       if (!BCMCPU_IS_6368())
+               return;
+       bcm_hwclock_set(CKCTL_6368_ROBOSW_CLK_EN |
+                       CKCTL_6368_SWPKT_USB_EN |
+                       CKCTL_6368_SWPKT_SAR_EN, enable);
+       if (enable) {
+               u32 val;
+
+               /* reset switch core afer clock change */
+               val = bcm_perf_readl(PERF_SOFTRESET_6368_REG);
+               val &= ~SOFTRESET_6368_ENETSW_MASK;
+               bcm_perf_writel(val, PERF_SOFTRESET_6368_REG);
+               msleep(10);
+               val |= SOFTRESET_6368_ENETSW_MASK;
+               bcm_perf_writel(val, PERF_SOFTRESET_6368_REG);
+               msleep(10);
+       }
+}
+
+static struct clk clk_enetsw = {
+       .set    = enetsw_set,
+};
+
 /*
  * PCM clock
  */
@@ -131,9 +160,10 @@ static struct clk clk_pcm = {
  */
 static void usbh_set(struct clk *clk, int enable)
 {
-       if (!BCMCPU_IS_6348())
-               return;
-       bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
+       if (BCMCPU_IS_6348())
+               bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
+       else if (BCMCPU_IS_6368())
+               bcm_hwclock_set(CKCTL_6368_USBH_CLK_EN, enable);
 }
 
 static struct clk clk_usbh = {
@@ -161,6 +191,36 @@ static struct clk clk_spi = {
        .set    = spi_set,
 };
 
+/*
+ * XTM clock
+ */
+static void xtm_set(struct clk *clk, int enable)
+{
+       if (!BCMCPU_IS_6368())
+               return;
+
+       bcm_hwclock_set(CKCTL_6368_SAR_CLK_EN |
+                       CKCTL_6368_SWPKT_SAR_EN, enable);
+
+       if (enable) {
+               u32 val;
+
+               /* reset sar core afer clock change */
+               val = bcm_perf_readl(PERF_SOFTRESET_6368_REG);
+               val &= ~SOFTRESET_6368_SAR_MASK;
+               bcm_perf_writel(val, PERF_SOFTRESET_6368_REG);
+               mdelay(1);
+               val |= SOFTRESET_6368_SAR_MASK;
+               bcm_perf_writel(val, PERF_SOFTRESET_6368_REG);
+               mdelay(1);
+       }
+}
+
+
+static struct clk clk_xtm = {
+       .set    = xtm_set,
+};
+
 /*
  * Internal peripheral clock
  */
@@ -204,12 +264,16 @@ struct clk *clk_get(struct device *dev, const char *id)
                return &clk_enet0;
        if (!strcmp(id, "enet1"))
                return &clk_enet1;
+       if (!strcmp(id, "enetsw"))
+               return &clk_enetsw;
        if (!strcmp(id, "ephy"))
                return &clk_ephy;
        if (!strcmp(id, "usbh"))
                return &clk_usbh;
        if (!strcmp(id, "spi"))
                return &clk_spi;
+       if (!strcmp(id, "xtm"))
+               return &clk_xtm;
        if (!strcmp(id, "periph"))
                return &clk_periph;
        if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
index 7c7e4d4486ce0d0099ab2cd92bca6d426237d2b8..8f0d6c7725ea278eecf0fedca355fb5e33c7e824 100644 (file)
@@ -29,166 +29,47 @@ static u16 bcm63xx_cpu_rev;
 static unsigned int bcm63xx_cpu_freq;
 static unsigned int bcm63xx_memory_size;
 
-/*
- * 6338 register sets and irqs
- */
-static const unsigned long bcm96338_regs_base[] = {
-       [RSET_DSL_LMEM]         = BCM_6338_DSL_LMEM_BASE,
-       [RSET_PERF]             = BCM_6338_PERF_BASE,
-       [RSET_TIMER]            = BCM_6338_TIMER_BASE,
-       [RSET_WDT]              = BCM_6338_WDT_BASE,
-       [RSET_UART0]            = BCM_6338_UART0_BASE,
-       [RSET_UART1]            = BCM_6338_UART1_BASE,
-       [RSET_GPIO]             = BCM_6338_GPIO_BASE,
-       [RSET_SPI]              = BCM_6338_SPI_BASE,
-       [RSET_OHCI0]            = BCM_6338_OHCI0_BASE,
-       [RSET_OHCI_PRIV]        = BCM_6338_OHCI_PRIV_BASE,
-       [RSET_USBH_PRIV]        = BCM_6338_USBH_PRIV_BASE,
-       [RSET_UDC0]             = BCM_6338_UDC0_BASE,
-       [RSET_MPI]              = BCM_6338_MPI_BASE,
-       [RSET_PCMCIA]           = BCM_6338_PCMCIA_BASE,
-       [RSET_SDRAM]            = BCM_6338_SDRAM_BASE,
-       [RSET_DSL]              = BCM_6338_DSL_BASE,
-       [RSET_ENET0]            = BCM_6338_ENET0_BASE,
-       [RSET_ENET1]            = BCM_6338_ENET1_BASE,
-       [RSET_ENETDMA]          = BCM_6338_ENETDMA_BASE,
-       [RSET_MEMC]             = BCM_6338_MEMC_BASE,
-       [RSET_DDR]              = BCM_6338_DDR_BASE,
+static const unsigned long bcm6338_regs_base[] = {
+       __GEN_CPU_REGS_TABLE(6338)
 };
 
-static const int bcm96338_irqs[] = {
-       [IRQ_TIMER]             = BCM_6338_TIMER_IRQ,
-       [IRQ_UART0]             = BCM_6338_UART0_IRQ,
-       [IRQ_DSL]               = BCM_6338_DSL_IRQ,
-       [IRQ_ENET0]             = BCM_6338_ENET0_IRQ,
-       [IRQ_ENET_PHY]          = BCM_6338_ENET_PHY_IRQ,
-       [IRQ_ENET0_RXDMA]       = BCM_6338_ENET0_RXDMA_IRQ,
-       [IRQ_ENET0_TXDMA]       = BCM_6338_ENET0_TXDMA_IRQ,
+static const int bcm6338_irqs[] = {
+       __GEN_CPU_IRQ_TABLE(6338)
 };
 
-/*
- * 6345 register sets and irqs
- */
-static const unsigned long bcm96345_regs_base[] = {
-       [RSET_DSL_LMEM]         = BCM_6345_DSL_LMEM_BASE,
-       [RSET_PERF]             = BCM_6345_PERF_BASE,
-       [RSET_TIMER]            = BCM_6345_TIMER_BASE,
-       [RSET_WDT]              = BCM_6345_WDT_BASE,
-       [RSET_UART0]            = BCM_6345_UART0_BASE,
-       [RSET_UART1]            = BCM_6345_UART1_BASE,
-       [RSET_GPIO]             = BCM_6345_GPIO_BASE,
-       [RSET_SPI]              = BCM_6345_SPI_BASE,
-       [RSET_UDC0]             = BCM_6345_UDC0_BASE,
-       [RSET_OHCI0]            = BCM_6345_OHCI0_BASE,
-       [RSET_OHCI_PRIV]        = BCM_6345_OHCI_PRIV_BASE,
-       [RSET_USBH_PRIV]        = BCM_6345_USBH_PRIV_BASE,
-       [RSET_MPI]              = BCM_6345_MPI_BASE,
-       [RSET_PCMCIA]           = BCM_6345_PCMCIA_BASE,
-       [RSET_DSL]              = BCM_6345_DSL_BASE,
-       [RSET_ENET0]            = BCM_6345_ENET0_BASE,
-       [RSET_ENET1]            = BCM_6345_ENET1_BASE,
-       [RSET_ENETDMA]          = BCM_6345_ENETDMA_BASE,
-       [RSET_EHCI0]            = BCM_6345_EHCI0_BASE,
-       [RSET_SDRAM]            = BCM_6345_SDRAM_BASE,
-       [RSET_MEMC]             = BCM_6345_MEMC_BASE,
-       [RSET_DDR]              = BCM_6345_DDR_BASE,
+static const unsigned long bcm6345_regs_base[] = {
+       __GEN_CPU_REGS_TABLE(6345)
 };
 
-static const int bcm96345_irqs[] = {
-       [IRQ_TIMER]             = BCM_6345_TIMER_IRQ,
-       [IRQ_UART0]             = BCM_6345_UART0_IRQ,
-       [IRQ_DSL]               = BCM_6345_DSL_IRQ,
-       [IRQ_ENET0]             = BCM_6345_ENET0_IRQ,
-       [IRQ_ENET_PHY]          = BCM_6345_ENET_PHY_IRQ,
-       [IRQ_ENET0_RXDMA]       = BCM_6345_ENET0_RXDMA_IRQ,
-       [IRQ_ENET0_TXDMA]       = BCM_6345_ENET0_TXDMA_IRQ,
+static const int bcm6345_irqs[] = {
+       __GEN_CPU_IRQ_TABLE(6345)
 };
 
-/*
- * 6348 register sets and irqs
- */
-static const unsigned long bcm96348_regs_base[] = {
-       [RSET_DSL_LMEM]         = BCM_6348_DSL_LMEM_BASE,
-       [RSET_PERF]             = BCM_6348_PERF_BASE,
-       [RSET_TIMER]            = BCM_6348_TIMER_BASE,
-       [RSET_WDT]              = BCM_6348_WDT_BASE,
-       [RSET_UART0]            = BCM_6348_UART0_BASE,
-       [RSET_UART1]            = BCM_6348_UART1_BASE,
-       [RSET_GPIO]             = BCM_6348_GPIO_BASE,
-       [RSET_SPI]              = BCM_6348_SPI_BASE,
-       [RSET_OHCI0]            = BCM_6348_OHCI0_BASE,
-       [RSET_OHCI_PRIV]        = BCM_6348_OHCI_PRIV_BASE,
-       [RSET_USBH_PRIV]        = BCM_6348_USBH_PRIV_BASE,
-       [RSET_MPI]              = BCM_6348_MPI_BASE,
-       [RSET_PCMCIA]           = BCM_6348_PCMCIA_BASE,
-       [RSET_SDRAM]            = BCM_6348_SDRAM_BASE,
-       [RSET_DSL]              = BCM_6348_DSL_BASE,
-       [RSET_ENET0]            = BCM_6348_ENET0_BASE,
-       [RSET_ENET1]            = BCM_6348_ENET1_BASE,
-       [RSET_ENETDMA]          = BCM_6348_ENETDMA_BASE,
-       [RSET_MEMC]             = BCM_6348_MEMC_BASE,
-       [RSET_DDR]              = BCM_6348_DDR_BASE,
+static const unsigned long bcm6348_regs_base[] = {
+       __GEN_CPU_REGS_TABLE(6348)
 };
 
-static const int bcm96348_irqs[] = {
-       [IRQ_TIMER]             = BCM_6348_TIMER_IRQ,
-       [IRQ_UART0]             = BCM_6348_UART0_IRQ,
-       [IRQ_DSL]               = BCM_6348_DSL_IRQ,
-       [IRQ_ENET0]             = BCM_6348_ENET0_IRQ,
-       [IRQ_ENET1]             = BCM_6348_ENET1_IRQ,
-       [IRQ_ENET_PHY]          = BCM_6348_ENET_PHY_IRQ,
-       [IRQ_OHCI0]             = BCM_6348_OHCI0_IRQ,
-       [IRQ_PCMCIA]            = BCM_6348_PCMCIA_IRQ,
-       [IRQ_ENET0_RXDMA]       = BCM_6348_ENET0_RXDMA_IRQ,
-       [IRQ_ENET0_TXDMA]       = BCM_6348_ENET0_TXDMA_IRQ,
-       [IRQ_ENET1_RXDMA]       = BCM_6348_ENET1_RXDMA_IRQ,
-       [IRQ_ENET1_TXDMA]       = BCM_6348_ENET1_TXDMA_IRQ,
-       [IRQ_PCI]               = BCM_6348_PCI_IRQ,
+static const int bcm6348_irqs[] = {
+       __GEN_CPU_IRQ_TABLE(6348)
+
 };
 
-/*
- * 6358 register sets and irqs
- */
-static const unsigned long bcm96358_regs_base[] = {
-       [RSET_DSL_LMEM]         = BCM_6358_DSL_LMEM_BASE,
-       [RSET_PERF]             = BCM_6358_PERF_BASE,
-       [RSET_TIMER]            = BCM_6358_TIMER_BASE,
-       [RSET_WDT]              = BCM_6358_WDT_BASE,
-       [RSET_UART0]            = BCM_6358_UART0_BASE,
-       [RSET_UART1]            = BCM_6358_UART1_BASE,
-       [RSET_GPIO]             = BCM_6358_GPIO_BASE,
-       [RSET_SPI]              = BCM_6358_SPI_BASE,
-       [RSET_OHCI0]            = BCM_6358_OHCI0_BASE,
-       [RSET_EHCI0]            = BCM_6358_EHCI0_BASE,
-       [RSET_OHCI_PRIV]        = BCM_6358_OHCI_PRIV_BASE,
-       [RSET_USBH_PRIV]        = BCM_6358_USBH_PRIV_BASE,
-       [RSET_MPI]              = BCM_6358_MPI_BASE,
-       [RSET_PCMCIA]           = BCM_6358_PCMCIA_BASE,
-       [RSET_SDRAM]            = BCM_6358_SDRAM_BASE,
-       [RSET_DSL]              = BCM_6358_DSL_BASE,
-       [RSET_ENET0]            = BCM_6358_ENET0_BASE,
-       [RSET_ENET1]            = BCM_6358_ENET1_BASE,
-       [RSET_ENETDMA]          = BCM_6358_ENETDMA_BASE,
-       [RSET_MEMC]             = BCM_6358_MEMC_BASE,
-       [RSET_DDR]              = BCM_6358_DDR_BASE,
+static const unsigned long bcm6358_regs_base[] = {
+       __GEN_CPU_REGS_TABLE(6358)
+};
+
+static const int bcm6358_irqs[] = {
+       __GEN_CPU_IRQ_TABLE(6358)
+
 };
 
-static const int bcm96358_irqs[] = {
-       [IRQ_TIMER]             = BCM_6358_TIMER_IRQ,
-       [IRQ_UART0]             = BCM_6358_UART0_IRQ,
-       [IRQ_UART1]             = BCM_6358_UART1_IRQ,
-       [IRQ_DSL]               = BCM_6358_DSL_IRQ,
-       [IRQ_ENET0]             = BCM_6358_ENET0_IRQ,
-       [IRQ_ENET1]             = BCM_6358_ENET1_IRQ,
-       [IRQ_ENET_PHY]          = BCM_6358_ENET_PHY_IRQ,
-       [IRQ_OHCI0]             = BCM_6358_OHCI0_IRQ,
-       [IRQ_EHCI0]             = BCM_6358_EHCI0_IRQ,
-       [IRQ_PCMCIA]            = BCM_6358_PCMCIA_IRQ,
-       [IRQ_ENET0_RXDMA]       = BCM_6358_ENET0_RXDMA_IRQ,
-       [IRQ_ENET0_TXDMA]       = BCM_6358_ENET0_TXDMA_IRQ,
-       [IRQ_ENET1_RXDMA]       = BCM_6358_ENET1_RXDMA_IRQ,
-       [IRQ_ENET1_TXDMA]       = BCM_6358_ENET1_TXDMA_IRQ,
-       [IRQ_PCI]               = BCM_6358_PCI_IRQ,
+static const unsigned long bcm6368_regs_base[] = {
+       __GEN_CPU_REGS_TABLE(6368)
+};
+
+static const int bcm6368_irqs[] = {
+       __GEN_CPU_IRQ_TABLE(6368)
+
 };
 
 u16 __bcm63xx_get_cpu_id(void)
@@ -217,20 +98,19 @@ unsigned int bcm63xx_get_memory_size(void)
 
 static unsigned int detect_cpu_clock(void)
 {
-       unsigned int tmp, n1 = 0, n2 = 0, m1 = 0;
-
-       /* BCM6338 has a fixed 240 Mhz frequency */
-       if (BCMCPU_IS_6338())
+       switch (bcm63xx_get_cpu_id()) {
+       case BCM6338_CPU_ID:
+               /* BCM6338 has a fixed 240 Mhz frequency */
                return 240000000;
 
-       /* BCM6345 has a fixed 140Mhz frequency */
-       if (BCMCPU_IS_6345())
+       case BCM6345_CPU_ID:
+               /* BCM6345 has a fixed 140Mhz frequency */
                return 140000000;
 
-       /*
-        * frequency depends on PLL configuration:
-        */
-       if (BCMCPU_IS_6348()) {
+       case BCM6348_CPU_ID:
+       {
+               unsigned int tmp, n1, n2, m1;
+
                /* 16MHz * (N1 + 1) * (N2 + 2) / (M1_CPU + 1) */
                tmp = bcm_perf_readl(PERF_MIPSPLLCTL_REG);
                n1 = (tmp & MIPSPLLCTL_N1_MASK) >> MIPSPLLCTL_N1_SHIFT;
@@ -239,17 +119,47 @@ static unsigned int detect_cpu_clock(void)
                n1 += 1;
                n2 += 2;
                m1 += 1;
+               return (16 * 1000000 * n1 * n2) / m1;
        }
 
-       if (BCMCPU_IS_6358()) {
+       case BCM6358_CPU_ID:
+       {
+               unsigned int tmp, n1, n2, m1;
+
                /* 16MHz * N1 * N2 / M1_CPU */
                tmp = bcm_ddr_readl(DDR_DMIPSPLLCFG_REG);
                n1 = (tmp & DMIPSPLLCFG_N1_MASK) >> DMIPSPLLCFG_N1_SHIFT;
                n2 = (tmp & DMIPSPLLCFG_N2_MASK) >> DMIPSPLLCFG_N2_SHIFT;
                m1 = (tmp & DMIPSPLLCFG_M1_MASK) >> DMIPSPLLCFG_M1_SHIFT;
+               return (16 * 1000000 * n1 * n2) / m1;
        }
 
-       return (16 * 1000000 * n1 * n2) / m1;
+       case BCM6368_CPU_ID:
+       {
+               unsigned int tmp, p1, p2, ndiv, m1;
+
+               /* (64MHz / P1) * P2 * NDIV / M1_CPU */
+               tmp = bcm_ddr_readl(DDR_DMIPSPLLCFG_6368_REG);
+
+               p1 = (tmp & DMIPSPLLCFG_6368_P1_MASK) >>
+                       DMIPSPLLCFG_6368_P1_SHIFT;
+
+               p2 = (tmp & DMIPSPLLCFG_6368_P2_MASK) >>
+                       DMIPSPLLCFG_6368_P2_SHIFT;
+
+               ndiv = (tmp & DMIPSPLLCFG_6368_NDIV_MASK) >>
+                       DMIPSPLLCFG_6368_NDIV_SHIFT;
+
+               tmp = bcm_ddr_readl(DDR_DMIPSPLLDIV_6368_REG);
+               m1 = (tmp & DMIPSPLLDIV_6368_MDIV_MASK) >>
+                       DMIPSPLLDIV_6368_MDIV_SHIFT;
+
+               return (((64 * 1000000) / p1) * p2 * ndiv) / m1;
+       }
+
+       default:
+               BUG();
+       }
 }
 
 /*
@@ -260,8 +170,10 @@ static unsigned int detect_memory_size(void)
        unsigned int cols = 0, rows = 0, is_32bits = 0, banks = 0;
        u32 val;
 
-       if (BCMCPU_IS_6345())
-               return (8 * 1024 * 1024);
+       if (BCMCPU_IS_6345()) {
+               val = bcm_sdram_readl(SDRAM_MBASE_REG);
+               return (val * 8 * 1024 * 1024);
+       }
 
        if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) {
                val = bcm_sdram_readl(SDRAM_CFG_REG);
@@ -271,7 +183,7 @@ static unsigned int detect_memory_size(void)
                banks = (val & SDRAM_CFG_BANK_MASK) ? 2 : 1;
        }
 
-       if (BCMCPU_IS_6358()) {
+       if (BCMCPU_IS_6358() || BCMCPU_IS_6368()) {
                val = bcm_memc_readl(MEMC_CFG_REG);
                rows = (val & MEMC_CFG_ROW_MASK) >> MEMC_CFG_ROW_SHIFT;
                cols = (val & MEMC_CFG_COL_MASK) >> MEMC_CFG_COL_SHIFT;
@@ -301,24 +213,33 @@ void __init bcm63xx_cpu_init(void)
        case CPU_BMIPS3300:
                if ((read_c0_prid() & 0xff00) == PRID_IMP_BMIPS3300_ALT) {
                        expected_cpu_id = BCM6348_CPU_ID;
-                       bcm63xx_regs_base = bcm96348_regs_base;
-                       bcm63xx_irqs = bcm96348_irqs;
+                       bcm63xx_regs_base = bcm6348_regs_base;
+                       bcm63xx_irqs = bcm6348_irqs;
                } else {
                        __cpu_name[cpu] = "Broadcom BCM6338";
                        expected_cpu_id = BCM6338_CPU_ID;
-                       bcm63xx_regs_base = bcm96338_regs_base;
-                       bcm63xx_irqs = bcm96338_irqs;
+                       bcm63xx_regs_base = bcm6338_regs_base;
+                       bcm63xx_irqs = bcm6338_irqs;
                }
                break;
        case CPU_BMIPS32:
                expected_cpu_id = BCM6345_CPU_ID;
-               bcm63xx_regs_base = bcm96345_regs_base;
-               bcm63xx_irqs = bcm96345_irqs;
+               bcm63xx_regs_base = bcm6345_regs_base;
+               bcm63xx_irqs = bcm6345_irqs;
                break;
        case CPU_BMIPS4350:
-               expected_cpu_id = BCM6358_CPU_ID;
-               bcm63xx_regs_base = bcm96358_regs_base;
-               bcm63xx_irqs = bcm96358_irqs;
+               switch (read_c0_prid() & 0xf0) {
+               case 0x10:
+                       expected_cpu_id = BCM6358_CPU_ID;
+                       bcm63xx_regs_base = bcm6358_regs_base;
+                       bcm63xx_irqs = bcm6358_irqs;
+                       break;
+               case 0x30:
+                       expected_cpu_id = BCM6368_CPU_ID;
+                       bcm63xx_regs_base = bcm6368_regs_base;
+                       bcm63xx_irqs = bcm6368_irqs;
+                       break;
+               }
                break;
        }
 
index c2963da0253e65ca9520879d0e6a992e541cd798..d6e42c608325a85d9abb5036ad2946dbbabb11ff 100644 (file)
@@ -54,7 +54,7 @@ int __init bcm63xx_uart_register(unsigned int id)
        if (id >= ARRAY_SIZE(bcm63xx_uart_devices))
                return -ENODEV;
 
-       if (id == 1 && !BCMCPU_IS_6358())
+       if (id == 1 && (!BCMCPU_IS_6358() && !BCMCPU_IS_6368()))
                return -ENODEV;
 
        if (id == 0) {
index f560fe7d38ddafd0920f3afbea58ffb91683dcc5..a6c2135dbf3867d480339e663530cc6f533548ec 100644 (file)
@@ -4,7 +4,7 @@
  * for more details.
  *
  * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
- * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
+ * Copyright (C) 2008-2011 Florian Fainelli <florian@openwrt.org>
  */
 
 #include <linux/kernel.h>
 #include <bcm63xx_io.h>
 #include <bcm63xx_regs.h>
 
+#ifndef BCMCPU_RUNTIME_DETECT
+#define gpio_out_low_reg       GPIO_DATA_LO_REG
+#ifdef CONFIG_BCM63XX_CPU_6345
+#ifdef gpio_out_low_reg
+#undef gpio_out_low_reg
+#define gpio_out_low_reg       GPIO_DATA_LO_REG_6345
+#endif /* gpio_out_low_reg */
+#endif /* CONFIG_BCM63XX_CPU_6345 */
+
+static inline void bcm63xx_gpio_out_low_reg_init(void)
+{
+}
+#else /* ! BCMCPU_RUNTIME_DETECT */
+static u32 gpio_out_low_reg;
+
+static void bcm63xx_gpio_out_low_reg_init(void)
+{
+       switch (bcm63xx_get_cpu_id()) {
+       case BCM6345_CPU_ID:
+               gpio_out_low_reg = GPIO_DATA_LO_REG_6345;
+               break;
+       default:
+               gpio_out_low_reg = GPIO_DATA_LO_REG;
+               break;
+       }
+}
+#endif /* ! BCMCPU_RUNTIME_DETECT */
+
 static DEFINE_SPINLOCK(bcm63xx_gpio_lock);
 static u32 gpio_out_low, gpio_out_high;
 
@@ -33,7 +61,7 @@ static void bcm63xx_gpio_set(struct gpio_chip *chip,
                BUG();
 
        if (gpio < 32) {
-               reg = GPIO_DATA_LO_REG;
+               reg = gpio_out_low_reg;
                mask = 1 << gpio;
                v = &gpio_out_low;
        } else {
@@ -60,7 +88,7 @@ static int bcm63xx_gpio_get(struct gpio_chip *chip, unsigned gpio)
                BUG();
 
        if (gpio < 32) {
-               reg = GPIO_DATA_LO_REG;
+               reg = gpio_out_low_reg;
                mask = 1 << gpio;
        } else {
                reg = GPIO_DATA_HI_REG;
@@ -125,8 +153,11 @@ static struct gpio_chip bcm63xx_gpio_chip = {
 
 int __init bcm63xx_gpio_init(void)
 {
-       gpio_out_low = bcm_gpio_readl(GPIO_DATA_LO_REG);
-       gpio_out_high = bcm_gpio_readl(GPIO_DATA_HI_REG);
+       bcm63xx_gpio_out_low_reg_init();
+
+       gpio_out_low = bcm_gpio_readl(gpio_out_low_reg);
+       if (!BCMCPU_IS_6345())
+               gpio_out_high = bcm_gpio_readl(GPIO_DATA_HI_REG);
        bcm63xx_gpio_chip.ngpio = bcm63xx_gpio_count();
        pr_info("registering %d GPIOs\n", bcm63xx_gpio_chip.ngpio);
 
index 162e11b4ed755f7e227d4cfc485d40170716abdf..9a216a451d92fd74228d697ac19ca949a9d11469 100644 (file)
 #include <bcm63xx_io.h>
 #include <bcm63xx_irq.h>
 
+static void __dispatch_internal(void) __maybe_unused;
+static void __dispatch_internal_64(void) __maybe_unused;
+static void __internal_irq_mask_32(unsigned int irq) __maybe_unused;
+static void __internal_irq_mask_64(unsigned int irq) __maybe_unused;
+static void __internal_irq_unmask_32(unsigned int irq) __maybe_unused;
+static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused;
+
+#ifndef BCMCPU_RUNTIME_DETECT
+#ifdef CONFIG_BCM63XX_CPU_6338
+#define irq_stat_reg           PERF_IRQSTAT_6338_REG
+#define irq_mask_reg           PERF_IRQMASK_6338_REG
+#define irq_bits               32
+#define is_ext_irq_cascaded    0
+#define ext_irq_start          0
+#define ext_irq_end            0
+#define ext_irq_count          4
+#define ext_irq_cfg_reg1       PERF_EXTIRQ_CFG_REG_6338
+#define ext_irq_cfg_reg2       0
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6345
+#define irq_stat_reg           PERF_IRQSTAT_6345_REG
+#define irq_mask_reg           PERF_IRQMASK_6345_REG
+#define irq_bits               32
+#define is_ext_irq_cascaded    0
+#define ext_irq_start          0
+#define ext_irq_end            0
+#define ext_irq_count          0
+#define ext_irq_cfg_reg1       0
+#define ext_irq_cfg_reg2       0
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6348
+#define irq_stat_reg           PERF_IRQSTAT_6348_REG
+#define irq_mask_reg           PERF_IRQMASK_6348_REG
+#define irq_bits               32
+#define is_ext_irq_cascaded    0
+#define ext_irq_start          0
+#define ext_irq_end            0
+#define ext_irq_count          4
+#define ext_irq_cfg_reg1       PERF_EXTIRQ_CFG_REG_6348
+#define ext_irq_cfg_reg2       0
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6358
+#define irq_stat_reg           PERF_IRQSTAT_6358_REG
+#define irq_mask_reg           PERF_IRQMASK_6358_REG
+#define irq_bits               32
+#define is_ext_irq_cascaded    1
+#define ext_irq_start          (BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE)
+#define ext_irq_end            (BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE)
+#define ext_irq_count          4
+#define ext_irq_cfg_reg1       PERF_EXTIRQ_CFG_REG_6358
+#define ext_irq_cfg_reg2       0
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6368
+#define irq_stat_reg           PERF_IRQSTAT_6368_REG
+#define irq_mask_reg           PERF_IRQMASK_6368_REG
+#define irq_bits               64
+#define is_ext_irq_cascaded    1
+#define ext_irq_start          (BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE)
+#define ext_irq_end            (BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE)
+#define ext_irq_count          6
+#define ext_irq_cfg_reg1       PERF_EXTIRQ_CFG_REG_6368
+#define ext_irq_cfg_reg2       PERF_EXTIRQ_CFG_REG2_6368
+#endif
+
+#if irq_bits == 32
+#define dispatch_internal                      __dispatch_internal
+#define internal_irq_mask                      __internal_irq_mask_32
+#define internal_irq_unmask                    __internal_irq_unmask_32
+#else
+#define dispatch_internal                      __dispatch_internal_64
+#define internal_irq_mask                      __internal_irq_mask_64
+#define internal_irq_unmask                    __internal_irq_unmask_64
+#endif
+
+#define irq_stat_addr  (bcm63xx_regset_address(RSET_PERF) + irq_stat_reg)
+#define irq_mask_addr  (bcm63xx_regset_address(RSET_PERF) + irq_mask_reg)
+
+static inline void bcm63xx_init_irq(void)
+{
+}
+#else /* ! BCMCPU_RUNTIME_DETECT */
+
+static u32 irq_stat_addr, irq_mask_addr;
+static void (*dispatch_internal)(void);
+static int is_ext_irq_cascaded;
+static unsigned int ext_irq_count;
+static unsigned int ext_irq_start, ext_irq_end;
+static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2;
+static void (*internal_irq_mask)(unsigned int irq);
+static void (*internal_irq_unmask)(unsigned int irq);
+
+static void bcm63xx_init_irq(void)
+{
+       int irq_bits;
+
+       irq_stat_addr = bcm63xx_regset_address(RSET_PERF);
+       irq_mask_addr = bcm63xx_regset_address(RSET_PERF);
+
+       switch (bcm63xx_get_cpu_id()) {
+       case BCM6338_CPU_ID:
+               irq_stat_addr += PERF_IRQSTAT_6338_REG;
+               irq_mask_addr += PERF_IRQMASK_6338_REG;
+               irq_bits = 32;
+               break;
+       case BCM6345_CPU_ID:
+               irq_stat_addr += PERF_IRQSTAT_6345_REG;
+               irq_mask_addr += PERF_IRQMASK_6345_REG;
+               irq_bits = 32;
+               break;
+       case BCM6348_CPU_ID:
+               irq_stat_addr += PERF_IRQSTAT_6348_REG;
+               irq_mask_addr += PERF_IRQMASK_6348_REG;
+               irq_bits = 32;
+               ext_irq_count = 4;
+               ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348;
+               break;
+       case BCM6358_CPU_ID:
+               irq_stat_addr += PERF_IRQSTAT_6358_REG;
+               irq_mask_addr += PERF_IRQMASK_6358_REG;
+               irq_bits = 32;
+               ext_irq_count = 4;
+               is_ext_irq_cascaded = 1;
+               ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+               ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE;
+               ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358;
+               break;
+       case BCM6368_CPU_ID:
+               irq_stat_addr += PERF_IRQSTAT_6368_REG;
+               irq_mask_addr += PERF_IRQMASK_6368_REG;
+               irq_bits = 64;
+               ext_irq_count = 6;
+               is_ext_irq_cascaded = 1;
+               ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+               ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE;
+               ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368;
+               ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368;
+               break;
+       default:
+               BUG();
+       }
+
+       if (irq_bits == 32) {
+               dispatch_internal = __dispatch_internal;
+               internal_irq_mask = __internal_irq_mask_32;
+               internal_irq_unmask = __internal_irq_unmask_32;
+       } else {
+               dispatch_internal = __dispatch_internal_64;
+               internal_irq_mask = __internal_irq_mask_64;
+               internal_irq_unmask = __internal_irq_unmask_64;
+       }
+}
+#endif /* ! BCMCPU_RUNTIME_DETECT */
+
+static inline u32 get_ext_irq_perf_reg(int irq)
+{
+       if (irq < 4)
+               return ext_irq_cfg_reg1;
+       return ext_irq_cfg_reg2;
+}
+
+static inline void handle_internal(int intbit)
+{
+       if (is_ext_irq_cascaded &&
+           intbit >= ext_irq_start && intbit <= ext_irq_end)
+               do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE);
+       else
+               do_IRQ(intbit + IRQ_INTERNAL_BASE);
+}
+
 /*
  * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not
  * prioritize any interrupt relatively to another. the static counter
  * will resume the loop where it ended the last time we left this
  * function.
  */
-static void bcm63xx_irq_dispatch_internal(void)
+static void __dispatch_internal(void)
 {
        u32 pending;
        static int i;
 
-       pending = bcm_perf_readl(PERF_IRQMASK_REG) &
-               bcm_perf_readl(PERF_IRQSTAT_REG);
+       pending = bcm_readl(irq_stat_addr) & bcm_readl(irq_mask_addr);
 
        if (!pending)
                return ;
@@ -41,7 +209,28 @@ static void bcm63xx_irq_dispatch_internal(void)
 
                i = (i + 1) & 0x1f;
                if (pending & (1 << to_call)) {
-                       do_IRQ(to_call + IRQ_INTERNAL_BASE);
+                       handle_internal(to_call);
+                       break;
+               }
+       }
+}
+
+static void __dispatch_internal_64(void)
+{
+       u64 pending;
+       static int i;
+
+       pending = bcm_readq(irq_stat_addr) & bcm_readq(irq_mask_addr);
+
+       if (!pending)
+               return ;
+
+       while (1) {
+               int to_call = i;
+
+               i = (i + 1) & 0x3f;
+               if (pending & (1ull << to_call)) {
+                       handle_internal(to_call);
                        break;
                }
        }
@@ -60,15 +249,17 @@ asmlinkage void plat_irq_dispatch(void)
                if (cause & CAUSEF_IP7)
                        do_IRQ(7);
                if (cause & CAUSEF_IP2)
-                       bcm63xx_irq_dispatch_internal();
-               if (cause & CAUSEF_IP3)
-                       do_IRQ(IRQ_EXT_0);
-               if (cause & CAUSEF_IP4)
-                       do_IRQ(IRQ_EXT_1);
-               if (cause & CAUSEF_IP5)
-                       do_IRQ(IRQ_EXT_2);
-               if (cause & CAUSEF_IP6)
-                       do_IRQ(IRQ_EXT_3);
+                       dispatch_internal();
+               if (!is_ext_irq_cascaded) {
+                       if (cause & CAUSEF_IP3)
+                               do_IRQ(IRQ_EXT_0);
+                       if (cause & CAUSEF_IP4)
+                               do_IRQ(IRQ_EXT_1);
+                       if (cause & CAUSEF_IP5)
+                               do_IRQ(IRQ_EXT_2);
+                       if (cause & CAUSEF_IP6)
+                               do_IRQ(IRQ_EXT_3);
+               }
        } while (1);
 }
 
@@ -76,24 +267,50 @@ asmlinkage void plat_irq_dispatch(void)
  * internal IRQs operations: only mask/unmask on PERF irq mask
  * register.
  */
-static inline void bcm63xx_internal_irq_mask(struct irq_data *d)
+static void __internal_irq_mask_32(unsigned int irq)
 {
-       unsigned int irq = d->irq - IRQ_INTERNAL_BASE;
        u32 mask;
 
-       mask = bcm_perf_readl(PERF_IRQMASK_REG);
+       mask = bcm_readl(irq_mask_addr);
        mask &= ~(1 << irq);
-       bcm_perf_writel(mask, PERF_IRQMASK_REG);
+       bcm_writel(mask, irq_mask_addr);
 }
 
-static void bcm63xx_internal_irq_unmask(struct irq_data *d)
+static void __internal_irq_mask_64(unsigned int irq)
+{
+       u64 mask;
+
+       mask = bcm_readq(irq_mask_addr);
+       mask &= ~(1ull << irq);
+       bcm_writeq(mask, irq_mask_addr);
+}
+
+static void __internal_irq_unmask_32(unsigned int irq)
 {
-       unsigned int irq = d->irq - IRQ_INTERNAL_BASE;
        u32 mask;
 
-       mask = bcm_perf_readl(PERF_IRQMASK_REG);
+       mask = bcm_readl(irq_mask_addr);
        mask |= (1 << irq);
-       bcm_perf_writel(mask, PERF_IRQMASK_REG);
+       bcm_writel(mask, irq_mask_addr);
+}
+
+static void __internal_irq_unmask_64(unsigned int irq)
+{
+       u64 mask;
+
+       mask = bcm_readq(irq_mask_addr);
+       mask |= (1ull << irq);
+       bcm_writeq(mask, irq_mask_addr);
+}
+
+static void bcm63xx_internal_irq_mask(struct irq_data *d)
+{
+       internal_irq_mask(d->irq - IRQ_INTERNAL_BASE);
+}
+
+static void bcm63xx_internal_irq_unmask(struct irq_data *d)
+{
+       internal_irq_unmask(d->irq - IRQ_INTERNAL_BASE);
 }
 
 /*
@@ -102,94 +319,131 @@ static void bcm63xx_internal_irq_unmask(struct irq_data *d)
  */
 static void bcm63xx_external_irq_mask(struct irq_data *d)
 {
-       unsigned int irq = d->irq - IRQ_EXT_BASE;
-       u32 reg;
+       unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
+       u32 reg, regaddr;
 
-       reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
-       reg &= ~EXTIRQ_CFG_MASK(irq);
-       bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
+       regaddr = get_ext_irq_perf_reg(irq);
+       reg = bcm_perf_readl(regaddr);
+
+       if (BCMCPU_IS_6348())
+               reg &= ~EXTIRQ_CFG_MASK_6348(irq % 4);
+       else
+               reg &= ~EXTIRQ_CFG_MASK(irq % 4);
+
+       bcm_perf_writel(reg, regaddr);
+       if (is_ext_irq_cascaded)
+               internal_irq_mask(irq + ext_irq_start);
 }
 
 static void bcm63xx_external_irq_unmask(struct irq_data *d)
 {
-       unsigned int irq = d->irq - IRQ_EXT_BASE;
-       u32 reg;
+       unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
+       u32 reg, regaddr;
 
-       reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
-       reg |= EXTIRQ_CFG_MASK(irq);
-       bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
+       regaddr = get_ext_irq_perf_reg(irq);
+       reg = bcm_perf_readl(regaddr);
+
+       if (BCMCPU_IS_6348())
+               reg |= EXTIRQ_CFG_MASK_6348(irq % 4);
+       else
+               reg |= EXTIRQ_CFG_MASK(irq % 4);
+
+       bcm_perf_writel(reg, regaddr);
+
+       if (is_ext_irq_cascaded)
+               internal_irq_unmask(irq + ext_irq_start);
 }
 
 static void bcm63xx_external_irq_clear(struct irq_data *d)
 {
-       unsigned int irq = d->irq - IRQ_EXT_BASE;
-       u32 reg;
+       unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
+       u32 reg, regaddr;
 
-       reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
-       reg |= EXTIRQ_CFG_CLEAR(irq);
-       bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
-}
+       regaddr = get_ext_irq_perf_reg(irq);
+       reg = bcm_perf_readl(regaddr);
 
-static unsigned int bcm63xx_external_irq_startup(struct irq_data *d)
-{
-       set_c0_status(0x100 << (d->irq - IRQ_MIPS_BASE));
-       irq_enable_hazard();
-       bcm63xx_external_irq_unmask(d);
-       return 0;
-}
+       if (BCMCPU_IS_6348())
+               reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4);
+       else
+               reg |= EXTIRQ_CFG_CLEAR(irq % 4);
 
-static void bcm63xx_external_irq_shutdown(struct irq_data *d)
-{
-       bcm63xx_external_irq_mask(d);
-       clear_c0_status(0x100 << (d->irq - IRQ_MIPS_BASE));
-       irq_disable_hazard();
+       bcm_perf_writel(reg, regaddr);
 }
 
 static int bcm63xx_external_irq_set_type(struct irq_data *d,
                                         unsigned int flow_type)
 {
-       unsigned int irq = d->irq - IRQ_EXT_BASE;
-       u32 reg;
+       unsigned int irq = d->irq - IRQ_EXTERNAL_BASE;
+       u32 reg, regaddr;
+       int levelsense, sense, bothedge;
 
        flow_type &= IRQ_TYPE_SENSE_MASK;
 
        if (flow_type == IRQ_TYPE_NONE)
                flow_type = IRQ_TYPE_LEVEL_LOW;
 
-       reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
+       levelsense = sense = bothedge = 0;
        switch (flow_type) {
        case IRQ_TYPE_EDGE_BOTH:
-               reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
-               reg |= EXTIRQ_CFG_BOTHEDGE(irq);
+               bothedge = 1;
                break;
 
        case IRQ_TYPE_EDGE_RISING:
-               reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
-               reg |= EXTIRQ_CFG_SENSE(irq);
-               reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
+               sense = 1;
                break;
 
        case IRQ_TYPE_EDGE_FALLING:
-               reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
-               reg &= ~EXTIRQ_CFG_SENSE(irq);
-               reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
                break;
 
        case IRQ_TYPE_LEVEL_HIGH:
-               reg |= EXTIRQ_CFG_LEVELSENSE(irq);
-               reg |= EXTIRQ_CFG_SENSE(irq);
+               levelsense = 1;
+               sense = 1;
                break;
 
        case IRQ_TYPE_LEVEL_LOW:
-               reg |= EXTIRQ_CFG_LEVELSENSE(irq);
-               reg &= ~EXTIRQ_CFG_SENSE(irq);
+               levelsense = 1;
                break;
 
        default:
                printk(KERN_ERR "bogus flow type combination given !\n");
                return -EINVAL;
        }
-       bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
+
+       regaddr = get_ext_irq_perf_reg(irq);
+       reg = bcm_perf_readl(regaddr);
+       irq %= 4;
+
+       if (BCMCPU_IS_6348()) {
+               if (levelsense)
+                       reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq);
+               else
+                       reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq);
+               if (sense)
+                       reg |= EXTIRQ_CFG_SENSE_6348(irq);
+               else
+                       reg &= ~EXTIRQ_CFG_SENSE_6348(irq);
+               if (bothedge)
+                       reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq);
+               else
+                       reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq);
+       }
+
+       if (BCMCPU_IS_6338() || BCMCPU_IS_6358() || BCMCPU_IS_6368()) {
+               if (levelsense)
+                       reg |= EXTIRQ_CFG_LEVELSENSE(irq);
+               else
+                       reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
+               if (sense)
+                       reg |= EXTIRQ_CFG_SENSE(irq);
+               else
+                       reg &= ~EXTIRQ_CFG_SENSE(irq);
+               if (bothedge)
+                       reg |= EXTIRQ_CFG_BOTHEDGE(irq);
+               else
+                       reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
+       }
+
+       bcm_perf_writel(reg, regaddr);
 
        irqd_set_trigger_type(d, flow_type);
        if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
@@ -208,9 +462,6 @@ static struct irq_chip bcm63xx_internal_irq_chip = {
 
 static struct irq_chip bcm63xx_external_irq_chip = {
        .name           = "bcm63xx_epic",
-       .irq_startup    = bcm63xx_external_irq_startup,
-       .irq_shutdown   = bcm63xx_external_irq_shutdown,
-
        .irq_ack        = bcm63xx_external_irq_clear,
 
        .irq_mask       = bcm63xx_external_irq_mask,
@@ -225,18 +476,30 @@ static struct irqaction cpu_ip2_cascade_action = {
        .flags          = IRQF_NO_THREAD,
 };
 
+static struct irqaction cpu_ext_cascade_action = {
+       .handler        = no_action,
+       .name           = "cascade_extirq",
+       .flags          = IRQF_NO_THREAD,
+};
+
 void __init arch_init_irq(void)
 {
        int i;
 
+       bcm63xx_init_irq();
        mips_cpu_irq_init();
        for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i)
                irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip,
                                         handle_level_irq);
 
-       for (i = IRQ_EXT_BASE; i < IRQ_EXT_BASE + 4; ++i)
+       for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + ext_irq_count; ++i)
                irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip,
                                         handle_edge_irq);
 
-       setup_irq(IRQ_MIPS_BASE + 2, &cpu_ip2_cascade_action);
+       if (!is_ext_irq_cascaded) {
+               for (i = 3; i < 3 + ext_irq_count; ++i)
+                       setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action);
+       }
+
+       setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action);
 }
index be252efa0757960bba1ce7d17e2dedd9f19629d3..99d7f405cbebf953c2646a842f1221bc7fe58d18 100644 (file)
@@ -32,9 +32,12 @@ void __init prom_init(void)
                mask = CKCTL_6345_ALL_SAFE_EN;
        else if (BCMCPU_IS_6348())
                mask = CKCTL_6348_ALL_SAFE_EN;
-       else
-               /* BCMCPU_IS_6358() */
+       else if (BCMCPU_IS_6358())
                mask = CKCTL_6358_ALL_SAFE_EN;
+       else if (BCMCPU_IS_6368())
+               mask = CKCTL_6368_ALL_SAFE_EN;
+       else
+               mask = 0;
 
        reg = bcm_perf_readl(PERF_CKCTL_REG);
        reg &= ~mask;
index d0056598fbfcac2e36438dda2940b7cd0df7194b..d209f85d87bb654cb41f0b2308c871bb6c3aa845 100644 (file)
@@ -63,13 +63,33 @@ static void bcm6348_a1_reboot(void)
 
 void bcm63xx_machine_reboot(void)
 {
-       u32 reg;
+       u32 reg, perf_regs[2] = { 0, 0 };
+       unsigned int i;
 
        /* mask and clear all external irq */
-       reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
-       reg &= ~EXTIRQ_CFG_MASK_ALL;
-       reg |= EXTIRQ_CFG_CLEAR_ALL;
-       bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
+       switch (bcm63xx_get_cpu_id()) {
+       case BCM6338_CPU_ID:
+               perf_regs[0] = PERF_EXTIRQ_CFG_REG_6338;
+               break;
+       case BCM6348_CPU_ID:
+               perf_regs[0] = PERF_EXTIRQ_CFG_REG_6348;
+               break;
+       case BCM6358_CPU_ID:
+               perf_regs[0] = PERF_EXTIRQ_CFG_REG_6358;
+               break;
+       }
+
+       for (i = 0; i < 2; i++) {
+               reg = bcm_perf_readl(perf_regs[i]);
+               if (BCMCPU_IS_6348()) {
+                       reg &= ~EXTIRQ_CFG_MASK_ALL_6348;
+                       reg |= EXTIRQ_CFG_CLEAR_ALL_6348;
+               } else {
+                       reg &= ~EXTIRQ_CFG_MASK_ALL;
+                       reg |= EXTIRQ_CFG_CLEAR_ALL;
+               }
+               bcm_perf_writel(reg, perf_regs[i]);
+       }
 
        if (BCMCPU_IS_6348() && (bcm63xx_get_cpu_rev() == 0xa1))
                bcm6348_a1_reboot();
@@ -124,4 +144,4 @@ int __init bcm63xx_register_devices(void)
        return board_register_devices();
 }
 
-arch_initcall(bcm63xx_register_devices);
+device_initcall(bcm63xx_register_devices);
index eb063e6dead923b2a26077b5c4262e5fd0c53a31..3112df8f90dbc9726166f13e93a82c441efc5a27 100644 (file)
@@ -2,6 +2,9 @@
 
 void putc(char c)
 {
-       /* all current (Jan. 2010) in-kernel boards */
+#ifdef CONFIG_MIPS_DB1300
+       alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c);
+#else
        alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
+#endif
 }
index cad555ebeca3b855356d928b66e736e6a286cef6..f9e275a50d982be23ffda94a1e23d019c25569b5 100644 (file)
@@ -86,10 +86,6 @@ config ARCH_SPARSEMEM_ENABLE
        def_bool y
        select SPARSEMEM_STATIC
 
-config CAVIUM_OCTEON_HELPER
-       def_bool y
-       depends on OCTEON_ETHERNET || PCI
-
 config IOMMU_HELPER
        bool
 
index ea4febaa4bb1caf50f2ef92cc6c711e94c4285e2..b6bb92c16a47e94981f6e49672554b82c228491f 100644 (file)
@@ -61,6 +61,16 @@ static phys_addr_t octeon_gen1_dma_to_phys(struct device *dev, dma_addr_t daddr)
        return daddr;
 }
 
+static dma_addr_t octeon_gen2_phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+       return octeon_hole_phys_to_dma(paddr);
+}
+
+static phys_addr_t octeon_gen2_dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+       return octeon_hole_dma_to_phys(daddr);
+}
+
 static dma_addr_t octeon_big_phys_to_dma(struct device *dev, phys_addr_t paddr)
 {
        if (paddr >= 0x410000000ull && paddr < 0x420000000ull)
@@ -262,11 +272,11 @@ void __init plat_swiotlb_setup(void)
 
        for (i = 0 ; i < boot_mem_map.nr_map; i++) {
                struct boot_mem_map_entry *e = &boot_mem_map.map[i];
-               if (e->type != BOOT_MEM_RAM)
+               if (e->type != BOOT_MEM_RAM && e->type != BOOT_MEM_INIT_RAM)
                        continue;
 
                /* These addresses map low for PCI. */
-               if (e->addr > 0x410000000ull)
+               if (e->addr > 0x410000000ull && !OCTEON_IS_MODEL(OCTEON_CN6XXX))
                        continue;
 
                addr_size += e->size;
@@ -295,6 +305,11 @@ void __init plat_swiotlb_setup(void)
                 */
                swiotlbsize = 64 * (1<<20);
        }
+#endif
+#ifdef CONFIG_USB_OCTEON_OHCI
+       /* OCTEON II ohci is only 32-bit. */
+       if (OCTEON_IS_MODEL(OCTEON_CN6XXX) && max_addr >= 0x100000000ul)
+               swiotlbsize = 64 * (1<<20);
 #endif
        swiotlb_nslabs = swiotlbsize >> IO_TLB_SHIFT;
        swiotlb_nslabs = ALIGN(swiotlb_nslabs, IO_TLB_SEGSIZE);
@@ -330,6 +345,10 @@ struct dma_map_ops *octeon_pci_dma_map_ops;
 void __init octeon_pci_dma_init(void)
 {
        switch (octeon_dma_bar_type) {
+       case OCTEON_DMA_BAR_TYPE_PCIE2:
+               _octeon_pci_dma_map_ops.phys_to_dma = octeon_gen2_phys_to_dma;
+               _octeon_pci_dma_map_ops.dma_to_phys = octeon_gen2_dma_to_phys;
+               break;
        case OCTEON_DMA_BAR_TYPE_PCIE:
                _octeon_pci_dma_map_ops.phys_to_dma = octeon_gen1_phys_to_dma;
                _octeon_pci_dma_map_ops.dma_to_phys = octeon_gen1_dma_to_phys;
index 7f41c5be2190ddca03fc92a00e8f21bd735414f5..b6d6e841a984ea61270581b4fed097dcd68897bf 100644 (file)
 #
 
 obj-y += cvmx-bootmem.o cvmx-l2c.o cvmx-sysinfo.o octeon-model.o
+obj-y += cvmx-pko.o cvmx-spi.o cvmx-cmd-queue.o \
+       cvmx-helper-board.o cvmx-helper.o cvmx-helper-xaui.o \
+       cvmx-helper-rgmii.o cvmx-helper-sgmii.o cvmx-helper-npi.o \
+       cvmx-helper-loop.o cvmx-helper-spi.o cvmx-helper-util.o \
+       cvmx-interrupt-decodes.o cvmx-interrupt-rsl.o
 
-obj-$(CONFIG_CAVIUM_OCTEON_HELPER) += cvmx-helper-errata.o cvmx-helper-jtag.o
+obj-y += cvmx-helper-errata.o cvmx-helper-jtag.o
similarity index 98%
rename from drivers/staging/octeon/cvmx-cmd-queue.c
rename to arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c
index e9809d375162b0870f2830583720b1da0126b5de..132bccc66a93654e50fb03c77c9de125434f385c 100644 (file)
 
 #include <asm/octeon/octeon.h>
 
-#include "cvmx-config.h"
-#include "cvmx-fpa.h"
-#include "cvmx-cmd-queue.h"
+#include <asm/octeon/cvmx-config.h>
+#include <asm/octeon/cvmx-fpa.h>
+#include <asm/octeon/cvmx-cmd-queue.h>
 
 #include <asm/octeon/cvmx-npei-defs.h>
 #include <asm/octeon/cvmx-pexp-defs.h>
-#include "cvmx-pko-defs.h"
+#include <asm/octeon/cvmx-pko-defs.h>
 
 /**
  * This application uses this pointer to access the global queue
similarity index 96%
rename from drivers/staging/octeon/cvmx-helper-board.c
rename to arch/mips/cavium-octeon/executive/cvmx-helper-board.c
index 57d35dc63ddb1e2ae45bd49e7772d32556c2da2c..fd2015331a207315c760ca195751b234c32ee1d3 100644 (file)
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-bootinfo.h>
 
-#include "cvmx-config.h"
+#include <asm/octeon/cvmx-config.h>
 
-#include "cvmx-mdio.h"
+#include <asm/octeon/cvmx-mdio.h>
 
-#include "cvmx-helper.h"
-#include "cvmx-helper-util.h"
-#include "cvmx-helper-board.h"
+#include <asm/octeon/cvmx-helper.h>
+#include <asm/octeon/cvmx-helper-util.h>
+#include <asm/octeon/cvmx-helper-board.h>
 
-#include "cvmx-gmxx-defs.h"
-#include "cvmx-asxx-defs.h"
+#include <asm/octeon/cvmx-gmxx-defs.h>
+#include <asm/octeon/cvmx-asxx-defs.h>
 
 /**
  * cvmx_override_board_link_get(int ipd_port) is a function
@@ -117,6 +117,10 @@ int cvmx_helper_board_get_mii_address(int ipd_port)
        case CVMX_BOARD_TYPE_EBH5200:
        case CVMX_BOARD_TYPE_EBH5201:
        case CVMX_BOARD_TYPE_EBT5200:
+               /* Board has 2 management ports */
+               if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) &&
+                   (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
+                       return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
                /*
                 * Board has 4 SGMII ports. The PHYs start right after the MII
                 * ports MII0 = 0, MII1 = 1, SGMII = 2-5.
@@ -128,6 +132,9 @@ int cvmx_helper_board_get_mii_address(int ipd_port)
        case CVMX_BOARD_TYPE_EBH5600:
        case CVMX_BOARD_TYPE_EBH5601:
        case CVMX_BOARD_TYPE_EBH5610:
+               /* Board has 1 management port */
+               if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
+                       return 0;
                /*
                 * Board has 8 SGMII ports. 4 connect out, two connect
                 * to a switch, and 2 loop to each other
@@ -147,6 +154,19 @@ int cvmx_helper_board_get_mii_address(int ipd_port)
                        return ipd_port - 16 + 1;
                else
                        return -1;
+       case CVMX_BOARD_TYPE_NIC_XLE_10G:
+       case CVMX_BOARD_TYPE_NIC10E:
+               return -1;
+       case CVMX_BOARD_TYPE_NIC4E:
+               if (ipd_port >= 0 && ipd_port <= 3)
+                       return (ipd_port + 0x1f) & 0x1f;
+               else
+                       return -1;
+       case CVMX_BOARD_TYPE_NIC2E:
+               if (ipd_port >= 0 && ipd_port <= 1)
+                       return ipd_port + 1;
+               else
+                       return -1;
        case CVMX_BOARD_TYPE_BBGW_REF:
                /*
                 * No PHYs are connected to Octeon, everything is
@@ -493,7 +513,6 @@ int cvmx_helper_board_link_set_phy(int phy_addr,
                cvmx_mdio_phy_reg_control_t reg_control;
                cvmx_mdio_phy_reg_status_t reg_status;
                cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
-               cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
                cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
 
                reg_status.u16 =
@@ -508,9 +527,6 @@ int cvmx_helper_board_link_set_phy(int phy_addr,
                reg_autoneg_adver.s.advert_100base_tx_full = 0;
                reg_autoneg_adver.s.advert_100base_tx_half = 0;
                if (reg_status.s.capable_extended_status) {
-                       reg_extended_status.u16 =
-                           cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
-                                          CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
                        reg_control_1000.u16 =
                            cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
                                           CVMX_MDIO_PHY_REG_CONTROL_1000);
similarity index 95%
rename from drivers/staging/octeon/cvmx-helper-loop.c
rename to arch/mips/cavium-octeon/executive/cvmx-helper-loop.c
index 55a571a69529e914edda285ecf889014c5ae88fa..bfbd46115e71453e2636a9da76a734ef750598fe 100644 (file)
  */
 #include <asm/octeon/octeon.h>
 
-#include "cvmx-config.h"
+#include <asm/octeon/cvmx-config.h>
 
-#include "cvmx-helper.h"
-#include "cvmx-pip-defs.h"
+#include <asm/octeon/cvmx-helper.h>
+#include <asm/octeon/cvmx-pip-defs.h>
 
 /**
  * Probe a LOOP interface and determine the number of ports
similarity index 96%
rename from drivers/staging/octeon/cvmx-helper-npi.c
rename to arch/mips/cavium-octeon/executive/cvmx-helper-npi.c
index 7388a1e72b38c5545b0e7be0a2a17c0b004ed4f8..cc94cfa545b49ecd510d4575119f3389bd34ac1c 100644 (file)
  */
 #include <asm/octeon/octeon.h>
 
-#include "cvmx-config.h"
+#include <asm/octeon/cvmx-config.h>
 
-#include "cvmx-helper.h"
+#include <asm/octeon/cvmx-helper.h>
 
-#include "cvmx-pip-defs.h"
+#include <asm/octeon/cvmx-pip-defs.h>
 
 /**
  * Probe a NPI interface and determine the number of ports
similarity index 97%
rename from drivers/staging/octeon/cvmx-helper-rgmii.c
rename to arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c
index aa2d5d7fee2be4c914ce7f83fc2fd5d8dfa481af..82b21843421caefd270aa44e68c53df988472898 100644 (file)
  */
 #include <asm/octeon/octeon.h>
 
-#include "cvmx-config.h"
+#include <asm/octeon/cvmx-config.h>
 
 
-#include "cvmx-mdio.h"
-#include "cvmx-pko.h"
-#include "cvmx-helper.h"
-#include "cvmx-helper-board.h"
+#include <asm/octeon/cvmx-mdio.h>
+#include <asm/octeon/cvmx-pko.h>
+#include <asm/octeon/cvmx-helper.h>
+#include <asm/octeon/cvmx-helper-board.h>
 
 #include <asm/octeon/cvmx-npi-defs.h>
-#include "cvmx-gmxx-defs.h"
-#include "cvmx-asxx-defs.h"
-#include "cvmx-dbg-defs.h"
+#include <asm/octeon/cvmx-gmxx-defs.h>
+#include <asm/octeon/cvmx-asxx-defs.h>
+#include <asm/octeon/cvmx-dbg-defs.h>
 
 void __cvmx_interrupt_gmxx_enable(int interface);
 void __cvmx_interrupt_asxx_enable(int block);
@@ -326,6 +326,7 @@ int __cvmx_helper_rgmii_link_set(int ipd_port,
                       cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) &
                                     ~(1 << index));
 
+       memset(pko_mem_queue_qos_save, 0, sizeof(pko_mem_queue_qos_save));
        /* Disable all queues so that TX should become idle */
        for (i = 0; i < cvmx_pko_get_num_queues(ipd_port); i++) {
                int queue = cvmx_pko_get_base_queue(ipd_port) + i;
similarity index 98%
rename from drivers/staging/octeon/cvmx-helper-sgmii.c
rename to arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c
index 6214e3b6d97528b900b6b90792756dda48fd9d04..0c0bf5d30e70375203a31efef560ff8302705979 100644 (file)
 
 #include <asm/octeon/octeon.h>
 
-#include "cvmx-config.h"
+#include <asm/octeon/cvmx-config.h>
 
-#include "cvmx-mdio.h"
-#include "cvmx-helper.h"
-#include "cvmx-helper-board.h"
+#include <asm/octeon/cvmx-mdio.h>
+#include <asm/octeon/cvmx-helper.h>
+#include <asm/octeon/cvmx-helper-board.h>
 
-#include "cvmx-gmxx-defs.h"
-#include "cvmx-pcsx-defs.h"
+#include <asm/octeon/cvmx-gmxx-defs.h>
+#include <asm/octeon/cvmx-pcsx-defs.h>
 
 void __cvmx_interrupt_gmxx_enable(int interface);
 void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block);
@@ -326,6 +326,10 @@ static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
        return 0;
 }
 
+int __cvmx_helper_sgmii_enumerate(int interface)
+{
+       return 4;
+}
 /**
  * Probe a SGMII interface and determine the number of ports
  * connected to it. The SGMII interface should still be down after
@@ -347,7 +351,7 @@ int __cvmx_helper_sgmii_probe(int interface)
        mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
        mode.s.en = 1;
        cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
-       return 4;
+       return __cvmx_helper_sgmii_enumerate(interface);
 }
 
 /**
similarity index 94%
rename from drivers/staging/octeon/cvmx-helper-spi.c
rename to arch/mips/cavium-octeon/executive/cvmx-helper-spi.c
index 8ba6c832471e85c1dd19767b0263238240d374d8..2830e4bdf7f3f6d2faeaf753ef286805e27a4cce 100644 (file)
@@ -35,12 +35,12 @@ void __cvmx_interrupt_stxx_int_msk_enable(int index);
  */
 #include <asm/octeon/octeon.h>
 
-#include "cvmx-config.h"
-#include "cvmx-spi.h"
-#include "cvmx-helper.h"
+#include <asm/octeon/cvmx-config.h>
+#include <asm/octeon/cvmx-spi.h>
+#include <asm/octeon/cvmx-helper.h>
 
-#include "cvmx-pip-defs.h"
-#include "cvmx-pko-defs.h"
+#include <asm/octeon/cvmx-pip-defs.h>
+#include <asm/octeon/cvmx-pko-defs.h>
 
 /*
  * CVMX_HELPER_SPI_TIMEOUT is used to determine how long the SPI
@@ -51,6 +51,16 @@ void __cvmx_interrupt_stxx_int_msk_enable(int index);
 #define CVMX_HELPER_SPI_TIMEOUT 10
 #endif
 
+int __cvmx_helper_spi_enumerate(int interface)
+{
+       if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
+           cvmx_spi4000_is_present(interface)) {
+               return 10;
+       } else {
+               return 16;
+       }
+}
+
 /**
  * Probe a SPI interface and determine the number of ports
  * connected to it. The SPI interface should still be down after
similarity index 97%
rename from drivers/staging/octeon/cvmx-helper-util.c
rename to arch/mips/cavium-octeon/executive/cvmx-helper-util.c
index 131182bf5abb699d5966a4f92e0f65934e1d0bb6..116dea17acf5a3e0cbe273a352fe06ad4d126836 100644 (file)
 
 #include <asm/octeon/octeon.h>
 
-#include "cvmx-config.h"
+#include <asm/octeon/cvmx-config.h>
 
-#include "cvmx-fpa.h"
-#include "cvmx-pip.h"
-#include "cvmx-pko.h"
-#include "cvmx-ipd.h"
-#include "cvmx-spi.h"
+#include <asm/octeon/cvmx-fpa.h>
+#include <asm/octeon/cvmx-pip.h>
+#include <asm/octeon/cvmx-pko.h>
+#include <asm/octeon/cvmx-ipd.h>
+#include <asm/octeon/cvmx-spi.h>
 
-#include "cvmx-helper.h"
-#include "cvmx-helper-util.h"
+#include <asm/octeon/cvmx-helper.h>
+#include <asm/octeon/cvmx-helper-util.h>
 
 #include <asm/octeon/cvmx-ipd-defs.h>
 
similarity index 97%
rename from drivers/staging/octeon/cvmx-helper-xaui.c
rename to arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c
index a11e6769e23490be94f1b14671a606e37e686c39..1723248e987dcc07c6336d82e6b954e178ee1875 100644 (file)
 
 #include <asm/octeon/octeon.h>
 
-#include "cvmx-config.h"
+#include <asm/octeon/cvmx-config.h>
 
-#include "cvmx-helper.h"
+#include <asm/octeon/cvmx-helper.h>
 
-#include "cvmx-pko-defs.h"
-#include "cvmx-gmxx-defs.h"
-#include "cvmx-pcsxx-defs.h"
+#include <asm/octeon/cvmx-pko-defs.h>
+#include <asm/octeon/cvmx-gmxx-defs.h>
+#include <asm/octeon/cvmx-pcsxx-defs.h>
 
 void __cvmx_interrupt_gmxx_enable(int interface);
 void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block);
 void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index);
+
+int __cvmx_helper_xaui_enumerate(int interface)
+{
+       union cvmx_gmxx_hg2_control gmx_hg2_control;
+
+       /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */
+       gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface));
+       if (gmx_hg2_control.s.hg2tx_en)
+               return 16;
+       else
+               return 1;
+}
+
 /**
  * Probe a XAUI interface and determine the number of ports
  * connected to it. The XAUI interface should still be down
@@ -56,7 +69,6 @@ void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index);
 int __cvmx_helper_xaui_probe(int interface)
 {
        int i;
-       union cvmx_gmxx_hg2_control gmx_hg2_control;
        union cvmx_gmxx_inf_mode mode;
 
        /*
@@ -90,13 +102,7 @@ int __cvmx_helper_xaui_probe(int interface)
                pko_mem_port_ptrs.s.pid = interface * 16 + i;
                cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64);
        }
-
-       /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */
-       gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface));
-       if (gmx_hg2_control.s.hg2tx_en)
-               return 16;
-       else
-               return 1;
+       return __cvmx_helper_xaui_enumerate(interface);
 }
 
 /**
similarity index 93%
rename from drivers/staging/octeon/cvmx-helper.c
rename to arch/mips/cavium-octeon/executive/cvmx-helper.c
index e9c5c836ceffdfab287ecb7233b233fa93f55ef2..fa4963856353e46dffc55a0b1d22a794f85f94c0 100644 (file)
  */
 #include <asm/octeon/octeon.h>
 
-#include "cvmx-config.h"
+#include <asm/octeon/cvmx-config.h>
 
-#include "cvmx-fpa.h"
-#include "cvmx-pip.h"
-#include "cvmx-pko.h"
-#include "cvmx-ipd.h"
-#include "cvmx-spi.h"
-#include "cvmx-helper.h"
-#include "cvmx-helper-board.h"
+#include <asm/octeon/cvmx-fpa.h>
+#include <asm/octeon/cvmx-pip.h>
+#include <asm/octeon/cvmx-pko.h>
+#include <asm/octeon/cvmx-ipd.h>
+#include <asm/octeon/cvmx-spi.h>
+#include <asm/octeon/cvmx-helper.h>
+#include <asm/octeon/cvmx-helper-board.h>
 
-#include "cvmx-pip-defs.h"
-#include "cvmx-smix-defs.h"
-#include "cvmx-asxx-defs.h"
+#include <asm/octeon/cvmx-pip-defs.h>
+#include <asm/octeon/cvmx-smix-defs.h>
+#include <asm/octeon/cvmx-asxx-defs.h>
 
 /**
  * cvmx_override_pko_queue_priority(int ipd_port, uint64_t
@@ -234,21 +234,16 @@ static int __cvmx_helper_port_setup_ipd(int ipd_port)
 }
 
 /**
- * This function probes an interface to determine the actual
- * number of hardware ports connected to it. It doesn't setup the
- * ports or enable them. The main goal here is to set the global
- * interface_port_count[interface] correctly. Hardware setup of the
- * ports will be performed later.
+ * This function sets the interface_port_count[interface] correctly,
+ * without modifying any hardware configuration.  Hardware setup of
+ * the ports will be performed later.
  *
  * @interface: Interface to probe
  *
  * Returns Zero on success, negative on failure
  */
-int cvmx_helper_interface_probe(int interface)
+int cvmx_helper_interface_enumerate(int interface)
 {
-       /* At this stage in the game we don't want packets to be moving yet.
-          The following probe calls should perform hardware setup
-          needed to determine port counts. Receive must still be disabled */
        switch (cvmx_helper_interface_get_mode(interface)) {
                /* These types don't support ports to IPD/PKO */
        case CVMX_HELPER_INTERFACE_MODE_DISABLED:
@@ -258,7 +253,7 @@ int cvmx_helper_interface_probe(int interface)
                /* XAUI is a single high speed port */
        case CVMX_HELPER_INTERFACE_MODE_XAUI:
                interface_port_count[interface] =
-                   __cvmx_helper_xaui_probe(interface);
+                   __cvmx_helper_xaui_enumerate(interface);
                break;
                /*
                 * RGMII/GMII/MII are all treated about the same. Most
@@ -267,7 +262,7 @@ int cvmx_helper_interface_probe(int interface)
        case CVMX_HELPER_INTERFACE_MODE_RGMII:
        case CVMX_HELPER_INTERFACE_MODE_GMII:
                interface_port_count[interface] =
-                   __cvmx_helper_rgmii_probe(interface);
+                   __cvmx_helper_rgmii_enumerate(interface);
                break;
                /*
                 * SPI4 can have 1-16 ports depending on the device at
@@ -275,7 +270,7 @@ int cvmx_helper_interface_probe(int interface)
                 */
        case CVMX_HELPER_INTERFACE_MODE_SPI:
                interface_port_count[interface] =
-                   __cvmx_helper_spi_probe(interface);
+                   __cvmx_helper_spi_enumerate(interface);
                break;
                /*
                 * SGMII can have 1-4 ports depending on how many are
@@ -284,12 +279,12 @@ int cvmx_helper_interface_probe(int interface)
        case CVMX_HELPER_INTERFACE_MODE_SGMII:
        case CVMX_HELPER_INTERFACE_MODE_PICMG:
                interface_port_count[interface] =
-                   __cvmx_helper_sgmii_probe(interface);
+                   __cvmx_helper_sgmii_enumerate(interface);
                break;
                /* PCI target Network Packet Interface */
        case CVMX_HELPER_INTERFACE_MODE_NPI:
                interface_port_count[interface] =
-                   __cvmx_helper_npi_probe(interface);
+                   __cvmx_helper_npi_enumerate(interface);
                break;
                /*
                 * Special loopback only ports. These are not the same
@@ -297,7 +292,7 @@ int cvmx_helper_interface_probe(int interface)
                 */
        case CVMX_HELPER_INTERFACE_MODE_LOOP:
                interface_port_count[interface] =
-                   __cvmx_helper_loop_probe(interface);
+                   __cvmx_helper_loop_enumerate(interface);
                break;
        }
 
@@ -312,6 +307,74 @@ int cvmx_helper_interface_probe(int interface)
        return 0;
 }
 
+/**
+ * This function probes an interface to determine the actual
+ * number of hardware ports connected to it. It doesn't setup the
+ * ports or enable them. The main goal here is to set the global
+ * interface_port_count[interface] correctly. Hardware setup of the
+ * ports will be performed later.
+ *
+ * @interface: Interface to probe
+ *
+ * Returns Zero on success, negative on failure
+ */
+int cvmx_helper_interface_probe(int interface)
+{
+       cvmx_helper_interface_enumerate(interface);
+       /* At this stage in the game we don't want packets to be moving yet.
+          The following probe calls should perform hardware setup
+          needed to determine port counts. Receive must still be disabled */
+       switch (cvmx_helper_interface_get_mode(interface)) {
+               /* These types don't support ports to IPD/PKO */
+       case CVMX_HELPER_INTERFACE_MODE_DISABLED:
+       case CVMX_HELPER_INTERFACE_MODE_PCIE:
+               break;
+               /* XAUI is a single high speed port */
+       case CVMX_HELPER_INTERFACE_MODE_XAUI:
+               __cvmx_helper_xaui_probe(interface);
+               break;
+               /*
+                * RGMII/GMII/MII are all treated about the same. Most
+                * functions refer to these ports as RGMII.
+                */
+       case CVMX_HELPER_INTERFACE_MODE_RGMII:
+       case CVMX_HELPER_INTERFACE_MODE_GMII:
+               __cvmx_helper_rgmii_probe(interface);
+               break;
+               /*
+                * SPI4 can have 1-16 ports depending on the device at
+                * the other end.
+                */
+       case CVMX_HELPER_INTERFACE_MODE_SPI:
+               __cvmx_helper_spi_probe(interface);
+               break;
+               /*
+                * SGMII can have 1-4 ports depending on how many are
+                * hooked up.
+                */
+       case CVMX_HELPER_INTERFACE_MODE_SGMII:
+       case CVMX_HELPER_INTERFACE_MODE_PICMG:
+               __cvmx_helper_sgmii_probe(interface);
+               break;
+               /* PCI target Network Packet Interface */
+       case CVMX_HELPER_INTERFACE_MODE_NPI:
+               __cvmx_helper_npi_probe(interface);
+               break;
+               /*
+                * Special loopback only ports. These are not the same
+                * as other ports in loopback mode.
+                */
+       case CVMX_HELPER_INTERFACE_MODE_LOOP:
+               __cvmx_helper_loop_probe(interface);
+               break;
+       }
+
+       /* Make sure all global variables propagate to other cores */
+       CVMX_SYNCWS;
+
+       return 0;
+}
+
 /**
  * Setup the IPD/PIP for the ports on an interface. Packet
  * classification and tagging are set for every port on the
@@ -548,7 +611,6 @@ int __cvmx_helper_errata_fix_ipd_ptr_alignment(void)
        union cvmx_gmxx_prtx_cfg gmx_cfg;
        int retry_cnt;
        int retry_loop_cnt;
-       int mtu;
        int i;
        cvmx_helper_link_info_t link_info;
 
@@ -662,10 +724,6 @@ int __cvmx_helper_errata_fix_ipd_ptr_alignment(void)
                cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
                               1 << INDEX(FIX_IPD_OUTPORT));
 
-               mtu =
-                   cvmx_read_csr(CVMX_GMXX_RXX_JABBER
-                                 (INDEX(FIX_IPD_OUTPORT),
-                                  INTERFACE(FIX_IPD_OUTPORT)));
                cvmx_write_csr(CVMX_GMXX_RXX_JABBER
                               (INDEX(FIX_IPD_OUTPORT),
                                INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4);
similarity index 98%
rename from drivers/staging/octeon/cvmx-interrupt-decodes.c
rename to arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c
index a3337e382ee96fb4c2b7cfa60809119d91b6191a..e59d1b79f24cd54cd083d2466f091279b83110b8 100644 (file)
 
 #include <asm/octeon/octeon.h>
 
-#include "cvmx-gmxx-defs.h"
-#include "cvmx-pcsx-defs.h"
-#include "cvmx-pcsxx-defs.h"
-#include "cvmx-spxx-defs.h"
-#include "cvmx-stxx-defs.h"
+#include <asm/octeon/cvmx-gmxx-defs.h>
+#include <asm/octeon/cvmx-pcsx-defs.h>
+#include <asm/octeon/cvmx-pcsxx-defs.h>
+#include <asm/octeon/cvmx-spxx-defs.h>
+#include <asm/octeon/cvmx-stxx-defs.h>
 
 #ifndef PRINT_ERROR
 #define PRINT_ERROR(format, ...)
similarity index 97%
rename from drivers/staging/octeon/cvmx-interrupt-rsl.c
rename to arch/mips/cavium-octeon/executive/cvmx-interrupt-rsl.c
index df50048cfbc08c69b2ecf9252e897aee3d539dce..bea7538ea4e970808815bbb43a360fef12eeae9d 100644 (file)
@@ -32,8 +32,8 @@
 
 #include <asm/octeon/octeon.h>
 
-#include "cvmx-asxx-defs.h"
-#include "cvmx-gmxx-defs.h"
+#include <asm/octeon/cvmx-asxx-defs.h>
+#include <asm/octeon/cvmx-gmxx-defs.h>
 
 #ifndef PRINT_ERROR
 #define PRINT_ERROR(format, ...)
similarity index 98%
rename from drivers/staging/octeon/cvmx-pko.c
rename to arch/mips/cavium-octeon/executive/cvmx-pko.c
index 50a2c9bd5a55f849ff9fcd2632f7524003ca5a5b..f557084b10924df198d018c8d79d6e3faa139f49 100644 (file)
@@ -31,9 +31,9 @@
 
 #include <asm/octeon/octeon.h>
 
-#include "cvmx-config.h"
-#include "cvmx-pko.h"
-#include "cvmx-helper.h"
+#include <asm/octeon/cvmx-config.h>
+#include <asm/octeon/cvmx-pko.h>
+#include <asm/octeon/cvmx-helper.h>
 
 /**
  * Internal state of packet output
@@ -54,7 +54,7 @@ void cvmx_pko_initialize_global(void)
        /*
         * Set the size of the PKO command buffers to an odd number of
         * 64bit words. This allows the normal two word send to stay
-        * aligned and never span a command word buffer.
+        * aligned and never span a comamnd word buffer.
         */
        config.u64 = 0;
        config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL;
similarity index 99%
rename from drivers/staging/octeon/cvmx-spi.c
rename to arch/mips/cavium-octeon/executive/cvmx-spi.c
index 82794d920cec9f405f1404e9d2f9b23ddd01cf1d..74afb1710cd98767d29837d0f9ed1630e5ebb5e9 100644 (file)
  */
 #include <asm/octeon/octeon.h>
 
-#include "cvmx-config.h"
+#include <asm/octeon/cvmx-config.h>
 
-#include "cvmx-pko.h"
-#include "cvmx-spi.h"
+#include <asm/octeon/cvmx-pko.h>
+#include <asm/octeon/cvmx-spi.h>
 
-#include "cvmx-spxx-defs.h"
-#include "cvmx-stxx-defs.h"
-#include "cvmx-srxx-defs.h"
+#include <asm/octeon/cvmx-spxx-defs.h>
+#include <asm/octeon/cvmx-stxx-defs.h>
+#include <asm/octeon/cvmx-srxx-defs.h>
 
 #define INVOKE_CB(function_p, args...)         \
        do {                                    \
index c8d35684504e87860074694e876d214d6c932072..f4c1b36fdf65d503a13e23de6e2c88a1b8a7bae0 100644 (file)
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
  * Contact Cavium Networks for more information
  ***********************license end**************************************/
 
-/*
- * File defining functions for working with different Octeon
- * models.
- */
 #include <asm/octeon/octeon.h>
 
 /**
@@ -69,11 +65,12 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
        char fuse_model[10];
        uint32_t fuse_data = 0;
 
-       fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3);
+       fus3.u64 = 0;
+       if (!OCTEON_IS_MODEL(OCTEON_CN6XXX))
+               fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3);
        fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2);
        fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3);
-
-       num_cores = cvmx_octeon_num_cores();
+       num_cores = cvmx_pop(cvmx_read_csr(CVMX_CIU_FUSE));
 
        /* Make sure the non existent devices look disabled */
        switch ((chip_id >> 8) & 0xff) {
@@ -108,7 +105,7 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
         * Assume pass number is encoded using <5:3><2:0>. Exceptions
         * will be fixed later.
         */
-       sprintf(pass, "%u.%u", ((chip_id >> 3) & 7) + 1, chip_id & 7);
+       sprintf(pass, "%d.%d", (int)((chip_id >> 3) & 7) + 1, (int)chip_id & 7);
 
        /*
         * Use the number of cores to determine the last 2 digits of
@@ -116,6 +113,12 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
         * later.
         */
        switch (num_cores) {
+       case 32:
+               core_model = "80";
+               break;
+       case 24:
+               core_model = "70";
+               break;
        case 16:
                core_model = "60";
                break;
@@ -246,8 +249,8 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
                break;
        case 3:         /* CN58XX */
                family = "58";
-               /* Special case. 4 core, no crypto */
-               if ((num_cores == 4) && fus_dat2.cn38xx.nocrypto)
+               /* Special case. 4 core, half cache (CP with half cache) */
+               if ((num_cores == 4) && fus3.cn58xx.crip_1024k && !strncmp(suffix, "CP", 2))
                        core_model = "29";
 
                /* Pass 1 uses different encodings for pass numbers */
@@ -285,6 +288,9 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
                                suffix = "NSP";
                                if (fus_dat3.s.nozip)
                                        suffix = "SCP";
+
+                               if (fus_dat3.s.bar2_en)
+                                       suffix = "NSPB2";
                        }
                        if (fus3.cn56xx.crip_1024k)
                                family = "54";
@@ -301,6 +307,60 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
                else
                        family = "52";
                break;
+       case 0x93:              /* CN61XX */
+               family = "61";
+               if (fus_dat2.cn61xx.nocrypto && fus_dat2.cn61xx.dorm_crypto)
+                       suffix = "AP";
+               if (fus_dat2.cn61xx.nocrypto)
+                       suffix = "CP";
+               else if (fus_dat2.cn61xx.dorm_crypto)
+                       suffix = "DAP";
+               else if (fus_dat3.cn61xx.nozip)
+                       suffix = "SCP";
+               break;
+       case 0x90:              /* CN63XX */
+               family = "63";
+               if (fus_dat3.s.l2c_crip == 2)
+                       family = "62";
+               if (num_cores == 6)     /* Other core counts match generic */
+                       core_model = "35";
+               if (fus_dat2.cn63xx.nocrypto)
+                       suffix = "CP";
+               else if (fus_dat2.cn63xx.dorm_crypto)
+                       suffix = "DAP";
+               else if (fus_dat3.cn63xx.nozip)
+                       suffix = "SCP";
+               else
+                       suffix = "AAP";
+               break;
+       case 0x92:              /* CN66XX */
+               family = "66";
+               if (num_cores == 6)     /* Other core counts match generic */
+                       core_model = "35";
+               if (fus_dat2.cn66xx.nocrypto && fus_dat2.cn66xx.dorm_crypto)
+                       suffix = "AP";
+               if (fus_dat2.cn66xx.nocrypto)
+                       suffix = "CP";
+               else if (fus_dat2.cn66xx.dorm_crypto)
+                       suffix = "DAP";
+               else if (fus_dat3.cn66xx.nozip)
+                       suffix = "SCP";
+               else
+                       suffix = "AAP";
+               break;
+       case 0x91:              /* CN68XX */
+               family = "68";
+               if (fus_dat2.cn68xx.nocrypto && fus_dat3.cn68xx.nozip)
+                       suffix = "CP";
+               else if (fus_dat2.cn68xx.dorm_crypto)
+                       suffix = "DAP";
+               else if (fus_dat3.cn68xx.nozip)
+                       suffix = "SCP";
+               else if (fus_dat2.cn68xx.nocrypto)
+                       suffix = "SP";
+               else
+                       suffix = "AAP";
+               break;
        default:
                family = "XX";
                core_model = "XX";
@@ -310,49 +370,40 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
        }
 
        clock_mhz = octeon_get_clock_rate() / 1000000;
-
        if (family[0] != '3') {
+               int fuse_base = 384 / 8;
+               if (family[0] == '6')
+                       fuse_base = 832 / 8;
+
                /* Check for model in fuses, overrides normal decode */
                /* This is _not_ valid for Octeon CN3XXX models */
-               fuse_data |= cvmx_fuse_read_byte(51);
+               fuse_data |= cvmx_fuse_read_byte(fuse_base + 3);
                fuse_data = fuse_data << 8;
-               fuse_data |= cvmx_fuse_read_byte(50);
+               fuse_data |= cvmx_fuse_read_byte(fuse_base + 2);
                fuse_data = fuse_data << 8;
-               fuse_data |= cvmx_fuse_read_byte(49);
+               fuse_data |= cvmx_fuse_read_byte(fuse_base + 1);
                fuse_data = fuse_data << 8;
-               fuse_data |= cvmx_fuse_read_byte(48);
+               fuse_data |= cvmx_fuse_read_byte(fuse_base);
                if (fuse_data & 0x7ffff) {
                        int model = fuse_data & 0x3fff;
                        int suffix = (fuse_data >> 14) & 0x1f;
                        if (suffix && model) {
-                               /*
-                                * Have both number and suffix in
-                                * fuses, so both
-                                */
-                               sprintf(fuse_model, "%d%c",
-                                       model, 'A' + suffix - 1);
+                               /* Have both number and suffix in fuses, so both */
+                               sprintf(fuse_model, "%d%c", model, 'A' + suffix - 1);
                                core_model = "";
                                family = fuse_model;
                        } else if (suffix && !model) {
-                               /*
-                                * Only have suffix, so add suffix to
-                                * 'normal' model number.
-                                */
-                               sprintf(fuse_model, "%s%c", core_model,
-                                       'A' + suffix - 1);
+                               /* Only have suffix, so add suffix to 'normal' model number */
+                               sprintf(fuse_model, "%s%c", core_model, 'A' + suffix - 1);
                                core_model = fuse_model;
                        } else {
-                               /*
-                                * Don't have suffix, so just use
-                                * model from fuses.
-                                */
+                               /* Don't have suffix, so just use model from fuses */
                                sprintf(fuse_model, "%d", model);
                                core_model = "";
                                family = fuse_model;
                        }
                }
        }
-       sprintf(buffer, "CN%s%sp%s-%d-%s",
-               family, core_model, pass, clock_mhz, suffix);
+       sprintf(buffer, "CN%s%sp%s-%d-%s", family, core_model, pass, clock_mhz, suffix);
        return buffer;
 }
index 2d9028f1474c0a3f343d6a6c75b12de71cbd2231..260b27367347b1da080e4045f00a54fa87656754 100644 (file)
@@ -642,14 +642,6 @@ void __init plat_mem_setup(void)
 
        total = 0;
 
-       /* First add the init memory we will be returning.  */
-       memory = __pa_symbol(&__init_begin) & PAGE_MASK;
-       mem_alloc_size = (__pa_symbol(&__init_end) & PAGE_MASK) - memory;
-       if (mem_alloc_size > 0) {
-               add_memory_region(memory, mem_alloc_size, BOOT_MEM_RAM);
-               total += mem_alloc_size;
-       }
-
        /*
         * The Mips memory init uses the first memory location for
         * some memory vectors. When SPARSEMEM is in use, it doesn't
@@ -767,11 +759,11 @@ void prom_free_prom_memory(void)
                        : "=r" (insn) : : "$31", "memory");
 
                if ((insn >> 26) != 0x33)
-                       panic("No PREF instruction at Core-14449 probe point.\n");
+                       panic("No PREF instruction at Core-14449 probe point.");
 
                if (((insn >> 16) & 0x1f) != 28)
                        panic("Core-14449 WAR not in place (%04x).\n"
-                             "Please build kernel with proper options (CONFIG_CAVIUM_CN63XXP1).\n", insn);
+                             "Please build kernel with proper options (CONFIG_CAVIUM_CN63XXP1).", insn);
        }
 #ifdef CONFIG_CAVIUM_DECODE_RSL
        cvmx_interrupt_rsl_enable();
@@ -779,7 +771,7 @@ void prom_free_prom_memory(void)
        /* Add an interrupt handler for general failures. */
        if (request_irq(OCTEON_IRQ_RML, octeon_rlm_interrupt, IRQF_SHARED,
                        "RML/RSL", octeon_rlm_interrupt)) {
-               panic("Unable to request_irq(OCTEON_IRQ_RML)\n");
+               panic("Unable to request_irq(OCTEON_IRQ_RML)");
        }
 #endif
 }
index efcfff4d4627c55f4238bfd3361fe937be25465e..b1535fe409d4b50935654cf04634ab81139c2992 100644 (file)
@@ -210,7 +210,7 @@ void octeon_prepare_cpus(unsigned int max_cpus)
        if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt,
                        IRQF_PERCPU | IRQF_NO_THREAD, "SMP-IPI",
                        mailbox_interrupt)) {
-               panic("Cannot request_irq(OCTEON_IRQ_MBOX0)\n");
+               panic("Cannot request_irq(OCTEON_IRQ_MBOX0)");
        }
 }
 
index 4044c9e0fb737d9962ad17178b8c05e14ffeaa9a..17a36c12517296f95f772396670f0610a7f29b86 100644 (file)
+CONFIG_MIPS=y
 CONFIG_MIPS_ALCHEMY=y
+CONFIG_MIPS_DB1000=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_HZ_100=y
-# CONFIG_SECCOMP is not set
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
 CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-db1000"
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION="-db1x00"
+CONFIG_LOCALVERSION_AUTO=y
 CONFIG_KERNEL_LZMA=y
+CONFIG_DEFAULT_HOSTNAME="db1x00"
+CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_FHANDLE=y
+CONFIG_AUDIT=y
 CONFIG_TINY_RCU=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+CONFIG_SYSCTL=y
 CONFIG_EXPERT=y
-# CONFIG_KALLSYMS is not set
-# CONFIG_PCSPKR_PLATFORM is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_COMPAT_BRK is not set
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_EMBEDDED=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PCI_QUIRKS=y
 CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_LBDAF is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
+CONFIG_SLABINFO=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+CONFIG_BLK_DEV_BSGLIB=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_FREEZER=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
 CONFIG_PCCARD=y
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
 CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
-CONFIG_PM=y
+CONFIG_BINFMT_ELF=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_PM_SLEEP=y
 CONFIG_PM_RUNTIME=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_XFRM=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_IP_PNP_RARP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_NET_IPIP=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_LRO=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_IPV6=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_STP=y
+CONFIG_GARP=y
+CONFIG_BRIDGE=y
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+CONFIG_VLAN_8021Q=y
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_LLC=y
+CONFIG_LLC2=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIBTUSB=y
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+CONFIG_MTD_CFI_I4=y
+CONFIG_MTD_CFI_I8=y
+CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_UTIL=y
 CONFIG_MTD_PHYSMAP=y
-# CONFIG_MISC_DEVICES is not set
+CONFIG_SCSI_MOD=y
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+CONFIG_SCSI_PROC_FS=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_ATA=y
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_ATA_SFF=y
+CONFIG_ATA_BMDMA=y
+CONFIG_PATA_HPT37X=y
+CONFIG_PATA_PCMCIA=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_FIREWIRE=y
+CONFIG_FIREWIRE_OHCI=y
+CONFIG_FIREWIRE_OHCI_DEBUG=y
+CONFIG_FIREWIRE_NET=y
 CONFIG_NETDEVICES=y
-CONFIG_MARVELL_PHY=y
-CONFIG_DAVICOM_PHY=y
-CONFIG_QSEMI_PHY=y
-CONFIG_LXT_PHY=y
-CONFIG_CICADA_PHY=y
-CONFIG_VITESSE_PHY=y
-CONFIG_SMSC_PHY=y
-CONFIG_BROADCOM_PHY=y
-CONFIG_ICPLUS_PHY=y
-CONFIG_REALTEK_PHY=y
-CONFIG_NATIONAL_PHY=y
-CONFIG_STE10XP=y
-CONFIG_LSI_ET1011C_PHY=y
-CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
+CONFIG_PHYLIB=y
+CONFIG_NET_ETHERNET=y
 CONFIG_MIPS_AU1X00_ENET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_WLAN is not set
-# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=y
+CONFIG_PCMCIA_PCNET=y
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOE=y
+CONFIG_INPUT=y
 CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+CONFIG_DEVKMEM=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_TTY_PRINTK=y
+CONFIG_DEVPORT=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_AU1100=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x16=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+CONFIG_SND_SEQUENCER=y
+CONFIG_SND_HRTIMER=y
+CONFIG_SND_SEQ_HRTIMER_DEFAULT=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_AC97_BUS=y
+CONFIG_SND_SOC_AU1XAUDIO=y
+CONFIG_SND_SOC_AU1XAC97C=y
+CONFIG_SND_SOC_DB1000=y
+CONFIG_SND_SOC_AC97_CODEC=y
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HIDRAW=y
+CONFIG_USB_HID=y
+CONFIG_USB_SUPPORT=y
 CONFIG_USB=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_DYNAMIC_MINORS=y
 CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
 CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
 CONFIG_RTC_DRV_AU1XXX=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-# CONFIG_EXT3_FS_XATTR is not set
-# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+CONFIG_EXT4_FS_XATTR=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_JBD2=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_GENERIC_ACL=y
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
 CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_MISC_FILESYSTEMS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_FS_POSIX_ACL=y
+CONFIG_JFFS2_FS_SECURITY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_JFFS2_CMODE_PRIORITY=y
 CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_ZLIB=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_PNFS_FILE_LAYOUT=y
+CONFIG_PNFS_BLOCK=y
 CONFIG_ROOT_NFS=y
+CONFIG_NFS_USE_KERNEL_DNS=y
+CONFIG_NFS_USE_NEW_IDMAPPER=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_SUNRPC_BACKCHANNEL=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_ISO8859_15=y
 CONFIG_NLS_UTF8=y
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_STRIP_ASM_SYMS=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_FTRACE is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="noirqdebug rootwait root=/dev/sda1 rootfstype=ext4 console=ttyS0,115200 video=au1100fb:panel:CRT_800x600_16"
 CONFIG_DEBUG_ZBOOT=y
 CONFIG_KEYS=y
 CONFIG_KEYS_DEBUG_PROC_KEYS=y
+CONFIG_SECURITYFS=y
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_XZ_DEC=y
diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig
deleted file mode 100644 (file)
index c6b4993..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-CONFIG_MIPS_ALCHEMY=y
-CONFIG_MIPS_DB1100=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_HZ_100=y
-# CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-db1100"
-CONFIG_KERNEL_LZMA=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_TINY_RCU=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_KALLSYMS is not set
-# CONFIG_PCSPKR_PLATFORM is not set
-# CONFIG_COMPAT_BRK is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_LBDAF is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
-CONFIG_PM=y
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-# CONFIG_BLK_DEV is not set
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_IDE_TASK_IOCTL=y
-CONFIG_NETDEVICES=y
-CONFIG_MARVELL_PHY=y
-CONFIG_DAVICOM_PHY=y
-CONFIG_QSEMI_PHY=y
-CONFIG_LXT_PHY=y
-CONFIG_CICADA_PHY=y
-CONFIG_VITESSE_PHY=y
-CONFIG_SMSC_PHY=y
-CONFIG_BROADCOM_PHY=y
-CONFIG_ICPLUS_PHY=y
-CONFIG_REALTEK_PHY=y
-CONFIG_NATIONAL_PHY=y
-CONFIG_STE10XP=y
-CONFIG_LSI_ET1011C_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-CONFIG_MIPS_AU1X00_ENET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_WLAN is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_VT_HW_CONSOLE_BINDING=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-CONFIG_FB=y
-CONFIG_FB_AU1100=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x16=y
-# CONFIG_HID_SUPPORT is not set
-CONFIG_USB=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_DYNAMIC_MINORS=y
-CONFIG_USB_SUSPEND=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AU1XXX=y
-CONFIG_EXT2_FS=y
-# CONFIG_PROC_PAGE_MONITOR is not set
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_FS_XATTR=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_LZO=y
-CONFIG_JFFS2_RUBIN=y
-CONFIG_SQUASHFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_STRIP_ASM_SYMS=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_FTRACE is not set
-CONFIG_DEBUG_ZBOOT=y
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
-CONFIG_SECURITYFS=y
diff --git a/arch/mips/configs/db1300_defconfig b/arch/mips/configs/db1300_defconfig
new file mode 100644 (file)
index 0000000..c38b190
--- /dev/null
@@ -0,0 +1,391 @@
+CONFIG_MIPS=y
+CONFIG_MIPS_ALCHEMY=y
+CONFIG_ALCHEMY_GPIOINT_AU1300=y
+CONFIG_MIPS_DB1300=y
+CONFIG_SOC_AU1300=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CSRC_R4K_LIB=y
+CONFIG_DMA_COHERENT=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_MIPS_DISABLE_OBSOLETE_IDE=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_CPU_MIPS32_R1=y
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_32BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+CONFIG_64BIT_PHYS_ADDR=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_COMPACTION=y
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_HZ_100=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION="-db1300"
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_LZMA=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_FHANDLE=y
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_TINY_RCU=y
+CONFIG_LOG_BUF_SHIFT=19
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EXPERT=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_EMBEDDED=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_SLAB=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_INLINE_SPIN_UNLOCK=y
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+CONFIG_INLINE_READ_UNLOCK=y
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+CONFIG_INLINE_WRITE_UNLOCK=y
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+CONFIG_MMU=y
+CONFIG_PCCARD=y
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
+CONFIG_BINFMT_ELF=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_TRAD_SIGNALS=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_INET_TUNNEL=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_IPV6=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_PLATFORM=y
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_UB=y
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+CONFIG_BLK_DEV_IDECS=y
+CONFIG_IDE_TASK_IOCTL=y
+CONFIG_IDE_PROC_FS=y
+CONFIG_BLK_DEV_PLATFORM=y
+CONFIG_SCSI_MOD=y
+CONFIG_NETDEVICES=y
+CONFIG_MII=y
+CONFIG_PHYLIB=y
+CONFIG_SMSC_PHY=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMSC911X=y
+CONFIG_INPUT=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_WM97XX=y
+CONFIG_TOUCHSCREEN_WM9712=y
+CONFIG_TOUCHSCREEN_WM9713=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_SMBUS=y
+CONFIG_I2C_AU1550=y
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_AU1550=y
+CONFIG_SPI_BITBANG=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=y
+CONFIG_SENSORS_ADM1025=y
+CONFIG_FB=y
+CONFIG_FB_AU1200=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_ACORN_8x8=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+CONFIG_SND_HRTIMER=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_VERBOSE_PROCFS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_CACHE_LZO=y
+CONFIG_SND_SOC_AC97_BUS=y
+CONFIG_SND_SOC_AU1XPSC=y
+CONFIG_SND_SOC_AU1XPSC_I2S=y
+CONFIG_SND_SOC_AU1XPSC_AC97=y
+CONFIG_SND_SOC_DB1300=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+CONFIG_SND_SOC_WM8731=y
+CONFIG_SND_SOC_WM9712=y
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HIDRAW=y
+CONFIG_USB_HID=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+CONFIG_RTC_DRV_AU1XXX=y
+CONFIG_EXT2_FS=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_GENERIC_ACL=y
+CONFIG_FAT_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_MISC_FILESYSTEMS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_FS_POSIX_ACL=y
+CONFIG_JFFS2_FS_SECURITY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_JFFS2_CMODE_PRIORITY=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_UTF8=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="video=au1200fb:panel:bs console=tty console=ttyS2,115200"
+CONFIG_DEBUG_ZBOOT=y
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+CONFIG_BITREVERSE=y
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_XZ_DEC=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig
deleted file mode 100644 (file)
index b6e21c7..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-CONFIG_MIPS_ALCHEMY=y
-CONFIG_MIPS_DB1500=y
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_HZ_100=y
-# CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-db1500"
-CONFIG_KERNEL_LZMA=y
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EXPERT=y
-# CONFIG_KALLSYMS is not set
-# CONFIG_PCSPKR_PLATFORM is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_COMPAT_BRK is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_PCI=y
-CONFIG_PCCARD=y
-# CONFIG_CARDBUS is not set
-CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
-CONFIG_PM=y
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECS=y
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_HPT366=y
-CONFIG_NETDEVICES=y
-CONFIG_MARVELL_PHY=y
-CONFIG_DAVICOM_PHY=y
-CONFIG_QSEMI_PHY=y
-CONFIG_LXT_PHY=y
-CONFIG_CICADA_PHY=y
-CONFIG_VITESSE_PHY=y
-CONFIG_SMSC_PHY=y
-CONFIG_BROADCOM_PHY=y
-CONFIG_ICPLUS_PHY=y
-CONFIG_REALTEK_PHY=y
-CONFIG_NATIONAL_PHY=y
-CONFIG_STE10XP=y
-CONFIG_LSI_ET1011C_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-CONFIG_MIPS_AU1X00_ENET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_WLAN is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_PCI is not set
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_VGA_ARB is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-CONFIG_USB=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_DYNAMIC_MINORS=y
-CONFIG_USB_SUSPEND=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AU1XXX=y
-CONFIG_EXT2_FS=y
-# CONFIG_PROC_PAGE_MONITOR is not set
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_FS_XATTR=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_LZO=y
-CONFIG_JFFS2_RUBIN=y
-CONFIG_SQUASHFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_CODEPAGE_1250=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_ISO8859_15=y
-CONFIG_NLS_UTF8=y
-CONFIG_STRIP_ASM_SYMS=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_FTRACE is not set
-CONFIG_DEBUG_ZBOOT=y
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
-CONFIG_SECURITYFS=y
index 798a553c9e80fb7154df4e42dcb06e1d9c7d7382..36cda27725e7e23c1745a960478bbc3edff0662c 100644 (file)
+CONFIG_MIPS=y
 CONFIG_MIPS_ALCHEMY=y
 CONFIG_MIPS_DB1550=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_HZ_100=y
-# CONFIG_SECCOMP is not set
+CONFIG_HZ=100
 CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION="-db1550"
+CONFIG_LOCALVERSION_AUTO=y
 CONFIG_KERNEL_LZMA=y
+CONFIG_DEFAULT_HOSTNAME="db1550"
+CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_FHANDLE=y
+CONFIG_AUDIT=y
 CONFIG_TINY_RCU=y
-CONFIG_LOG_BUF_SHIFT=14
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
 CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_KALLSYMS is not set
-# CONFIG_PCSPKR_PLATFORM is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_COMPAT_BRK is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_EMBEDDED=y
+CONFIG_PCI_QUIRKS=y
 CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+CONFIG_BLK_DEV_BSGLIB=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
 CONFIG_PCI=y
 CONFIG_PCCARD=y
-# CONFIG_CARDBUS is not set
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
 CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
-CONFIG_PM=y
+CONFIG_BINFMT_ELF=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_BINFMT_MISC=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_PM_SLEEP=y
 CONFIG_PM_RUNTIME=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_XFRM=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_IP_PNP_RARP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_LRO=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_IPV6=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
 CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_UTIL=y
 CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_NAND_ECC=y
 CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_AU1550=y
-CONFIG_BLK_DEV_UB=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECS=y
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS is not set
-CONFIG_IDE_TASK_IOCTL=y
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_HPT366=y
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_PLATFORM=y
+CONFIG_MISC_DEVICES=y
+CONFIG_EEPROM_AT24=y
+CONFIG_SCSI_MOD=y
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_ATA=y
+CONFIG_ATA_SFF=y
+CONFIG_ATA_BMDMA=y
+CONFIG_PATA_HPT37X=y
+CONFIG_PATA_PCMCIA=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
 CONFIG_NETDEVICES=y
-CONFIG_MARVELL_PHY=y
-CONFIG_DAVICOM_PHY=y
-CONFIG_QSEMI_PHY=y
-CONFIG_LXT_PHY=y
-CONFIG_CICADA_PHY=y
-CONFIG_VITESSE_PHY=y
-CONFIG_SMSC_PHY=y
-CONFIG_BROADCOM_PHY=y
-CONFIG_ICPLUS_PHY=y
-CONFIG_REALTEK_PHY=y
-CONFIG_NATIONAL_PHY=y
-CONFIG_STE10XP=y
-CONFIG_LSI_ET1011C_PHY=y
-CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
+CONFIG_PHYLIB=y
+CONFIG_NET_ETHERNET=y
 CONFIG_MIPS_AU1X00_ENET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_WLAN is not set
-# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=y
+CONFIG_PCMCIA_PCNET=y
+CONFIG_INPUT=y
 CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+CONFIG_DEVKMEM=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_DEVPORT=y
 CONFIG_I2C=y
-# CONFIG_I2C_COMPAT is not set
+CONFIG_I2C_BOARDINFO=y
 CONFIG_I2C_CHARDEV=y
-# CONFIG_I2C_HELPER_AUTO is not set
 CONFIG_I2C_AU1550=y
 CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
 CONFIG_SPI_AU1550=y
-# CONFIG_HWMON is not set
-# CONFIG_VGA_ARB is not set
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_SPI_BITBANG=y
+CONFIG_HWMON=y
+CONFIG_SENSORS_ADM1025=y
+CONFIG_SENSORS_LM70=y
+CONFIG_DUMMY_CONSOLE=y
 CONFIG_SOUND=y
 CONFIG_SND=y
-CONFIG_SND_HRTIMER=y
-CONFIG_SND_DYNAMIC_MINORS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
-# CONFIG_SND_VERBOSE_PROCFS is not set
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_PCI is not set
-# CONFIG_SND_SPI is not set
-# CONFIG_SND_MIPS is not set
-# CONFIG_SND_PCMCIA is not set
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=y
 CONFIG_SND_SOC=y
+CONFIG_SND_SOC_AC97_BUS=y
 CONFIG_SND_SOC_AU1XPSC=y
-# CONFIG_HID_SUPPORT is not set
+CONFIG_SND_SOC_AU1XPSC_I2S=y
+CONFIG_SND_SOC_AU1XPSC_AC97=y
+CONFIG_SND_SOC_DB1200=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+CONFIG_SND_SOC_AC97_CODEC=y
+CONFIG_SND_SOC_WM8731=y
+CONFIG_SND_SOC_WM9712=y
+CONFIG_AC97_BUS=y
 CONFIG_USB=y
-# CONFIG_USB_DEVICE_CLASS is not set
 CONFIG_USB_DYNAMIC_MINORS=y
-CONFIG_USB_SUSPEND=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
 CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
 CONFIG_RTC_DRV_AU1XXX=y
-CONFIG_EXT2_FS=y
-# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+CONFIG_EXT4_FS_XATTR=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_JBD2=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 CONFIG_CONFIGFS_FS=y
+CONFIG_MISC_FILESYSTEMS=y
 CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
 CONFIG_JFFS2_SUMMARY=y
 CONFIG_JFFS2_FS_XATTR=y
-# CONFIG_JFFS2_FS_POSIX_ACL is not set
-# CONFIG_JFFS2_FS_SECURITY is not set
 CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
 CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
 CONFIG_JFFS2_RUBIN=y
+CONFIG_JFFS2_CMODE_PRIORITY=y
 CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_ZLIB=y
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_PNFS_FILE_LAYOUT=y
+CONFIG_PNFS_BLOCK=y
 CONFIG_ROOT_NFS=y
+CONFIG_NFS_USE_KERNEL_DNS=y
+CONFIG_NFS_USE_NEW_IDMAPPER=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_SUNRPC_BACKCHANNEL=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_CODEPAGE_852=y
@@ -148,10 +265,21 @@ CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_NLS_ISO8859_15=y
 CONFIG_NLS_UTF8=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_FTRACE is not set
-CONFIG_DEBUG_ZBOOT=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_FRAME_WARN=1024
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="noirqdebug console=ttyS0,115200 root=/dev/sda1 rootfstype=ext4"
 CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
 CONFIG_SECURITYFS=y
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_BITREVERSE=y
+CONFIG_CRC16=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_BCH=y
+CONFIG_NLATTR=y
diff --git a/arch/mips/configs/nlm_xlp_defconfig b/arch/mips/configs/nlm_xlp_defconfig
new file mode 100644 (file)
index 0000000..4479fd6
--- /dev/null
@@ -0,0 +1,570 @@
+CONFIG_NLM_XLP_BOARD=y
+CONFIG_64BIT=y
+CONFIG_KSM=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_SMP=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+# CONFIG_SECCOMP is not set
+CONFIG_USE_OF=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_CROSS_COMPILE="mips-linux-gnu-"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_AUDIT=y
+CONFIG_CGROUPS=y
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs.xlp"
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_INITRAMFS_COMPRESSION_LZMA=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLK_DEV_INTEGRITY=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_MISC=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_DEBUG=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_NET_IPIP=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETLABEL=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NETFILTER_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_FTP=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_SECURITY=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_DECNET_NF_GRABULATOR=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+CONFIG_IP_DCCP=m
+CONFIG_RDS=m
+CONFIG_RDS_TCP=m
+CONFIG_TIPC=m
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_DECNET=m
+CONFIG_LLC2=m
+CONFIG_IPX=m
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+CONFIG_X25=m
+CONFIG_LAPB=m
+CONFIG_ECONET=m
+CONFIG_ECONET_AUNUDP=y
+CONFIG_ECONET_NATIVE=y
+CONFIG_WAN_ROUTER=m
+CONFIG_PHONET=m
+CONFIG_IEEE802154=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_DCB=y
+CONFIG_NET_PKTGEN=m
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+CONFIG_CONNECTOR=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_OSD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_CDROM_PKTCDVD=y
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=m
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_TGT_ATTRS=y
+CONFIG_SCSI_SAS_LIBSAS=m
+CONFIG_SCSI_SRP_ATTRS=m
+CONFIG_SCSI_SRP_TGT_ATTRS=y
+CONFIG_ISCSI_TCP=m
+CONFIG_LIBFCOE=m
+CONFIG_SCSI_DEBUG=m
+CONFIG_SCSI_DH=y
+CONFIG_SCSI_DH_RDAC=m
+CONFIG_SCSI_DH_HP_SW=m
+CONFIG_SCSI_DH_EMC=m
+CONFIG_SCSI_DH_ALUA=m
+CONFIG_SCSI_OSD_INITIATOR=m
+CONFIG_SCSI_OSD_ULD=m
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+CONFIG_LEGACY_PTY_COUNT=0
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_N_HDLC=m
+# CONFIG_DEVKMEM is not set
+CONFIG_STALDRV=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=48
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+CONFIG_RAW_DRIVER=m
+# CONFIG_HWMON is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_UIO=y
+CONFIG_UIO_PDRV=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_GFS2_FS=m
+CONFIG_GFS2_FS_LOCKING_DLM=y
+CONFIG_OCFS2_FS=m
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_NILFS2_FS=m
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=m
+CONFIG_FSCACHE=m
+CONFIG_FSCACHE_STATS=y
+CONFIG_FSCACHE_HISTOGRAM=y
+CONFIG_CACHEFILES=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_NTFS_FS=m
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ADFS_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_ECRYPT_FS=y
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=m
+CONFIG_VXFS_FS=m
+CONFIG_MINIX_FS=m
+CONFIG_OMFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+CONFIG_EXOFS_FS=m
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+CONFIG_CODA_FS=m
+CONFIG_AFS_FS=m
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ACORN_PARTITION=y
+CONFIG_ACORN_PARTITION_ICS=y
+CONFIG_ACORN_PARTITION_RISCIX=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+CONFIG_SGI_PARTITION=y
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
+CONFIG_SYSV68_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="cp437"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_PRINTK_TIME=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_SCHED_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_KGDB=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_LSM_MMAP_MIN_ADDR=0
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_SECURITY_TOMOYO=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SALSA20=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ZLIB=m
+CONFIG_CRYPTO_LZO=m
+CONFIG_CRC_CCITT=m
+CONFIG_CRC7=m
index e4b399fdaa619d7f5a9f247b3ee094e4f1a0fda2..7c68666fdd646c3354f872ffc91eeeecfa4785d3 100644 (file)
@@ -8,7 +8,7 @@ CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_KEXEC=y
 CONFIG_EXPERIMENTAL=y
-CONFIG_CROSS_COMPILE="mips64-unknown-linux-gnu-"
+CONFIG_CROSS_COMPILE="mips-linux-gnu-"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -22,15 +22,13 @@ CONFIG_AUDIT=y
 CONFIG_NAMESPACES=y
 CONFIG_SCHED_AUTOGROUP=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs"
+CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs.xlr"
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
 CONFIG_INITRAMFS_COMPRESSION_GZIP=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_ELF_CORE is not set
-# CONFIG_PCSPKR_PLATFORM is not set
 # CONFIG_PERF_EVENTS is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
@@ -39,6 +37,9 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_DEBUG=y
 CONFIG_BINFMT_MISC=m
 CONFIG_PM_RUNTIME=y
 CONFIG_PM_DEBUG=y
@@ -297,12 +298,10 @@ CONFIG_NET_ACT_SIMP=m
 CONFIG_NET_ACT_SKBEDIT=m
 CONFIG_DCB=y
 CONFIG_NET_PKTGEN=m
-# CONFIG_WIRELESS is not set
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
 CONFIG_CONNECTOR=y
-CONFIG_MTD=m
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
@@ -339,6 +338,9 @@ CONFIG_SCSI_DH_EMC=m
 CONFIG_SCSI_DH_ALUA=m
 CONFIG_SCSI_OSD_INITIATOR=m
 CONFIG_SCSI_OSD_ULD=m
+CONFIG_NETDEVICES=y
+CONFIG_E1000E=y
+CONFIG_SKY2=y
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
@@ -443,7 +445,6 @@ CONFIG_CIFS_UPCALL=y
 CONFIG_CIFS_XATTR=y
 CONFIG_CIFS_POSIX=y
 CONFIG_CIFS_DFS_UPCALL=y
-CONFIG_CIFS_EXPERIMENTAL=y
 CONFIG_NCP_FS=m
 CONFIG_NCPFS_PACKET_SIGNING=y
 CONFIG_NCPFS_IOCTL_LOCKING=y
@@ -516,7 +517,6 @@ CONFIG_PRINTK_TIME=y
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
 # CONFIG_ENABLE_MUST_CHECK is not set
 CONFIG_UNUSED_SYMBOLS=y
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
diff --git a/arch/mips/configs/pb1200_defconfig b/arch/mips/configs/pb1200_defconfig
deleted file mode 100644 (file)
index dcbe270..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-CONFIG_MIPS_ALCHEMY=y
-CONFIG_MIPS_PB1200=y
-CONFIG_KSM=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_HZ_100=y
-# CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-pb1200"
-CONFIG_KERNEL_LZMA=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_TINY_RCU=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_KALLSYMS is not set
-# CONFIG_PCSPKR_PLATFORM is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_COMPAT_BRK is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_LBDAF is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_PCCARD=y
-CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
-CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
-CONFIG_BINFMT_MISC=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_PLATFORM=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_UB=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECS=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_IDE_TASK_IOCTL=y
-# CONFIG_IDE_PROC_FS is not set
-CONFIG_BLK_DEV_IDE_AU1XXX=y
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_SMC91X=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_WLAN is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_VT_HW_CONSOLE_BINDING=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=2
-CONFIG_SERIAL_8250_RUNTIME_UARTS=2
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-# CONFIG_I2C_COMPAT is not set
-CONFIG_I2C_CHARDEV=y
-# CONFIG_I2C_HELPER_AUTO is not set
-CONFIG_I2C_AU1550=y
-CONFIG_SPI=y
-CONFIG_SPI_AU1550=y
-CONFIG_GPIOLIB=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_SENSORS_ADM1025=y
-CONFIG_SENSORS_LM70=y
-CONFIG_FB=y
-CONFIG_FB_AU1200=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x16=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_DYNAMIC_MINORS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
-# CONFIG_SND_VERBOSE_PROCFS is not set
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_SPI is not set
-# CONFIG_SND_MIPS is not set
-# CONFIG_SND_USB is not set
-# CONFIG_SND_PCMCIA is not set
-CONFIG_SND_SOC=y
-CONFIG_SND_SOC_AU1XPSC=y
-CONFIG_SND_SOC_DB1200=y
-CONFIG_HIDRAW=y
-CONFIG_USB_HIDDEV=y
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_DYNAMIC_MINORS=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_MMC=y
-# CONFIG_MMC_BLOCK_BOUNCE is not set
-CONFIG_MMC_AU1X=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AU1XXX=y
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-CONFIG_ZISOFS=y
-CONFIG_UDF_FS=y
-CONFIG_VFAT_FS=y
-# CONFIG_PROC_PAGE_MONITOR is not set
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_LZO=y
-CONFIG_JFFS2_RUBIN=y
-CONFIG_SQUASHFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_EFI_PARTITION=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_CODEPAGE_852=y
-CONFIG_NLS_CODEPAGE_1250=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_ISO8859_2=y
-CONFIG_NLS_ISO8859_15=y
-CONFIG_NLS_UTF8=y
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_STRIP_ASM_SYMS=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_FTRACE is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyS0,115200"
-CONFIG_DEBUG_ZBOOT=y
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
-CONFIG_SECURITYFS=y
index f7b7ba6d5c45f589951f301bca6f29bc1e8bacba..b874accd878a7cc33bfea390526e8f67340765de 100644 (file)
@@ -110,7 +110,6 @@ static struct irqaction fpuirq = {
 };
 
 static struct irqaction busirq = {
-       .flags = IRQF_DISABLED,
        .name = "bus error",
        .flags = IRQF_NO_THREAD,
 };
index 7897f05e316520ed5279e479eef15a4278a6afa9..f53f9ca73996de669ba0d500f7a8f78bfa13adcf 100644 (file)
@@ -1,3 +1,5 @@
 include include/asm-generic/Kbuild.asm
 
-header-y += cachectl.h sgidefs.h sysmips.h
+header-y += cachectl.h
+header-y += sgidefs.h
+header-y += sysmips.h
diff --git a/arch/mips/include/asm/bmips.h b/arch/mips/include/asm/bmips.h
new file mode 100644 (file)
index 0000000..552a65a
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2011 by Kevin Cernekee (cernekee@gmail.com)
+ *
+ * Definitions for BMIPS processors
+ */
+#ifndef _ASM_BMIPS_H
+#define _ASM_BMIPS_H
+
+#include <linux/compiler.h>
+#include <linux/linkage.h>
+#include <asm/addrspace.h>
+#include <asm/mipsregs.h>
+#include <asm/hazards.h>
+
+/* NOTE: the CBR register returns a PA, and it can be above 0xff00_0000 */
+#define BMIPS_GET_CBR()                        ((void __iomem *)(CKSEG1 | \
+                                        (unsigned long) \
+                                        ((read_c0_brcm_cbr() >> 18) << 18)))
+
+#define BMIPS_RAC_CONFIG               0x00000000
+#define BMIPS_RAC_ADDRESS_RANGE                0x00000004
+#define BMIPS_RAC_CONFIG_1             0x00000008
+#define BMIPS_L2_CONFIG                        0x0000000c
+#define BMIPS_LMB_CONTROL              0x0000001c
+#define BMIPS_SYSTEM_BASE              0x00000020
+#define BMIPS_PERF_GLOBAL_CONTROL      0x00020000
+#define BMIPS_PERF_CONTROL_0           0x00020004
+#define BMIPS_PERF_CONTROL_1           0x00020008
+#define BMIPS_PERF_COUNTER_0           0x00020010
+#define BMIPS_PERF_COUNTER_1           0x00020014
+#define BMIPS_PERF_COUNTER_2           0x00020018
+#define BMIPS_PERF_COUNTER_3           0x0002001c
+#define BMIPS_RELO_VECTOR_CONTROL_0    0x00030000
+#define BMIPS_RELO_VECTOR_CONTROL_1    0x00038000
+
+#define BMIPS_NMI_RESET_VEC            0x80000000
+#define BMIPS_WARM_RESTART_VEC         0x80000380
+
+#define ZSCM_REG_BASE                  0x97000000
+
+#if !defined(__ASSEMBLY__)
+
+#include <linux/cpumask.h>
+#include <asm/r4kcache.h>
+
+extern struct plat_smp_ops bmips_smp_ops;
+extern char bmips_reset_nmi_vec;
+extern char bmips_reset_nmi_vec_end;
+extern char bmips_smp_movevec;
+extern char bmips_smp_int_vec;
+extern char bmips_smp_int_vec_end;
+
+extern int bmips_smp_enabled;
+extern int bmips_cpu_offset;
+extern cpumask_t bmips_booted_mask;
+
+extern void bmips_ebase_setup(void);
+extern asmlinkage void plat_wired_tlb_setup(void);
+
+static inline unsigned long bmips_read_zscm_reg(unsigned int offset)
+{
+       unsigned long ret;
+
+       __asm__ __volatile__(
+               ".set push\n"
+               ".set noreorder\n"
+               "cache %1, 0(%2)\n"
+               "sync\n"
+               "_ssnop\n"
+               "_ssnop\n"
+               "_ssnop\n"
+               "_ssnop\n"
+               "_ssnop\n"
+               "_ssnop\n"
+               "_ssnop\n"
+               "mfc0 %0, $28, 3\n"
+               "_ssnop\n"
+               ".set pop\n"
+               : "=&r" (ret)
+               : "i" (Index_Load_Tag_S), "r" (ZSCM_REG_BASE + offset)
+               : "memory");
+       return ret;
+}
+
+static inline void bmips_write_zscm_reg(unsigned int offset, unsigned long data)
+{
+       __asm__ __volatile__(
+               ".set push\n"
+               ".set noreorder\n"
+               "mtc0 %0, $28, 3\n"
+               "_ssnop\n"
+               "_ssnop\n"
+               "_ssnop\n"
+               "cache %1, 0(%2)\n"
+               "_ssnop\n"
+               "_ssnop\n"
+               "_ssnop\n"
+               : /* no outputs */
+               : "r" (data),
+                 "i" (Index_Store_Tag_S), "r" (ZSCM_REG_BASE + offset)
+               : "memory");
+}
+
+#endif /* !defined(__ASSEMBLY__) */
+
+#endif /* _ASM_BMIPS_H */
index 35cd1bab69c3c23d81015da791d2e7609526d962..7a51d879e6ca2180c448812b9bc1591f3020f678 100644 (file)
@@ -86,6 +86,7 @@ extern unsigned long mips_machtype;
 #define BOOT_MEM_RAM           1
 #define BOOT_MEM_ROM_DATA      2
 #define BOOT_MEM_RESERVED      3
+#define BOOT_MEM_INIT_RAM      4
 
 /*
  * A memory map that's built upon what was determined
index 37c6857c8d4a322e3d4a9c68502b7a946ccb50e9..888766ae1f8598f1ff98373c6dbc7a6658307fc8 100644 (file)
@@ -9,6 +9,7 @@
 #define _ASM_BRANCH_H
 
 #include <asm/ptrace.h>
+#include <asm/inst.h>
 
 static inline int delay_slot(struct pt_regs *regs)
 {
@@ -23,7 +24,11 @@ static inline unsigned long exception_epc(struct pt_regs *regs)
        return regs->cp0_epc + 4;
 }
 
+#define BRANCH_LIKELY_TAKEN 0x0001
+
 extern int __compute_return_epc(struct pt_regs *regs);
+extern int __compute_return_epc_for_insn(struct pt_regs *regs,
+                                        union mips_instruction insn);
 
 static inline int compute_return_epc(struct pt_regs *regs)
 {
index 2f7f41873f242ef9abd77002976ebced8cbdea3c..f9fa2a479dd0e175ae7fc839d833b15695103f04 100644 (file)
 #define PRID_IMP_NETLOGIC_XLS412B      0x4c00
 #define PRID_IMP_NETLOGIC_XLS408B      0x4e00
 #define PRID_IMP_NETLOGIC_XLS404B      0x4f00
+#define PRID_IMP_NETLOGIC_AU13XX       0x8000
+
+#define PRID_IMP_NETLOGIC_XLP8XX       0x1000
+#define PRID_IMP_NETLOGIC_XLP3XX       0x1100
 
 /*
  * Definitions for 7:0 on legacy processors
@@ -263,7 +267,7 @@ enum cpu_type_enum {
         */
        CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
        CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS, CPU_CAVIUM_OCTEON2,
-       CPU_XLR,
+       CPU_XLR, CPU_XLP,
 
        CPU_LAST
 };
diff --git a/arch/mips/include/asm/gio_device.h b/arch/mips/include/asm/gio_device.h
new file mode 100644 (file)
index 0000000..5437c84
--- /dev/null
@@ -0,0 +1,56 @@
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+struct gio_device_id {
+       __u8 id;
+};
+
+struct gio_device {
+       struct device   dev;
+       struct resource resource;
+       unsigned int    irq;
+       unsigned int    slotno;
+
+       const char      *name;
+       struct gio_device_id id;
+       unsigned        id32:1;
+       unsigned        gio64:1;
+};
+#define to_gio_device(d) container_of(d, struct gio_device, dev)
+
+struct gio_driver {
+       const char    *name;
+       struct module *owner;
+       const struct gio_device_id *id_table;
+
+       int  (*probe)(struct gio_device *, const struct gio_device_id *);
+       void (*remove)(struct gio_device *);
+       int  (*suspend)(struct gio_device *, pm_message_t);
+       int  (*resume)(struct gio_device *);
+       void (*shutdown)(struct gio_device *);
+
+       struct device_driver driver;
+};
+#define to_gio_driver(drv) container_of(drv, struct gio_driver, driver)
+
+extern const struct gio_device_id *gio_match_device(const struct gio_device_id *,
+                                                   const struct gio_device *);
+extern struct gio_device *gio_dev_get(struct gio_device *);
+extern void gio_dev_put(struct gio_device *);
+
+extern int gio_device_register(struct gio_device *);
+extern void gio_device_unregister(struct gio_device *);
+extern void gio_release_dev(struct device *);
+
+static inline void gio_device_free(struct gio_device *dev)
+{
+       gio_release_dev(&dev->dev);
+}
+
+extern int gio_register_driver(struct gio_driver *);
+extern void gio_unregister_driver(struct gio_driver *);
+
+#define gio_get_drvdata(_dev)        drv_get_drvdata(&(_dev)->dev)
+#define gio_set_drvdata(_dev, data)  drv_set_drvdata(&(_dev)->dev, (data))
+
+extern void gio_set_master(struct gio_device *);
index 4e332165d7b710a8e4327c7d820c66883d12b89c..b4c20e4f87cd63f0718b785470478fdb74b5f8fd 100644 (file)
@@ -87,7 +87,8 @@ do {                                                                  \
        : "=r" (tmp));                                                  \
 } while (0)
 
-#elif defined(CONFIG_CPU_MIPSR1) && !defined(CONFIG_MIPS_ALCHEMY)
+#elif (defined(CONFIG_CPU_MIPSR1) && !defined(CONFIG_MIPS_ALCHEMY)) || \
+       defined(CONFIG_CPU_BMIPS)
 
 /*
  * These are slightly complicated by the fact that we guarantee R1 kernels to
@@ -139,8 +140,8 @@ do {                                                                        \
 } while (0)
 
 #elif defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_CPU_CAVIUM_OCTEON) || \
-      defined(CONFIG_CPU_LOONGSON2) || defined(CONFIG_CPU_R10000) || \
-      defined(CONFIG_CPU_R5500)
+       defined(CONFIG_CPU_LOONGSON2) || defined(CONFIG_CPU_R10000) || \
+       defined(CONFIG_CPU_R5500)
 
 /*
  * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
index c565b7c3f0b5b071833c751e4edddfb61aba84f4..58d36889f09b3c7e6af95106d1d6fd22c19f4f0d 100644 (file)
@@ -70,7 +70,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
 static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
                                         unsigned long addr, pte_t *ptep)
 {
-       flush_tlb_mm(vma->vm_mm);
+       flush_tlb_page(vma, addr & huge_page_mask(hstate_vma(vma)));
 }
 
 static inline int huge_pte_none(pte_t pte)
index e6ea4d4d720545c1746a575436aef03308d28b30..1fbbca01e681976027044e8697603ef28f224755 100644 (file)
@@ -74,6 +74,8 @@ struct prev_kprobe {
                : MAX_JPROBES_STACK_SIZE)
 
 
+#define SKIP_DELAYSLOT 0x0001
+
 /* per-cpu kprobe control block */
 struct kprobe_ctlblk {
        unsigned long kprobe_status;
@@ -82,6 +84,9 @@ struct kprobe_ctlblk {
        unsigned long kprobe_saved_epc;
        unsigned long jprobe_saved_sp;
        struct pt_regs jprobe_saved_regs;
+       /* Per-thread fields, used while emulating branches */
+       unsigned long flags;
+       unsigned long target_epc;
        u8 jprobes_stack[MAX_JPROBES_STACK_SIZE];
        struct prev_kprobe prev_kprobe;
 };
index cda1c8070b27a4c0aa6afeea96fe24474e5026ba..2f0becb4ec8f490283ce1c22e1af3ae44d05c0f7 100644 (file)
 #include <linux/bitops.h>
 
 #define AR71XX_APB_BASE                0x18000000
+#define AR71XX_EHCI_BASE       0x1b000000
+#define AR71XX_EHCI_SIZE       0x1000
+#define AR71XX_OHCI_BASE       0x1c000000
+#define AR71XX_OHCI_SIZE       0x1000
 #define AR71XX_SPI_BASE                0x1f000000
 #define AR71XX_SPI_SIZE                0x01000000
 
@@ -27,6 +31,8 @@
 #define AR71XX_DDR_CTRL_SIZE   0x100
 #define AR71XX_UART_BASE       (AR71XX_APB_BASE + 0x00020000)
 #define AR71XX_UART_SIZE       0x100
+#define AR71XX_USB_CTRL_BASE   (AR71XX_APB_BASE + 0x00030000)
+#define AR71XX_USB_CTRL_SIZE   0x100
 #define AR71XX_GPIO_BASE        (AR71XX_APB_BASE + 0x00040000)
 #define AR71XX_GPIO_SIZE        0x100
 #define AR71XX_PLL_BASE                (AR71XX_APB_BASE + 0x00050000)
 #define AR71XX_RESET_BASE      (AR71XX_APB_BASE + 0x00060000)
 #define AR71XX_RESET_SIZE      0x100
 
+#define AR7240_USB_CTRL_BASE   (AR71XX_APB_BASE + 0x00030000)
+#define AR7240_USB_CTRL_SIZE   0x100
+#define AR7240_OHCI_BASE       0x1b000000
+#define AR7240_OHCI_SIZE       0x1000
+
+#define AR724X_EHCI_BASE       0x1b000000
+#define AR724X_EHCI_SIZE       0x1000
+
+#define AR913X_EHCI_BASE       0x1b000000
+#define AR913X_EHCI_SIZE       0x1000
 #define AR913X_WMAC_BASE       (AR71XX_APB_BASE + 0x000C0000)
 #define AR913X_WMAC_SIZE       0x30000
 
+#define AR933X_UART_BASE       (AR71XX_APB_BASE + 0x00020000)
+#define AR933X_UART_SIZE       0x14
+#define AR933X_WMAC_BASE       (AR71XX_APB_BASE + 0x00100000)
+#define AR933X_WMAC_SIZE       0x20000
+#define AR933X_EHCI_BASE       0x1b000000
+#define AR933X_EHCI_SIZE       0x1000
+
 /*
  * DDR_CTRL block
  */
 #define AR913X_DDR_REG_FLUSH_USB       0x84
 #define AR913X_DDR_REG_FLUSH_WMAC      0x88
 
+#define AR933X_DDR_REG_FLUSH_GE0       0x7c
+#define AR933X_DDR_REG_FLUSH_GE1       0x80
+#define AR933X_DDR_REG_FLUSH_USB       0x84
+#define AR933X_DDR_REG_FLUSH_WMAC      0x88
+
 /*
  * PLL block
  */
 #define AR913X_AHB_DIV_SHIFT           19
 #define AR913X_AHB_DIV_MASK            0x1
 
+#define AR933X_PLL_CPU_CONFIG_REG      0x00
+#define AR933X_PLL_CLOCK_CTRL_REG      0x08
+
+#define AR933X_PLL_CPU_CONFIG_NINT_SHIFT       10
+#define AR933X_PLL_CPU_CONFIG_NINT_MASK                0x3f
+#define AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT     16
+#define AR933X_PLL_CPU_CONFIG_REFDIV_MASK      0x1f
+#define AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT     23
+#define AR933X_PLL_CPU_CONFIG_OUTDIV_MASK      0x7
+
+#define AR933X_PLL_CLOCK_CTRL_BYPASS           BIT(2)
+#define AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT    5
+#define AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK     0x3
+#define AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT    10
+#define AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK     0x3
+#define AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT    15
+#define AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK     0x7
+
+/*
+ * USB_CONFIG block
+ */
+#define AR71XX_USB_CTRL_REG_FLADJ      0x00
+#define AR71XX_USB_CTRL_REG_CONFIG     0x04
+
 /*
  * RESET block
  */
 
 #define AR724X_RESET_REG_RESET_MODULE          0x1c
 
+#define AR933X_RESET_REG_RESET_MODULE          0x1c
+#define AR933X_RESET_REG_BOOTSTRAP             0xac
+
+#define MISC_INT_ETHSW                 BIT(12)
+#define MISC_INT_TIMER4                        BIT(10)
+#define MISC_INT_TIMER3                        BIT(9)
+#define MISC_INT_TIMER2                        BIT(8)
 #define MISC_INT_DMA                   BIT(7)
 #define MISC_INT_OHCI                  BIT(6)
 #define MISC_INT_PERFC                 BIT(5)
 #define AR71XX_RESET_PCI_BUS           BIT(1)
 #define AR71XX_RESET_PCI_CORE          BIT(0)
 
+#define AR7240_RESET_USB_HOST          BIT(5)
+#define AR7240_RESET_OHCI_DLL          BIT(3)
+
 #define AR724X_RESET_GE1_MDIO          BIT(23)
 #define AR724X_RESET_GE0_MDIO          BIT(22)
 #define AR724X_RESET_PCIE_PHY_SERIAL   BIT(10)
 #define AR724X_RESET_PCIE_PHY          BIT(7)
 #define AR724X_RESET_PCIE              BIT(6)
-#define AR724X_RESET_OHCI_DLL          BIT(3)
+#define AR724X_RESET_USB_HOST          BIT(5)
+#define AR724X_RESET_USB_PHY           BIT(4)
+#define AR724X_RESET_USBSUS_OVERRIDE   BIT(3)
 
 #define AR913X_RESET_AMBA2WMAC         BIT(22)
+#define AR913X_RESET_USBSUS_OVERRIDE   BIT(10)
+#define AR913X_RESET_USB_HOST          BIT(5)
+#define AR913X_RESET_USB_PHY           BIT(4)
+
+#define AR933X_RESET_WMAC              BIT(11)
+#define AR933X_RESET_USB_HOST          BIT(5)
+#define AR933X_RESET_USB_PHY           BIT(4)
+#define AR933X_RESET_USBSUS_OVERRIDE   BIT(3)
+
+#define AR933X_BOOTSTRAP_REF_CLK_40    BIT(0)
 
 #define REV_ID_MAJOR_MASK              0xfff0
 #define REV_ID_MAJOR_AR71XX            0x00a0
 #define REV_ID_MAJOR_AR7240            0x00c0
 #define REV_ID_MAJOR_AR7241            0x0100
 #define REV_ID_MAJOR_AR7242            0x1100
+#define REV_ID_MAJOR_AR9330            0x0110
+#define REV_ID_MAJOR_AR9331            0x1110
 
 #define AR71XX_REV_ID_MINOR_MASK       0x3
 #define AR71XX_REV_ID_MINOR_AR7130     0x0
 #define AR913X_REV_ID_REVISION_MASK    0x3
 #define AR913X_REV_ID_REVISION_SHIFT   2
 
+#define AR933X_REV_ID_REVISION_MASK    0x3
+
 #define AR724X_REV_ID_REVISION_MASK    0x3
 
 /*
 #define AR71XX_GPIO_COUNT              16
 #define AR724X_GPIO_COUNT              18
 #define AR913X_GPIO_COUNT              22
+#define AR933X_GPIO_COUNT              30
 
 #endif /* __ASM_MACH_AR71XX_REGS_H */
diff --git a/arch/mips/include/asm/mach-ath79/ar933x_uart.h b/arch/mips/include/asm/mach-ath79/ar933x_uart.h
new file mode 100644 (file)
index 0000000..5273055
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  Atheros AR933X UART defines
+ *
+ *  Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+
+#ifndef __AR933X_UART_H
+#define __AR933X_UART_H
+
+#define AR933X_UART_REGS_SIZE          20
+#define AR933X_UART_FIFO_SIZE          16
+
+#define AR933X_UART_DATA_REG           0x00
+#define AR933X_UART_CS_REG             0x04
+#define AR933X_UART_CLOCK_REG          0x08
+#define AR933X_UART_INT_REG            0x0c
+#define AR933X_UART_INT_EN_REG         0x10
+
+#define AR933X_UART_DATA_TX_RX_MASK    0xff
+#define AR933X_UART_DATA_RX_CSR                BIT(8)
+#define AR933X_UART_DATA_TX_CSR                BIT(9)
+
+#define AR933X_UART_CS_PARITY_S                0
+#define AR933X_UART_CS_PARITY_M                0x3
+#define   AR933X_UART_CS_PARITY_NONE   0
+#define   AR933X_UART_CS_PARITY_ODD    1
+#define   AR933X_UART_CS_PARITY_EVEN   2
+#define AR933X_UART_CS_IF_MODE_S       2
+#define AR933X_UART_CS_IF_MODE_M       0x3
+#define   AR933X_UART_CS_IF_MODE_NONE  0
+#define   AR933X_UART_CS_IF_MODE_DTE   1
+#define   AR933X_UART_CS_IF_MODE_DCE   2
+#define AR933X_UART_CS_FLOW_CTRL_S     4
+#define AR933X_UART_CS_FLOW_CTRL_M     0x3
+#define AR933X_UART_CS_DMA_EN          BIT(6)
+#define AR933X_UART_CS_TX_READY_ORIDE  BIT(7)
+#define AR933X_UART_CS_RX_READY_ORIDE  BIT(8)
+#define AR933X_UART_CS_TX_READY                BIT(9)
+#define AR933X_UART_CS_RX_BREAK                BIT(10)
+#define AR933X_UART_CS_TX_BREAK                BIT(11)
+#define AR933X_UART_CS_HOST_INT                BIT(12)
+#define AR933X_UART_CS_HOST_INT_EN     BIT(13)
+#define AR933X_UART_CS_TX_BUSY         BIT(14)
+#define AR933X_UART_CS_RX_BUSY         BIT(15)
+
+#define AR933X_UART_CLOCK_STEP_M       0xffff
+#define AR933X_UART_CLOCK_SCALE_M      0xfff
+#define AR933X_UART_CLOCK_SCALE_S      16
+#define AR933X_UART_CLOCK_STEP_M       0xffff
+
+#define AR933X_UART_INT_RX_VALID       BIT(0)
+#define AR933X_UART_INT_TX_READY       BIT(1)
+#define AR933X_UART_INT_RX_FRAMING_ERR BIT(2)
+#define AR933X_UART_INT_RX_OFLOW_ERR   BIT(3)
+#define AR933X_UART_INT_TX_OFLOW_ERR   BIT(4)
+#define AR933X_UART_INT_RX_PARITY_ERR  BIT(5)
+#define AR933X_UART_INT_RX_BREAK_ON    BIT(6)
+#define AR933X_UART_INT_RX_BREAK_OFF   BIT(7)
+#define AR933X_UART_INT_RX_FULL                BIT(8)
+#define AR933X_UART_INT_TX_EMPTY       BIT(9)
+#define AR933X_UART_INT_ALLINTS                0x3ff
+
+#endif /* __AR933X_UART_H */
diff --git a/arch/mips/include/asm/mach-ath79/ar933x_uart_platform.h b/arch/mips/include/asm/mach-ath79/ar933x_uart_platform.h
new file mode 100644 (file)
index 0000000..6cb30f2
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ *  Platform data definition for Atheros AR933X UART
+ *
+ *  Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+
+#ifndef _AR933X_UART_PLATFORM_H
+#define _AR933X_UART_PLATFORM_H
+
+struct ar933x_uart_platform_data {
+       unsigned        uartclk;
+};
+
+#endif /* _AR933X_UART_PLATFORM_H */
index 6a9f168506fe061cb85f517c04e4605cc9f54208..6d0c6c9d5622fbe7890add97b200e4e6ced76d02 100644 (file)
@@ -26,10 +26,13 @@ enum ath79_soc_type {
        ATH79_SOC_AR7241,
        ATH79_SOC_AR7242,
        ATH79_SOC_AR9130,
-       ATH79_SOC_AR9132
+       ATH79_SOC_AR9132,
+       ATH79_SOC_AR9330,
+       ATH79_SOC_AR9331,
 };
 
 extern enum ath79_soc_type ath79_soc;
+extern unsigned int ath79_soc_rev;
 
 static inline int soc_is_ar71xx(void)
 {
@@ -66,6 +69,12 @@ static inline int soc_is_ar913x(void)
                ath79_soc == ATH79_SOC_AR9132);
 }
 
+static inline int soc_is_ar933x(void)
+{
+       return (ath79_soc == ATH79_SOC_AR9330 ||
+               ath79_soc == ATH79_SOC_AR9331);
+}
+
 extern void __iomem *ath79_ddr_base;
 extern void __iomem *ath79_pll_base;
 extern void __iomem *ath79_reset_base;
index 189bc6eb9c10d1884fe51c3d22da31272d3ca04a..519958fe4e3c7d0532c6b639148e9aa2b9522e74 100644 (file)
 #define __ASM_MACH_ATH79_IRQ_H
 
 #define MIPS_CPU_IRQ_BASE      0
-#define NR_IRQS                        16
+#define NR_IRQS                        40
 
 #define ATH79_MISC_IRQ_BASE    8
-#define ATH79_MISC_IRQ_COUNT   8
+#define ATH79_MISC_IRQ_COUNT   32
 
 #define ATH79_CPU_IRQ_IP2      (MIPS_CPU_IRQ_BASE + 2)
 #define ATH79_CPU_IRQ_USB      (MIPS_CPU_IRQ_BASE + 3)
 #define ATH79_MISC_IRQ_PERFC   (ATH79_MISC_IRQ_BASE + 5)
 #define ATH79_MISC_IRQ_OHCI    (ATH79_MISC_IRQ_BASE + 6)
 #define ATH79_MISC_IRQ_DMA     (ATH79_MISC_IRQ_BASE + 7)
+#define ATH79_MISC_IRQ_TIMER2  (ATH79_MISC_IRQ_BASE + 8)
+#define ATH79_MISC_IRQ_TIMER3  (ATH79_MISC_IRQ_BASE + 9)
+#define ATH79_MISC_IRQ_TIMER4  (ATH79_MISC_IRQ_BASE + 10)
+#define ATH79_MISC_IRQ_ETHSW   (ATH79_MISC_IRQ_BASE + 12)
 
 #include_next <irq.h>
 
diff --git a/arch/mips/include/asm/mach-ath79/pci-ath724x.h b/arch/mips/include/asm/mach-ath79/pci-ath724x.h
new file mode 100644 (file)
index 0000000..454885f
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ *  Atheros 724x PCI support
+ *
+ *  Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+
+#ifndef __ASM_MACH_ATH79_PCI_ATH724X_H
+#define __ASM_MACH_ATH79_PCI_ATH724X_H
+
+struct ath724x_pci_data {
+       int irq;
+       void *pdata;
+};
+
+void ath724x_pci_add_data(struct ath724x_pci_data *data, int size);
+
+#endif /* __ASM_MACH_ATH79_PCI_ATH724X_H */
index de24ec57dd2f6181200caa0be4136c45c1066748..569828d3ccab48a9581743542849e0931044792e 100644 (file)
@@ -136,6 +136,7 @@ static inline int au1xxx_cpu_needs_config_od(void)
 #define ALCHEMY_CPU_AU1100     2
 #define ALCHEMY_CPU_AU1550     3
 #define ALCHEMY_CPU_AU1200     4
+#define ALCHEMY_CPU_AU1300     5
 
 static inline int alchemy_get_cputype(void)
 {
@@ -156,6 +157,9 @@ static inline int alchemy_get_cputype(void)
        case 0x05030000:
                return ALCHEMY_CPU_AU1200;
                break;
+       case 0x800c0000:
+               return ALCHEMY_CPU_AU1300;
+               break;
        }
 
        return ALCHEMY_CPU_UNKNOWN;
@@ -166,6 +170,7 @@ static inline int alchemy_get_uarts(int type)
 {
        switch (type) {
        case ALCHEMY_CPU_AU1000:
+       case ALCHEMY_CPU_AU1300:
                return 4;
        case ALCHEMY_CPU_AU1500:
        case ALCHEMY_CPU_AU1200:
@@ -243,6 +248,7 @@ extern unsigned long au1xxx_calc_clock(void);
 /* PM: arch/mips/alchemy/common/sleeper.S, power.c, irq.c */
 void alchemy_sleep_au1000(void);
 void alchemy_sleep_au1550(void);
+void alchemy_sleep_au1300(void);
 void au_sleep(void);
 
 /* USB: drivers/usb/host/alchemy-common.c */
@@ -251,6 +257,7 @@ enum alchemy_usb_block {
        ALCHEMY_USB_UDC0,
        ALCHEMY_USB_EHCI0,
        ALCHEMY_USB_OTG0,
+       ALCHEMY_USB_OHCI1,
 };
 int alchemy_usb_control(int block, int enable);
 
@@ -263,14 +270,92 @@ struct alchemy_pci_platdata {
        unsigned long pci_cfg_clr;
 };
 
-/* SOC Interrupt numbers */
+/* Multifunction pins: Each of these pins can either be assigned to the
+ * GPIO controller or a on-chip peripheral.
+ * Call "au1300_pinfunc_to_dev()" or "au1300_pinfunc_to_gpio()" to
+ * assign one of these to either the GPIO controller or the device.
+ */
+enum au1300_multifunc_pins {
+       /* wake-from-str pins 0-3 */
+       AU1300_PIN_WAKE0 = 0, AU1300_PIN_WAKE1, AU1300_PIN_WAKE2,
+       AU1300_PIN_WAKE3,
+       /* external clock sources for PSCs: 4-5 */
+       AU1300_PIN_EXTCLK0, AU1300_PIN_EXTCLK1,
+       /* 8bit MMC interface on SD0: 6-9 */
+       AU1300_PIN_SD0DAT4, AU1300_PIN_SD0DAT5, AU1300_PIN_SD0DAT6,
+       AU1300_PIN_SD0DAT7,
+       /* aux clk input for freqgen 3: 10 */
+       AU1300_PIN_FG3AUX,
+       /* UART1 pins: 11-18 */
+       AU1300_PIN_U1RI, AU1300_PIN_U1DCD, AU1300_PIN_U1DSR,
+       AU1300_PIN_U1CTS, AU1300_PIN_U1RTS, AU1300_PIN_U1DTR,
+       AU1300_PIN_U1RX, AU1300_PIN_U1TX,
+       /* UART0 pins: 19-24 */
+       AU1300_PIN_U0RI, AU1300_PIN_U0DCD, AU1300_PIN_U0DSR,
+       AU1300_PIN_U0CTS, AU1300_PIN_U0RTS, AU1300_PIN_U0DTR,
+       /* UART2: 25-26 */
+       AU1300_PIN_U2RX, AU1300_PIN_U2TX,
+       /* UART3: 27-28 */
+       AU1300_PIN_U3RX, AU1300_PIN_U3TX,
+       /* LCD controller PWMs, ext pixclock: 29-31 */
+       AU1300_PIN_LCDPWM0, AU1300_PIN_LCDPWM1, AU1300_PIN_LCDCLKIN,
+       /* SD1 interface: 32-37 */
+       AU1300_PIN_SD1DAT0, AU1300_PIN_SD1DAT1, AU1300_PIN_SD1DAT2,
+       AU1300_PIN_SD1DAT3, AU1300_PIN_SD1CMD, AU1300_PIN_SD1CLK,
+       /* SD2 interface: 38-43 */
+       AU1300_PIN_SD2DAT0, AU1300_PIN_SD2DAT1, AU1300_PIN_SD2DAT2,
+       AU1300_PIN_SD2DAT3, AU1300_PIN_SD2CMD, AU1300_PIN_SD2CLK,
+       /* PSC0/1 clocks: 44-45 */
+       AU1300_PIN_PSC0CLK, AU1300_PIN_PSC1CLK,
+       /* PSCs: 46-49/50-53/54-57/58-61 */
+       AU1300_PIN_PSC0SYNC0, AU1300_PIN_PSC0SYNC1, AU1300_PIN_PSC0D0,
+       AU1300_PIN_PSC0D1,
+       AU1300_PIN_PSC1SYNC0, AU1300_PIN_PSC1SYNC1, AU1300_PIN_PSC1D0,
+       AU1300_PIN_PSC1D1,
+       AU1300_PIN_PSC2SYNC0, AU1300_PIN_PSC2SYNC1, AU1300_PIN_PSC2D0,
+       AU1300_PIN_PSC2D1,
+       AU1300_PIN_PSC3SYNC0, AU1300_PIN_PSC3SYNC1, AU1300_PIN_PSC3D0,
+       AU1300_PIN_PSC3D1,
+       /* PCMCIA interface: 62-70 */
+       AU1300_PIN_PCE2, AU1300_PIN_PCE1, AU1300_PIN_PIOS16,
+       AU1300_PIN_PIOR, AU1300_PIN_PWE, AU1300_PIN_PWAIT,
+       AU1300_PIN_PREG, AU1300_PIN_POE, AU1300_PIN_PIOW,
+       /* camera interface H/V sync inputs: 71-72 */
+       AU1300_PIN_CIMLS, AU1300_PIN_CIMFS,
+       /* PSC2/3 clocks: 73-74 */
+       AU1300_PIN_PSC2CLK, AU1300_PIN_PSC3CLK,
+};
+
+/* GPIC (Au1300) pin management: arch/mips/alchemy/common/gpioint.c */
+extern void au1300_pinfunc_to_gpio(enum au1300_multifunc_pins gpio);
+extern void au1300_pinfunc_to_dev(enum au1300_multifunc_pins gpio);
+extern void au1300_set_irq_priority(unsigned int irq, int p);
+extern void au1300_set_dbdma_gpio(int dchan, unsigned int gpio);
+
+/* Au1300 allows to disconnect certain blocks from internal power supply */
+enum au1300_vss_block {
+       AU1300_VSS_MPE = 0,
+       AU1300_VSS_BSA,
+       AU1300_VSS_GPE,
+       AU1300_VSS_MGP,
+};
 
+extern void au1300_vss_block_control(int block, int enable);
+
+
+/* SOC Interrupt numbers */
+/* Au1000-style (IC0/1): 2 controllers with 32 sources each */
 #define AU1000_INTC0_INT_BASE  (MIPS_CPU_IRQ_BASE + 8)
 #define AU1000_INTC0_INT_LAST  (AU1000_INTC0_INT_BASE + 31)
 #define AU1000_INTC1_INT_BASE  (AU1000_INTC0_INT_LAST + 1)
 #define AU1000_INTC1_INT_LAST  (AU1000_INTC1_INT_BASE + 31)
 #define AU1000_MAX_INTR        AU1000_INTC1_INT_LAST
 
+/* Au1300-style (GPIC): 1 controller with up to 128 sources */
+#define ALCHEMY_GPIC_INT_BASE  (MIPS_CPU_IRQ_BASE + 8)
+#define ALCHEMY_GPIC_INT_NUM   128
+#define ALCHEMY_GPIC_INT_LAST  (ALCHEMY_GPIC_INT_BASE + ALCHEMY_GPIC_INT_NUM - 1)
+
 enum soc_au1000_ints {
        AU1000_FIRST_INT        = AU1000_INTC0_INT_BASE,
        AU1000_UART0_INT        = AU1000_FIRST_INT,
@@ -591,24 +676,77 @@ enum soc_au1200_ints {
 
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
 
+/* Au1300 peripheral interrupt numbers */
+#define AU1300_FIRST_INT       (ALCHEMY_GPIC_INT_BASE)
+#define AU1300_UART1_INT       (AU1300_FIRST_INT + 17)
+#define AU1300_UART2_INT       (AU1300_FIRST_INT + 25)
+#define AU1300_UART3_INT       (AU1300_FIRST_INT + 27)
+#define AU1300_SD1_INT         (AU1300_FIRST_INT + 32)
+#define AU1300_SD2_INT         (AU1300_FIRST_INT + 38)
+#define AU1300_PSC0_INT                (AU1300_FIRST_INT + 48)
+#define AU1300_PSC1_INT                (AU1300_FIRST_INT + 52)
+#define AU1300_PSC2_INT                (AU1300_FIRST_INT + 56)
+#define AU1300_PSC3_INT                (AU1300_FIRST_INT + 60)
+#define AU1300_NAND_INT                (AU1300_FIRST_INT + 62)
+#define AU1300_DDMA_INT                (AU1300_FIRST_INT + 75)
+#define AU1300_MMU_INT         (AU1300_FIRST_INT + 76)
+#define AU1300_MPU_INT         (AU1300_FIRST_INT + 77)
+#define AU1300_GPU_INT         (AU1300_FIRST_INT + 78)
+#define AU1300_UDMA_INT                (AU1300_FIRST_INT + 79)
+#define AU1300_TOY_INT         (AU1300_FIRST_INT + 80)
+#define AU1300_TOY_MATCH0_INT  (AU1300_FIRST_INT + 81)
+#define AU1300_TOY_MATCH1_INT  (AU1300_FIRST_INT + 82)
+#define AU1300_TOY_MATCH2_INT  (AU1300_FIRST_INT + 83)
+#define AU1300_RTC_INT         (AU1300_FIRST_INT + 84)
+#define AU1300_RTC_MATCH0_INT  (AU1300_FIRST_INT + 85)
+#define AU1300_RTC_MATCH1_INT  (AU1300_FIRST_INT + 86)
+#define AU1300_RTC_MATCH2_INT  (AU1300_FIRST_INT + 87)
+#define AU1300_UART0_INT       (AU1300_FIRST_INT + 88)
+#define AU1300_SD0_INT         (AU1300_FIRST_INT + 89)
+#define AU1300_USB_INT         (AU1300_FIRST_INT + 90)
+#define AU1300_LCD_INT         (AU1300_FIRST_INT + 91)
+#define AU1300_BSA_INT         (AU1300_FIRST_INT + 92)
+#define AU1300_MPE_INT         (AU1300_FIRST_INT + 93)
+#define AU1300_ITE_INT         (AU1300_FIRST_INT + 94)
+#define AU1300_AES_INT         (AU1300_FIRST_INT + 95)
+#define AU1300_CIM_INT         (AU1300_FIRST_INT + 96)
+
+/**********************************************************************/
+
 /*
  * Physical base addresses for integrated peripherals
- * 0..au1000 1..au1500 2..au1100 3..au1550 4..au1200
+ * 0..au1000 1..au1500 2..au1100 3..au1550 4..au1200 5..au1300
  */
 
 #define AU1000_AC97_PHYS_ADDR          0x10000000 /* 012 */
+#define AU1300_ROM_PHYS_ADDR           0x10000000 /* 5 */
+#define AU1300_OTP_PHYS_ADDR           0x10002000 /* 5 */
+#define AU1300_VSS_PHYS_ADDR           0x10003000 /* 5 */
+#define AU1300_UART0_PHYS_ADDR         0x10100000 /* 5 */
+#define AU1300_UART1_PHYS_ADDR         0x10101000 /* 5 */
+#define AU1300_UART2_PHYS_ADDR         0x10102000 /* 5 */
+#define AU1300_UART3_PHYS_ADDR         0x10103000 /* 5 */
 #define AU1000_USB_OHCI_PHYS_ADDR      0x10100000 /* 012 */
 #define AU1000_USB_UDC_PHYS_ADDR       0x10200000 /* 0123 */
+#define AU1300_GPIC_PHYS_ADDR          0x10200000 /* 5 */
 #define AU1000_IRDA_PHYS_ADDR          0x10300000 /* 02 */
-#define AU1200_AES_PHYS_ADDR           0x10300000 /* 4 */
+#define AU1200_AES_PHYS_ADDR           0x10300000 /* 45 */
 #define AU1000_IC0_PHYS_ADDR           0x10400000 /* 01234 */
+#define AU1300_GPU_PHYS_ADDR           0x10500000 /* 5 */
 #define AU1000_MAC0_PHYS_ADDR          0x10500000 /* 023 */
 #define AU1000_MAC1_PHYS_ADDR          0x10510000 /* 023 */
 #define AU1000_MACEN_PHYS_ADDR         0x10520000 /* 023 */
-#define AU1100_SD0_PHYS_ADDR           0x10600000 /* 24 */
+#define AU1100_SD0_PHYS_ADDR           0x10600000 /* 245 */
+#define AU1300_SD1_PHYS_ADDR           0x10601000 /* 5 */
+#define AU1300_SD2_PHYS_ADDR           0x10602000 /* 5 */
 #define AU1100_SD1_PHYS_ADDR           0x10680000 /* 24 */
+#define AU1300_SYS_PHYS_ADDR           0x10900000 /* 5 */
 #define AU1550_PSC2_PHYS_ADDR          0x10A00000 /* 3 */
 #define AU1550_PSC3_PHYS_ADDR          0x10B00000 /* 3 */
+#define AU1300_PSC0_PHYS_ADDR          0x10A00000 /* 5 */
+#define AU1300_PSC1_PHYS_ADDR          0x10A01000 /* 5 */
+#define AU1300_PSC2_PHYS_ADDR          0x10A02000 /* 5 */
+#define AU1300_PSC3_PHYS_ADDR          0x10A03000 /* 5 */
 #define AU1000_I2S_PHYS_ADDR           0x11000000 /* 02 */
 #define AU1500_MAC0_PHYS_ADDR          0x11500000 /* 1 */
 #define AU1500_MAC1_PHYS_ADDR          0x11510000 /* 1 */
@@ -622,37 +760,96 @@ enum soc_au1200_ints {
 #define AU1000_SSI1_PHYS_ADDR          0x11680000 /* 02 */
 #define AU1500_GPIO2_PHYS_ADDR         0x11700000 /* 1234 */
 #define AU1000_IC1_PHYS_ADDR           0x11800000 /* 01234 */
-#define AU1000_SYS_PHYS_ADDR           0x11900000 /* 01234 */
+#define AU1000_SYS_PHYS_ADDR           0x11900000 /* 012345 */
 #define AU1550_PSC0_PHYS_ADDR          0x11A00000 /* 34 */
 #define AU1550_PSC1_PHYS_ADDR          0x11B00000 /* 34 */
 #define AU1000_MEM_PHYS_ADDR           0x14000000 /* 01234 */
 #define AU1000_STATIC_MEM_PHYS_ADDR    0x14001000 /* 01234 */
+#define AU1300_UDMA_PHYS_ADDR          0x14001800 /* 5 */
 #define AU1000_DMA_PHYS_ADDR           0x14002000 /* 012 */
-#define AU1550_DBDMA_PHYS_ADDR         0x14002000 /* 34 */
-#define AU1550_DBDMA_CONF_PHYS_ADDR    0x14003000 /* 34 */
+#define AU1550_DBDMA_PHYS_ADDR         0x14002000 /* 345 */
+#define AU1550_DBDMA_CONF_PHYS_ADDR    0x14003000 /* 345 */
 #define AU1000_MACDMA0_PHYS_ADDR       0x14004000 /* 0123 */
 #define AU1000_MACDMA1_PHYS_ADDR       0x14004200 /* 0123 */
-#define AU1200_CIM_PHYS_ADDR           0x14004000 /* 4 */
+#define AU1200_CIM_PHYS_ADDR           0x14004000 /* 45 */
 #define AU1500_PCI_PHYS_ADDR           0x14005000 /* 13 */
 #define AU1550_PE_PHYS_ADDR            0x14008000 /* 3 */
 #define AU1200_MAEBE_PHYS_ADDR         0x14010000 /* 4 */
 #define AU1200_MAEFE_PHYS_ADDR         0x14012000 /* 4 */
+#define AU1300_MAEITE_PHYS_ADDR                0x14010000 /* 5 */
+#define AU1300_MAEMPE_PHYS_ADDR                0x14014000 /* 5 */
 #define AU1550_USB_OHCI_PHYS_ADDR      0x14020000 /* 3 */
 #define AU1200_USB_CTL_PHYS_ADDR       0x14020000 /* 4 */
 #define AU1200_USB_OTG_PHYS_ADDR       0x14020020 /* 4 */
 #define AU1200_USB_OHCI_PHYS_ADDR      0x14020100 /* 4 */
 #define AU1200_USB_EHCI_PHYS_ADDR      0x14020200 /* 4 */
 #define AU1200_USB_UDC_PHYS_ADDR       0x14022000 /* 4 */
+#define AU1300_USB_EHCI_PHYS_ADDR      0x14020000 /* 5 */
+#define AU1300_USB_OHCI0_PHYS_ADDR     0x14020400 /* 5 */
+#define AU1300_USB_OHCI1_PHYS_ADDR     0x14020800 /* 5 */
+#define AU1300_USB_CTL_PHYS_ADDR       0x14021000 /* 5 */
+#define AU1300_USB_OTG_PHYS_ADDR       0x14022000 /* 5 */
+#define AU1300_MAEBSA_PHYS_ADDR                0x14030000 /* 5 */
 #define AU1100_LCD_PHYS_ADDR           0x15000000 /* 2 */
-#define AU1200_LCD_PHYS_ADDR           0x15000000 /* 4 */
+#define AU1200_LCD_PHYS_ADDR           0x15000000 /* 45 */
 #define AU1500_PCI_MEM_PHYS_ADDR       0x400000000ULL /* 13 */
 #define AU1500_PCI_IO_PHYS_ADDR                0x500000000ULL /* 13 */
 #define AU1500_PCI_CONFIG0_PHYS_ADDR   0x600000000ULL /* 13 */
 #define AU1500_PCI_CONFIG1_PHYS_ADDR   0x680000000ULL /* 13 */
-#define AU1000_PCMCIA_IO_PHYS_ADDR     0xF00000000ULL /* 01234 */
-#define AU1000_PCMCIA_ATTR_PHYS_ADDR   0xF40000000ULL /* 01234 */
-#define AU1000_PCMCIA_MEM_PHYS_ADDR    0xF80000000ULL /* 01234 */
+#define AU1000_PCMCIA_IO_PHYS_ADDR     0xF00000000ULL /* 012345 */
+#define AU1000_PCMCIA_ATTR_PHYS_ADDR   0xF40000000ULL /* 012345 */
+#define AU1000_PCMCIA_MEM_PHYS_ADDR    0xF80000000ULL /* 012345 */
 
+/**********************************************************************/
+
+
+/*
+ * Au1300 GPIO+INT controller (GPIC) register offsets and bits
+ * Registers are 128bits (0x10 bytes), divided into 4 "banks".
+ */
+#define AU1300_GPIC_PINVAL     0x0000
+#define AU1300_GPIC_PINVALCLR  0x0010
+#define AU1300_GPIC_IPEND      0x0020
+#define AU1300_GPIC_PRIENC     0x0030
+#define AU1300_GPIC_IEN                0x0040  /* int_mask in manual */
+#define AU1300_GPIC_IDIS       0x0050  /* int_maskclr in manual */
+#define AU1300_GPIC_DMASEL     0x0060
+#define AU1300_GPIC_DEVSEL     0x0080
+#define AU1300_GPIC_DEVCLR     0x0090
+#define AU1300_GPIC_RSTVAL     0x00a0
+/* pin configuration space. one 32bit register for up to 128 IRQs */
+#define AU1300_GPIC_PINCFG     0x1000
+
+#define GPIC_GPIO_TO_BIT(gpio) \
+       (1 << ((gpio) & 0x1f))
+
+#define GPIC_GPIO_BANKOFF(gpio)        \
+       (((gpio) >> 5) * 4)
+
+/* Pin Control bits: who owns the pin, what does it do */
+#define GPIC_CFG_PC_GPIN               0
+#define GPIC_CFG_PC_DEV                        1
+#define GPIC_CFG_PC_GPOLOW             2
+#define GPIC_CFG_PC_GPOHIGH            3
+#define GPIC_CFG_PC_MASK               3
+
+/* assign pin to MIPS IRQ line */
+#define GPIC_CFG_IL_SET(x)     (((x) & 3) << 2)
+#define GPIC_CFG_IL_MASK       (3 << 2)
+
+/* pin interrupt type setup */
+#define GPIC_CFG_IC_OFF                (0 << 4)
+#define GPIC_CFG_IC_LEVEL_LOW  (1 << 4)
+#define GPIC_CFG_IC_LEVEL_HIGH (2 << 4)
+#define GPIC_CFG_IC_EDGE_FALL  (5 << 4)
+#define GPIC_CFG_IC_EDGE_RISE  (6 << 4)
+#define GPIC_CFG_IC_EDGE_BOTH  (7 << 4)
+#define GPIC_CFG_IC_MASK       (7 << 4)
+
+/* allow interrupt to wake cpu from 'wait' */
+#define GPIC_CFG_IDLEWAKE      (1 << 7)
+
+/***********************************************************************/
 
 /* Au1000 SDRAM memory controller register offsets */
 #define AU1000_MEM_SDMODE0             0x0000
@@ -1068,44 +1265,20 @@ enum soc_au1200_ints {
 #define SSI_ENABLE_CD          (1 << 1)
 #define SSI_ENABLE_E           (1 << 0)
 
-/* IrDA Controller */
-#define IRDA_BASE              0xB0300000
-#define IR_RING_PTR_STATUS     (IRDA_BASE + 0x00)
-#define IR_RING_BASE_ADDR_H    (IRDA_BASE + 0x04)
-#define IR_RING_BASE_ADDR_L    (IRDA_BASE + 0x08)
-#define IR_RING_SIZE           (IRDA_BASE + 0x0C)
-#define IR_RING_PROMPT         (IRDA_BASE + 0x10)
-#define IR_RING_ADDR_CMPR      (IRDA_BASE + 0x14)
-#define IR_INT_CLEAR           (IRDA_BASE + 0x18)
-#define IR_CONFIG_1            (IRDA_BASE + 0x20)
-#  define IR_RX_INVERT_LED     (1 << 0)
-#  define IR_TX_INVERT_LED     (1 << 1)
-#  define IR_ST                (1 << 2)
-#  define IR_SF                (1 << 3)
-#  define IR_SIR               (1 << 4)
-#  define IR_MIR               (1 << 5)
-#  define IR_FIR               (1 << 6)
-#  define IR_16CRC             (1 << 7)
-#  define IR_TD                (1 << 8)
-#  define IR_RX_ALL            (1 << 9)
-#  define IR_DMA_ENABLE        (1 << 10)
-#  define IR_RX_ENABLE         (1 << 11)
-#  define IR_TX_ENABLE         (1 << 12)
-#  define IR_LOOPBACK          (1 << 14)
-#  define IR_SIR_MODE          (IR_SIR | IR_DMA_ENABLE | \
-                                IR_RX_ALL | IR_RX_ENABLE | IR_SF | IR_16CRC)
-#define IR_SIR_FLAGS           (IRDA_BASE + 0x24)
-#define IR_ENABLE              (IRDA_BASE + 0x28)
-#  define IR_RX_STATUS         (1 << 9)
-#  define IR_TX_STATUS         (1 << 10)
-#define IR_READ_PHY_CONFIG     (IRDA_BASE + 0x2C)
-#define IR_WRITE_PHY_CONFIG    (IRDA_BASE + 0x30)
-#define IR_MAX_PKT_LEN         (IRDA_BASE + 0x34)
-#define IR_RX_BYTE_CNT         (IRDA_BASE + 0x38)
-#define IR_CONFIG_2            (IRDA_BASE + 0x3C)
-#  define IR_MODE_INV          (1 << 0)
-#  define IR_ONE_PIN           (1 << 1)
-#define IR_INTERFACE_CONFIG    (IRDA_BASE + 0x40)
+
+/*
+ * The IrDA peripheral has an IRFIRSEL pin, but on the DB/PB boards it's not
+ * used to select FIR/SIR mode on the transceiver but as a GPIO.  Instead a
+ * CPLD has to be told about the mode.
+ */
+#define AU1000_IRDA_PHY_MODE_OFF       0
+#define AU1000_IRDA_PHY_MODE_SIR       1
+#define AU1000_IRDA_PHY_MODE_FIR       2
+
+struct au1k_irda_platform_data {
+       void(*set_phy_mode)(int mode);
+};
+
 
 /* GPIO */
 #define SYS_PINFUNC            0xB190002C
index 94000a3b6f0b7c7e07feab37f33a74c82c40d535..e221659f1bca5ae0f788b554b80d188a561b5eee 100644 (file)
@@ -130,8 +130,10 @@ struct au1xmmc_platform_data {
 #define SD_CONFIG2_DF  (0x00000008)
 #define SD_CONFIG2_DC  (0x00000010)
 #define SD_CONFIG2_xx2 (0x000000e0)
+#define SD_CONFIG2_BB  (0x00000080)
 #define SD_CONFIG2_WB  (0x00000100)
 #define SD_CONFIG2_RW  (0x00000200)
+#define SD_CONFIG2_DP  (0x00000400)
 
 
 /*
diff --git a/arch/mips/include/asm/mach-au1x00/au1200fb.h b/arch/mips/include/asm/mach-au1x00/au1200fb.h
new file mode 100644 (file)
index 0000000..b3c87cc
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * platform data for au1200fb driver.
+ */
+
+#ifndef _AU1200FB_PLAT_H_
+#define _AU1200FB_PLAT_H_
+
+struct au1200fb_platdata {
+       int (*panel_index)(void);
+       int (*panel_init)(void);
+       int (*panel_shutdown)(void);
+};
+
+#endif
diff --git a/arch/mips/include/asm/mach-au1x00/au1550nd.h b/arch/mips/include/asm/mach-au1x00/au1550nd.h
new file mode 100644 (file)
index 0000000..ad4c0a0
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * platform data for the Au1550 NAND driver
+ */
+
+#ifndef _AU1550ND_H_
+#define _AU1550ND_H_
+
+#include <linux/mtd/partitions.h>
+
+struct au1550nd_platdata {
+       struct mtd_partition *parts;
+       int num_parts;
+       int devwidth;   /* 0 = 8bit device, 1 = 16bit device */
+};
+
+#endif
index 323ce2d145f29e064c3daa87e936214778421c25..217810e18361c3e31e351efd11a5bde15cc9fc70 100644 (file)
@@ -183,6 +183,37 @@ typedef volatile struct au1xxx_ddma_desc {
 #define AU1200_DSCR_CMD0_PSC1_SYNC     25
 #define AU1200_DSCR_CMD0_CIM_SYNC      26
 
+#define AU1300_DSCR_CMD0_UART0_TX      0
+#define AU1300_DSCR_CMD0_UART0_RX      1
+#define AU1300_DSCR_CMD0_UART1_TX      2
+#define AU1300_DSCR_CMD0_UART1_RX      3
+#define AU1300_DSCR_CMD0_UART2_TX      4
+#define AU1300_DSCR_CMD0_UART2_RX      5
+#define AU1300_DSCR_CMD0_UART3_TX      6
+#define AU1300_DSCR_CMD0_UART3_RX      7
+#define AU1300_DSCR_CMD0_SDMS_TX0      8
+#define AU1300_DSCR_CMD0_SDMS_RX0      9
+#define AU1300_DSCR_CMD0_SDMS_TX1      10
+#define AU1300_DSCR_CMD0_SDMS_RX1      11
+#define AU1300_DSCR_CMD0_AES_TX        12
+#define AU1300_DSCR_CMD0_AES_RX        13
+#define AU1300_DSCR_CMD0_PSC0_TX       14
+#define AU1300_DSCR_CMD0_PSC0_RX       15
+#define AU1300_DSCR_CMD0_PSC1_TX       16
+#define AU1300_DSCR_CMD0_PSC1_RX       17
+#define AU1300_DSCR_CMD0_PSC2_TX       18
+#define AU1300_DSCR_CMD0_PSC2_RX       19
+#define AU1300_DSCR_CMD0_PSC3_TX       20
+#define AU1300_DSCR_CMD0_PSC3_RX       21
+#define AU1300_DSCR_CMD0_LCD           22
+#define AU1300_DSCR_CMD0_NAND_FLASH    23
+#define AU1300_DSCR_CMD0_SDMS_TX2      24
+#define AU1300_DSCR_CMD0_SDMS_RX2      25
+#define AU1300_DSCR_CMD0_CIM_SYNC      26
+#define AU1300_DSCR_CMD0_UDMA          27
+#define AU1300_DSCR_CMD0_DMA_REQ0      28
+#define AU1300_DSCR_CMD0_DMA_REQ1      29
+
 #define DSCR_CMD0_THROTTLE     30
 #define DSCR_CMD0_ALWAYS       31
 #define DSCR_NDEV_IDS          32
index d5df0cab9b8799774387b08ba447a5e3f5d7145e..3f741af37d47cf8153aabe49a8e435e7f7fa4257 100644 (file)
 #define cpu_has_4k_cache               1
 #define cpu_has_tx39_cache             0
 #define cpu_has_fpu                    0
+#define cpu_has_32fpr                  0
 #define cpu_has_counter                        1
 #define cpu_has_watch                  1
 #define cpu_has_divec                  1
 #define cpu_has_vce                    0
 #define cpu_has_cache_cdex_p           0
 #define cpu_has_cache_cdex_s           0
+#define cpu_has_prefetch               1
 #define cpu_has_mcheck                 1
 #define cpu_has_ejtag                  1
 #define cpu_has_llsc                   1
@@ -29,6 +31,7 @@
 #define cpu_has_vtag_icache            0
 #define cpu_has_dc_aliases             0
 #define cpu_has_ic_fills_f_dc          1
+#define cpu_has_pindexed_dcache                0
 #define cpu_has_mips32r1               1
 #define cpu_has_mips32r2               0
 #define cpu_has_mips64r1               0
diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1300.h b/arch/mips/include/asm/mach-au1x00/gpio-au1300.h
new file mode 100644 (file)
index 0000000..556e1be
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * gpio-au1300.h -- GPIO control for Au1300 GPIC and compatibles.
+ *
+ * Copyright (c) 2009-2011 Manuel Lauss <manuel.lauss@googlemail.com>
+ */
+
+#ifndef _GPIO_AU1300_H_
+#define _GPIO_AU1300_H_
+
+#include <asm/addrspace.h>
+#include <asm/io.h>
+#include <asm/mach-au1x00/au1000.h>
+
+/* with the current GPIC design, up to 128 GPIOs are possible.
+ * The only implementation so far is in the Au1300, which has 75 externally
+ * available GPIOs.
+ */
+#define AU1300_GPIO_BASE       0
+#define AU1300_GPIO_NUM                75
+#define AU1300_GPIO_MAX                (AU1300_GPIO_BASE + AU1300_GPIO_NUM - 1)
+
+#define AU1300_GPIC_ADDR       \
+       (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR)
+
+static inline int au1300_gpio_get_value(unsigned int gpio)
+{
+       void __iomem *roff = AU1300_GPIC_ADDR;
+       int bit;
+
+       gpio -= AU1300_GPIO_BASE;
+       roff += GPIC_GPIO_BANKOFF(gpio);
+       bit = GPIC_GPIO_TO_BIT(gpio);
+       return __raw_readl(roff + AU1300_GPIC_PINVAL) & bit;
+}
+
+static inline int au1300_gpio_direction_input(unsigned int gpio)
+{
+       void __iomem *roff = AU1300_GPIC_ADDR;
+       unsigned long bit;
+
+       gpio -= AU1300_GPIO_BASE;
+
+       roff += GPIC_GPIO_BANKOFF(gpio);
+       bit = GPIC_GPIO_TO_BIT(gpio);
+       __raw_writel(bit, roff + AU1300_GPIC_DEVCLR);
+       wmb();
+
+       return 0;
+}
+
+static inline int au1300_gpio_set_value(unsigned int gpio, int v)
+{
+       void __iomem *roff = AU1300_GPIC_ADDR;
+       unsigned long bit;
+
+       gpio -= AU1300_GPIO_BASE;
+
+       roff += GPIC_GPIO_BANKOFF(gpio);
+       bit = GPIC_GPIO_TO_BIT(gpio);
+       __raw_writel(bit, roff + (v ? AU1300_GPIC_PINVAL
+                                   : AU1300_GPIC_PINVALCLR));
+       wmb();
+
+       return 0;
+}
+
+static inline int au1300_gpio_direction_output(unsigned int gpio, int v)
+{
+       /* hw switches to output automatically */
+       return au1300_gpio_set_value(gpio, v);
+}
+
+static inline int au1300_gpio_to_irq(unsigned int gpio)
+{
+       return AU1300_FIRST_INT + (gpio - AU1300_GPIO_BASE);
+}
+
+static inline int au1300_irq_to_gpio(unsigned int irq)
+{
+       return (irq - AU1300_FIRST_INT) + AU1300_GPIO_BASE;
+}
+
+static inline int au1300_gpio_is_valid(unsigned int gpio)
+{
+       int ret;
+
+       switch (alchemy_get_cputype()) {
+       case ALCHEMY_CPU_AU1300:
+               ret = ((gpio >= AU1300_GPIO_BASE) && (gpio <= AU1300_GPIO_MAX));
+               break;
+       default:
+               ret = 0;
+       }
+       return ret;
+}
+
+static inline int au1300_gpio_cansleep(unsigned int gpio)
+{
+       return 0;
+}
+
+/* hardware remembers gpio 0-63 levels on powerup */
+static inline int au1300_gpio_getinitlvl(unsigned int gpio)
+{
+       void __iomem *roff = AU1300_GPIC_ADDR;
+       unsigned long v;
+
+       if (unlikely(gpio > 63))
+               return 0;
+       else if (gpio > 31) {
+               gpio -= 32;
+               roff += 4;
+       }
+
+       v = __raw_readl(roff + AU1300_GPIC_RSTVAL);
+       return (v >> gpio) & 1;
+}
+
+/**********************************************************************/
+
+/* Linux gpio framework integration.
+*
+* 4 use cases of Alchemy GPIOS:
+*(1) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=y:
+*      Board must register gpiochips.
+*(2) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=n:
+*      A gpiochip for the 75 GPIOs is registered.
+*
+*(3) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=y:
+*      the boards' gpio.h must provide the linux gpio wrapper functions,
+*
+*(4) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=n:
+*      inlinable gpio functions are provided which enable access to the
+*      Au1300 gpios only by using the numbers straight out of the data-
+*      sheets.
+
+* Cases 1 and 3 are intended for boards which want to provide their own
+* GPIO namespace and -operations (i.e. for example you have 8 GPIOs
+* which are in part provided by spare Au1300 GPIO pins and in part by
+* an external FPGA but you still want them to be accssible in linux
+* as gpio0-7. The board can of course use the alchemy_gpioX_* functions
+* as required).
+*/
+
+#ifndef CONFIG_GPIOLIB
+
+#ifdef CONFIG_ALCHEMY_GPIOINT_AU1300
+
+#ifndef CONFIG_ALCHEMY_GPIO_INDIRECT   /* case (4) */
+
+static inline int gpio_direction_input(unsigned int gpio)
+{
+       return au1300_gpio_direction_input(gpio);
+}
+
+static inline int gpio_direction_output(unsigned int gpio, int v)
+{
+       return au1300_gpio_direction_output(gpio, v);
+}
+
+static inline int gpio_get_value(unsigned int gpio)
+{
+       return au1300_gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int v)
+{
+       au1300_gpio_set_value(gpio, v);
+}
+
+static inline int gpio_get_value_cansleep(unsigned gpio)
+{
+       return gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value_cansleep(unsigned gpio, int value)
+{
+       gpio_set_value(gpio, value);
+}
+
+static inline int gpio_is_valid(unsigned int gpio)
+{
+       return au1300_gpio_is_valid(gpio);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+       return au1300_gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+       return au1300_gpio_to_irq(gpio);
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+       return au1300_irq_to_gpio(irq);
+}
+
+static inline int gpio_request(unsigned int gpio, const char *label)
+{
+       return 0;
+}
+
+static inline void gpio_free(unsigned int gpio)
+{
+}
+
+static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
+{
+       return -ENOSYS;
+}
+
+static inline void gpio_unexport(unsigned gpio)
+{
+}
+
+static inline int gpio_export(unsigned gpio, bool direction_may_change)
+{
+       return -ENOSYS;
+}
+
+static inline int gpio_sysfs_set_active_low(unsigned gpio, int value)
+{
+       return -ENOSYS;
+}
+
+static inline int gpio_export_link(struct device *dev, const char *name,
+                                  unsigned gpio)
+{
+       return -ENOSYS;
+}
+
+#endif /* !CONFIG_ALCHEMY_GPIO_INDIRECT */
+
+#endif /* CONFIG_ALCHEMY_GPIOINT_AU1300 */
+
+#endif /* CONFIG GPIOLIB */
+
+#endif /* _GPIO_AU1300_H_ */
index fcdc8c4809db523617cefd3ef46c93cf26ee5e4c..22e7ff17fc48298752bffef99d69cc48ac3ca598 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/gpio-au1000.h>
+#include <asm/mach-au1x00/gpio-au1300.h>
 
 /* On Au1000, Au1500 and Au1100 GPIOs won't work as inputs before
  * SYS_PININPUTEN is written to at least once.  On Au1550/Au1200/Au1300 this
@@ -58,6 +59,8 @@ static inline int __au_irq_to_gpio(unsigned int irq)
        switch (alchemy_get_cputype()) {
        case ALCHEMY_CPU_AU1000...ALCHEMY_CPU_AU1200:
                return alchemy_irq_to_gpio(irq);
+       case ALCHEMY_CPU_AU1300:
+               return au1300_irq_to_gpio(irq);
        }
        return -EINVAL;
 }
index 96a2391ad85be96a4d4d8e2c9b95ca35c9af6244..5b8d15bb5fe85a4b6d234f6aaf006d9e451efb8d 100644 (file)
@@ -13,6 +13,7 @@
 #define BCM6345_CPU_ID         0x6345
 #define BCM6348_CPU_ID         0x6348
 #define BCM6358_CPU_ID         0x6358
+#define BCM6368_CPU_ID         0x6368
 
 void __init bcm63xx_cpu_init(void);
 u16 __bcm63xx_get_cpu_id(void);
@@ -71,6 +72,19 @@ unsigned int bcm63xx_get_cpu_freq(void);
 # define BCMCPU_IS_6358()      (0)
 #endif
 
+#ifdef CONFIG_BCM63XX_CPU_6368
+# ifdef bcm63xx_get_cpu_id
+#  undef bcm63xx_get_cpu_id
+#  define bcm63xx_get_cpu_id() __bcm63xx_get_cpu_id()
+#  define BCMCPU_RUNTIME_DETECT
+# else
+#  define bcm63xx_get_cpu_id() BCM6368_CPU_ID
+# endif
+# define BCMCPU_IS_6368()      (bcm63xx_get_cpu_id() == BCM6368_CPU_ID)
+#else
+# define BCMCPU_IS_6368()      (0)
+#endif
+
 #ifndef bcm63xx_get_cpu_id
 #error "No CPU support configured"
 #endif
@@ -88,6 +102,7 @@ enum bcm63xx_regs_set {
        RSET_UART1,
        RSET_GPIO,
        RSET_SPI,
+       RSET_SPI2,
        RSET_UDC0,
        RSET_OHCI0,
        RSET_OHCI_PRIV,
@@ -98,10 +113,23 @@ enum bcm63xx_regs_set {
        RSET_ENET0,
        RSET_ENET1,
        RSET_ENETDMA,
+       RSET_ENETDMAC,
+       RSET_ENETDMAS,
+       RSET_ENETSW,
        RSET_EHCI0,
        RSET_SDRAM,
        RSET_MEMC,
        RSET_DDR,
+       RSET_M2M,
+       RSET_ATM,
+       RSET_XTM,
+       RSET_XTMDMA,
+       RSET_XTMDMAC,
+       RSET_XTMDMAS,
+       RSET_PCM,
+       RSET_PCMDMA,
+       RSET_PCMDMAC,
+       RSET_PCMDMAS,
 };
 
 #define RSET_DSL_LMEM_SIZE             (64 * 1024 * 4)
@@ -109,11 +137,18 @@ enum bcm63xx_regs_set {
 #define RSET_WDT_SIZE                  12
 #define RSET_ENET_SIZE                 2048
 #define RSET_ENETDMA_SIZE              2048
+#define RSET_ENETSW_SIZE               65536
 #define RSET_UART_SIZE                 24
 #define RSET_UDC_SIZE                  256
 #define RSET_OHCI_SIZE                 256
 #define RSET_EHCI_SIZE                 256
 #define RSET_PCMCIA_SIZE               12
+#define RSET_M2M_SIZE                  256
+#define RSET_ATM_SIZE                  4096
+#define RSET_XTM_SIZE                  10240
+#define RSET_XTMDMA_SIZE               256
+#define RSET_XTMDMAC_SIZE(chans)       (16 * (chans))
+#define RSET_XTMDMAS_SIZE(chans)       (16 * (chans))
 
 /*
  * 6338 register sets base address
@@ -127,6 +162,7 @@ enum bcm63xx_regs_set {
 #define BCM_6338_UART1_BASE            (0xdeadbeef)
 #define BCM_6338_GPIO_BASE             (0xfffe0400)
 #define BCM_6338_SPI_BASE              (0xfffe0c00)
+#define BCM_6338_SPI2_BASE             (0xdeadbeef)
 #define BCM_6338_UDC0_BASE             (0xdeadbeef)
 #define BCM_6338_USBDMA_BASE           (0xfffe2400)
 #define BCM_6338_OHCI0_BASE            (0xdeadbeef)
@@ -136,15 +172,27 @@ enum bcm63xx_regs_set {
 #define BCM_6338_PCMCIA_BASE           (0xdeadbeef)
 #define BCM_6338_SDRAM_REGS_BASE       (0xfffe3100)
 #define BCM_6338_DSL_BASE              (0xfffe1000)
-#define BCM_6338_SAR_BASE              (0xfffe2000)
 #define BCM_6338_UBUS_BASE             (0xdeadbeef)
 #define BCM_6338_ENET0_BASE            (0xfffe2800)
 #define BCM_6338_ENET1_BASE            (0xdeadbeef)
 #define BCM_6338_ENETDMA_BASE          (0xfffe2400)
+#define BCM_6338_ENETDMAC_BASE         (0xfffe2500)
+#define BCM_6338_ENETDMAS_BASE         (0xfffe2600)
+#define BCM_6338_ENETSW_BASE           (0xdeadbeef)
 #define BCM_6338_EHCI0_BASE            (0xdeadbeef)
 #define BCM_6338_SDRAM_BASE            (0xfffe3100)
 #define BCM_6338_MEMC_BASE             (0xdeadbeef)
 #define BCM_6338_DDR_BASE              (0xdeadbeef)
+#define BCM_6338_M2M_BASE              (0xdeadbeef)
+#define BCM_6338_ATM_BASE              (0xfffe2000)
+#define BCM_6338_XTM_BASE              (0xdeadbeef)
+#define BCM_6338_XTMDMA_BASE           (0xdeadbeef)
+#define BCM_6338_XTMDMAC_BASE          (0xdeadbeef)
+#define BCM_6338_XTMDMAS_BASE          (0xdeadbeef)
+#define BCM_6338_PCM_BASE              (0xdeadbeef)
+#define BCM_6338_PCMDMA_BASE           (0xdeadbeef)
+#define BCM_6338_PCMDMAC_BASE          (0xdeadbeef)
+#define BCM_6338_PCMDMAS_BASE          (0xdeadbeef)
 
 /*
  * 6345 register sets base address
@@ -158,24 +206,37 @@ enum bcm63xx_regs_set {
 #define BCM_6345_UART1_BASE            (0xdeadbeef)
 #define BCM_6345_GPIO_BASE             (0xfffe0400)
 #define BCM_6345_SPI_BASE              (0xdeadbeef)
+#define BCM_6345_SPI2_BASE             (0xdeadbeef)
 #define BCM_6345_UDC0_BASE             (0xdeadbeef)
 #define BCM_6345_USBDMA_BASE           (0xfffe2800)
 #define BCM_6345_ENET0_BASE            (0xfffe1800)
 #define BCM_6345_ENETDMA_BASE          (0xfffe2800)
+#define BCM_6345_ENETDMAC_BASE         (0xfffe2900)
+#define BCM_6345_ENETDMAS_BASE         (0xfffe2a00)
+#define BCM_6345_ENETSW_BASE           (0xdeadbeef)
 #define BCM_6345_PCMCIA_BASE           (0xfffe2028)
-#define BCM_6345_MPI_BASE              (0xdeadbeef)
+#define BCM_6345_MPI_BASE              (0xfffe2000)
 #define BCM_6345_OHCI0_BASE            (0xfffe2100)
 #define BCM_6345_OHCI_PRIV_BASE                (0xfffe2200)
 #define BCM_6345_USBH_PRIV_BASE                (0xdeadbeef)
 #define BCM_6345_SDRAM_REGS_BASE       (0xfffe2300)
 #define BCM_6345_DSL_BASE              (0xdeadbeef)
-#define BCM_6345_SAR_BASE              (0xdeadbeef)
 #define BCM_6345_UBUS_BASE             (0xdeadbeef)
 #define BCM_6345_ENET1_BASE            (0xdeadbeef)
 #define BCM_6345_EHCI0_BASE            (0xdeadbeef)
 #define BCM_6345_SDRAM_BASE            (0xfffe2300)
 #define BCM_6345_MEMC_BASE             (0xdeadbeef)
 #define BCM_6345_DDR_BASE              (0xdeadbeef)
+#define BCM_6345_M2M_BASE              (0xdeadbeef)
+#define BCM_6345_ATM_BASE              (0xfffe4000)
+#define BCM_6345_XTM_BASE              (0xdeadbeef)
+#define BCM_6345_XTMDMA_BASE           (0xdeadbeef)
+#define BCM_6345_XTMDMAC_BASE          (0xdeadbeef)
+#define BCM_6345_XTMDMAS_BASE          (0xdeadbeef)
+#define BCM_6345_PCM_BASE              (0xdeadbeef)
+#define BCM_6345_PCMDMA_BASE           (0xdeadbeef)
+#define BCM_6345_PCMDMAC_BASE          (0xdeadbeef)
+#define BCM_6345_PCMDMAS_BASE          (0xdeadbeef)
 
 /*
  * 6348 register sets base address
@@ -188,6 +249,7 @@ enum bcm63xx_regs_set {
 #define BCM_6348_UART1_BASE            (0xdeadbeef)
 #define BCM_6348_GPIO_BASE             (0xfffe0400)
 #define BCM_6348_SPI_BASE              (0xfffe0c00)
+#define BCM_6348_SPI2_BASE             (0xdeadbeef)
 #define BCM_6348_UDC0_BASE             (0xfffe1000)
 #define BCM_6348_OHCI0_BASE            (0xfffe1b00)
 #define BCM_6348_OHCI_PRIV_BASE                (0xfffe1c00)
@@ -195,14 +257,27 @@ enum bcm63xx_regs_set {
 #define BCM_6348_MPI_BASE              (0xfffe2000)
 #define BCM_6348_PCMCIA_BASE           (0xfffe2054)
 #define BCM_6348_SDRAM_REGS_BASE       (0xfffe2300)
+#define BCM_6348_M2M_BASE              (0xfffe2800)
 #define BCM_6348_DSL_BASE              (0xfffe3000)
 #define BCM_6348_ENET0_BASE            (0xfffe6000)
 #define BCM_6348_ENET1_BASE            (0xfffe6800)
 #define BCM_6348_ENETDMA_BASE          (0xfffe7000)
+#define BCM_6348_ENETDMAC_BASE         (0xfffe7100)
+#define BCM_6348_ENETDMAS_BASE         (0xfffe7200)
+#define BCM_6348_ENETSW_BASE           (0xdeadbeef)
 #define BCM_6348_EHCI0_BASE            (0xdeadbeef)
 #define BCM_6348_SDRAM_BASE            (0xfffe2300)
 #define BCM_6348_MEMC_BASE             (0xdeadbeef)
 #define BCM_6348_DDR_BASE              (0xdeadbeef)
+#define BCM_6348_ATM_BASE              (0xfffe4000)
+#define BCM_6348_XTM_BASE              (0xdeadbeef)
+#define BCM_6348_XTMDMA_BASE           (0xdeadbeef)
+#define BCM_6348_XTMDMAC_BASE          (0xdeadbeef)
+#define BCM_6348_XTMDMAS_BASE          (0xdeadbeef)
+#define BCM_6348_PCM_BASE              (0xdeadbeef)
+#define BCM_6348_PCMDMA_BASE           (0xdeadbeef)
+#define BCM_6348_PCMDMAC_BASE          (0xdeadbeef)
+#define BCM_6348_PCMDMAS_BASE          (0xdeadbeef)
 
 /*
  * 6358 register sets base address
@@ -215,6 +290,7 @@ enum bcm63xx_regs_set {
 #define BCM_6358_UART1_BASE            (0xfffe0120)
 #define BCM_6358_GPIO_BASE             (0xfffe0080)
 #define BCM_6358_SPI_BASE              (0xdeadbeef)
+#define BCM_6358_SPI2_BASE             (0xfffe0800)
 #define BCM_6358_UDC0_BASE             (0xfffe0800)
 #define BCM_6358_OHCI0_BASE            (0xfffe1400)
 #define BCM_6358_OHCI_PRIV_BASE                (0xdeadbeef)
@@ -222,214 +298,175 @@ enum bcm63xx_regs_set {
 #define BCM_6358_MPI_BASE              (0xfffe1000)
 #define BCM_6358_PCMCIA_BASE           (0xfffe1054)
 #define BCM_6358_SDRAM_REGS_BASE       (0xfffe2300)
+#define BCM_6358_M2M_BASE              (0xdeadbeef)
 #define BCM_6358_DSL_BASE              (0xfffe3000)
 #define BCM_6358_ENET0_BASE            (0xfffe4000)
 #define BCM_6358_ENET1_BASE            (0xfffe4800)
 #define BCM_6358_ENETDMA_BASE          (0xfffe5000)
+#define BCM_6358_ENETDMAC_BASE         (0xfffe5100)
+#define BCM_6358_ENETDMAS_BASE         (0xfffe5200)
+#define BCM_6358_ENETSW_BASE           (0xdeadbeef)
 #define BCM_6358_EHCI0_BASE            (0xfffe1300)
 #define BCM_6358_SDRAM_BASE            (0xdeadbeef)
 #define BCM_6358_MEMC_BASE             (0xfffe1200)
 #define BCM_6358_DDR_BASE              (0xfffe12a0)
+#define BCM_6358_ATM_BASE              (0xfffe2000)
+#define BCM_6358_XTM_BASE              (0xdeadbeef)
+#define BCM_6358_XTMDMA_BASE           (0xdeadbeef)
+#define BCM_6358_XTMDMAC_BASE          (0xdeadbeef)
+#define BCM_6358_XTMDMAS_BASE          (0xdeadbeef)
+#define BCM_6358_PCM_BASE              (0xfffe1600)
+#define BCM_6358_PCMDMA_BASE           (0xfffe1800)
+#define BCM_6358_PCMDMAC_BASE          (0xfffe1900)
+#define BCM_6358_PCMDMAS_BASE          (0xfffe1a00)
+
+
+/*
+ * 6368 register sets base address
+ */
+#define BCM_6368_DSL_LMEM_BASE         (0xdeadbeef)
+#define BCM_6368_PERF_BASE             (0xb0000000)
+#define BCM_6368_TIMER_BASE            (0xb0000040)
+#define BCM_6368_WDT_BASE              (0xb000005c)
+#define BCM_6368_UART0_BASE            (0xb0000100)
+#define BCM_6368_UART1_BASE            (0xb0000120)
+#define BCM_6368_GPIO_BASE             (0xb0000080)
+#define BCM_6368_SPI_BASE              (0xdeadbeef)
+#define BCM_6368_SPI2_BASE             (0xb0000800)
+#define BCM_6368_UDC0_BASE             (0xdeadbeef)
+#define BCM_6368_OHCI0_BASE            (0xb0001600)
+#define BCM_6368_OHCI_PRIV_BASE                (0xdeadbeef)
+#define BCM_6368_USBH_PRIV_BASE                (0xb0001700)
+#define BCM_6368_MPI_BASE              (0xb0001000)
+#define BCM_6368_PCMCIA_BASE           (0xb0001054)
+#define BCM_6368_SDRAM_REGS_BASE       (0xdeadbeef)
+#define BCM_6368_M2M_BASE              (0xdeadbeef)
+#define BCM_6368_DSL_BASE              (0xdeadbeef)
+#define BCM_6368_ENET0_BASE            (0xdeadbeef)
+#define BCM_6368_ENET1_BASE            (0xdeadbeef)
+#define BCM_6368_ENETDMA_BASE          (0xb0006800)
+#define BCM_6368_ENETDMAC_BASE         (0xb0006a00)
+#define BCM_6368_ENETDMAS_BASE         (0xb0006c00)
+#define BCM_6368_ENETSW_BASE           (0xb0f00000)
+#define BCM_6368_EHCI0_BASE            (0xb0001500)
+#define BCM_6368_SDRAM_BASE            (0xdeadbeef)
+#define BCM_6368_MEMC_BASE             (0xb0001200)
+#define BCM_6368_DDR_BASE              (0xb0001280)
+#define BCM_6368_ATM_BASE              (0xdeadbeef)
+#define BCM_6368_XTM_BASE              (0xb0001800)
+#define BCM_6368_XTMDMA_BASE           (0xb0005000)
+#define BCM_6368_XTMDMAC_BASE          (0xb0005200)
+#define BCM_6368_XTMDMAS_BASE          (0xb0005400)
+#define BCM_6368_PCM_BASE              (0xb0004000)
+#define BCM_6368_PCMDMA_BASE           (0xb0005800)
+#define BCM_6368_PCMDMAC_BASE          (0xb0005a00)
+#define BCM_6368_PCMDMAS_BASE          (0xb0005c00)
 
 
 extern const unsigned long *bcm63xx_regs_base;
 
+#define __GEN_RSET_BASE(__cpu, __rset)                                 \
+       case RSET_## __rset :                                           \
+               return BCM_## __cpu ##_## __rset ##_BASE;
+
+#define __GEN_RSET(__cpu)                                              \
+       switch (set) {                                                  \
+       __GEN_RSET_BASE(__cpu, DSL_LMEM)                                \
+       __GEN_RSET_BASE(__cpu, PERF)                                    \
+       __GEN_RSET_BASE(__cpu, TIMER)                                   \
+       __GEN_RSET_BASE(__cpu, WDT)                                     \
+       __GEN_RSET_BASE(__cpu, UART0)                                   \
+       __GEN_RSET_BASE(__cpu, UART1)                                   \
+       __GEN_RSET_BASE(__cpu, GPIO)                                    \
+       __GEN_RSET_BASE(__cpu, SPI)                                     \
+       __GEN_RSET_BASE(__cpu, SPI2)                                    \
+       __GEN_RSET_BASE(__cpu, UDC0)                                    \
+       __GEN_RSET_BASE(__cpu, OHCI0)                                   \
+       __GEN_RSET_BASE(__cpu, OHCI_PRIV)                               \
+       __GEN_RSET_BASE(__cpu, USBH_PRIV)                               \
+       __GEN_RSET_BASE(__cpu, MPI)                                     \
+       __GEN_RSET_BASE(__cpu, PCMCIA)                                  \
+       __GEN_RSET_BASE(__cpu, DSL)                                     \
+       __GEN_RSET_BASE(__cpu, ENET0)                                   \
+       __GEN_RSET_BASE(__cpu, ENET1)                                   \
+       __GEN_RSET_BASE(__cpu, ENETDMA)                                 \
+       __GEN_RSET_BASE(__cpu, ENETDMAC)                                \
+       __GEN_RSET_BASE(__cpu, ENETDMAS)                                \
+       __GEN_RSET_BASE(__cpu, ENETSW)                                  \
+       __GEN_RSET_BASE(__cpu, EHCI0)                                   \
+       __GEN_RSET_BASE(__cpu, SDRAM)                                   \
+       __GEN_RSET_BASE(__cpu, MEMC)                                    \
+       __GEN_RSET_BASE(__cpu, DDR)                                     \
+       __GEN_RSET_BASE(__cpu, M2M)                                     \
+       __GEN_RSET_BASE(__cpu, ATM)                                     \
+       __GEN_RSET_BASE(__cpu, XTM)                                     \
+       __GEN_RSET_BASE(__cpu, XTMDMA)                                  \
+       __GEN_RSET_BASE(__cpu, XTMDMAC)                                 \
+       __GEN_RSET_BASE(__cpu, XTMDMAS)                                 \
+       __GEN_RSET_BASE(__cpu, PCM)                                     \
+       __GEN_RSET_BASE(__cpu, PCMDMA)                                  \
+       __GEN_RSET_BASE(__cpu, PCMDMAC)                                 \
+       __GEN_RSET_BASE(__cpu, PCMDMAS)                                 \
+       }
+
+#define __GEN_CPU_REGS_TABLE(__cpu)                                    \
+       [RSET_DSL_LMEM]         = BCM_## __cpu ##_DSL_LMEM_BASE,        \
+       [RSET_PERF]             = BCM_## __cpu ##_PERF_BASE,            \
+       [RSET_TIMER]            = BCM_## __cpu ##_TIMER_BASE,           \
+       [RSET_WDT]              = BCM_## __cpu ##_WDT_BASE,             \
+       [RSET_UART0]            = BCM_## __cpu ##_UART0_BASE,           \
+       [RSET_UART1]            = BCM_## __cpu ##_UART1_BASE,           \
+       [RSET_GPIO]             = BCM_## __cpu ##_GPIO_BASE,            \
+       [RSET_SPI]              = BCM_## __cpu ##_SPI_BASE,             \
+       [RSET_SPI2]             = BCM_## __cpu ##_SPI2_BASE,            \
+       [RSET_UDC0]             = BCM_## __cpu ##_UDC0_BASE,            \
+       [RSET_OHCI0]            = BCM_## __cpu ##_OHCI0_BASE,           \
+       [RSET_OHCI_PRIV]        = BCM_## __cpu ##_OHCI_PRIV_BASE,       \
+       [RSET_USBH_PRIV]        = BCM_## __cpu ##_USBH_PRIV_BASE,       \
+       [RSET_MPI]              = BCM_## __cpu ##_MPI_BASE,             \
+       [RSET_PCMCIA]           = BCM_## __cpu ##_PCMCIA_BASE,          \
+       [RSET_DSL]              = BCM_## __cpu ##_DSL_BASE,             \
+       [RSET_ENET0]            = BCM_## __cpu ##_ENET0_BASE,           \
+       [RSET_ENET1]            = BCM_## __cpu ##_ENET1_BASE,           \
+       [RSET_ENETDMA]          = BCM_## __cpu ##_ENETDMA_BASE,         \
+       [RSET_ENETDMAC]         = BCM_## __cpu ##_ENETDMAC_BASE,        \
+       [RSET_ENETDMAS]         = BCM_## __cpu ##_ENETDMAS_BASE,        \
+       [RSET_ENETSW]           = BCM_## __cpu ##_ENETSW_BASE,          \
+       [RSET_EHCI0]            = BCM_## __cpu ##_EHCI0_BASE,           \
+       [RSET_SDRAM]            = BCM_## __cpu ##_SDRAM_BASE,           \
+       [RSET_MEMC]             = BCM_## __cpu ##_MEMC_BASE,            \
+       [RSET_DDR]              = BCM_## __cpu ##_DDR_BASE,             \
+       [RSET_M2M]              = BCM_## __cpu ##_M2M_BASE,             \
+       [RSET_ATM]              = BCM_## __cpu ##_ATM_BASE,             \
+       [RSET_XTM]              = BCM_## __cpu ##_XTM_BASE,             \
+       [RSET_XTMDMA]           = BCM_## __cpu ##_XTMDMA_BASE,          \
+       [RSET_XTMDMAC]          = BCM_## __cpu ##_XTMDMAC_BASE,         \
+       [RSET_XTMDMAS]          = BCM_## __cpu ##_XTMDMAS_BASE,         \
+       [RSET_PCM]              = BCM_## __cpu ##_PCM_BASE,             \
+       [RSET_PCMDMA]           = BCM_## __cpu ##_PCMDMA_BASE,          \
+       [RSET_PCMDMAC]          = BCM_## __cpu ##_PCMDMAC_BASE,         \
+       [RSET_PCMDMAS]          = BCM_## __cpu ##_PCMDMAS_BASE,         \
+
+
 static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set)
 {
 #ifdef BCMCPU_RUNTIME_DETECT
        return bcm63xx_regs_base[set];
 #else
 #ifdef CONFIG_BCM63XX_CPU_6338
-       switch (set) {
-       case RSET_DSL_LMEM:
-               return BCM_6338_DSL_LMEM_BASE;
-       case RSET_PERF:
-               return BCM_6338_PERF_BASE;
-       case RSET_TIMER:
-               return BCM_6338_TIMER_BASE;
-       case RSET_WDT:
-               return BCM_6338_WDT_BASE;
-       case RSET_UART0:
-               return BCM_6338_UART0_BASE;
-       case RSET_UART1:
-               return BCM_6338_UART1_BASE;
-       case RSET_GPIO:
-               return BCM_6338_GPIO_BASE;
-       case RSET_SPI:
-               return BCM_6338_SPI_BASE;
-       case RSET_UDC0:
-               return BCM_6338_UDC0_BASE;
-       case RSET_OHCI0:
-               return BCM_6338_OHCI0_BASE;
-       case RSET_OHCI_PRIV:
-               return BCM_6338_OHCI_PRIV_BASE;
-       case RSET_USBH_PRIV:
-               return BCM_6338_USBH_PRIV_BASE;
-       case RSET_MPI:
-               return BCM_6338_MPI_BASE;
-       case RSET_PCMCIA:
-               return BCM_6338_PCMCIA_BASE;
-       case RSET_DSL:
-               return BCM_6338_DSL_BASE;
-       case RSET_ENET0:
-               return BCM_6338_ENET0_BASE;
-       case RSET_ENET1:
-               return BCM_6338_ENET1_BASE;
-       case RSET_ENETDMA:
-               return BCM_6338_ENETDMA_BASE;
-       case RSET_EHCI0:
-               return BCM_6338_EHCI0_BASE;
-       case RSET_SDRAM:
-               return BCM_6338_SDRAM_BASE;
-       case RSET_MEMC:
-               return BCM_6338_MEMC_BASE;
-       case RSET_DDR:
-               return BCM_6338_DDR_BASE;
-       }
+       __GEN_RSET(6338)
 #endif
 #ifdef CONFIG_BCM63XX_CPU_6345
-       switch (set) {
-       case RSET_DSL_LMEM:
-               return BCM_6345_DSL_LMEM_BASE;
-       case RSET_PERF:
-               return BCM_6345_PERF_BASE;
-       case RSET_TIMER:
-               return BCM_6345_TIMER_BASE;
-       case RSET_WDT:
-               return BCM_6345_WDT_BASE;
-       case RSET_UART0:
-               return BCM_6345_UART0_BASE;
-       case RSET_UART1:
-               return BCM_6345_UART1_BASE;
-       case RSET_GPIO:
-               return BCM_6345_GPIO_BASE;
-       case RSET_SPI:
-               return BCM_6345_SPI_BASE;
-       case RSET_UDC0:
-               return BCM_6345_UDC0_BASE;
-       case RSET_OHCI0:
-               return BCM_6345_OHCI0_BASE;
-       case RSET_OHCI_PRIV:
-               return BCM_6345_OHCI_PRIV_BASE;
-       case RSET_USBH_PRIV:
-               return BCM_6345_USBH_PRIV_BASE;
-       case RSET_MPI:
-               return BCM_6345_MPI_BASE;
-       case RSET_PCMCIA:
-               return BCM_6345_PCMCIA_BASE;
-       case RSET_DSL:
-               return BCM_6345_DSL_BASE;
-       case RSET_ENET0:
-               return BCM_6345_ENET0_BASE;
-       case RSET_ENET1:
-               return BCM_6345_ENET1_BASE;
-       case RSET_ENETDMA:
-               return BCM_6345_ENETDMA_BASE;
-       case RSET_EHCI0:
-               return BCM_6345_EHCI0_BASE;
-       case RSET_SDRAM:
-               return BCM_6345_SDRAM_BASE;
-       case RSET_MEMC:
-               return BCM_6345_MEMC_BASE;
-       case RSET_DDR:
-               return BCM_6345_DDR_BASE;
-       }
+       __GEN_RSET(6345)
 #endif
 #ifdef CONFIG_BCM63XX_CPU_6348
-       switch (set) {
-       case RSET_DSL_LMEM:
-               return BCM_6348_DSL_LMEM_BASE;
-       case RSET_PERF:
-               return BCM_6348_PERF_BASE;
-       case RSET_TIMER:
-               return BCM_6348_TIMER_BASE;
-       case RSET_WDT:
-               return BCM_6348_WDT_BASE;
-       case RSET_UART0:
-               return BCM_6348_UART0_BASE;
-       case RSET_UART1:
-               return BCM_6348_UART1_BASE;
-       case RSET_GPIO:
-               return BCM_6348_GPIO_BASE;
-       case RSET_SPI:
-               return BCM_6348_SPI_BASE;
-       case RSET_UDC0:
-               return BCM_6348_UDC0_BASE;
-       case RSET_OHCI0:
-               return BCM_6348_OHCI0_BASE;
-       case RSET_OHCI_PRIV:
-               return BCM_6348_OHCI_PRIV_BASE;
-       case RSET_USBH_PRIV:
-               return BCM_6348_USBH_PRIV_BASE;
-       case RSET_MPI:
-               return BCM_6348_MPI_BASE;
-       case RSET_PCMCIA:
-               return BCM_6348_PCMCIA_BASE;
-       case RSET_DSL:
-               return BCM_6348_DSL_BASE;
-       case RSET_ENET0:
-               return BCM_6348_ENET0_BASE;
-       case RSET_ENET1:
-               return BCM_6348_ENET1_BASE;
-       case RSET_ENETDMA:
-               return BCM_6348_ENETDMA_BASE;
-       case RSET_EHCI0:
-               return BCM_6348_EHCI0_BASE;
-       case RSET_SDRAM:
-               return BCM_6348_SDRAM_BASE;
-       case RSET_MEMC:
-               return BCM_6348_MEMC_BASE;
-       case RSET_DDR:
-               return BCM_6348_DDR_BASE;
-       }
+       __GEN_RSET(6348)
 #endif
 #ifdef CONFIG_BCM63XX_CPU_6358
-       switch (set) {
-       case RSET_DSL_LMEM:
-               return BCM_6358_DSL_LMEM_BASE;
-       case RSET_PERF:
-               return BCM_6358_PERF_BASE;
-       case RSET_TIMER:
-               return BCM_6358_TIMER_BASE;
-       case RSET_WDT:
-               return BCM_6358_WDT_BASE;
-       case RSET_UART0:
-               return BCM_6358_UART0_BASE;
-       case RSET_UART1:
-               return BCM_6358_UART1_BASE;
-       case RSET_GPIO:
-               return BCM_6358_GPIO_BASE;
-       case RSET_SPI:
-               return BCM_6358_SPI_BASE;
-       case RSET_UDC0:
-               return BCM_6358_UDC0_BASE;
-       case RSET_OHCI0:
-               return BCM_6358_OHCI0_BASE;
-       case RSET_OHCI_PRIV:
-               return BCM_6358_OHCI_PRIV_BASE;
-       case RSET_USBH_PRIV:
-               return BCM_6358_USBH_PRIV_BASE;
-       case RSET_MPI:
-               return BCM_6358_MPI_BASE;
-       case RSET_PCMCIA:
-               return BCM_6358_PCMCIA_BASE;
-       case RSET_ENET0:
-               return BCM_6358_ENET0_BASE;
-       case RSET_ENET1:
-               return BCM_6358_ENET1_BASE;
-       case RSET_ENETDMA:
-               return BCM_6358_ENETDMA_BASE;
-       case RSET_DSL:
-               return BCM_6358_DSL_BASE;
-       case RSET_EHCI0:
-               return BCM_6358_EHCI0_BASE;
-       case RSET_SDRAM:
-               return BCM_6358_SDRAM_BASE;
-       case RSET_MEMC:
-               return BCM_6358_MEMC_BASE;
-       case RSET_DDR:
-               return BCM_6358_DDR_BASE;
-       }
+       __GEN_RSET(6358)
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6368
+       __GEN_RSET(6368)
 #endif
 #endif
        /* unreached */
@@ -449,75 +486,114 @@ enum bcm63xx_irq {
        IRQ_ENET_PHY,
        IRQ_OHCI0,
        IRQ_EHCI0,
-       IRQ_PCMCIA0,
        IRQ_ENET0_RXDMA,
        IRQ_ENET0_TXDMA,
        IRQ_ENET1_RXDMA,
        IRQ_ENET1_TXDMA,
        IRQ_PCI,
        IRQ_PCMCIA,
+       IRQ_ATM,
+       IRQ_ENETSW_RXDMA0,
+       IRQ_ENETSW_RXDMA1,
+       IRQ_ENETSW_RXDMA2,
+       IRQ_ENETSW_RXDMA3,
+       IRQ_ENETSW_TXDMA0,
+       IRQ_ENETSW_TXDMA1,
+       IRQ_ENETSW_TXDMA2,
+       IRQ_ENETSW_TXDMA3,
+       IRQ_XTM,
+       IRQ_XTM_DMA0,
 };
 
 /*
  * 6338 irqs
  */
 #define BCM_6338_TIMER_IRQ             (IRQ_INTERNAL_BASE + 0)
-#define BCM_6338_SPI_IRQ               (IRQ_INTERNAL_BASE + 1)
 #define BCM_6338_UART0_IRQ             (IRQ_INTERNAL_BASE + 2)
-#define BCM_6338_DG_IRQ                        (IRQ_INTERNAL_BASE + 4)
+#define BCM_6338_UART1_IRQ             0
 #define BCM_6338_DSL_IRQ               (IRQ_INTERNAL_BASE + 5)
-#define BCM_6338_ATM_IRQ               (IRQ_INTERNAL_BASE + 6)
-#define BCM_6338_UDC0_IRQ              (IRQ_INTERNAL_BASE + 7)
 #define BCM_6338_ENET0_IRQ             (IRQ_INTERNAL_BASE + 8)
+#define BCM_6338_ENET1_IRQ             0
 #define BCM_6338_ENET_PHY_IRQ          (IRQ_INTERNAL_BASE + 9)
-#define BCM_6338_SDRAM_IRQ             (IRQ_INTERNAL_BASE + 10)
-#define BCM_6338_USB_CNTL_RX_DMA_IRQ   (IRQ_INTERNAL_BASE + 11)
-#define BCM_6338_USB_CNTL_TX_DMA_IRQ   (IRQ_INTERNAL_BASE + 12)
-#define BCM_6338_USB_BULK_RX_DMA_IRQ   (IRQ_INTERNAL_BASE + 13)
-#define BCM_6338_USB_BULK_TX_DMA_IRQ   (IRQ_INTERNAL_BASE + 14)
+#define BCM_6338_OHCI0_IRQ             0
+#define BCM_6338_EHCI0_IRQ             0
 #define BCM_6338_ENET0_RXDMA_IRQ       (IRQ_INTERNAL_BASE + 15)
 #define BCM_6338_ENET0_TXDMA_IRQ       (IRQ_INTERNAL_BASE + 16)
-#define BCM_6338_SDIO_IRQ              (IRQ_INTERNAL_BASE + 17)
+#define BCM_6338_ENET1_RXDMA_IRQ       0
+#define BCM_6338_ENET1_TXDMA_IRQ       0
+#define BCM_6338_PCI_IRQ               0
+#define BCM_6338_PCMCIA_IRQ            0
+#define BCM_6338_ATM_IRQ               0
+#define BCM_6338_ENETSW_RXDMA0_IRQ     0
+#define BCM_6338_ENETSW_RXDMA1_IRQ     0
+#define BCM_6338_ENETSW_RXDMA2_IRQ     0
+#define BCM_6338_ENETSW_RXDMA3_IRQ     0
+#define BCM_6338_ENETSW_TXDMA0_IRQ     0
+#define BCM_6338_ENETSW_TXDMA1_IRQ     0
+#define BCM_6338_ENETSW_TXDMA2_IRQ     0
+#define BCM_6338_ENETSW_TXDMA3_IRQ     0
+#define BCM_6338_XTM_IRQ               0
+#define BCM_6338_XTM_DMA0_IRQ          0
 
 /*
  * 6345 irqs
  */
 #define BCM_6345_TIMER_IRQ             (IRQ_INTERNAL_BASE + 0)
 #define BCM_6345_UART0_IRQ             (IRQ_INTERNAL_BASE + 2)
+#define BCM_6345_UART1_IRQ             0
 #define BCM_6345_DSL_IRQ               (IRQ_INTERNAL_BASE + 3)
-#define BCM_6345_ATM_IRQ               (IRQ_INTERNAL_BASE + 4)
-#define BCM_6345_USB_IRQ               (IRQ_INTERNAL_BASE + 5)
 #define BCM_6345_ENET0_IRQ             (IRQ_INTERNAL_BASE + 8)
+#define BCM_6345_ENET1_IRQ             0
 #define BCM_6345_ENET_PHY_IRQ          (IRQ_INTERNAL_BASE + 12)
+#define BCM_6345_OHCI0_IRQ             0
+#define BCM_6345_EHCI0_IRQ             0
 #define BCM_6345_ENET0_RXDMA_IRQ       (IRQ_INTERNAL_BASE + 13 + 1)
 #define BCM_6345_ENET0_TXDMA_IRQ       (IRQ_INTERNAL_BASE + 13 + 2)
-#define BCM_6345_EBI_RX_IRQ            (IRQ_INTERNAL_BASE + 13 + 5)
-#define BCM_6345_EBI_TX_IRQ            (IRQ_INTERNAL_BASE + 13 + 6)
-#define BCM_6345_RESERVED_RX_IRQ       (IRQ_INTERNAL_BASE + 13 + 9)
-#define BCM_6345_RESERVED_TX_IRQ       (IRQ_INTERNAL_BASE + 13 + 10)
-#define BCM_6345_USB_BULK_RX_DMA_IRQ   (IRQ_INTERNAL_BASE + 13 + 13)
-#define BCM_6345_USB_BULK_TX_DMA_IRQ   (IRQ_INTERNAL_BASE + 13 + 14)
-#define BCM_6345_USB_CNTL_RX_DMA_IRQ   (IRQ_INTERNAL_BASE + 13 + 15)
-#define BCM_6345_USB_CNTL_TX_DMA_IRQ   (IRQ_INTERNAL_BASE + 13 + 16)
-#define BCM_6345_USB_ISO_RX_DMA_IRQ    (IRQ_INTERNAL_BASE + 13 + 17)
-#define BCM_6345_USB_ISO_TX_DMA_IRQ    (IRQ_INTERNAL_BASE + 13 + 18)
+#define BCM_6345_ENET1_RXDMA_IRQ       0
+#define BCM_6345_ENET1_TXDMA_IRQ       0
+#define BCM_6345_PCI_IRQ               0
+#define BCM_6345_PCMCIA_IRQ            0
+#define BCM_6345_ATM_IRQ               0
+#define BCM_6345_ENETSW_RXDMA0_IRQ     0
+#define BCM_6345_ENETSW_RXDMA1_IRQ     0
+#define BCM_6345_ENETSW_RXDMA2_IRQ     0
+#define BCM_6345_ENETSW_RXDMA3_IRQ     0
+#define BCM_6345_ENETSW_TXDMA0_IRQ     0
+#define BCM_6345_ENETSW_TXDMA1_IRQ     0
+#define BCM_6345_ENETSW_TXDMA2_IRQ     0
+#define BCM_6345_ENETSW_TXDMA3_IRQ     0
+#define BCM_6345_XTM_IRQ               0
+#define BCM_6345_XTM_DMA0_IRQ          0
 
 /*
  * 6348 irqs
  */
 #define BCM_6348_TIMER_IRQ             (IRQ_INTERNAL_BASE + 0)
 #define BCM_6348_UART0_IRQ             (IRQ_INTERNAL_BASE + 2)
+#define BCM_6348_UART1_IRQ             0
 #define BCM_6348_DSL_IRQ               (IRQ_INTERNAL_BASE + 4)
-#define BCM_6348_ENET1_IRQ             (IRQ_INTERNAL_BASE + 7)
 #define BCM_6348_ENET0_IRQ             (IRQ_INTERNAL_BASE + 8)
+#define BCM_6348_ENET1_IRQ             (IRQ_INTERNAL_BASE + 7)
 #define BCM_6348_ENET_PHY_IRQ          (IRQ_INTERNAL_BASE + 9)
 #define BCM_6348_OHCI0_IRQ             (IRQ_INTERNAL_BASE + 12)
+#define BCM_6348_EHCI0_IRQ             0
 #define BCM_6348_ENET0_RXDMA_IRQ       (IRQ_INTERNAL_BASE + 20)
 #define BCM_6348_ENET0_TXDMA_IRQ       (IRQ_INTERNAL_BASE + 21)
 #define BCM_6348_ENET1_RXDMA_IRQ       (IRQ_INTERNAL_BASE + 22)
 #define BCM_6348_ENET1_TXDMA_IRQ       (IRQ_INTERNAL_BASE + 23)
-#define BCM_6348_PCMCIA_IRQ            (IRQ_INTERNAL_BASE + 24)
 #define BCM_6348_PCI_IRQ               (IRQ_INTERNAL_BASE + 24)
+#define BCM_6348_PCMCIA_IRQ            (IRQ_INTERNAL_BASE + 24)
+#define BCM_6348_ATM_IRQ               (IRQ_INTERNAL_BASE + 5)
+#define BCM_6348_ENETSW_RXDMA0_IRQ     0
+#define BCM_6348_ENETSW_RXDMA1_IRQ     0
+#define BCM_6348_ENETSW_RXDMA2_IRQ     0
+#define BCM_6348_ENETSW_RXDMA3_IRQ     0
+#define BCM_6348_ENETSW_TXDMA0_IRQ     0
+#define BCM_6348_ENETSW_TXDMA1_IRQ     0
+#define BCM_6348_ENETSW_TXDMA2_IRQ     0
+#define BCM_6348_ENETSW_TXDMA3_IRQ     0
+#define BCM_6348_XTM_IRQ               0
+#define BCM_6348_XTM_DMA0_IRQ          0
 
 /*
  * 6358 irqs
@@ -525,21 +601,108 @@ enum bcm63xx_irq {
 #define BCM_6358_TIMER_IRQ             (IRQ_INTERNAL_BASE + 0)
 #define BCM_6358_UART0_IRQ             (IRQ_INTERNAL_BASE + 2)
 #define BCM_6358_UART1_IRQ             (IRQ_INTERNAL_BASE + 3)
-#define BCM_6358_OHCI0_IRQ             (IRQ_INTERNAL_BASE + 5)
-#define BCM_6358_ENET1_IRQ             (IRQ_INTERNAL_BASE + 6)
+#define BCM_6358_DSL_IRQ               (IRQ_INTERNAL_BASE + 29)
 #define BCM_6358_ENET0_IRQ             (IRQ_INTERNAL_BASE + 8)
+#define BCM_6358_ENET1_IRQ             (IRQ_INTERNAL_BASE + 6)
 #define BCM_6358_ENET_PHY_IRQ          (IRQ_INTERNAL_BASE + 9)
+#define BCM_6358_OHCI0_IRQ             (IRQ_INTERNAL_BASE + 5)
 #define BCM_6358_EHCI0_IRQ             (IRQ_INTERNAL_BASE + 10)
 #define BCM_6358_ENET0_RXDMA_IRQ       (IRQ_INTERNAL_BASE + 15)
 #define BCM_6358_ENET0_TXDMA_IRQ       (IRQ_INTERNAL_BASE + 16)
 #define BCM_6358_ENET1_RXDMA_IRQ       (IRQ_INTERNAL_BASE + 17)
 #define BCM_6358_ENET1_TXDMA_IRQ       (IRQ_INTERNAL_BASE + 18)
-#define BCM_6358_DSL_IRQ               (IRQ_INTERNAL_BASE + 29)
 #define BCM_6358_PCI_IRQ               (IRQ_INTERNAL_BASE + 31)
 #define BCM_6358_PCMCIA_IRQ            (IRQ_INTERNAL_BASE + 24)
+#define BCM_6358_ATM_IRQ               (IRQ_INTERNAL_BASE + 19)
+#define BCM_6358_ENETSW_RXDMA0_IRQ     0
+#define BCM_6358_ENETSW_RXDMA1_IRQ     0
+#define BCM_6358_ENETSW_RXDMA2_IRQ     0
+#define BCM_6358_ENETSW_RXDMA3_IRQ     0
+#define BCM_6358_ENETSW_TXDMA0_IRQ     0
+#define BCM_6358_ENETSW_TXDMA1_IRQ     0
+#define BCM_6358_ENETSW_TXDMA2_IRQ     0
+#define BCM_6358_ENETSW_TXDMA3_IRQ     0
+#define BCM_6358_XTM_IRQ               0
+#define BCM_6358_XTM_DMA0_IRQ          0
+
+#define BCM_6358_PCM_DMA0_IRQ          (IRQ_INTERNAL_BASE + 23)
+#define BCM_6358_PCM_DMA1_IRQ          (IRQ_INTERNAL_BASE + 24)
+#define BCM_6358_EXT_IRQ0              (IRQ_INTERNAL_BASE + 25)
+#define BCM_6358_EXT_IRQ1              (IRQ_INTERNAL_BASE + 26)
+#define BCM_6358_EXT_IRQ2              (IRQ_INTERNAL_BASE + 27)
+#define BCM_6358_EXT_IRQ3              (IRQ_INTERNAL_BASE + 28)
+
+/*
+ * 6368 irqs
+ */
+#define BCM_6368_HIGH_IRQ_BASE         (IRQ_INTERNAL_BASE + 32)
+
+#define BCM_6368_TIMER_IRQ             (IRQ_INTERNAL_BASE + 0)
+#define BCM_6368_UART0_IRQ             (IRQ_INTERNAL_BASE + 2)
+#define BCM_6368_UART1_IRQ             (IRQ_INTERNAL_BASE + 3)
+#define BCM_6368_DSL_IRQ               (IRQ_INTERNAL_BASE + 4)
+#define BCM_6368_ENET0_IRQ             0
+#define BCM_6368_ENET1_IRQ             0
+#define BCM_6368_ENET_PHY_IRQ          (IRQ_INTERNAL_BASE + 15)
+#define BCM_6368_OHCI0_IRQ             (IRQ_INTERNAL_BASE + 5)
+#define BCM_6368_EHCI0_IRQ             (IRQ_INTERNAL_BASE + 7)
+#define BCM_6368_PCMCIA_IRQ            0
+#define BCM_6368_ENET0_RXDMA_IRQ       0
+#define BCM_6368_ENET0_TXDMA_IRQ       0
+#define BCM_6368_ENET1_RXDMA_IRQ       0
+#define BCM_6368_ENET1_TXDMA_IRQ       0
+#define BCM_6368_PCI_IRQ               (IRQ_INTERNAL_BASE + 13)
+#define BCM_6368_ATM_IRQ               0
+#define BCM_6368_ENETSW_RXDMA0_IRQ     (BCM_6368_HIGH_IRQ_BASE + 0)
+#define BCM_6368_ENETSW_RXDMA1_IRQ     (BCM_6368_HIGH_IRQ_BASE + 1)
+#define BCM_6368_ENETSW_RXDMA2_IRQ     (BCM_6368_HIGH_IRQ_BASE + 2)
+#define BCM_6368_ENETSW_RXDMA3_IRQ     (BCM_6368_HIGH_IRQ_BASE + 3)
+#define BCM_6368_ENETSW_TXDMA0_IRQ     (BCM_6368_HIGH_IRQ_BASE + 4)
+#define BCM_6368_ENETSW_TXDMA1_IRQ     (BCM_6368_HIGH_IRQ_BASE + 5)
+#define BCM_6368_ENETSW_TXDMA2_IRQ     (BCM_6368_HIGH_IRQ_BASE + 6)
+#define BCM_6368_ENETSW_TXDMA3_IRQ     (BCM_6368_HIGH_IRQ_BASE + 7)
+#define BCM_6368_XTM_IRQ               (IRQ_INTERNAL_BASE + 11)
+#define BCM_6368_XTM_DMA0_IRQ          (BCM_6368_HIGH_IRQ_BASE + 8)
+
+#define BCM_6368_PCM_DMA0_IRQ          (BCM_6368_HIGH_IRQ_BASE + 30)
+#define BCM_6368_PCM_DMA1_IRQ          (BCM_6368_HIGH_IRQ_BASE + 31)
+#define BCM_6368_EXT_IRQ0              (IRQ_INTERNAL_BASE + 20)
+#define BCM_6368_EXT_IRQ1              (IRQ_INTERNAL_BASE + 21)
+#define BCM_6368_EXT_IRQ2              (IRQ_INTERNAL_BASE + 22)
+#define BCM_6368_EXT_IRQ3              (IRQ_INTERNAL_BASE + 23)
+#define BCM_6368_EXT_IRQ4              (IRQ_INTERNAL_BASE + 24)
+#define BCM_6368_EXT_IRQ5              (IRQ_INTERNAL_BASE + 25)
 
 extern const int *bcm63xx_irqs;
 
+#define __GEN_CPU_IRQ_TABLE(__cpu)                                     \
+       [IRQ_TIMER]             = BCM_## __cpu ##_TIMER_IRQ,            \
+       [IRQ_UART0]             = BCM_## __cpu ##_UART0_IRQ,            \
+       [IRQ_UART1]             = BCM_## __cpu ##_UART1_IRQ,            \
+       [IRQ_DSL]               = BCM_## __cpu ##_DSL_IRQ,              \
+       [IRQ_ENET0]             = BCM_## __cpu ##_ENET0_IRQ,            \
+       [IRQ_ENET1]             = BCM_## __cpu ##_ENET1_IRQ,            \
+       [IRQ_ENET_PHY]          = BCM_## __cpu ##_ENET_PHY_IRQ,         \
+       [IRQ_OHCI0]             = BCM_## __cpu ##_OHCI0_IRQ,            \
+       [IRQ_EHCI0]             = BCM_## __cpu ##_EHCI0_IRQ,            \
+       [IRQ_ENET0_RXDMA]       = BCM_## __cpu ##_ENET0_RXDMA_IRQ,      \
+       [IRQ_ENET0_TXDMA]       = BCM_## __cpu ##_ENET0_TXDMA_IRQ,      \
+       [IRQ_ENET1_RXDMA]       = BCM_## __cpu ##_ENET1_RXDMA_IRQ,      \
+       [IRQ_ENET1_TXDMA]       = BCM_## __cpu ##_ENET1_TXDMA_IRQ,      \
+       [IRQ_PCI]               = BCM_## __cpu ##_PCI_IRQ,              \
+       [IRQ_PCMCIA]            = BCM_## __cpu ##_PCMCIA_IRQ,           \
+       [IRQ_ATM]               = BCM_## __cpu ##_ATM_IRQ,              \
+       [IRQ_ENETSW_RXDMA0]     = BCM_## __cpu ##_ENETSW_RXDMA0_IRQ,    \
+       [IRQ_ENETSW_RXDMA1]     = BCM_## __cpu ##_ENETSW_RXDMA1_IRQ,    \
+       [IRQ_ENETSW_RXDMA2]     = BCM_## __cpu ##_ENETSW_RXDMA2_IRQ,    \
+       [IRQ_ENETSW_RXDMA3]     = BCM_## __cpu ##_ENETSW_RXDMA3_IRQ,    \
+       [IRQ_ENETSW_TXDMA0]     = BCM_## __cpu ##_ENETSW_TXDMA0_IRQ,    \
+       [IRQ_ENETSW_TXDMA1]     = BCM_## __cpu ##_ENETSW_TXDMA1_IRQ,    \
+       [IRQ_ENETSW_TXDMA2]     = BCM_## __cpu ##_ENETSW_TXDMA2_IRQ,    \
+       [IRQ_ENETSW_TXDMA3]     = BCM_## __cpu ##_ENETSW_TXDMA3_IRQ,    \
+       [IRQ_XTM]               = BCM_## __cpu ##_XTM_IRQ,              \
+       [IRQ_XTM_DMA0]          = BCM_## __cpu ##_XTM_DMA0_IRQ,         \
+
 static inline int bcm63xx_get_irq_number(enum bcm63xx_irq irq)
 {
        return bcm63xx_irqs[irq];
@@ -550,4 +713,8 @@ static inline int bcm63xx_get_irq_number(enum bcm63xx_irq irq)
  */
 unsigned int bcm63xx_get_memory_size(void);
 
+void bcm63xx_machine_halt(void);
+
+void bcm63xx_machine_reboot(void);
+
 #endif /* !BCM63XX_CPU_H_ */
index 3999ec0aa7f5b99c2d57e06cb20a876a372ff06b..3d5de96d40369523940662c3400302ef9a0e48fb 100644 (file)
@@ -14,6 +14,8 @@ static inline unsigned long bcm63xx_gpio_count(void)
                return 8;
        case BCM6345_CPU_ID:
                return 16;
+       case BCM6368_CPU_ID:
+               return 38;
        case BCM6348_CPU_ID:
        default:
                return 37;
index 91180fac6ed9ce82ba5eb731e0ccb37f6f367613..72477a6441ddb9a39c769c47809878f120de027a 100644 (file)
 #define bcm_readb(a)   (*(volatile unsigned char *)    BCM_REGS_VA(a))
 #define bcm_readw(a)   (*(volatile unsigned short *)   BCM_REGS_VA(a))
 #define bcm_readl(a)   (*(volatile unsigned int *)     BCM_REGS_VA(a))
+#define bcm_readq(a)   (*(volatile u64 *)              BCM_REGS_VA(a))
 #define bcm_writeb(v, a) (*(volatile unsigned char *) BCM_REGS_VA((a)) = (v))
 #define bcm_writew(v, a) (*(volatile unsigned short *) BCM_REGS_VA((a)) = (v))
 #define bcm_writel(v, a) (*(volatile unsigned int *) BCM_REGS_VA((a)) = (v))
+#define bcm_writeq(v, a) (*(volatile u64 *) BCM_REGS_VA((a)) = (v))
 
 /*
  * IO helpers to access register set for current CPU
index 5f95577c82136ac9719b799e06cbd2eef719dfa1..0c3074b871b828efe027b57327d28d11acf47cf7 100644 (file)
@@ -3,13 +3,11 @@
 
 #include <bcm63xx_cpu.h>
 
-#define IRQ_MIPS_BASE                  0
 #define IRQ_INTERNAL_BASE              8
-
-#define IRQ_EXT_BASE                   (IRQ_MIPS_BASE + 3)
-#define IRQ_EXT_0                      (IRQ_EXT_BASE + 0)
-#define IRQ_EXT_1                      (IRQ_EXT_BASE + 1)
-#define IRQ_EXT_2                      (IRQ_EXT_BASE + 2)
-#define IRQ_EXT_3                      (IRQ_EXT_BASE + 3)
+#define IRQ_EXTERNAL_BASE              100
+#define IRQ_EXT_0                      (IRQ_EXTERNAL_BASE + 0)
+#define IRQ_EXT_1                      (IRQ_EXTERNAL_BASE + 1)
+#define IRQ_EXT_2                      (IRQ_EXTERNAL_BASE + 2)
+#define IRQ_EXT_3                      (IRQ_EXTERNAL_BASE + 3)
 
 #endif /* ! BCM63XX_IRQ_H_ */
index 0ed5230243c9efee9f010c1d12b0af620a0c2a5f..94d4faad29a1a4286c934d28e76175ca97eee935 100644 (file)
                                        CKCTL_6358_USBSU_EN |           \
                                        CKCTL_6358_EPHY_EN)
 
+#define CKCTL_6368_VDSL_QPROC_EN       (1 << 2)
+#define CKCTL_6368_VDSL_AFE_EN         (1 << 3)
+#define CKCTL_6368_VDSL_BONDING_EN     (1 << 4)
+#define CKCTL_6368_VDSL_EN             (1 << 5)
+#define CKCTL_6368_PHYMIPS_EN          (1 << 6)
+#define CKCTL_6368_SWPKT_USB_EN                (1 << 7)
+#define CKCTL_6368_SWPKT_SAR_EN                (1 << 8)
+#define CKCTL_6368_SPI_CLK_EN          (1 << 9)
+#define CKCTL_6368_USBD_CLK_EN         (1 << 10)
+#define CKCTL_6368_SAR_CLK_EN          (1 << 11)
+#define CKCTL_6368_ROBOSW_CLK_EN       (1 << 12)
+#define CKCTL_6368_UTOPIA_CLK_EN       (1 << 13)
+#define CKCTL_6368_PCM_CLK_EN          (1 << 14)
+#define CKCTL_6368_USBH_CLK_EN         (1 << 15)
+#define CKCTL_6368_DISABLE_GLESS_EN    (1 << 16)
+#define CKCTL_6368_NAND_CLK_EN         (1 << 17)
+#define CKCTL_6368_IPSEC_CLK_EN                (1 << 17)
+
+#define CKCTL_6368_ALL_SAFE_EN         (CKCTL_6368_SWPKT_USB_EN |      \
+                                       CKCTL_6368_SWPKT_SAR_EN |       \
+                                       CKCTL_6368_SPI_CLK_EN |         \
+                                       CKCTL_6368_USBD_CLK_EN |        \
+                                       CKCTL_6368_SAR_CLK_EN |         \
+                                       CKCTL_6368_ROBOSW_CLK_EN |      \
+                                       CKCTL_6368_UTOPIA_CLK_EN |      \
+                                       CKCTL_6368_PCM_CLK_EN |         \
+                                       CKCTL_6368_USBH_CLK_EN |        \
+                                       CKCTL_6368_DISABLE_GLESS_EN |   \
+                                       CKCTL_6368_NAND_CLK_EN |        \
+                                       CKCTL_6368_IPSEC_CLK_EN)
+
 /* System PLL Control register  */
 #define PERF_SYS_PLL_CTL_REG           0x8
 #define SYS_PLL_SOFT_RESET             0x1
 
 /* Interrupt Mask register */
-#define PERF_IRQMASK_REG               0xc
+#define PERF_IRQMASK_6338_REG          0xc
+#define PERF_IRQMASK_6345_REG          0xc
+#define PERF_IRQMASK_6348_REG          0xc
+#define PERF_IRQMASK_6358_REG          0xc
+#define PERF_IRQMASK_6368_REG          0x20
 
 /* Interrupt Status register */
-#define PERF_IRQSTAT_REG               0x10
+#define PERF_IRQSTAT_6338_REG          0x10
+#define PERF_IRQSTAT_6345_REG          0x10
+#define PERF_IRQSTAT_6348_REG          0x10
+#define PERF_IRQSTAT_6358_REG          0x10
+#define PERF_IRQSTAT_6368_REG          0x28
 
 /* External Interrupt Configuration register */
-#define PERF_EXTIRQ_CFG_REG            0x14
+#define PERF_EXTIRQ_CFG_REG_6338       0x14
+#define PERF_EXTIRQ_CFG_REG_6348       0x14
+#define PERF_EXTIRQ_CFG_REG_6358       0x14
+#define PERF_EXTIRQ_CFG_REG_6368       0x18
+
+#define PERF_EXTIRQ_CFG_REG2_6368      0x1c
+
+/* for 6348 only */
+#define EXTIRQ_CFG_SENSE_6348(x)       (1 << (x))
+#define EXTIRQ_CFG_STAT_6348(x)                (1 << (x + 5))
+#define EXTIRQ_CFG_CLEAR_6348(x)       (1 << (x + 10))
+#define EXTIRQ_CFG_MASK_6348(x)                (1 << (x + 15))
+#define EXTIRQ_CFG_BOTHEDGE_6348(x)    (1 << (x + 20))
+#define EXTIRQ_CFG_LEVELSENSE_6348(x)  (1 << (x + 25))
+#define EXTIRQ_CFG_CLEAR_ALL_6348      (0xf << 10)
+#define EXTIRQ_CFG_MASK_ALL_6348       (0xf << 15)
+
+/* for all others */
 #define EXTIRQ_CFG_SENSE(x)            (1 << (x))
-#define EXTIRQ_CFG_STAT(x)             (1 << (x + 5))
-#define EXTIRQ_CFG_CLEAR(x)            (1 << (x + 10))
-#define EXTIRQ_CFG_MASK(x)             (1 << (x + 15))
-#define EXTIRQ_CFG_BOTHEDGE(x)         (1 << (x + 20))
-#define EXTIRQ_CFG_LEVELSENSE(x)       (1 << (x + 25))
-
-#define EXTIRQ_CFG_CLEAR_ALL           (0xf << 10)
-#define EXTIRQ_CFG_MASK_ALL            (0xf << 15)
+#define EXTIRQ_CFG_STAT(x)             (1 << (x + 4))
+#define EXTIRQ_CFG_CLEAR(x)            (1 << (x + 8))
+#define EXTIRQ_CFG_MASK(x)             (1 << (x + 12))
+#define EXTIRQ_CFG_BOTHEDGE(x)         (1 << (x + 16))
+#define EXTIRQ_CFG_LEVELSENSE(x)       (1 << (x + 20))
+#define EXTIRQ_CFG_CLEAR_ALL           (0xf << 8)
+#define EXTIRQ_CFG_MASK_ALL            (0xf << 12)
 
 /* Soft Reset register */
 #define PERF_SOFTRESET_REG             0x28
+#define PERF_SOFTRESET_6368_REG                0x10
 
 #define SOFTRESET_6338_SPI_MASK                (1 << 0)
 #define SOFTRESET_6338_ENET_MASK       (1 << 2)
                                  SOFTRESET_6348_ACLC_MASK |            \
                                  SOFTRESET_6348_ADSLMIPSPLL_MASK)
 
+#define SOFTRESET_6368_SPI_MASK                (1 << 0)
+#define SOFTRESET_6368_MPI_MASK                (1 << 3)
+#define SOFTRESET_6368_EPHY_MASK       (1 << 6)
+#define SOFTRESET_6368_SAR_MASK                (1 << 7)
+#define SOFTRESET_6368_ENETSW_MASK     (1 << 10)
+#define SOFTRESET_6368_USBS_MASK       (1 << 11)
+#define SOFTRESET_6368_USBH_MASK       (1 << 12)
+#define SOFTRESET_6368_PCM_MASK                (1 << 13)
+
 /* MIPS PLL control register */
 #define PERF_MIPSPLLCTL_REG            0x34
 #define MIPSPLLCTL_N1_SHIFT            20
 #define GPIO_CTL_LO_REG                        0x4
 #define GPIO_DATA_HI_REG               0x8
 #define GPIO_DATA_LO_REG               0xC
+#define GPIO_DATA_LO_REG_6345          0x8
 
 /* GPIO mux registers and constants */
 #define GPIO_MODE_REG                  0x18
 #define GPIO_MODE_6358_SERIAL_LED      (1 << 10)
 #define GPIO_MODE_6358_UTOPIA          (1 << 12)
 
+#define GPIO_MODE_6368_ANALOG_AFE_0    (1 << 0)
+#define GPIO_MODE_6368_ANALOG_AFE_1    (1 << 1)
+#define GPIO_MODE_6368_SYS_IRQ         (1 << 2)
+#define GPIO_MODE_6368_SERIAL_LED_DATA (1 << 3)
+#define GPIO_MODE_6368_SERIAL_LED_CLK  (1 << 4)
+#define GPIO_MODE_6368_INET_LED                (1 << 5)
+#define GPIO_MODE_6368_EPHY0_LED       (1 << 6)
+#define GPIO_MODE_6368_EPHY1_LED       (1 << 7)
+#define GPIO_MODE_6368_EPHY2_LED       (1 << 8)
+#define GPIO_MODE_6368_EPHY3_LED       (1 << 9)
+#define GPIO_MODE_6368_ROBOSW_LED_DAT  (1 << 10)
+#define GPIO_MODE_6368_ROBOSW_LED_CLK  (1 << 11)
+#define GPIO_MODE_6368_ROBOSW_LED0     (1 << 12)
+#define GPIO_MODE_6368_ROBOSW_LED1     (1 << 13)
+#define GPIO_MODE_6368_USBD_LED                (1 << 14)
+#define GPIO_MODE_6368_NTR_PULSE       (1 << 15)
+#define GPIO_MODE_6368_PCI_REQ1                (1 << 16)
+#define GPIO_MODE_6368_PCI_GNT1                (1 << 17)
+#define GPIO_MODE_6368_PCI_INTB                (1 << 18)
+#define GPIO_MODE_6368_PCI_REQ0                (1 << 19)
+#define GPIO_MODE_6368_PCI_GNT0                (1 << 20)
+#define GPIO_MODE_6368_PCMCIA_CD1      (1 << 22)
+#define GPIO_MODE_6368_PCMCIA_CD2      (1 << 23)
+#define GPIO_MODE_6368_PCMCIA_VS1      (1 << 24)
+#define GPIO_MODE_6368_PCMCIA_VS2      (1 << 25)
+#define GPIO_MODE_6368_EBI_CS2         (1 << 26)
+#define GPIO_MODE_6368_EBI_CS3         (1 << 27)
+#define GPIO_MODE_6368_SPI_SSN2                (1 << 28)
+#define GPIO_MODE_6368_SPI_SSN3                (1 << 29)
+#define GPIO_MODE_6368_SPI_SSN4                (1 << 30)
+#define GPIO_MODE_6368_SPI_SSN5                (1 << 31)
+
+
+#define GPIO_BASEMODE_6368_REG         0x38
+#define GPIO_BASEMODE_6368_UART2       0x1
+#define GPIO_BASEMODE_6368_GPIO                0x0
+#define GPIO_BASEMODE_6368_MASK                0x7
+/* those bits must be kept as read in gpio basemode register*/
 
 /*************************************************************************
  * _REG relative to RSET_ENET
 #define ENETDMA_SRAM4_REG(x)           (0x20c + (x) * 0x10)
 
 
+/*************************************************************************
+ * _REG relative to RSET_ENETDMAC
+ *************************************************************************/
+
+/* Channel Configuration register */
+#define ENETDMAC_CHANCFG_REG(x)                ((x) * 0x10)
+#define ENETDMAC_CHANCFG_EN_SHIFT      0
+#define ENETDMAC_CHANCFG_EN_MASK       (1 << ENETDMA_CHANCFG_EN_SHIFT)
+#define ENETDMAC_CHANCFG_PKTHALT_SHIFT 1
+#define ENETDMAC_CHANCFG_PKTHALT_MASK  (1 << ENETDMA_CHANCFG_PKTHALT_SHIFT)
+
+/* Interrupt Control/Status register */
+#define ENETDMAC_IR_REG(x)             (0x4 + (x) * 0x10)
+#define ENETDMAC_IR_BUFDONE_MASK       (1 << 0)
+#define ENETDMAC_IR_PKTDONE_MASK       (1 << 1)
+#define ENETDMAC_IR_NOTOWNER_MASK      (1 << 2)
+
+/* Interrupt Mask register */
+#define ENETDMAC_IRMASK_REG(x)         (0x8 + (x) * 0x10)
+
+/* Maximum Burst Length */
+#define ENETDMAC_MAXBURST_REG(x)       (0xc + (x) * 0x10)
+
+
+/*************************************************************************
+ * _REG relative to RSET_ENETDMAS
+ *************************************************************************/
+
+/* Ring Start Address register */
+#define ENETDMAS_RSTART_REG(x)         ((x) * 0x10)
+
+/* State Ram Word 2 */
+#define ENETDMAS_SRAM2_REG(x)          (0x4 + (x) * 0x10)
+
+/* State Ram Word 3 */
+#define ENETDMAS_SRAM3_REG(x)          (0x8 + (x) * 0x10)
+
+/* State Ram Word 4 */
+#define ENETDMAS_SRAM4_REG(x)          (0xc + (x) * 0x10)
+
+
+/*************************************************************************
+ * _REG relative to RSET_ENETSW
+ *************************************************************************/
+
+/* MIB register */
+#define ENETSW_MIB_REG(x)              (0x2800 + (x) * 4)
+#define ENETSW_MIB_REG_COUNT           47
+
+
 /*************************************************************************
  * _REG relative to RSET_OHCI_PRIV
  *************************************************************************/
  * _REG relative to RSET_USBH_PRIV
  *************************************************************************/
 
-#define USBH_PRIV_SWAP_REG             0x0
+#define USBH_PRIV_SWAP_6358_REG                0x0
+#define USBH_PRIV_SWAP_6368_REG                0x1c
+
 #define USBH_PRIV_SWAP_EHCI_ENDN_SHIFT 4
 #define USBH_PRIV_SWAP_EHCI_ENDN_MASK  (1 << USBH_PRIV_SWAP_EHCI_ENDN_SHIFT)
 #define USBH_PRIV_SWAP_EHCI_DATA_SHIFT 3
 #define USBH_PRIV_SWAP_OHCI_DATA_SHIFT 0
 #define USBH_PRIV_SWAP_OHCI_DATA_MASK  (1 << USBH_PRIV_SWAP_OHCI_DATA_SHIFT)
 
-#define USBH_PRIV_TEST_REG             0x24
+#define USBH_PRIV_TEST_6358_REG                0x24
+#define USBH_PRIV_TEST_6368_REG                0x14
+
+#define USBH_PRIV_SETUP_6368_REG       0x28
+#define USBH_PRIV_SETUP_IOC_SHIFT      4
+#define USBH_PRIV_SETUP_IOC_MASK       (1 << USBH_PRIV_SETUP_IOC_SHIFT)
+
 
 
 /*************************************************************************
 #define SDRAM_CFG_BANK_SHIFT           13
 #define SDRAM_CFG_BANK_MASK            (1 << SDRAM_CFG_BANK_SHIFT)
 
+#define SDRAM_MBASE_REG                        0xc
+
 #define SDRAM_PRIO_REG                 0x2C
 #define SDRAM_PRIO_MIPS_SHIFT          29
 #define SDRAM_PRIO_MIPS_MASK           (1 << SDRAM_PRIO_MIPS_SHIFT)
 #define DMIPSPLLCFG_N2_SHIFT           29
 #define DMIPSPLLCFG_N2_MASK            (0x7 << DMIPSPLLCFG_N2_SHIFT)
 
+#define DDR_DMIPSPLLCFG_6368_REG       0x20
+#define DMIPSPLLCFG_6368_P1_SHIFT      0
+#define DMIPSPLLCFG_6368_P1_MASK       (0xf << DMIPSPLLCFG_6368_P1_SHIFT)
+#define DMIPSPLLCFG_6368_P2_SHIFT      4
+#define DMIPSPLLCFG_6368_P2_MASK       (0xf << DMIPSPLLCFG_6368_P2_SHIFT)
+#define DMIPSPLLCFG_6368_NDIV_SHIFT    16
+#define DMIPSPLLCFG_6368_NDIV_MASK     (0x1ff << DMIPSPLLCFG_6368_NDIV_SHIFT)
+
+#define DDR_DMIPSPLLDIV_6368_REG       0x24
+#define DMIPSPLLDIV_6368_MDIV_SHIFT    0
+#define DMIPSPLLDIV_6368_MDIV_MASK     (0xff << DMIPSPLLDIV_6368_MDIV_SHIFT)
+
+
+/*************************************************************************
+ * _REG relative to RSET_M2M
+ *************************************************************************/
+
+#define M2M_RX                         0
+#define M2M_TX                         1
+
+#define M2M_SRC_REG(x)                 ((x) * 0x40 + 0x00)
+#define M2M_DST_REG(x)                 ((x) * 0x40 + 0x04)
+#define M2M_SIZE_REG(x)                        ((x) * 0x40 + 0x08)
+
+#define M2M_CTRL_REG(x)                        ((x) * 0x40 + 0x0c)
+#define M2M_CTRL_ENABLE_MASK           (1 << 0)
+#define M2M_CTRL_IRQEN_MASK            (1 << 1)
+#define M2M_CTRL_ERROR_CLR_MASK                (1 << 6)
+#define M2M_CTRL_DONE_CLR_MASK         (1 << 7)
+#define M2M_CTRL_NOINC_MASK            (1 << 8)
+#define M2M_CTRL_PCMCIASWAP_MASK       (1 << 9)
+#define M2M_CTRL_SWAPBYTE_MASK         (1 << 10)
+#define M2M_CTRL_ENDIAN_MASK           (1 << 11)
+
+#define M2M_STAT_REG(x)                        ((x) * 0x40 + 0x10)
+#define M2M_STAT_DONE                  (1 << 0)
+#define M2M_STAT_ERROR                 (1 << 1)
+
+#define M2M_SRCID_REG(x)               ((x) * 0x40 + 0x14)
+#define M2M_DSTID_REG(x)               ((x) * 0x40 + 0x18)
+
 #endif /* BCM63XX_REGS_H_ */
diff --git a/arch/mips/include/asm/mach-bcm63xx/ioremap.h b/arch/mips/include/asm/mach-bcm63xx/ioremap.h
new file mode 100644 (file)
index 0000000..ef94ba7
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef BCM63XX_IOREMAP_H_
+#define BCM63XX_IOREMAP_H_
+
+#include <bcm63xx_cpu.h>
+
+static inline phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size)
+{
+       return phys_addr;
+}
+
+static inline int is_bcm63xx_internal_registers(phys_t offset)
+{
+       switch (bcm63xx_get_cpu_id()) {
+       case BCM6338_CPU_ID:
+       case BCM6345_CPU_ID:
+       case BCM6348_CPU_ID:
+       case BCM6358_CPU_ID:
+               if (offset >= 0xfff00000)
+                       return 1;
+               break;
+       case BCM6368_CPU_ID:
+               if (offset >= 0xb0000000 && offset < 0xb1000000)
+                       return 1;
+               break;
+       }
+       return 0;
+}
+
+static inline void __iomem *plat_ioremap(phys_t offset, unsigned long size,
+                                        unsigned long flags)
+{
+       if (is_bcm63xx_internal_registers(offset))
+               return (void __iomem *)offset;
+       return NULL;
+}
+
+static inline int plat_iounmap(const volatile void __iomem *addr)
+{
+       return is_bcm63xx_internal_registers((unsigned long)addr);
+}
+
+#endif /* BCM63XX_IOREMAP_H_ */
diff --git a/arch/mips/include/asm/mach-bcm63xx/irq.h b/arch/mips/include/asm/mach-bcm63xx/irq.h
new file mode 100644 (file)
index 0000000..9332e78
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_BCM63XX_IRQ_H
+#define __ASM_MACH_BCM63XX_IRQ_H
+
+#define NR_IRQS        128
+#define MIPS_CPU_IRQ_BASE 0
+
+#endif
index 618d2de02ed35c638a7fa28d97823ca439f83bea..bb9fc23d853a675e8aa978eb1a4bd26f4919782d 100644 (file)
@@ -34,6 +34,8 @@
 #define PB1200_BCSR_PHYS_ADDR  0x0D800000
 #define PB1200_BCSR_HEXLED_OFS 0x00400000
 
+#define DB1300_BCSR_PHYS_ADDR  0x19800000
+#define DB1300_BCSR_HEXLED_OFS 0x00400000
 
 enum bcsr_id {
        /* BCSR base 1 */
@@ -105,6 +107,7 @@ enum bcsr_whoami_boards {
        BCSR_WHOAMI_PB1200 = BCSR_WHOAMI_PB1200_DDR1,
        BCSR_WHOAMI_PB1200_DDR2,
        BCSR_WHOAMI_DB1200,
+       BCSR_WHOAMI_DB1300,
 };
 
 /* STATUS reg.  Unless otherwise noted, they're valid on all boards.
@@ -118,12 +121,12 @@ enum bcsr_whoami_boards {
 #define BCSR_STATUS_SRAMWIDTH          0x0080
 #define BCSR_STATUS_FLASHBUSY          0x0100
 #define BCSR_STATUS_ROMBUSY            0x0400
-#define BCSR_STATUS_SD0WP              0x0400  /* DB1200 */
+#define BCSR_STATUS_SD0WP              0x0400  /* DB1200/DB1300:SD1 */
 #define BCSR_STATUS_SD1WP              0x0800
 #define BCSR_STATUS_USBOTGID           0x0800  /* PB/DB1550 */
 #define BCSR_STATUS_DB1000_SWAPBOOT    0x2000
-#define BCSR_STATUS_DB1200_SWAPBOOT    0x0040  /* DB1200 */
-#define BCSR_STATUS_IDECBLID           0x0200  /* DB1200 */
+#define BCSR_STATUS_DB1200_SWAPBOOT    0x0040  /* DB1200/1300 */
+#define BCSR_STATUS_IDECBLID           0x0200  /* DB1200/1300 */
 #define BCSR_STATUS_DB1200_U0RXD       0x1000  /* DB1200 */
 #define BCSR_STATUS_DB1200_U1RXD       0x2000  /* DB1200 */
 #define BCSR_STATUS_FLASHDEN           0xC000
@@ -133,6 +136,11 @@ enum bcsr_whoami_boards {
 #define BCSR_STATUS_PB1550_U1RXD       0x2000  /* PB1550 */
 #define BCSR_STATUS_PB1550_U3RXD       0x8000  /* PB1550 */
 
+#define BCSR_STATUS_CFWP               0x4000  /* DB1300 */
+#define BCSR_STATUS_USBOCn             0x2000  /* DB1300 */
+#define BCSR_STATUS_OTGOCn             0x1000  /* DB1300 */
+#define BCSR_STATUS_DCDMARQ            0x0010  /* DB1300 */
+#define BCSR_STATUS_IDEDMARQ           0x0020  /* DB1300 */
 
 /* DB/PB1000,1100,1500,1550 */
 #define BCSR_RESETS_PHY0               0x0001
@@ -155,17 +163,17 @@ enum bcsr_whoami_boards {
 #define BCSR_BOARD_GPIO200RST          0x0400
 #define BCSR_BOARD_PCICLKOUT           0x0800
 #define BCSR_BOARD_PCICFG              0x1000
-#define BCSR_BOARD_SPISEL              0x4000  /* PB/DB1550 */
+#define BCSR_BOARD_SPISEL              0x2000  /* PB/DB1550 */
 #define BCSR_BOARD_SD0WP               0x4000  /* DB1100 */
 #define BCSR_BOARD_SD1WP               0x8000  /* DB1100 */
 
 
-/* DB/PB1200 */
+/* DB/PB1200/1300 */
 #define BCSR_RESETS_ETH                        0x0001
 #define BCSR_RESETS_CAMERA             0x0002
 #define BCSR_RESETS_DC                 0x0004
 #define BCSR_RESETS_IDE                        0x0008
-#define BCSR_RESETS_TV                 0x0010  /* DB1200 */
+#define BCSR_RESETS_TV                 0x0010  /* DB1200/1300 */
 /* Not resets but in the same register */
 #define BCSR_RESETS_PWMR1MUX           0x0800  /* DB1200 */
 #define BCSR_RESETS_PB1200_WSCFSM      0x0800  /* PB1200 */
@@ -174,13 +182,22 @@ enum bcsr_whoami_boards {
 #define BCSR_RESETS_SPISEL             0x4000
 #define BCSR_RESETS_SD1MUX             0x8000  /* PB1200 */
 
+#define BCSR_RESETS_VDDQSHDN           0x0200  /* DB1300 */
+#define BCSR_RESETS_OTPPGM             0x0400  /* DB1300 */
+#define BCSR_RESETS_OTPSCLK            0x0800  /* DB1300 */
+#define BCSR_RESETS_OTPWRPROT          0x1000  /* DB1300 */
+#define BCSR_RESETS_OTPCSB             0x2000  /* DB1300 */
+#define BCSR_RESETS_OTGPWR             0x4000  /* DB1300 */
+#define BCSR_RESETS_USBHPWR            0x8000  /* DB1300 */
+
 #define BCSR_BOARD_LCDVEE              0x0001
 #define BCSR_BOARD_LCDVDD              0x0002
 #define BCSR_BOARD_LCDBL               0x0004
 #define BCSR_BOARD_CAMSNAP             0x0010
 #define BCSR_BOARD_CAMPWR              0x0020
 #define BCSR_BOARD_SD0PWR              0x0040
-
+#define BCSR_BOARD_CAMCS               0x0010  /* DB1300 */
+#define BCSR_BOARD_HDMI_DE             0x0040  /* DB1300 */
 
 #define BCSR_SWITCHES_DIP              0x00FF
 #define BCSR_SWITCHES_DIP_1            0x0080
@@ -214,7 +231,10 @@ enum bcsr_whoami_boards {
 #define BCSR_SYSTEM_RESET              0x8000  /* clear to reset */
 #define BCSR_SYSTEM_PWROFF             0x4000  /* set to power off */
 #define BCSR_SYSTEM_VDDI               0x001F  /* PB1xxx boards */
-
+#define BCSR_SYSTEM_DEBUGCSMASK                0x003F  /* DB1300 */
+#define BCSR_SYSTEM_UDMAMODE           0x0100  /* DB1300 */
+#define BCSR_SYSTEM_WAKEONIRQ          0x0200  /* DB1300 */
+#define BCSR_SYSTEM_VDDI1300           0x3C00  /* DB1300 */
 
 
 
index 7a39657108c4a5d7f5ee2d8dba99d6a1b9713f1c..b2a8319521e5ed253d4f18d6c513968dd8cd1b7d 100644 (file)
 #define BCSR_INT_PC1EJECT      0x0800
 #define BCSR_INT_SD0INSERT     0x1000
 #define BCSR_INT_SD0EJECT      0x2000
+#define BCSR_INT_SD1INSERT     0x4000
+#define BCSR_INT_SD1EJECT      0x8000
 
-#define IDE_PHYS_ADDR          0x18800000
 #define IDE_REG_SHIFT          5
 
-#define DB1200_IDE_PHYS_ADDR   IDE_PHYS_ADDR
+#define DB1200_IDE_PHYS_ADDR   0x18800000
 #define DB1200_IDE_PHYS_LEN    (16 << IDE_REG_SHIFT)
 #define DB1200_ETH_PHYS_ADDR   0x19000300
 #define DB1200_NAND_PHYS_ADDR  0x20000000
 
+#define PB1200_IDE_PHYS_ADDR   0x0C800000
+#define PB1200_ETH_PHYS_ADDR   0x0D000300
+#define PB1200_NAND_PHYS_ADDR  0x1C000000
+
 /*
  * External Interrupts for DBAu1200 as of 8/6/2004.
  * Bit positions in the CPLD registers can be calculated by taking
@@ -77,6 +82,8 @@ enum external_db1200_ints {
        DB1200_PC1_EJECT_INT,
        DB1200_SD0_INSERT_INT,
        DB1200_SD0_EJECT_INT,
+       PB1200_SD1_INSERT_INT,
+       PB1200_SD1_EJECT_INT,
 
        DB1200_INT_END          = DB1200_INT_BEGIN + 15,
 };
diff --git a/arch/mips/include/asm/mach-db1x00/db1300.h b/arch/mips/include/asm/mach-db1x00/db1300.h
new file mode 100644 (file)
index 0000000..7fe5fb3
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * NetLogic DB1300 board constants
+ */
+
+#ifndef _DB1300_H_
+#define _DB1300_H_
+
+/* FPGA (external mux) interrupt sources */
+#define DB1300_FIRST_INT       (ALCHEMY_GPIC_INT_LAST + 1)
+#define DB1300_IDE_INT         (DB1300_FIRST_INT + 0)
+#define DB1300_ETH_INT         (DB1300_FIRST_INT + 1)
+#define DB1300_CF_INT          (DB1300_FIRST_INT + 2)
+#define DB1300_VIDEO_INT       (DB1300_FIRST_INT + 4)
+#define DB1300_HDMI_INT                (DB1300_FIRST_INT + 5)
+#define DB1300_DC_INT          (DB1300_FIRST_INT + 6)
+#define DB1300_FLASH_INT       (DB1300_FIRST_INT + 7)
+#define DB1300_CF_INSERT_INT   (DB1300_FIRST_INT + 8)
+#define DB1300_CF_EJECT_INT    (DB1300_FIRST_INT + 9)
+#define DB1300_AC97_INT                (DB1300_FIRST_INT + 10)
+#define DB1300_AC97_PEN_INT    (DB1300_FIRST_INT + 11)
+#define DB1300_SD1_INSERT_INT  (DB1300_FIRST_INT + 12)
+#define DB1300_SD1_EJECT_INT   (DB1300_FIRST_INT + 13)
+#define DB1300_OTG_VBUS_OC_INT (DB1300_FIRST_INT + 14)
+#define DB1300_HOST_VBUS_OC_INT        (DB1300_FIRST_INT + 15)
+#define DB1300_LAST_INT                (DB1300_FIRST_INT + 15)
+
+/* SMSC9210 CS */
+#define DB1300_ETH_PHYS_ADDR   0x19000000
+#define DB1300_ETH_PHYS_END    0x197fffff
+
+/* ATA CS */
+#define DB1300_IDE_PHYS_ADDR   0x18800000
+#define DB1300_IDE_REG_SHIFT   5
+#define DB1300_IDE_PHYS_LEN    (16 << DB1300_IDE_REG_SHIFT)
+
+/* NAND CS */
+#define DB1300_NAND_PHYS_ADDR  0x20000000
+#define DB1300_NAND_PHYS_END   0x20000fff
+
+#endif /* _DB1300_H_ */
diff --git a/arch/mips/include/asm/mach-db1x00/db1x00.h b/arch/mips/include/asm/mach-db1x00/db1x00.h
deleted file mode 100644 (file)
index a5affb0..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * AMD Alchemy DBAu1x00 Reference Boards
- *
- * Copyright 2001, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.com>
- * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- *
- */
-#ifndef __ASM_DB1X00_H
-#define __ASM_DB1X00_H
-
-#include <asm/mach-au1x00/au1xxx_psc.h>
-
-#ifdef CONFIG_MIPS_DB1550
-
-#define DBDMA_AC97_TX_CHAN     AU1550_DSCR_CMD0_PSC1_TX
-#define DBDMA_AC97_RX_CHAN     AU1550_DSCR_CMD0_PSC1_RX
-#define DBDMA_I2S_TX_CHAN      AU1550_DSCR_CMD0_PSC3_TX
-#define DBDMA_I2S_RX_CHAN      AU1550_DSCR_CMD0_PSC3_RX
-
-#define SPI_PSC_BASE           AU1550_PSC0_PHYS_ADDR
-#define AC97_PSC_BASE          AU1550_PSC1_PHYS_ADDR
-#define SMBUS_PSC_BASE         AU1550_PSC2_PHYS_ADDR
-#define I2S_PSC_BASE           AU1550_PSC3_PHYS_ADDR
-
-#define NAND_PHYS_ADDR         0x20000000
-
-#endif
-
-/*
- * NAND defines
- *
- * Timing values as described in databook, * ns value stripped of the
- * lower 2 bits.
- * These defines are here rather than an Au1550 generic file because
- * the parts chosen on another board may be different and may require
- * different timings.
- */
-#define NAND_T_H               (18 >> 2)
-#define NAND_T_PUL             (30 >> 2)
-#define NAND_T_SU              (30 >> 2)
-#define NAND_T_WH              (30 >> 2)
-
-/* Bitfield shift amounts */
-#define NAND_T_H_SHIFT         0
-#define NAND_T_PUL_SHIFT       4
-#define NAND_T_SU_SHIFT                8
-#define NAND_T_WH_SHIFT                12
-
-#define NAND_TIMING    (((NAND_T_H   & 0xF) << NAND_T_H_SHIFT)   | \
-                        ((NAND_T_PUL & 0xF) << NAND_T_PUL_SHIFT) | \
-                        ((NAND_T_SU  & 0xF) << NAND_T_SU_SHIFT)  | \
-                        ((NAND_T_WH  & 0xF) << NAND_T_WH_SHIFT))
-#define NAND_CS        1
-
-/* Should be done by YAMON */
-#define NAND_STCFG     0x00400005 /* 8-bit NAND */
-#define NAND_STTIME    0x00007774 /* valid for 396 MHz SD=2 only */
-#define NAND_STADDR    0x12000FFF /* physical address 0x20000000 */
-
-#endif /* __ASM_DB1X00_H */
diff --git a/arch/mips/include/asm/mach-db1x00/irq.h b/arch/mips/include/asm/mach-db1x00/irq.h
new file mode 100644 (file)
index 0000000..15b2669
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 by Ralf Baechle
+ */
+#ifndef __ASM_MACH_GENERIC_IRQ_H
+#define __ASM_MACH_GENERIC_IRQ_H
+
+
+#ifdef NR_IRQS
+#undef NR_IRQS
+#endif
+
+#ifndef MIPS_CPU_IRQ_BASE
+#define MIPS_CPU_IRQ_BASE 0
+#endif
+
+/* 8 (MIPS) + 128 (au1300) + 16 (cpld) */
+#define NR_IRQS 152
+
+#endif /* __ASM_MACH_GENERIC_IRQ_H */
index 001a8ce17c1733f390291451b5c87985efbd97dd..a38f4d43e5e575e8ad47145ae5c5b3729f284488 100644 (file)
@@ -98,7 +98,7 @@ static inline void fd_disable_irq(void)
 static inline int fd_request_irq(void)
 {
        return request_irq(FLOPPY_IRQ, floppy_interrupt,
-                          IRQF_DISABLED, "floppy", NULL);
+                          0, "floppy", NULL);
 }
 
 static inline void fd_free_irq(void)
index 56e9ca6ae426b28923c57f084b82ede0411193db..88b5acb751456ce520501b387088cbf4b1150be7 100644 (file)
@@ -90,7 +90,7 @@ static inline void fd_disable_irq(void)
 static inline int fd_request_irq(void)
 {
        return request_irq(FLOPPY_IRQ, floppy_interrupt,
-                          IRQF_DISABLED, "floppy", NULL);
+                          0, "floppy", NULL);
 }
 
 static inline void fd_free_irq(void)
index 3b728275b9b0bf1a004fdf40bacf119650f9428e..d193fb68cf270d66e734fc7ef88613417cdb94be 100644 (file)
 
 #define cpu_has_llsc           1
 #define cpu_has_vtag_icache    0
-#define cpu_has_dc_aliases     0
-#define cpu_has_ic_fills_f_dc  0
+#define cpu_has_ic_fills_f_dc  1
 #define cpu_has_dsp            0
 #define cpu_has_mipsmt         0
-#define cpu_has_userlocal      0
-#define cpu_icache_snoops_remote_store 0
+#define cpu_icache_snoops_remote_store 1
 
-#define cpu_has_nofpuex                0
 #define cpu_has_64bits         1
 
 #define cpu_has_mips32r1       1
-#define cpu_has_mips32r2       0
 #define cpu_has_mips64r1       1
-#define cpu_has_mips64r2       0
 
 #define cpu_has_inclusive_pcaches      0
 
 #define cpu_dcache_line_size() 32
 #define cpu_icache_line_size() 32
 
+#if defined(CONFIG_CPU_XLR)
+#define cpu_has_userlocal      0
+#define cpu_has_dc_aliases     0
+#define cpu_has_mips32r2       0
+#define cpu_has_mips64r2       0
+#elif defined(CONFIG_CPU_XLP)
+#define cpu_has_userlocal      1
+#define cpu_has_mips32r2       1
+#define cpu_has_mips64r2       1
+#define cpu_has_dc_aliases     1
+#else
+#error "Unknown Netlogic CPU"
+#endif
+
 #endif /* __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H */
diff --git a/arch/mips/include/asm/mach-pb1x00/mc146818rtc.h b/arch/mips/include/asm/mach-pb1x00/mc146818rtc.h
deleted file mode 100644 (file)
index 622c587..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1998, 2001, 03 by Ralf Baechle
- *
- * RTC routines for PC style attached Dallas chip.
- */
-#ifndef __ASM_MACH_AU1XX_MC146818RTC_H
-#define __ASM_MACH_AU1XX_MC146818RTC_H
-
-#include <asm/io.h>
-#include <asm/mach-au1x00/au1000.h>
-
-#define RTC_PORT(x)    (0x0c000000 + (x))
-#define RTC_IRQ                8
-#define PB1500_RTC_ADDR 0x0c000000
-
-static inline unsigned char CMOS_READ(unsigned long offset)
-{
-       offset <<= 2;
-       return (u8)(au_readl(offset + PB1500_RTC_ADDR) & 0xff);
-}
-
-static inline void CMOS_WRITE(unsigned char data, unsigned long offset)
-{
-       offset <<= 2;
-       au_writel(data, offset + PB1500_RTC_ADDR);
-}
-
-#define RTC_ALWAYS_BCD 1
-
-#endif /* __ASM_MACH_AU1XX_MC146818RTC_H */
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1000.h b/arch/mips/include/asm/mach-pb1x00/pb1000.h
deleted file mode 100644 (file)
index 6505925..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Alchemy Semi Pb1000 Reference Board
- *
- * Copyright 2001, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.com>
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- *
- */
-#ifndef __ASM_PB1000_H
-#define __ASM_PB1000_H
-
-/* PCMCIA PB1000 specific defines */
-#define PCMCIA_MAX_SOCK  1
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-
-#define PB1000_PCR             0xBE000000
-#  define PCR_SLOT_0_VPP0      (1 << 0)
-#  define PCR_SLOT_0_VPP1      (1 << 1)
-#  define PCR_SLOT_0_VCC0      (1 << 2)
-#  define PCR_SLOT_0_VCC1      (1 << 3)
-#  define PCR_SLOT_0_RST       (1 << 4)
-#  define PCR_SLOT_1_VPP0      (1 << 8)
-#  define PCR_SLOT_1_VPP1      (1 << 9)
-#  define PCR_SLOT_1_VCC0      (1 << 10)
-#  define PCR_SLOT_1_VCC1      (1 << 11)
-#  define PCR_SLOT_1_RST       (1 << 12)
-
-#define PB1000_MDR             0xBE000004
-#  define MDR_PI               (1 << 5)        /* PCMCIA int latch  */
-#  define MDR_EPI              (1 << 14)       /* enable PCMCIA int */
-#  define MDR_CPI              (1 << 15)       /* clear  PCMCIA int  */
-
-#define PB1000_ACR1            0xBE000008
-#  define ACR1_SLOT_0_CD1      (1 << 0)        /* card detect 1        */
-#  define ACR1_SLOT_0_CD2      (1 << 1)        /* card detect 2        */
-#  define ACR1_SLOT_0_READY    (1 << 2)        /* ready                */
-#  define ACR1_SLOT_0_STATUS   (1 << 3)        /* status change        */
-#  define ACR1_SLOT_0_VS1      (1 << 4)        /* voltage sense 1      */
-#  define ACR1_SLOT_0_VS2      (1 << 5)        /* voltage sense 2      */
-#  define ACR1_SLOT_0_INPACK   (1 << 6)        /* inpack pin status    */
-#  define ACR1_SLOT_1_CD1      (1 << 8)        /* card detect 1        */
-#  define ACR1_SLOT_1_CD2      (1 << 9)        /* card detect 2        */
-#  define ACR1_SLOT_1_READY    (1 << 10)       /* ready                */
-#  define ACR1_SLOT_1_STATUS   (1 << 11)       /* status change        */
-#  define ACR1_SLOT_1_VS1      (1 << 12)       /* voltage sense 1      */
-#  define ACR1_SLOT_1_VS2      (1 << 13)       /* voltage sense 2      */
-#  define ACR1_SLOT_1_INPACK   (1 << 14)       /* inpack pin status    */
-
-#define CPLD_AUX0              0xBE00000C
-#define CPLD_AUX1              0xBE000010
-#define CPLD_AUX2              0xBE000014
-
-/* Voltage levels */
-
-/* VPPEN1 - VPPEN0 */
-#define VPP_GND ((0 << 1) | (0 << 0))
-#define VPP_5V ((1 << 1) | (0 << 0))
-#define VPP_3V ((0 << 1) | (1 << 0))
-#define VPP_12V ((0 << 1) | (1 << 0))
-#define VPP_HIZ ((1 << 1) | (1 << 0))
-
-/* VCCEN1 - VCCEN0 */
-#define VCC_3V ((0 << 1) | (1 << 0))
-#define VCC_5V ((1 << 1) | (0 << 0))
-#define VCC_HIZ ((0 << 1) | (0 << 0))
-
-/* VPP/VCC */
-#define SET_VCC_VPP(VCC, VPP, SLOT) \
-       ((((VCC) << 2) | ((VPP) << 0)) << ((SLOT) * 8))
-#endif /* __ASM_PB1000_H */
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1200.h b/arch/mips/include/asm/mach-pb1x00/pb1200.h
deleted file mode 100644 (file)
index 374416a..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * AMD Alchemy Pb1200 Reference Board
- * Board Registers defines.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- *
- */
-#ifndef __ASM_PB1200_H
-#define __ASM_PB1200_H
-
-#include <linux/types.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1xxx_psc.h>
-
-#define DBDMA_AC97_TX_CHAN     AU1200_DSCR_CMD0_PSC1_TX
-#define DBDMA_AC97_RX_CHAN     AU1200_DSCR_CMD0_PSC1_RX
-#define DBDMA_I2S_TX_CHAN      AU1200_DSCR_CMD0_PSC1_TX
-#define DBDMA_I2S_RX_CHAN      AU1200_DSCR_CMD0_PSC1_RX
-
-/*
- * SPI and SMB are muxed on the Pb1200 board.
- * Refer to board documentation.
- */
-#define SPI_PSC_BASE           AU1550_PSC0_PHYS_ADDR
-#define SMBUS_PSC_BASE         AU1550_PSC0_PHYS_ADDR
-/*
- * AC97 and I2S are muxed on the Pb1200 board.
- * Refer to board documentation.
- */
-#define AC97_PSC_BASE       AU1550_PSC1_PHYS_ADDR
-#define I2S_PSC_BASE   AU1550_PSC1_PHYS_ADDR
-
-
-#define BCSR_SYSTEM_VDDI       0x001F
-#define BCSR_SYSTEM_POWEROFF   0x4000
-#define BCSR_SYSTEM_RESET      0x8000
-
-/* Bit positions for the different interrupt sources */
-#define BCSR_INT_IDE           0x0001
-#define BCSR_INT_ETH           0x0002
-#define BCSR_INT_PC0           0x0004
-#define BCSR_INT_PC0STSCHG     0x0008
-#define BCSR_INT_PC1           0x0010
-#define BCSR_INT_PC1STSCHG     0x0020
-#define BCSR_INT_DC            0x0040
-#define BCSR_INT_FLASHBUSY     0x0080
-#define BCSR_INT_PC0INSERT     0x0100
-#define BCSR_INT_PC0EJECT      0x0200
-#define BCSR_INT_PC1INSERT     0x0400
-#define BCSR_INT_PC1EJECT      0x0800
-#define BCSR_INT_SD0INSERT     0x1000
-#define BCSR_INT_SD0EJECT      0x2000
-#define BCSR_INT_SD1INSERT     0x4000
-#define BCSR_INT_SD1EJECT      0x8000
-
-#define SMC91C111_PHYS_ADDR    0x0D000300
-#define SMC91C111_INT          PB1200_ETH_INT
-
-#define IDE_PHYS_ADDR          0x0C800000
-#define IDE_REG_SHIFT          5
-#define IDE_PHYS_LEN           (16 << IDE_REG_SHIFT)
-#define IDE_INT                PB1200_IDE_INT
-
-#define NAND_PHYS_ADDR         0x1C000000
-
-/*
- * Timing values as described in databook, * ns value stripped of
- * lower 2 bits.
- * These defines are here rather than an Au1200 generic file because
- * the parts chosen on another board may be different and may require
- * different timings.
- */
-#define NAND_T_H               (18 >> 2)
-#define NAND_T_PUL             (30 >> 2)
-#define NAND_T_SU              (30 >> 2)
-#define NAND_T_WH              (30 >> 2)
-
-/* Bitfield shift amounts */
-#define NAND_T_H_SHIFT         0
-#define NAND_T_PUL_SHIFT       4
-#define NAND_T_SU_SHIFT                8
-#define NAND_T_WH_SHIFT                12
-
-#define NAND_TIMING    (((NAND_T_H   & 0xF) << NAND_T_H_SHIFT)   | \
-                        ((NAND_T_PUL & 0xF) << NAND_T_PUL_SHIFT) | \
-                        ((NAND_T_SU  & 0xF) << NAND_T_SU_SHIFT)  | \
-                        ((NAND_T_WH  & 0xF) << NAND_T_WH_SHIFT))
-
-/*
- * External Interrupts for Pb1200 as of 8/6/2004.
- * Bit positions in the CPLD registers can be calculated by taking
- * the interrupt define and subtracting the PB1200_INT_BEGIN value.
- *
- *   Example: IDE bis pos is  = 64 - 64
- *            ETH bit pos is  = 65 - 64
- */
-enum external_pb1200_ints {
-       PB1200_INT_BEGIN        = AU1000_MAX_INTR + 1,
-
-       PB1200_IDE_INT          = PB1200_INT_BEGIN,
-       PB1200_ETH_INT,
-       PB1200_PC0_INT,
-       PB1200_PC0_STSCHG_INT,
-       PB1200_PC1_INT,
-       PB1200_PC1_STSCHG_INT,
-       PB1200_DC_INT,
-       PB1200_FLASHBUSY_INT,
-       PB1200_PC0_INSERT_INT,
-       PB1200_PC0_EJECT_INT,
-       PB1200_PC1_INSERT_INT,
-       PB1200_PC1_EJECT_INT,
-       PB1200_SD0_INSERT_INT,
-       PB1200_SD0_EJECT_INT,
-       PB1200_SD1_INSERT_INT,
-       PB1200_SD1_EJECT_INT,
-
-       PB1200_INT_END          = PB1200_INT_BEGIN + 15
-};
-
-/* NAND chip select */
-#define NAND_CS 1
-
-#endif /* __ASM_PB1200_H */
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1550.h b/arch/mips/include/asm/mach-pb1x00/pb1550.h
deleted file mode 100644 (file)
index 443b88a..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * AMD Alchemy Semi PB1550 Reference Board
- * Board Registers defines.
- *
- * Copyright 2004 Embedded Edge LLC.
- * Copyright 2005 Ralf Baechle (ralf@linux-mips.org)
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- *
- */
-#ifndef __ASM_PB1550_H
-#define __ASM_PB1550_H
-
-#include <linux/types.h>
-#include <asm/mach-au1x00/au1xxx_psc.h>
-
-#define DBDMA_AC97_TX_CHAN     AU1550_DSCR_CMD0_PSC1_TX
-#define DBDMA_AC97_RX_CHAN     AU1550_DSCR_CMD0_PSC1_RX
-#define DBDMA_I2S_TX_CHAN      AU1550_DSCR_CMD0_PSC3_TX
-#define DBDMA_I2S_RX_CHAN      AU1550_DSCR_CMD0_PSC3_RX
-
-#define SPI_PSC_BASE           AU1550_PSC0_PHYS_ADDR
-#define AC97_PSC_BASE          AU1550_PSC1_PHYS_ADDR
-#define SMBUS_PSC_BASE         AU1550_PSC2_PHYS_ADDR
-#define I2S_PSC_BASE           AU1550_PSC3_PHYS_ADDR
-
-/*
- * Timing values as described in databook, * ns value stripped of
- * lower 2 bits.
- * These defines are here rather than an SOC1550 generic file because
- * the parts chosen on another board may be different and may require
- * different timings.
- */
-#define NAND_T_H               (18 >> 2)
-#define NAND_T_PUL             (30 >> 2)
-#define NAND_T_SU              (30 >> 2)
-#define NAND_T_WH              (30 >> 2)
-
-/* Bitfield shift amounts */
-#define NAND_T_H_SHIFT         0
-#define NAND_T_PUL_SHIFT       4
-#define NAND_T_SU_SHIFT                8
-#define NAND_T_WH_SHIFT                12
-
-#define NAND_TIMING    (((NAND_T_H   & 0xF) << NAND_T_H_SHIFT)   | \
-                        ((NAND_T_PUL & 0xF) << NAND_T_PUL_SHIFT) | \
-                        ((NAND_T_SU  & 0xF) << NAND_T_SU_SHIFT)  | \
-                        ((NAND_T_WH  & 0xF) << NAND_T_WH_SHIFT))
-
-#define NAND_CS 1
-
-/* Should be done by YAMON */
-#define NAND_STCFG     0x00400005 /* 8-bit NAND */
-#define NAND_STTIME    0x00007774 /* valid for 396 MHz SD=2 only */
-#define NAND_STADDR    0x12000FFF /* physical address 0x20000000 */
-
-#endif /* __ASM_PB1550_H */
index 2ea7b817feb87988c09711d63f5c02f570ea0ee1..7f87d824eeb089ca3be7aa4f56efa889ec98c40d 100644 (file)
@@ -1106,7 +1106,7 @@ do {                                                                      \
 #define read_c0_brcm_reset()           __read_32bit_c0_register($22, 5)
 #define write_c0_brcm_reset(val)       __write_32bit_c0_register($22, 5, val)
 
-/* BMIPS4380 */
+/* BMIPS43xx */
 #define read_c0_brcm_cmt_intr()                __read_32bit_c0_register($22, 1)
 #define write_c0_brcm_cmt_intr(val)    __write_32bit_c0_register($22, 1, val)
 
@@ -1667,6 +1667,13 @@ __BUILD_SET_C0(config)
 __BUILD_SET_C0(intcontrol)
 __BUILD_SET_C0(intctl)
 __BUILD_SET_C0(srsmap)
+__BUILD_SET_C0(brcm_config_0)
+__BUILD_SET_C0(brcm_bus_pll)
+__BUILD_SET_C0(brcm_reset)
+__BUILD_SET_C0(brcm_cmt_intr)
+__BUILD_SET_C0(brcm_cmt_ctrl)
+__BUILD_SET_C0(brcm_config)
+__BUILD_SET_C0(brcm_mode)
 
 #endif /* !__ASSEMBLY__ */
 
index bc01a02cacd8fd95ee3ab50378ae64aee3c701bb..7467d1d933d54a0eba29fe93465b78c26ade6108 100644 (file)
@@ -74,7 +74,9 @@ search_module_dbetables(unsigned long addr)
 }
 #endif
 
-#ifdef CONFIG_CPU_MIPS32_R1
+#ifdef CONFIG_CPU_BMIPS
+#define MODULE_PROC_FAMILY "BMIPS "
+#elif defined CONFIG_CPU_MIPS32_R1
 #define MODULE_PROC_FAMILY "MIPS32_R1 "
 #elif defined CONFIG_CPU_MIPS32_R2
 #define MODULE_PROC_FAMILY "MIPS32_R2 "
@@ -120,6 +122,8 @@ search_module_dbetables(unsigned long addr)
 #define MODULE_PROC_FAMILY "OCTEON "
 #elif defined CONFIG_CPU_XLR
 #define MODULE_PROC_FAMILY "XLR "
+#elif defined CONFIG_CPU_XLP
+#define MODULE_PROC_FAMILY "XLP "
 #else
 #error MODULE_PROC_FAMILY undefined for your processor configuration
 #endif
diff --git a/arch/mips/include/asm/netlogic/common.h b/arch/mips/include/asm/netlogic/common.h
new file mode 100644 (file)
index 0000000..fdd2f44
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NETLOGIC_COMMON_H_
+#define _NETLOGIC_COMMON_H_
+
+/*
+ * Common SMP definitions
+ */
+#define        RESET_VEC_PHYS          0x1fc00000
+#define        RESET_DATA_PHYS         (RESET_VEC_PHYS + (1<<10))
+#define        BOOT_THREAD_MODE        0
+#define        BOOT_NMI_LOCK           4
+#define        BOOT_NMI_HANDLER        8
+
+#ifndef __ASSEMBLY__
+struct irq_desc;
+extern struct plat_smp_ops nlm_smp_ops;
+extern char nlm_reset_entry[], nlm_reset_entry_end[];
+void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc);
+void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc);
+void nlm_smp_irq_init(void);
+void nlm_boot_secondary_cpus(void);
+int nlm_wakeup_secondary_cpus(u32 wakeup_mask);
+void nlm_rmiboot_preboot(void);
+
+static inline void
+nlm_set_nmi_handler(void *handler)
+{
+       char *reset_data;
+
+       reset_data = (char *)CKSEG1ADDR(RESET_DATA_PHYS);
+       *(int64_t *)(reset_data + BOOT_NMI_HANDLER) = (long)handler;
+}
+
+/*
+ * Misc.
+ */
+unsigned int nlm_get_cpu_frequency(void);
+
+extern unsigned long nlm_common_ebase;
+extern int nlm_threads_per_core;
+extern uint32_t nlm_cpumask, nlm_coremask;
+#endif
+#endif /* _NETLOGIC_COMMON_H_ */
diff --git a/arch/mips/include/asm/netlogic/haldefs.h b/arch/mips/include/asm/netlogic/haldefs.h
new file mode 100644 (file)
index 0000000..72a0c78
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __NLM_HAL_HALDEFS_H__
+#define __NLM_HAL_HALDEFS_H__
+
+/*
+ * This file contains platform specific memory mapped IO implementation
+ * and will provide a way to read 32/64 bit memory mapped registers in
+ * all ABIs
+ */
+#if !defined(CONFIG_64BIT) && defined(CONFIG_CPU_XLP)
+#error "o32 compile not supported on XLP yet"
+#endif
+/*
+ * For o32 compilation, we have to disable interrupts and enable KX bit to
+ * access 64 bit addresses or data.
+ *
+ * We need to disable interrupts because we save just the lower 32 bits of
+ * registers in  interrupt handling. So if we get hit by an interrupt while
+ * using the upper 32 bits of a register, we lose.
+ */
+static inline uint32_t nlm_save_flags_kx(void)
+{
+       return change_c0_status(ST0_KX | ST0_IE, ST0_KX);
+}
+
+static inline uint32_t nlm_save_flags_cop2(void)
+{
+       return change_c0_status(ST0_CU2 | ST0_IE, ST0_CU2);
+}
+
+static inline void nlm_restore_flags(uint32_t sr)
+{
+       write_c0_status(sr);
+}
+
+/*
+ * The n64 implementations are simple, the o32 implementations when they
+ * are added, will have to disable interrupts and enable KX before doing
+ * 64 bit ops.
+ */
+static inline uint32_t
+nlm_read_reg(uint64_t base, uint32_t reg)
+{
+       volatile uint32_t *addr = (volatile uint32_t *)(long)base + reg;
+
+       return *addr;
+}
+
+static inline void
+nlm_write_reg(uint64_t base, uint32_t reg, uint32_t val)
+{
+       volatile uint32_t *addr = (volatile uint32_t *)(long)base + reg;
+
+       *addr = val;
+}
+
+static inline uint64_t
+nlm_read_reg64(uint64_t base, uint32_t reg)
+{
+       uint64_t addr = base + (reg >> 1) * sizeof(uint64_t);
+       volatile uint64_t *ptr = (volatile uint64_t *)(long)addr;
+
+       return *ptr;
+}
+
+static inline void
+nlm_write_reg64(uint64_t base, uint32_t reg, uint64_t val)
+{
+       uint64_t addr = base + (reg >> 1) * sizeof(uint64_t);
+       volatile uint64_t *ptr = (volatile uint64_t *)(long)addr;
+
+       *ptr = val;
+}
+
+/*
+ * Routines to store 32/64 bit values to 64 bit addresses,
+ * used when going thru XKPHYS to access registers
+ */
+static inline uint32_t
+nlm_read_reg_xkphys(uint64_t base, uint32_t reg)
+{
+       return nlm_read_reg(base, reg);
+}
+
+static inline void
+nlm_write_reg_xkphys(uint64_t base, uint32_t reg, uint32_t val)
+{
+       nlm_write_reg(base, reg, val);
+}
+
+static inline uint64_t
+nlm_read_reg64_xkphys(uint64_t base, uint32_t reg)
+{
+       return nlm_read_reg64(base, reg);
+}
+
+static inline void
+nlm_write_reg64_xkphys(uint64_t base, uint32_t reg, uint64_t val)
+{
+       nlm_write_reg64(base, reg, val);
+}
+
+/* Location where IO base is mapped */
+extern uint64_t nlm_io_base;
+
+#if defined(CONFIG_CPU_XLP)
+static inline uint64_t
+nlm_pcicfg_base(uint32_t devoffset)
+{
+       return nlm_io_base + devoffset;
+}
+
+static inline uint64_t
+nlm_xkphys_map_pcibar0(uint64_t pcibase)
+{
+       uint64_t paddr;
+
+       paddr = nlm_read_reg(pcibase, 0x4) & ~0xfu;
+       return (uint64_t)0x9000000000000000 | paddr;
+}
+#elif defined(CONFIG_CPU_XLR)
+
+static inline uint64_t
+nlm_mmio_base(uint32_t devoffset)
+{
+       return nlm_io_base + devoffset;
+}
+#endif
+
+#endif
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/bridge.h b/arch/mips/include/asm/netlogic/xlp-hal/bridge.h
new file mode 100644 (file)
index 0000000..ca95133
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __NLM_HAL_BRIDGE_H__
+#define __NLM_HAL_BRIDGE_H__
+
+/**
+* @file_name mio.h
+* @author Netlogic Microsystems
+* @brief Basic definitions of XLP memory and io subsystem
+*/
+
+/*
+ * BRIDGE specific registers
+ *
+ * These registers start after the PCIe header, which has 0x40
+ * standard entries
+ */
+#define BRIDGE_MODE                    0x00
+#define BRIDGE_PCI_CFG_BASE            0x01
+#define BRIDGE_PCI_CFG_LIMIT           0x02
+#define BRIDGE_PCIE_CFG_BASE           0x03
+#define BRIDGE_PCIE_CFG_LIMIT          0x04
+#define BRIDGE_BUSNUM_BAR0             0x05
+#define BRIDGE_BUSNUM_BAR1             0x06
+#define BRIDGE_BUSNUM_BAR2             0x07
+#define BRIDGE_BUSNUM_BAR3             0x08
+#define BRIDGE_BUSNUM_BAR4             0x09
+#define BRIDGE_BUSNUM_BAR5             0x0a
+#define BRIDGE_BUSNUM_BAR6             0x0b
+#define BRIDGE_FLASH_BAR0              0x0c
+#define BRIDGE_FLASH_BAR1              0x0d
+#define BRIDGE_FLASH_BAR2              0x0e
+#define BRIDGE_FLASH_BAR3              0x0f
+#define BRIDGE_FLASH_LIMIT0            0x10
+#define BRIDGE_FLASH_LIMIT1            0x11
+#define BRIDGE_FLASH_LIMIT2            0x12
+#define BRIDGE_FLASH_LIMIT3            0x13
+
+#define BRIDGE_DRAM_BAR(i)             (0x14 + (i))
+#define BRIDGE_DRAM_BAR0               0x14
+#define BRIDGE_DRAM_BAR1               0x15
+#define BRIDGE_DRAM_BAR2               0x16
+#define BRIDGE_DRAM_BAR3               0x17
+#define BRIDGE_DRAM_BAR4               0x18
+#define BRIDGE_DRAM_BAR5               0x19
+#define BRIDGE_DRAM_BAR6               0x1a
+#define BRIDGE_DRAM_BAR7               0x1b
+
+#define BRIDGE_DRAM_LIMIT(i)           (0x1c + (i))
+#define BRIDGE_DRAM_LIMIT0             0x1c
+#define BRIDGE_DRAM_LIMIT1             0x1d
+#define BRIDGE_DRAM_LIMIT2             0x1e
+#define BRIDGE_DRAM_LIMIT3             0x1f
+#define BRIDGE_DRAM_LIMIT4             0x20
+#define BRIDGE_DRAM_LIMIT5             0x21
+#define BRIDGE_DRAM_LIMIT6             0x22
+#define BRIDGE_DRAM_LIMIT7             0x23
+
+#define BRIDGE_DRAM_NODE_TRANSLN0      0x24
+#define BRIDGE_DRAM_NODE_TRANSLN1      0x25
+#define BRIDGE_DRAM_NODE_TRANSLN2      0x26
+#define BRIDGE_DRAM_NODE_TRANSLN3      0x27
+#define BRIDGE_DRAM_NODE_TRANSLN4      0x28
+#define BRIDGE_DRAM_NODE_TRANSLN5      0x29
+#define BRIDGE_DRAM_NODE_TRANSLN6      0x2a
+#define BRIDGE_DRAM_NODE_TRANSLN7      0x2b
+#define BRIDGE_DRAM_CHNL_TRANSLN0      0x2c
+#define BRIDGE_DRAM_CHNL_TRANSLN1      0x2d
+#define BRIDGE_DRAM_CHNL_TRANSLN2      0x2e
+#define BRIDGE_DRAM_CHNL_TRANSLN3      0x2f
+#define BRIDGE_DRAM_CHNL_TRANSLN4      0x30
+#define BRIDGE_DRAM_CHNL_TRANSLN5      0x31
+#define BRIDGE_DRAM_CHNL_TRANSLN6      0x32
+#define BRIDGE_DRAM_CHNL_TRANSLN7      0x33
+#define BRIDGE_PCIEMEM_BASE0           0x34
+#define BRIDGE_PCIEMEM_BASE1           0x35
+#define BRIDGE_PCIEMEM_BASE2           0x36
+#define BRIDGE_PCIEMEM_BASE3           0x37
+#define BRIDGE_PCIEMEM_LIMIT0          0x38
+#define BRIDGE_PCIEMEM_LIMIT1          0x39
+#define BRIDGE_PCIEMEM_LIMIT2          0x3a
+#define BRIDGE_PCIEMEM_LIMIT3          0x3b
+#define BRIDGE_PCIEIO_BASE0            0x3c
+#define BRIDGE_PCIEIO_BASE1            0x3d
+#define BRIDGE_PCIEIO_BASE2            0x3e
+#define BRIDGE_PCIEIO_BASE3            0x3f
+#define BRIDGE_PCIEIO_LIMIT0           0x40
+#define BRIDGE_PCIEIO_LIMIT1           0x41
+#define BRIDGE_PCIEIO_LIMIT2           0x42
+#define BRIDGE_PCIEIO_LIMIT3           0x43
+#define BRIDGE_PCIEMEM_BASE4           0x44
+#define BRIDGE_PCIEMEM_BASE5           0x45
+#define BRIDGE_PCIEMEM_BASE6           0x46
+#define BRIDGE_PCIEMEM_LIMIT4          0x47
+#define BRIDGE_PCIEMEM_LIMIT5          0x48
+#define BRIDGE_PCIEMEM_LIMIT6          0x49
+#define BRIDGE_PCIEIO_BASE4            0x4a
+#define BRIDGE_PCIEIO_BASE5            0x4b
+#define BRIDGE_PCIEIO_BASE6            0x4c
+#define BRIDGE_PCIEIO_LIMIT4           0x4d
+#define BRIDGE_PCIEIO_LIMIT5           0x4e
+#define BRIDGE_PCIEIO_LIMIT6           0x4f
+#define BRIDGE_NBU_EVENT_CNT_CTL       0x50
+#define BRIDGE_EVNTCTR1_LOW            0x51
+#define BRIDGE_EVNTCTR1_HI             0x52
+#define BRIDGE_EVNT_CNT_CTL2           0x53
+#define BRIDGE_EVNTCTR2_LOW            0x54
+#define BRIDGE_EVNTCTR2_HI             0x55
+#define BRIDGE_TRACEBUF_MATCH0         0x56
+#define BRIDGE_TRACEBUF_MATCH1         0x57
+#define BRIDGE_TRACEBUF_MATCH_LOW      0x58
+#define BRIDGE_TRACEBUF_MATCH_HI       0x59
+#define BRIDGE_TRACEBUF_CTRL           0x5a
+#define BRIDGE_TRACEBUF_INIT           0x5b
+#define BRIDGE_TRACEBUF_ACCESS         0x5c
+#define BRIDGE_TRACEBUF_READ_DATA0     0x5d
+#define BRIDGE_TRACEBUF_READ_DATA1     0x5d
+#define BRIDGE_TRACEBUF_READ_DATA2     0x5f
+#define BRIDGE_TRACEBUF_READ_DATA3     0x60
+#define BRIDGE_TRACEBUF_STATUS         0x61
+#define BRIDGE_ADDRESS_ERROR0          0x62
+#define BRIDGE_ADDRESS_ERROR1          0x63
+#define BRIDGE_ADDRESS_ERROR2          0x64
+#define BRIDGE_TAG_ECC_ADDR_ERROR0     0x65
+#define BRIDGE_TAG_ECC_ADDR_ERROR1     0x66
+#define BRIDGE_TAG_ECC_ADDR_ERROR2     0x67
+#define BRIDGE_LINE_FLUSH0             0x68
+#define BRIDGE_LINE_FLUSH1             0x69
+#define BRIDGE_NODE_ID                 0x6a
+#define BRIDGE_ERROR_INTERRUPT_EN      0x6b
+#define BRIDGE_PCIE0_WEIGHT            0x2c0
+#define BRIDGE_PCIE1_WEIGHT            0x2c1
+#define BRIDGE_PCIE2_WEIGHT            0x2c2
+#define BRIDGE_PCIE3_WEIGHT            0x2c3
+#define BRIDGE_USB_WEIGHT              0x2c4
+#define BRIDGE_NET_WEIGHT              0x2c5
+#define BRIDGE_POE_WEIGHT              0x2c6
+#define BRIDGE_CMS_WEIGHT              0x2c7
+#define BRIDGE_DMAENG_WEIGHT           0x2c8
+#define BRIDGE_SEC_WEIGHT              0x2c9
+#define BRIDGE_COMP_WEIGHT             0x2ca
+#define BRIDGE_GIO_WEIGHT              0x2cb
+#define BRIDGE_FLASH_WEIGHT            0x2cc
+
+#ifndef __ASSEMBLY__
+
+#define nlm_read_bridge_reg(b, r)      nlm_read_reg(b, r)
+#define nlm_write_bridge_reg(b, r, v)  nlm_write_reg(b, r, v)
+#define        nlm_get_bridge_pcibase(node)    \
+                       nlm_pcicfg_base(XLP_IO_BRIDGE_OFFSET(node))
+#define        nlm_get_bridge_regbase(node)    \
+                       (nlm_get_bridge_pcibase(node) + XLP_IO_PCI_HDRSZ)
+
+#endif /* __ASSEMBLY__ */
+#endif /* __NLM_HAL_BRIDGE_H__ */
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h b/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h
new file mode 100644 (file)
index 0000000..bf7d41d
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __NLM_HAL_CPUCONTROL_H__
+#define __NLM_HAL_CPUCONTROL_H__
+
+#define CPU_BLOCKID_IFU                0
+#define CPU_BLOCKID_ICU                1
+#define CPU_BLOCKID_IEU                2
+#define CPU_BLOCKID_LSU                3
+#define CPU_BLOCKID_MMU                4
+#define CPU_BLOCKID_PRF                5
+#define CPU_BLOCKID_SCH                7
+#define CPU_BLOCKID_SCU                8
+#define CPU_BLOCKID_FPU                9
+#define CPU_BLOCKID_MAP                10
+
+#define LSU_DEFEATURE          0x304
+#define LSU_CERRLOG_REGID      0x09
+#define SCHED_DEFEATURE                0x700
+
+/* Offsets of interest from the 'MAP' Block */
+#define MAP_THREADMODE                 0x00
+#define MAP_EXT_EBASE_ENABLE           0x04
+#define MAP_CCDI_CONFIG                        0x08
+#define MAP_THRD0_CCDI_STATUS          0x0c
+#define MAP_THRD1_CCDI_STATUS          0x10
+#define MAP_THRD2_CCDI_STATUS          0x14
+#define MAP_THRD3_CCDI_STATUS          0x18
+#define MAP_THRD0_DEBUG_MODE           0x1c
+#define MAP_THRD1_DEBUG_MODE           0x20
+#define MAP_THRD2_DEBUG_MODE           0x24
+#define MAP_THRD3_DEBUG_MODE           0x28
+#define MAP_MISC_STATE                 0x60
+#define MAP_DEBUG_READ_CTL             0x64
+#define MAP_DEBUG_READ_REG0            0x68
+#define MAP_DEBUG_READ_REG1            0x6c
+
+#define MMU_SETUP              0x400
+#define MMU_LFSRSEED           0x401
+#define MMU_HPW_NUM_PAGE_LVL   0x410
+#define MMU_PGWKR_PGDBASE      0x411
+#define MMU_PGWKR_PGDSHFT      0x412
+#define MMU_PGWKR_PGDMASK      0x413
+#define MMU_PGWKR_PUDSHFT      0x414
+#define MMU_PGWKR_PUDMASK      0x415
+#define MMU_PGWKR_PMDSHFT      0x416
+#define MMU_PGWKR_PMDMASK      0x417
+#define MMU_PGWKR_PTESHFT      0x418
+#define MMU_PGWKR_PTEMASK      0x419
+
+#endif /* __NLM_CPUCONTROL_H__ */
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/iomap.h b/arch/mips/include/asm/netlogic/xlp-hal/iomap.h
new file mode 100644 (file)
index 0000000..86cc339
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __NLM_HAL_IOMAP_H__
+#define __NLM_HAL_IOMAP_H__
+
+#define XLP_DEFAULT_IO_BASE             0x18000000
+#define NMI_BASE                       0xbfc00000
+#define        XLP_IO_CLK                      133333333
+
+#define XLP_PCIE_CFG_SIZE              0x1000          /* 4K */
+#define XLP_PCIE_DEV_BLK_SIZE          (8 * XLP_PCIE_CFG_SIZE)
+#define XLP_PCIE_BUS_BLK_SIZE          (256 * XLP_PCIE_DEV_BLK_SIZE)
+#define XLP_IO_SIZE                    (64 << 20)      /* ECFG space size */
+#define XLP_IO_PCI_HDRSZ               0x100
+#define XLP_IO_DEV(node, dev)          ((dev) + (node) * 8)
+#define XLP_HDR_OFFSET(node, bus, dev, fn)     (((bus) << 20) | \
+                               ((XLP_IO_DEV(node, dev)) << 15) | ((fn) << 12))
+
+#define XLP_IO_BRIDGE_OFFSET(node)     XLP_HDR_OFFSET(node, 0, 0, 0)
+/* coherent inter chip */
+#define XLP_IO_CIC0_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 0, 1)
+#define XLP_IO_CIC1_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 0, 2)
+#define XLP_IO_CIC2_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 0, 3)
+#define XLP_IO_PIC_OFFSET(node)                XLP_HDR_OFFSET(node, 0, 0, 4)
+
+#define XLP_IO_PCIE_OFFSET(node, i)    XLP_HDR_OFFSET(node, 0, 1, i)
+#define XLP_IO_PCIE0_OFFSET(node)      XLP_HDR_OFFSET(node, 0, 1, 0)
+#define XLP_IO_PCIE1_OFFSET(node)      XLP_HDR_OFFSET(node, 0, 1, 1)
+#define XLP_IO_PCIE2_OFFSET(node)      XLP_HDR_OFFSET(node, 0, 1, 2)
+#define XLP_IO_PCIE3_OFFSET(node)      XLP_HDR_OFFSET(node, 0, 1, 3)
+
+#define XLP_IO_USB_OFFSET(node, i)     XLP_HDR_OFFSET(node, 0, 2, i)
+#define XLP_IO_USB_EHCI0_OFFSET(node)  XLP_HDR_OFFSET(node, 0, 2, 0)
+#define XLP_IO_USB_OHCI0_OFFSET(node)  XLP_HDR_OFFSET(node, 0, 2, 1)
+#define XLP_IO_USB_OHCI1_OFFSET(node)  XLP_HDR_OFFSET(node, 0, 2, 2)
+#define XLP_IO_USB_EHCI1_OFFSET(node)  XLP_HDR_OFFSET(node, 0, 2, 3)
+#define XLP_IO_USB_OHCI2_OFFSET(node)  XLP_HDR_OFFSET(node, 0, 2, 4)
+#define XLP_IO_USB_OHCI3_OFFSET(node)  XLP_HDR_OFFSET(node, 0, 2, 5)
+
+#define XLP_IO_NAE_OFFSET(node)                XLP_HDR_OFFSET(node, 0, 3, 0)
+#define XLP_IO_POE_OFFSET(node)                XLP_HDR_OFFSET(node, 0, 3, 1)
+
+#define XLP_IO_CMS_OFFSET(node)                XLP_HDR_OFFSET(node, 0, 4, 0)
+
+#define XLP_IO_DMA_OFFSET(node)                XLP_HDR_OFFSET(node, 0, 5, 1)
+#define XLP_IO_SEC_OFFSET(node)                XLP_HDR_OFFSET(node, 0, 5, 2)
+#define XLP_IO_CMP_OFFSET(node)                XLP_HDR_OFFSET(node, 0, 5, 3)
+
+#define XLP_IO_UART_OFFSET(node, i)    XLP_HDR_OFFSET(node, 0, 6, i)
+#define XLP_IO_UART0_OFFSET(node)      XLP_HDR_OFFSET(node, 0, 6, 0)
+#define XLP_IO_UART1_OFFSET(node)      XLP_HDR_OFFSET(node, 0, 6, 1)
+#define XLP_IO_I2C_OFFSET(node, i)     XLP_HDR_OFFSET(node, 0, 6, 2 + i)
+#define XLP_IO_I2C0_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 6, 2)
+#define XLP_IO_I2C1_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 6, 3)
+#define XLP_IO_GPIO_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 6, 4)
+/* system management */
+#define XLP_IO_SYS_OFFSET(node)                XLP_HDR_OFFSET(node, 0, 6, 5)
+#define XLP_IO_JTAG_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 6, 6)
+
+#define XLP_IO_NOR_OFFSET(node)                XLP_HDR_OFFSET(node, 0, 7, 0)
+#define XLP_IO_NAND_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 7, 1)
+#define XLP_IO_SPI_OFFSET(node)                XLP_HDR_OFFSET(node, 0, 7, 2)
+/* SD flash */
+#define XLP_IO_SD_OFFSET(node)          XLP_HDR_OFFSET(node, 0, 7, 3)
+#define XLP_IO_MMC_OFFSET(node, slot)   \
+               ((XLP_IO_SD_OFFSET(node))+(slot*0x100)+XLP_IO_PCI_HDRSZ)
+
+/* PCI config header register id's */
+#define XLP_PCI_CFGREG0                        0x00
+#define XLP_PCI_CFGREG1                        0x01
+#define XLP_PCI_CFGREG2                        0x02
+#define XLP_PCI_CFGREG3                        0x03
+#define XLP_PCI_CFGREG4                        0x04
+#define XLP_PCI_CFGREG5                        0x05
+#define XLP_PCI_DEVINFO_REG0           0x30
+#define XLP_PCI_DEVINFO_REG1           0x31
+#define XLP_PCI_DEVINFO_REG2           0x32
+#define XLP_PCI_DEVINFO_REG3           0x33
+#define XLP_PCI_DEVINFO_REG4           0x34
+#define XLP_PCI_DEVINFO_REG5           0x35
+#define XLP_PCI_DEVINFO_REG6           0x36
+#define XLP_PCI_DEVINFO_REG7           0x37
+#define XLP_PCI_DEVSCRATCH_REG0                0x38
+#define XLP_PCI_DEVSCRATCH_REG1                0x39
+#define XLP_PCI_DEVSCRATCH_REG2                0x3a
+#define XLP_PCI_DEVSCRATCH_REG3                0x3b
+#define XLP_PCI_MSGSTN_REG             0x3c
+#define XLP_PCI_IRTINFO_REG            0x3d
+#define XLP_PCI_UCODEINFO_REG          0x3e
+#define XLP_PCI_SBB_WT_REG             0x3f
+
+/* PCI IDs for SoC device */
+#define        PCI_VENDOR_NETLOGIC             0x184e
+
+#define        PCI_DEVICE_ID_NLM_ROOT          0x1001
+#define        PCI_DEVICE_ID_NLM_ICI           0x1002
+#define        PCI_DEVICE_ID_NLM_PIC           0x1003
+#define        PCI_DEVICE_ID_NLM_PCIE          0x1004
+#define        PCI_DEVICE_ID_NLM_EHCI          0x1007
+#define        PCI_DEVICE_ID_NLM_ILK           0x1008
+#define        PCI_DEVICE_ID_NLM_NAE           0x1009
+#define        PCI_DEVICE_ID_NLM_POE           0x100A
+#define        PCI_DEVICE_ID_NLM_FMN           0x100B
+#define        PCI_DEVICE_ID_NLM_RAID          0x100D
+#define        PCI_DEVICE_ID_NLM_SAE           0x100D
+#define        PCI_DEVICE_ID_NLM_RSA           0x100E
+#define        PCI_DEVICE_ID_NLM_CMP           0x100F
+#define        PCI_DEVICE_ID_NLM_UART          0x1010
+#define        PCI_DEVICE_ID_NLM_I2C           0x1011
+#define        PCI_DEVICE_ID_NLM_NOR           0x1015
+#define        PCI_DEVICE_ID_NLM_NAND          0x1016
+#define        PCI_DEVICE_ID_NLM_MMC           0x1018
+
+#ifndef __ASSEMBLY__
+
+#define nlm_read_pci_reg(b, r)         nlm_read_reg(b, r)
+#define nlm_write_pci_reg(b, r, v)     nlm_write_reg(b, r, v)
+
+#endif /* !__ASSEMBLY */
+
+#endif /* __NLM_HAL_IOMAP_H__ */
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pic.h b/arch/mips/include/asm/netlogic/xlp-hal/pic.h
new file mode 100644 (file)
index 0000000..b6628f7
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NLM_HAL_PIC_H
+#define _NLM_HAL_PIC_H
+
+/* PIC Specific registers */
+#define PIC_CTRL                0x00
+
+/* PIC control register defines */
+#define PIC_CTRL_ITV           32 /* interrupt timeout value */
+#define PIC_CTRL_ICI           19 /* ICI interrupt timeout enable */
+#define PIC_CTRL_ITE           18 /* interrupt timeout enable */
+#define PIC_CTRL_STE           10 /* system timer interrupt enable */
+#define PIC_CTRL_WWR1          8  /* watchdog 1 wraparound count for reset */
+#define PIC_CTRL_WWR0          6  /* watchdog 0 wraparound count for reset */
+#define PIC_CTRL_WWN1          4  /* watchdog 1 wraparound count for NMI */
+#define PIC_CTRL_WWN0          2  /* watchdog 0 wraparound count for NMI */
+#define PIC_CTRL_WTE           0  /* watchdog timer enable */
+
+/* PIC Status register defines */
+#define PIC_ICI_STATUS         33 /* ICI interrupt timeout status */
+#define PIC_ITE_STATUS         32 /* interrupt timeout status */
+#define PIC_STS_STATUS         4  /* System timer interrupt status */
+#define PIC_WNS_STATUS         2  /* NMI status for watchdog timers */
+#define PIC_WIS_STATUS         0  /* Interrupt status for watchdog timers */
+
+/* PIC IPI control register offsets */
+#define PIC_IPICTRL_NMI                32
+#define PIC_IPICTRL_RIV                20 /* received interrupt vector */
+#define PIC_IPICTRL_IDB                16 /* interrupt destination base */
+#define PIC_IPICTRL_DTE                 0 /* interrupt destination thread enables */
+
+/* PIC IRT register offsets */
+#define PIC_IRT_ENABLE         31
+#define PIC_IRT_NMI            29
+#define PIC_IRT_SCH            28 /* Scheduling scheme */
+#define PIC_IRT_RVEC           20 /* Interrupt receive vectors */
+#define PIC_IRT_DT             19 /* Destination type */
+#define PIC_IRT_DB             16 /* Destination base */
+#define PIC_IRT_DTE            0  /* Destination thread enables */
+
+#define PIC_BYTESWAP            0x02
+#define PIC_STATUS              0x04
+#define PIC_INTR_TIMEOUT       0x06
+#define PIC_ICI0_INTR_TIMEOUT  0x08
+#define PIC_ICI1_INTR_TIMEOUT  0x0a
+#define PIC_ICI2_INTR_TIMEOUT  0x0c
+#define PIC_IPI_CTL            0x0e
+#define PIC_INT_ACK             0x10
+#define PIC_INT_PENDING0        0x12
+#define PIC_INT_PENDING1        0x14
+#define PIC_INT_PENDING2        0x16
+
+#define PIC_WDOG0_MAXVAL        0x18
+#define PIC_WDOG0_COUNT         0x1a
+#define PIC_WDOG0_ENABLE0       0x1c
+#define PIC_WDOG0_ENABLE1       0x1e
+#define PIC_WDOG0_BEATCMD       0x20
+#define PIC_WDOG0_BEAT0         0x22
+#define PIC_WDOG0_BEAT1         0x24
+
+#define PIC_WDOG1_MAXVAL        0x26
+#define PIC_WDOG1_COUNT         0x28
+#define PIC_WDOG1_ENABLE0       0x2a
+#define PIC_WDOG1_ENABLE1       0x2c
+#define PIC_WDOG1_BEATCMD       0x2e
+#define PIC_WDOG1_BEAT0         0x30
+#define PIC_WDOG1_BEAT1         0x32
+
+#define PIC_WDOG_MAXVAL(i)      (PIC_WDOG0_MAXVAL + ((i) ? 7 : 0))
+#define PIC_WDOG_COUNT(i)       (PIC_WDOG0_COUNT + ((i) ? 7 : 0))
+#define PIC_WDOG_ENABLE0(i)     (PIC_WDOG0_ENABLE0 + ((i) ? 7 : 0))
+#define PIC_WDOG_ENABLE1(i)     (PIC_WDOG0_ENABLE1 + ((i) ? 7 : 0))
+#define PIC_WDOG_BEATCMD(i)     (PIC_WDOG0_BEATCMD + ((i) ? 7 : 0))
+#define PIC_WDOG_BEAT0(i)       (PIC_WDOG0_BEAT0 + ((i) ? 7 : 0))
+#define PIC_WDOG_BEAT1(i)       (PIC_WDOG0_BEAT1 + ((i) ? 7 : 0))
+
+#define PIC_TIMER0_MAXVAL    0x34
+#define PIC_TIMER1_MAXVAL    0x36
+#define PIC_TIMER2_MAXVAL    0x38
+#define PIC_TIMER3_MAXVAL    0x3a
+#define PIC_TIMER4_MAXVAL    0x3c
+#define PIC_TIMER5_MAXVAL    0x3e
+#define PIC_TIMER6_MAXVAL    0x40
+#define PIC_TIMER7_MAXVAL    0x42
+#define PIC_TIMER_MAXVAL(i)  (PIC_TIMER0_MAXVAL + ((i) * 2))
+
+#define PIC_TIMER0_COUNT     0x44
+#define PIC_TIMER1_COUNT     0x46
+#define PIC_TIMER2_COUNT     0x48
+#define PIC_TIMER3_COUNT     0x4a
+#define PIC_TIMER4_COUNT     0x4c
+#define PIC_TIMER5_COUNT     0x4e
+#define PIC_TIMER6_COUNT     0x50
+#define PIC_TIMER7_COUNT     0x52
+#define PIC_TIMER_COUNT(i)   (PIC_TIMER0_COUNT + ((i) * 2))
+
+#define PIC_ITE0_N0_N1          0x54
+#define PIC_ITE1_N0_N1          0x58
+#define PIC_ITE2_N0_N1          0x5c
+#define PIC_ITE3_N0_N1          0x60
+#define PIC_ITE4_N0_N1          0x64
+#define PIC_ITE5_N0_N1          0x68
+#define PIC_ITE6_N0_N1          0x6c
+#define PIC_ITE7_N0_N1          0x70
+#define PIC_ITE_N0_N1(i)        (PIC_ITE0_N0_N1 + ((i) * 4))
+
+#define PIC_ITE0_N2_N3          0x56
+#define PIC_ITE1_N2_N3          0x5a
+#define PIC_ITE2_N2_N3          0x5e
+#define PIC_ITE3_N2_N3          0x62
+#define PIC_ITE4_N2_N3          0x66
+#define PIC_ITE5_N2_N3          0x6a
+#define PIC_ITE6_N2_N3          0x6e
+#define PIC_ITE7_N2_N3          0x72
+#define PIC_ITE_N2_N3(i)        (PIC_ITE0_N2_N3 + ((i) * 4))
+
+#define PIC_IRT0                0x74
+#define PIC_IRT(i)              (PIC_IRT0 + ((i) * 2))
+
+#define TIMER_CYCLES_MAXVAL    0xffffffffffffffffULL
+
+/*
+ *    IRT Map
+ */
+#define PIC_NUM_IRTS           160
+
+#define PIC_IRT_WD_0_INDEX     0
+#define PIC_IRT_WD_1_INDEX     1
+#define PIC_IRT_WD_NMI_0_INDEX 2
+#define PIC_IRT_WD_NMI_1_INDEX 3
+#define PIC_IRT_TIMER_0_INDEX  4
+#define PIC_IRT_TIMER_1_INDEX  5
+#define PIC_IRT_TIMER_2_INDEX  6
+#define PIC_IRT_TIMER_3_INDEX  7
+#define PIC_IRT_TIMER_4_INDEX  8
+#define PIC_IRT_TIMER_5_INDEX  9
+#define PIC_IRT_TIMER_6_INDEX  10
+#define PIC_IRT_TIMER_7_INDEX  11
+#define PIC_IRT_CLOCK_INDEX    PIC_IRT_TIMER_7_INDEX
+#define PIC_IRT_TIMER_INDEX(num)       ((num) + PIC_IRT_TIMER_0_INDEX)
+
+
+/* 11 and 12 */
+#define PIC_NUM_MSG_Q_IRTS     32
+#define PIC_IRT_MSG_Q0_INDEX   12
+#define PIC_IRT_MSG_Q_INDEX(qid)       ((qid) + PIC_IRT_MSG_Q0_INDEX)
+/* 12 to 43 */
+#define PIC_IRT_MSG_0_INDEX    44
+#define PIC_IRT_MSG_1_INDEX    45
+/* 44 and 45 */
+#define PIC_NUM_PCIE_MSIX_IRTS 32
+#define PIC_IRT_PCIE_MSIX_0_INDEX      46
+#define PIC_IRT_PCIE_MSIX_INDEX(num)   ((num) + PIC_IRT_PCIE_MSIX_0_INDEX)
+/* 46 to 77 */
+#define PIC_NUM_PCIE_LINK_IRTS         4
+#define PIC_IRT_PCIE_LINK_0_INDEX      78
+#define PIC_IRT_PCIE_LINK_1_INDEX      79
+#define PIC_IRT_PCIE_LINK_2_INDEX      80
+#define PIC_IRT_PCIE_LINK_3_INDEX      81
+#define PIC_IRT_PCIE_LINK_INDEX(num)   ((num) + PIC_IRT_PCIE_LINK_0_INDEX)
+/* 78 to 81 */
+#define PIC_NUM_NA_IRTS                        32
+/* 82 to 113 */
+#define PIC_IRT_NA_0_INDEX             82
+#define PIC_IRT_NA_INDEX(num)          ((num) + PIC_IRT_NA_0_INDEX)
+#define PIC_IRT_POE_INDEX              114
+
+#define PIC_NUM_USB_IRTS               6
+#define PIC_IRT_USB_0_INDEX            115
+#define PIC_IRT_EHCI_0_INDEX           115
+#define PIC_IRT_EHCI_1_INDEX           118
+#define PIC_IRT_USB_INDEX(num)         ((num) + PIC_IRT_USB_0_INDEX)
+/* 115 to 120 */
+#define PIC_IRT_GDX_INDEX              121
+#define PIC_IRT_SEC_INDEX              122
+#define PIC_IRT_RSA_INDEX              123
+
+#define PIC_NUM_COMP_IRTS              4
+#define PIC_IRT_COMP_0_INDEX           124
+#define PIC_IRT_COMP_INDEX(num)                ((num) + PIC_IRT_COMP_0_INDEX)
+/* 124 to 127 */
+#define PIC_IRT_GBU_INDEX              128
+#define PIC_IRT_ICC_0_INDEX            129 /* ICC - Inter Chip Coherency */
+#define PIC_IRT_ICC_1_INDEX            130
+#define PIC_IRT_ICC_2_INDEX            131
+#define PIC_IRT_CAM_INDEX              132
+#define PIC_IRT_UART_0_INDEX           133
+#define PIC_IRT_UART_1_INDEX           134
+#define PIC_IRT_I2C_0_INDEX            135
+#define PIC_IRT_I2C_1_INDEX            136
+#define PIC_IRT_SYS_0_INDEX            137
+#define PIC_IRT_SYS_1_INDEX            138
+#define PIC_IRT_JTAG_INDEX             139
+#define PIC_IRT_PIC_INDEX              140
+#define PIC_IRT_NBU_INDEX              141
+#define PIC_IRT_TCU_INDEX              142
+#define PIC_IRT_GCU_INDEX              143 /* GBC - Global Coherency */
+#define PIC_IRT_DMC_0_INDEX            144
+#define PIC_IRT_DMC_1_INDEX            145
+
+#define PIC_NUM_GPIO_IRTS              4
+#define PIC_IRT_GPIO_0_INDEX           146
+#define PIC_IRT_GPIO_INDEX(num)                ((num) + PIC_IRT_GPIO_0_INDEX)
+
+/* 146 to 149 */
+#define PIC_IRT_NOR_INDEX              150
+#define PIC_IRT_NAND_INDEX             151
+#define PIC_IRT_SPI_INDEX              152
+#define PIC_IRT_MMC_INDEX              153
+
+#define PIC_CLOCK_TIMER                        7
+#define PIC_IRQ_BASE                   8
+
+#if !defined(LOCORE) && !defined(__ASSEMBLY__)
+
+#define PIC_IRT_FIRST_IRQ              (PIC_IRQ_BASE)
+#define PIC_IRT_LAST_IRQ               63
+#define PIC_IRQ_IS_IRT(irq)            ((irq) >= PIC_IRT_FIRST_IRQ)
+
+/*
+ *   Misc
+ */
+#define PIC_IRT_VALID                  1
+#define PIC_LOCAL_SCHEDULING           1
+#define PIC_GLOBAL_SCHEDULING          0
+
+#define nlm_read_pic_reg(b, r) nlm_read_reg64(b, r)
+#define nlm_write_pic_reg(b, r, v) nlm_write_reg64(b, r, v)
+#define nlm_get_pic_pcibase(node) nlm_pcicfg_base(XLP_IO_PIC_OFFSET(node))
+#define nlm_get_pic_regbase(node) (nlm_get_pic_pcibase(node) + XLP_IO_PCI_HDRSZ)
+
+/* IRT and h/w interrupt routines */
+static inline int
+nlm_pic_read_irt(uint64_t base, int irt_index)
+{
+       return nlm_read_pic_reg(base, PIC_IRT(irt_index));
+}
+
+static inline uint64_t
+nlm_pic_read_control(uint64_t base)
+{
+       return nlm_read_pic_reg(base, PIC_CTRL);
+}
+
+static inline void
+nlm_pic_write_control(uint64_t base, uint64_t control)
+{
+       nlm_write_pic_reg(base, PIC_CTRL, control);
+}
+
+static inline void
+nlm_pic_update_control(uint64_t base, uint64_t control)
+{
+       uint64_t val;
+
+       val = nlm_read_pic_reg(base, PIC_CTRL);
+       nlm_write_pic_reg(base, PIC_CTRL, control | val);
+}
+
+static inline void
+nlm_set_irt_to_cpu(uint64_t base, int irt, int cpu)
+{
+       uint64_t val;
+
+       val = nlm_read_pic_reg(base, PIC_IRT(irt));
+       val |= cpu & 0xf;
+       if (cpu > 15)
+               val |= 1 << 16;
+       nlm_write_pic_reg(base, PIC_IRT(irt), val);
+}
+
+static inline void
+nlm_pic_write_irt(uint64_t base, int irt_num, int en, int nmi,
+       int sch, int vec, int dt, int db, int dte)
+{
+       uint64_t val;
+
+       val = (((uint64_t)en & 0x1) << 31) | ((nmi & 0x1) << 29) |
+                       ((sch & 0x1) << 28) | ((vec & 0x3f) << 20) |
+                       ((dt & 0x1) << 19) | ((db & 0x7) << 16) |
+                       (dte & 0xffff);
+
+       nlm_write_pic_reg(base, PIC_IRT(irt_num), val);
+}
+
+static inline void
+nlm_pic_write_irt_direct(uint64_t base, int irt_num, int en, int nmi,
+       int sch, int vec, int cpu)
+{
+       nlm_pic_write_irt(base, irt_num, en, nmi, sch, vec, 1,
+               (cpu >> 4),             /* thread group */
+               1 << (cpu & 0xf));      /* thread mask */
+}
+
+static inline uint64_t
+nlm_pic_read_timer(uint64_t base, int timer)
+{
+       return nlm_read_pic_reg(base, PIC_TIMER_COUNT(timer));
+}
+
+static inline void
+nlm_pic_write_timer(uint64_t base, int timer, uint64_t value)
+{
+       nlm_write_pic_reg(base, PIC_TIMER_COUNT(timer), value);
+}
+
+static inline void
+nlm_pic_set_timer(uint64_t base, int timer, uint64_t value, int irq, int cpu)
+{
+       uint64_t pic_ctrl = nlm_read_pic_reg(base, PIC_CTRL);
+       int en;
+
+       en = (irq > 0);
+       nlm_write_pic_reg(base, PIC_TIMER_MAXVAL(timer), value);
+       nlm_pic_write_irt_direct(base, PIC_IRT_TIMER_INDEX(timer),
+               en, 0, 0, irq, cpu);
+
+       /* enable the timer */
+       pic_ctrl |= (1 << (PIC_CTRL_STE + timer));
+       nlm_write_pic_reg(base, PIC_CTRL, pic_ctrl);
+}
+
+static inline void
+nlm_pic_enable_irt(uint64_t base, int irt)
+{
+       uint64_t reg;
+
+       reg = nlm_read_pic_reg(base, PIC_IRT(irt));
+       nlm_write_pic_reg(base, PIC_IRT(irt), reg | (1u << 31));
+}
+
+static inline void
+nlm_pic_disable_irt(uint64_t base, int irt)
+{
+       uint32_t reg;
+
+       reg = nlm_read_pic_reg(base, PIC_IRT(irt));
+       nlm_write_pic_reg(base, PIC_IRT(irt), reg & ~((uint64_t)1 << 31));
+}
+
+static inline void
+nlm_pic_send_ipi(uint64_t base, int hwt, int irq, int nmi)
+{
+       uint64_t ipi;
+       int     node, ncpu;
+
+       node = hwt / 32;
+       ncpu = hwt & 0x1f;
+       ipi = ((uint64_t)nmi << 31) | (irq << 20) | (node << 17) |
+               (1 << (ncpu & 0xf));
+       if (ncpu > 15)
+               ipi |= 0x10000; /* Setting bit 16 to select cpus 16-31 */
+
+       nlm_write_pic_reg(base, PIC_IPI_CTL, ipi);
+}
+
+static inline void
+nlm_pic_ack(uint64_t base, int irt_num)
+{
+       nlm_write_pic_reg(base, PIC_INT_ACK, irt_num);
+
+       /* Ack the Status register for Watchdog & System timers */
+       if (irt_num < 12)
+               nlm_write_pic_reg(base, PIC_STATUS, (1 << irt_num));
+}
+
+static inline void
+nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt)
+{
+       nlm_pic_write_irt_direct(base, irt, 0, 0, 0, irq, 0);
+}
+
+extern uint64_t nlm_pic_base;
+int nlm_irq_to_irt(int irq);
+int nlm_irt_to_irq(int irt);
+
+#endif /* __ASSEMBLY__ */
+#endif /* _NLM_HAL_PIC_H */
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/sys.h b/arch/mips/include/asm/netlogic/xlp-hal/sys.h
new file mode 100644 (file)
index 0000000..21432f7
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __NLM_HAL_SYS_H__
+#define __NLM_HAL_SYS_H__
+
+/**
+* @file_name sys.h
+* @author Netlogic Microsystems
+* @brief HAL for System configuration registers
+*/
+#define        SYS_CHIP_RESET                          0x00
+#define        SYS_POWER_ON_RESET_CFG                  0x01
+#define        SYS_EFUSE_DEVICE_CFG_STATUS0            0x02
+#define        SYS_EFUSE_DEVICE_CFG_STATUS1            0x03
+#define        SYS_EFUSE_DEVICE_CFG_STATUS2            0x04
+#define        SYS_EFUSE_DEVICE_CFG3                   0x05
+#define        SYS_EFUSE_DEVICE_CFG4                   0x06
+#define        SYS_EFUSE_DEVICE_CFG5                   0x07
+#define        SYS_EFUSE_DEVICE_CFG6                   0x08
+#define        SYS_EFUSE_DEVICE_CFG7                   0x09
+#define        SYS_PLL_CTRL                            0x0a
+#define        SYS_CPU_RESET                           0x0b
+#define        SYS_CPU_NONCOHERENT_MODE                0x0d
+#define        SYS_CORE_DFS_DIS_CTRL                   0x0e
+#define        SYS_CORE_DFS_RST_CTRL                   0x0f
+#define        SYS_CORE_DFS_BYP_CTRL                   0x10
+#define        SYS_CORE_DFS_PHA_CTRL                   0x11
+#define        SYS_CORE_DFS_DIV_INC_CTRL               0x12
+#define        SYS_CORE_DFS_DIV_DEC_CTRL               0x13
+#define        SYS_CORE_DFS_DIV_VALUE                  0x14
+#define        SYS_RESET                               0x15
+#define        SYS_DFS_DIS_CTRL                        0x16
+#define        SYS_DFS_RST_CTRL                        0x17
+#define        SYS_DFS_BYP_CTRL                        0x18
+#define        SYS_DFS_DIV_INC_CTRL                    0x19
+#define        SYS_DFS_DIV_DEC_CTRL                    0x1a
+#define        SYS_DFS_DIV_VALUE0                      0x1b
+#define        SYS_DFS_DIV_VALUE1                      0x1c
+#define        SYS_SENSE_AMP_DLY                       0x1d
+#define        SYS_SOC_SENSE_AMP_DLY                   0x1e
+#define        SYS_CTRL0                               0x1f
+#define        SYS_CTRL1                               0x20
+#define        SYS_TIMEOUT_BS1                         0x21
+#define        SYS_BYTE_SWAP                           0x22
+#define        SYS_VRM_VID                             0x23
+#define        SYS_PWR_RAM_CMD                         0x24
+#define        SYS_PWR_RAM_ADDR                        0x25
+#define        SYS_PWR_RAM_DATA0                       0x26
+#define        SYS_PWR_RAM_DATA1                       0x27
+#define        SYS_PWR_RAM_DATA2                       0x28
+#define        SYS_PWR_UCODE                           0x29
+#define        SYS_CPU0_PWR_STATUS                     0x2a
+#define        SYS_CPU1_PWR_STATUS                     0x2b
+#define        SYS_CPU2_PWR_STATUS                     0x2c
+#define        SYS_CPU3_PWR_STATUS                     0x2d
+#define        SYS_CPU4_PWR_STATUS                     0x2e
+#define        SYS_CPU5_PWR_STATUS                     0x2f
+#define        SYS_CPU6_PWR_STATUS                     0x30
+#define        SYS_CPU7_PWR_STATUS                     0x31
+#define        SYS_STATUS                              0x32
+#define        SYS_INT_POL                             0x33
+#define        SYS_INT_TYPE                            0x34
+#define        SYS_INT_STATUS                          0x35
+#define        SYS_INT_MASK0                           0x36
+#define        SYS_INT_MASK1                           0x37
+#define        SYS_UCO_S_ECC                           0x38
+#define        SYS_UCO_M_ECC                           0x39
+#define        SYS_UCO_ADDR                            0x3a
+#define        SYS_UCO_INSTR                           0x3b
+#define        SYS_MEM_BIST0                           0x3c
+#define        SYS_MEM_BIST1                           0x3d
+#define        SYS_MEM_BIST2                           0x3e
+#define        SYS_MEM_BIST3                           0x3f
+#define        SYS_MEM_BIST4                           0x40
+#define        SYS_MEM_BIST5                           0x41
+#define        SYS_MEM_BIST6                           0x42
+#define        SYS_MEM_BIST7                           0x43
+#define        SYS_MEM_BIST8                           0x44
+#define        SYS_MEM_BIST9                           0x45
+#define        SYS_MEM_BIST10                          0x46
+#define        SYS_MEM_BIST11                          0x47
+#define        SYS_MEM_BIST12                          0x48
+#define        SYS_SCRTCH0                             0x49
+#define        SYS_SCRTCH1                             0x4a
+#define        SYS_SCRTCH2                             0x4b
+#define        SYS_SCRTCH3                             0x4c
+
+#ifndef __ASSEMBLY__
+
+#define        nlm_read_sys_reg(b, r)          nlm_read_reg(b, r)
+#define        nlm_write_sys_reg(b, r, v)      nlm_write_reg(b, r, v)
+#define        nlm_get_sys_pcibase(node) nlm_pcicfg_base(XLP_IO_SYS_OFFSET(node))
+#define        nlm_get_sys_regbase(node) (nlm_get_sys_pcibase(node) + XLP_IO_PCI_HDRSZ)
+
+extern uint64_t nlm_sys_base;
+#endif
+#endif
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/uart.h b/arch/mips/include/asm/netlogic/xlp-hal/uart.h
new file mode 100644 (file)
index 0000000..6a7046c
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __XLP_HAL_UART_H__
+#define __XLP_HAL_UART_H__
+
+/* UART Specific registers */
+#define UART_RX_DATA           0x00
+#define UART_TX_DATA           0x00
+
+#define UART_INT_EN            0x01
+#define UART_INT_ID            0x02
+#define UART_FIFO_CTL          0x02
+#define UART_LINE_CTL          0x03
+#define UART_MODEM_CTL         0x04
+#define UART_LINE_STS          0x05
+#define UART_MODEM_STS         0x06
+
+#define UART_DIVISOR0          0x00
+#define UART_DIVISOR1          0x01
+
+#define BASE_BAUD              (XLP_IO_CLK/16)
+#define BAUD_DIVISOR(baud)     (BASE_BAUD / baud)
+
+/* LCR mask values */
+#define LCR_5BITS              0x00
+#define LCR_6BITS              0x01
+#define LCR_7BITS              0x02
+#define LCR_8BITS              0x03
+#define LCR_STOPB              0x04
+#define LCR_PENAB              0x08
+#define LCR_PODD               0x00
+#define LCR_PEVEN              0x10
+#define LCR_PONE               0x20
+#define LCR_PZERO              0x30
+#define LCR_SBREAK             0x40
+#define LCR_EFR_ENABLE         0xbf
+#define LCR_DLAB               0x80
+
+/* MCR mask values */
+#define MCR_DTR                        0x01
+#define MCR_RTS                        0x02
+#define MCR_DRS                        0x04
+#define MCR_IE                 0x08
+#define MCR_LOOPBACK           0x10
+
+/* FCR mask values */
+#define FCR_RCV_RST            0x02
+#define FCR_XMT_RST            0x04
+#define FCR_RX_LOW             0x00
+#define FCR_RX_MEDL            0x40
+#define FCR_RX_MEDH            0x80
+#define FCR_RX_HIGH            0xc0
+
+/* IER mask values */
+#define IER_ERXRDY             0x1
+#define IER_ETXRDY             0x2
+#define IER_ERLS               0x4
+#define IER_EMSC               0x8
+
+#if !defined(LOCORE) && !defined(__ASSEMBLY__)
+
+#define        nlm_read_uart_reg(b, r)         nlm_read_reg(b, r)
+#define        nlm_write_uart_reg(b, r, v)     nlm_write_reg(b, r, v)
+#define nlm_get_uart_pcibase(node, inst)       \
+               nlm_pcicfg_base(XLP_IO_UART_OFFSET(node, inst))
+#define nlm_get_uart_regbase(node, inst)       \
+                       (nlm_get_uart_pcibase(node, inst) + XLP_IO_PCI_HDRSZ)
+
+static inline void
+nlm_uart_set_baudrate(uint64_t base, int baud)
+{
+       uint32_t lcr;
+
+       lcr = nlm_read_uart_reg(base, UART_LINE_CTL);
+
+       /* enable divisor register, and write baud values */
+       nlm_write_uart_reg(base, UART_LINE_CTL, lcr | (1 << 7));
+       nlm_write_uart_reg(base, UART_DIVISOR0,
+                       (BAUD_DIVISOR(baud) & 0xff));
+       nlm_write_uart_reg(base, UART_DIVISOR1,
+                       ((BAUD_DIVISOR(baud) >> 8) & 0xff));
+
+       /* restore default lcr */
+       nlm_write_uart_reg(base, UART_LINE_CTL, lcr);
+}
+
+static inline void
+nlm_uart_outbyte(uint64_t base, char c)
+{
+       uint32_t lsr;
+
+       for (;;) {
+               lsr = nlm_read_uart_reg(base, UART_LINE_STS);
+               if (lsr & 0x20)
+                       break;
+       }
+
+       nlm_write_uart_reg(base, UART_TX_DATA, (int)c);
+}
+
+static inline char
+nlm_uart_inbyte(uint64_t base)
+{
+       int data, lsr;
+
+       for (;;) {
+               lsr = nlm_read_uart_reg(base, UART_LINE_STS);
+               if (lsr & 0x80) { /* parity/frame/break-error - push a zero */
+                       data = 0;
+                       break;
+               }
+               if (lsr & 0x01) {       /* Rx data */
+                       data = nlm_read_uart_reg(base, UART_RX_DATA);
+                       break;
+               }
+       }
+
+       return (char)data;
+}
+
+static inline int
+nlm_uart_init(uint64_t base, int baud, int databits, int stopbits,
+       int parity, int int_en, int loopback)
+{
+       uint32_t lcr;
+
+       lcr = 0;
+       if (databits >= 8)
+               lcr |= LCR_8BITS;
+       else if (databits == 7)
+               lcr |= LCR_7BITS;
+       else if (databits == 6)
+               lcr |= LCR_6BITS;
+       else
+               lcr |= LCR_5BITS;
+
+       if (stopbits > 1)
+               lcr |= LCR_STOPB;
+
+       lcr |= parity << 3;
+
+       /* setup default lcr */
+       nlm_write_uart_reg(base, UART_LINE_CTL, lcr);
+
+       /* Reset the FIFOs */
+       nlm_write_uart_reg(base, UART_LINE_CTL, FCR_RCV_RST | FCR_XMT_RST);
+
+       nlm_uart_set_baudrate(base, baud);
+
+       if (loopback)
+               nlm_write_uart_reg(base, UART_MODEM_CTL, 0x1f);
+
+       if (int_en)
+               nlm_write_uart_reg(base, UART_INT_EN, IER_ERXRDY | IER_ETXRDY);
+
+       return 0;
+}
+#endif /* !LOCORE && !__ASSEMBLY__ */
+#endif /* __XLP_HAL_UART_H__ */
similarity index 82%
rename from arch/mips/netlogic/xlr/xlr_console.c
rename to arch/mips/include/asm/netlogic/xlp-hal/xlp.h
index 759df06922019b582f97df491d60c80eee2e4dcc..1540588e396dbee6600755a3bb3ad2417d8b962e 100644 (file)
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <linux/types.h>
-#include <asm/netlogic/xlr/iomap.h>
+#ifndef _NLM_HAL_XLP_H
+#define _NLM_HAL_XLP_H
 
-void prom_putchar(char c)
-{
-       nlm_reg_t *mmio;
+#define PIC_UART_0_IRQ           17
+#define PIC_UART_1_IRQ           18
 
-       mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET);
-       while (netlogic_read_reg(mmio, 0x5) == 0)
-               ;
-       netlogic_write_reg(mmio, 0x0, c);
-}
+#ifndef __ASSEMBLY__
+
+/* SMP support functions */
+void xlp_boot_core0_siblings(void);
+void xlp_wakeup_secondary_cpus(void);
+
+void xlp_mmu_init(void);
+void nlm_hal_init(void);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASM_NLM_XLP_H */
index 2e3a4dd53045e4c2056ec0a1ade4617437bc77ae..2e768f032e83198eba1652a57f2287a988f1d607 100644 (file)
 #define DEFAULT_HT_TYPE0_CFG_BASE       0x16000000
 #define DEFAULT_HT_TYPE1_CFG_BASE       0x17000000
 
-#ifndef __ASSEMBLY__
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-typedef volatile __u32 nlm_reg_t;
-extern unsigned long netlogic_io_base;
-
-/* FIXME read once in write_reg */
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
-#define netlogic_read_reg(base, offset)                ((base)[(offset)])
-#define netlogic_write_reg(base, offset, value)        ((base)[(offset)] = (value))
-#else
-#define netlogic_read_reg(base, offset)                (be32_to_cpu((base)[(offset)]))
-#define netlogic_write_reg(base, offset, value) \
-                               ((base)[(offset)] = cpu_to_be32((value)))
-#endif
-
-#define netlogic_read_reg_le32(base, offset) (le32_to_cpu((base)[(offset)]))
-#define netlogic_write_reg_le32(base, offset, value) \
-                               ((base)[(offset)] = cpu_to_le32((value)))
-#define netlogic_io_mmio(offset) ((nlm_reg_t *)(netlogic_io_base+(offset)))
-#endif /* __ASSEMBLY__ */
 #endif
diff --git a/arch/mips/include/asm/netlogic/xlr/msidef.h b/arch/mips/include/asm/netlogic/xlr/msidef.h
new file mode 100644 (file)
index 0000000..7e39d40
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ASM_RMI_MSIDEF_H
+#define ASM_RMI_MSIDEF_H
+
+/*
+ * Constants for Intel APIC based MSI messages.
+ * Adapted for the RMI XLR using identical defines
+ */
+
+/*
+ * Shifts for MSI data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT          0
+#define  MSI_DATA_VECTOR_MASK          0x000000ff
+#define         MSI_DATA_VECTOR(v)             (((v) << MSI_DATA_VECTOR_SHIFT) & \
+                                               MSI_DATA_VECTOR_MASK)
+
+#define MSI_DATA_DELIVERY_MODE_SHIFT   8
+#define  MSI_DATA_DELIVERY_FIXED       (0 << MSI_DATA_DELIVERY_MODE_SHIFT)
+#define  MSI_DATA_DELIVERY_LOWPRI      (1 << MSI_DATA_DELIVERY_MODE_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT           14
+#define         MSI_DATA_LEVEL_DEASSERT        (0 << MSI_DATA_LEVEL_SHIFT)
+#define         MSI_DATA_LEVEL_ASSERT          (1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT         15
+#define  MSI_DATA_TRIGGER_EDGE         (0 << MSI_DATA_TRIGGER_SHIFT)
+#define  MSI_DATA_TRIGGER_LEVEL                (1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for msi address
+ */
+
+#define MSI_ADDR_BASE_HI               0
+#define MSI_ADDR_BASE_LO               0xfee00000
+
+#define MSI_ADDR_DEST_MODE_SHIFT       2
+#define  MSI_ADDR_DEST_MODE_PHYSICAL   (0 << MSI_ADDR_DEST_MODE_SHIFT)
+#define         MSI_ADDR_DEST_MODE_LOGICAL     (1 << MSI_ADDR_DEST_MODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT     3
+#define  MSI_ADDR_REDIRECTION_CPU      (0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define  MSI_ADDR_REDIRECTION_LOWPRI   (1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+#define MSI_ADDR_DEST_ID_SHIFT         12
+#define         MSI_ADDR_DEST_ID_MASK          0x00ffff0
+#define  MSI_ADDR_DEST_ID(dest)                (((dest) << MSI_ADDR_DEST_ID_SHIFT) & \
+                                                MSI_ADDR_DEST_ID_MASK)
+
+#endif /* ASM_RMI_MSIDEF_H */
index 5cceb746f080ce988e3f52d4d0c926f6cfa5bcf0..868013e62f3225711ed0033401cc9690a9c200c0 100644 (file)
 /* end XLS */
 
 #ifndef __ASSEMBLY__
-static inline void pic_send_ipi(u32 ipi)
+
+#define PIC_IRQ_IS_EDGE_TRIGGERED(irq) (((irq) >= PIC_TIMER_0_IRQ) && \
+                                       ((irq) <= PIC_TIMER_7_IRQ))
+#define PIC_IRQ_IS_IRT(irq)            (((irq) >= PIC_IRT_FIRST_IRQ) && \
+                                       ((irq) <= PIC_IRT_LAST_IRQ))
+
+static inline int
+nlm_irq_to_irt(int irq)
 {
-       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+       if (PIC_IRQ_IS_IRT(irq) == 0)
+               return -1;
 
-       netlogic_write_reg(mmio, PIC_IPI, ipi);
+       return PIC_IRQ_TO_INTR(irq);
 }
 
-static inline u32 pic_read_control(void)
+static inline int
+nlm_irt_to_irq(int irt)
 {
-       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
 
-       return netlogic_read_reg(mmio, PIC_CTRL);
+       return PIC_INTR_TO_IRQ(irt);
 }
 
-static inline void pic_write_control(u32 control)
+static inline void
+nlm_pic_enable_irt(uint64_t base, int irt)
 {
-       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+       uint32_t reg;
 
-       netlogic_write_reg(mmio, PIC_CTRL, control);
+       reg = nlm_read_reg(base, PIC_IRT_1(irt));
+       nlm_write_reg(base, PIC_IRT_1(irt), reg | (1u << 31));
 }
 
-static inline void pic_update_control(u32 control)
+static inline void
+nlm_pic_disable_irt(uint64_t base, int irt)
 {
-       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+       uint32_t reg;
 
-       netlogic_write_reg(mmio, PIC_CTRL,
-               (control | netlogic_read_reg(mmio, PIC_CTRL)));
+       reg = nlm_read_reg(base, PIC_IRT_1(irt));
+       nlm_write_reg(base, PIC_IRT_1(irt), reg & ~(1u << 31));
 }
 
-#define PIC_IRQ_IS_EDGE_TRIGGERED(irq) (((irq) >= PIC_TIMER_0_IRQ) && \
-                                       ((irq) <= PIC_TIMER_7_IRQ))
-#define PIC_IRQ_IS_IRT(irq)            (((irq) >= PIC_IRT_FIRST_IRQ) && \
-                                       ((irq) <= PIC_IRT_LAST_IRQ))
-#endif
+static inline void
+nlm_pic_send_ipi(uint64_t base, int hwt, int irq, int nmi)
+{
+       unsigned int tid, pid;
+
+       tid = hwt & 0x3;
+       pid = (hwt >> 2) & 0x07;
+       nlm_write_reg(base, PIC_IPI,
+               (pid << 20) | (tid << 16) | (nmi << 8) | irq);
+}
+
+static inline void
+nlm_pic_ack(uint64_t base, int irt)
+{
+       nlm_write_reg(base, PIC_INT_ACK, 1u << irt);
+}
 
+static inline void
+nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt)
+{
+       nlm_write_reg(base, PIC_IRT_0(irt), (1u << hwt));
+       /* local scheduling, invalid, level by default */
+       nlm_write_reg(base, PIC_IRT_1(irt),
+               (1 << 30) | (1 << 6) | irq);
+}
+
+extern uint64_t nlm_pic_base;
+#endif
 #endif /* _ASM_NLM_XLR_PIC_H */
index 3e6372692a04fe7f0cdf1fd133cd54cdfe3ea830..ff4a17b0bf78df40462a8b4f71279ebe1cfd3910 100644 (file)
@@ -40,17 +40,8 @@ struct uart_port;
 unsigned int nlm_xlr_uart_in(struct uart_port *, int);
 void nlm_xlr_uart_out(struct uart_port *, int, int);
 
-/* SMP support functions */
-struct irq_desc;
-void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc);
-void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc);
-int nlm_wakeup_secondary_cpus(u32 wakeup_mask);
-void nlm_smp_irq_init(void);
-void nlm_boot_smp_nmi(void);
-void prom_pre_boot_secondary_cpus(void);
-
-extern struct plat_smp_ops nlm_smp_ops;
-extern unsigned long nlm_common_ebase;
+/* SMP helpers */
+void xlr_wakeup_secondary_cpus(void);
 
 /* XLS B silicon "Rook" */
 static inline unsigned int nlm_chip_is_xls_b(void)
index 4e4c3a8282d624575d39a335348bd920c29fb86d..1db1dc2724cb2c5ed74a83ae9fe8da05490e4c23 100644 (file)
@@ -39,7 +39,7 @@
  * versions.
  */
 #define CVMX_BOOTINFO_MAJ_VER 1
-#define CVMX_BOOTINFO_MIN_VER 2
+#define CVMX_BOOTINFO_MIN_VER 3
 
 #if (CVMX_BOOTINFO_MAJ_VER == 1)
 #define CVMX_BOOTINFO_OCTEON_SERIAL_LEN 20
@@ -116,7 +116,13 @@ struct cvmx_bootinfo {
         */
        uint32_t config_flags;
 #endif
-
+#if (CVMX_BOOTINFO_MIN_VER >= 3)
+       /*
+        * Address of the OF Flattened Device Tree structure
+        * describing the board.
+        */
+       uint64_t fdt_addr;
+#endif
 };
 
 #define CVMX_BOOTINFO_CFG_FLAG_PCI_HOST                        (1ull << 0)
@@ -164,6 +170,22 @@ enum cvmx_board_types_enum {
        /* Special 'generic' board type, supports many boards */
        CVMX_BOARD_TYPE_GENERIC = 28,
        CVMX_BOARD_TYPE_EBH5610 = 29,
+       CVMX_BOARD_TYPE_LANAI2_A = 30,
+       CVMX_BOARD_TYPE_LANAI2_U = 31,
+       CVMX_BOARD_TYPE_EBB5600 = 32,
+       CVMX_BOARD_TYPE_EBB6300 = 33,
+       CVMX_BOARD_TYPE_NIC_XLE_10G = 34,
+       CVMX_BOARD_TYPE_LANAI2_G = 35,
+       CVMX_BOARD_TYPE_EBT5810 = 36,
+       CVMX_BOARD_TYPE_NIC10E = 37,
+       CVMX_BOARD_TYPE_EP6300C = 38,
+       CVMX_BOARD_TYPE_EBB6800 = 39,
+       CVMX_BOARD_TYPE_NIC4E = 40,
+       CVMX_BOARD_TYPE_NIC2E = 41,
+       CVMX_BOARD_TYPE_EBB6600 = 42,
+       CVMX_BOARD_TYPE_REDWING = 43,
+       CVMX_BOARD_TYPE_NIC68_4 = 44,
+       CVMX_BOARD_TYPE_NIC10E_66 = 45,
        CVMX_BOARD_TYPE_MAX,
 
        /*
@@ -181,6 +203,23 @@ enum cvmx_board_types_enum {
        CVMX_BOARD_TYPE_CUST_NS0216 = 10002,
        CVMX_BOARD_TYPE_CUST_NB5 = 10003,
        CVMX_BOARD_TYPE_CUST_WMR500 = 10004,
+       CVMX_BOARD_TYPE_CUST_ITB101 = 10005,
+       CVMX_BOARD_TYPE_CUST_NTE102 = 10006,
+       CVMX_BOARD_TYPE_CUST_AGS103 = 10007,
+       CVMX_BOARD_TYPE_CUST_GST104 = 10008,
+       CVMX_BOARD_TYPE_CUST_GCT105 = 10009,
+       CVMX_BOARD_TYPE_CUST_AGS106 = 10010,
+       CVMX_BOARD_TYPE_CUST_SGM107 = 10011,
+       CVMX_BOARD_TYPE_CUST_GCT108 = 10012,
+       CVMX_BOARD_TYPE_CUST_AGS109 = 10013,
+       CVMX_BOARD_TYPE_CUST_GCT110 = 10014,
+       CVMX_BOARD_TYPE_CUST_L2_AIR_SENDER = 10015,
+       CVMX_BOARD_TYPE_CUST_L2_AIR_RECEIVER = 10016,
+       CVMX_BOARD_TYPE_CUST_L2_ACCTON2_TX = 10017,
+       CVMX_BOARD_TYPE_CUST_L2_ACCTON2_RX = 10018,
+       CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_TX = 10019,
+       CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_RX = 10020,
+       CVMX_BOARD_TYPE_CUST_L2_ZINWELL = 10021,
        CVMX_BOARD_TYPE_CUST_DEFINED_MAX = 20000,
 
        /*
@@ -241,6 +280,22 @@ static inline const char *cvmx_board_type_to_string(enum
                ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CB5200)
                ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_GENERIC)
                ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5610)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_A)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_U)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB5600)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6300)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC_XLE_10G)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_G)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5810)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC10E)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EP6300C)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6800)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC4E)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC2E)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6600)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_REDWING)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC68_4)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC10E_66)
                ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_MAX)
 
                        /* Customer boards listed here */
@@ -249,6 +304,23 @@ static inline const char *cvmx_board_type_to_string(enum
                ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NS0216)
                ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NB5)
                ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_WMR500)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_ITB101)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NTE102)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS103)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GST104)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT105)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS106)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_SGM107)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT108)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS109)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT110)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_AIR_SENDER)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_AIR_RECEIVER)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ACCTON2_TX)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ACCTON2_RX)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_TX)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_RX)
+               ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ZINWELL)
                ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MAX)
 
                    /* Customer private range */
@@ -265,9 +337,9 @@ static inline const char *cvmx_chip_type_to_string(enum
 {
        switch (type) {
                ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_NULL)
-                   ENUM_CHIP_TYPE_CASE(CVMX_CHIP_SIM_TYPE_DEPRECATED)
-                   ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_OCTEON_SAMPLE)
-                   ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_MAX)
+               ENUM_CHIP_TYPE_CASE(CVMX_CHIP_SIM_TYPE_DEPRECATED)
+               ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_OCTEON_SAMPLE)
+               ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_MAX)
        }
        return "Unsupported Chip";
 }
similarity index 99%
rename from drivers/staging/octeon/cvmx-config.h
rename to arch/mips/include/asm/octeon/cvmx-config.h
index 078a520481cf8d140070914c37f987d5c9f2ebbc..26835d1b43b87633f0d4ebbcfa09947fd33c6112 100644 (file)
@@ -166,4 +166,3 @@ typedef enum {
 #define CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE 0
 
 #endif /* __CVMX_CONFIG_H__ */
-
diff --git a/arch/mips/include/asm/octeon/cvmx-dpi-defs.h b/arch/mips/include/asm/octeon/cvmx-dpi-defs.h
new file mode 100644 (file)
index 0000000..c34ad04
--- /dev/null
@@ -0,0 +1,643 @@
+/***********************license start***************
+ * Author: Cavium Networks
+ *
+ * Contact: support@caviumnetworks.com
+ * This file is part of the OCTEON SDK
+ *
+ * Copyright (c) 2003-2011 Cavium Networks
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * or visit http://www.gnu.org/licenses/.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium Networks for more information
+ ***********************license end**************************************/
+
+#ifndef __CVMX_DPI_DEFS_H__
+#define __CVMX_DPI_DEFS_H__
+
+#define CVMX_DPI_BIST_STATUS (CVMX_ADD_IO_SEG(0x0001DF0000000000ull))
+#define CVMX_DPI_CTL (CVMX_ADD_IO_SEG(0x0001DF0000000040ull))
+#define CVMX_DPI_DMAX_COUNTS(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000300ull) + ((offset) & 7) * 8)
+#define CVMX_DPI_DMAX_DBELL(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000200ull) + ((offset) & 7) * 8)
+#define CVMX_DPI_DMAX_ERR_RSP_STATUS(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000A80ull) + ((offset) & 7) * 8)
+#define CVMX_DPI_DMAX_IBUFF_SADDR(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000280ull) + ((offset) & 7) * 8)
+#define CVMX_DPI_DMAX_IFLIGHT(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000A00ull) + ((offset) & 7) * 8)
+#define CVMX_DPI_DMAX_NADDR(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000380ull) + ((offset) & 7) * 8)
+#define CVMX_DPI_DMAX_REQBNK0(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000400ull) + ((offset) & 7) * 8)
+#define CVMX_DPI_DMAX_REQBNK1(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000480ull) + ((offset) & 7) * 8)
+#define CVMX_DPI_DMA_CONTROL (CVMX_ADD_IO_SEG(0x0001DF0000000048ull))
+#define CVMX_DPI_DMA_ENGX_EN(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000080ull) + ((offset) & 7) * 8)
+#define CVMX_DPI_DMA_PPX_CNT(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000B00ull) + ((offset) & 31) * 8)
+#define CVMX_DPI_ENGX_BUF(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000880ull) + ((offset) & 7) * 8)
+#define CVMX_DPI_INFO_REG (CVMX_ADD_IO_SEG(0x0001DF0000000980ull))
+#define CVMX_DPI_INT_EN (CVMX_ADD_IO_SEG(0x0001DF0000000010ull))
+#define CVMX_DPI_INT_REG (CVMX_ADD_IO_SEG(0x0001DF0000000008ull))
+#define CVMX_DPI_NCBX_CFG(block_id) (CVMX_ADD_IO_SEG(0x0001DF0000000800ull))
+#define CVMX_DPI_PINT_INFO (CVMX_ADD_IO_SEG(0x0001DF0000000830ull))
+#define CVMX_DPI_PKT_ERR_RSP (CVMX_ADD_IO_SEG(0x0001DF0000000078ull))
+#define CVMX_DPI_REQ_ERR_RSP (CVMX_ADD_IO_SEG(0x0001DF0000000058ull))
+#define CVMX_DPI_REQ_ERR_RSP_EN (CVMX_ADD_IO_SEG(0x0001DF0000000068ull))
+#define CVMX_DPI_REQ_ERR_RST (CVMX_ADD_IO_SEG(0x0001DF0000000060ull))
+#define CVMX_DPI_REQ_ERR_RST_EN (CVMX_ADD_IO_SEG(0x0001DF0000000070ull))
+#define CVMX_DPI_REQ_ERR_SKIP_COMP (CVMX_ADD_IO_SEG(0x0001DF0000000838ull))
+#define CVMX_DPI_REQ_GBL_EN (CVMX_ADD_IO_SEG(0x0001DF0000000050ull))
+#define CVMX_DPI_SLI_PRTX_CFG(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000900ull) + ((offset) & 3) * 8)
+#define CVMX_DPI_SLI_PRTX_ERR_INFO(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000940ull) + ((offset) & 3) * 8)
+
+union cvmx_dpi_bist_status {
+       uint64_t u64;
+       struct cvmx_dpi_bist_status_s {
+               uint64_t reserved_47_63:17;
+               uint64_t bist:47;
+       } s;
+       struct cvmx_dpi_bist_status_s cn61xx;
+       struct cvmx_dpi_bist_status_cn63xx {
+               uint64_t reserved_45_63:19;
+               uint64_t bist:45;
+       } cn63xx;
+       struct cvmx_dpi_bist_status_cn63xxp1 {
+               uint64_t reserved_37_63:27;
+               uint64_t bist:37;
+       } cn63xxp1;
+       struct cvmx_dpi_bist_status_s cn66xx;
+       struct cvmx_dpi_bist_status_cn63xx cn68xx;
+       struct cvmx_dpi_bist_status_cn63xx cn68xxp1;
+};
+
+union cvmx_dpi_ctl {
+       uint64_t u64;
+       struct cvmx_dpi_ctl_s {
+               uint64_t reserved_2_63:62;
+               uint64_t clk:1;
+               uint64_t en:1;
+       } s;
+       struct cvmx_dpi_ctl_cn61xx {
+               uint64_t reserved_1_63:63;
+               uint64_t en:1;
+       } cn61xx;
+       struct cvmx_dpi_ctl_s cn63xx;
+       struct cvmx_dpi_ctl_s cn63xxp1;
+       struct cvmx_dpi_ctl_s cn66xx;
+       struct cvmx_dpi_ctl_s cn68xx;
+       struct cvmx_dpi_ctl_s cn68xxp1;
+};
+
+union cvmx_dpi_dmax_counts {
+       uint64_t u64;
+       struct cvmx_dpi_dmax_counts_s {
+               uint64_t reserved_39_63:25;
+               uint64_t fcnt:7;
+               uint64_t dbell:32;
+       } s;
+       struct cvmx_dpi_dmax_counts_s cn61xx;
+       struct cvmx_dpi_dmax_counts_s cn63xx;
+       struct cvmx_dpi_dmax_counts_s cn63xxp1;
+       struct cvmx_dpi_dmax_counts_s cn66xx;
+       struct cvmx_dpi_dmax_counts_s cn68xx;
+       struct cvmx_dpi_dmax_counts_s cn68xxp1;
+};
+
+union cvmx_dpi_dmax_dbell {
+       uint64_t u64;
+       struct cvmx_dpi_dmax_dbell_s {
+               uint64_t reserved_16_63:48;
+               uint64_t dbell:16;
+       } s;
+       struct cvmx_dpi_dmax_dbell_s cn61xx;
+       struct cvmx_dpi_dmax_dbell_s cn63xx;
+       struct cvmx_dpi_dmax_dbell_s cn63xxp1;
+       struct cvmx_dpi_dmax_dbell_s cn66xx;
+       struct cvmx_dpi_dmax_dbell_s cn68xx;
+       struct cvmx_dpi_dmax_dbell_s cn68xxp1;
+};
+
+union cvmx_dpi_dmax_err_rsp_status {
+       uint64_t u64;
+       struct cvmx_dpi_dmax_err_rsp_status_s {
+               uint64_t reserved_6_63:58;
+               uint64_t status:6;
+       } s;
+       struct cvmx_dpi_dmax_err_rsp_status_s cn61xx;
+       struct cvmx_dpi_dmax_err_rsp_status_s cn66xx;
+       struct cvmx_dpi_dmax_err_rsp_status_s cn68xx;
+       struct cvmx_dpi_dmax_err_rsp_status_s cn68xxp1;
+};
+
+union cvmx_dpi_dmax_ibuff_saddr {
+       uint64_t u64;
+       struct cvmx_dpi_dmax_ibuff_saddr_s {
+               uint64_t reserved_62_63:2;
+               uint64_t csize:14;
+               uint64_t reserved_41_47:7;
+               uint64_t idle:1;
+               uint64_t saddr:33;
+               uint64_t reserved_0_6:7;
+       } s;
+       struct cvmx_dpi_dmax_ibuff_saddr_cn61xx {
+               uint64_t reserved_62_63:2;
+               uint64_t csize:14;
+               uint64_t reserved_41_47:7;
+               uint64_t idle:1;
+               uint64_t reserved_36_39:4;
+               uint64_t saddr:29;
+               uint64_t reserved_0_6:7;
+       } cn61xx;
+       struct cvmx_dpi_dmax_ibuff_saddr_cn61xx cn63xx;
+       struct cvmx_dpi_dmax_ibuff_saddr_cn61xx cn63xxp1;
+       struct cvmx_dpi_dmax_ibuff_saddr_cn61xx cn66xx;
+       struct cvmx_dpi_dmax_ibuff_saddr_s cn68xx;
+       struct cvmx_dpi_dmax_ibuff_saddr_s cn68xxp1;
+};
+
+union cvmx_dpi_dmax_iflight {
+       uint64_t u64;
+       struct cvmx_dpi_dmax_iflight_s {
+               uint64_t reserved_3_63:61;
+               uint64_t cnt:3;
+       } s;
+       struct cvmx_dpi_dmax_iflight_s cn61xx;
+       struct cvmx_dpi_dmax_iflight_s cn66xx;
+       struct cvmx_dpi_dmax_iflight_s cn68xx;
+       struct cvmx_dpi_dmax_iflight_s cn68xxp1;
+};
+
+union cvmx_dpi_dmax_naddr {
+       uint64_t u64;
+       struct cvmx_dpi_dmax_naddr_s {
+               uint64_t reserved_40_63:24;
+               uint64_t addr:40;
+       } s;
+       struct cvmx_dpi_dmax_naddr_cn61xx {
+               uint64_t reserved_36_63:28;
+               uint64_t addr:36;
+       } cn61xx;
+       struct cvmx_dpi_dmax_naddr_cn61xx cn63xx;
+       struct cvmx_dpi_dmax_naddr_cn61xx cn63xxp1;
+       struct cvmx_dpi_dmax_naddr_cn61xx cn66xx;
+       struct cvmx_dpi_dmax_naddr_s cn68xx;
+       struct cvmx_dpi_dmax_naddr_s cn68xxp1;
+};
+
+union cvmx_dpi_dmax_reqbnk0 {
+       uint64_t u64;
+       struct cvmx_dpi_dmax_reqbnk0_s {
+               uint64_t state:64;
+       } s;
+       struct cvmx_dpi_dmax_reqbnk0_s cn61xx;
+       struct cvmx_dpi_dmax_reqbnk0_s cn63xx;
+       struct cvmx_dpi_dmax_reqbnk0_s cn63xxp1;
+       struct cvmx_dpi_dmax_reqbnk0_s cn66xx;
+       struct cvmx_dpi_dmax_reqbnk0_s cn68xx;
+       struct cvmx_dpi_dmax_reqbnk0_s cn68xxp1;
+};
+
+union cvmx_dpi_dmax_reqbnk1 {
+       uint64_t u64;
+       struct cvmx_dpi_dmax_reqbnk1_s {
+               uint64_t state:64;
+       } s;
+       struct cvmx_dpi_dmax_reqbnk1_s cn61xx;
+       struct cvmx_dpi_dmax_reqbnk1_s cn63xx;
+       struct cvmx_dpi_dmax_reqbnk1_s cn63xxp1;
+       struct cvmx_dpi_dmax_reqbnk1_s cn66xx;
+       struct cvmx_dpi_dmax_reqbnk1_s cn68xx;
+       struct cvmx_dpi_dmax_reqbnk1_s cn68xxp1;
+};
+
+union cvmx_dpi_dma_control {
+       uint64_t u64;
+       struct cvmx_dpi_dma_control_s {
+               uint64_t reserved_62_63:2;
+               uint64_t dici_mode:1;
+               uint64_t pkt_en1:1;
+               uint64_t ffp_dis:1;
+               uint64_t commit_mode:1;
+               uint64_t pkt_hp:1;
+               uint64_t pkt_en:1;
+               uint64_t reserved_54_55:2;
+               uint64_t dma_enb:6;
+               uint64_t reserved_34_47:14;
+               uint64_t b0_lend:1;
+               uint64_t dwb_denb:1;
+               uint64_t dwb_ichk:9;
+               uint64_t fpa_que:3;
+               uint64_t o_add1:1;
+               uint64_t o_ro:1;
+               uint64_t o_ns:1;
+               uint64_t o_es:2;
+               uint64_t o_mode:1;
+               uint64_t reserved_0_13:14;
+       } s;
+       struct cvmx_dpi_dma_control_s cn61xx;
+       struct cvmx_dpi_dma_control_cn63xx {
+               uint64_t reserved_61_63:3;
+               uint64_t pkt_en1:1;
+               uint64_t ffp_dis:1;
+               uint64_t commit_mode:1;
+               uint64_t pkt_hp:1;
+               uint64_t pkt_en:1;
+               uint64_t reserved_54_55:2;
+               uint64_t dma_enb:6;
+               uint64_t reserved_34_47:14;
+               uint64_t b0_lend:1;
+               uint64_t dwb_denb:1;
+               uint64_t dwb_ichk:9;
+               uint64_t fpa_que:3;
+               uint64_t o_add1:1;
+               uint64_t o_ro:1;
+               uint64_t o_ns:1;
+               uint64_t o_es:2;
+               uint64_t o_mode:1;
+               uint64_t reserved_0_13:14;
+       } cn63xx;
+       struct cvmx_dpi_dma_control_cn63xxp1 {
+               uint64_t reserved_59_63:5;
+               uint64_t commit_mode:1;
+               uint64_t pkt_hp:1;
+               uint64_t pkt_en:1;
+               uint64_t reserved_54_55:2;
+               uint64_t dma_enb:6;
+               uint64_t reserved_34_47:14;
+               uint64_t b0_lend:1;
+               uint64_t dwb_denb:1;
+               uint64_t dwb_ichk:9;
+               uint64_t fpa_que:3;
+               uint64_t o_add1:1;
+               uint64_t o_ro:1;
+               uint64_t o_ns:1;
+               uint64_t o_es:2;
+               uint64_t o_mode:1;
+               uint64_t reserved_0_13:14;
+       } cn63xxp1;
+       struct cvmx_dpi_dma_control_cn63xx cn66xx;
+       struct cvmx_dpi_dma_control_s cn68xx;
+       struct cvmx_dpi_dma_control_cn63xx cn68xxp1;
+};
+
+union cvmx_dpi_dma_engx_en {
+       uint64_t u64;
+       struct cvmx_dpi_dma_engx_en_s {
+               uint64_t reserved_8_63:56;
+               uint64_t qen:8;
+       } s;
+       struct cvmx_dpi_dma_engx_en_s cn61xx;
+       struct cvmx_dpi_dma_engx_en_s cn63xx;
+       struct cvmx_dpi_dma_engx_en_s cn63xxp1;
+       struct cvmx_dpi_dma_engx_en_s cn66xx;
+       struct cvmx_dpi_dma_engx_en_s cn68xx;
+       struct cvmx_dpi_dma_engx_en_s cn68xxp1;
+};
+
+union cvmx_dpi_dma_ppx_cnt {
+       uint64_t u64;
+       struct cvmx_dpi_dma_ppx_cnt_s {
+               uint64_t reserved_16_63:48;
+               uint64_t cnt:16;
+       } s;
+       struct cvmx_dpi_dma_ppx_cnt_s cn61xx;
+       struct cvmx_dpi_dma_ppx_cnt_s cn68xx;
+};
+
+union cvmx_dpi_engx_buf {
+       uint64_t u64;
+       struct cvmx_dpi_engx_buf_s {
+               uint64_t reserved_37_63:27;
+               uint64_t compblks:5;
+               uint64_t reserved_9_31:23;
+               uint64_t base:5;
+               uint64_t blks:4;
+       } s;
+       struct cvmx_dpi_engx_buf_s cn61xx;
+       struct cvmx_dpi_engx_buf_cn63xx {
+               uint64_t reserved_8_63:56;
+               uint64_t base:4;
+               uint64_t blks:4;
+       } cn63xx;
+       struct cvmx_dpi_engx_buf_cn63xx cn63xxp1;
+       struct cvmx_dpi_engx_buf_s cn66xx;
+       struct cvmx_dpi_engx_buf_s cn68xx;
+       struct cvmx_dpi_engx_buf_s cn68xxp1;
+};
+
+union cvmx_dpi_info_reg {
+       uint64_t u64;
+       struct cvmx_dpi_info_reg_s {
+               uint64_t reserved_8_63:56;
+               uint64_t ffp:4;
+               uint64_t reserved_2_3:2;
+               uint64_t ncb:1;
+               uint64_t rsl:1;
+       } s;
+       struct cvmx_dpi_info_reg_s cn61xx;
+       struct cvmx_dpi_info_reg_s cn63xx;
+       struct cvmx_dpi_info_reg_cn63xxp1 {
+               uint64_t reserved_2_63:62;
+               uint64_t ncb:1;
+               uint64_t rsl:1;
+       } cn63xxp1;
+       struct cvmx_dpi_info_reg_s cn66xx;
+       struct cvmx_dpi_info_reg_s cn68xx;
+       struct cvmx_dpi_info_reg_s cn68xxp1;
+};
+
+union cvmx_dpi_int_en {
+       uint64_t u64;
+       struct cvmx_dpi_int_en_s {
+               uint64_t reserved_28_63:36;
+               uint64_t sprt3_rst:1;
+               uint64_t sprt2_rst:1;
+               uint64_t sprt1_rst:1;
+               uint64_t sprt0_rst:1;
+               uint64_t reserved_23_23:1;
+               uint64_t req_badfil:1;
+               uint64_t req_inull:1;
+               uint64_t req_anull:1;
+               uint64_t req_undflw:1;
+               uint64_t req_ovrflw:1;
+               uint64_t req_badlen:1;
+               uint64_t req_badadr:1;
+               uint64_t dmadbo:8;
+               uint64_t reserved_2_7:6;
+               uint64_t nfovr:1;
+               uint64_t nderr:1;
+       } s;
+       struct cvmx_dpi_int_en_s cn61xx;
+       struct cvmx_dpi_int_en_cn63xx {
+               uint64_t reserved_26_63:38;
+               uint64_t sprt1_rst:1;
+               uint64_t sprt0_rst:1;
+               uint64_t reserved_23_23:1;
+               uint64_t req_badfil:1;
+               uint64_t req_inull:1;
+               uint64_t req_anull:1;
+               uint64_t req_undflw:1;
+               uint64_t req_ovrflw:1;
+               uint64_t req_badlen:1;
+               uint64_t req_badadr:1;
+               uint64_t dmadbo:8;
+               uint64_t reserved_2_7:6;
+               uint64_t nfovr:1;
+               uint64_t nderr:1;
+       } cn63xx;
+       struct cvmx_dpi_int_en_cn63xx cn63xxp1;
+       struct cvmx_dpi_int_en_s cn66xx;
+       struct cvmx_dpi_int_en_cn63xx cn68xx;
+       struct cvmx_dpi_int_en_cn63xx cn68xxp1;
+};
+
+union cvmx_dpi_int_reg {
+       uint64_t u64;
+       struct cvmx_dpi_int_reg_s {
+               uint64_t reserved_28_63:36;
+               uint64_t sprt3_rst:1;
+               uint64_t sprt2_rst:1;
+               uint64_t sprt1_rst:1;
+               uint64_t sprt0_rst:1;
+               uint64_t reserved_23_23:1;
+               uint64_t req_badfil:1;
+               uint64_t req_inull:1;
+               uint64_t req_anull:1;
+               uint64_t req_undflw:1;
+               uint64_t req_ovrflw:1;
+               uint64_t req_badlen:1;
+               uint64_t req_badadr:1;
+               uint64_t dmadbo:8;
+               uint64_t reserved_2_7:6;
+               uint64_t nfovr:1;
+               uint64_t nderr:1;
+       } s;
+       struct cvmx_dpi_int_reg_s cn61xx;
+       struct cvmx_dpi_int_reg_cn63xx {
+               uint64_t reserved_26_63:38;
+               uint64_t sprt1_rst:1;
+               uint64_t sprt0_rst:1;
+               uint64_t reserved_23_23:1;
+               uint64_t req_badfil:1;
+               uint64_t req_inull:1;
+               uint64_t req_anull:1;
+               uint64_t req_undflw:1;
+               uint64_t req_ovrflw:1;
+               uint64_t req_badlen:1;
+               uint64_t req_badadr:1;
+               uint64_t dmadbo:8;
+               uint64_t reserved_2_7:6;
+               uint64_t nfovr:1;
+               uint64_t nderr:1;
+       } cn63xx;
+       struct cvmx_dpi_int_reg_cn63xx cn63xxp1;
+       struct cvmx_dpi_int_reg_s cn66xx;
+       struct cvmx_dpi_int_reg_cn63xx cn68xx;
+       struct cvmx_dpi_int_reg_cn63xx cn68xxp1;
+};
+
+union cvmx_dpi_ncbx_cfg {
+       uint64_t u64;
+       struct cvmx_dpi_ncbx_cfg_s {
+               uint64_t reserved_6_63:58;
+               uint64_t molr:6;
+       } s;
+       struct cvmx_dpi_ncbx_cfg_s cn61xx;
+       struct cvmx_dpi_ncbx_cfg_s cn66xx;
+       struct cvmx_dpi_ncbx_cfg_s cn68xx;
+};
+
+union cvmx_dpi_pint_info {
+       uint64_t u64;
+       struct cvmx_dpi_pint_info_s {
+               uint64_t reserved_14_63:50;
+               uint64_t iinfo:6;
+               uint64_t reserved_6_7:2;
+               uint64_t sinfo:6;
+       } s;
+       struct cvmx_dpi_pint_info_s cn61xx;
+       struct cvmx_dpi_pint_info_s cn63xx;
+       struct cvmx_dpi_pint_info_s cn63xxp1;
+       struct cvmx_dpi_pint_info_s cn66xx;
+       struct cvmx_dpi_pint_info_s cn68xx;
+       struct cvmx_dpi_pint_info_s cn68xxp1;
+};
+
+union cvmx_dpi_pkt_err_rsp {
+       uint64_t u64;
+       struct cvmx_dpi_pkt_err_rsp_s {
+               uint64_t reserved_1_63:63;
+               uint64_t pkterr:1;
+       } s;
+       struct cvmx_dpi_pkt_err_rsp_s cn61xx;
+       struct cvmx_dpi_pkt_err_rsp_s cn63xx;
+       struct cvmx_dpi_pkt_err_rsp_s cn63xxp1;
+       struct cvmx_dpi_pkt_err_rsp_s cn66xx;
+       struct cvmx_dpi_pkt_err_rsp_s cn68xx;
+       struct cvmx_dpi_pkt_err_rsp_s cn68xxp1;
+};
+
+union cvmx_dpi_req_err_rsp {
+       uint64_t u64;
+       struct cvmx_dpi_req_err_rsp_s {
+               uint64_t reserved_8_63:56;
+               uint64_t qerr:8;
+       } s;
+       struct cvmx_dpi_req_err_rsp_s cn61xx;
+       struct cvmx_dpi_req_err_rsp_s cn63xx;
+       struct cvmx_dpi_req_err_rsp_s cn63xxp1;
+       struct cvmx_dpi_req_err_rsp_s cn66xx;
+       struct cvmx_dpi_req_err_rsp_s cn68xx;
+       struct cvmx_dpi_req_err_rsp_s cn68xxp1;
+};
+
+union cvmx_dpi_req_err_rsp_en {
+       uint64_t u64;
+       struct cvmx_dpi_req_err_rsp_en_s {
+               uint64_t reserved_8_63:56;
+               uint64_t en:8;
+       } s;
+       struct cvmx_dpi_req_err_rsp_en_s cn61xx;
+       struct cvmx_dpi_req_err_rsp_en_s cn63xx;
+       struct cvmx_dpi_req_err_rsp_en_s cn63xxp1;
+       struct cvmx_dpi_req_err_rsp_en_s cn66xx;
+       struct cvmx_dpi_req_err_rsp_en_s cn68xx;
+       struct cvmx_dpi_req_err_rsp_en_s cn68xxp1;
+};
+
+union cvmx_dpi_req_err_rst {
+       uint64_t u64;
+       struct cvmx_dpi_req_err_rst_s {
+               uint64_t reserved_8_63:56;
+               uint64_t qerr:8;
+       } s;
+       struct cvmx_dpi_req_err_rst_s cn61xx;
+       struct cvmx_dpi_req_err_rst_s cn63xx;
+       struct cvmx_dpi_req_err_rst_s cn63xxp1;
+       struct cvmx_dpi_req_err_rst_s cn66xx;
+       struct cvmx_dpi_req_err_rst_s cn68xx;
+       struct cvmx_dpi_req_err_rst_s cn68xxp1;
+};
+
+union cvmx_dpi_req_err_rst_en {
+       uint64_t u64;
+       struct cvmx_dpi_req_err_rst_en_s {
+               uint64_t reserved_8_63:56;
+               uint64_t en:8;
+       } s;
+       struct cvmx_dpi_req_err_rst_en_s cn61xx;
+       struct cvmx_dpi_req_err_rst_en_s cn63xx;
+       struct cvmx_dpi_req_err_rst_en_s cn63xxp1;
+       struct cvmx_dpi_req_err_rst_en_s cn66xx;
+       struct cvmx_dpi_req_err_rst_en_s cn68xx;
+       struct cvmx_dpi_req_err_rst_en_s cn68xxp1;
+};
+
+union cvmx_dpi_req_err_skip_comp {
+       uint64_t u64;
+       struct cvmx_dpi_req_err_skip_comp_s {
+               uint64_t reserved_24_63:40;
+               uint64_t en_rst:8;
+               uint64_t reserved_8_15:8;
+               uint64_t en_rsp:8;
+       } s;
+       struct cvmx_dpi_req_err_skip_comp_s cn61xx;
+       struct cvmx_dpi_req_err_skip_comp_s cn66xx;
+       struct cvmx_dpi_req_err_skip_comp_s cn68xx;
+       struct cvmx_dpi_req_err_skip_comp_s cn68xxp1;
+};
+
+union cvmx_dpi_req_gbl_en {
+       uint64_t u64;
+       struct cvmx_dpi_req_gbl_en_s {
+               uint64_t reserved_8_63:56;
+               uint64_t qen:8;
+       } s;
+       struct cvmx_dpi_req_gbl_en_s cn61xx;
+       struct cvmx_dpi_req_gbl_en_s cn63xx;
+       struct cvmx_dpi_req_gbl_en_s cn63xxp1;
+       struct cvmx_dpi_req_gbl_en_s cn66xx;
+       struct cvmx_dpi_req_gbl_en_s cn68xx;
+       struct cvmx_dpi_req_gbl_en_s cn68xxp1;
+};
+
+union cvmx_dpi_sli_prtx_cfg {
+       uint64_t u64;
+       struct cvmx_dpi_sli_prtx_cfg_s {
+               uint64_t reserved_25_63:39;
+               uint64_t halt:1;
+               uint64_t qlm_cfg:4;
+               uint64_t reserved_17_19:3;
+               uint64_t rd_mode:1;
+               uint64_t reserved_14_15:2;
+               uint64_t molr:6;
+               uint64_t mps_lim:1;
+               uint64_t reserved_5_6:2;
+               uint64_t mps:1;
+               uint64_t mrrs_lim:1;
+               uint64_t reserved_2_2:1;
+               uint64_t mrrs:2;
+       } s;
+       struct cvmx_dpi_sli_prtx_cfg_s cn61xx;
+       struct cvmx_dpi_sli_prtx_cfg_cn63xx {
+               uint64_t reserved_25_63:39;
+               uint64_t halt:1;
+               uint64_t reserved_21_23:3;
+               uint64_t qlm_cfg:1;
+               uint64_t reserved_17_19:3;
+               uint64_t rd_mode:1;
+               uint64_t reserved_14_15:2;
+               uint64_t molr:6;
+               uint64_t mps_lim:1;
+               uint64_t reserved_5_6:2;
+               uint64_t mps:1;
+               uint64_t mrrs_lim:1;
+               uint64_t reserved_2_2:1;
+               uint64_t mrrs:2;
+       } cn63xx;
+       struct cvmx_dpi_sli_prtx_cfg_cn63xx cn63xxp1;
+       struct cvmx_dpi_sli_prtx_cfg_s cn66xx;
+       struct cvmx_dpi_sli_prtx_cfg_cn63xx cn68xx;
+       struct cvmx_dpi_sli_prtx_cfg_cn63xx cn68xxp1;
+};
+
+union cvmx_dpi_sli_prtx_err {
+       uint64_t u64;
+       struct cvmx_dpi_sli_prtx_err_s {
+               uint64_t addr:61;
+               uint64_t reserved_0_2:3;
+       } s;
+       struct cvmx_dpi_sli_prtx_err_s cn61xx;
+       struct cvmx_dpi_sli_prtx_err_s cn63xx;
+       struct cvmx_dpi_sli_prtx_err_s cn63xxp1;
+       struct cvmx_dpi_sli_prtx_err_s cn66xx;
+       struct cvmx_dpi_sli_prtx_err_s cn68xx;
+       struct cvmx_dpi_sli_prtx_err_s cn68xxp1;
+};
+
+union cvmx_dpi_sli_prtx_err_info {
+       uint64_t u64;
+       struct cvmx_dpi_sli_prtx_err_info_s {
+               uint64_t reserved_9_63:55;
+               uint64_t lock:1;
+               uint64_t reserved_5_7:3;
+               uint64_t type:1;
+               uint64_t reserved_3_3:1;
+               uint64_t reqq:3;
+       } s;
+       struct cvmx_dpi_sli_prtx_err_info_s cn61xx;
+       struct cvmx_dpi_sli_prtx_err_info_s cn63xx;
+       struct cvmx_dpi_sli_prtx_err_info_s cn63xxp1;
+       struct cvmx_dpi_sli_prtx_err_info_s cn66xx;
+       struct cvmx_dpi_sli_prtx_err_info_s cn68xx;
+       struct cvmx_dpi_sli_prtx_err_info_s cn68xxp1;
+};
+
+#endif
similarity index 96%
rename from drivers/staging/octeon/cvmx-helper-board.h
rename to arch/mips/include/asm/octeon/cvmx-helper-board.h
index b465bec4355329ade772797cedef1322f3e53138..88527fa835c9657e4cb27b68eae5a2e25d5ac8cd 100644 (file)
@@ -44,6 +44,12 @@ typedef enum {
        set_phy_link_flags_flow_control_mask = 0x3 << 1,        /* Mask for 2 bit wide flow control field */
 } cvmx_helper_board_set_phy_link_flags_types_t;
 
+/*
+ * Fake IPD port, the RGMII/MII interface may use different PHY, use
+ * this macro to return appropriate MIX address to read the PHY.
+ */
+#define CVMX_HELPER_BOARD_MGMT_IPD_PORT     -10
+
 /**
  * cvmx_override_board_link_get(int ipd_port) is a function
  * pointer. It is meant to allow customization of the process of
similarity index 96%
rename from drivers/staging/octeon/cvmx-helper-loop.h
rename to arch/mips/include/asm/octeon/cvmx-helper-loop.h
index e646a6ccce754143cb670383b12ff7a2aa1eeb65..077f0e9d3b2dc5c485c8d808933a9a54deb10d26 100644 (file)
@@ -44,6 +44,7 @@
  * Returns Number of ports on the interface. Zero to disable.
  */
 extern int __cvmx_helper_loop_probe(int interface);
+static inline int __cvmx_helper_loop_enumerate(int interface) {return 4; }
 
 /**
  * Bringup and enable a LOOP interface. After this call packet
similarity index 96%
rename from drivers/staging/octeon/cvmx-helper-npi.h
rename to arch/mips/include/asm/octeon/cvmx-helper-npi.h
index 908e7b08c214cfbe6cc0a37ee1126c4fd91bc531..8df4c7fafdba3dd20427a13b4c9337f9488bc8cc 100644 (file)
@@ -45,6 +45,7 @@
  * Returns Number of ports on the interface. Zero to disable.
  */
 extern int __cvmx_helper_npi_probe(int interface);
+#define __cvmx_helper_npi_enumerate __cvmx_helper_npi_probe
 
 /**
  * Bringup and enable a NPI interface. After this call packet
similarity index 98%
rename from drivers/staging/octeon/cvmx-helper-rgmii.h
rename to arch/mips/include/asm/octeon/cvmx-helper-rgmii.h
index ea2652604a570f38f010549c14743e9bfa0c777a..78295ba0050f6d4a8085ade41f7797cd42932a7f 100644 (file)
@@ -43,6 +43,7 @@
  * Returns Number of RGMII/GMII/MII ports (0-4).
  */
 extern int __cvmx_helper_rgmii_probe(int interface);
+#define __cvmx_helper_rgmii_enumerate __cvmx_helper_rgmii_probe
 
 /**
  * Put an RGMII interface in loopback mode. Internal packets sent
similarity index 98%
rename from drivers/staging/octeon/cvmx-helper-sgmii.h
rename to arch/mips/include/asm/octeon/cvmx-helper-sgmii.h
index 19b48d60857f09489b326a5240fccdd64c17e41b..9a9b6c103ede600bfe6576e598e1344a762f978b 100644 (file)
@@ -45,6 +45,7 @@
  * Returns Number of ports on the interface. Zero to disable.
  */
 extern int __cvmx_helper_sgmii_probe(int interface);
+extern int __cvmx_helper_sgmii_enumerate(int interface);
 
 /**
  * Bringup and enable a SGMII interface. After this call packet
similarity index 98%
rename from drivers/staging/octeon/cvmx-helper-spi.h
rename to arch/mips/include/asm/octeon/cvmx-helper-spi.h
index 69bac036d10e5b29ff20ed4b1ec919d13936f546..9f1c6b968f9145f0b523236b1e7281ed1fb52544 100644 (file)
@@ -42,6 +42,7 @@
  * Returns Number of ports on the interface. Zero to disable.
  */
 extern int __cvmx_helper_spi_probe(int interface);
+extern int __cvmx_helper_spi_enumerate(int interface);
 
 /**
  * Bringup and enable a SPI interface. After this call packet I/O
similarity index 98%
rename from drivers/staging/octeon/cvmx-helper-xaui.h
rename to arch/mips/include/asm/octeon/cvmx-helper-xaui.h
index 4b4db2f93cd4dc91a59f961d2d66b62ddd10214d..f6fbc4f45b561f5a6b9cc13a8c44c0d1993b2954 100644 (file)
@@ -45,6 +45,7 @@
  * Returns Number of ports on the interface. Zero to disable.
  */
 extern int __cvmx_helper_xaui_probe(int interface);
+extern int __cvmx_helper_xaui_enumerate(int interface);
 
 /**
  * Bringup and enable a XAUI interface. After this call packet
similarity index 99%
rename from drivers/staging/octeon/cvmx-helper.h
rename to arch/mips/include/asm/octeon/cvmx-helper.h
index 51916f3cc40c69d69d6fa4db1e2f1334ae618234..3169cd79f2ac251901e81ba366050b9c6e87eca5 100644 (file)
@@ -207,6 +207,7 @@ extern int cvmx_helper_link_set(int ipd_port,
  * Returns Zero on success, negative on failure
  */
 extern int cvmx_helper_interface_probe(int interface);
+extern int cvmx_helper_interface_enumerate(int interface);
 
 /**
  * Configure a port for internal and/or external loopback. Internal loopback
index 52b14a333ad44ada1b25b3bfc0e0475743fa4e23..b1774126736d93dc3f3755cac20004448f04a3d2 100644 (file)
 #define CVMX_MIO_BOOT_REG_CFGX(offset) (CVMX_ADD_IO_SEG(0x0001180000000000ull) + ((offset) & 7) * 8)
 #define CVMX_MIO_BOOT_REG_TIMX(offset) (CVMX_ADD_IO_SEG(0x0001180000000040ull) + ((offset) & 7) * 8)
 #define CVMX_MIO_BOOT_THR (CVMX_ADD_IO_SEG(0x00011800000000B0ull))
+#define CVMX_MIO_EMM_BUF_DAT (CVMX_ADD_IO_SEG(0x00011800000020E8ull))
+#define CVMX_MIO_EMM_BUF_IDX (CVMX_ADD_IO_SEG(0x00011800000020E0ull))
+#define CVMX_MIO_EMM_CFG (CVMX_ADD_IO_SEG(0x0001180000002000ull))
+#define CVMX_MIO_EMM_CMD (CVMX_ADD_IO_SEG(0x0001180000002058ull))
+#define CVMX_MIO_EMM_DMA (CVMX_ADD_IO_SEG(0x0001180000002050ull))
+#define CVMX_MIO_EMM_INT (CVMX_ADD_IO_SEG(0x0001180000002078ull))
+#define CVMX_MIO_EMM_INT_EN (CVMX_ADD_IO_SEG(0x0001180000002080ull))
+#define CVMX_MIO_EMM_MODEX(offset) (CVMX_ADD_IO_SEG(0x0001180000002008ull) + ((offset) & 3) * 8)
+#define CVMX_MIO_EMM_RCA (CVMX_ADD_IO_SEG(0x00011800000020A0ull))
+#define CVMX_MIO_EMM_RSP_HI (CVMX_ADD_IO_SEG(0x0001180000002070ull))
+#define CVMX_MIO_EMM_RSP_LO (CVMX_ADD_IO_SEG(0x0001180000002068ull))
+#define CVMX_MIO_EMM_RSP_STS (CVMX_ADD_IO_SEG(0x0001180000002060ull))
+#define CVMX_MIO_EMM_SAMPLE (CVMX_ADD_IO_SEG(0x0001180000002090ull))
+#define CVMX_MIO_EMM_STS_MASK (CVMX_ADD_IO_SEG(0x0001180000002098ull))
+#define CVMX_MIO_EMM_SWITCH (CVMX_ADD_IO_SEG(0x0001180000002048ull))
+#define CVMX_MIO_EMM_WDOG (CVMX_ADD_IO_SEG(0x0001180000002088ull))
 #define CVMX_MIO_FUS_BNK_DATX(offset) (CVMX_ADD_IO_SEG(0x0001180000001520ull) + ((offset) & 3) * 8)
 #define CVMX_MIO_FUS_DAT0 (CVMX_ADD_IO_SEG(0x0001180000001400ull))
 #define CVMX_MIO_FUS_DAT1 (CVMX_ADD_IO_SEG(0x0001180000001408ull))
@@ -60,6 +76,7 @@
 #define CVMX_MIO_FUS_REPAIR_RES2 (CVMX_ADD_IO_SEG(0x0001180000001568ull))
 #define CVMX_MIO_FUS_SPR_REPAIR_RES (CVMX_ADD_IO_SEG(0x0001180000001548ull))
 #define CVMX_MIO_FUS_SPR_REPAIR_SUM (CVMX_ADD_IO_SEG(0x0001180000001540ull))
+#define CVMX_MIO_FUS_TGG (CVMX_ADD_IO_SEG(0x0001180000001428ull))
 #define CVMX_MIO_FUS_UNLOCK (CVMX_ADD_IO_SEG(0x0001180000001578ull))
 #define CVMX_MIO_FUS_WADR (CVMX_ADD_IO_SEG(0x0001180000001508ull))
 #define CVMX_MIO_GPIO_COMP (CVMX_ADD_IO_SEG(0x00011800000000C8ull))
 #define CVMX_MIO_NDF_DMA_INT_EN (CVMX_ADD_IO_SEG(0x0001180000000178ull))
 #define CVMX_MIO_PLL_CTL (CVMX_ADD_IO_SEG(0x0001180000001448ull))
 #define CVMX_MIO_PLL_SETTING (CVMX_ADD_IO_SEG(0x0001180000001440ull))
+#define CVMX_MIO_PTP_CKOUT_HI_INCR (CVMX_ADD_IO_SEG(0x0001070000000F40ull))
+#define CVMX_MIO_PTP_CKOUT_LO_INCR (CVMX_ADD_IO_SEG(0x0001070000000F48ull))
+#define CVMX_MIO_PTP_CKOUT_THRESH_HI (CVMX_ADD_IO_SEG(0x0001070000000F38ull))
+#define CVMX_MIO_PTP_CKOUT_THRESH_LO (CVMX_ADD_IO_SEG(0x0001070000000F30ull))
 #define CVMX_MIO_PTP_CLOCK_CFG (CVMX_ADD_IO_SEG(0x0001070000000F00ull))
 #define CVMX_MIO_PTP_CLOCK_COMP (CVMX_ADD_IO_SEG(0x0001070000000F18ull))
 #define CVMX_MIO_PTP_CLOCK_HI (CVMX_ADD_IO_SEG(0x0001070000000F10ull))
 #define CVMX_MIO_PTP_CLOCK_LO (CVMX_ADD_IO_SEG(0x0001070000000F08ull))
 #define CVMX_MIO_PTP_EVT_CNT (CVMX_ADD_IO_SEG(0x0001070000000F28ull))
+#define CVMX_MIO_PTP_PPS_HI_INCR (CVMX_ADD_IO_SEG(0x0001070000000F60ull))
+#define CVMX_MIO_PTP_PPS_LO_INCR (CVMX_ADD_IO_SEG(0x0001070000000F68ull))
+#define CVMX_MIO_PTP_PPS_THRESH_HI (CVMX_ADD_IO_SEG(0x0001070000000F58ull))
+#define CVMX_MIO_PTP_PPS_THRESH_LO (CVMX_ADD_IO_SEG(0x0001070000000F50ull))
 #define CVMX_MIO_PTP_TIMESTAMP (CVMX_ADD_IO_SEG(0x0001070000000F20ull))
+#define CVMX_MIO_QLMX_CFG(offset) (CVMX_ADD_IO_SEG(0x0001180000001590ull) + ((offset) & 7) * 8)
 #define CVMX_MIO_RST_BOOT (CVMX_ADD_IO_SEG(0x0001180000001600ull))
 #define CVMX_MIO_RST_CFG (CVMX_ADD_IO_SEG(0x0001180000001610ull))
+#define CVMX_MIO_RST_CKILL (CVMX_ADD_IO_SEG(0x0001180000001638ull))
+#define CVMX_MIO_RST_CNTLX(offset) (CVMX_ADD_IO_SEG(0x0001180000001648ull) + ((offset) & 3) * 8)
 #define CVMX_MIO_RST_CTLX(offset) (CVMX_ADD_IO_SEG(0x0001180000001618ull) + ((offset) & 1) * 8)
 #define CVMX_MIO_RST_DELAY (CVMX_ADD_IO_SEG(0x0001180000001608ull))
 #define CVMX_MIO_RST_INT (CVMX_ADD_IO_SEG(0x0001180000001628ull))
@@ -183,11 +211,21 @@ union cvmx_mio_boot_bist_stat {
        struct cvmx_mio_boot_bist_stat_cn52xxp1 cn56xxp1;
        struct cvmx_mio_boot_bist_stat_cn38xx cn58xx;
        struct cvmx_mio_boot_bist_stat_cn38xx cn58xxp1;
+       struct cvmx_mio_boot_bist_stat_cn61xx {
+               uint64_t reserved_12_63:52;
+               uint64_t stat:12;
+       } cn61xx;
        struct cvmx_mio_boot_bist_stat_cn63xx {
                uint64_t reserved_9_63:55;
                uint64_t stat:9;
        } cn63xx;
        struct cvmx_mio_boot_bist_stat_cn63xx cn63xxp1;
+       struct cvmx_mio_boot_bist_stat_cn66xx {
+               uint64_t reserved_10_63:54;
+               uint64_t stat:10;
+       } cn66xx;
+       struct cvmx_mio_boot_bist_stat_cn66xx cn68xx;
+       struct cvmx_mio_boot_bist_stat_cn66xx cn68xxp1;
 };
 
 union cvmx_mio_boot_comp {
@@ -204,12 +242,16 @@ union cvmx_mio_boot_comp {
        struct cvmx_mio_boot_comp_cn50xx cn52xxp1;
        struct cvmx_mio_boot_comp_cn50xx cn56xx;
        struct cvmx_mio_boot_comp_cn50xx cn56xxp1;
-       struct cvmx_mio_boot_comp_cn63xx {
+       struct cvmx_mio_boot_comp_cn61xx {
                uint64_t reserved_12_63:52;
                uint64_t pctl:6;
                uint64_t nctl:6;
-       } cn63xx;
-       struct cvmx_mio_boot_comp_cn63xx cn63xxp1;
+       } cn61xx;
+       struct cvmx_mio_boot_comp_cn61xx cn63xx;
+       struct cvmx_mio_boot_comp_cn61xx cn63xxp1;
+       struct cvmx_mio_boot_comp_cn61xx cn66xx;
+       struct cvmx_mio_boot_comp_cn61xx cn68xx;
+       struct cvmx_mio_boot_comp_cn61xx cn68xxp1;
 };
 
 union cvmx_mio_boot_dma_cfgx {
@@ -230,8 +272,12 @@ union cvmx_mio_boot_dma_cfgx {
        struct cvmx_mio_boot_dma_cfgx_s cn52xxp1;
        struct cvmx_mio_boot_dma_cfgx_s cn56xx;
        struct cvmx_mio_boot_dma_cfgx_s cn56xxp1;
+       struct cvmx_mio_boot_dma_cfgx_s cn61xx;
        struct cvmx_mio_boot_dma_cfgx_s cn63xx;
        struct cvmx_mio_boot_dma_cfgx_s cn63xxp1;
+       struct cvmx_mio_boot_dma_cfgx_s cn66xx;
+       struct cvmx_mio_boot_dma_cfgx_s cn68xx;
+       struct cvmx_mio_boot_dma_cfgx_s cn68xxp1;
 };
 
 union cvmx_mio_boot_dma_intx {
@@ -245,8 +291,12 @@ union cvmx_mio_boot_dma_intx {
        struct cvmx_mio_boot_dma_intx_s cn52xxp1;
        struct cvmx_mio_boot_dma_intx_s cn56xx;
        struct cvmx_mio_boot_dma_intx_s cn56xxp1;
+       struct cvmx_mio_boot_dma_intx_s cn61xx;
        struct cvmx_mio_boot_dma_intx_s cn63xx;
        struct cvmx_mio_boot_dma_intx_s cn63xxp1;
+       struct cvmx_mio_boot_dma_intx_s cn66xx;
+       struct cvmx_mio_boot_dma_intx_s cn68xx;
+       struct cvmx_mio_boot_dma_intx_s cn68xxp1;
 };
 
 union cvmx_mio_boot_dma_int_enx {
@@ -260,8 +310,12 @@ union cvmx_mio_boot_dma_int_enx {
        struct cvmx_mio_boot_dma_int_enx_s cn52xxp1;
        struct cvmx_mio_boot_dma_int_enx_s cn56xx;
        struct cvmx_mio_boot_dma_int_enx_s cn56xxp1;
+       struct cvmx_mio_boot_dma_int_enx_s cn61xx;
        struct cvmx_mio_boot_dma_int_enx_s cn63xx;
        struct cvmx_mio_boot_dma_int_enx_s cn63xxp1;
+       struct cvmx_mio_boot_dma_int_enx_s cn66xx;
+       struct cvmx_mio_boot_dma_int_enx_s cn68xx;
+       struct cvmx_mio_boot_dma_int_enx_s cn68xxp1;
 };
 
 union cvmx_mio_boot_dma_timx {
@@ -287,8 +341,12 @@ union cvmx_mio_boot_dma_timx {
        struct cvmx_mio_boot_dma_timx_s cn52xxp1;
        struct cvmx_mio_boot_dma_timx_s cn56xx;
        struct cvmx_mio_boot_dma_timx_s cn56xxp1;
+       struct cvmx_mio_boot_dma_timx_s cn61xx;
        struct cvmx_mio_boot_dma_timx_s cn63xx;
        struct cvmx_mio_boot_dma_timx_s cn63xxp1;
+       struct cvmx_mio_boot_dma_timx_s cn66xx;
+       struct cvmx_mio_boot_dma_timx_s cn68xx;
+       struct cvmx_mio_boot_dma_timx_s cn68xxp1;
 };
 
 union cvmx_mio_boot_err {
@@ -309,8 +367,12 @@ union cvmx_mio_boot_err {
        struct cvmx_mio_boot_err_s cn56xxp1;
        struct cvmx_mio_boot_err_s cn58xx;
        struct cvmx_mio_boot_err_s cn58xxp1;
+       struct cvmx_mio_boot_err_s cn61xx;
        struct cvmx_mio_boot_err_s cn63xx;
        struct cvmx_mio_boot_err_s cn63xxp1;
+       struct cvmx_mio_boot_err_s cn66xx;
+       struct cvmx_mio_boot_err_s cn68xx;
+       struct cvmx_mio_boot_err_s cn68xxp1;
 };
 
 union cvmx_mio_boot_int {
@@ -331,8 +393,12 @@ union cvmx_mio_boot_int {
        struct cvmx_mio_boot_int_s cn56xxp1;
        struct cvmx_mio_boot_int_s cn58xx;
        struct cvmx_mio_boot_int_s cn58xxp1;
+       struct cvmx_mio_boot_int_s cn61xx;
        struct cvmx_mio_boot_int_s cn63xx;
        struct cvmx_mio_boot_int_s cn63xxp1;
+       struct cvmx_mio_boot_int_s cn66xx;
+       struct cvmx_mio_boot_int_s cn68xx;
+       struct cvmx_mio_boot_int_s cn68xxp1;
 };
 
 union cvmx_mio_boot_loc_adr {
@@ -353,8 +419,12 @@ union cvmx_mio_boot_loc_adr {
        struct cvmx_mio_boot_loc_adr_s cn56xxp1;
        struct cvmx_mio_boot_loc_adr_s cn58xx;
        struct cvmx_mio_boot_loc_adr_s cn58xxp1;
+       struct cvmx_mio_boot_loc_adr_s cn61xx;
        struct cvmx_mio_boot_loc_adr_s cn63xx;
        struct cvmx_mio_boot_loc_adr_s cn63xxp1;
+       struct cvmx_mio_boot_loc_adr_s cn66xx;
+       struct cvmx_mio_boot_loc_adr_s cn68xx;
+       struct cvmx_mio_boot_loc_adr_s cn68xxp1;
 };
 
 union cvmx_mio_boot_loc_cfgx {
@@ -377,8 +447,12 @@ union cvmx_mio_boot_loc_cfgx {
        struct cvmx_mio_boot_loc_cfgx_s cn56xxp1;
        struct cvmx_mio_boot_loc_cfgx_s cn58xx;
        struct cvmx_mio_boot_loc_cfgx_s cn58xxp1;
+       struct cvmx_mio_boot_loc_cfgx_s cn61xx;
        struct cvmx_mio_boot_loc_cfgx_s cn63xx;
        struct cvmx_mio_boot_loc_cfgx_s cn63xxp1;
+       struct cvmx_mio_boot_loc_cfgx_s cn66xx;
+       struct cvmx_mio_boot_loc_cfgx_s cn68xx;
+       struct cvmx_mio_boot_loc_cfgx_s cn68xxp1;
 };
 
 union cvmx_mio_boot_loc_dat {
@@ -397,14 +471,19 @@ union cvmx_mio_boot_loc_dat {
        struct cvmx_mio_boot_loc_dat_s cn56xxp1;
        struct cvmx_mio_boot_loc_dat_s cn58xx;
        struct cvmx_mio_boot_loc_dat_s cn58xxp1;
+       struct cvmx_mio_boot_loc_dat_s cn61xx;
        struct cvmx_mio_boot_loc_dat_s cn63xx;
        struct cvmx_mio_boot_loc_dat_s cn63xxp1;
+       struct cvmx_mio_boot_loc_dat_s cn66xx;
+       struct cvmx_mio_boot_loc_dat_s cn68xx;
+       struct cvmx_mio_boot_loc_dat_s cn68xxp1;
 };
 
 union cvmx_mio_boot_pin_defs {
        uint64_t u64;
        struct cvmx_mio_boot_pin_defs_s {
-               uint64_t reserved_16_63:48;
+               uint64_t reserved_32_63:32;
+               uint64_t user1:16;
                uint64_t ale:1;
                uint64_t width:1;
                uint64_t dmack_p2:1;
@@ -412,7 +491,7 @@ union cvmx_mio_boot_pin_defs {
                uint64_t dmack_p0:1;
                uint64_t term:2;
                uint64_t nand:1;
-               uint64_t reserved_0_7:8;
+               uint64_t user0:8;
        } s;
        struct cvmx_mio_boot_pin_defs_cn52xx {
                uint64_t reserved_16_63:48;
@@ -435,8 +514,23 @@ union cvmx_mio_boot_pin_defs {
                uint64_t term:2;
                uint64_t reserved_0_8:9;
        } cn56xx;
+       struct cvmx_mio_boot_pin_defs_cn61xx {
+               uint64_t reserved_32_63:32;
+               uint64_t user1:16;
+               uint64_t ale:1;
+               uint64_t width:1;
+               uint64_t reserved_13_13:1;
+               uint64_t dmack_p1:1;
+               uint64_t dmack_p0:1;
+               uint64_t term:2;
+               uint64_t nand:1;
+               uint64_t user0:8;
+       } cn61xx;
        struct cvmx_mio_boot_pin_defs_cn52xx cn63xx;
        struct cvmx_mio_boot_pin_defs_cn52xx cn63xxp1;
+       struct cvmx_mio_boot_pin_defs_cn52xx cn66xx;
+       struct cvmx_mio_boot_pin_defs_cn52xx cn68xx;
+       struct cvmx_mio_boot_pin_defs_cn52xx cn68xxp1;
 };
 
 union cvmx_mio_boot_reg_cfgx {
@@ -498,8 +592,12 @@ union cvmx_mio_boot_reg_cfgx {
        struct cvmx_mio_boot_reg_cfgx_s cn56xxp1;
        struct cvmx_mio_boot_reg_cfgx_cn30xx cn58xx;
        struct cvmx_mio_boot_reg_cfgx_cn30xx cn58xxp1;
+       struct cvmx_mio_boot_reg_cfgx_s cn61xx;
        struct cvmx_mio_boot_reg_cfgx_s cn63xx;
        struct cvmx_mio_boot_reg_cfgx_s cn63xxp1;
+       struct cvmx_mio_boot_reg_cfgx_s cn66xx;
+       struct cvmx_mio_boot_reg_cfgx_s cn68xx;
+       struct cvmx_mio_boot_reg_cfgx_s cn68xxp1;
 };
 
 union cvmx_mio_boot_reg_timx {
@@ -544,8 +642,12 @@ union cvmx_mio_boot_reg_timx {
        struct cvmx_mio_boot_reg_timx_s cn56xxp1;
        struct cvmx_mio_boot_reg_timx_s cn58xx;
        struct cvmx_mio_boot_reg_timx_s cn58xxp1;
+       struct cvmx_mio_boot_reg_timx_s cn61xx;
        struct cvmx_mio_boot_reg_timx_s cn63xx;
        struct cvmx_mio_boot_reg_timx_s cn63xxp1;
+       struct cvmx_mio_boot_reg_timx_s cn66xx;
+       struct cvmx_mio_boot_reg_timx_s cn68xx;
+       struct cvmx_mio_boot_reg_timx_s cn68xxp1;
 };
 
 union cvmx_mio_boot_thr {
@@ -574,8 +676,231 @@ union cvmx_mio_boot_thr {
        struct cvmx_mio_boot_thr_s cn56xxp1;
        struct cvmx_mio_boot_thr_cn30xx cn58xx;
        struct cvmx_mio_boot_thr_cn30xx cn58xxp1;
+       struct cvmx_mio_boot_thr_s cn61xx;
        struct cvmx_mio_boot_thr_s cn63xx;
        struct cvmx_mio_boot_thr_s cn63xxp1;
+       struct cvmx_mio_boot_thr_s cn66xx;
+       struct cvmx_mio_boot_thr_s cn68xx;
+       struct cvmx_mio_boot_thr_s cn68xxp1;
+};
+
+union cvmx_mio_emm_buf_dat {
+       uint64_t u64;
+       struct cvmx_mio_emm_buf_dat_s {
+               uint64_t dat:64;
+       } s;
+       struct cvmx_mio_emm_buf_dat_s cn61xx;
+};
+
+union cvmx_mio_emm_buf_idx {
+       uint64_t u64;
+       struct cvmx_mio_emm_buf_idx_s {
+               uint64_t reserved_17_63:47;
+               uint64_t inc:1;
+               uint64_t reserved_7_15:9;
+               uint64_t buf_num:1;
+               uint64_t offset:6;
+       } s;
+       struct cvmx_mio_emm_buf_idx_s cn61xx;
+};
+
+union cvmx_mio_emm_cfg {
+       uint64_t u64;
+       struct cvmx_mio_emm_cfg_s {
+               uint64_t reserved_17_63:47;
+               uint64_t boot_fail:1;
+               uint64_t reserved_4_15:12;
+               uint64_t bus_ena:4;
+       } s;
+       struct cvmx_mio_emm_cfg_s cn61xx;
+};
+
+union cvmx_mio_emm_cmd {
+       uint64_t u64;
+       struct cvmx_mio_emm_cmd_s {
+               uint64_t reserved_62_63:2;
+               uint64_t bus_id:2;
+               uint64_t cmd_val:1;
+               uint64_t reserved_56_58:3;
+               uint64_t dbuf:1;
+               uint64_t offset:6;
+               uint64_t reserved_43_48:6;
+               uint64_t ctype_xor:2;
+               uint64_t rtype_xor:3;
+               uint64_t cmd_idx:6;
+               uint64_t arg:32;
+       } s;
+       struct cvmx_mio_emm_cmd_s cn61xx;
+};
+
+union cvmx_mio_emm_dma {
+       uint64_t u64;
+       struct cvmx_mio_emm_dma_s {
+               uint64_t reserved_62_63:2;
+               uint64_t bus_id:2;
+               uint64_t dma_val:1;
+               uint64_t sector:1;
+               uint64_t dat_null:1;
+               uint64_t thres:6;
+               uint64_t rel_wr:1;
+               uint64_t rw:1;
+               uint64_t multi:1;
+               uint64_t block_cnt:16;
+               uint64_t card_addr:32;
+       } s;
+       struct cvmx_mio_emm_dma_s cn61xx;
+};
+
+union cvmx_mio_emm_int {
+       uint64_t u64;
+       struct cvmx_mio_emm_int_s {
+               uint64_t reserved_7_63:57;
+               uint64_t switch_err:1;
+               uint64_t switch_done:1;
+               uint64_t dma_err:1;
+               uint64_t cmd_err:1;
+               uint64_t dma_done:1;
+               uint64_t cmd_done:1;
+               uint64_t buf_done:1;
+       } s;
+       struct cvmx_mio_emm_int_s cn61xx;
+};
+
+union cvmx_mio_emm_int_en {
+       uint64_t u64;
+       struct cvmx_mio_emm_int_en_s {
+               uint64_t reserved_7_63:57;
+               uint64_t switch_err:1;
+               uint64_t switch_done:1;
+               uint64_t dma_err:1;
+               uint64_t cmd_err:1;
+               uint64_t dma_done:1;
+               uint64_t cmd_done:1;
+               uint64_t buf_done:1;
+       } s;
+       struct cvmx_mio_emm_int_en_s cn61xx;
+};
+
+union cvmx_mio_emm_modex {
+       uint64_t u64;
+       struct cvmx_mio_emm_modex_s {
+               uint64_t reserved_49_63:15;
+               uint64_t hs_timing:1;
+               uint64_t reserved_43_47:5;
+               uint64_t bus_width:3;
+               uint64_t reserved_36_39:4;
+               uint64_t power_class:4;
+               uint64_t clk_hi:16;
+               uint64_t clk_lo:16;
+       } s;
+       struct cvmx_mio_emm_modex_s cn61xx;
+};
+
+union cvmx_mio_emm_rca {
+       uint64_t u64;
+       struct cvmx_mio_emm_rca_s {
+               uint64_t reserved_16_63:48;
+               uint64_t card_rca:16;
+       } s;
+       struct cvmx_mio_emm_rca_s cn61xx;
+};
+
+union cvmx_mio_emm_rsp_hi {
+       uint64_t u64;
+       struct cvmx_mio_emm_rsp_hi_s {
+               uint64_t dat:64;
+       } s;
+       struct cvmx_mio_emm_rsp_hi_s cn61xx;
+};
+
+union cvmx_mio_emm_rsp_lo {
+       uint64_t u64;
+       struct cvmx_mio_emm_rsp_lo_s {
+               uint64_t dat:64;
+       } s;
+       struct cvmx_mio_emm_rsp_lo_s cn61xx;
+};
+
+union cvmx_mio_emm_rsp_sts {
+       uint64_t u64;
+       struct cvmx_mio_emm_rsp_sts_s {
+               uint64_t reserved_62_63:2;
+               uint64_t bus_id:2;
+               uint64_t cmd_val:1;
+               uint64_t switch_val:1;
+               uint64_t dma_val:1;
+               uint64_t dma_pend:1;
+               uint64_t reserved_29_55:27;
+               uint64_t dbuf_err:1;
+               uint64_t reserved_24_27:4;
+               uint64_t dbuf:1;
+               uint64_t blk_timeout:1;
+               uint64_t blk_crc_err:1;
+               uint64_t rsp_busybit:1;
+               uint64_t stp_timeout:1;
+               uint64_t stp_crc_err:1;
+               uint64_t stp_bad_sts:1;
+               uint64_t stp_val:1;
+               uint64_t rsp_timeout:1;
+               uint64_t rsp_crc_err:1;
+               uint64_t rsp_bad_sts:1;
+               uint64_t rsp_val:1;
+               uint64_t rsp_type:3;
+               uint64_t cmd_type:2;
+               uint64_t cmd_idx:6;
+               uint64_t cmd_done:1;
+       } s;
+       struct cvmx_mio_emm_rsp_sts_s cn61xx;
+};
+
+union cvmx_mio_emm_sample {
+       uint64_t u64;
+       struct cvmx_mio_emm_sample_s {
+               uint64_t reserved_26_63:38;
+               uint64_t cmd_cnt:10;
+               uint64_t reserved_10_15:6;
+               uint64_t dat_cnt:10;
+       } s;
+       struct cvmx_mio_emm_sample_s cn61xx;
+};
+
+union cvmx_mio_emm_sts_mask {
+       uint64_t u64;
+       struct cvmx_mio_emm_sts_mask_s {
+               uint64_t reserved_32_63:32;
+               uint64_t sts_msk:32;
+       } s;
+       struct cvmx_mio_emm_sts_mask_s cn61xx;
+};
+
+union cvmx_mio_emm_switch {
+       uint64_t u64;
+       struct cvmx_mio_emm_switch_s {
+               uint64_t reserved_62_63:2;
+               uint64_t bus_id:2;
+               uint64_t switch_exe:1;
+               uint64_t switch_err0:1;
+               uint64_t switch_err1:1;
+               uint64_t switch_err2:1;
+               uint64_t reserved_49_55:7;
+               uint64_t hs_timing:1;
+               uint64_t reserved_43_47:5;
+               uint64_t bus_width:3;
+               uint64_t reserved_36_39:4;
+               uint64_t power_class:4;
+               uint64_t clk_hi:16;
+               uint64_t clk_lo:16;
+       } s;
+       struct cvmx_mio_emm_switch_s cn61xx;
+};
+
+union cvmx_mio_emm_wdog {
+       uint64_t u64;
+       struct cvmx_mio_emm_wdog_s {
+               uint64_t reserved_26_63:38;
+               uint64_t clk_cnt:26;
+       } s;
+       struct cvmx_mio_emm_wdog_s cn61xx;
 };
 
 union cvmx_mio_fus_bnk_datx {
@@ -590,8 +915,12 @@ union cvmx_mio_fus_bnk_datx {
        struct cvmx_mio_fus_bnk_datx_s cn56xxp1;
        struct cvmx_mio_fus_bnk_datx_s cn58xx;
        struct cvmx_mio_fus_bnk_datx_s cn58xxp1;
+       struct cvmx_mio_fus_bnk_datx_s cn61xx;
        struct cvmx_mio_fus_bnk_datx_s cn63xx;
        struct cvmx_mio_fus_bnk_datx_s cn63xxp1;
+       struct cvmx_mio_fus_bnk_datx_s cn66xx;
+       struct cvmx_mio_fus_bnk_datx_s cn68xx;
+       struct cvmx_mio_fus_bnk_datx_s cn68xxp1;
 };
 
 union cvmx_mio_fus_dat0 {
@@ -611,8 +940,12 @@ union cvmx_mio_fus_dat0 {
        struct cvmx_mio_fus_dat0_s cn56xxp1;
        struct cvmx_mio_fus_dat0_s cn58xx;
        struct cvmx_mio_fus_dat0_s cn58xxp1;
+       struct cvmx_mio_fus_dat0_s cn61xx;
        struct cvmx_mio_fus_dat0_s cn63xx;
        struct cvmx_mio_fus_dat0_s cn63xxp1;
+       struct cvmx_mio_fus_dat0_s cn66xx;
+       struct cvmx_mio_fus_dat0_s cn68xx;
+       struct cvmx_mio_fus_dat0_s cn68xxp1;
 };
 
 union cvmx_mio_fus_dat1 {
@@ -632,14 +965,21 @@ union cvmx_mio_fus_dat1 {
        struct cvmx_mio_fus_dat1_s cn56xxp1;
        struct cvmx_mio_fus_dat1_s cn58xx;
        struct cvmx_mio_fus_dat1_s cn58xxp1;
+       struct cvmx_mio_fus_dat1_s cn61xx;
        struct cvmx_mio_fus_dat1_s cn63xx;
        struct cvmx_mio_fus_dat1_s cn63xxp1;
+       struct cvmx_mio_fus_dat1_s cn66xx;
+       struct cvmx_mio_fus_dat1_s cn68xx;
+       struct cvmx_mio_fus_dat1_s cn68xxp1;
 };
 
 union cvmx_mio_fus_dat2 {
        uint64_t u64;
        struct cvmx_mio_fus_dat2_s {
-               uint64_t reserved_35_63:29;
+               uint64_t reserved_48_63:16;
+               uint64_t fus118:1;
+               uint64_t rom_info:10;
+               uint64_t power_limit:2;
                uint64_t dorm_crypto:1;
                uint64_t fus318:1;
                uint64_t raid_en:1;
@@ -747,6 +1087,23 @@ union cvmx_mio_fus_dat2 {
                uint64_t pp_dis:16;
        } cn58xx;
        struct cvmx_mio_fus_dat2_cn58xx cn58xxp1;
+       struct cvmx_mio_fus_dat2_cn61xx {
+               uint64_t reserved_48_63:16;
+               uint64_t fus118:1;
+               uint64_t rom_info:10;
+               uint64_t power_limit:2;
+               uint64_t dorm_crypto:1;
+               uint64_t fus318:1;
+               uint64_t raid_en:1;
+               uint64_t reserved_29_31:3;
+               uint64_t nodfa_cp2:1;
+               uint64_t nomul:1;
+               uint64_t nocrypto:1;
+               uint64_t reserved_24_25:2;
+               uint64_t chip_id:8;
+               uint64_t reserved_4_15:12;
+               uint64_t pp_dis:4;
+       } cn61xx;
        struct cvmx_mio_fus_dat2_cn63xx {
                uint64_t reserved_35_63:29;
                uint64_t dorm_crypto:1;
@@ -762,6 +1119,38 @@ union cvmx_mio_fus_dat2 {
                uint64_t pp_dis:6;
        } cn63xx;
        struct cvmx_mio_fus_dat2_cn63xx cn63xxp1;
+       struct cvmx_mio_fus_dat2_cn66xx {
+               uint64_t reserved_48_63:16;
+               uint64_t fus118:1;
+               uint64_t rom_info:10;
+               uint64_t power_limit:2;
+               uint64_t dorm_crypto:1;
+               uint64_t fus318:1;
+               uint64_t raid_en:1;
+               uint64_t reserved_29_31:3;
+               uint64_t nodfa_cp2:1;
+               uint64_t nomul:1;
+               uint64_t nocrypto:1;
+               uint64_t reserved_24_25:2;
+               uint64_t chip_id:8;
+               uint64_t reserved_10_15:6;
+               uint64_t pp_dis:10;
+       } cn66xx;
+       struct cvmx_mio_fus_dat2_cn68xx {
+               uint64_t reserved_37_63:27;
+               uint64_t power_limit:2;
+               uint64_t dorm_crypto:1;
+               uint64_t fus318:1;
+               uint64_t raid_en:1;
+               uint64_t reserved_29_31:3;
+               uint64_t nodfa_cp2:1;
+               uint64_t nomul:1;
+               uint64_t nocrypto:1;
+               uint64_t reserved_24_25:2;
+               uint64_t chip_id:8;
+               uint64_t reserved_0_15:16;
+       } cn68xx;
+       struct cvmx_mio_fus_dat2_cn68xx cn68xxp1;
 };
 
 union cvmx_mio_fus_dat3 {
@@ -834,7 +1223,7 @@ union cvmx_mio_fus_dat3 {
        struct cvmx_mio_fus_dat3_cn38xx cn56xxp1;
        struct cvmx_mio_fus_dat3_cn38xx cn58xx;
        struct cvmx_mio_fus_dat3_cn38xx cn58xxp1;
-       struct cvmx_mio_fus_dat3_cn63xx {
+       struct cvmx_mio_fus_dat3_cn61xx {
                uint64_t reserved_58_63:6;
                uint64_t pll_ctl:10;
                uint64_t dfa_info_dte:3;
@@ -853,8 +1242,12 @@ union cvmx_mio_fus_dat3 {
                uint64_t nozip:1;
                uint64_t nodfa_dte:1;
                uint64_t reserved_0_23:24;
-       } cn63xx;
-       struct cvmx_mio_fus_dat3_cn63xx cn63xxp1;
+       } cn61xx;
+       struct cvmx_mio_fus_dat3_cn61xx cn63xx;
+       struct cvmx_mio_fus_dat3_cn61xx cn63xxp1;
+       struct cvmx_mio_fus_dat3_cn61xx cn66xx;
+       struct cvmx_mio_fus_dat3_cn61xx cn68xx;
+       struct cvmx_mio_fus_dat3_cn61xx cn68xxp1;
 };
 
 union cvmx_mio_fus_ema {
@@ -875,8 +1268,12 @@ union cvmx_mio_fus_ema {
                uint64_t ema:2;
        } cn58xx;
        struct cvmx_mio_fus_ema_cn58xx cn58xxp1;
+       struct cvmx_mio_fus_ema_s cn61xx;
        struct cvmx_mio_fus_ema_s cn63xx;
        struct cvmx_mio_fus_ema_s cn63xxp1;
+       struct cvmx_mio_fus_ema_s cn66xx;
+       struct cvmx_mio_fus_ema_s cn68xx;
+       struct cvmx_mio_fus_ema_s cn68xxp1;
 };
 
 union cvmx_mio_fus_pdf {
@@ -890,14 +1287,21 @@ union cvmx_mio_fus_pdf {
        struct cvmx_mio_fus_pdf_s cn56xx;
        struct cvmx_mio_fus_pdf_s cn56xxp1;
        struct cvmx_mio_fus_pdf_s cn58xx;
+       struct cvmx_mio_fus_pdf_s cn61xx;
        struct cvmx_mio_fus_pdf_s cn63xx;
        struct cvmx_mio_fus_pdf_s cn63xxp1;
+       struct cvmx_mio_fus_pdf_s cn66xx;
+       struct cvmx_mio_fus_pdf_s cn68xx;
+       struct cvmx_mio_fus_pdf_s cn68xxp1;
 };
 
 union cvmx_mio_fus_pll {
        uint64_t u64;
        struct cvmx_mio_fus_pll_s {
-               uint64_t reserved_8_63:56;
+               uint64_t reserved_48_63:16;
+               uint64_t rclk_align_r:8;
+               uint64_t rclk_align_l:8;
+               uint64_t reserved_8_31:24;
                uint64_t c_cout_rst:1;
                uint64_t c_cout_sel:2;
                uint64_t pnr_cout_rst:1;
@@ -916,8 +1320,20 @@ union cvmx_mio_fus_pll {
        struct cvmx_mio_fus_pll_cn50xx cn56xxp1;
        struct cvmx_mio_fus_pll_cn50xx cn58xx;
        struct cvmx_mio_fus_pll_cn50xx cn58xxp1;
-       struct cvmx_mio_fus_pll_s cn63xx;
-       struct cvmx_mio_fus_pll_s cn63xxp1;
+       struct cvmx_mio_fus_pll_cn61xx {
+               uint64_t reserved_8_63:56;
+               uint64_t c_cout_rst:1;
+               uint64_t c_cout_sel:2;
+               uint64_t pnr_cout_rst:1;
+               uint64_t pnr_cout_sel:2;
+               uint64_t rfslip:1;
+               uint64_t fbslip:1;
+       } cn61xx;
+       struct cvmx_mio_fus_pll_cn61xx cn63xx;
+       struct cvmx_mio_fus_pll_cn61xx cn63xxp1;
+       struct cvmx_mio_fus_pll_cn61xx cn66xx;
+       struct cvmx_mio_fus_pll_s cn68xx;
+       struct cvmx_mio_fus_pll_s cn68xxp1;
 };
 
 union cvmx_mio_fus_prog {
@@ -941,8 +1357,12 @@ union cvmx_mio_fus_prog {
        struct cvmx_mio_fus_prog_cn30xx cn56xxp1;
        struct cvmx_mio_fus_prog_cn30xx cn58xx;
        struct cvmx_mio_fus_prog_cn30xx cn58xxp1;
+       struct cvmx_mio_fus_prog_s cn61xx;
        struct cvmx_mio_fus_prog_s cn63xx;
        struct cvmx_mio_fus_prog_s cn63xxp1;
+       struct cvmx_mio_fus_prog_s cn66xx;
+       struct cvmx_mio_fus_prog_s cn68xx;
+       struct cvmx_mio_fus_prog_s cn68xxp1;
 };
 
 union cvmx_mio_fus_prog_times {
@@ -969,7 +1389,7 @@ union cvmx_mio_fus_prog_times {
        struct cvmx_mio_fus_prog_times_cn50xx cn56xxp1;
        struct cvmx_mio_fus_prog_times_cn50xx cn58xx;
        struct cvmx_mio_fus_prog_times_cn50xx cn58xxp1;
-       struct cvmx_mio_fus_prog_times_cn63xx {
+       struct cvmx_mio_fus_prog_times_cn61xx {
                uint64_t reserved_35_63:29;
                uint64_t vgate_pin:1;
                uint64_t fsrc_pin:1;
@@ -978,8 +1398,12 @@ union cvmx_mio_fus_prog_times {
                uint64_t sclk_lo:4;
                uint64_t sclk_hi:15;
                uint64_t setup:6;
-       } cn63xx;
-       struct cvmx_mio_fus_prog_times_cn63xx cn63xxp1;
+       } cn61xx;
+       struct cvmx_mio_fus_prog_times_cn61xx cn63xx;
+       struct cvmx_mio_fus_prog_times_cn61xx cn63xxp1;
+       struct cvmx_mio_fus_prog_times_cn61xx cn66xx;
+       struct cvmx_mio_fus_prog_times_cn61xx cn68xx;
+       struct cvmx_mio_fus_prog_times_cn61xx cn68xxp1;
 };
 
 union cvmx_mio_fus_rcmd {
@@ -1013,8 +1437,12 @@ union cvmx_mio_fus_rcmd {
        struct cvmx_mio_fus_rcmd_s cn56xxp1;
        struct cvmx_mio_fus_rcmd_cn30xx cn58xx;
        struct cvmx_mio_fus_rcmd_cn30xx cn58xxp1;
+       struct cvmx_mio_fus_rcmd_s cn61xx;
        struct cvmx_mio_fus_rcmd_s cn63xx;
        struct cvmx_mio_fus_rcmd_s cn63xxp1;
+       struct cvmx_mio_fus_rcmd_s cn66xx;
+       struct cvmx_mio_fus_rcmd_s cn68xx;
+       struct cvmx_mio_fus_rcmd_s cn68xxp1;
 };
 
 union cvmx_mio_fus_read_times {
@@ -1027,8 +1455,12 @@ union cvmx_mio_fus_read_times {
                uint64_t sdh:4;
                uint64_t setup:10;
        } s;
+       struct cvmx_mio_fus_read_times_s cn61xx;
        struct cvmx_mio_fus_read_times_s cn63xx;
        struct cvmx_mio_fus_read_times_s cn63xxp1;
+       struct cvmx_mio_fus_read_times_s cn66xx;
+       struct cvmx_mio_fus_read_times_s cn68xx;
+       struct cvmx_mio_fus_read_times_s cn68xxp1;
 };
 
 union cvmx_mio_fus_repair_res0 {
@@ -1040,8 +1472,12 @@ union cvmx_mio_fus_repair_res0 {
                uint64_t repair1:18;
                uint64_t repair0:18;
        } s;
+       struct cvmx_mio_fus_repair_res0_s cn61xx;
        struct cvmx_mio_fus_repair_res0_s cn63xx;
        struct cvmx_mio_fus_repair_res0_s cn63xxp1;
+       struct cvmx_mio_fus_repair_res0_s cn66xx;
+       struct cvmx_mio_fus_repair_res0_s cn68xx;
+       struct cvmx_mio_fus_repair_res0_s cn68xxp1;
 };
 
 union cvmx_mio_fus_repair_res1 {
@@ -1052,8 +1488,12 @@ union cvmx_mio_fus_repair_res1 {
                uint64_t repair4:18;
                uint64_t repair3:18;
        } s;
+       struct cvmx_mio_fus_repair_res1_s cn61xx;
        struct cvmx_mio_fus_repair_res1_s cn63xx;
        struct cvmx_mio_fus_repair_res1_s cn63xxp1;
+       struct cvmx_mio_fus_repair_res1_s cn66xx;
+       struct cvmx_mio_fus_repair_res1_s cn68xx;
+       struct cvmx_mio_fus_repair_res1_s cn68xxp1;
 };
 
 union cvmx_mio_fus_repair_res2 {
@@ -1062,8 +1502,12 @@ union cvmx_mio_fus_repair_res2 {
                uint64_t reserved_18_63:46;
                uint64_t repair6:18;
        } s;
+       struct cvmx_mio_fus_repair_res2_s cn61xx;
        struct cvmx_mio_fus_repair_res2_s cn63xx;
        struct cvmx_mio_fus_repair_res2_s cn63xxp1;
+       struct cvmx_mio_fus_repair_res2_s cn66xx;
+       struct cvmx_mio_fus_repair_res2_s cn68xx;
+       struct cvmx_mio_fus_repair_res2_s cn68xxp1;
 };
 
 union cvmx_mio_fus_spr_repair_res {
@@ -1084,8 +1528,12 @@ union cvmx_mio_fus_spr_repair_res {
        struct cvmx_mio_fus_spr_repair_res_s cn56xxp1;
        struct cvmx_mio_fus_spr_repair_res_s cn58xx;
        struct cvmx_mio_fus_spr_repair_res_s cn58xxp1;
+       struct cvmx_mio_fus_spr_repair_res_s cn61xx;
        struct cvmx_mio_fus_spr_repair_res_s cn63xx;
        struct cvmx_mio_fus_spr_repair_res_s cn63xxp1;
+       struct cvmx_mio_fus_spr_repair_res_s cn66xx;
+       struct cvmx_mio_fus_spr_repair_res_s cn68xx;
+       struct cvmx_mio_fus_spr_repair_res_s cn68xxp1;
 };
 
 union cvmx_mio_fus_spr_repair_sum {
@@ -1104,8 +1552,22 @@ union cvmx_mio_fus_spr_repair_sum {
        struct cvmx_mio_fus_spr_repair_sum_s cn56xxp1;
        struct cvmx_mio_fus_spr_repair_sum_s cn58xx;
        struct cvmx_mio_fus_spr_repair_sum_s cn58xxp1;
+       struct cvmx_mio_fus_spr_repair_sum_s cn61xx;
        struct cvmx_mio_fus_spr_repair_sum_s cn63xx;
        struct cvmx_mio_fus_spr_repair_sum_s cn63xxp1;
+       struct cvmx_mio_fus_spr_repair_sum_s cn66xx;
+       struct cvmx_mio_fus_spr_repair_sum_s cn68xx;
+       struct cvmx_mio_fus_spr_repair_sum_s cn68xxp1;
+};
+
+union cvmx_mio_fus_tgg {
+       uint64_t u64;
+       struct cvmx_mio_fus_tgg_s {
+               uint64_t val:1;
+               uint64_t dat:63;
+       } s;
+       struct cvmx_mio_fus_tgg_s cn61xx;
+       struct cvmx_mio_fus_tgg_s cn66xx;
 };
 
 union cvmx_mio_fus_unlock {
@@ -1141,11 +1603,15 @@ union cvmx_mio_fus_wadr {
        struct cvmx_mio_fus_wadr_cn52xx cn56xxp1;
        struct cvmx_mio_fus_wadr_cn50xx cn58xx;
        struct cvmx_mio_fus_wadr_cn50xx cn58xxp1;
-       struct cvmx_mio_fus_wadr_cn63xx {
+       struct cvmx_mio_fus_wadr_cn61xx {
                uint64_t reserved_4_63:60;
                uint64_t addr:4;
-       } cn63xx;
-       struct cvmx_mio_fus_wadr_cn63xx cn63xxp1;
+       } cn61xx;
+       struct cvmx_mio_fus_wadr_cn61xx cn63xx;
+       struct cvmx_mio_fus_wadr_cn61xx cn63xxp1;
+       struct cvmx_mio_fus_wadr_cn61xx cn66xx;
+       struct cvmx_mio_fus_wadr_cn61xx cn68xx;
+       struct cvmx_mio_fus_wadr_cn61xx cn68xxp1;
 };
 
 union cvmx_mio_gpio_comp {
@@ -1155,8 +1621,12 @@ union cvmx_mio_gpio_comp {
                uint64_t pctl:6;
                uint64_t nctl:6;
        } s;
+       struct cvmx_mio_gpio_comp_s cn61xx;
        struct cvmx_mio_gpio_comp_s cn63xx;
        struct cvmx_mio_gpio_comp_s cn63xxp1;
+       struct cvmx_mio_gpio_comp_s cn66xx;
+       struct cvmx_mio_gpio_comp_s cn68xx;
+       struct cvmx_mio_gpio_comp_s cn68xxp1;
 };
 
 union cvmx_mio_ndf_dma_cfg {
@@ -1174,8 +1644,12 @@ union cvmx_mio_ndf_dma_cfg {
                uint64_t adr:36;
        } s;
        struct cvmx_mio_ndf_dma_cfg_s cn52xx;
+       struct cvmx_mio_ndf_dma_cfg_s cn61xx;
        struct cvmx_mio_ndf_dma_cfg_s cn63xx;
        struct cvmx_mio_ndf_dma_cfg_s cn63xxp1;
+       struct cvmx_mio_ndf_dma_cfg_s cn66xx;
+       struct cvmx_mio_ndf_dma_cfg_s cn68xx;
+       struct cvmx_mio_ndf_dma_cfg_s cn68xxp1;
 };
 
 union cvmx_mio_ndf_dma_int {
@@ -1185,8 +1659,12 @@ union cvmx_mio_ndf_dma_int {
                uint64_t done:1;
        } s;
        struct cvmx_mio_ndf_dma_int_s cn52xx;
+       struct cvmx_mio_ndf_dma_int_s cn61xx;
        struct cvmx_mio_ndf_dma_int_s cn63xx;
        struct cvmx_mio_ndf_dma_int_s cn63xxp1;
+       struct cvmx_mio_ndf_dma_int_s cn66xx;
+       struct cvmx_mio_ndf_dma_int_s cn68xx;
+       struct cvmx_mio_ndf_dma_int_s cn68xxp1;
 };
 
 union cvmx_mio_ndf_dma_int_en {
@@ -1196,8 +1674,12 @@ union cvmx_mio_ndf_dma_int_en {
                uint64_t done:1;
        } s;
        struct cvmx_mio_ndf_dma_int_en_s cn52xx;
+       struct cvmx_mio_ndf_dma_int_en_s cn61xx;
        struct cvmx_mio_ndf_dma_int_en_s cn63xx;
        struct cvmx_mio_ndf_dma_int_en_s cn63xxp1;
+       struct cvmx_mio_ndf_dma_int_en_s cn66xx;
+       struct cvmx_mio_ndf_dma_int_en_s cn68xx;
+       struct cvmx_mio_ndf_dma_int_en_s cn68xxp1;
 };
 
 union cvmx_mio_pll_ctl {
@@ -1220,10 +1702,63 @@ union cvmx_mio_pll_setting {
        struct cvmx_mio_pll_setting_s cn31xx;
 };
 
+union cvmx_mio_ptp_ckout_hi_incr {
+       uint64_t u64;
+       struct cvmx_mio_ptp_ckout_hi_incr_s {
+               uint64_t nanosec:32;
+               uint64_t frnanosec:32;
+       } s;
+       struct cvmx_mio_ptp_ckout_hi_incr_s cn61xx;
+       struct cvmx_mio_ptp_ckout_hi_incr_s cn66xx;
+       struct cvmx_mio_ptp_ckout_hi_incr_s cn68xx;
+};
+
+union cvmx_mio_ptp_ckout_lo_incr {
+       uint64_t u64;
+       struct cvmx_mio_ptp_ckout_lo_incr_s {
+               uint64_t nanosec:32;
+               uint64_t frnanosec:32;
+       } s;
+       struct cvmx_mio_ptp_ckout_lo_incr_s cn61xx;
+       struct cvmx_mio_ptp_ckout_lo_incr_s cn66xx;
+       struct cvmx_mio_ptp_ckout_lo_incr_s cn68xx;
+};
+
+union cvmx_mio_ptp_ckout_thresh_hi {
+       uint64_t u64;
+       struct cvmx_mio_ptp_ckout_thresh_hi_s {
+               uint64_t nanosec:64;
+       } s;
+       struct cvmx_mio_ptp_ckout_thresh_hi_s cn61xx;
+       struct cvmx_mio_ptp_ckout_thresh_hi_s cn66xx;
+       struct cvmx_mio_ptp_ckout_thresh_hi_s cn68xx;
+};
+
+union cvmx_mio_ptp_ckout_thresh_lo {
+       uint64_t u64;
+       struct cvmx_mio_ptp_ckout_thresh_lo_s {
+               uint64_t reserved_32_63:32;
+               uint64_t frnanosec:32;
+       } s;
+       struct cvmx_mio_ptp_ckout_thresh_lo_s cn61xx;
+       struct cvmx_mio_ptp_ckout_thresh_lo_s cn66xx;
+       struct cvmx_mio_ptp_ckout_thresh_lo_s cn68xx;
+};
+
 union cvmx_mio_ptp_clock_cfg {
        uint64_t u64;
        struct cvmx_mio_ptp_clock_cfg_s {
-               uint64_t reserved_24_63:40;
+               uint64_t reserved_42_63:22;
+               uint64_t pps:1;
+               uint64_t ckout:1;
+               uint64_t ext_clk_edge:2;
+               uint64_t ckout_out4:1;
+               uint64_t pps_out:5;
+               uint64_t pps_inv:1;
+               uint64_t pps_en:1;
+               uint64_t ckout_out:4;
+               uint64_t ckout_inv:1;
+               uint64_t ckout_en:1;
                uint64_t evcnt_in:6;
                uint64_t evcnt_edge:1;
                uint64_t evcnt_en:1;
@@ -1234,8 +1769,42 @@ union cvmx_mio_ptp_clock_cfg {
                uint64_t ext_clk_en:1;
                uint64_t ptp_en:1;
        } s;
-       struct cvmx_mio_ptp_clock_cfg_s cn63xx;
-       struct cvmx_mio_ptp_clock_cfg_s cn63xxp1;
+       struct cvmx_mio_ptp_clock_cfg_s cn61xx;
+       struct cvmx_mio_ptp_clock_cfg_cn63xx {
+               uint64_t reserved_24_63:40;
+               uint64_t evcnt_in:6;
+               uint64_t evcnt_edge:1;
+               uint64_t evcnt_en:1;
+               uint64_t tstmp_in:6;
+               uint64_t tstmp_edge:1;
+               uint64_t tstmp_en:1;
+               uint64_t ext_clk_in:6;
+               uint64_t ext_clk_en:1;
+               uint64_t ptp_en:1;
+       } cn63xx;
+       struct cvmx_mio_ptp_clock_cfg_cn63xx cn63xxp1;
+       struct cvmx_mio_ptp_clock_cfg_cn66xx {
+               uint64_t reserved_40_63:24;
+               uint64_t ext_clk_edge:2;
+               uint64_t ckout_out4:1;
+               uint64_t pps_out:5;
+               uint64_t pps_inv:1;
+               uint64_t pps_en:1;
+               uint64_t ckout_out:4;
+               uint64_t ckout_inv:1;
+               uint64_t ckout_en:1;
+               uint64_t evcnt_in:6;
+               uint64_t evcnt_edge:1;
+               uint64_t evcnt_en:1;
+               uint64_t tstmp_in:6;
+               uint64_t tstmp_edge:1;
+               uint64_t tstmp_en:1;
+               uint64_t ext_clk_in:6;
+               uint64_t ext_clk_en:1;
+               uint64_t ptp_en:1;
+       } cn66xx;
+       struct cvmx_mio_ptp_clock_cfg_s cn68xx;
+       struct cvmx_mio_ptp_clock_cfg_cn63xx cn68xxp1;
 };
 
 union cvmx_mio_ptp_clock_comp {
@@ -1244,8 +1813,12 @@ union cvmx_mio_ptp_clock_comp {
                uint64_t nanosec:32;
                uint64_t frnanosec:32;
        } s;
+       struct cvmx_mio_ptp_clock_comp_s cn61xx;
        struct cvmx_mio_ptp_clock_comp_s cn63xx;
        struct cvmx_mio_ptp_clock_comp_s cn63xxp1;
+       struct cvmx_mio_ptp_clock_comp_s cn66xx;
+       struct cvmx_mio_ptp_clock_comp_s cn68xx;
+       struct cvmx_mio_ptp_clock_comp_s cn68xxp1;
 };
 
 union cvmx_mio_ptp_clock_hi {
@@ -1253,8 +1826,12 @@ union cvmx_mio_ptp_clock_hi {
        struct cvmx_mio_ptp_clock_hi_s {
                uint64_t nanosec:64;
        } s;
+       struct cvmx_mio_ptp_clock_hi_s cn61xx;
        struct cvmx_mio_ptp_clock_hi_s cn63xx;
        struct cvmx_mio_ptp_clock_hi_s cn63xxp1;
+       struct cvmx_mio_ptp_clock_hi_s cn66xx;
+       struct cvmx_mio_ptp_clock_hi_s cn68xx;
+       struct cvmx_mio_ptp_clock_hi_s cn68xxp1;
 };
 
 union cvmx_mio_ptp_clock_lo {
@@ -1263,8 +1840,12 @@ union cvmx_mio_ptp_clock_lo {
                uint64_t reserved_32_63:32;
                uint64_t frnanosec:32;
        } s;
+       struct cvmx_mio_ptp_clock_lo_s cn61xx;
        struct cvmx_mio_ptp_clock_lo_s cn63xx;
        struct cvmx_mio_ptp_clock_lo_s cn63xxp1;
+       struct cvmx_mio_ptp_clock_lo_s cn66xx;
+       struct cvmx_mio_ptp_clock_lo_s cn68xx;
+       struct cvmx_mio_ptp_clock_lo_s cn68xxp1;
 };
 
 union cvmx_mio_ptp_evt_cnt {
@@ -1272,8 +1853,55 @@ union cvmx_mio_ptp_evt_cnt {
        struct cvmx_mio_ptp_evt_cnt_s {
                uint64_t cntr:64;
        } s;
+       struct cvmx_mio_ptp_evt_cnt_s cn61xx;
        struct cvmx_mio_ptp_evt_cnt_s cn63xx;
        struct cvmx_mio_ptp_evt_cnt_s cn63xxp1;
+       struct cvmx_mio_ptp_evt_cnt_s cn66xx;
+       struct cvmx_mio_ptp_evt_cnt_s cn68xx;
+       struct cvmx_mio_ptp_evt_cnt_s cn68xxp1;
+};
+
+union cvmx_mio_ptp_pps_hi_incr {
+       uint64_t u64;
+       struct cvmx_mio_ptp_pps_hi_incr_s {
+               uint64_t nanosec:32;
+               uint64_t frnanosec:32;
+       } s;
+       struct cvmx_mio_ptp_pps_hi_incr_s cn61xx;
+       struct cvmx_mio_ptp_pps_hi_incr_s cn66xx;
+       struct cvmx_mio_ptp_pps_hi_incr_s cn68xx;
+};
+
+union cvmx_mio_ptp_pps_lo_incr {
+       uint64_t u64;
+       struct cvmx_mio_ptp_pps_lo_incr_s {
+               uint64_t nanosec:32;
+               uint64_t frnanosec:32;
+       } s;
+       struct cvmx_mio_ptp_pps_lo_incr_s cn61xx;
+       struct cvmx_mio_ptp_pps_lo_incr_s cn66xx;
+       struct cvmx_mio_ptp_pps_lo_incr_s cn68xx;
+};
+
+union cvmx_mio_ptp_pps_thresh_hi {
+       uint64_t u64;
+       struct cvmx_mio_ptp_pps_thresh_hi_s {
+               uint64_t nanosec:64;
+       } s;
+       struct cvmx_mio_ptp_pps_thresh_hi_s cn61xx;
+       struct cvmx_mio_ptp_pps_thresh_hi_s cn66xx;
+       struct cvmx_mio_ptp_pps_thresh_hi_s cn68xx;
+};
+
+union cvmx_mio_ptp_pps_thresh_lo {
+       uint64_t u64;
+       struct cvmx_mio_ptp_pps_thresh_lo_s {
+               uint64_t reserved_32_63:32;
+               uint64_t frnanosec:32;
+       } s;
+       struct cvmx_mio_ptp_pps_thresh_lo_s cn61xx;
+       struct cvmx_mio_ptp_pps_thresh_lo_s cn66xx;
+       struct cvmx_mio_ptp_pps_thresh_lo_s cn68xx;
 };
 
 union cvmx_mio_ptp_timestamp {
@@ -1281,14 +1909,52 @@ union cvmx_mio_ptp_timestamp {
        struct cvmx_mio_ptp_timestamp_s {
                uint64_t nanosec:64;
        } s;
+       struct cvmx_mio_ptp_timestamp_s cn61xx;
        struct cvmx_mio_ptp_timestamp_s cn63xx;
        struct cvmx_mio_ptp_timestamp_s cn63xxp1;
+       struct cvmx_mio_ptp_timestamp_s cn66xx;
+       struct cvmx_mio_ptp_timestamp_s cn68xx;
+       struct cvmx_mio_ptp_timestamp_s cn68xxp1;
+};
+
+union cvmx_mio_qlmx_cfg {
+       uint64_t u64;
+       struct cvmx_mio_qlmx_cfg_s {
+               uint64_t reserved_12_63:52;
+               uint64_t qlm_spd:4;
+               uint64_t reserved_4_7:4;
+               uint64_t qlm_cfg:4;
+       } s;
+       struct cvmx_mio_qlmx_cfg_cn61xx {
+               uint64_t reserved_12_63:52;
+               uint64_t qlm_spd:4;
+               uint64_t reserved_2_7:6;
+               uint64_t qlm_cfg:2;
+       } cn61xx;
+       struct cvmx_mio_qlmx_cfg_s cn66xx;
+       struct cvmx_mio_qlmx_cfg_cn68xx {
+               uint64_t reserved_12_63:52;
+               uint64_t qlm_spd:4;
+               uint64_t reserved_3_7:5;
+               uint64_t qlm_cfg:3;
+       } cn68xx;
+       struct cvmx_mio_qlmx_cfg_cn68xx cn68xxp1;
 };
 
 union cvmx_mio_rst_boot {
        uint64_t u64;
        struct cvmx_mio_rst_boot_s {
-               uint64_t reserved_36_63:28;
+               uint64_t chipkill:1;
+               uint64_t jtcsrdis:1;
+               uint64_t ejtagdis:1;
+               uint64_t romen:1;
+               uint64_t ckill_ppdis:1;
+               uint64_t jt_tstmode:1;
+               uint64_t reserved_50_57:8;
+               uint64_t lboot_ext:2;
+               uint64_t reserved_44_47:4;
+               uint64_t qlm4_spd:4;
+               uint64_t qlm3_spd:4;
                uint64_t c_mul:6;
                uint64_t pnr_mul:6;
                uint64_t qlm2_spd:4;
@@ -1298,32 +1964,168 @@ union cvmx_mio_rst_boot {
                uint64_t rboot:1;
                uint64_t rboot_pin:1;
        } s;
-       struct cvmx_mio_rst_boot_s cn63xx;
-       struct cvmx_mio_rst_boot_s cn63xxp1;
+       struct cvmx_mio_rst_boot_cn61xx {
+               uint64_t chipkill:1;
+               uint64_t jtcsrdis:1;
+               uint64_t ejtagdis:1;
+               uint64_t romen:1;
+               uint64_t ckill_ppdis:1;
+               uint64_t jt_tstmode:1;
+               uint64_t reserved_50_57:8;
+               uint64_t lboot_ext:2;
+               uint64_t reserved_36_47:12;
+               uint64_t c_mul:6;
+               uint64_t pnr_mul:6;
+               uint64_t qlm2_spd:4;
+               uint64_t qlm1_spd:4;
+               uint64_t qlm0_spd:4;
+               uint64_t lboot:10;
+               uint64_t rboot:1;
+               uint64_t rboot_pin:1;
+       } cn61xx;
+       struct cvmx_mio_rst_boot_cn63xx {
+               uint64_t reserved_36_63:28;
+               uint64_t c_mul:6;
+               uint64_t pnr_mul:6;
+               uint64_t qlm2_spd:4;
+               uint64_t qlm1_spd:4;
+               uint64_t qlm0_spd:4;
+               uint64_t lboot:10;
+               uint64_t rboot:1;
+               uint64_t rboot_pin:1;
+       } cn63xx;
+       struct cvmx_mio_rst_boot_cn63xx cn63xxp1;
+       struct cvmx_mio_rst_boot_cn66xx {
+               uint64_t chipkill:1;
+               uint64_t jtcsrdis:1;
+               uint64_t ejtagdis:1;
+               uint64_t romen:1;
+               uint64_t ckill_ppdis:1;
+               uint64_t reserved_50_58:9;
+               uint64_t lboot_ext:2;
+               uint64_t reserved_36_47:12;
+               uint64_t c_mul:6;
+               uint64_t pnr_mul:6;
+               uint64_t qlm2_spd:4;
+               uint64_t qlm1_spd:4;
+               uint64_t qlm0_spd:4;
+               uint64_t lboot:10;
+               uint64_t rboot:1;
+               uint64_t rboot_pin:1;
+       } cn66xx;
+       struct cvmx_mio_rst_boot_cn68xx {
+               uint64_t reserved_59_63:5;
+               uint64_t jt_tstmode:1;
+               uint64_t reserved_44_57:14;
+               uint64_t qlm4_spd:4;
+               uint64_t qlm3_spd:4;
+               uint64_t c_mul:6;
+               uint64_t pnr_mul:6;
+               uint64_t qlm2_spd:4;
+               uint64_t qlm1_spd:4;
+               uint64_t qlm0_spd:4;
+               uint64_t lboot:10;
+               uint64_t rboot:1;
+               uint64_t rboot_pin:1;
+       } cn68xx;
+       struct cvmx_mio_rst_boot_cn68xxp1 {
+               uint64_t reserved_44_63:20;
+               uint64_t qlm4_spd:4;
+               uint64_t qlm3_spd:4;
+               uint64_t c_mul:6;
+               uint64_t pnr_mul:6;
+               uint64_t qlm2_spd:4;
+               uint64_t qlm1_spd:4;
+               uint64_t qlm0_spd:4;
+               uint64_t lboot:10;
+               uint64_t rboot:1;
+               uint64_t rboot_pin:1;
+       } cn68xxp1;
 };
 
 union cvmx_mio_rst_cfg {
        uint64_t u64;
        struct cvmx_mio_rst_cfg_s {
+               uint64_t reserved_3_63:61;
+               uint64_t cntl_clr_bist:1;
+               uint64_t warm_clr_bist:1;
+               uint64_t soft_clr_bist:1;
+       } s;
+       struct cvmx_mio_rst_cfg_cn61xx {
                uint64_t bist_delay:58;
                uint64_t reserved_3_5:3;
                uint64_t cntl_clr_bist:1;
                uint64_t warm_clr_bist:1;
                uint64_t soft_clr_bist:1;
-       } s;
-       struct cvmx_mio_rst_cfg_s cn63xx;
+       } cn61xx;
+       struct cvmx_mio_rst_cfg_cn61xx cn63xx;
        struct cvmx_mio_rst_cfg_cn63xxp1 {
                uint64_t bist_delay:58;
                uint64_t reserved_2_5:4;
                uint64_t warm_clr_bist:1;
                uint64_t soft_clr_bist:1;
        } cn63xxp1;
+       struct cvmx_mio_rst_cfg_cn61xx cn66xx;
+       struct cvmx_mio_rst_cfg_cn68xx {
+               uint64_t bist_delay:56;
+               uint64_t reserved_3_7:5;
+               uint64_t cntl_clr_bist:1;
+               uint64_t warm_clr_bist:1;
+               uint64_t soft_clr_bist:1;
+       } cn68xx;
+       struct cvmx_mio_rst_cfg_cn68xx cn68xxp1;
+};
+
+union cvmx_mio_rst_ckill {
+       uint64_t u64;
+       struct cvmx_mio_rst_ckill_s {
+               uint64_t reserved_47_63:17;
+               uint64_t timer:47;
+       } s;
+       struct cvmx_mio_rst_ckill_s cn61xx;
+       struct cvmx_mio_rst_ckill_s cn66xx;
+};
+
+union cvmx_mio_rst_cntlx {
+       uint64_t u64;
+       struct cvmx_mio_rst_cntlx_s {
+               uint64_t reserved_13_63:51;
+               uint64_t in_rev_ln:1;
+               uint64_t rev_lanes:1;
+               uint64_t gen1_only:1;
+               uint64_t prst_link:1;
+               uint64_t rst_done:1;
+               uint64_t rst_link:1;
+               uint64_t host_mode:1;
+               uint64_t prtmode:2;
+               uint64_t rst_drv:1;
+               uint64_t rst_rcv:1;
+               uint64_t rst_chip:1;
+               uint64_t rst_val:1;
+       } s;
+       struct cvmx_mio_rst_cntlx_s cn61xx;
+       struct cvmx_mio_rst_cntlx_cn66xx {
+               uint64_t reserved_10_63:54;
+               uint64_t prst_link:1;
+               uint64_t rst_done:1;
+               uint64_t rst_link:1;
+               uint64_t host_mode:1;
+               uint64_t prtmode:2;
+               uint64_t rst_drv:1;
+               uint64_t rst_rcv:1;
+               uint64_t rst_chip:1;
+               uint64_t rst_val:1;
+       } cn66xx;
+       struct cvmx_mio_rst_cntlx_cn66xx cn68xx;
 };
 
 union cvmx_mio_rst_ctlx {
        uint64_t u64;
        struct cvmx_mio_rst_ctlx_s {
-               uint64_t reserved_10_63:54;
+               uint64_t reserved_13_63:51;
+               uint64_t in_rev_ln:1;
+               uint64_t rev_lanes:1;
+               uint64_t gen1_only:1;
                uint64_t prst_link:1;
                uint64_t rst_done:1;
                uint64_t rst_link:1;
@@ -1334,7 +2136,19 @@ union cvmx_mio_rst_ctlx {
                uint64_t rst_chip:1;
                uint64_t rst_val:1;
        } s;
-       struct cvmx_mio_rst_ctlx_s cn63xx;
+       struct cvmx_mio_rst_ctlx_s cn61xx;
+       struct cvmx_mio_rst_ctlx_cn63xx {
+               uint64_t reserved_10_63:54;
+               uint64_t prst_link:1;
+               uint64_t rst_done:1;
+               uint64_t rst_link:1;
+               uint64_t host_mode:1;
+               uint64_t prtmode:2;
+               uint64_t rst_drv:1;
+               uint64_t rst_rcv:1;
+               uint64_t rst_chip:1;
+               uint64_t rst_val:1;
+       } cn63xx;
        struct cvmx_mio_rst_ctlx_cn63xxp1 {
                uint64_t reserved_9_63:55;
                uint64_t rst_done:1;
@@ -1346,17 +2160,24 @@ union cvmx_mio_rst_ctlx {
                uint64_t rst_chip:1;
                uint64_t rst_val:1;
        } cn63xxp1;
+       struct cvmx_mio_rst_ctlx_cn63xx cn66xx;
+       struct cvmx_mio_rst_ctlx_cn63xx cn68xx;
+       struct cvmx_mio_rst_ctlx_cn63xx cn68xxp1;
 };
 
 union cvmx_mio_rst_delay {
        uint64_t u64;
        struct cvmx_mio_rst_delay_s {
                uint64_t reserved_32_63:32;
-               uint64_t soft_rst_dly:16;
                uint64_t warm_rst_dly:16;
+               uint64_t soft_rst_dly:16;
        } s;
+       struct cvmx_mio_rst_delay_s cn61xx;
        struct cvmx_mio_rst_delay_s cn63xx;
        struct cvmx_mio_rst_delay_s cn63xxp1;
+       struct cvmx_mio_rst_delay_s cn66xx;
+       struct cvmx_mio_rst_delay_s cn68xx;
+       struct cvmx_mio_rst_delay_s cn68xxp1;
 };
 
 union cvmx_mio_rst_int {
@@ -1365,12 +2186,25 @@ union cvmx_mio_rst_int {
                uint64_t reserved_10_63:54;
                uint64_t perst1:1;
                uint64_t perst0:1;
-               uint64_t reserved_2_7:6;
+               uint64_t reserved_4_7:4;
+               uint64_t rst_link3:1;
+               uint64_t rst_link2:1;
                uint64_t rst_link1:1;
                uint64_t rst_link0:1;
        } s;
-       struct cvmx_mio_rst_int_s cn63xx;
-       struct cvmx_mio_rst_int_s cn63xxp1;
+       struct cvmx_mio_rst_int_cn61xx {
+               uint64_t reserved_10_63:54;
+               uint64_t perst1:1;
+               uint64_t perst0:1;
+               uint64_t reserved_2_7:6;
+               uint64_t rst_link1:1;
+               uint64_t rst_link0:1;
+       } cn61xx;
+       struct cvmx_mio_rst_int_cn61xx cn63xx;
+       struct cvmx_mio_rst_int_cn61xx cn63xxp1;
+       struct cvmx_mio_rst_int_s cn66xx;
+       struct cvmx_mio_rst_int_cn61xx cn68xx;
+       struct cvmx_mio_rst_int_cn61xx cn68xxp1;
 };
 
 union cvmx_mio_rst_int_en {
@@ -1379,12 +2213,25 @@ union cvmx_mio_rst_int_en {
                uint64_t reserved_10_63:54;
                uint64_t perst1:1;
                uint64_t perst0:1;
-               uint64_t reserved_2_7:6;
+               uint64_t reserved_4_7:4;
+               uint64_t rst_link3:1;
+               uint64_t rst_link2:1;
                uint64_t rst_link1:1;
                uint64_t rst_link0:1;
        } s;
-       struct cvmx_mio_rst_int_en_s cn63xx;
-       struct cvmx_mio_rst_int_en_s cn63xxp1;
+       struct cvmx_mio_rst_int_en_cn61xx {
+               uint64_t reserved_10_63:54;
+               uint64_t perst1:1;
+               uint64_t perst0:1;
+               uint64_t reserved_2_7:6;
+               uint64_t rst_link1:1;
+               uint64_t rst_link0:1;
+       } cn61xx;
+       struct cvmx_mio_rst_int_en_cn61xx cn63xx;
+       struct cvmx_mio_rst_int_en_cn61xx cn63xxp1;
+       struct cvmx_mio_rst_int_en_s cn66xx;
+       struct cvmx_mio_rst_int_en_cn61xx cn68xx;
+       struct cvmx_mio_rst_int_en_cn61xx cn68xxp1;
 };
 
 union cvmx_mio_twsx_int {
@@ -1424,8 +2271,12 @@ union cvmx_mio_twsx_int {
        struct cvmx_mio_twsx_int_s cn56xxp1;
        struct cvmx_mio_twsx_int_s cn58xx;
        struct cvmx_mio_twsx_int_s cn58xxp1;
+       struct cvmx_mio_twsx_int_s cn61xx;
        struct cvmx_mio_twsx_int_s cn63xx;
        struct cvmx_mio_twsx_int_s cn63xxp1;
+       struct cvmx_mio_twsx_int_s cn66xx;
+       struct cvmx_mio_twsx_int_s cn68xx;
+       struct cvmx_mio_twsx_int_s cn68xxp1;
 };
 
 union cvmx_mio_twsx_sw_twsi {
@@ -1455,8 +2306,12 @@ union cvmx_mio_twsx_sw_twsi {
        struct cvmx_mio_twsx_sw_twsi_s cn56xxp1;
        struct cvmx_mio_twsx_sw_twsi_s cn58xx;
        struct cvmx_mio_twsx_sw_twsi_s cn58xxp1;
+       struct cvmx_mio_twsx_sw_twsi_s cn61xx;
        struct cvmx_mio_twsx_sw_twsi_s cn63xx;
        struct cvmx_mio_twsx_sw_twsi_s cn63xxp1;
+       struct cvmx_mio_twsx_sw_twsi_s cn66xx;
+       struct cvmx_mio_twsx_sw_twsi_s cn68xx;
+       struct cvmx_mio_twsx_sw_twsi_s cn68xxp1;
 };
 
 union cvmx_mio_twsx_sw_twsi_ext {
@@ -1477,8 +2332,12 @@ union cvmx_mio_twsx_sw_twsi_ext {
        struct cvmx_mio_twsx_sw_twsi_ext_s cn56xxp1;
        struct cvmx_mio_twsx_sw_twsi_ext_s cn58xx;
        struct cvmx_mio_twsx_sw_twsi_ext_s cn58xxp1;
+       struct cvmx_mio_twsx_sw_twsi_ext_s cn61xx;
        struct cvmx_mio_twsx_sw_twsi_ext_s cn63xx;
        struct cvmx_mio_twsx_sw_twsi_ext_s cn63xxp1;
+       struct cvmx_mio_twsx_sw_twsi_ext_s cn66xx;
+       struct cvmx_mio_twsx_sw_twsi_ext_s cn68xx;
+       struct cvmx_mio_twsx_sw_twsi_ext_s cn68xxp1;
 };
 
 union cvmx_mio_twsx_twsi_sw {
@@ -1499,8 +2358,12 @@ union cvmx_mio_twsx_twsi_sw {
        struct cvmx_mio_twsx_twsi_sw_s cn56xxp1;
        struct cvmx_mio_twsx_twsi_sw_s cn58xx;
        struct cvmx_mio_twsx_twsi_sw_s cn58xxp1;
+       struct cvmx_mio_twsx_twsi_sw_s cn61xx;
        struct cvmx_mio_twsx_twsi_sw_s cn63xx;
        struct cvmx_mio_twsx_twsi_sw_s cn63xxp1;
+       struct cvmx_mio_twsx_twsi_sw_s cn66xx;
+       struct cvmx_mio_twsx_twsi_sw_s cn68xx;
+       struct cvmx_mio_twsx_twsi_sw_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_dlh {
@@ -1520,8 +2383,12 @@ union cvmx_mio_uartx_dlh {
        struct cvmx_mio_uartx_dlh_s cn56xxp1;
        struct cvmx_mio_uartx_dlh_s cn58xx;
        struct cvmx_mio_uartx_dlh_s cn58xxp1;
+       struct cvmx_mio_uartx_dlh_s cn61xx;
        struct cvmx_mio_uartx_dlh_s cn63xx;
        struct cvmx_mio_uartx_dlh_s cn63xxp1;
+       struct cvmx_mio_uartx_dlh_s cn66xx;
+       struct cvmx_mio_uartx_dlh_s cn68xx;
+       struct cvmx_mio_uartx_dlh_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_dll {
@@ -1541,8 +2408,12 @@ union cvmx_mio_uartx_dll {
        struct cvmx_mio_uartx_dll_s cn56xxp1;
        struct cvmx_mio_uartx_dll_s cn58xx;
        struct cvmx_mio_uartx_dll_s cn58xxp1;
+       struct cvmx_mio_uartx_dll_s cn61xx;
        struct cvmx_mio_uartx_dll_s cn63xx;
        struct cvmx_mio_uartx_dll_s cn63xxp1;
+       struct cvmx_mio_uartx_dll_s cn66xx;
+       struct cvmx_mio_uartx_dll_s cn68xx;
+       struct cvmx_mio_uartx_dll_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_far {
@@ -1562,8 +2433,12 @@ union cvmx_mio_uartx_far {
        struct cvmx_mio_uartx_far_s cn56xxp1;
        struct cvmx_mio_uartx_far_s cn58xx;
        struct cvmx_mio_uartx_far_s cn58xxp1;
+       struct cvmx_mio_uartx_far_s cn61xx;
        struct cvmx_mio_uartx_far_s cn63xx;
        struct cvmx_mio_uartx_far_s cn63xxp1;
+       struct cvmx_mio_uartx_far_s cn66xx;
+       struct cvmx_mio_uartx_far_s cn68xx;
+       struct cvmx_mio_uartx_far_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_fcr {
@@ -1588,8 +2463,12 @@ union cvmx_mio_uartx_fcr {
        struct cvmx_mio_uartx_fcr_s cn56xxp1;
        struct cvmx_mio_uartx_fcr_s cn58xx;
        struct cvmx_mio_uartx_fcr_s cn58xxp1;
+       struct cvmx_mio_uartx_fcr_s cn61xx;
        struct cvmx_mio_uartx_fcr_s cn63xx;
        struct cvmx_mio_uartx_fcr_s cn63xxp1;
+       struct cvmx_mio_uartx_fcr_s cn66xx;
+       struct cvmx_mio_uartx_fcr_s cn68xx;
+       struct cvmx_mio_uartx_fcr_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_htx {
@@ -1609,8 +2488,12 @@ union cvmx_mio_uartx_htx {
        struct cvmx_mio_uartx_htx_s cn56xxp1;
        struct cvmx_mio_uartx_htx_s cn58xx;
        struct cvmx_mio_uartx_htx_s cn58xxp1;
+       struct cvmx_mio_uartx_htx_s cn61xx;
        struct cvmx_mio_uartx_htx_s cn63xx;
        struct cvmx_mio_uartx_htx_s cn63xxp1;
+       struct cvmx_mio_uartx_htx_s cn66xx;
+       struct cvmx_mio_uartx_htx_s cn68xx;
+       struct cvmx_mio_uartx_htx_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_ier {
@@ -1635,8 +2518,12 @@ union cvmx_mio_uartx_ier {
        struct cvmx_mio_uartx_ier_s cn56xxp1;
        struct cvmx_mio_uartx_ier_s cn58xx;
        struct cvmx_mio_uartx_ier_s cn58xxp1;
+       struct cvmx_mio_uartx_ier_s cn61xx;
        struct cvmx_mio_uartx_ier_s cn63xx;
        struct cvmx_mio_uartx_ier_s cn63xxp1;
+       struct cvmx_mio_uartx_ier_s cn66xx;
+       struct cvmx_mio_uartx_ier_s cn68xx;
+       struct cvmx_mio_uartx_ier_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_iir {
@@ -1658,8 +2545,12 @@ union cvmx_mio_uartx_iir {
        struct cvmx_mio_uartx_iir_s cn56xxp1;
        struct cvmx_mio_uartx_iir_s cn58xx;
        struct cvmx_mio_uartx_iir_s cn58xxp1;
+       struct cvmx_mio_uartx_iir_s cn61xx;
        struct cvmx_mio_uartx_iir_s cn63xx;
        struct cvmx_mio_uartx_iir_s cn63xxp1;
+       struct cvmx_mio_uartx_iir_s cn66xx;
+       struct cvmx_mio_uartx_iir_s cn68xx;
+       struct cvmx_mio_uartx_iir_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_lcr {
@@ -1685,8 +2576,12 @@ union cvmx_mio_uartx_lcr {
        struct cvmx_mio_uartx_lcr_s cn56xxp1;
        struct cvmx_mio_uartx_lcr_s cn58xx;
        struct cvmx_mio_uartx_lcr_s cn58xxp1;
+       struct cvmx_mio_uartx_lcr_s cn61xx;
        struct cvmx_mio_uartx_lcr_s cn63xx;
        struct cvmx_mio_uartx_lcr_s cn63xxp1;
+       struct cvmx_mio_uartx_lcr_s cn66xx;
+       struct cvmx_mio_uartx_lcr_s cn68xx;
+       struct cvmx_mio_uartx_lcr_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_lsr {
@@ -1713,8 +2608,12 @@ union cvmx_mio_uartx_lsr {
        struct cvmx_mio_uartx_lsr_s cn56xxp1;
        struct cvmx_mio_uartx_lsr_s cn58xx;
        struct cvmx_mio_uartx_lsr_s cn58xxp1;
+       struct cvmx_mio_uartx_lsr_s cn61xx;
        struct cvmx_mio_uartx_lsr_s cn63xx;
        struct cvmx_mio_uartx_lsr_s cn63xxp1;
+       struct cvmx_mio_uartx_lsr_s cn66xx;
+       struct cvmx_mio_uartx_lsr_s cn68xx;
+       struct cvmx_mio_uartx_lsr_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_mcr {
@@ -1739,8 +2638,12 @@ union cvmx_mio_uartx_mcr {
        struct cvmx_mio_uartx_mcr_s cn56xxp1;
        struct cvmx_mio_uartx_mcr_s cn58xx;
        struct cvmx_mio_uartx_mcr_s cn58xxp1;
+       struct cvmx_mio_uartx_mcr_s cn61xx;
        struct cvmx_mio_uartx_mcr_s cn63xx;
        struct cvmx_mio_uartx_mcr_s cn63xxp1;
+       struct cvmx_mio_uartx_mcr_s cn66xx;
+       struct cvmx_mio_uartx_mcr_s cn68xx;
+       struct cvmx_mio_uartx_mcr_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_msr {
@@ -1767,8 +2670,12 @@ union cvmx_mio_uartx_msr {
        struct cvmx_mio_uartx_msr_s cn56xxp1;
        struct cvmx_mio_uartx_msr_s cn58xx;
        struct cvmx_mio_uartx_msr_s cn58xxp1;
+       struct cvmx_mio_uartx_msr_s cn61xx;
        struct cvmx_mio_uartx_msr_s cn63xx;
        struct cvmx_mio_uartx_msr_s cn63xxp1;
+       struct cvmx_mio_uartx_msr_s cn66xx;
+       struct cvmx_mio_uartx_msr_s cn68xx;
+       struct cvmx_mio_uartx_msr_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_rbr {
@@ -1788,8 +2695,12 @@ union cvmx_mio_uartx_rbr {
        struct cvmx_mio_uartx_rbr_s cn56xxp1;
        struct cvmx_mio_uartx_rbr_s cn58xx;
        struct cvmx_mio_uartx_rbr_s cn58xxp1;
+       struct cvmx_mio_uartx_rbr_s cn61xx;
        struct cvmx_mio_uartx_rbr_s cn63xx;
        struct cvmx_mio_uartx_rbr_s cn63xxp1;
+       struct cvmx_mio_uartx_rbr_s cn66xx;
+       struct cvmx_mio_uartx_rbr_s cn68xx;
+       struct cvmx_mio_uartx_rbr_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_rfl {
@@ -1809,8 +2720,12 @@ union cvmx_mio_uartx_rfl {
        struct cvmx_mio_uartx_rfl_s cn56xxp1;
        struct cvmx_mio_uartx_rfl_s cn58xx;
        struct cvmx_mio_uartx_rfl_s cn58xxp1;
+       struct cvmx_mio_uartx_rfl_s cn61xx;
        struct cvmx_mio_uartx_rfl_s cn63xx;
        struct cvmx_mio_uartx_rfl_s cn63xxp1;
+       struct cvmx_mio_uartx_rfl_s cn66xx;
+       struct cvmx_mio_uartx_rfl_s cn68xx;
+       struct cvmx_mio_uartx_rfl_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_rfw {
@@ -1832,8 +2747,12 @@ union cvmx_mio_uartx_rfw {
        struct cvmx_mio_uartx_rfw_s cn56xxp1;
        struct cvmx_mio_uartx_rfw_s cn58xx;
        struct cvmx_mio_uartx_rfw_s cn58xxp1;
+       struct cvmx_mio_uartx_rfw_s cn61xx;
        struct cvmx_mio_uartx_rfw_s cn63xx;
        struct cvmx_mio_uartx_rfw_s cn63xxp1;
+       struct cvmx_mio_uartx_rfw_s cn66xx;
+       struct cvmx_mio_uartx_rfw_s cn68xx;
+       struct cvmx_mio_uartx_rfw_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_sbcr {
@@ -1853,8 +2772,12 @@ union cvmx_mio_uartx_sbcr {
        struct cvmx_mio_uartx_sbcr_s cn56xxp1;
        struct cvmx_mio_uartx_sbcr_s cn58xx;
        struct cvmx_mio_uartx_sbcr_s cn58xxp1;
+       struct cvmx_mio_uartx_sbcr_s cn61xx;
        struct cvmx_mio_uartx_sbcr_s cn63xx;
        struct cvmx_mio_uartx_sbcr_s cn63xxp1;
+       struct cvmx_mio_uartx_sbcr_s cn66xx;
+       struct cvmx_mio_uartx_sbcr_s cn68xx;
+       struct cvmx_mio_uartx_sbcr_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_scr {
@@ -1874,8 +2797,12 @@ union cvmx_mio_uartx_scr {
        struct cvmx_mio_uartx_scr_s cn56xxp1;
        struct cvmx_mio_uartx_scr_s cn58xx;
        struct cvmx_mio_uartx_scr_s cn58xxp1;
+       struct cvmx_mio_uartx_scr_s cn61xx;
        struct cvmx_mio_uartx_scr_s cn63xx;
        struct cvmx_mio_uartx_scr_s cn63xxp1;
+       struct cvmx_mio_uartx_scr_s cn66xx;
+       struct cvmx_mio_uartx_scr_s cn68xx;
+       struct cvmx_mio_uartx_scr_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_sfe {
@@ -1895,8 +2822,12 @@ union cvmx_mio_uartx_sfe {
        struct cvmx_mio_uartx_sfe_s cn56xxp1;
        struct cvmx_mio_uartx_sfe_s cn58xx;
        struct cvmx_mio_uartx_sfe_s cn58xxp1;
+       struct cvmx_mio_uartx_sfe_s cn61xx;
        struct cvmx_mio_uartx_sfe_s cn63xx;
        struct cvmx_mio_uartx_sfe_s cn63xxp1;
+       struct cvmx_mio_uartx_sfe_s cn66xx;
+       struct cvmx_mio_uartx_sfe_s cn68xx;
+       struct cvmx_mio_uartx_sfe_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_srr {
@@ -1918,8 +2849,12 @@ union cvmx_mio_uartx_srr {
        struct cvmx_mio_uartx_srr_s cn56xxp1;
        struct cvmx_mio_uartx_srr_s cn58xx;
        struct cvmx_mio_uartx_srr_s cn58xxp1;
+       struct cvmx_mio_uartx_srr_s cn61xx;
        struct cvmx_mio_uartx_srr_s cn63xx;
        struct cvmx_mio_uartx_srr_s cn63xxp1;
+       struct cvmx_mio_uartx_srr_s cn66xx;
+       struct cvmx_mio_uartx_srr_s cn68xx;
+       struct cvmx_mio_uartx_srr_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_srt {
@@ -1939,8 +2874,12 @@ union cvmx_mio_uartx_srt {
        struct cvmx_mio_uartx_srt_s cn56xxp1;
        struct cvmx_mio_uartx_srt_s cn58xx;
        struct cvmx_mio_uartx_srt_s cn58xxp1;
+       struct cvmx_mio_uartx_srt_s cn61xx;
        struct cvmx_mio_uartx_srt_s cn63xx;
        struct cvmx_mio_uartx_srt_s cn63xxp1;
+       struct cvmx_mio_uartx_srt_s cn66xx;
+       struct cvmx_mio_uartx_srt_s cn68xx;
+       struct cvmx_mio_uartx_srt_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_srts {
@@ -1960,8 +2899,12 @@ union cvmx_mio_uartx_srts {
        struct cvmx_mio_uartx_srts_s cn56xxp1;
        struct cvmx_mio_uartx_srts_s cn58xx;
        struct cvmx_mio_uartx_srts_s cn58xxp1;
+       struct cvmx_mio_uartx_srts_s cn61xx;
        struct cvmx_mio_uartx_srts_s cn63xx;
        struct cvmx_mio_uartx_srts_s cn63xxp1;
+       struct cvmx_mio_uartx_srts_s cn66xx;
+       struct cvmx_mio_uartx_srts_s cn68xx;
+       struct cvmx_mio_uartx_srts_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_stt {
@@ -1981,8 +2924,12 @@ union cvmx_mio_uartx_stt {
        struct cvmx_mio_uartx_stt_s cn56xxp1;
        struct cvmx_mio_uartx_stt_s cn58xx;
        struct cvmx_mio_uartx_stt_s cn58xxp1;
+       struct cvmx_mio_uartx_stt_s cn61xx;
        struct cvmx_mio_uartx_stt_s cn63xx;
        struct cvmx_mio_uartx_stt_s cn63xxp1;
+       struct cvmx_mio_uartx_stt_s cn66xx;
+       struct cvmx_mio_uartx_stt_s cn68xx;
+       struct cvmx_mio_uartx_stt_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_tfl {
@@ -2002,8 +2949,12 @@ union cvmx_mio_uartx_tfl {
        struct cvmx_mio_uartx_tfl_s cn56xxp1;
        struct cvmx_mio_uartx_tfl_s cn58xx;
        struct cvmx_mio_uartx_tfl_s cn58xxp1;
+       struct cvmx_mio_uartx_tfl_s cn61xx;
        struct cvmx_mio_uartx_tfl_s cn63xx;
        struct cvmx_mio_uartx_tfl_s cn63xxp1;
+       struct cvmx_mio_uartx_tfl_s cn66xx;
+       struct cvmx_mio_uartx_tfl_s cn68xx;
+       struct cvmx_mio_uartx_tfl_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_tfr {
@@ -2023,8 +2974,12 @@ union cvmx_mio_uartx_tfr {
        struct cvmx_mio_uartx_tfr_s cn56xxp1;
        struct cvmx_mio_uartx_tfr_s cn58xx;
        struct cvmx_mio_uartx_tfr_s cn58xxp1;
+       struct cvmx_mio_uartx_tfr_s cn61xx;
        struct cvmx_mio_uartx_tfr_s cn63xx;
        struct cvmx_mio_uartx_tfr_s cn63xxp1;
+       struct cvmx_mio_uartx_tfr_s cn66xx;
+       struct cvmx_mio_uartx_tfr_s cn68xx;
+       struct cvmx_mio_uartx_tfr_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_thr {
@@ -2044,8 +2999,12 @@ union cvmx_mio_uartx_thr {
        struct cvmx_mio_uartx_thr_s cn56xxp1;
        struct cvmx_mio_uartx_thr_s cn58xx;
        struct cvmx_mio_uartx_thr_s cn58xxp1;
+       struct cvmx_mio_uartx_thr_s cn61xx;
        struct cvmx_mio_uartx_thr_s cn63xx;
        struct cvmx_mio_uartx_thr_s cn63xxp1;
+       struct cvmx_mio_uartx_thr_s cn66xx;
+       struct cvmx_mio_uartx_thr_s cn68xx;
+       struct cvmx_mio_uartx_thr_s cn68xxp1;
 };
 
 union cvmx_mio_uartx_usr {
@@ -2069,8 +3028,12 @@ union cvmx_mio_uartx_usr {
        struct cvmx_mio_uartx_usr_s cn56xxp1;
        struct cvmx_mio_uartx_usr_s cn58xx;
        struct cvmx_mio_uartx_usr_s cn58xxp1;
+       struct cvmx_mio_uartx_usr_s cn61xx;
        struct cvmx_mio_uartx_usr_s cn63xx;
        struct cvmx_mio_uartx_usr_s cn63xxp1;
+       struct cvmx_mio_uartx_usr_s cn66xx;
+       struct cvmx_mio_uartx_usr_s cn68xx;
+       struct cvmx_mio_uartx_usr_s cn68xxp1;
 };
 
 union cvmx_mio_uart2_dlh {
index 9899a9d2ba721fb4ac437a00f967a7acf1d7fbbe..a3075f733ca563b60b38cb7bd75d9b36af852a65 100644 (file)
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2010 Cavium Networks
+ * Copyright (c) 2003-2011 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -65,7 +65,7 @@
 #define CVMX_NPEI_LAST_WIN_RDATA0 (0x0000000000000600ull)
 #define CVMX_NPEI_LAST_WIN_RDATA1 (0x0000000000000610ull)
 #define CVMX_NPEI_MEM_ACCESS_CTL (0x00000000000004F0ull)
-#define CVMX_NPEI_MEM_ACCESS_SUBIDX(offset) (0x0000000000000340ull + ((offset) & 31) * 16 - 16*12)
+#define CVMX_NPEI_MEM_ACCESS_SUBIDX(offset) (0x0000000000000280ull + ((offset) & 31) * 16 - 16*12)
 #define CVMX_NPEI_MSI_ENB0 (0x0000000000003C50ull)
 #define CVMX_NPEI_MSI_ENB1 (0x0000000000003C60ull)
 #define CVMX_NPEI_MSI_ENB2 (0x0000000000003C70ull)
index f8cb88902efbd472c613e6ac45ee26aff25cb2f3..7b1dc8b74e5b2a1271bab9673425c0da7c7f7fba 100644 (file)
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2010 Cavium Networks
+ * Copyright (c) 2003-2011 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -116,8 +116,12 @@ union cvmx_pciercx_cfg000 {
        struct cvmx_pciercx_cfg000_s cn52xxp1;
        struct cvmx_pciercx_cfg000_s cn56xx;
        struct cvmx_pciercx_cfg000_s cn56xxp1;
+       struct cvmx_pciercx_cfg000_s cn61xx;
        struct cvmx_pciercx_cfg000_s cn63xx;
        struct cvmx_pciercx_cfg000_s cn63xxp1;
+       struct cvmx_pciercx_cfg000_s cn66xx;
+       struct cvmx_pciercx_cfg000_s cn68xx;
+       struct cvmx_pciercx_cfg000_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg001 {
@@ -152,8 +156,12 @@ union cvmx_pciercx_cfg001 {
        struct cvmx_pciercx_cfg001_s cn52xxp1;
        struct cvmx_pciercx_cfg001_s cn56xx;
        struct cvmx_pciercx_cfg001_s cn56xxp1;
+       struct cvmx_pciercx_cfg001_s cn61xx;
        struct cvmx_pciercx_cfg001_s cn63xx;
        struct cvmx_pciercx_cfg001_s cn63xxp1;
+       struct cvmx_pciercx_cfg001_s cn66xx;
+       struct cvmx_pciercx_cfg001_s cn68xx;
+       struct cvmx_pciercx_cfg001_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg002 {
@@ -168,8 +176,12 @@ union cvmx_pciercx_cfg002 {
        struct cvmx_pciercx_cfg002_s cn52xxp1;
        struct cvmx_pciercx_cfg002_s cn56xx;
        struct cvmx_pciercx_cfg002_s cn56xxp1;
+       struct cvmx_pciercx_cfg002_s cn61xx;
        struct cvmx_pciercx_cfg002_s cn63xx;
        struct cvmx_pciercx_cfg002_s cn63xxp1;
+       struct cvmx_pciercx_cfg002_s cn66xx;
+       struct cvmx_pciercx_cfg002_s cn68xx;
+       struct cvmx_pciercx_cfg002_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg003 {
@@ -185,8 +197,12 @@ union cvmx_pciercx_cfg003 {
        struct cvmx_pciercx_cfg003_s cn52xxp1;
        struct cvmx_pciercx_cfg003_s cn56xx;
        struct cvmx_pciercx_cfg003_s cn56xxp1;
+       struct cvmx_pciercx_cfg003_s cn61xx;
        struct cvmx_pciercx_cfg003_s cn63xx;
        struct cvmx_pciercx_cfg003_s cn63xxp1;
+       struct cvmx_pciercx_cfg003_s cn66xx;
+       struct cvmx_pciercx_cfg003_s cn68xx;
+       struct cvmx_pciercx_cfg003_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg004 {
@@ -198,8 +214,12 @@ union cvmx_pciercx_cfg004 {
        struct cvmx_pciercx_cfg004_s cn52xxp1;
        struct cvmx_pciercx_cfg004_s cn56xx;
        struct cvmx_pciercx_cfg004_s cn56xxp1;
+       struct cvmx_pciercx_cfg004_s cn61xx;
        struct cvmx_pciercx_cfg004_s cn63xx;
        struct cvmx_pciercx_cfg004_s cn63xxp1;
+       struct cvmx_pciercx_cfg004_s cn66xx;
+       struct cvmx_pciercx_cfg004_s cn68xx;
+       struct cvmx_pciercx_cfg004_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg005 {
@@ -211,8 +231,12 @@ union cvmx_pciercx_cfg005 {
        struct cvmx_pciercx_cfg005_s cn52xxp1;
        struct cvmx_pciercx_cfg005_s cn56xx;
        struct cvmx_pciercx_cfg005_s cn56xxp1;
+       struct cvmx_pciercx_cfg005_s cn61xx;
        struct cvmx_pciercx_cfg005_s cn63xx;
        struct cvmx_pciercx_cfg005_s cn63xxp1;
+       struct cvmx_pciercx_cfg005_s cn66xx;
+       struct cvmx_pciercx_cfg005_s cn68xx;
+       struct cvmx_pciercx_cfg005_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg006 {
@@ -227,8 +251,12 @@ union cvmx_pciercx_cfg006 {
        struct cvmx_pciercx_cfg006_s cn52xxp1;
        struct cvmx_pciercx_cfg006_s cn56xx;
        struct cvmx_pciercx_cfg006_s cn56xxp1;
+       struct cvmx_pciercx_cfg006_s cn61xx;
        struct cvmx_pciercx_cfg006_s cn63xx;
        struct cvmx_pciercx_cfg006_s cn63xxp1;
+       struct cvmx_pciercx_cfg006_s cn66xx;
+       struct cvmx_pciercx_cfg006_s cn68xx;
+       struct cvmx_pciercx_cfg006_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg007 {
@@ -256,8 +284,12 @@ union cvmx_pciercx_cfg007 {
        struct cvmx_pciercx_cfg007_s cn52xxp1;
        struct cvmx_pciercx_cfg007_s cn56xx;
        struct cvmx_pciercx_cfg007_s cn56xxp1;
+       struct cvmx_pciercx_cfg007_s cn61xx;
        struct cvmx_pciercx_cfg007_s cn63xx;
        struct cvmx_pciercx_cfg007_s cn63xxp1;
+       struct cvmx_pciercx_cfg007_s cn66xx;
+       struct cvmx_pciercx_cfg007_s cn68xx;
+       struct cvmx_pciercx_cfg007_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg008 {
@@ -272,8 +304,12 @@ union cvmx_pciercx_cfg008 {
        struct cvmx_pciercx_cfg008_s cn52xxp1;
        struct cvmx_pciercx_cfg008_s cn56xx;
        struct cvmx_pciercx_cfg008_s cn56xxp1;
+       struct cvmx_pciercx_cfg008_s cn61xx;
        struct cvmx_pciercx_cfg008_s cn63xx;
        struct cvmx_pciercx_cfg008_s cn63xxp1;
+       struct cvmx_pciercx_cfg008_s cn66xx;
+       struct cvmx_pciercx_cfg008_s cn68xx;
+       struct cvmx_pciercx_cfg008_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg009 {
@@ -290,8 +326,12 @@ union cvmx_pciercx_cfg009 {
        struct cvmx_pciercx_cfg009_s cn52xxp1;
        struct cvmx_pciercx_cfg009_s cn56xx;
        struct cvmx_pciercx_cfg009_s cn56xxp1;
+       struct cvmx_pciercx_cfg009_s cn61xx;
        struct cvmx_pciercx_cfg009_s cn63xx;
        struct cvmx_pciercx_cfg009_s cn63xxp1;
+       struct cvmx_pciercx_cfg009_s cn66xx;
+       struct cvmx_pciercx_cfg009_s cn68xx;
+       struct cvmx_pciercx_cfg009_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg010 {
@@ -303,8 +343,12 @@ union cvmx_pciercx_cfg010 {
        struct cvmx_pciercx_cfg010_s cn52xxp1;
        struct cvmx_pciercx_cfg010_s cn56xx;
        struct cvmx_pciercx_cfg010_s cn56xxp1;
+       struct cvmx_pciercx_cfg010_s cn61xx;
        struct cvmx_pciercx_cfg010_s cn63xx;
        struct cvmx_pciercx_cfg010_s cn63xxp1;
+       struct cvmx_pciercx_cfg010_s cn66xx;
+       struct cvmx_pciercx_cfg010_s cn68xx;
+       struct cvmx_pciercx_cfg010_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg011 {
@@ -316,8 +360,12 @@ union cvmx_pciercx_cfg011 {
        struct cvmx_pciercx_cfg011_s cn52xxp1;
        struct cvmx_pciercx_cfg011_s cn56xx;
        struct cvmx_pciercx_cfg011_s cn56xxp1;
+       struct cvmx_pciercx_cfg011_s cn61xx;
        struct cvmx_pciercx_cfg011_s cn63xx;
        struct cvmx_pciercx_cfg011_s cn63xxp1;
+       struct cvmx_pciercx_cfg011_s cn66xx;
+       struct cvmx_pciercx_cfg011_s cn68xx;
+       struct cvmx_pciercx_cfg011_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg012 {
@@ -330,8 +378,12 @@ union cvmx_pciercx_cfg012 {
        struct cvmx_pciercx_cfg012_s cn52xxp1;
        struct cvmx_pciercx_cfg012_s cn56xx;
        struct cvmx_pciercx_cfg012_s cn56xxp1;
+       struct cvmx_pciercx_cfg012_s cn61xx;
        struct cvmx_pciercx_cfg012_s cn63xx;
        struct cvmx_pciercx_cfg012_s cn63xxp1;
+       struct cvmx_pciercx_cfg012_s cn66xx;
+       struct cvmx_pciercx_cfg012_s cn68xx;
+       struct cvmx_pciercx_cfg012_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg013 {
@@ -344,8 +396,12 @@ union cvmx_pciercx_cfg013 {
        struct cvmx_pciercx_cfg013_s cn52xxp1;
        struct cvmx_pciercx_cfg013_s cn56xx;
        struct cvmx_pciercx_cfg013_s cn56xxp1;
+       struct cvmx_pciercx_cfg013_s cn61xx;
        struct cvmx_pciercx_cfg013_s cn63xx;
        struct cvmx_pciercx_cfg013_s cn63xxp1;
+       struct cvmx_pciercx_cfg013_s cn66xx;
+       struct cvmx_pciercx_cfg013_s cn68xx;
+       struct cvmx_pciercx_cfg013_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg014 {
@@ -357,8 +413,12 @@ union cvmx_pciercx_cfg014 {
        struct cvmx_pciercx_cfg014_s cn52xxp1;
        struct cvmx_pciercx_cfg014_s cn56xx;
        struct cvmx_pciercx_cfg014_s cn56xxp1;
+       struct cvmx_pciercx_cfg014_s cn61xx;
        struct cvmx_pciercx_cfg014_s cn63xx;
        struct cvmx_pciercx_cfg014_s cn63xxp1;
+       struct cvmx_pciercx_cfg014_s cn66xx;
+       struct cvmx_pciercx_cfg014_s cn68xx;
+       struct cvmx_pciercx_cfg014_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg015 {
@@ -384,8 +444,12 @@ union cvmx_pciercx_cfg015 {
        struct cvmx_pciercx_cfg015_s cn52xxp1;
        struct cvmx_pciercx_cfg015_s cn56xx;
        struct cvmx_pciercx_cfg015_s cn56xxp1;
+       struct cvmx_pciercx_cfg015_s cn61xx;
        struct cvmx_pciercx_cfg015_s cn63xx;
        struct cvmx_pciercx_cfg015_s cn63xxp1;
+       struct cvmx_pciercx_cfg015_s cn66xx;
+       struct cvmx_pciercx_cfg015_s cn68xx;
+       struct cvmx_pciercx_cfg015_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg016 {
@@ -406,8 +470,12 @@ union cvmx_pciercx_cfg016 {
        struct cvmx_pciercx_cfg016_s cn52xxp1;
        struct cvmx_pciercx_cfg016_s cn56xx;
        struct cvmx_pciercx_cfg016_s cn56xxp1;
+       struct cvmx_pciercx_cfg016_s cn61xx;
        struct cvmx_pciercx_cfg016_s cn63xx;
        struct cvmx_pciercx_cfg016_s cn63xxp1;
+       struct cvmx_pciercx_cfg016_s cn66xx;
+       struct cvmx_pciercx_cfg016_s cn68xx;
+       struct cvmx_pciercx_cfg016_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg017 {
@@ -430,14 +498,19 @@ union cvmx_pciercx_cfg017 {
        struct cvmx_pciercx_cfg017_s cn52xxp1;
        struct cvmx_pciercx_cfg017_s cn56xx;
        struct cvmx_pciercx_cfg017_s cn56xxp1;
+       struct cvmx_pciercx_cfg017_s cn61xx;
        struct cvmx_pciercx_cfg017_s cn63xx;
        struct cvmx_pciercx_cfg017_s cn63xxp1;
+       struct cvmx_pciercx_cfg017_s cn66xx;
+       struct cvmx_pciercx_cfg017_s cn68xx;
+       struct cvmx_pciercx_cfg017_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg020 {
        uint32_t u32;
        struct cvmx_pciercx_cfg020_s {
-               uint32_t reserved_24_31:8;
+               uint32_t reserved_25_31:7;
+               uint32_t pvm:1;
                uint32_t m64:1;
                uint32_t mme:3;
                uint32_t mmc:3;
@@ -445,12 +518,24 @@ union cvmx_pciercx_cfg020 {
                uint32_t ncp:8;
                uint32_t msicid:8;
        } s;
-       struct cvmx_pciercx_cfg020_s cn52xx;
-       struct cvmx_pciercx_cfg020_s cn52xxp1;
-       struct cvmx_pciercx_cfg020_s cn56xx;
-       struct cvmx_pciercx_cfg020_s cn56xxp1;
-       struct cvmx_pciercx_cfg020_s cn63xx;
-       struct cvmx_pciercx_cfg020_s cn63xxp1;
+       struct cvmx_pciercx_cfg020_cn52xx {
+               uint32_t reserved_24_31:8;
+               uint32_t m64:1;
+               uint32_t mme:3;
+               uint32_t mmc:3;
+               uint32_t msien:1;
+               uint32_t ncp:8;
+               uint32_t msicid:8;
+       } cn52xx;
+       struct cvmx_pciercx_cfg020_cn52xx cn52xxp1;
+       struct cvmx_pciercx_cfg020_cn52xx cn56xx;
+       struct cvmx_pciercx_cfg020_cn52xx cn56xxp1;
+       struct cvmx_pciercx_cfg020_s cn61xx;
+       struct cvmx_pciercx_cfg020_cn52xx cn63xx;
+       struct cvmx_pciercx_cfg020_cn52xx cn63xxp1;
+       struct cvmx_pciercx_cfg020_cn52xx cn66xx;
+       struct cvmx_pciercx_cfg020_cn52xx cn68xx;
+       struct cvmx_pciercx_cfg020_cn52xx cn68xxp1;
 };
 
 union cvmx_pciercx_cfg021 {
@@ -463,8 +548,12 @@ union cvmx_pciercx_cfg021 {
        struct cvmx_pciercx_cfg021_s cn52xxp1;
        struct cvmx_pciercx_cfg021_s cn56xx;
        struct cvmx_pciercx_cfg021_s cn56xxp1;
+       struct cvmx_pciercx_cfg021_s cn61xx;
        struct cvmx_pciercx_cfg021_s cn63xx;
        struct cvmx_pciercx_cfg021_s cn63xxp1;
+       struct cvmx_pciercx_cfg021_s cn66xx;
+       struct cvmx_pciercx_cfg021_s cn68xx;
+       struct cvmx_pciercx_cfg021_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg022 {
@@ -476,8 +565,12 @@ union cvmx_pciercx_cfg022 {
        struct cvmx_pciercx_cfg022_s cn52xxp1;
        struct cvmx_pciercx_cfg022_s cn56xx;
        struct cvmx_pciercx_cfg022_s cn56xxp1;
+       struct cvmx_pciercx_cfg022_s cn61xx;
        struct cvmx_pciercx_cfg022_s cn63xx;
        struct cvmx_pciercx_cfg022_s cn63xxp1;
+       struct cvmx_pciercx_cfg022_s cn66xx;
+       struct cvmx_pciercx_cfg022_s cn68xx;
+       struct cvmx_pciercx_cfg022_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg023 {
@@ -490,8 +583,12 @@ union cvmx_pciercx_cfg023 {
        struct cvmx_pciercx_cfg023_s cn52xxp1;
        struct cvmx_pciercx_cfg023_s cn56xx;
        struct cvmx_pciercx_cfg023_s cn56xxp1;
+       struct cvmx_pciercx_cfg023_s cn61xx;
        struct cvmx_pciercx_cfg023_s cn63xx;
        struct cvmx_pciercx_cfg023_s cn63xxp1;
+       struct cvmx_pciercx_cfg023_s cn66xx;
+       struct cvmx_pciercx_cfg023_s cn68xx;
+       struct cvmx_pciercx_cfg023_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg028 {
@@ -509,8 +606,12 @@ union cvmx_pciercx_cfg028 {
        struct cvmx_pciercx_cfg028_s cn52xxp1;
        struct cvmx_pciercx_cfg028_s cn56xx;
        struct cvmx_pciercx_cfg028_s cn56xxp1;
+       struct cvmx_pciercx_cfg028_s cn61xx;
        struct cvmx_pciercx_cfg028_s cn63xx;
        struct cvmx_pciercx_cfg028_s cn63xxp1;
+       struct cvmx_pciercx_cfg028_s cn66xx;
+       struct cvmx_pciercx_cfg028_s cn68xx;
+       struct cvmx_pciercx_cfg028_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg029 {
@@ -532,8 +633,12 @@ union cvmx_pciercx_cfg029 {
        struct cvmx_pciercx_cfg029_s cn52xxp1;
        struct cvmx_pciercx_cfg029_s cn56xx;
        struct cvmx_pciercx_cfg029_s cn56xxp1;
+       struct cvmx_pciercx_cfg029_s cn61xx;
        struct cvmx_pciercx_cfg029_s cn63xx;
        struct cvmx_pciercx_cfg029_s cn63xxp1;
+       struct cvmx_pciercx_cfg029_s cn66xx;
+       struct cvmx_pciercx_cfg029_s cn68xx;
+       struct cvmx_pciercx_cfg029_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg030 {
@@ -563,15 +668,20 @@ union cvmx_pciercx_cfg030 {
        struct cvmx_pciercx_cfg030_s cn52xxp1;
        struct cvmx_pciercx_cfg030_s cn56xx;
        struct cvmx_pciercx_cfg030_s cn56xxp1;
+       struct cvmx_pciercx_cfg030_s cn61xx;
        struct cvmx_pciercx_cfg030_s cn63xx;
        struct cvmx_pciercx_cfg030_s cn63xxp1;
+       struct cvmx_pciercx_cfg030_s cn66xx;
+       struct cvmx_pciercx_cfg030_s cn68xx;
+       struct cvmx_pciercx_cfg030_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg031 {
        uint32_t u32;
        struct cvmx_pciercx_cfg031_s {
                uint32_t pnum:8;
-               uint32_t reserved_22_23:2;
+               uint32_t reserved_23_23:1;
+               uint32_t aspm:1;
                uint32_t lbnc:1;
                uint32_t dllarc:1;
                uint32_t sderc:1;
@@ -582,12 +692,28 @@ union cvmx_pciercx_cfg031 {
                uint32_t mlw:6;
                uint32_t mls:4;
        } s;
-       struct cvmx_pciercx_cfg031_s cn52xx;
-       struct cvmx_pciercx_cfg031_s cn52xxp1;
-       struct cvmx_pciercx_cfg031_s cn56xx;
-       struct cvmx_pciercx_cfg031_s cn56xxp1;
-       struct cvmx_pciercx_cfg031_s cn63xx;
-       struct cvmx_pciercx_cfg031_s cn63xxp1;
+       struct cvmx_pciercx_cfg031_cn52xx {
+               uint32_t pnum:8;
+               uint32_t reserved_22_23:2;
+               uint32_t lbnc:1;
+               uint32_t dllarc:1;
+               uint32_t sderc:1;
+               uint32_t cpm:1;
+               uint32_t l1el:3;
+               uint32_t l0el:3;
+               uint32_t aslpms:2;
+               uint32_t mlw:6;
+               uint32_t mls:4;
+       } cn52xx;
+       struct cvmx_pciercx_cfg031_cn52xx cn52xxp1;
+       struct cvmx_pciercx_cfg031_cn52xx cn56xx;
+       struct cvmx_pciercx_cfg031_cn52xx cn56xxp1;
+       struct cvmx_pciercx_cfg031_s cn61xx;
+       struct cvmx_pciercx_cfg031_cn52xx cn63xx;
+       struct cvmx_pciercx_cfg031_cn52xx cn63xxp1;
+       struct cvmx_pciercx_cfg031_s cn66xx;
+       struct cvmx_pciercx_cfg031_s cn68xx;
+       struct cvmx_pciercx_cfg031_cn52xx cn68xxp1;
 };
 
 union cvmx_pciercx_cfg032 {
@@ -618,8 +744,12 @@ union cvmx_pciercx_cfg032 {
        struct cvmx_pciercx_cfg032_s cn52xxp1;
        struct cvmx_pciercx_cfg032_s cn56xx;
        struct cvmx_pciercx_cfg032_s cn56xxp1;
+       struct cvmx_pciercx_cfg032_s cn61xx;
        struct cvmx_pciercx_cfg032_s cn63xx;
        struct cvmx_pciercx_cfg032_s cn63xxp1;
+       struct cvmx_pciercx_cfg032_s cn66xx;
+       struct cvmx_pciercx_cfg032_s cn68xx;
+       struct cvmx_pciercx_cfg032_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg033 {
@@ -642,8 +772,12 @@ union cvmx_pciercx_cfg033 {
        struct cvmx_pciercx_cfg033_s cn52xxp1;
        struct cvmx_pciercx_cfg033_s cn56xx;
        struct cvmx_pciercx_cfg033_s cn56xxp1;
+       struct cvmx_pciercx_cfg033_s cn61xx;
        struct cvmx_pciercx_cfg033_s cn63xx;
        struct cvmx_pciercx_cfg033_s cn63xxp1;
+       struct cvmx_pciercx_cfg033_s cn66xx;
+       struct cvmx_pciercx_cfg033_s cn68xx;
+       struct cvmx_pciercx_cfg033_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg034 {
@@ -676,8 +810,12 @@ union cvmx_pciercx_cfg034 {
        struct cvmx_pciercx_cfg034_s cn52xxp1;
        struct cvmx_pciercx_cfg034_s cn56xx;
        struct cvmx_pciercx_cfg034_s cn56xxp1;
+       struct cvmx_pciercx_cfg034_s cn61xx;
        struct cvmx_pciercx_cfg034_s cn63xx;
        struct cvmx_pciercx_cfg034_s cn63xxp1;
+       struct cvmx_pciercx_cfg034_s cn66xx;
+       struct cvmx_pciercx_cfg034_s cn68xx;
+       struct cvmx_pciercx_cfg034_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg035 {
@@ -696,8 +834,12 @@ union cvmx_pciercx_cfg035 {
        struct cvmx_pciercx_cfg035_s cn52xxp1;
        struct cvmx_pciercx_cfg035_s cn56xx;
        struct cvmx_pciercx_cfg035_s cn56xxp1;
+       struct cvmx_pciercx_cfg035_s cn61xx;
        struct cvmx_pciercx_cfg035_s cn63xx;
        struct cvmx_pciercx_cfg035_s cn63xxp1;
+       struct cvmx_pciercx_cfg035_s cn66xx;
+       struct cvmx_pciercx_cfg035_s cn68xx;
+       struct cvmx_pciercx_cfg035_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg036 {
@@ -712,38 +854,95 @@ union cvmx_pciercx_cfg036 {
        struct cvmx_pciercx_cfg036_s cn52xxp1;
        struct cvmx_pciercx_cfg036_s cn56xx;
        struct cvmx_pciercx_cfg036_s cn56xxp1;
+       struct cvmx_pciercx_cfg036_s cn61xx;
        struct cvmx_pciercx_cfg036_s cn63xx;
        struct cvmx_pciercx_cfg036_s cn63xxp1;
+       struct cvmx_pciercx_cfg036_s cn66xx;
+       struct cvmx_pciercx_cfg036_s cn68xx;
+       struct cvmx_pciercx_cfg036_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg037 {
        uint32_t u32;
        struct cvmx_pciercx_cfg037_s {
-               uint32_t reserved_5_31:27;
+               uint32_t reserved_14_31:18;
+               uint32_t tph:2;
+               uint32_t reserved_11_11:1;
+               uint32_t noroprpr:1;
+               uint32_t atom128s:1;
+               uint32_t atom64s:1;
+               uint32_t atom32s:1;
+               uint32_t atom_ops:1;
+               uint32_t reserved_5_5:1;
                uint32_t ctds:1;
                uint32_t ctrs:4;
        } s;
-       struct cvmx_pciercx_cfg037_s cn52xx;
-       struct cvmx_pciercx_cfg037_s cn52xxp1;
-       struct cvmx_pciercx_cfg037_s cn56xx;
-       struct cvmx_pciercx_cfg037_s cn56xxp1;
-       struct cvmx_pciercx_cfg037_s cn63xx;
-       struct cvmx_pciercx_cfg037_s cn63xxp1;
+       struct cvmx_pciercx_cfg037_cn52xx {
+               uint32_t reserved_5_31:27;
+               uint32_t ctds:1;
+               uint32_t ctrs:4;
+       } cn52xx;
+       struct cvmx_pciercx_cfg037_cn52xx cn52xxp1;
+       struct cvmx_pciercx_cfg037_cn52xx cn56xx;
+       struct cvmx_pciercx_cfg037_cn52xx cn56xxp1;
+       struct cvmx_pciercx_cfg037_cn61xx {
+               uint32_t reserved_14_31:18;
+               uint32_t tph:2;
+               uint32_t reserved_11_11:1;
+               uint32_t noroprpr:1;
+               uint32_t atom128s:1;
+               uint32_t atom64s:1;
+               uint32_t atom32s:1;
+               uint32_t atom_ops:1;
+               uint32_t ari_fw:1;
+               uint32_t ctds:1;
+               uint32_t ctrs:4;
+       } cn61xx;
+       struct cvmx_pciercx_cfg037_cn52xx cn63xx;
+       struct cvmx_pciercx_cfg037_cn52xx cn63xxp1;
+       struct cvmx_pciercx_cfg037_cn66xx {
+               uint32_t reserved_14_31:18;
+               uint32_t tph:2;
+               uint32_t reserved_11_11:1;
+               uint32_t noroprpr:1;
+               uint32_t atom128s:1;
+               uint32_t atom64s:1;
+               uint32_t atom32s:1;
+               uint32_t atom_ops:1;
+               uint32_t ari:1;
+               uint32_t ctds:1;
+               uint32_t ctrs:4;
+       } cn66xx;
+       struct cvmx_pciercx_cfg037_cn66xx cn68xx;
+       struct cvmx_pciercx_cfg037_cn66xx cn68xxp1;
 };
 
 union cvmx_pciercx_cfg038 {
        uint32_t u32;
        struct cvmx_pciercx_cfg038_s {
-               uint32_t reserved_5_31:27;
+               uint32_t reserved_10_31:22;
+               uint32_t id0_cp:1;
+               uint32_t id0_rq:1;
+               uint32_t atom_op_eb:1;
+               uint32_t atom_op:1;
+               uint32_t ari:1;
                uint32_t ctd:1;
                uint32_t ctv:4;
        } s;
-       struct cvmx_pciercx_cfg038_s cn52xx;
-       struct cvmx_pciercx_cfg038_s cn52xxp1;
-       struct cvmx_pciercx_cfg038_s cn56xx;
-       struct cvmx_pciercx_cfg038_s cn56xxp1;
-       struct cvmx_pciercx_cfg038_s cn63xx;
-       struct cvmx_pciercx_cfg038_s cn63xxp1;
+       struct cvmx_pciercx_cfg038_cn52xx {
+               uint32_t reserved_5_31:27;
+               uint32_t ctd:1;
+               uint32_t ctv:4;
+       } cn52xx;
+       struct cvmx_pciercx_cfg038_cn52xx cn52xxp1;
+       struct cvmx_pciercx_cfg038_cn52xx cn56xx;
+       struct cvmx_pciercx_cfg038_cn52xx cn56xxp1;
+       struct cvmx_pciercx_cfg038_s cn61xx;
+       struct cvmx_pciercx_cfg038_cn52xx cn63xx;
+       struct cvmx_pciercx_cfg038_cn52xx cn63xxp1;
+       struct cvmx_pciercx_cfg038_s cn66xx;
+       struct cvmx_pciercx_cfg038_s cn68xx;
+       struct cvmx_pciercx_cfg038_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg039 {
@@ -760,8 +959,12 @@ union cvmx_pciercx_cfg039 {
        struct cvmx_pciercx_cfg039_cn52xx cn52xxp1;
        struct cvmx_pciercx_cfg039_cn52xx cn56xx;
        struct cvmx_pciercx_cfg039_cn52xx cn56xxp1;
+       struct cvmx_pciercx_cfg039_s cn61xx;
        struct cvmx_pciercx_cfg039_s cn63xx;
        struct cvmx_pciercx_cfg039_cn52xx cn63xxp1;
+       struct cvmx_pciercx_cfg039_s cn66xx;
+       struct cvmx_pciercx_cfg039_s cn68xx;
+       struct cvmx_pciercx_cfg039_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg040 {
@@ -785,8 +988,12 @@ union cvmx_pciercx_cfg040 {
        struct cvmx_pciercx_cfg040_cn52xx cn52xxp1;
        struct cvmx_pciercx_cfg040_cn52xx cn56xx;
        struct cvmx_pciercx_cfg040_cn52xx cn56xxp1;
+       struct cvmx_pciercx_cfg040_s cn61xx;
        struct cvmx_pciercx_cfg040_s cn63xx;
        struct cvmx_pciercx_cfg040_s cn63xxp1;
+       struct cvmx_pciercx_cfg040_s cn66xx;
+       struct cvmx_pciercx_cfg040_s cn68xx;
+       struct cvmx_pciercx_cfg040_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg041 {
@@ -798,8 +1005,12 @@ union cvmx_pciercx_cfg041 {
        struct cvmx_pciercx_cfg041_s cn52xxp1;
        struct cvmx_pciercx_cfg041_s cn56xx;
        struct cvmx_pciercx_cfg041_s cn56xxp1;
+       struct cvmx_pciercx_cfg041_s cn61xx;
        struct cvmx_pciercx_cfg041_s cn63xx;
        struct cvmx_pciercx_cfg041_s cn63xxp1;
+       struct cvmx_pciercx_cfg041_s cn66xx;
+       struct cvmx_pciercx_cfg041_s cn68xx;
+       struct cvmx_pciercx_cfg041_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg042 {
@@ -811,8 +1022,12 @@ union cvmx_pciercx_cfg042 {
        struct cvmx_pciercx_cfg042_s cn52xxp1;
        struct cvmx_pciercx_cfg042_s cn56xx;
        struct cvmx_pciercx_cfg042_s cn56xxp1;
+       struct cvmx_pciercx_cfg042_s cn61xx;
        struct cvmx_pciercx_cfg042_s cn63xx;
        struct cvmx_pciercx_cfg042_s cn63xxp1;
+       struct cvmx_pciercx_cfg042_s cn66xx;
+       struct cvmx_pciercx_cfg042_s cn68xx;
+       struct cvmx_pciercx_cfg042_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg064 {
@@ -826,14 +1041,20 @@ union cvmx_pciercx_cfg064 {
        struct cvmx_pciercx_cfg064_s cn52xxp1;
        struct cvmx_pciercx_cfg064_s cn56xx;
        struct cvmx_pciercx_cfg064_s cn56xxp1;
+       struct cvmx_pciercx_cfg064_s cn61xx;
        struct cvmx_pciercx_cfg064_s cn63xx;
        struct cvmx_pciercx_cfg064_s cn63xxp1;
+       struct cvmx_pciercx_cfg064_s cn66xx;
+       struct cvmx_pciercx_cfg064_s cn68xx;
+       struct cvmx_pciercx_cfg064_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg065 {
        uint32_t u32;
        struct cvmx_pciercx_cfg065_s {
-               uint32_t reserved_21_31:11;
+               uint32_t reserved_25_31:7;
+               uint32_t uatombs:1;
+               uint32_t reserved_21_23:3;
                uint32_t ures:1;
                uint32_t ecrces:1;
                uint32_t mtlps:1;
@@ -848,18 +1069,39 @@ union cvmx_pciercx_cfg065 {
                uint32_t dlpes:1;
                uint32_t reserved_0_3:4;
        } s;
-       struct cvmx_pciercx_cfg065_s cn52xx;
-       struct cvmx_pciercx_cfg065_s cn52xxp1;
-       struct cvmx_pciercx_cfg065_s cn56xx;
-       struct cvmx_pciercx_cfg065_s cn56xxp1;
-       struct cvmx_pciercx_cfg065_s cn63xx;
-       struct cvmx_pciercx_cfg065_s cn63xxp1;
+       struct cvmx_pciercx_cfg065_cn52xx {
+               uint32_t reserved_21_31:11;
+               uint32_t ures:1;
+               uint32_t ecrces:1;
+               uint32_t mtlps:1;
+               uint32_t ros:1;
+               uint32_t ucs:1;
+               uint32_t cas:1;
+               uint32_t cts:1;
+               uint32_t fcpes:1;
+               uint32_t ptlps:1;
+               uint32_t reserved_6_11:6;
+               uint32_t sdes:1;
+               uint32_t dlpes:1;
+               uint32_t reserved_0_3:4;
+       } cn52xx;
+       struct cvmx_pciercx_cfg065_cn52xx cn52xxp1;
+       struct cvmx_pciercx_cfg065_cn52xx cn56xx;
+       struct cvmx_pciercx_cfg065_cn52xx cn56xxp1;
+       struct cvmx_pciercx_cfg065_s cn61xx;
+       struct cvmx_pciercx_cfg065_cn52xx cn63xx;
+       struct cvmx_pciercx_cfg065_cn52xx cn63xxp1;
+       struct cvmx_pciercx_cfg065_s cn66xx;
+       struct cvmx_pciercx_cfg065_s cn68xx;
+       struct cvmx_pciercx_cfg065_cn52xx cn68xxp1;
 };
 
 union cvmx_pciercx_cfg066 {
        uint32_t u32;
        struct cvmx_pciercx_cfg066_s {
-               uint32_t reserved_21_31:11;
+               uint32_t reserved_25_31:7;
+               uint32_t uatombm:1;
+               uint32_t reserved_21_23:3;
                uint32_t urem:1;
                uint32_t ecrcem:1;
                uint32_t mtlpm:1;
@@ -874,18 +1116,39 @@ union cvmx_pciercx_cfg066 {
                uint32_t dlpem:1;
                uint32_t reserved_0_3:4;
        } s;
-       struct cvmx_pciercx_cfg066_s cn52xx;
-       struct cvmx_pciercx_cfg066_s cn52xxp1;
-       struct cvmx_pciercx_cfg066_s cn56xx;
-       struct cvmx_pciercx_cfg066_s cn56xxp1;
-       struct cvmx_pciercx_cfg066_s cn63xx;
-       struct cvmx_pciercx_cfg066_s cn63xxp1;
+       struct cvmx_pciercx_cfg066_cn52xx {
+               uint32_t reserved_21_31:11;
+               uint32_t urem:1;
+               uint32_t ecrcem:1;
+               uint32_t mtlpm:1;
+               uint32_t rom:1;
+               uint32_t ucm:1;
+               uint32_t cam:1;
+               uint32_t ctm:1;
+               uint32_t fcpem:1;
+               uint32_t ptlpm:1;
+               uint32_t reserved_6_11:6;
+               uint32_t sdem:1;
+               uint32_t dlpem:1;
+               uint32_t reserved_0_3:4;
+       } cn52xx;
+       struct cvmx_pciercx_cfg066_cn52xx cn52xxp1;
+       struct cvmx_pciercx_cfg066_cn52xx cn56xx;
+       struct cvmx_pciercx_cfg066_cn52xx cn56xxp1;
+       struct cvmx_pciercx_cfg066_s cn61xx;
+       struct cvmx_pciercx_cfg066_cn52xx cn63xx;
+       struct cvmx_pciercx_cfg066_cn52xx cn63xxp1;
+       struct cvmx_pciercx_cfg066_s cn66xx;
+       struct cvmx_pciercx_cfg066_s cn68xx;
+       struct cvmx_pciercx_cfg066_cn52xx cn68xxp1;
 };
 
 union cvmx_pciercx_cfg067 {
        uint32_t u32;
        struct cvmx_pciercx_cfg067_s {
-               uint32_t reserved_21_31:11;
+               uint32_t reserved_25_31:7;
+               uint32_t uatombs:1;
+               uint32_t reserved_21_23:3;
                uint32_t ures:1;
                uint32_t ecrces:1;
                uint32_t mtlps:1;
@@ -900,12 +1163,31 @@ union cvmx_pciercx_cfg067 {
                uint32_t dlpes:1;
                uint32_t reserved_0_3:4;
        } s;
-       struct cvmx_pciercx_cfg067_s cn52xx;
-       struct cvmx_pciercx_cfg067_s cn52xxp1;
-       struct cvmx_pciercx_cfg067_s cn56xx;
-       struct cvmx_pciercx_cfg067_s cn56xxp1;
-       struct cvmx_pciercx_cfg067_s cn63xx;
-       struct cvmx_pciercx_cfg067_s cn63xxp1;
+       struct cvmx_pciercx_cfg067_cn52xx {
+               uint32_t reserved_21_31:11;
+               uint32_t ures:1;
+               uint32_t ecrces:1;
+               uint32_t mtlps:1;
+               uint32_t ros:1;
+               uint32_t ucs:1;
+               uint32_t cas:1;
+               uint32_t cts:1;
+               uint32_t fcpes:1;
+               uint32_t ptlps:1;
+               uint32_t reserved_6_11:6;
+               uint32_t sdes:1;
+               uint32_t dlpes:1;
+               uint32_t reserved_0_3:4;
+       } cn52xx;
+       struct cvmx_pciercx_cfg067_cn52xx cn52xxp1;
+       struct cvmx_pciercx_cfg067_cn52xx cn56xx;
+       struct cvmx_pciercx_cfg067_cn52xx cn56xxp1;
+       struct cvmx_pciercx_cfg067_s cn61xx;
+       struct cvmx_pciercx_cfg067_cn52xx cn63xx;
+       struct cvmx_pciercx_cfg067_cn52xx cn63xxp1;
+       struct cvmx_pciercx_cfg067_s cn66xx;
+       struct cvmx_pciercx_cfg067_s cn68xx;
+       struct cvmx_pciercx_cfg067_cn52xx cn68xxp1;
 };
 
 union cvmx_pciercx_cfg068 {
@@ -925,8 +1207,12 @@ union cvmx_pciercx_cfg068 {
        struct cvmx_pciercx_cfg068_s cn52xxp1;
        struct cvmx_pciercx_cfg068_s cn56xx;
        struct cvmx_pciercx_cfg068_s cn56xxp1;
+       struct cvmx_pciercx_cfg068_s cn61xx;
        struct cvmx_pciercx_cfg068_s cn63xx;
        struct cvmx_pciercx_cfg068_s cn63xxp1;
+       struct cvmx_pciercx_cfg068_s cn66xx;
+       struct cvmx_pciercx_cfg068_s cn68xx;
+       struct cvmx_pciercx_cfg068_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg069 {
@@ -946,8 +1232,12 @@ union cvmx_pciercx_cfg069 {
        struct cvmx_pciercx_cfg069_s cn52xxp1;
        struct cvmx_pciercx_cfg069_s cn56xx;
        struct cvmx_pciercx_cfg069_s cn56xxp1;
+       struct cvmx_pciercx_cfg069_s cn61xx;
        struct cvmx_pciercx_cfg069_s cn63xx;
        struct cvmx_pciercx_cfg069_s cn63xxp1;
+       struct cvmx_pciercx_cfg069_s cn66xx;
+       struct cvmx_pciercx_cfg069_s cn68xx;
+       struct cvmx_pciercx_cfg069_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg070 {
@@ -964,8 +1254,12 @@ union cvmx_pciercx_cfg070 {
        struct cvmx_pciercx_cfg070_s cn52xxp1;
        struct cvmx_pciercx_cfg070_s cn56xx;
        struct cvmx_pciercx_cfg070_s cn56xxp1;
+       struct cvmx_pciercx_cfg070_s cn61xx;
        struct cvmx_pciercx_cfg070_s cn63xx;
        struct cvmx_pciercx_cfg070_s cn63xxp1;
+       struct cvmx_pciercx_cfg070_s cn66xx;
+       struct cvmx_pciercx_cfg070_s cn68xx;
+       struct cvmx_pciercx_cfg070_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg071 {
@@ -977,8 +1271,12 @@ union cvmx_pciercx_cfg071 {
        struct cvmx_pciercx_cfg071_s cn52xxp1;
        struct cvmx_pciercx_cfg071_s cn56xx;
        struct cvmx_pciercx_cfg071_s cn56xxp1;
+       struct cvmx_pciercx_cfg071_s cn61xx;
        struct cvmx_pciercx_cfg071_s cn63xx;
        struct cvmx_pciercx_cfg071_s cn63xxp1;
+       struct cvmx_pciercx_cfg071_s cn66xx;
+       struct cvmx_pciercx_cfg071_s cn68xx;
+       struct cvmx_pciercx_cfg071_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg072 {
@@ -990,8 +1288,12 @@ union cvmx_pciercx_cfg072 {
        struct cvmx_pciercx_cfg072_s cn52xxp1;
        struct cvmx_pciercx_cfg072_s cn56xx;
        struct cvmx_pciercx_cfg072_s cn56xxp1;
+       struct cvmx_pciercx_cfg072_s cn61xx;
        struct cvmx_pciercx_cfg072_s cn63xx;
        struct cvmx_pciercx_cfg072_s cn63xxp1;
+       struct cvmx_pciercx_cfg072_s cn66xx;
+       struct cvmx_pciercx_cfg072_s cn68xx;
+       struct cvmx_pciercx_cfg072_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg073 {
@@ -1003,8 +1305,12 @@ union cvmx_pciercx_cfg073 {
        struct cvmx_pciercx_cfg073_s cn52xxp1;
        struct cvmx_pciercx_cfg073_s cn56xx;
        struct cvmx_pciercx_cfg073_s cn56xxp1;
+       struct cvmx_pciercx_cfg073_s cn61xx;
        struct cvmx_pciercx_cfg073_s cn63xx;
        struct cvmx_pciercx_cfg073_s cn63xxp1;
+       struct cvmx_pciercx_cfg073_s cn66xx;
+       struct cvmx_pciercx_cfg073_s cn68xx;
+       struct cvmx_pciercx_cfg073_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg074 {
@@ -1016,8 +1322,12 @@ union cvmx_pciercx_cfg074 {
        struct cvmx_pciercx_cfg074_s cn52xxp1;
        struct cvmx_pciercx_cfg074_s cn56xx;
        struct cvmx_pciercx_cfg074_s cn56xxp1;
+       struct cvmx_pciercx_cfg074_s cn61xx;
        struct cvmx_pciercx_cfg074_s cn63xx;
        struct cvmx_pciercx_cfg074_s cn63xxp1;
+       struct cvmx_pciercx_cfg074_s cn66xx;
+       struct cvmx_pciercx_cfg074_s cn68xx;
+       struct cvmx_pciercx_cfg074_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg075 {
@@ -1032,8 +1342,12 @@ union cvmx_pciercx_cfg075 {
        struct cvmx_pciercx_cfg075_s cn52xxp1;
        struct cvmx_pciercx_cfg075_s cn56xx;
        struct cvmx_pciercx_cfg075_s cn56xxp1;
+       struct cvmx_pciercx_cfg075_s cn61xx;
        struct cvmx_pciercx_cfg075_s cn63xx;
        struct cvmx_pciercx_cfg075_s cn63xxp1;
+       struct cvmx_pciercx_cfg075_s cn66xx;
+       struct cvmx_pciercx_cfg075_s cn68xx;
+       struct cvmx_pciercx_cfg075_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg076 {
@@ -1053,8 +1367,12 @@ union cvmx_pciercx_cfg076 {
        struct cvmx_pciercx_cfg076_s cn52xxp1;
        struct cvmx_pciercx_cfg076_s cn56xx;
        struct cvmx_pciercx_cfg076_s cn56xxp1;
+       struct cvmx_pciercx_cfg076_s cn61xx;
        struct cvmx_pciercx_cfg076_s cn63xx;
        struct cvmx_pciercx_cfg076_s cn63xxp1;
+       struct cvmx_pciercx_cfg076_s cn66xx;
+       struct cvmx_pciercx_cfg076_s cn68xx;
+       struct cvmx_pciercx_cfg076_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg077 {
@@ -1067,8 +1385,12 @@ union cvmx_pciercx_cfg077 {
        struct cvmx_pciercx_cfg077_s cn52xxp1;
        struct cvmx_pciercx_cfg077_s cn56xx;
        struct cvmx_pciercx_cfg077_s cn56xxp1;
+       struct cvmx_pciercx_cfg077_s cn61xx;
        struct cvmx_pciercx_cfg077_s cn63xx;
        struct cvmx_pciercx_cfg077_s cn63xxp1;
+       struct cvmx_pciercx_cfg077_s cn66xx;
+       struct cvmx_pciercx_cfg077_s cn68xx;
+       struct cvmx_pciercx_cfg077_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg448 {
@@ -1081,8 +1403,12 @@ union cvmx_pciercx_cfg448 {
        struct cvmx_pciercx_cfg448_s cn52xxp1;
        struct cvmx_pciercx_cfg448_s cn56xx;
        struct cvmx_pciercx_cfg448_s cn56xxp1;
+       struct cvmx_pciercx_cfg448_s cn61xx;
        struct cvmx_pciercx_cfg448_s cn63xx;
        struct cvmx_pciercx_cfg448_s cn63xxp1;
+       struct cvmx_pciercx_cfg448_s cn66xx;
+       struct cvmx_pciercx_cfg448_s cn68xx;
+       struct cvmx_pciercx_cfg448_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg449 {
@@ -1094,8 +1420,12 @@ union cvmx_pciercx_cfg449 {
        struct cvmx_pciercx_cfg449_s cn52xxp1;
        struct cvmx_pciercx_cfg449_s cn56xx;
        struct cvmx_pciercx_cfg449_s cn56xxp1;
+       struct cvmx_pciercx_cfg449_s cn61xx;
        struct cvmx_pciercx_cfg449_s cn63xx;
        struct cvmx_pciercx_cfg449_s cn63xxp1;
+       struct cvmx_pciercx_cfg449_s cn66xx;
+       struct cvmx_pciercx_cfg449_s cn68xx;
+       struct cvmx_pciercx_cfg449_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg450 {
@@ -1112,26 +1442,42 @@ union cvmx_pciercx_cfg450 {
        struct cvmx_pciercx_cfg450_s cn52xxp1;
        struct cvmx_pciercx_cfg450_s cn56xx;
        struct cvmx_pciercx_cfg450_s cn56xxp1;
+       struct cvmx_pciercx_cfg450_s cn61xx;
        struct cvmx_pciercx_cfg450_s cn63xx;
        struct cvmx_pciercx_cfg450_s cn63xxp1;
+       struct cvmx_pciercx_cfg450_s cn66xx;
+       struct cvmx_pciercx_cfg450_s cn68xx;
+       struct cvmx_pciercx_cfg450_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg451 {
        uint32_t u32;
        struct cvmx_pciercx_cfg451_s {
-               uint32_t reserved_30_31:2;
+               uint32_t reserved_31_31:1;
+               uint32_t easpml1:1;
                uint32_t l1el:3;
                uint32_t l0el:3;
                uint32_t n_fts_cc:8;
                uint32_t n_fts:8;
                uint32_t ack_freq:8;
        } s;
-       struct cvmx_pciercx_cfg451_s cn52xx;
-       struct cvmx_pciercx_cfg451_s cn52xxp1;
-       struct cvmx_pciercx_cfg451_s cn56xx;
-       struct cvmx_pciercx_cfg451_s cn56xxp1;
-       struct cvmx_pciercx_cfg451_s cn63xx;
-       struct cvmx_pciercx_cfg451_s cn63xxp1;
+       struct cvmx_pciercx_cfg451_cn52xx {
+               uint32_t reserved_30_31:2;
+               uint32_t l1el:3;
+               uint32_t l0el:3;
+               uint32_t n_fts_cc:8;
+               uint32_t n_fts:8;
+               uint32_t ack_freq:8;
+       } cn52xx;
+       struct cvmx_pciercx_cfg451_cn52xx cn52xxp1;
+       struct cvmx_pciercx_cfg451_cn52xx cn56xx;
+       struct cvmx_pciercx_cfg451_cn52xx cn56xxp1;
+       struct cvmx_pciercx_cfg451_s cn61xx;
+       struct cvmx_pciercx_cfg451_cn52xx cn63xx;
+       struct cvmx_pciercx_cfg451_cn52xx cn63xxp1;
+       struct cvmx_pciercx_cfg451_s cn66xx;
+       struct cvmx_pciercx_cfg451_s cn68xx;
+       struct cvmx_pciercx_cfg451_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg452 {
@@ -1155,8 +1501,24 @@ union cvmx_pciercx_cfg452 {
        struct cvmx_pciercx_cfg452_s cn52xxp1;
        struct cvmx_pciercx_cfg452_s cn56xx;
        struct cvmx_pciercx_cfg452_s cn56xxp1;
+       struct cvmx_pciercx_cfg452_cn61xx {
+               uint32_t reserved_22_31:10;
+               uint32_t lme:6;
+               uint32_t reserved_8_15:8;
+               uint32_t flm:1;
+               uint32_t reserved_6_6:1;
+               uint32_t dllle:1;
+               uint32_t reserved_4_4:1;
+               uint32_t ra:1;
+               uint32_t le:1;
+               uint32_t sd:1;
+               uint32_t omr:1;
+       } cn61xx;
        struct cvmx_pciercx_cfg452_s cn63xx;
        struct cvmx_pciercx_cfg452_s cn63xxp1;
+       struct cvmx_pciercx_cfg452_cn61xx cn66xx;
+       struct cvmx_pciercx_cfg452_cn61xx cn68xx;
+       struct cvmx_pciercx_cfg452_cn61xx cn68xxp1;
 };
 
 union cvmx_pciercx_cfg453 {
@@ -1172,13 +1534,26 @@ union cvmx_pciercx_cfg453 {
        struct cvmx_pciercx_cfg453_s cn52xxp1;
        struct cvmx_pciercx_cfg453_s cn56xx;
        struct cvmx_pciercx_cfg453_s cn56xxp1;
+       struct cvmx_pciercx_cfg453_s cn61xx;
        struct cvmx_pciercx_cfg453_s cn63xx;
        struct cvmx_pciercx_cfg453_s cn63xxp1;
+       struct cvmx_pciercx_cfg453_s cn66xx;
+       struct cvmx_pciercx_cfg453_s cn68xx;
+       struct cvmx_pciercx_cfg453_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg454 {
        uint32_t u32;
        struct cvmx_pciercx_cfg454_s {
+               uint32_t cx_nfunc:3;
+               uint32_t tmfcwt:5;
+               uint32_t tmanlt:5;
+               uint32_t tmrt:5;
+               uint32_t reserved_11_13:3;
+               uint32_t nskps:3;
+               uint32_t reserved_0_7:8;
+       } s;
+       struct cvmx_pciercx_cfg454_cn52xx {
                uint32_t reserved_29_31:3;
                uint32_t tmfcwt:5;
                uint32_t tmanlt:5;
@@ -1187,13 +1562,23 @@ union cvmx_pciercx_cfg454 {
                uint32_t nskps:3;
                uint32_t reserved_4_7:4;
                uint32_t ntss:4;
-       } s;
-       struct cvmx_pciercx_cfg454_s cn52xx;
-       struct cvmx_pciercx_cfg454_s cn52xxp1;
-       struct cvmx_pciercx_cfg454_s cn56xx;
-       struct cvmx_pciercx_cfg454_s cn56xxp1;
-       struct cvmx_pciercx_cfg454_s cn63xx;
-       struct cvmx_pciercx_cfg454_s cn63xxp1;
+       } cn52xx;
+       struct cvmx_pciercx_cfg454_cn52xx cn52xxp1;
+       struct cvmx_pciercx_cfg454_cn52xx cn56xx;
+       struct cvmx_pciercx_cfg454_cn52xx cn56xxp1;
+       struct cvmx_pciercx_cfg454_cn61xx {
+               uint32_t cx_nfunc:3;
+               uint32_t tmfcwt:5;
+               uint32_t tmanlt:5;
+               uint32_t tmrt:5;
+               uint32_t reserved_8_13:6;
+               uint32_t mfuncn:8;
+       } cn61xx;
+       struct cvmx_pciercx_cfg454_cn52xx cn63xx;
+       struct cvmx_pciercx_cfg454_cn52xx cn63xxp1;
+       struct cvmx_pciercx_cfg454_cn61xx cn66xx;
+       struct cvmx_pciercx_cfg454_cn61xx cn68xx;
+       struct cvmx_pciercx_cfg454_cn52xx cn68xxp1;
 };
 
 union cvmx_pciercx_cfg455 {
@@ -1223,23 +1608,37 @@ union cvmx_pciercx_cfg455 {
        struct cvmx_pciercx_cfg455_s cn52xxp1;
        struct cvmx_pciercx_cfg455_s cn56xx;
        struct cvmx_pciercx_cfg455_s cn56xxp1;
+       struct cvmx_pciercx_cfg455_s cn61xx;
        struct cvmx_pciercx_cfg455_s cn63xx;
        struct cvmx_pciercx_cfg455_s cn63xxp1;
+       struct cvmx_pciercx_cfg455_s cn66xx;
+       struct cvmx_pciercx_cfg455_s cn68xx;
+       struct cvmx_pciercx_cfg455_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg456 {
        uint32_t u32;
        struct cvmx_pciercx_cfg456_s {
-               uint32_t reserved_2_31:30;
+               uint32_t reserved_4_31:28;
+               uint32_t m_handle_flush:1;
+               uint32_t m_dabort_4ucpl:1;
                uint32_t m_vend1_drp:1;
                uint32_t m_vend0_drp:1;
        } s;
-       struct cvmx_pciercx_cfg456_s cn52xx;
-       struct cvmx_pciercx_cfg456_s cn52xxp1;
-       struct cvmx_pciercx_cfg456_s cn56xx;
-       struct cvmx_pciercx_cfg456_s cn56xxp1;
-       struct cvmx_pciercx_cfg456_s cn63xx;
-       struct cvmx_pciercx_cfg456_s cn63xxp1;
+       struct cvmx_pciercx_cfg456_cn52xx {
+               uint32_t reserved_2_31:30;
+               uint32_t m_vend1_drp:1;
+               uint32_t m_vend0_drp:1;
+       } cn52xx;
+       struct cvmx_pciercx_cfg456_cn52xx cn52xxp1;
+       struct cvmx_pciercx_cfg456_cn52xx cn56xx;
+       struct cvmx_pciercx_cfg456_cn52xx cn56xxp1;
+       struct cvmx_pciercx_cfg456_s cn61xx;
+       struct cvmx_pciercx_cfg456_cn52xx cn63xx;
+       struct cvmx_pciercx_cfg456_cn52xx cn63xxp1;
+       struct cvmx_pciercx_cfg456_s cn66xx;
+       struct cvmx_pciercx_cfg456_s cn68xx;
+       struct cvmx_pciercx_cfg456_cn52xx cn68xxp1;
 };
 
 union cvmx_pciercx_cfg458 {
@@ -1251,8 +1650,12 @@ union cvmx_pciercx_cfg458 {
        struct cvmx_pciercx_cfg458_s cn52xxp1;
        struct cvmx_pciercx_cfg458_s cn56xx;
        struct cvmx_pciercx_cfg458_s cn56xxp1;
+       struct cvmx_pciercx_cfg458_s cn61xx;
        struct cvmx_pciercx_cfg458_s cn63xx;
        struct cvmx_pciercx_cfg458_s cn63xxp1;
+       struct cvmx_pciercx_cfg458_s cn66xx;
+       struct cvmx_pciercx_cfg458_s cn68xx;
+       struct cvmx_pciercx_cfg458_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg459 {
@@ -1264,8 +1667,12 @@ union cvmx_pciercx_cfg459 {
        struct cvmx_pciercx_cfg459_s cn52xxp1;
        struct cvmx_pciercx_cfg459_s cn56xx;
        struct cvmx_pciercx_cfg459_s cn56xxp1;
+       struct cvmx_pciercx_cfg459_s cn61xx;
        struct cvmx_pciercx_cfg459_s cn63xx;
        struct cvmx_pciercx_cfg459_s cn63xxp1;
+       struct cvmx_pciercx_cfg459_s cn66xx;
+       struct cvmx_pciercx_cfg459_s cn68xx;
+       struct cvmx_pciercx_cfg459_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg460 {
@@ -1279,8 +1686,12 @@ union cvmx_pciercx_cfg460 {
        struct cvmx_pciercx_cfg460_s cn52xxp1;
        struct cvmx_pciercx_cfg460_s cn56xx;
        struct cvmx_pciercx_cfg460_s cn56xxp1;
+       struct cvmx_pciercx_cfg460_s cn61xx;
        struct cvmx_pciercx_cfg460_s cn63xx;
        struct cvmx_pciercx_cfg460_s cn63xxp1;
+       struct cvmx_pciercx_cfg460_s cn66xx;
+       struct cvmx_pciercx_cfg460_s cn68xx;
+       struct cvmx_pciercx_cfg460_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg461 {
@@ -1294,8 +1705,12 @@ union cvmx_pciercx_cfg461 {
        struct cvmx_pciercx_cfg461_s cn52xxp1;
        struct cvmx_pciercx_cfg461_s cn56xx;
        struct cvmx_pciercx_cfg461_s cn56xxp1;
+       struct cvmx_pciercx_cfg461_s cn61xx;
        struct cvmx_pciercx_cfg461_s cn63xx;
        struct cvmx_pciercx_cfg461_s cn63xxp1;
+       struct cvmx_pciercx_cfg461_s cn66xx;
+       struct cvmx_pciercx_cfg461_s cn68xx;
+       struct cvmx_pciercx_cfg461_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg462 {
@@ -1309,8 +1724,12 @@ union cvmx_pciercx_cfg462 {
        struct cvmx_pciercx_cfg462_s cn52xxp1;
        struct cvmx_pciercx_cfg462_s cn56xx;
        struct cvmx_pciercx_cfg462_s cn56xxp1;
+       struct cvmx_pciercx_cfg462_s cn61xx;
        struct cvmx_pciercx_cfg462_s cn63xx;
        struct cvmx_pciercx_cfg462_s cn63xxp1;
+       struct cvmx_pciercx_cfg462_s cn66xx;
+       struct cvmx_pciercx_cfg462_s cn68xx;
+       struct cvmx_pciercx_cfg462_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg463 {
@@ -1325,8 +1744,12 @@ union cvmx_pciercx_cfg463 {
        struct cvmx_pciercx_cfg463_s cn52xxp1;
        struct cvmx_pciercx_cfg463_s cn56xx;
        struct cvmx_pciercx_cfg463_s cn56xxp1;
+       struct cvmx_pciercx_cfg463_s cn61xx;
        struct cvmx_pciercx_cfg463_s cn63xx;
        struct cvmx_pciercx_cfg463_s cn63xxp1;
+       struct cvmx_pciercx_cfg463_s cn66xx;
+       struct cvmx_pciercx_cfg463_s cn68xx;
+       struct cvmx_pciercx_cfg463_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg464 {
@@ -1341,8 +1764,12 @@ union cvmx_pciercx_cfg464 {
        struct cvmx_pciercx_cfg464_s cn52xxp1;
        struct cvmx_pciercx_cfg464_s cn56xx;
        struct cvmx_pciercx_cfg464_s cn56xxp1;
+       struct cvmx_pciercx_cfg464_s cn61xx;
        struct cvmx_pciercx_cfg464_s cn63xx;
        struct cvmx_pciercx_cfg464_s cn63xxp1;
+       struct cvmx_pciercx_cfg464_s cn66xx;
+       struct cvmx_pciercx_cfg464_s cn68xx;
+       struct cvmx_pciercx_cfg464_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg465 {
@@ -1357,8 +1784,12 @@ union cvmx_pciercx_cfg465 {
        struct cvmx_pciercx_cfg465_s cn52xxp1;
        struct cvmx_pciercx_cfg465_s cn56xx;
        struct cvmx_pciercx_cfg465_s cn56xxp1;
+       struct cvmx_pciercx_cfg465_s cn61xx;
        struct cvmx_pciercx_cfg465_s cn63xx;
        struct cvmx_pciercx_cfg465_s cn63xxp1;
+       struct cvmx_pciercx_cfg465_s cn66xx;
+       struct cvmx_pciercx_cfg465_s cn68xx;
+       struct cvmx_pciercx_cfg465_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg466 {
@@ -1376,8 +1807,12 @@ union cvmx_pciercx_cfg466 {
        struct cvmx_pciercx_cfg466_s cn52xxp1;
        struct cvmx_pciercx_cfg466_s cn56xx;
        struct cvmx_pciercx_cfg466_s cn56xxp1;
+       struct cvmx_pciercx_cfg466_s cn61xx;
        struct cvmx_pciercx_cfg466_s cn63xx;
        struct cvmx_pciercx_cfg466_s cn63xxp1;
+       struct cvmx_pciercx_cfg466_s cn66xx;
+       struct cvmx_pciercx_cfg466_s cn68xx;
+       struct cvmx_pciercx_cfg466_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg467 {
@@ -1393,8 +1828,12 @@ union cvmx_pciercx_cfg467 {
        struct cvmx_pciercx_cfg467_s cn52xxp1;
        struct cvmx_pciercx_cfg467_s cn56xx;
        struct cvmx_pciercx_cfg467_s cn56xxp1;
+       struct cvmx_pciercx_cfg467_s cn61xx;
        struct cvmx_pciercx_cfg467_s cn63xx;
        struct cvmx_pciercx_cfg467_s cn63xxp1;
+       struct cvmx_pciercx_cfg467_s cn66xx;
+       struct cvmx_pciercx_cfg467_s cn68xx;
+       struct cvmx_pciercx_cfg467_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg468 {
@@ -1410,8 +1849,12 @@ union cvmx_pciercx_cfg468 {
        struct cvmx_pciercx_cfg468_s cn52xxp1;
        struct cvmx_pciercx_cfg468_s cn56xx;
        struct cvmx_pciercx_cfg468_s cn56xxp1;
+       struct cvmx_pciercx_cfg468_s cn61xx;
        struct cvmx_pciercx_cfg468_s cn63xx;
        struct cvmx_pciercx_cfg468_s cn63xxp1;
+       struct cvmx_pciercx_cfg468_s cn66xx;
+       struct cvmx_pciercx_cfg468_s cn68xx;
+       struct cvmx_pciercx_cfg468_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg490 {
@@ -1426,8 +1869,12 @@ union cvmx_pciercx_cfg490 {
        struct cvmx_pciercx_cfg490_s cn52xxp1;
        struct cvmx_pciercx_cfg490_s cn56xx;
        struct cvmx_pciercx_cfg490_s cn56xxp1;
+       struct cvmx_pciercx_cfg490_s cn61xx;
        struct cvmx_pciercx_cfg490_s cn63xx;
        struct cvmx_pciercx_cfg490_s cn63xxp1;
+       struct cvmx_pciercx_cfg490_s cn66xx;
+       struct cvmx_pciercx_cfg490_s cn68xx;
+       struct cvmx_pciercx_cfg490_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg491 {
@@ -1442,8 +1889,12 @@ union cvmx_pciercx_cfg491 {
        struct cvmx_pciercx_cfg491_s cn52xxp1;
        struct cvmx_pciercx_cfg491_s cn56xx;
        struct cvmx_pciercx_cfg491_s cn56xxp1;
+       struct cvmx_pciercx_cfg491_s cn61xx;
        struct cvmx_pciercx_cfg491_s cn63xx;
        struct cvmx_pciercx_cfg491_s cn63xxp1;
+       struct cvmx_pciercx_cfg491_s cn66xx;
+       struct cvmx_pciercx_cfg491_s cn68xx;
+       struct cvmx_pciercx_cfg491_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg492 {
@@ -1458,8 +1909,12 @@ union cvmx_pciercx_cfg492 {
        struct cvmx_pciercx_cfg492_s cn52xxp1;
        struct cvmx_pciercx_cfg492_s cn56xx;
        struct cvmx_pciercx_cfg492_s cn56xxp1;
+       struct cvmx_pciercx_cfg492_s cn61xx;
        struct cvmx_pciercx_cfg492_s cn63xx;
        struct cvmx_pciercx_cfg492_s cn63xxp1;
+       struct cvmx_pciercx_cfg492_s cn66xx;
+       struct cvmx_pciercx_cfg492_s cn68xx;
+       struct cvmx_pciercx_cfg492_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg515 {
@@ -1473,8 +1928,12 @@ union cvmx_pciercx_cfg515 {
                uint32_t le:9;
                uint32_t n_fts:8;
        } s;
+       struct cvmx_pciercx_cfg515_s cn61xx;
        struct cvmx_pciercx_cfg515_s cn63xx;
        struct cvmx_pciercx_cfg515_s cn63xxp1;
+       struct cvmx_pciercx_cfg515_s cn66xx;
+       struct cvmx_pciercx_cfg515_s cn68xx;
+       struct cvmx_pciercx_cfg515_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg516 {
@@ -1486,8 +1945,12 @@ union cvmx_pciercx_cfg516 {
        struct cvmx_pciercx_cfg516_s cn52xxp1;
        struct cvmx_pciercx_cfg516_s cn56xx;
        struct cvmx_pciercx_cfg516_s cn56xxp1;
+       struct cvmx_pciercx_cfg516_s cn61xx;
        struct cvmx_pciercx_cfg516_s cn63xx;
        struct cvmx_pciercx_cfg516_s cn63xxp1;
+       struct cvmx_pciercx_cfg516_s cn66xx;
+       struct cvmx_pciercx_cfg516_s cn68xx;
+       struct cvmx_pciercx_cfg516_s cn68xxp1;
 };
 
 union cvmx_pciercx_cfg517 {
@@ -1499,8 +1962,12 @@ union cvmx_pciercx_cfg517 {
        struct cvmx_pciercx_cfg517_s cn52xxp1;
        struct cvmx_pciercx_cfg517_s cn56xx;
        struct cvmx_pciercx_cfg517_s cn56xxp1;
+       struct cvmx_pciercx_cfg517_s cn61xx;
        struct cvmx_pciercx_cfg517_s cn63xx;
        struct cvmx_pciercx_cfg517_s cn63xxp1;
+       struct cvmx_pciercx_cfg517_s cn66xx;
+       struct cvmx_pciercx_cfg517_s cn68xx;
+       struct cvmx_pciercx_cfg517_s cn68xxp1;
 };
 
 #endif
diff --git a/arch/mips/include/asm/octeon/cvmx-pemx-defs.h b/arch/mips/include/asm/octeon/cvmx-pemx-defs.h
new file mode 100644 (file)
index 0000000..be189a2
--- /dev/null
@@ -0,0 +1,509 @@
+/***********************license start***************
+ * Author: Cavium Networks
+ *
+ * Contact: support@caviumnetworks.com
+ * This file is part of the OCTEON SDK
+ *
+ * Copyright (c) 2003-2011 Cavium Networks
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * or visit http://www.gnu.org/licenses/.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium Networks for more information
+ ***********************license end**************************************/
+
+#ifndef __CVMX_PEMX_DEFS_H__
+#define __CVMX_PEMX_DEFS_H__
+
+#define CVMX_PEMX_BAR1_INDEXX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C00000A8ull) + (((offset) & 15) + ((block_id) & 1) * 0x200000ull) * 8)
+#define CVMX_PEMX_BAR2_MASK(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000130ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_BAR_CTL(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000128ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_BIST_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000018ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_BIST_STATUS2(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000420ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_CFG_RD(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000030ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_CFG_WR(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000028ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_CPL_LUT_VALID(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000098ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_CTL_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000000ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_DBG_INFO(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000008ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_DBG_INFO_EN(block_id) (CVMX_ADD_IO_SEG(0x00011800C00000A0ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_DIAG_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000020ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_INB_READ_CREDITS(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000138ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_INT_ENB(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000410ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_INT_ENB_INT(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000418ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_INT_SUM(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000408ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_P2N_BAR0_START(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000080ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_P2N_BAR1_START(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000088ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_P2N_BAR2_START(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000090ull) + ((block_id) & 1) * 0x1000000ull)
+#define CVMX_PEMX_P2P_BARX_END(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C0000048ull) + (((offset) & 3) + ((block_id) & 1) * 0x100000ull) * 16)
+#define CVMX_PEMX_P2P_BARX_START(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C0000040ull) + (((offset) & 3) + ((block_id) & 1) * 0x100000ull) * 16)
+#define CVMX_PEMX_TLP_CREDITS(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000038ull) + ((block_id) & 1) * 0x1000000ull)
+
+union cvmx_pemx_bar1_indexx {
+       uint64_t u64;
+       struct cvmx_pemx_bar1_indexx_s {
+               uint64_t reserved_20_63:44;
+               uint64_t addr_idx:16;
+               uint64_t ca:1;
+               uint64_t end_swp:2;
+               uint64_t addr_v:1;
+       } s;
+       struct cvmx_pemx_bar1_indexx_s cn61xx;
+       struct cvmx_pemx_bar1_indexx_s cn63xx;
+       struct cvmx_pemx_bar1_indexx_s cn63xxp1;
+       struct cvmx_pemx_bar1_indexx_s cn66xx;
+       struct cvmx_pemx_bar1_indexx_s cn68xx;
+       struct cvmx_pemx_bar1_indexx_s cn68xxp1;
+};
+
+union cvmx_pemx_bar2_mask {
+       uint64_t u64;
+       struct cvmx_pemx_bar2_mask_s {
+               uint64_t reserved_38_63:26;
+               uint64_t mask:35;
+               uint64_t reserved_0_2:3;
+       } s;
+       struct cvmx_pemx_bar2_mask_s cn61xx;
+       struct cvmx_pemx_bar2_mask_s cn66xx;
+       struct cvmx_pemx_bar2_mask_s cn68xx;
+       struct cvmx_pemx_bar2_mask_s cn68xxp1;
+};
+
+union cvmx_pemx_bar_ctl {
+       uint64_t u64;
+       struct cvmx_pemx_bar_ctl_s {
+               uint64_t reserved_7_63:57;
+               uint64_t bar1_siz:3;
+               uint64_t bar2_enb:1;
+               uint64_t bar2_esx:2;
+               uint64_t bar2_cax:1;
+       } s;
+       struct cvmx_pemx_bar_ctl_s cn61xx;
+       struct cvmx_pemx_bar_ctl_s cn63xx;
+       struct cvmx_pemx_bar_ctl_s cn63xxp1;
+       struct cvmx_pemx_bar_ctl_s cn66xx;
+       struct cvmx_pemx_bar_ctl_s cn68xx;
+       struct cvmx_pemx_bar_ctl_s cn68xxp1;
+};
+
+union cvmx_pemx_bist_status {
+       uint64_t u64;
+       struct cvmx_pemx_bist_status_s {
+               uint64_t reserved_8_63:56;
+               uint64_t retry:1;
+               uint64_t rqdata0:1;
+               uint64_t rqdata1:1;
+               uint64_t rqdata2:1;
+               uint64_t rqdata3:1;
+               uint64_t rqhdr1:1;
+               uint64_t rqhdr0:1;
+               uint64_t sot:1;
+       } s;
+       struct cvmx_pemx_bist_status_s cn61xx;
+       struct cvmx_pemx_bist_status_s cn63xx;
+       struct cvmx_pemx_bist_status_s cn63xxp1;
+       struct cvmx_pemx_bist_status_s cn66xx;
+       struct cvmx_pemx_bist_status_s cn68xx;
+       struct cvmx_pemx_bist_status_s cn68xxp1;
+};
+
+union cvmx_pemx_bist_status2 {
+       uint64_t u64;
+       struct cvmx_pemx_bist_status2_s {
+               uint64_t reserved_10_63:54;
+               uint64_t e2p_cpl:1;
+               uint64_t e2p_n:1;
+               uint64_t e2p_p:1;
+               uint64_t peai_p2e:1;
+               uint64_t pef_tpf1:1;
+               uint64_t pef_tpf0:1;
+               uint64_t pef_tnf:1;
+               uint64_t pef_tcf1:1;
+               uint64_t pef_tc0:1;
+               uint64_t ppf:1;
+       } s;
+       struct cvmx_pemx_bist_status2_s cn61xx;
+       struct cvmx_pemx_bist_status2_s cn63xx;
+       struct cvmx_pemx_bist_status2_s cn63xxp1;
+       struct cvmx_pemx_bist_status2_s cn66xx;
+       struct cvmx_pemx_bist_status2_s cn68xx;
+       struct cvmx_pemx_bist_status2_s cn68xxp1;
+};
+
+union cvmx_pemx_cfg_rd {
+       uint64_t u64;
+       struct cvmx_pemx_cfg_rd_s {
+               uint64_t data:32;
+               uint64_t addr:32;
+       } s;
+       struct cvmx_pemx_cfg_rd_s cn61xx;
+       struct cvmx_pemx_cfg_rd_s cn63xx;
+       struct cvmx_pemx_cfg_rd_s cn63xxp1;
+       struct cvmx_pemx_cfg_rd_s cn66xx;
+       struct cvmx_pemx_cfg_rd_s cn68xx;
+       struct cvmx_pemx_cfg_rd_s cn68xxp1;
+};
+
+union cvmx_pemx_cfg_wr {
+       uint64_t u64;
+       struct cvmx_pemx_cfg_wr_s {
+               uint64_t data:32;
+               uint64_t addr:32;
+       } s;
+       struct cvmx_pemx_cfg_wr_s cn61xx;
+       struct cvmx_pemx_cfg_wr_s cn63xx;
+       struct cvmx_pemx_cfg_wr_s cn63xxp1;
+       struct cvmx_pemx_cfg_wr_s cn66xx;
+       struct cvmx_pemx_cfg_wr_s cn68xx;
+       struct cvmx_pemx_cfg_wr_s cn68xxp1;
+};
+
+union cvmx_pemx_cpl_lut_valid {
+       uint64_t u64;
+       struct cvmx_pemx_cpl_lut_valid_s {
+               uint64_t reserved_32_63:32;
+               uint64_t tag:32;
+       } s;
+       struct cvmx_pemx_cpl_lut_valid_s cn61xx;
+       struct cvmx_pemx_cpl_lut_valid_s cn63xx;
+       struct cvmx_pemx_cpl_lut_valid_s cn63xxp1;
+       struct cvmx_pemx_cpl_lut_valid_s cn66xx;
+       struct cvmx_pemx_cpl_lut_valid_s cn68xx;
+       struct cvmx_pemx_cpl_lut_valid_s cn68xxp1;
+};
+
+union cvmx_pemx_ctl_status {
+       uint64_t u64;
+       struct cvmx_pemx_ctl_status_s {
+               uint64_t reserved_48_63:16;
+               uint64_t auto_sd:1;
+               uint64_t dnum:5;
+               uint64_t pbus:8;
+               uint64_t reserved_32_33:2;
+               uint64_t cfg_rtry:16;
+               uint64_t reserved_12_15:4;
+               uint64_t pm_xtoff:1;
+               uint64_t pm_xpme:1;
+               uint64_t ob_p_cmd:1;
+               uint64_t reserved_7_8:2;
+               uint64_t nf_ecrc:1;
+               uint64_t dly_one:1;
+               uint64_t lnk_enb:1;
+               uint64_t ro_ctlp:1;
+               uint64_t fast_lm:1;
+               uint64_t inv_ecrc:1;
+               uint64_t inv_lcrc:1;
+       } s;
+       struct cvmx_pemx_ctl_status_s cn61xx;
+       struct cvmx_pemx_ctl_status_s cn63xx;
+       struct cvmx_pemx_ctl_status_s cn63xxp1;
+       struct cvmx_pemx_ctl_status_s cn66xx;
+       struct cvmx_pemx_ctl_status_s cn68xx;
+       struct cvmx_pemx_ctl_status_s cn68xxp1;
+};
+
+union cvmx_pemx_dbg_info {
+       uint64_t u64;
+       struct cvmx_pemx_dbg_info_s {
+               uint64_t reserved_31_63:33;
+               uint64_t ecrc_e:1;
+               uint64_t rawwpp:1;
+               uint64_t racpp:1;
+               uint64_t ramtlp:1;
+               uint64_t rarwdns:1;
+               uint64_t caar:1;
+               uint64_t racca:1;
+               uint64_t racur:1;
+               uint64_t rauc:1;
+               uint64_t rqo:1;
+               uint64_t fcuv:1;
+               uint64_t rpe:1;
+               uint64_t fcpvwt:1;
+               uint64_t dpeoosd:1;
+               uint64_t rtwdle:1;
+               uint64_t rdwdle:1;
+               uint64_t mre:1;
+               uint64_t rte:1;
+               uint64_t acto:1;
+               uint64_t rvdm:1;
+               uint64_t rumep:1;
+               uint64_t rptamrc:1;
+               uint64_t rpmerc:1;
+               uint64_t rfemrc:1;
+               uint64_t rnfemrc:1;
+               uint64_t rcemrc:1;
+               uint64_t rpoison:1;
+               uint64_t recrce:1;
+               uint64_t rtlplle:1;
+               uint64_t rtlpmal:1;
+               uint64_t spoison:1;
+       } s;
+       struct cvmx_pemx_dbg_info_s cn61xx;
+       struct cvmx_pemx_dbg_info_s cn63xx;
+       struct cvmx_pemx_dbg_info_s cn63xxp1;
+       struct cvmx_pemx_dbg_info_s cn66xx;
+       struct cvmx_pemx_dbg_info_s cn68xx;
+       struct cvmx_pemx_dbg_info_s cn68xxp1;
+};
+
+union cvmx_pemx_dbg_info_en {
+       uint64_t u64;
+       struct cvmx_pemx_dbg_info_en_s {
+               uint64_t reserved_31_63:33;
+               uint64_t ecrc_e:1;
+               uint64_t rawwpp:1;
+               uint64_t racpp:1;
+               uint64_t ramtlp:1;
+               uint64_t rarwdns:1;
+               uint64_t caar:1;
+               uint64_t racca:1;
+               uint64_t racur:1;
+               uint64_t rauc:1;
+               uint64_t rqo:1;
+               uint64_t fcuv:1;
+               uint64_t rpe:1;
+               uint64_t fcpvwt:1;
+               uint64_t dpeoosd:1;
+               uint64_t rtwdle:1;
+               uint64_t rdwdle:1;
+               uint64_t mre:1;
+               uint64_t rte:1;
+               uint64_t acto:1;
+               uint64_t rvdm:1;
+               uint64_t rumep:1;
+               uint64_t rptamrc:1;
+               uint64_t rpmerc:1;
+               uint64_t rfemrc:1;
+               uint64_t rnfemrc:1;
+               uint64_t rcemrc:1;
+               uint64_t rpoison:1;
+               uint64_t recrce:1;
+               uint64_t rtlplle:1;
+               uint64_t rtlpmal:1;
+               uint64_t spoison:1;
+       } s;
+       struct cvmx_pemx_dbg_info_en_s cn61xx;
+       struct cvmx_pemx_dbg_info_en_s cn63xx;
+       struct cvmx_pemx_dbg_info_en_s cn63xxp1;
+       struct cvmx_pemx_dbg_info_en_s cn66xx;
+       struct cvmx_pemx_dbg_info_en_s cn68xx;
+       struct cvmx_pemx_dbg_info_en_s cn68xxp1;
+};
+
+union cvmx_pemx_diag_status {
+       uint64_t u64;
+       struct cvmx_pemx_diag_status_s {
+               uint64_t reserved_4_63:60;
+               uint64_t pm_dst:1;
+               uint64_t pm_stat:1;
+               uint64_t pm_en:1;
+               uint64_t aux_en:1;
+       } s;
+       struct cvmx_pemx_diag_status_s cn61xx;
+       struct cvmx_pemx_diag_status_s cn63xx;
+       struct cvmx_pemx_diag_status_s cn63xxp1;
+       struct cvmx_pemx_diag_status_s cn66xx;
+       struct cvmx_pemx_diag_status_s cn68xx;
+       struct cvmx_pemx_diag_status_s cn68xxp1;
+};
+
+union cvmx_pemx_inb_read_credits {
+       uint64_t u64;
+       struct cvmx_pemx_inb_read_credits_s {
+               uint64_t reserved_6_63:58;
+               uint64_t num:6;
+       } s;
+       struct cvmx_pemx_inb_read_credits_s cn61xx;
+       struct cvmx_pemx_inb_read_credits_s cn66xx;
+       struct cvmx_pemx_inb_read_credits_s cn68xx;
+};
+
+union cvmx_pemx_int_enb {
+       uint64_t u64;
+       struct cvmx_pemx_int_enb_s {
+               uint64_t reserved_14_63:50;
+               uint64_t crs_dr:1;
+               uint64_t crs_er:1;
+               uint64_t rdlk:1;
+               uint64_t exc:1;
+               uint64_t un_bx:1;
+               uint64_t un_b2:1;
+               uint64_t un_b1:1;
+               uint64_t up_bx:1;
+               uint64_t up_b2:1;
+               uint64_t up_b1:1;
+               uint64_t pmem:1;
+               uint64_t pmei:1;
+               uint64_t se:1;
+               uint64_t aeri:1;
+       } s;
+       struct cvmx_pemx_int_enb_s cn61xx;
+       struct cvmx_pemx_int_enb_s cn63xx;
+       struct cvmx_pemx_int_enb_s cn63xxp1;
+       struct cvmx_pemx_int_enb_s cn66xx;
+       struct cvmx_pemx_int_enb_s cn68xx;
+       struct cvmx_pemx_int_enb_s cn68xxp1;
+};
+
+union cvmx_pemx_int_enb_int {
+       uint64_t u64;
+       struct cvmx_pemx_int_enb_int_s {
+               uint64_t reserved_14_63:50;
+               uint64_t crs_dr:1;
+               uint64_t crs_er:1;
+               uint64_t rdlk:1;
+               uint64_t exc:1;
+               uint64_t un_bx:1;
+               uint64_t un_b2:1;
+               uint64_t un_b1:1;
+               uint64_t up_bx:1;
+               uint64_t up_b2:1;
+               uint64_t up_b1:1;
+               uint64_t pmem:1;
+               uint64_t pmei:1;
+               uint64_t se:1;
+               uint64_t aeri:1;
+       } s;
+       struct cvmx_pemx_int_enb_int_s cn61xx;
+       struct cvmx_pemx_int_enb_int_s cn63xx;
+       struct cvmx_pemx_int_enb_int_s cn63xxp1;
+       struct cvmx_pemx_int_enb_int_s cn66xx;
+       struct cvmx_pemx_int_enb_int_s cn68xx;
+       struct cvmx_pemx_int_enb_int_s cn68xxp1;
+};
+
+union cvmx_pemx_int_sum {
+       uint64_t u64;
+       struct cvmx_pemx_int_sum_s {
+               uint64_t reserved_14_63:50;
+               uint64_t crs_dr:1;
+               uint64_t crs_er:1;
+               uint64_t rdlk:1;
+               uint64_t exc:1;
+               uint64_t un_bx:1;
+               uint64_t un_b2:1;
+               uint64_t un_b1:1;
+               uint64_t up_bx:1;
+               uint64_t up_b2:1;
+               uint64_t up_b1:1;
+               uint64_t pmem:1;
+               uint64_t pmei:1;
+               uint64_t se:1;
+               uint64_t aeri:1;
+       } s;
+       struct cvmx_pemx_int_sum_s cn61xx;
+       struct cvmx_pemx_int_sum_s cn63xx;
+       struct cvmx_pemx_int_sum_s cn63xxp1;
+       struct cvmx_pemx_int_sum_s cn66xx;
+       struct cvmx_pemx_int_sum_s cn68xx;
+       struct cvmx_pemx_int_sum_s cn68xxp1;
+};
+
+union cvmx_pemx_p2n_bar0_start {
+       uint64_t u64;
+       struct cvmx_pemx_p2n_bar0_start_s {
+               uint64_t addr:50;
+               uint64_t reserved_0_13:14;
+       } s;
+       struct cvmx_pemx_p2n_bar0_start_s cn61xx;
+       struct cvmx_pemx_p2n_bar0_start_s cn63xx;
+       struct cvmx_pemx_p2n_bar0_start_s cn63xxp1;
+       struct cvmx_pemx_p2n_bar0_start_s cn66xx;
+       struct cvmx_pemx_p2n_bar0_start_s cn68xx;
+       struct cvmx_pemx_p2n_bar0_start_s cn68xxp1;
+};
+
+union cvmx_pemx_p2n_bar1_start {
+       uint64_t u64;
+       struct cvmx_pemx_p2n_bar1_start_s {
+               uint64_t addr:38;
+               uint64_t reserved_0_25:26;
+       } s;
+       struct cvmx_pemx_p2n_bar1_start_s cn61xx;
+       struct cvmx_pemx_p2n_bar1_start_s cn63xx;
+       struct cvmx_pemx_p2n_bar1_start_s cn63xxp1;
+       struct cvmx_pemx_p2n_bar1_start_s cn66xx;
+       struct cvmx_pemx_p2n_bar1_start_s cn68xx;
+       struct cvmx_pemx_p2n_bar1_start_s cn68xxp1;
+};
+
+union cvmx_pemx_p2n_bar2_start {
+       uint64_t u64;
+       struct cvmx_pemx_p2n_bar2_start_s {
+               uint64_t addr:23;
+               uint64_t reserved_0_40:41;
+       } s;
+       struct cvmx_pemx_p2n_bar2_start_s cn61xx;
+       struct cvmx_pemx_p2n_bar2_start_s cn63xx;
+       struct cvmx_pemx_p2n_bar2_start_s cn63xxp1;
+       struct cvmx_pemx_p2n_bar2_start_s cn66xx;
+       struct cvmx_pemx_p2n_bar2_start_s cn68xx;
+       struct cvmx_pemx_p2n_bar2_start_s cn68xxp1;
+};
+
+union cvmx_pemx_p2p_barx_end {
+       uint64_t u64;
+       struct cvmx_pemx_p2p_barx_end_s {
+               uint64_t addr:52;
+               uint64_t reserved_0_11:12;
+       } s;
+       struct cvmx_pemx_p2p_barx_end_s cn63xx;
+       struct cvmx_pemx_p2p_barx_end_s cn63xxp1;
+       struct cvmx_pemx_p2p_barx_end_s cn66xx;
+       struct cvmx_pemx_p2p_barx_end_s cn68xx;
+       struct cvmx_pemx_p2p_barx_end_s cn68xxp1;
+};
+
+union cvmx_pemx_p2p_barx_start {
+       uint64_t u64;
+       struct cvmx_pemx_p2p_barx_start_s {
+               uint64_t addr:52;
+               uint64_t reserved_0_11:12;
+       } s;
+       struct cvmx_pemx_p2p_barx_start_s cn63xx;
+       struct cvmx_pemx_p2p_barx_start_s cn63xxp1;
+       struct cvmx_pemx_p2p_barx_start_s cn66xx;
+       struct cvmx_pemx_p2p_barx_start_s cn68xx;
+       struct cvmx_pemx_p2p_barx_start_s cn68xxp1;
+};
+
+union cvmx_pemx_tlp_credits {
+       uint64_t u64;
+       struct cvmx_pemx_tlp_credits_s {
+               uint64_t reserved_56_63:8;
+               uint64_t peai_ppf:8;
+               uint64_t pem_cpl:8;
+               uint64_t pem_np:8;
+               uint64_t pem_p:8;
+               uint64_t sli_cpl:8;
+               uint64_t sli_np:8;
+               uint64_t sli_p:8;
+       } s;
+       struct cvmx_pemx_tlp_credits_cn61xx {
+               uint64_t reserved_56_63:8;
+               uint64_t peai_ppf:8;
+               uint64_t reserved_24_47:24;
+               uint64_t sli_cpl:8;
+               uint64_t sli_np:8;
+               uint64_t sli_p:8;
+       } cn61xx;
+       struct cvmx_pemx_tlp_credits_s cn63xx;
+       struct cvmx_pemx_tlp_credits_s cn63xxp1;
+       struct cvmx_pemx_tlp_credits_s cn66xx;
+       struct cvmx_pemx_tlp_credits_s cn68xx;
+       struct cvmx_pemx_tlp_credits_s cn68xxp1;
+};
+
+#endif
index 5ab8679d89af0698d55d54441eb96910bb6752ec..4438d211988bfe5874a9f88b1eccc3ddfa3f5954 100644 (file)
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2010 Cavium Networks
+ * Copyright (c) 2003-2011 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
  * Contact Cavium Networks for more information
  ***********************license end**************************************/
 
-/**
- * cvmx-pexp-defs.h
- *
- * Configuration and status register (CSR) definitions for
- * OCTEON PEXP.
- *
- */
 #ifndef __CVMX_PEXP_DEFS_H__
 #define __CVMX_PEXP_DEFS_H__
 
 #define CVMX_PEXP_NPEI_STATE3 (CVMX_ADD_IO_SEG(0x00011F0000008640ull))
 #define CVMX_PEXP_NPEI_WINDOW_CTL (CVMX_ADD_IO_SEG(0x00011F0000008380ull))
 #define CVMX_PEXP_SLI_BIST_STATUS (CVMX_ADD_IO_SEG(0x00011F0000010580ull))
-#define CVMX_PEXP_SLI_CTL_PORTX(offset) (CVMX_ADD_IO_SEG(0x00011F0000010050ull) + ((offset) & 1) * 16)
+#define CVMX_PEXP_SLI_CTL_PORTX(offset) (CVMX_ADD_IO_SEG(0x00011F0000010050ull) + ((offset) & 3) * 16)
 #define CVMX_PEXP_SLI_CTL_STATUS (CVMX_ADD_IO_SEG(0x00011F0000010570ull))
 #define CVMX_PEXP_SLI_DATA_OUT_CNT (CVMX_ADD_IO_SEG(0x00011F00000105F0ull))
 #define CVMX_PEXP_SLI_DBG_DATA (CVMX_ADD_IO_SEG(0x00011F0000010310ull))
 #define CVMX_PEXP_SLI_INT_SUM (CVMX_ADD_IO_SEG(0x00011F0000010330ull))
 #define CVMX_PEXP_SLI_LAST_WIN_RDATA0 (CVMX_ADD_IO_SEG(0x00011F0000010600ull))
 #define CVMX_PEXP_SLI_LAST_WIN_RDATA1 (CVMX_ADD_IO_SEG(0x00011F0000010610ull))
+#define CVMX_PEXP_SLI_LAST_WIN_RDATA2 (CVMX_ADD_IO_SEG(0x00011F00000106C0ull))
+#define CVMX_PEXP_SLI_LAST_WIN_RDATA3 (CVMX_ADD_IO_SEG(0x00011F00000106D0ull))
 #define CVMX_PEXP_SLI_MAC_CREDIT_CNT (CVMX_ADD_IO_SEG(0x00011F0000013D70ull))
+#define CVMX_PEXP_SLI_MAC_CREDIT_CNT2 (CVMX_ADD_IO_SEG(0x00011F0000013E10ull))
 #define CVMX_PEXP_SLI_MEM_ACCESS_CTL (CVMX_ADD_IO_SEG(0x00011F00000102F0ull))
 #define CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(offset) (CVMX_ADD_IO_SEG(0x00011F00000100E0ull) + ((offset) & 31) * 16 - 16*12)
 #define CVMX_PEXP_SLI_MSI_ENB0 (CVMX_ADD_IO_SEG(0x00011F0000013C50ull))
 #define CVMX_PEXP_SLI_PKT_IPTR (CVMX_ADD_IO_SEG(0x00011F0000011070ull))
 #define CVMX_PEXP_SLI_PKT_OUTPUT_WMARK (CVMX_ADD_IO_SEG(0x00011F0000011180ull))
 #define CVMX_PEXP_SLI_PKT_OUT_BMODE (CVMX_ADD_IO_SEG(0x00011F00000110D0ull))
+#define CVMX_PEXP_SLI_PKT_OUT_BP_EN (CVMX_ADD_IO_SEG(0x00011F0000011240ull))
 #define CVMX_PEXP_SLI_PKT_OUT_ENB (CVMX_ADD_IO_SEG(0x00011F0000011010ull))
 #define CVMX_PEXP_SLI_PKT_PCIE_PORT (CVMX_ADD_IO_SEG(0x00011F00000110E0ull))
 #define CVMX_PEXP_SLI_PKT_PORT_IN_RST (CVMX_ADD_IO_SEG(0x00011F00000111F0ull))
 #define CVMX_PEXP_SLI_PKT_SLIST_ROR (CVMX_ADD_IO_SEG(0x00011F0000011030ull))
 #define CVMX_PEXP_SLI_PKT_TIME_INT (CVMX_ADD_IO_SEG(0x00011F0000011140ull))
 #define CVMX_PEXP_SLI_PKT_TIME_INT_ENB (CVMX_ADD_IO_SEG(0x00011F0000011160ull))
-#define CVMX_PEXP_SLI_S2M_PORTX_CTL(offset) (CVMX_ADD_IO_SEG(0x00011F0000013D80ull) + ((offset) & 1) * 16)
+#define CVMX_PEXP_SLI_PORTX_PKIND(offset) (CVMX_ADD_IO_SEG(0x00011F0000010800ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_SLI_S2M_PORTX_CTL(offset) (CVMX_ADD_IO_SEG(0x00011F0000013D80ull) + ((offset) & 3) * 16)
 #define CVMX_PEXP_SLI_SCRATCH_1 (CVMX_ADD_IO_SEG(0x00011F00000103C0ull))
 #define CVMX_PEXP_SLI_SCRATCH_2 (CVMX_ADD_IO_SEG(0x00011F00000103D0ull))
 #define CVMX_PEXP_SLI_STATE1 (CVMX_ADD_IO_SEG(0x00011F0000010620ull))
 #define CVMX_PEXP_SLI_STATE2 (CVMX_ADD_IO_SEG(0x00011F0000010630ull))
 #define CVMX_PEXP_SLI_STATE3 (CVMX_ADD_IO_SEG(0x00011F0000010640ull))
+#define CVMX_PEXP_SLI_TX_PIPE (CVMX_ADD_IO_SEG(0x00011F0000011230ull))
 #define CVMX_PEXP_SLI_WINDOW_CTL (CVMX_ADD_IO_SEG(0x00011F00000102E0ull))
 
 #endif
diff --git a/arch/mips/include/asm/octeon/cvmx-sli-defs.h b/arch/mips/include/asm/octeon/cvmx-sli-defs.h
new file mode 100644 (file)
index 0000000..7c6c901
--- /dev/null
@@ -0,0 +1,2172 @@
+/***********************license start***************
+ * Author: Cavium Networks
+ *
+ * Contact: support@caviumnetworks.com
+ * This file is part of the OCTEON SDK
+ *
+ * Copyright (c) 2003-2011 Cavium Networks
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * or visit http://www.gnu.org/licenses/.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium Networks for more information
+ ***********************license end**************************************/
+
+#ifndef __CVMX_SLI_DEFS_H__
+#define __CVMX_SLI_DEFS_H__
+
+#define CVMX_SLI_BIST_STATUS (0x0000000000000580ull)
+#define CVMX_SLI_CTL_PORTX(offset) (0x0000000000000050ull + ((offset) & 3) * 16)
+#define CVMX_SLI_CTL_STATUS (0x0000000000000570ull)
+#define CVMX_SLI_DATA_OUT_CNT (0x00000000000005F0ull)
+#define CVMX_SLI_DBG_DATA (0x0000000000000310ull)
+#define CVMX_SLI_DBG_SELECT (0x0000000000000300ull)
+#define CVMX_SLI_DMAX_CNT(offset) (0x0000000000000400ull + ((offset) & 1) * 16)
+#define CVMX_SLI_DMAX_INT_LEVEL(offset) (0x00000000000003E0ull + ((offset) & 1) * 16)
+#define CVMX_SLI_DMAX_TIM(offset) (0x0000000000000420ull + ((offset) & 1) * 16)
+#define CVMX_SLI_INT_ENB_CIU (0x0000000000003CD0ull)
+#define CVMX_SLI_INT_ENB_PORTX(offset) (0x0000000000000340ull + ((offset) & 1) * 16)
+#define CVMX_SLI_INT_SUM (0x0000000000000330ull)
+#define CVMX_SLI_LAST_WIN_RDATA0 (0x0000000000000600ull)
+#define CVMX_SLI_LAST_WIN_RDATA1 (0x0000000000000610ull)
+#define CVMX_SLI_LAST_WIN_RDATA2 (0x00000000000006C0ull)
+#define CVMX_SLI_LAST_WIN_RDATA3 (0x00000000000006D0ull)
+#define CVMX_SLI_MAC_CREDIT_CNT (0x0000000000003D70ull)
+#define CVMX_SLI_MAC_CREDIT_CNT2 (0x0000000000003E10ull)
+#define CVMX_SLI_MAC_NUMBER (0x0000000000003E00ull)
+#define CVMX_SLI_MEM_ACCESS_CTL (0x00000000000002F0ull)
+#define CVMX_SLI_MEM_ACCESS_SUBIDX(offset) (0x00000000000000E0ull + ((offset) & 31) * 16 - 16*12)
+#define CVMX_SLI_MSI_ENB0 (0x0000000000003C50ull)
+#define CVMX_SLI_MSI_ENB1 (0x0000000000003C60ull)
+#define CVMX_SLI_MSI_ENB2 (0x0000000000003C70ull)
+#define CVMX_SLI_MSI_ENB3 (0x0000000000003C80ull)
+#define CVMX_SLI_MSI_RCV0 (0x0000000000003C10ull)
+#define CVMX_SLI_MSI_RCV1 (0x0000000000003C20ull)
+#define CVMX_SLI_MSI_RCV2 (0x0000000000003C30ull)
+#define CVMX_SLI_MSI_RCV3 (0x0000000000003C40ull)
+#define CVMX_SLI_MSI_RD_MAP (0x0000000000003CA0ull)
+#define CVMX_SLI_MSI_W1C_ENB0 (0x0000000000003CF0ull)
+#define CVMX_SLI_MSI_W1C_ENB1 (0x0000000000003D00ull)
+#define CVMX_SLI_MSI_W1C_ENB2 (0x0000000000003D10ull)
+#define CVMX_SLI_MSI_W1C_ENB3 (0x0000000000003D20ull)
+#define CVMX_SLI_MSI_W1S_ENB0 (0x0000000000003D30ull)
+#define CVMX_SLI_MSI_W1S_ENB1 (0x0000000000003D40ull)
+#define CVMX_SLI_MSI_W1S_ENB2 (0x0000000000003D50ull)
+#define CVMX_SLI_MSI_W1S_ENB3 (0x0000000000003D60ull)
+#define CVMX_SLI_MSI_WR_MAP (0x0000000000003C90ull)
+#define CVMX_SLI_PCIE_MSI_RCV (0x0000000000003CB0ull)
+#define CVMX_SLI_PCIE_MSI_RCV_B1 (0x0000000000000650ull)
+#define CVMX_SLI_PCIE_MSI_RCV_B2 (0x0000000000000660ull)
+#define CVMX_SLI_PCIE_MSI_RCV_B3 (0x0000000000000670ull)
+#define CVMX_SLI_PKTX_CNTS(offset) (0x0000000000002400ull + ((offset) & 31) * 16)
+#define CVMX_SLI_PKTX_INSTR_BADDR(offset) (0x0000000000002800ull + ((offset) & 31) * 16)
+#define CVMX_SLI_PKTX_INSTR_BAOFF_DBELL(offset) (0x0000000000002C00ull + ((offset) & 31) * 16)
+#define CVMX_SLI_PKTX_INSTR_FIFO_RSIZE(offset) (0x0000000000003000ull + ((offset) & 31) * 16)
+#define CVMX_SLI_PKTX_INSTR_HEADER(offset) (0x0000000000003400ull + ((offset) & 31) * 16)
+#define CVMX_SLI_PKTX_IN_BP(offset) (0x0000000000003800ull + ((offset) & 31) * 16)
+#define CVMX_SLI_PKTX_OUT_SIZE(offset) (0x0000000000000C00ull + ((offset) & 31) * 16)
+#define CVMX_SLI_PKTX_SLIST_BADDR(offset) (0x0000000000001400ull + ((offset) & 31) * 16)
+#define CVMX_SLI_PKTX_SLIST_BAOFF_DBELL(offset) (0x0000000000001800ull + ((offset) & 31) * 16)
+#define CVMX_SLI_PKTX_SLIST_FIFO_RSIZE(offset) (0x0000000000001C00ull + ((offset) & 31) * 16)
+#define CVMX_SLI_PKT_CNT_INT (0x0000000000001130ull)
+#define CVMX_SLI_PKT_CNT_INT_ENB (0x0000000000001150ull)
+#define CVMX_SLI_PKT_CTL (0x0000000000001220ull)
+#define CVMX_SLI_PKT_DATA_OUT_ES (0x00000000000010B0ull)
+#define CVMX_SLI_PKT_DATA_OUT_NS (0x00000000000010A0ull)
+#define CVMX_SLI_PKT_DATA_OUT_ROR (0x0000000000001090ull)
+#define CVMX_SLI_PKT_DPADDR (0x0000000000001080ull)
+#define CVMX_SLI_PKT_INPUT_CONTROL (0x0000000000001170ull)
+#define CVMX_SLI_PKT_INSTR_ENB (0x0000000000001000ull)
+#define CVMX_SLI_PKT_INSTR_RD_SIZE (0x00000000000011A0ull)
+#define CVMX_SLI_PKT_INSTR_SIZE (0x0000000000001020ull)
+#define CVMX_SLI_PKT_INT_LEVELS (0x0000000000001120ull)
+#define CVMX_SLI_PKT_IN_BP (0x0000000000001210ull)
+#define CVMX_SLI_PKT_IN_DONEX_CNTS(offset) (0x0000000000002000ull + ((offset) & 31) * 16)
+#define CVMX_SLI_PKT_IN_INSTR_COUNTS (0x0000000000001200ull)
+#define CVMX_SLI_PKT_IN_PCIE_PORT (0x00000000000011B0ull)
+#define CVMX_SLI_PKT_IPTR (0x0000000000001070ull)
+#define CVMX_SLI_PKT_OUTPUT_WMARK (0x0000000000001180ull)
+#define CVMX_SLI_PKT_OUT_BMODE (0x00000000000010D0ull)
+#define CVMX_SLI_PKT_OUT_BP_EN (0x0000000000001240ull)
+#define CVMX_SLI_PKT_OUT_ENB (0x0000000000001010ull)
+#define CVMX_SLI_PKT_PCIE_PORT (0x00000000000010E0ull)
+#define CVMX_SLI_PKT_PORT_IN_RST (0x00000000000011F0ull)
+#define CVMX_SLI_PKT_SLIST_ES (0x0000000000001050ull)
+#define CVMX_SLI_PKT_SLIST_NS (0x0000000000001040ull)
+#define CVMX_SLI_PKT_SLIST_ROR (0x0000000000001030ull)
+#define CVMX_SLI_PKT_TIME_INT (0x0000000000001140ull)
+#define CVMX_SLI_PKT_TIME_INT_ENB (0x0000000000001160ull)
+#define CVMX_SLI_PORTX_PKIND(offset) (0x0000000000000800ull + ((offset) & 31) * 16)
+#define CVMX_SLI_S2M_PORTX_CTL(offset) (0x0000000000003D80ull + ((offset) & 3) * 16)
+#define CVMX_SLI_SCRATCH_1 (0x00000000000003C0ull)
+#define CVMX_SLI_SCRATCH_2 (0x00000000000003D0ull)
+#define CVMX_SLI_STATE1 (0x0000000000000620ull)
+#define CVMX_SLI_STATE2 (0x0000000000000630ull)
+#define CVMX_SLI_STATE3 (0x0000000000000640ull)
+#define CVMX_SLI_TX_PIPE (0x0000000000001230ull)
+#define CVMX_SLI_WINDOW_CTL (0x00000000000002E0ull)
+#define CVMX_SLI_WIN_RD_ADDR (0x0000000000000010ull)
+#define CVMX_SLI_WIN_RD_DATA (0x0000000000000040ull)
+#define CVMX_SLI_WIN_WR_ADDR (0x0000000000000000ull)
+#define CVMX_SLI_WIN_WR_DATA (0x0000000000000020ull)
+#define CVMX_SLI_WIN_WR_MASK (0x0000000000000030ull)
+
+union cvmx_sli_bist_status {
+       uint64_t u64;
+       struct cvmx_sli_bist_status_s {
+               uint64_t reserved_32_63:32;
+               uint64_t ncb_req:1;
+               uint64_t n2p0_c:1;
+               uint64_t n2p0_o:1;
+               uint64_t n2p1_c:1;
+               uint64_t n2p1_o:1;
+               uint64_t cpl_p0:1;
+               uint64_t cpl_p1:1;
+               uint64_t reserved_19_24:6;
+               uint64_t p2n0_c0:1;
+               uint64_t p2n0_c1:1;
+               uint64_t p2n0_n:1;
+               uint64_t p2n0_p0:1;
+               uint64_t p2n0_p1:1;
+               uint64_t p2n1_c0:1;
+               uint64_t p2n1_c1:1;
+               uint64_t p2n1_n:1;
+               uint64_t p2n1_p0:1;
+               uint64_t p2n1_p1:1;
+               uint64_t reserved_6_8:3;
+               uint64_t dsi1_1:1;
+               uint64_t dsi1_0:1;
+               uint64_t dsi0_1:1;
+               uint64_t dsi0_0:1;
+               uint64_t msi:1;
+               uint64_t ncb_cmd:1;
+       } s;
+       struct cvmx_sli_bist_status_cn61xx {
+               uint64_t reserved_31_63:33;
+               uint64_t n2p0_c:1;
+               uint64_t n2p0_o:1;
+               uint64_t reserved_27_28:2;
+               uint64_t cpl_p0:1;
+               uint64_t cpl_p1:1;
+               uint64_t reserved_19_24:6;
+               uint64_t p2n0_c0:1;
+               uint64_t p2n0_c1:1;
+               uint64_t p2n0_n:1;
+               uint64_t p2n0_p0:1;
+               uint64_t p2n0_p1:1;
+               uint64_t p2n1_c0:1;
+               uint64_t p2n1_c1:1;
+               uint64_t p2n1_n:1;
+               uint64_t p2n1_p0:1;
+               uint64_t p2n1_p1:1;
+               uint64_t reserved_6_8:3;
+               uint64_t dsi1_1:1;
+               uint64_t dsi1_0:1;
+               uint64_t dsi0_1:1;
+               uint64_t dsi0_0:1;
+               uint64_t msi:1;
+               uint64_t ncb_cmd:1;
+       } cn61xx;
+       struct cvmx_sli_bist_status_cn63xx {
+               uint64_t reserved_31_63:33;
+               uint64_t n2p0_c:1;
+               uint64_t n2p0_o:1;
+               uint64_t n2p1_c:1;
+               uint64_t n2p1_o:1;
+               uint64_t cpl_p0:1;
+               uint64_t cpl_p1:1;
+               uint64_t reserved_19_24:6;
+               uint64_t p2n0_c0:1;
+               uint64_t p2n0_c1:1;
+               uint64_t p2n0_n:1;
+               uint64_t p2n0_p0:1;
+               uint64_t p2n0_p1:1;
+               uint64_t p2n1_c0:1;
+               uint64_t p2n1_c1:1;
+               uint64_t p2n1_n:1;
+               uint64_t p2n1_p0:1;
+               uint64_t p2n1_p1:1;
+               uint64_t reserved_6_8:3;
+               uint64_t dsi1_1:1;
+               uint64_t dsi1_0:1;
+               uint64_t dsi0_1:1;
+               uint64_t dsi0_0:1;
+               uint64_t msi:1;
+               uint64_t ncb_cmd:1;
+       } cn63xx;
+       struct cvmx_sli_bist_status_cn63xx cn63xxp1;
+       struct cvmx_sli_bist_status_cn61xx cn66xx;
+       struct cvmx_sli_bist_status_s cn68xx;
+       struct cvmx_sli_bist_status_s cn68xxp1;
+};
+
+union cvmx_sli_ctl_portx {
+       uint64_t u64;
+       struct cvmx_sli_ctl_portx_s {
+               uint64_t reserved_22_63:42;
+               uint64_t intd:1;
+               uint64_t intc:1;
+               uint64_t intb:1;
+               uint64_t inta:1;
+               uint64_t dis_port:1;
+               uint64_t waitl_com:1;
+               uint64_t intd_map:2;
+               uint64_t intc_map:2;
+               uint64_t intb_map:2;
+               uint64_t inta_map:2;
+               uint64_t ctlp_ro:1;
+               uint64_t reserved_6_6:1;
+               uint64_t ptlp_ro:1;
+               uint64_t reserved_1_4:4;
+               uint64_t wait_com:1;
+       } s;
+       struct cvmx_sli_ctl_portx_s cn61xx;
+       struct cvmx_sli_ctl_portx_s cn63xx;
+       struct cvmx_sli_ctl_portx_s cn63xxp1;
+       struct cvmx_sli_ctl_portx_s cn66xx;
+       struct cvmx_sli_ctl_portx_s cn68xx;
+       struct cvmx_sli_ctl_portx_s cn68xxp1;
+};
+
+union cvmx_sli_ctl_status {
+       uint64_t u64;
+       struct cvmx_sli_ctl_status_s {
+               uint64_t reserved_20_63:44;
+               uint64_t p1_ntags:6;
+               uint64_t p0_ntags:6;
+               uint64_t chip_rev:8;
+       } s;
+       struct cvmx_sli_ctl_status_cn61xx {
+               uint64_t reserved_14_63:50;
+               uint64_t p0_ntags:6;
+               uint64_t chip_rev:8;
+       } cn61xx;
+       struct cvmx_sli_ctl_status_s cn63xx;
+       struct cvmx_sli_ctl_status_s cn63xxp1;
+       struct cvmx_sli_ctl_status_cn61xx cn66xx;
+       struct cvmx_sli_ctl_status_s cn68xx;
+       struct cvmx_sli_ctl_status_s cn68xxp1;
+};
+
+union cvmx_sli_data_out_cnt {
+       uint64_t u64;
+       struct cvmx_sli_data_out_cnt_s {
+               uint64_t reserved_44_63:20;
+               uint64_t p1_ucnt:16;
+               uint64_t p1_fcnt:6;
+               uint64_t p0_ucnt:16;
+               uint64_t p0_fcnt:6;
+       } s;
+       struct cvmx_sli_data_out_cnt_s cn61xx;
+       struct cvmx_sli_data_out_cnt_s cn63xx;
+       struct cvmx_sli_data_out_cnt_s cn63xxp1;
+       struct cvmx_sli_data_out_cnt_s cn66xx;
+       struct cvmx_sli_data_out_cnt_s cn68xx;
+       struct cvmx_sli_data_out_cnt_s cn68xxp1;
+};
+
+union cvmx_sli_dbg_data {
+       uint64_t u64;
+       struct cvmx_sli_dbg_data_s {
+               uint64_t reserved_18_63:46;
+               uint64_t dsel_ext:1;
+               uint64_t data:17;
+       } s;
+       struct cvmx_sli_dbg_data_s cn61xx;
+       struct cvmx_sli_dbg_data_s cn63xx;
+       struct cvmx_sli_dbg_data_s cn63xxp1;
+       struct cvmx_sli_dbg_data_s cn66xx;
+       struct cvmx_sli_dbg_data_s cn68xx;
+       struct cvmx_sli_dbg_data_s cn68xxp1;
+};
+
+union cvmx_sli_dbg_select {
+       uint64_t u64;
+       struct cvmx_sli_dbg_select_s {
+               uint64_t reserved_33_63:31;
+               uint64_t adbg_sel:1;
+               uint64_t dbg_sel:32;
+       } s;
+       struct cvmx_sli_dbg_select_s cn61xx;
+       struct cvmx_sli_dbg_select_s cn63xx;
+       struct cvmx_sli_dbg_select_s cn63xxp1;
+       struct cvmx_sli_dbg_select_s cn66xx;
+       struct cvmx_sli_dbg_select_s cn68xx;
+       struct cvmx_sli_dbg_select_s cn68xxp1;
+};
+
+union cvmx_sli_dmax_cnt {
+       uint64_t u64;
+       struct cvmx_sli_dmax_cnt_s {
+               uint64_t reserved_32_63:32;
+               uint64_t cnt:32;
+       } s;
+       struct cvmx_sli_dmax_cnt_s cn61xx;
+       struct cvmx_sli_dmax_cnt_s cn63xx;
+       struct cvmx_sli_dmax_cnt_s cn63xxp1;
+       struct cvmx_sli_dmax_cnt_s cn66xx;
+       struct cvmx_sli_dmax_cnt_s cn68xx;
+       struct cvmx_sli_dmax_cnt_s cn68xxp1;
+};
+
+union cvmx_sli_dmax_int_level {
+       uint64_t u64;
+       struct cvmx_sli_dmax_int_level_s {
+               uint64_t time:32;
+               uint64_t cnt:32;
+       } s;
+       struct cvmx_sli_dmax_int_level_s cn61xx;
+       struct cvmx_sli_dmax_int_level_s cn63xx;
+       struct cvmx_sli_dmax_int_level_s cn63xxp1;
+       struct cvmx_sli_dmax_int_level_s cn66xx;
+       struct cvmx_sli_dmax_int_level_s cn68xx;
+       struct cvmx_sli_dmax_int_level_s cn68xxp1;
+};
+
+union cvmx_sli_dmax_tim {
+       uint64_t u64;
+       struct cvmx_sli_dmax_tim_s {
+               uint64_t reserved_32_63:32;
+               uint64_t tim:32;
+       } s;
+       struct cvmx_sli_dmax_tim_s cn61xx;
+       struct cvmx_sli_dmax_tim_s cn63xx;
+       struct cvmx_sli_dmax_tim_s cn63xxp1;
+       struct cvmx_sli_dmax_tim_s cn66xx;
+       struct cvmx_sli_dmax_tim_s cn68xx;
+       struct cvmx_sli_dmax_tim_s cn68xxp1;
+};
+
+union cvmx_sli_int_enb_ciu {
+       uint64_t u64;
+       struct cvmx_sli_int_enb_ciu_s {
+               uint64_t reserved_62_63:2;
+               uint64_t pipe_err:1;
+               uint64_t ill_pad:1;
+               uint64_t sprt3_err:1;
+               uint64_t sprt2_err:1;
+               uint64_t sprt1_err:1;
+               uint64_t sprt0_err:1;
+               uint64_t pins_err:1;
+               uint64_t pop_err:1;
+               uint64_t pdi_err:1;
+               uint64_t pgl_err:1;
+               uint64_t pin_bp:1;
+               uint64_t pout_err:1;
+               uint64_t psldbof:1;
+               uint64_t pidbof:1;
+               uint64_t reserved_38_47:10;
+               uint64_t dtime:2;
+               uint64_t dcnt:2;
+               uint64_t dmafi:2;
+               uint64_t reserved_28_31:4;
+               uint64_t m3_un_wi:1;
+               uint64_t m3_un_b0:1;
+               uint64_t m3_up_wi:1;
+               uint64_t m3_up_b0:1;
+               uint64_t m2_un_wi:1;
+               uint64_t m2_un_b0:1;
+               uint64_t m2_up_wi:1;
+               uint64_t m2_up_b0:1;
+               uint64_t reserved_18_19:2;
+               uint64_t mio_int1:1;
+               uint64_t mio_int0:1;
+               uint64_t m1_un_wi:1;
+               uint64_t m1_un_b0:1;
+               uint64_t m1_up_wi:1;
+               uint64_t m1_up_b0:1;
+               uint64_t m0_un_wi:1;
+               uint64_t m0_un_b0:1;
+               uint64_t m0_up_wi:1;
+               uint64_t m0_up_b0:1;
+               uint64_t reserved_6_7:2;
+               uint64_t ptime:1;
+               uint64_t pcnt:1;
+               uint64_t iob2big:1;
+               uint64_t bar0_to:1;
+               uint64_t reserved_1_1:1;
+               uint64_t rml_to:1;
+       } s;
+       struct cvmx_sli_int_enb_ciu_cn61xx {
+               uint64_t reserved_61_63:3;
+               uint64_t ill_pad:1;
+               uint64_t sprt3_err:1;
+               uint64_t sprt2_err:1;
+               uint64_t sprt1_err:1;
+               uint64_t sprt0_err:1;
+               uint64_t pins_err:1;
+               uint64_t pop_err:1;
+               uint64_t pdi_err:1;
+               uint64_t pgl_err:1;
+               uint64_t pin_bp:1;
+               uint64_t pout_err:1;
+               uint64_t psldbof:1;
+               uint64_t pidbof:1;
+               uint64_t reserved_38_47:10;
+               uint64_t dtime:2;
+               uint64_t dcnt:2;
+               uint64_t dmafi:2;
+               uint64_t reserved_28_31:4;
+               uint64_t m3_un_wi:1;
+               uint64_t m3_un_b0:1;
+               uint64_t m3_up_wi:1;
+               uint64_t m3_up_b0:1;
+               uint64_t m2_un_wi:1;
+               uint64_t m2_un_b0:1;
+               uint64_t m2_up_wi:1;
+               uint64_t m2_up_b0:1;
+               uint64_t reserved_18_19:2;
+               uint64_t mio_int1:1;
+               uint64_t mio_int0:1;
+               uint64_t m1_un_wi:1;
+               uint64_t m1_un_b0:1;
+               uint64_t m1_up_wi:1;
+               uint64_t m1_up_b0:1;
+               uint64_t m0_un_wi:1;
+               uint64_t m0_un_b0:1;
+               uint64_t m0_up_wi:1;
+               uint64_t m0_up_b0:1;
+               uint64_t reserved_6_7:2;
+               uint64_t ptime:1;
+               uint64_t pcnt:1;
+               uint64_t iob2big:1;
+               uint64_t bar0_to:1;
+               uint64_t reserved_1_1:1;
+               uint64_t rml_to:1;
+       } cn61xx;
+       struct cvmx_sli_int_enb_ciu_cn63xx {
+               uint64_t reserved_61_63:3;
+               uint64_t ill_pad:1;
+               uint64_t reserved_58_59:2;
+               uint64_t sprt1_err:1;
+               uint64_t sprt0_err:1;
+               uint64_t pins_err:1;
+               uint64_t pop_err:1;
+               uint64_t pdi_err:1;
+               uint64_t pgl_err:1;
+               uint64_t pin_bp:1;
+               uint64_t pout_err:1;
+               uint64_t psldbof:1;
+               uint64_t pidbof:1;
+               uint64_t reserved_38_47:10;
+               uint64_t dtime:2;
+               uint64_t dcnt:2;
+               uint64_t dmafi:2;
+               uint64_t reserved_18_31:14;
+               uint64_t mio_int1:1;
+               uint64_t mio_int0:1;
+               uint64_t m1_un_wi:1;
+               uint64_t m1_un_b0:1;
+               uint64_t m1_up_wi:1;
+               uint64_t m1_up_b0:1;
+               uint64_t m0_un_wi:1;
+               uint64_t m0_un_b0:1;
+               uint64_t m0_up_wi:1;
+               uint64_t m0_up_b0:1;
+               uint64_t reserved_6_7:2;
+               uint64_t ptime:1;
+               uint64_t pcnt:1;
+               uint64_t iob2big:1;
+               uint64_t bar0_to:1;
+               uint64_t reserved_1_1:1;
+               uint64_t rml_to:1;
+       } cn63xx;
+       struct cvmx_sli_int_enb_ciu_cn63xx cn63xxp1;
+       struct cvmx_sli_int_enb_ciu_cn61xx cn66xx;
+       struct cvmx_sli_int_enb_ciu_cn68xx {
+               uint64_t reserved_62_63:2;
+               uint64_t pipe_err:1;
+               uint64_t ill_pad:1;
+               uint64_t reserved_58_59:2;
+               uint64_t sprt1_err:1;
+               uint64_t sprt0_err:1;
+               uint64_t pins_err:1;
+               uint64_t pop_err:1;
+               uint64_t pdi_err:1;
+               uint64_t pgl_err:1;
+               uint64_t reserved_51_51:1;
+               uint64_t pout_err:1;
+               uint64_t psldbof:1;
+               uint64_t pidbof:1;
+               uint64_t reserved_38_47:10;
+               uint64_t dtime:2;
+               uint64_t dcnt:2;
+               uint64_t dmafi:2;
+               uint64_t reserved_18_31:14;
+               uint64_t mio_int1:1;
+               uint64_t mio_int0:1;
+               uint64_t m1_un_wi:1;
+               uint64_t m1_un_b0:1;
+               uint64_t m1_up_wi:1;
+               uint64_t m1_up_b0:1;
+               uint64_t m0_un_wi:1;
+               uint64_t m0_un_b0:1;
+               uint64_t m0_up_wi:1;
+               uint64_t m0_up_b0:1;
+               uint64_t reserved_6_7:2;
+               uint64_t ptime:1;
+               uint64_t pcnt:1;
+               uint64_t iob2big:1;
+               uint64_t bar0_to:1;
+               uint64_t reserved_1_1:1;
+               uint64_t rml_to:1;
+       } cn68xx;
+       struct cvmx_sli_int_enb_ciu_cn68xx cn68xxp1;
+};
+
+union cvmx_sli_int_enb_portx {
+       uint64_t u64;
+       struct cvmx_sli_int_enb_portx_s {
+               uint64_t reserved_62_63:2;
+               uint64_t pipe_err:1;
+               uint64_t ill_pad:1;
+               uint64_t sprt3_err:1;
+               uint64_t sprt2_err:1;
+               uint64_t sprt1_err:1;
+               uint64_t sprt0_err:1;
+               uint64_t pins_err:1;
+               uint64_t pop_err:1;
+               uint64_t pdi_err:1;
+               uint64_t pgl_err:1;
+               uint64_t pin_bp:1;
+               uint64_t pout_err:1;
+               uint64_t psldbof:1;
+               uint64_t pidbof:1;
+               uint64_t reserved_38_47:10;
+               uint64_t dtime:2;
+               uint64_t dcnt:2;
+               uint64_t dmafi:2;
+               uint64_t reserved_28_31:4;
+               uint64_t m3_un_wi:1;
+               uint64_t m3_un_b0:1;
+               uint64_t m3_up_wi:1;
+               uint64_t m3_up_b0:1;
+               uint64_t m2_un_wi:1;
+               uint64_t m2_un_b0:1;
+               uint64_t m2_up_wi:1;
+               uint64_t m2_up_b0:1;
+               uint64_t mac1_int:1;
+               uint64_t mac0_int:1;
+               uint64_t mio_int1:1;
+               uint64_t mio_int0:1;
+               uint64_t m1_un_wi:1;
+               uint64_t m1_un_b0:1;
+               uint64_t m1_up_wi:1;
+               uint64_t m1_up_b0:1;
+               uint64_t m0_un_wi:1;
+               uint64_t m0_un_b0:1;
+               uint64_t m0_up_wi:1;
+               uint64_t m0_up_b0:1;
+               uint64_t reserved_6_7:2;
+               uint64_t ptime:1;
+               uint64_t pcnt:1;
+               uint64_t iob2big:1;
+               uint64_t bar0_to:1;
+               uint64_t reserved_1_1:1;
+               uint64_t rml_to:1;
+       } s;
+       struct cvmx_sli_int_enb_portx_cn61xx {
+               uint64_t reserved_61_63:3;
+               uint64_t ill_pad:1;
+               uint64_t sprt3_err:1;
+               uint64_t sprt2_err:1;
+               uint64_t sprt1_err:1;
+               uint64_t sprt0_err:1;
+               uint64_t pins_err:1;
+               uint64_t pop_err:1;
+               uint64_t pdi_err:1;
+               uint64_t pgl_err:1;
+               uint64_t pin_bp:1;
+               uint64_t pout_err:1;
+               uint64_t psldbof:1;
+               uint64_t pidbof:1;
+               uint64_t reserved_38_47:10;
+               uint64_t dtime:2;
+               uint64_t dcnt:2;
+               uint64_t dmafi:2;
+               uint64_t reserved_28_31:4;
+               uint64_t m3_un_wi:1;
+               uint64_t m3_un_b0:1;
+               uint64_t m3_up_wi:1;
+               uint64_t m3_up_b0:1;
+               uint64_t m2_un_wi:1;
+               uint64_t m2_un_b0:1;
+               uint64_t m2_up_wi:1;
+               uint64_t m2_up_b0:1;
+               uint64_t mac1_int:1;
+               uint64_t mac0_int:1;
+               uint64_t mio_int1:1;
+               uint64_t mio_int0:1;
+               uint64_t m1_un_wi:1;
+               uint64_t m1_un_b0:1;
+               uint64_t m1_up_wi:1;
+               uint64_t m1_up_b0:1;
+               uint64_t m0_un_wi:1;
+               uint64_t m0_un_b0:1;
+               uint64_t m0_up_wi:1;
+               uint64_t m0_up_b0:1;
+               uint64_t reserved_6_7:2;
+               uint64_t ptime:1;
+               uint64_t pcnt:1;
+               uint64_t iob2big:1;
+               uint64_t bar0_to:1;
+               uint64_t reserved_1_1:1;
+               uint64_t rml_to:1;
+       } cn61xx;
+       struct cvmx_sli_int_enb_portx_cn63xx {
+               uint64_t reserved_61_63:3;
+               uint64_t ill_pad:1;
+               uint64_t reserved_58_59:2;
+               uint64_t sprt1_err:1;
+               uint64_t sprt0_err:1;
+               uint64_t pins_err:1;
+               uint64_t pop_err:1;
+               uint64_t pdi_err:1;
+               uint64_t pgl_err:1;
+               uint64_t pin_bp:1;
+               uint64_t pout_err:1;
+               uint64_t psldbof:1;
+               uint64_t pidbof:1;
+               uint64_t reserved_38_47:10;
+               uint64_t dtime:2;
+               uint64_t dcnt:2;
+               uint64_t dmafi:2;
+               uint64_t reserved_20_31:12;
+               uint64_t mac1_int:1;
+               uint64_t mac0_int:1;
+               uint64_t mio_int1:1;
+               uint64_t mio_int0:1;
+               uint64_t m1_un_wi:1;
+               uint64_t m1_un_b0:1;
+               uint64_t m1_up_wi:1;
+               uint64_t m1_up_b0:1;
+               uint64_t m0_un_wi:1;
+               uint64_t m0_un_b0:1;
+               uint64_t m0_up_wi:1;
+               uint64_t m0_up_b0:1;
+               uint64_t reserved_6_7:2;
+               uint64_t ptime:1;
+               uint64_t pcnt:1;
+               uint64_t iob2big:1;
+               uint64_t bar0_to:1;
+               uint64_t reserved_1_1:1;
+               uint64_t rml_to:1;
+       } cn63xx;
+       struct cvmx_sli_int_enb_portx_cn63xx cn63xxp1;
+       struct cvmx_sli_int_enb_portx_cn61xx cn66xx;
+       struct cvmx_sli_int_enb_portx_cn68xx {
+               uint64_t reserved_62_63:2;
+               uint64_t pipe_err:1;
+               uint64_t ill_pad:1;
+               uint64_t reserved_58_59:2;
+               uint64_t sprt1_err:1;
+               uint64_t sprt0_err:1;
+               uint64_t pins_err:1;
+               uint64_t pop_err:1;
+               uint64_t pdi_err:1;
+               uint64_t pgl_err:1;
+               uint64_t reserved_51_51:1;
+               uint64_t pout_err:1;
+               uint64_t psldbof:1;
+               uint64_t pidbof:1;
+               uint64_t reserved_38_47:10;
+               uint64_t dtime:2;
+               uint64_t dcnt:2;
+               uint64_t dmafi:2;
+               uint64_t reserved_20_31:12;
+               uint64_t mac1_int:1;
+               uint64_t mac0_int:1;
+               uint64_t mio_int1:1;
+               uint64_t mio_int0:1;
+               uint64_t m1_un_wi:1;
+               uint64_t m1_un_b0:1;
+               uint64_t m1_up_wi:1;
+               uint64_t m1_up_b0:1;
+               uint64_t m0_un_wi:1;
+               uint64_t m0_un_b0:1;
+               uint64_t m0_up_wi:1;
+               uint64_t m0_up_b0:1;
+               uint64_t reserved_6_7:2;
+               uint64_t ptime:1;
+               uint64_t pcnt:1;
+               uint64_t iob2big:1;
+               uint64_t bar0_to:1;
+               uint64_t reserved_1_1:1;
+               uint64_t rml_to:1;
+       } cn68xx;
+       struct cvmx_sli_int_enb_portx_cn68xx cn68xxp1;
+};
+
+union cvmx_sli_int_sum {
+       uint64_t u64;
+       struct cvmx_sli_int_sum_s {
+               uint64_t reserved_62_63:2;
+               uint64_t pipe_err:1;
+               uint64_t ill_pad:1;
+               uint64_t sprt3_err:1;
+               uint64_t sprt2_err:1;
+               uint64_t sprt1_err:1;
+               uint64_t sprt0_err:1;
+               uint64_t pins_err:1;
+               uint64_t pop_err:1;
+               uint64_t pdi_err:1;
+               uint64_t pgl_err:1;
+               uint64_t pin_bp:1;
+               uint64_t pout_err:1;
+               uint64_t psldbof:1;
+               uint64_t pidbof:1;
+               uint64_t reserved_38_47:10;
+               uint64_t dtime:2;
+               uint64_t dcnt:2;
+               uint64_t dmafi:2;
+               uint64_t reserved_28_31:4;
+               uint64_t m3_un_wi:1;
+               uint64_t m3_un_b0:1;
+               uint64_t m3_up_wi:1;
+               uint64_t m3_up_b0:1;
+               uint64_t m2_un_wi:1;
+               uint64_t m2_un_b0:1;
+               uint64_t m2_up_wi:1;
+               uint64_t m2_up_b0:1;
+               uint64_t mac1_int:1;
+               uint64_t mac0_int:1;
+               uint64_t mio_int1:1;
+               uint64_t mio_int0:1;
+               uint64_t m1_un_wi:1;
+               uint64_t m1_un_b0:1;
+               uint64_t m1_up_wi:1;
+               uint64_t m1_up_b0:1;
+               uint64_t m0_un_wi:1;
+               uint64_t m0_un_b0:1;
+               uint64_t m0_up_wi:1;
+               uint64_t m0_up_b0:1;
+               uint64_t reserved_6_7:2;
+               uint64_t ptime:1;
+               uint64_t pcnt:1;
+               uint64_t iob2big:1;
+               uint64_t bar0_to:1;
+               uint64_t reserved_1_1:1;
+               uint64_t rml_to:1;
+       } s;
+       struct cvmx_sli_int_sum_cn61xx {
+               uint64_t reserved_61_63:3;
+               uint64_t ill_pad:1;
+               uint64_t sprt3_err:1;
+               uint64_t sprt2_err:1;
+               uint64_t sprt1_err:1;
+               uint64_t sprt0_err:1;
+               uint64_t pins_err:1;
+               uint64_t pop_err:1;
+               uint64_t pdi_err:1;
+               uint64_t pgl_err:1;
+               uint64_t pin_bp:1;
+               uint64_t pout_err:1;
+               uint64_t psldbof:1;
+               uint64_t pidbof:1;
+               uint64_t reserved_38_47:10;
+               uint64_t dtime:2;
+               uint64_t dcnt:2;
+               uint64_t dmafi:2;
+               uint64_t reserved_28_31:4;
+               uint64_t m3_un_wi:1;
+               uint64_t m3_un_b0:1;
+               uint64_t m3_up_wi:1;
+               uint64_t m3_up_b0:1;
+               uint64_t m2_un_wi:1;
+               uint64_t m2_un_b0:1;
+               uint64_t m2_up_wi:1;
+               uint64_t m2_up_b0:1;
+               uint64_t mac1_int:1;
+               uint64_t mac0_int:1;
+               uint64_t mio_int1:1;
+               uint64_t mio_int0:1;
+               uint64_t m1_un_wi:1;
+               uint64_t m1_un_b0:1;
+               uint64_t m1_up_wi:1;
+               uint64_t m1_up_b0:1;
+               uint64_t m0_un_wi:1;
+               uint64_t m0_un_b0:1;
+               uint64_t m0_up_wi:1;
+               uint64_t m0_up_b0:1;
+               uint64_t reserved_6_7:2;
+               uint64_t ptime:1;
+               uint64_t pcnt:1;
+               uint64_t iob2big:1;
+               uint64_t bar0_to:1;
+               uint64_t reserved_1_1:1;
+               uint64_t rml_to:1;
+       } cn61xx;
+       struct cvmx_sli_int_sum_cn63xx {
+               uint64_t reserved_61_63:3;
+               uint64_t ill_pad:1;
+               uint64_t reserved_58_59:2;
+               uint64_t sprt1_err:1;
+               uint64_t sprt0_err:1;
+               uint64_t pins_err:1;
+               uint64_t pop_err:1;
+               uint64_t pdi_err:1;
+               uint64_t pgl_err:1;
+               uint64_t pin_bp:1;
+               uint64_t pout_err:1;
+               uint64_t psldbof:1;
+               uint64_t pidbof:1;
+               uint64_t reserved_38_47:10;
+               uint64_t dtime:2;
+               uint64_t dcnt:2;
+               uint64_t dmafi:2;
+               uint64_t reserved_20_31:12;
+               uint64_t mac1_int:1;
+               uint64_t mac0_int:1;
+               uint64_t mio_int1:1;
+               uint64_t mio_int0:1;
+               uint64_t m1_un_wi:1;
+               uint64_t m1_un_b0:1;
+               uint64_t m1_up_wi:1;
+               uint64_t m1_up_b0:1;
+               uint64_t m0_un_wi:1;
+               uint64_t m0_un_b0:1;
+               uint64_t m0_up_wi:1;
+               uint64_t m0_up_b0:1;
+               uint64_t reserved_6_7:2;
+               uint64_t ptime:1;
+               uint64_t pcnt:1;
+               uint64_t iob2big:1;
+               uint64_t bar0_to:1;
+               uint64_t reserved_1_1:1;
+               uint64_t rml_to:1;
+       } cn63xx;
+       struct cvmx_sli_int_sum_cn63xx cn63xxp1;
+       struct cvmx_sli_int_sum_cn61xx cn66xx;
+       struct cvmx_sli_int_sum_cn68xx {
+               uint64_t reserved_62_63:2;
+               uint64_t pipe_err:1;
+               uint64_t ill_pad:1;
+               uint64_t reserved_58_59:2;
+               uint64_t sprt1_err:1;
+               uint64_t sprt0_err:1;
+               uint64_t pins_err:1;
+               uint64_t pop_err:1;
+               uint64_t pdi_err:1;
+               uint64_t pgl_err:1;
+               uint64_t reserved_51_51:1;
+               uint64_t pout_err:1;
+               uint64_t psldbof:1;
+               uint64_t pidbof:1;
+               uint64_t reserved_38_47:10;
+               uint64_t dtime:2;
+               uint64_t dcnt:2;
+               uint64_t dmafi:2;
+               uint64_t reserved_20_31:12;
+               uint64_t mac1_int:1;
+               uint64_t mac0_int:1;
+               uint64_t mio_int1:1;
+               uint64_t mio_int0:1;
+               uint64_t m1_un_wi:1;
+               uint64_t m1_un_b0:1;
+               uint64_t m1_up_wi:1;
+               uint64_t m1_up_b0:1;
+               uint64_t m0_un_wi:1;
+               uint64_t m0_un_b0:1;
+               uint64_t m0_up_wi:1;
+               uint64_t m0_up_b0:1;
+               uint64_t reserved_6_7:2;
+               uint64_t ptime:1;
+               uint64_t pcnt:1;
+               uint64_t iob2big:1;
+               uint64_t bar0_to:1;
+               uint64_t reserved_1_1:1;
+               uint64_t rml_to:1;
+       } cn68xx;
+       struct cvmx_sli_int_sum_cn68xx cn68xxp1;
+};
+
+union cvmx_sli_last_win_rdata0 {
+       uint64_t u64;
+       struct cvmx_sli_last_win_rdata0_s {
+               uint64_t data:64;
+       } s;
+       struct cvmx_sli_last_win_rdata0_s cn61xx;
+       struct cvmx_sli_last_win_rdata0_s cn63xx;
+       struct cvmx_sli_last_win_rdata0_s cn63xxp1;
+       struct cvmx_sli_last_win_rdata0_s cn66xx;
+       struct cvmx_sli_last_win_rdata0_s cn68xx;
+       struct cvmx_sli_last_win_rdata0_s cn68xxp1;
+};
+
+union cvmx_sli_last_win_rdata1 {
+       uint64_t u64;
+       struct cvmx_sli_last_win_rdata1_s {
+               uint64_t data:64;
+       } s;
+       struct cvmx_sli_last_win_rdata1_s cn61xx;
+       struct cvmx_sli_last_win_rdata1_s cn63xx;
+       struct cvmx_sli_last_win_rdata1_s cn63xxp1;
+       struct cvmx_sli_last_win_rdata1_s cn66xx;
+       struct cvmx_sli_last_win_rdata1_s cn68xx;
+       struct cvmx_sli_last_win_rdata1_s cn68xxp1;
+};
+
+union cvmx_sli_last_win_rdata2 {
+       uint64_t u64;
+       struct cvmx_sli_last_win_rdata2_s {
+               uint64_t data:64;
+       } s;
+       struct cvmx_sli_last_win_rdata2_s cn61xx;
+       struct cvmx_sli_last_win_rdata2_s cn66xx;
+};
+
+union cvmx_sli_last_win_rdata3 {
+       uint64_t u64;
+       struct cvmx_sli_last_win_rdata3_s {
+               uint64_t data:64;
+       } s;
+       struct cvmx_sli_last_win_rdata3_s cn61xx;
+       struct cvmx_sli_last_win_rdata3_s cn66xx;
+};
+
+union cvmx_sli_mac_credit_cnt {
+       uint64_t u64;
+       struct cvmx_sli_mac_credit_cnt_s {
+               uint64_t reserved_54_63:10;
+               uint64_t p1_c_d:1;
+               uint64_t p1_n_d:1;
+               uint64_t p1_p_d:1;
+               uint64_t p0_c_d:1;
+               uint64_t p0_n_d:1;
+               uint64_t p0_p_d:1;
+               uint64_t p1_ccnt:8;
+               uint64_t p1_ncnt:8;
+               uint64_t p1_pcnt:8;
+               uint64_t p0_ccnt:8;
+               uint64_t p0_ncnt:8;
+               uint64_t p0_pcnt:8;
+       } s;
+       struct cvmx_sli_mac_credit_cnt_s cn61xx;
+       struct cvmx_sli_mac_credit_cnt_s cn63xx;
+       struct cvmx_sli_mac_credit_cnt_cn63xxp1 {
+               uint64_t reserved_48_63:16;
+               uint64_t p1_ccnt:8;
+               uint64_t p1_ncnt:8;
+               uint64_t p1_pcnt:8;
+               uint64_t p0_ccnt:8;
+               uint64_t p0_ncnt:8;
+               uint64_t p0_pcnt:8;
+       } cn63xxp1;
+       struct cvmx_sli_mac_credit_cnt_s cn66xx;
+       struct cvmx_sli_mac_credit_cnt_s cn68xx;
+       struct cvmx_sli_mac_credit_cnt_s cn68xxp1;
+};
+
+union cvmx_sli_mac_credit_cnt2 {
+       uint64_t u64;
+       struct cvmx_sli_mac_credit_cnt2_s {
+               uint64_t reserved_54_63:10;
+               uint64_t p3_c_d:1;
+               uint64_t p3_n_d:1;
+               uint64_t p3_p_d:1;
+               uint64_t p2_c_d:1;
+               uint64_t p2_n_d:1;
+               uint64_t p2_p_d:1;
+               uint64_t p3_ccnt:8;
+               uint64_t p3_ncnt:8;
+               uint64_t p3_pcnt:8;
+               uint64_t p2_ccnt:8;
+               uint64_t p2_ncnt:8;
+               uint64_t p2_pcnt:8;
+       } s;
+       struct cvmx_sli_mac_credit_cnt2_s cn61xx;
+       struct cvmx_sli_mac_credit_cnt2_s cn66xx;
+};
+
+union cvmx_sli_mac_number {
+       uint64_t u64;
+       struct cvmx_sli_mac_number_s {
+               uint64_t reserved_9_63:55;
+               uint64_t a_mode:1;
+               uint64_t num:8;
+       } s;
+       struct cvmx_sli_mac_number_s cn61xx;
+       struct cvmx_sli_mac_number_cn63xx {
+               uint64_t reserved_8_63:56;
+               uint64_t num:8;
+       } cn63xx;
+       struct cvmx_sli_mac_number_s cn66xx;
+       struct cvmx_sli_mac_number_cn63xx cn68xx;
+       struct cvmx_sli_mac_number_cn63xx cn68xxp1;
+};
+
+union cvmx_sli_mem_access_ctl {
+       uint64_t u64;
+       struct cvmx_sli_mem_access_ctl_s {
+               uint64_t reserved_14_63:50;
+               uint64_t max_word:4;
+               uint64_t timer:10;
+       } s;
+       struct cvmx_sli_mem_access_ctl_s cn61xx;
+       struct cvmx_sli_mem_access_ctl_s cn63xx;
+       struct cvmx_sli_mem_access_ctl_s cn63xxp1;
+       struct cvmx_sli_mem_access_ctl_s cn66xx;
+       struct cvmx_sli_mem_access_ctl_s cn68xx;
+       struct cvmx_sli_mem_access_ctl_s cn68xxp1;
+};
+
+union cvmx_sli_mem_access_subidx {
+       uint64_t u64;
+       struct cvmx_sli_mem_access_subidx_s {
+               uint64_t reserved_43_63:21;
+               uint64_t zero:1;
+               uint64_t port:3;
+               uint64_t nmerge:1;
+               uint64_t esr:2;
+               uint64_t esw:2;
+               uint64_t wtype:2;
+               uint64_t rtype:2;
+               uint64_t reserved_0_29:30;
+       } s;
+       struct cvmx_sli_mem_access_subidx_cn61xx {
+               uint64_t reserved_43_63:21;
+               uint64_t zero:1;
+               uint64_t port:3;
+               uint64_t nmerge:1;
+               uint64_t esr:2;
+               uint64_t esw:2;
+               uint64_t wtype:2;
+               uint64_t rtype:2;
+               uint64_t ba:30;
+       } cn61xx;
+       struct cvmx_sli_mem_access_subidx_cn61xx cn63xx;
+       struct cvmx_sli_mem_access_subidx_cn61xx cn63xxp1;
+       struct cvmx_sli_mem_access_subidx_cn61xx cn66xx;
+       struct cvmx_sli_mem_access_subidx_cn68xx {
+               uint64_t reserved_43_63:21;
+               uint64_t zero:1;
+               uint64_t port:3;
+               uint64_t nmerge:1;
+               uint64_t esr:2;
+               uint64_t esw:2;
+               uint64_t wtype:2;
+               uint64_t rtype:2;
+               uint64_t ba:28;
+               uint64_t reserved_0_1:2;
+       } cn68xx;
+       struct cvmx_sli_mem_access_subidx_cn68xx cn68xxp1;
+};
+
+union cvmx_sli_msi_enb0 {
+       uint64_t u64;
+       struct cvmx_sli_msi_enb0_s {
+               uint64_t enb:64;
+       } s;
+       struct cvmx_sli_msi_enb0_s cn61xx;
+       struct cvmx_sli_msi_enb0_s cn63xx;
+       struct cvmx_sli_msi_enb0_s cn63xxp1;
+       struct cvmx_sli_msi_enb0_s cn66xx;
+       struct cvmx_sli_msi_enb0_s cn68xx;
+       struct cvmx_sli_msi_enb0_s cn68xxp1;
+};
+
+union cvmx_sli_msi_enb1 {
+       uint64_t u64;
+       struct cvmx_sli_msi_enb1_s {
+               uint64_t enb:64;
+       } s;
+       struct cvmx_sli_msi_enb1_s cn61xx;
+       struct cvmx_sli_msi_enb1_s cn63xx;
+       struct cvmx_sli_msi_enb1_s cn63xxp1;
+       struct cvmx_sli_msi_enb1_s cn66xx;
+       struct cvmx_sli_msi_enb1_s cn68xx;
+       struct cvmx_sli_msi_enb1_s cn68xxp1;
+};
+
+union cvmx_sli_msi_enb2 {
+       uint64_t u64;
+       struct cvmx_sli_msi_enb2_s {
+               uint64_t enb:64;
+       } s;
+       struct cvmx_sli_msi_enb2_s cn61xx;
+       struct cvmx_sli_msi_enb2_s cn63xx;
+       struct cvmx_sli_msi_enb2_s cn63xxp1;
+       struct cvmx_sli_msi_enb2_s cn66xx;
+       struct cvmx_sli_msi_enb2_s cn68xx;
+       struct cvmx_sli_msi_enb2_s cn68xxp1;
+};
+
+union cvmx_sli_msi_enb3 {
+       uint64_t u64;
+       struct cvmx_sli_msi_enb3_s {
+               uint64_t enb:64;
+       } s;
+       struct cvmx_sli_msi_enb3_s cn61xx;
+       struct cvmx_sli_msi_enb3_s cn63xx;
+       struct cvmx_sli_msi_enb3_s cn63xxp1;
+       struct cvmx_sli_msi_enb3_s cn66xx;
+       struct cvmx_sli_msi_enb3_s cn68xx;
+       struct cvmx_sli_msi_enb3_s cn68xxp1;
+};
+
+union cvmx_sli_msi_rcv0 {
+       uint64_t u64;
+       struct cvmx_sli_msi_rcv0_s {
+               uint64_t intr:64;
+       } s;
+       struct cvmx_sli_msi_rcv0_s cn61xx;
+       struct cvmx_sli_msi_rcv0_s cn63xx;
+       struct cvmx_sli_msi_rcv0_s cn63xxp1;
+       struct cvmx_sli_msi_rcv0_s cn66xx;
+       struct cvmx_sli_msi_rcv0_s cn68xx;
+       struct cvmx_sli_msi_rcv0_s cn68xxp1;
+};
+
+union cvmx_sli_msi_rcv1 {
+       uint64_t u64;
+       struct cvmx_sli_msi_rcv1_s {
+               uint64_t intr:64;
+       } s;
+       struct cvmx_sli_msi_rcv1_s cn61xx;
+       struct cvmx_sli_msi_rcv1_s cn63xx;
+       struct cvmx_sli_msi_rcv1_s cn63xxp1;
+       struct cvmx_sli_msi_rcv1_s cn66xx;
+       struct cvmx_sli_msi_rcv1_s cn68xx;
+       struct cvmx_sli_msi_rcv1_s cn68xxp1;
+};
+
+union cvmx_sli_msi_rcv2 {
+       uint64_t u64;
+       struct cvmx_sli_msi_rcv2_s {
+               uint64_t intr:64;
+       } s;
+       struct cvmx_sli_msi_rcv2_s cn61xx;
+       struct cvmx_sli_msi_rcv2_s cn63xx;
+       struct cvmx_sli_msi_rcv2_s cn63xxp1;
+       struct cvmx_sli_msi_rcv2_s cn66xx;
+       struct cvmx_sli_msi_rcv2_s cn68xx;
+       struct cvmx_sli_msi_rcv2_s cn68xxp1;
+};
+
+union cvmx_sli_msi_rcv3 {
+       uint64_t u64;
+       struct cvmx_sli_msi_rcv3_s {
+               uint64_t intr:64;
+       } s;
+       struct cvmx_sli_msi_rcv3_s cn61xx;
+       struct cvmx_sli_msi_rcv3_s cn63xx;
+       struct cvmx_sli_msi_rcv3_s cn63xxp1;
+       struct cvmx_sli_msi_rcv3_s cn66xx;
+       struct cvmx_sli_msi_rcv3_s cn68xx;
+       struct cvmx_sli_msi_rcv3_s cn68xxp1;
+};
+
+union cvmx_sli_msi_rd_map {
+       uint64_t u64;
+       struct cvmx_sli_msi_rd_map_s {
+               uint64_t reserved_16_63:48;
+               uint64_t rd_int:8;
+               uint64_t msi_int:8;
+       } s;
+       struct cvmx_sli_msi_rd_map_s cn61xx;
+       struct cvmx_sli_msi_rd_map_s cn63xx;
+       struct cvmx_sli_msi_rd_map_s cn63xxp1;
+       struct cvmx_sli_msi_rd_map_s cn66xx;
+       struct cvmx_sli_msi_rd_map_s cn68xx;
+       struct cvmx_sli_msi_rd_map_s cn68xxp1;
+};
+
+union cvmx_sli_msi_w1c_enb0 {
+       uint64_t u64;
+       struct cvmx_sli_msi_w1c_enb0_s {
+               uint64_t clr:64;
+       } s;
+       struct cvmx_sli_msi_w1c_enb0_s cn61xx;
+       struct cvmx_sli_msi_w1c_enb0_s cn63xx;
+       struct cvmx_sli_msi_w1c_enb0_s cn63xxp1;
+       struct cvmx_sli_msi_w1c_enb0_s cn66xx;
+       struct cvmx_sli_msi_w1c_enb0_s cn68xx;
+       struct cvmx_sli_msi_w1c_enb0_s cn68xxp1;
+};
+
+union cvmx_sli_msi_w1c_enb1 {
+       uint64_t u64;
+       struct cvmx_sli_msi_w1c_enb1_s {
+               uint64_t clr:64;
+       } s;
+       struct cvmx_sli_msi_w1c_enb1_s cn61xx;
+       struct cvmx_sli_msi_w1c_enb1_s cn63xx;
+       struct cvmx_sli_msi_w1c_enb1_s cn63xxp1;
+       struct cvmx_sli_msi_w1c_enb1_s cn66xx;
+       struct cvmx_sli_msi_w1c_enb1_s cn68xx;
+       struct cvmx_sli_msi_w1c_enb1_s cn68xxp1;
+};
+
+union cvmx_sli_msi_w1c_enb2 {
+       uint64_t u64;
+       struct cvmx_sli_msi_w1c_enb2_s {
+               uint64_t clr:64;
+       } s;
+       struct cvmx_sli_msi_w1c_enb2_s cn61xx;
+       struct cvmx_sli_msi_w1c_enb2_s cn63xx;
+       struct cvmx_sli_msi_w1c_enb2_s cn63xxp1;
+       struct cvmx_sli_msi_w1c_enb2_s cn66xx;
+       struct cvmx_sli_msi_w1c_enb2_s cn68xx;
+       struct cvmx_sli_msi_w1c_enb2_s cn68xxp1;
+};
+
+union cvmx_sli_msi_w1c_enb3 {
+       uint64_t u64;
+       struct cvmx_sli_msi_w1c_enb3_s {
+               uint64_t clr:64;
+       } s;
+       struct cvmx_sli_msi_w1c_enb3_s cn61xx;
+       struct cvmx_sli_msi_w1c_enb3_s cn63xx;
+       struct cvmx_sli_msi_w1c_enb3_s cn63xxp1;
+       struct cvmx_sli_msi_w1c_enb3_s cn66xx;
+       struct cvmx_sli_msi_w1c_enb3_s cn68xx;
+       struct cvmx_sli_msi_w1c_enb3_s cn68xxp1;
+};
+
+union cvmx_sli_msi_w1s_enb0 {
+       uint64_t u64;
+       struct cvmx_sli_msi_w1s_enb0_s {
+               uint64_t set:64;
+       } s;
+       struct cvmx_sli_msi_w1s_enb0_s cn61xx;
+       struct cvmx_sli_msi_w1s_enb0_s cn63xx;
+       struct cvmx_sli_msi_w1s_enb0_s cn63xxp1;
+       struct cvmx_sli_msi_w1s_enb0_s cn66xx;
+       struct cvmx_sli_msi_w1s_enb0_s cn68xx;
+       struct cvmx_sli_msi_w1s_enb0_s cn68xxp1;
+};
+
+union cvmx_sli_msi_w1s_enb1 {
+       uint64_t u64;
+       struct cvmx_sli_msi_w1s_enb1_s {
+               uint64_t set:64;
+       } s;
+       struct cvmx_sli_msi_w1s_enb1_s cn61xx;
+       struct cvmx_sli_msi_w1s_enb1_s cn63xx;
+       struct cvmx_sli_msi_w1s_enb1_s cn63xxp1;
+       struct cvmx_sli_msi_w1s_enb1_s cn66xx;
+       struct cvmx_sli_msi_w1s_enb1_s cn68xx;
+       struct cvmx_sli_msi_w1s_enb1_s cn68xxp1;
+};
+
+union cvmx_sli_msi_w1s_enb2 {
+       uint64_t u64;
+       struct cvmx_sli_msi_w1s_enb2_s {
+               uint64_t set:64;
+       } s;
+       struct cvmx_sli_msi_w1s_enb2_s cn61xx;
+       struct cvmx_sli_msi_w1s_enb2_s cn63xx;
+       struct cvmx_sli_msi_w1s_enb2_s cn63xxp1;
+       struct cvmx_sli_msi_w1s_enb2_s cn66xx;
+       struct cvmx_sli_msi_w1s_enb2_s cn68xx;
+       struct cvmx_sli_msi_w1s_enb2_s cn68xxp1;
+};
+
+union cvmx_sli_msi_w1s_enb3 {
+       uint64_t u64;
+       struct cvmx_sli_msi_w1s_enb3_s {
+               uint64_t set:64;
+       } s;
+       struct cvmx_sli_msi_w1s_enb3_s cn61xx;
+       struct cvmx_sli_msi_w1s_enb3_s cn63xx;
+       struct cvmx_sli_msi_w1s_enb3_s cn63xxp1;
+       struct cvmx_sli_msi_w1s_enb3_s cn66xx;
+       struct cvmx_sli_msi_w1s_enb3_s cn68xx;
+       struct cvmx_sli_msi_w1s_enb3_s cn68xxp1;
+};
+
+union cvmx_sli_msi_wr_map {
+       uint64_t u64;
+       struct cvmx_sli_msi_wr_map_s {
+               uint64_t reserved_16_63:48;
+               uint64_t ciu_int:8;
+               uint64_t msi_int:8;
+       } s;
+       struct cvmx_sli_msi_wr_map_s cn61xx;
+       struct cvmx_sli_msi_wr_map_s cn63xx;
+       struct cvmx_sli_msi_wr_map_s cn63xxp1;
+       struct cvmx_sli_msi_wr_map_s cn66xx;
+       struct cvmx_sli_msi_wr_map_s cn68xx;
+       struct cvmx_sli_msi_wr_map_s cn68xxp1;
+};
+
+union cvmx_sli_pcie_msi_rcv {
+       uint64_t u64;
+       struct cvmx_sli_pcie_msi_rcv_s {
+               uint64_t reserved_8_63:56;
+               uint64_t intr:8;
+       } s;
+       struct cvmx_sli_pcie_msi_rcv_s cn61xx;
+       struct cvmx_sli_pcie_msi_rcv_s cn63xx;
+       struct cvmx_sli_pcie_msi_rcv_s cn63xxp1;
+       struct cvmx_sli_pcie_msi_rcv_s cn66xx;
+       struct cvmx_sli_pcie_msi_rcv_s cn68xx;
+       struct cvmx_sli_pcie_msi_rcv_s cn68xxp1;
+};
+
+union cvmx_sli_pcie_msi_rcv_b1 {
+       uint64_t u64;
+       struct cvmx_sli_pcie_msi_rcv_b1_s {
+               uint64_t reserved_16_63:48;
+               uint64_t intr:8;
+               uint64_t reserved_0_7:8;
+       } s;
+       struct cvmx_sli_pcie_msi_rcv_b1_s cn61xx;
+       struct cvmx_sli_pcie_msi_rcv_b1_s cn63xx;
+       struct cvmx_sli_pcie_msi_rcv_b1_s cn63xxp1;
+       struct cvmx_sli_pcie_msi_rcv_b1_s cn66xx;
+       struct cvmx_sli_pcie_msi_rcv_b1_s cn68xx;
+       struct cvmx_sli_pcie_msi_rcv_b1_s cn68xxp1;
+};
+
+union cvmx_sli_pcie_msi_rcv_b2 {
+       uint64_t u64;
+       struct cvmx_sli_pcie_msi_rcv_b2_s {
+               uint64_t reserved_24_63:40;
+               uint64_t intr:8;
+               uint64_t reserved_0_15:16;
+       } s;
+       struct cvmx_sli_pcie_msi_rcv_b2_s cn61xx;
+       struct cvmx_sli_pcie_msi_rcv_b2_s cn63xx;
+       struct cvmx_sli_pcie_msi_rcv_b2_s cn63xxp1;
+       struct cvmx_sli_pcie_msi_rcv_b2_s cn66xx;
+       struct cvmx_sli_pcie_msi_rcv_b2_s cn68xx;
+       struct cvmx_sli_pcie_msi_rcv_b2_s cn68xxp1;
+};
+
+union cvmx_sli_pcie_msi_rcv_b3 {
+       uint64_t u64;
+       struct cvmx_sli_pcie_msi_rcv_b3_s {
+               uint64_t reserved_32_63:32;
+               uint64_t intr:8;
+               uint64_t reserved_0_23:24;
+       } s;
+       struct cvmx_sli_pcie_msi_rcv_b3_s cn61xx;
+       struct cvmx_sli_pcie_msi_rcv_b3_s cn63xx;
+       struct cvmx_sli_pcie_msi_rcv_b3_s cn63xxp1;
+       struct cvmx_sli_pcie_msi_rcv_b3_s cn66xx;
+       struct cvmx_sli_pcie_msi_rcv_b3_s cn68xx;
+       struct cvmx_sli_pcie_msi_rcv_b3_s cn68xxp1;
+};
+
+union cvmx_sli_pktx_cnts {
+       uint64_t u64;
+       struct cvmx_sli_pktx_cnts_s {
+               uint64_t reserved_54_63:10;
+               uint64_t timer:22;
+               uint64_t cnt:32;
+       } s;
+       struct cvmx_sli_pktx_cnts_s cn61xx;
+       struct cvmx_sli_pktx_cnts_s cn63xx;
+       struct cvmx_sli_pktx_cnts_s cn63xxp1;
+       struct cvmx_sli_pktx_cnts_s cn66xx;
+       struct cvmx_sli_pktx_cnts_s cn68xx;
+       struct cvmx_sli_pktx_cnts_s cn68xxp1;
+};
+
+union cvmx_sli_pktx_in_bp {
+       uint64_t u64;
+       struct cvmx_sli_pktx_in_bp_s {
+               uint64_t wmark:32;
+               uint64_t cnt:32;
+       } s;
+       struct cvmx_sli_pktx_in_bp_s cn61xx;
+       struct cvmx_sli_pktx_in_bp_s cn63xx;
+       struct cvmx_sli_pktx_in_bp_s cn63xxp1;
+       struct cvmx_sli_pktx_in_bp_s cn66xx;
+};
+
+union cvmx_sli_pktx_instr_baddr {
+       uint64_t u64;
+       struct cvmx_sli_pktx_instr_baddr_s {
+               uint64_t addr:61;
+               uint64_t reserved_0_2:3;
+       } s;
+       struct cvmx_sli_pktx_instr_baddr_s cn61xx;
+       struct cvmx_sli_pktx_instr_baddr_s cn63xx;
+       struct cvmx_sli_pktx_instr_baddr_s cn63xxp1;
+       struct cvmx_sli_pktx_instr_baddr_s cn66xx;
+       struct cvmx_sli_pktx_instr_baddr_s cn68xx;
+       struct cvmx_sli_pktx_instr_baddr_s cn68xxp1;
+};
+
+union cvmx_sli_pktx_instr_baoff_dbell {
+       uint64_t u64;
+       struct cvmx_sli_pktx_instr_baoff_dbell_s {
+               uint64_t aoff:32;
+               uint64_t dbell:32;
+       } s;
+       struct cvmx_sli_pktx_instr_baoff_dbell_s cn61xx;
+       struct cvmx_sli_pktx_instr_baoff_dbell_s cn63xx;
+       struct cvmx_sli_pktx_instr_baoff_dbell_s cn63xxp1;
+       struct cvmx_sli_pktx_instr_baoff_dbell_s cn66xx;
+       struct cvmx_sli_pktx_instr_baoff_dbell_s cn68xx;
+       struct cvmx_sli_pktx_instr_baoff_dbell_s cn68xxp1;
+};
+
+union cvmx_sli_pktx_instr_fifo_rsize {
+       uint64_t u64;
+       struct cvmx_sli_pktx_instr_fifo_rsize_s {
+               uint64_t max:9;
+               uint64_t rrp:9;
+               uint64_t wrp:9;
+               uint64_t fcnt:5;
+               uint64_t rsize:32;
+       } s;
+       struct cvmx_sli_pktx_instr_fifo_rsize_s cn61xx;
+       struct cvmx_sli_pktx_instr_fifo_rsize_s cn63xx;
+       struct cvmx_sli_pktx_instr_fifo_rsize_s cn63xxp1;
+       struct cvmx_sli_pktx_instr_fifo_rsize_s cn66xx;
+       struct cvmx_sli_pktx_instr_fifo_rsize_s cn68xx;
+       struct cvmx_sli_pktx_instr_fifo_rsize_s cn68xxp1;
+};
+
+union cvmx_sli_pktx_instr_header {
+       uint64_t u64;
+       struct cvmx_sli_pktx_instr_header_s {
+               uint64_t reserved_44_63:20;
+               uint64_t pbp:1;
+               uint64_t reserved_38_42:5;
+               uint64_t rparmode:2;
+               uint64_t reserved_35_35:1;
+               uint64_t rskp_len:7;
+               uint64_t rngrpext:2;
+               uint64_t rnqos:1;
+               uint64_t rngrp:1;
+               uint64_t rntt:1;
+               uint64_t rntag:1;
+               uint64_t use_ihdr:1;
+               uint64_t reserved_16_20:5;
+               uint64_t par_mode:2;
+               uint64_t reserved_13_13:1;
+               uint64_t skp_len:7;
+               uint64_t ngrpext:2;
+               uint64_t nqos:1;
+               uint64_t ngrp:1;
+               uint64_t ntt:1;
+               uint64_t ntag:1;
+       } s;
+       struct cvmx_sli_pktx_instr_header_cn61xx {
+               uint64_t reserved_44_63:20;
+               uint64_t pbp:1;
+               uint64_t reserved_38_42:5;
+               uint64_t rparmode:2;
+               uint64_t reserved_35_35:1;
+               uint64_t rskp_len:7;
+               uint64_t reserved_26_27:2;
+               uint64_t rnqos:1;
+               uint64_t rngrp:1;
+               uint64_t rntt:1;
+               uint64_t rntag:1;
+               uint64_t use_ihdr:1;
+               uint64_t reserved_16_20:5;
+               uint64_t par_mode:2;
+               uint64_t reserved_13_13:1;
+               uint64_t skp_len:7;
+               uint64_t reserved_4_5:2;
+               uint64_t nqos:1;
+               uint64_t ngrp:1;
+               uint64_t ntt:1;
+               uint64_t ntag:1;
+       } cn61xx;
+       struct cvmx_sli_pktx_instr_header_cn61xx cn63xx;
+       struct cvmx_sli_pktx_instr_header_cn61xx cn63xxp1;
+       struct cvmx_sli_pktx_instr_header_cn61xx cn66xx;
+       struct cvmx_sli_pktx_instr_header_s cn68xx;
+       struct cvmx_sli_pktx_instr_header_cn61xx cn68xxp1;
+};
+
+union cvmx_sli_pktx_out_size {
+       uint64_t u64;
+       struct cvmx_sli_pktx_out_size_s {
+               uint64_t reserved_23_63:41;
+               uint64_t isize:7;
+               uint64_t bsize:16;
+       } s;
+       struct cvmx_sli_pktx_out_size_s cn61xx;
+       struct cvmx_sli_pktx_out_size_s cn63xx;
+       struct cvmx_sli_pktx_out_size_s cn63xxp1;
+       struct cvmx_sli_pktx_out_size_s cn66xx;
+       struct cvmx_sli_pktx_out_size_s cn68xx;
+       struct cvmx_sli_pktx_out_size_s cn68xxp1;
+};
+
+union cvmx_sli_pktx_slist_baddr {
+       uint64_t u64;
+       struct cvmx_sli_pktx_slist_baddr_s {
+               uint64_t addr:60;
+               uint64_t reserved_0_3:4;
+       } s;
+       struct cvmx_sli_pktx_slist_baddr_s cn61xx;
+       struct cvmx_sli_pktx_slist_baddr_s cn63xx;
+       struct cvmx_sli_pktx_slist_baddr_s cn63xxp1;
+       struct cvmx_sli_pktx_slist_baddr_s cn66xx;
+       struct cvmx_sli_pktx_slist_baddr_s cn68xx;
+       struct cvmx_sli_pktx_slist_baddr_s cn68xxp1;
+};
+
+union cvmx_sli_pktx_slist_baoff_dbell {
+       uint64_t u64;
+       struct cvmx_sli_pktx_slist_baoff_dbell_s {
+               uint64_t aoff:32;
+               uint64_t dbell:32;
+       } s;
+       struct cvmx_sli_pktx_slist_baoff_dbell_s cn61xx;
+       struct cvmx_sli_pktx_slist_baoff_dbell_s cn63xx;
+       struct cvmx_sli_pktx_slist_baoff_dbell_s cn63xxp1;
+       struct cvmx_sli_pktx_slist_baoff_dbell_s cn66xx;
+       struct cvmx_sli_pktx_slist_baoff_dbell_s cn68xx;
+       struct cvmx_sli_pktx_slist_baoff_dbell_s cn68xxp1;
+};
+
+union cvmx_sli_pktx_slist_fifo_rsize {
+       uint64_t u64;
+       struct cvmx_sli_pktx_slist_fifo_rsize_s {
+               uint64_t reserved_32_63:32;
+               uint64_t rsize:32;
+       } s;
+       struct cvmx_sli_pktx_slist_fifo_rsize_s cn61xx;
+       struct cvmx_sli_pktx_slist_fifo_rsize_s cn63xx;
+       struct cvmx_sli_pktx_slist_fifo_rsize_s cn63xxp1;
+       struct cvmx_sli_pktx_slist_fifo_rsize_s cn66xx;
+       struct cvmx_sli_pktx_slist_fifo_rsize_s cn68xx;
+       struct cvmx_sli_pktx_slist_fifo_rsize_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_cnt_int {
+       uint64_t u64;
+       struct cvmx_sli_pkt_cnt_int_s {
+               uint64_t reserved_32_63:32;
+               uint64_t port:32;
+       } s;
+       struct cvmx_sli_pkt_cnt_int_s cn61xx;
+       struct cvmx_sli_pkt_cnt_int_s cn63xx;
+       struct cvmx_sli_pkt_cnt_int_s cn63xxp1;
+       struct cvmx_sli_pkt_cnt_int_s cn66xx;
+       struct cvmx_sli_pkt_cnt_int_s cn68xx;
+       struct cvmx_sli_pkt_cnt_int_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_cnt_int_enb {
+       uint64_t u64;
+       struct cvmx_sli_pkt_cnt_int_enb_s {
+               uint64_t reserved_32_63:32;
+               uint64_t port:32;
+       } s;
+       struct cvmx_sli_pkt_cnt_int_enb_s cn61xx;
+       struct cvmx_sli_pkt_cnt_int_enb_s cn63xx;
+       struct cvmx_sli_pkt_cnt_int_enb_s cn63xxp1;
+       struct cvmx_sli_pkt_cnt_int_enb_s cn66xx;
+       struct cvmx_sli_pkt_cnt_int_enb_s cn68xx;
+       struct cvmx_sli_pkt_cnt_int_enb_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_ctl {
+       uint64_t u64;
+       struct cvmx_sli_pkt_ctl_s {
+               uint64_t reserved_5_63:59;
+               uint64_t ring_en:1;
+               uint64_t pkt_bp:4;
+       } s;
+       struct cvmx_sli_pkt_ctl_s cn61xx;
+       struct cvmx_sli_pkt_ctl_s cn63xx;
+       struct cvmx_sli_pkt_ctl_s cn63xxp1;
+       struct cvmx_sli_pkt_ctl_s cn66xx;
+       struct cvmx_sli_pkt_ctl_s cn68xx;
+       struct cvmx_sli_pkt_ctl_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_data_out_es {
+       uint64_t u64;
+       struct cvmx_sli_pkt_data_out_es_s {
+               uint64_t es:64;
+       } s;
+       struct cvmx_sli_pkt_data_out_es_s cn61xx;
+       struct cvmx_sli_pkt_data_out_es_s cn63xx;
+       struct cvmx_sli_pkt_data_out_es_s cn63xxp1;
+       struct cvmx_sli_pkt_data_out_es_s cn66xx;
+       struct cvmx_sli_pkt_data_out_es_s cn68xx;
+       struct cvmx_sli_pkt_data_out_es_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_data_out_ns {
+       uint64_t u64;
+       struct cvmx_sli_pkt_data_out_ns_s {
+               uint64_t reserved_32_63:32;
+               uint64_t nsr:32;
+       } s;
+       struct cvmx_sli_pkt_data_out_ns_s cn61xx;
+       struct cvmx_sli_pkt_data_out_ns_s cn63xx;
+       struct cvmx_sli_pkt_data_out_ns_s cn63xxp1;
+       struct cvmx_sli_pkt_data_out_ns_s cn66xx;
+       struct cvmx_sli_pkt_data_out_ns_s cn68xx;
+       struct cvmx_sli_pkt_data_out_ns_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_data_out_ror {
+       uint64_t u64;
+       struct cvmx_sli_pkt_data_out_ror_s {
+               uint64_t reserved_32_63:32;
+               uint64_t ror:32;
+       } s;
+       struct cvmx_sli_pkt_data_out_ror_s cn61xx;
+       struct cvmx_sli_pkt_data_out_ror_s cn63xx;
+       struct cvmx_sli_pkt_data_out_ror_s cn63xxp1;
+       struct cvmx_sli_pkt_data_out_ror_s cn66xx;
+       struct cvmx_sli_pkt_data_out_ror_s cn68xx;
+       struct cvmx_sli_pkt_data_out_ror_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_dpaddr {
+       uint64_t u64;
+       struct cvmx_sli_pkt_dpaddr_s {
+               uint64_t reserved_32_63:32;
+               uint64_t dptr:32;
+       } s;
+       struct cvmx_sli_pkt_dpaddr_s cn61xx;
+       struct cvmx_sli_pkt_dpaddr_s cn63xx;
+       struct cvmx_sli_pkt_dpaddr_s cn63xxp1;
+       struct cvmx_sli_pkt_dpaddr_s cn66xx;
+       struct cvmx_sli_pkt_dpaddr_s cn68xx;
+       struct cvmx_sli_pkt_dpaddr_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_in_bp {
+       uint64_t u64;
+       struct cvmx_sli_pkt_in_bp_s {
+               uint64_t reserved_32_63:32;
+               uint64_t bp:32;
+       } s;
+       struct cvmx_sli_pkt_in_bp_s cn61xx;
+       struct cvmx_sli_pkt_in_bp_s cn63xx;
+       struct cvmx_sli_pkt_in_bp_s cn63xxp1;
+       struct cvmx_sli_pkt_in_bp_s cn66xx;
+};
+
+union cvmx_sli_pkt_in_donex_cnts {
+       uint64_t u64;
+       struct cvmx_sli_pkt_in_donex_cnts_s {
+               uint64_t reserved_32_63:32;
+               uint64_t cnt:32;
+       } s;
+       struct cvmx_sli_pkt_in_donex_cnts_s cn61xx;
+       struct cvmx_sli_pkt_in_donex_cnts_s cn63xx;
+       struct cvmx_sli_pkt_in_donex_cnts_s cn63xxp1;
+       struct cvmx_sli_pkt_in_donex_cnts_s cn66xx;
+       struct cvmx_sli_pkt_in_donex_cnts_s cn68xx;
+       struct cvmx_sli_pkt_in_donex_cnts_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_in_instr_counts {
+       uint64_t u64;
+       struct cvmx_sli_pkt_in_instr_counts_s {
+               uint64_t wr_cnt:32;
+               uint64_t rd_cnt:32;
+       } s;
+       struct cvmx_sli_pkt_in_instr_counts_s cn61xx;
+       struct cvmx_sli_pkt_in_instr_counts_s cn63xx;
+       struct cvmx_sli_pkt_in_instr_counts_s cn63xxp1;
+       struct cvmx_sli_pkt_in_instr_counts_s cn66xx;
+       struct cvmx_sli_pkt_in_instr_counts_s cn68xx;
+       struct cvmx_sli_pkt_in_instr_counts_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_in_pcie_port {
+       uint64_t u64;
+       struct cvmx_sli_pkt_in_pcie_port_s {
+               uint64_t pp:64;
+       } s;
+       struct cvmx_sli_pkt_in_pcie_port_s cn61xx;
+       struct cvmx_sli_pkt_in_pcie_port_s cn63xx;
+       struct cvmx_sli_pkt_in_pcie_port_s cn63xxp1;
+       struct cvmx_sli_pkt_in_pcie_port_s cn66xx;
+       struct cvmx_sli_pkt_in_pcie_port_s cn68xx;
+       struct cvmx_sli_pkt_in_pcie_port_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_input_control {
+       uint64_t u64;
+       struct cvmx_sli_pkt_input_control_s {
+               uint64_t prd_erst:1;
+               uint64_t prd_rds:7;
+               uint64_t gii_erst:1;
+               uint64_t gii_rds:7;
+               uint64_t reserved_41_47:7;
+               uint64_t prc_idle:1;
+               uint64_t reserved_24_39:16;
+               uint64_t pin_rst:1;
+               uint64_t pkt_rr:1;
+               uint64_t pbp_dhi:13;
+               uint64_t d_nsr:1;
+               uint64_t d_esr:2;
+               uint64_t d_ror:1;
+               uint64_t use_csr:1;
+               uint64_t nsr:1;
+               uint64_t esr:2;
+               uint64_t ror:1;
+       } s;
+       struct cvmx_sli_pkt_input_control_s cn61xx;
+       struct cvmx_sli_pkt_input_control_cn63xx {
+               uint64_t reserved_23_63:41;
+               uint64_t pkt_rr:1;
+               uint64_t pbp_dhi:13;
+               uint64_t d_nsr:1;
+               uint64_t d_esr:2;
+               uint64_t d_ror:1;
+               uint64_t use_csr:1;
+               uint64_t nsr:1;
+               uint64_t esr:2;
+               uint64_t ror:1;
+       } cn63xx;
+       struct cvmx_sli_pkt_input_control_cn63xx cn63xxp1;
+       struct cvmx_sli_pkt_input_control_s cn66xx;
+       struct cvmx_sli_pkt_input_control_s cn68xx;
+       struct cvmx_sli_pkt_input_control_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_instr_enb {
+       uint64_t u64;
+       struct cvmx_sli_pkt_instr_enb_s {
+               uint64_t reserved_32_63:32;
+               uint64_t enb:32;
+       } s;
+       struct cvmx_sli_pkt_instr_enb_s cn61xx;
+       struct cvmx_sli_pkt_instr_enb_s cn63xx;
+       struct cvmx_sli_pkt_instr_enb_s cn63xxp1;
+       struct cvmx_sli_pkt_instr_enb_s cn66xx;
+       struct cvmx_sli_pkt_instr_enb_s cn68xx;
+       struct cvmx_sli_pkt_instr_enb_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_instr_rd_size {
+       uint64_t u64;
+       struct cvmx_sli_pkt_instr_rd_size_s {
+               uint64_t rdsize:64;
+       } s;
+       struct cvmx_sli_pkt_instr_rd_size_s cn61xx;
+       struct cvmx_sli_pkt_instr_rd_size_s cn63xx;
+       struct cvmx_sli_pkt_instr_rd_size_s cn63xxp1;
+       struct cvmx_sli_pkt_instr_rd_size_s cn66xx;
+       struct cvmx_sli_pkt_instr_rd_size_s cn68xx;
+       struct cvmx_sli_pkt_instr_rd_size_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_instr_size {
+       uint64_t u64;
+       struct cvmx_sli_pkt_instr_size_s {
+               uint64_t reserved_32_63:32;
+               uint64_t is_64b:32;
+       } s;
+       struct cvmx_sli_pkt_instr_size_s cn61xx;
+       struct cvmx_sli_pkt_instr_size_s cn63xx;
+       struct cvmx_sli_pkt_instr_size_s cn63xxp1;
+       struct cvmx_sli_pkt_instr_size_s cn66xx;
+       struct cvmx_sli_pkt_instr_size_s cn68xx;
+       struct cvmx_sli_pkt_instr_size_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_int_levels {
+       uint64_t u64;
+       struct cvmx_sli_pkt_int_levels_s {
+               uint64_t reserved_54_63:10;
+               uint64_t time:22;
+               uint64_t cnt:32;
+       } s;
+       struct cvmx_sli_pkt_int_levels_s cn61xx;
+       struct cvmx_sli_pkt_int_levels_s cn63xx;
+       struct cvmx_sli_pkt_int_levels_s cn63xxp1;
+       struct cvmx_sli_pkt_int_levels_s cn66xx;
+       struct cvmx_sli_pkt_int_levels_s cn68xx;
+       struct cvmx_sli_pkt_int_levels_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_iptr {
+       uint64_t u64;
+       struct cvmx_sli_pkt_iptr_s {
+               uint64_t reserved_32_63:32;
+               uint64_t iptr:32;
+       } s;
+       struct cvmx_sli_pkt_iptr_s cn61xx;
+       struct cvmx_sli_pkt_iptr_s cn63xx;
+       struct cvmx_sli_pkt_iptr_s cn63xxp1;
+       struct cvmx_sli_pkt_iptr_s cn66xx;
+       struct cvmx_sli_pkt_iptr_s cn68xx;
+       struct cvmx_sli_pkt_iptr_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_out_bmode {
+       uint64_t u64;
+       struct cvmx_sli_pkt_out_bmode_s {
+               uint64_t reserved_32_63:32;
+               uint64_t bmode:32;
+       } s;
+       struct cvmx_sli_pkt_out_bmode_s cn61xx;
+       struct cvmx_sli_pkt_out_bmode_s cn63xx;
+       struct cvmx_sli_pkt_out_bmode_s cn63xxp1;
+       struct cvmx_sli_pkt_out_bmode_s cn66xx;
+       struct cvmx_sli_pkt_out_bmode_s cn68xx;
+       struct cvmx_sli_pkt_out_bmode_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_out_bp_en {
+       uint64_t u64;
+       struct cvmx_sli_pkt_out_bp_en_s {
+               uint64_t reserved_32_63:32;
+               uint64_t bp_en:32;
+       } s;
+       struct cvmx_sli_pkt_out_bp_en_s cn68xx;
+       struct cvmx_sli_pkt_out_bp_en_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_out_enb {
+       uint64_t u64;
+       struct cvmx_sli_pkt_out_enb_s {
+               uint64_t reserved_32_63:32;
+               uint64_t enb:32;
+       } s;
+       struct cvmx_sli_pkt_out_enb_s cn61xx;
+       struct cvmx_sli_pkt_out_enb_s cn63xx;
+       struct cvmx_sli_pkt_out_enb_s cn63xxp1;
+       struct cvmx_sli_pkt_out_enb_s cn66xx;
+       struct cvmx_sli_pkt_out_enb_s cn68xx;
+       struct cvmx_sli_pkt_out_enb_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_output_wmark {
+       uint64_t u64;
+       struct cvmx_sli_pkt_output_wmark_s {
+               uint64_t reserved_32_63:32;
+               uint64_t wmark:32;
+       } s;
+       struct cvmx_sli_pkt_output_wmark_s cn61xx;
+       struct cvmx_sli_pkt_output_wmark_s cn63xx;
+       struct cvmx_sli_pkt_output_wmark_s cn63xxp1;
+       struct cvmx_sli_pkt_output_wmark_s cn66xx;
+       struct cvmx_sli_pkt_output_wmark_s cn68xx;
+       struct cvmx_sli_pkt_output_wmark_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_pcie_port {
+       uint64_t u64;
+       struct cvmx_sli_pkt_pcie_port_s {
+               uint64_t pp:64;
+       } s;
+       struct cvmx_sli_pkt_pcie_port_s cn61xx;
+       struct cvmx_sli_pkt_pcie_port_s cn63xx;
+       struct cvmx_sli_pkt_pcie_port_s cn63xxp1;
+       struct cvmx_sli_pkt_pcie_port_s cn66xx;
+       struct cvmx_sli_pkt_pcie_port_s cn68xx;
+       struct cvmx_sli_pkt_pcie_port_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_port_in_rst {
+       uint64_t u64;
+       struct cvmx_sli_pkt_port_in_rst_s {
+               uint64_t in_rst:32;
+               uint64_t out_rst:32;
+       } s;
+       struct cvmx_sli_pkt_port_in_rst_s cn61xx;
+       struct cvmx_sli_pkt_port_in_rst_s cn63xx;
+       struct cvmx_sli_pkt_port_in_rst_s cn63xxp1;
+       struct cvmx_sli_pkt_port_in_rst_s cn66xx;
+       struct cvmx_sli_pkt_port_in_rst_s cn68xx;
+       struct cvmx_sli_pkt_port_in_rst_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_slist_es {
+       uint64_t u64;
+       struct cvmx_sli_pkt_slist_es_s {
+               uint64_t es:64;
+       } s;
+       struct cvmx_sli_pkt_slist_es_s cn61xx;
+       struct cvmx_sli_pkt_slist_es_s cn63xx;
+       struct cvmx_sli_pkt_slist_es_s cn63xxp1;
+       struct cvmx_sli_pkt_slist_es_s cn66xx;
+       struct cvmx_sli_pkt_slist_es_s cn68xx;
+       struct cvmx_sli_pkt_slist_es_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_slist_ns {
+       uint64_t u64;
+       struct cvmx_sli_pkt_slist_ns_s {
+               uint64_t reserved_32_63:32;
+               uint64_t nsr:32;
+       } s;
+       struct cvmx_sli_pkt_slist_ns_s cn61xx;
+       struct cvmx_sli_pkt_slist_ns_s cn63xx;
+       struct cvmx_sli_pkt_slist_ns_s cn63xxp1;
+       struct cvmx_sli_pkt_slist_ns_s cn66xx;
+       struct cvmx_sli_pkt_slist_ns_s cn68xx;
+       struct cvmx_sli_pkt_slist_ns_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_slist_ror {
+       uint64_t u64;
+       struct cvmx_sli_pkt_slist_ror_s {
+               uint64_t reserved_32_63:32;
+               uint64_t ror:32;
+       } s;
+       struct cvmx_sli_pkt_slist_ror_s cn61xx;
+       struct cvmx_sli_pkt_slist_ror_s cn63xx;
+       struct cvmx_sli_pkt_slist_ror_s cn63xxp1;
+       struct cvmx_sli_pkt_slist_ror_s cn66xx;
+       struct cvmx_sli_pkt_slist_ror_s cn68xx;
+       struct cvmx_sli_pkt_slist_ror_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_time_int {
+       uint64_t u64;
+       struct cvmx_sli_pkt_time_int_s {
+               uint64_t reserved_32_63:32;
+               uint64_t port:32;
+       } s;
+       struct cvmx_sli_pkt_time_int_s cn61xx;
+       struct cvmx_sli_pkt_time_int_s cn63xx;
+       struct cvmx_sli_pkt_time_int_s cn63xxp1;
+       struct cvmx_sli_pkt_time_int_s cn66xx;
+       struct cvmx_sli_pkt_time_int_s cn68xx;
+       struct cvmx_sli_pkt_time_int_s cn68xxp1;
+};
+
+union cvmx_sli_pkt_time_int_enb {
+       uint64_t u64;
+       struct cvmx_sli_pkt_time_int_enb_s {
+               uint64_t reserved_32_63:32;
+               uint64_t port:32;
+       } s;
+       struct cvmx_sli_pkt_time_int_enb_s cn61xx;
+       struct cvmx_sli_pkt_time_int_enb_s cn63xx;
+       struct cvmx_sli_pkt_time_int_enb_s cn63xxp1;
+       struct cvmx_sli_pkt_time_int_enb_s cn66xx;
+       struct cvmx_sli_pkt_time_int_enb_s cn68xx;
+       struct cvmx_sli_pkt_time_int_enb_s cn68xxp1;
+};
+
+union cvmx_sli_portx_pkind {
+       uint64_t u64;
+       struct cvmx_sli_portx_pkind_s {
+               uint64_t reserved_25_63:39;
+               uint64_t rpk_enb:1;
+               uint64_t reserved_22_23:2;
+               uint64_t pkindr:6;
+               uint64_t reserved_14_15:2;
+               uint64_t bpkind:6;
+               uint64_t reserved_6_7:2;
+               uint64_t pkind:6;
+       } s;
+       struct cvmx_sli_portx_pkind_s cn68xx;
+       struct cvmx_sli_portx_pkind_cn68xxp1 {
+               uint64_t reserved_14_63:50;
+               uint64_t bpkind:6;
+               uint64_t reserved_6_7:2;
+               uint64_t pkind:6;
+       } cn68xxp1;
+};
+
+union cvmx_sli_s2m_portx_ctl {
+       uint64_t u64;
+       struct cvmx_sli_s2m_portx_ctl_s {
+               uint64_t reserved_5_63:59;
+               uint64_t wind_d:1;
+               uint64_t bar0_d:1;
+               uint64_t mrrs:3;
+       } s;
+       struct cvmx_sli_s2m_portx_ctl_s cn61xx;
+       struct cvmx_sli_s2m_portx_ctl_s cn63xx;
+       struct cvmx_sli_s2m_portx_ctl_s cn63xxp1;
+       struct cvmx_sli_s2m_portx_ctl_s cn66xx;
+       struct cvmx_sli_s2m_portx_ctl_s cn68xx;
+       struct cvmx_sli_s2m_portx_ctl_s cn68xxp1;
+};
+
+union cvmx_sli_scratch_1 {
+       uint64_t u64;
+       struct cvmx_sli_scratch_1_s {
+               uint64_t data:64;
+       } s;
+       struct cvmx_sli_scratch_1_s cn61xx;
+       struct cvmx_sli_scratch_1_s cn63xx;
+       struct cvmx_sli_scratch_1_s cn63xxp1;
+       struct cvmx_sli_scratch_1_s cn66xx;
+       struct cvmx_sli_scratch_1_s cn68xx;
+       struct cvmx_sli_scratch_1_s cn68xxp1;
+};
+
+union cvmx_sli_scratch_2 {
+       uint64_t u64;
+       struct cvmx_sli_scratch_2_s {
+               uint64_t data:64;
+       } s;
+       struct cvmx_sli_scratch_2_s cn61xx;
+       struct cvmx_sli_scratch_2_s cn63xx;
+       struct cvmx_sli_scratch_2_s cn63xxp1;
+       struct cvmx_sli_scratch_2_s cn66xx;
+       struct cvmx_sli_scratch_2_s cn68xx;
+       struct cvmx_sli_scratch_2_s cn68xxp1;
+};
+
+union cvmx_sli_state1 {
+       uint64_t u64;
+       struct cvmx_sli_state1_s {
+               uint64_t cpl1:12;
+               uint64_t cpl0:12;
+               uint64_t arb:1;
+               uint64_t csr:39;
+       } s;
+       struct cvmx_sli_state1_s cn61xx;
+       struct cvmx_sli_state1_s cn63xx;
+       struct cvmx_sli_state1_s cn63xxp1;
+       struct cvmx_sli_state1_s cn66xx;
+       struct cvmx_sli_state1_s cn68xx;
+       struct cvmx_sli_state1_s cn68xxp1;
+};
+
+union cvmx_sli_state2 {
+       uint64_t u64;
+       struct cvmx_sli_state2_s {
+               uint64_t reserved_56_63:8;
+               uint64_t nnp1:8;
+               uint64_t reserved_47_47:1;
+               uint64_t rac:1;
+               uint64_t csm1:15;
+               uint64_t csm0:15;
+               uint64_t nnp0:8;
+               uint64_t nnd:8;
+       } s;
+       struct cvmx_sli_state2_s cn61xx;
+       struct cvmx_sli_state2_s cn63xx;
+       struct cvmx_sli_state2_s cn63xxp1;
+       struct cvmx_sli_state2_s cn66xx;
+       struct cvmx_sli_state2_s cn68xx;
+       struct cvmx_sli_state2_s cn68xxp1;
+};
+
+union cvmx_sli_state3 {
+       uint64_t u64;
+       struct cvmx_sli_state3_s {
+               uint64_t reserved_56_63:8;
+               uint64_t psm1:15;
+               uint64_t psm0:15;
+               uint64_t nsm1:13;
+               uint64_t nsm0:13;
+       } s;
+       struct cvmx_sli_state3_s cn61xx;
+       struct cvmx_sli_state3_s cn63xx;
+       struct cvmx_sli_state3_s cn63xxp1;
+       struct cvmx_sli_state3_s cn66xx;
+       struct cvmx_sli_state3_s cn68xx;
+       struct cvmx_sli_state3_s cn68xxp1;
+};
+
+union cvmx_sli_tx_pipe {
+       uint64_t u64;
+       struct cvmx_sli_tx_pipe_s {
+               uint64_t reserved_24_63:40;
+               uint64_t nump:8;
+               uint64_t reserved_7_15:9;
+               uint64_t base:7;
+       } s;
+       struct cvmx_sli_tx_pipe_s cn68xx;
+       struct cvmx_sli_tx_pipe_s cn68xxp1;
+};
+
+union cvmx_sli_win_rd_addr {
+       uint64_t u64;
+       struct cvmx_sli_win_rd_addr_s {
+               uint64_t reserved_51_63:13;
+               uint64_t ld_cmd:2;
+               uint64_t iobit:1;
+               uint64_t rd_addr:48;
+       } s;
+       struct cvmx_sli_win_rd_addr_s cn61xx;
+       struct cvmx_sli_win_rd_addr_s cn63xx;
+       struct cvmx_sli_win_rd_addr_s cn63xxp1;
+       struct cvmx_sli_win_rd_addr_s cn66xx;
+       struct cvmx_sli_win_rd_addr_s cn68xx;
+       struct cvmx_sli_win_rd_addr_s cn68xxp1;
+};
+
+union cvmx_sli_win_rd_data {
+       uint64_t u64;
+       struct cvmx_sli_win_rd_data_s {
+               uint64_t rd_data:64;
+       } s;
+       struct cvmx_sli_win_rd_data_s cn61xx;
+       struct cvmx_sli_win_rd_data_s cn63xx;
+       struct cvmx_sli_win_rd_data_s cn63xxp1;
+       struct cvmx_sli_win_rd_data_s cn66xx;
+       struct cvmx_sli_win_rd_data_s cn68xx;
+       struct cvmx_sli_win_rd_data_s cn68xxp1;
+};
+
+union cvmx_sli_win_wr_addr {
+       uint64_t u64;
+       struct cvmx_sli_win_wr_addr_s {
+               uint64_t reserved_49_63:15;
+               uint64_t iobit:1;
+               uint64_t wr_addr:45;
+               uint64_t reserved_0_2:3;
+       } s;
+       struct cvmx_sli_win_wr_addr_s cn61xx;
+       struct cvmx_sli_win_wr_addr_s cn63xx;
+       struct cvmx_sli_win_wr_addr_s cn63xxp1;
+       struct cvmx_sli_win_wr_addr_s cn66xx;
+       struct cvmx_sli_win_wr_addr_s cn68xx;
+       struct cvmx_sli_win_wr_addr_s cn68xxp1;
+};
+
+union cvmx_sli_win_wr_data {
+       uint64_t u64;
+       struct cvmx_sli_win_wr_data_s {
+               uint64_t wr_data:64;
+       } s;
+       struct cvmx_sli_win_wr_data_s cn61xx;
+       struct cvmx_sli_win_wr_data_s cn63xx;
+       struct cvmx_sli_win_wr_data_s cn63xxp1;
+       struct cvmx_sli_win_wr_data_s cn66xx;
+       struct cvmx_sli_win_wr_data_s cn68xx;
+       struct cvmx_sli_win_wr_data_s cn68xxp1;
+};
+
+union cvmx_sli_win_wr_mask {
+       uint64_t u64;
+       struct cvmx_sli_win_wr_mask_s {
+               uint64_t reserved_8_63:56;
+               uint64_t wr_mask:8;
+       } s;
+       struct cvmx_sli_win_wr_mask_s cn61xx;
+       struct cvmx_sli_win_wr_mask_s cn63xx;
+       struct cvmx_sli_win_wr_mask_s cn63xxp1;
+       struct cvmx_sli_win_wr_mask_s cn66xx;
+       struct cvmx_sli_win_wr_mask_s cn68xx;
+       struct cvmx_sli_win_wr_mask_s cn68xxp1;
+};
+
+union cvmx_sli_window_ctl {
+       uint64_t u64;
+       struct cvmx_sli_window_ctl_s {
+               uint64_t reserved_32_63:32;
+               uint64_t time:32;
+       } s;
+       struct cvmx_sli_window_ctl_s cn61xx;
+       struct cvmx_sli_window_ctl_s cn63xx;
+       struct cvmx_sli_window_ctl_s cn63xxp1;
+       struct cvmx_sli_window_ctl_s cn66xx;
+       struct cvmx_sli_window_ctl_s cn68xx;
+       struct cvmx_sli_window_ctl_s cn68xxp1;
+};
+
+#endif
diff --git a/arch/mips/include/asm/octeon/cvmx-sriox-defs.h b/arch/mips/include/asm/octeon/cvmx-sriox-defs.h
new file mode 100644 (file)
index 0000000..7be7e9e
--- /dev/null
@@ -0,0 +1,1036 @@
+/***********************license start***************
+ * Author: Cavium Networks
+ *
+ * Contact: support@caviumnetworks.com
+ * This file is part of the OCTEON SDK
+ *
+ * Copyright (c) 2003-2011 Cavium Networks
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * or visit http://www.gnu.org/licenses/.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium Networks for more information
+ ***********************license end**************************************/
+
+#ifndef __CVMX_SRIOX_DEFS_H__
+#define __CVMX_SRIOX_DEFS_H__
+
+#define CVMX_SRIOX_ACC_CTRL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000148ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_ASMBLY_ID(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000200ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_ASMBLY_INFO(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000208ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_BELL_RESP_CTRL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000310ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_BIST_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000108ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_IMSG_CTRL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000508ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_IMSG_INST_HDRX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000510ull) + (((offset) & 1) + ((block_id) & 3) * 0x200000ull) * 8)
+#define CVMX_SRIOX_IMSG_QOS_GRPX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000600ull) + (((offset) & 31) + ((block_id) & 3) * 0x200000ull) * 8)
+#define CVMX_SRIOX_IMSG_STATUSX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000700ull) + (((offset) & 31) + ((block_id) & 3) * 0x200000ull) * 8)
+#define CVMX_SRIOX_IMSG_VPORT_THR(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000500ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_IMSG_VPORT_THR2(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000528ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_INT2_ENABLE(block_id) (CVMX_ADD_IO_SEG(0x00011800C80003E0ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_INT2_REG(block_id) (CVMX_ADD_IO_SEG(0x00011800C80003E8ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_INT_ENABLE(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000110ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_INT_INFO0(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000120ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_INT_INFO1(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000128ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_INT_INFO2(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000130ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_INT_INFO3(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000138ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_INT_REG(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000118ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_IP_FEATURE(block_id) (CVMX_ADD_IO_SEG(0x00011800C80003F8ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_MAC_BUFFERS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000390ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_MAINT_OP(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000158ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_MAINT_RD_DATA(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000160ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_MCE_TX_CTL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000240ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_MEM_OP_CTRL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000168ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_OMSG_CTRLX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000488ull) + (((offset) & 1) + ((block_id) & 3) * 0x40000ull) * 64)
+#define CVMX_SRIOX_OMSG_DONE_COUNTSX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C80004B0ull) + (((offset) & 1) + ((block_id) & 3) * 0x40000ull) * 64)
+#define CVMX_SRIOX_OMSG_FMP_MRX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000498ull) + (((offset) & 1) + ((block_id) & 3) * 0x40000ull) * 64)
+#define CVMX_SRIOX_OMSG_NMP_MRX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C80004A0ull) + (((offset) & 1) + ((block_id) & 3) * 0x40000ull) * 64)
+#define CVMX_SRIOX_OMSG_PORTX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000480ull) + (((offset) & 1) + ((block_id) & 3) * 0x40000ull) * 64)
+#define CVMX_SRIOX_OMSG_SILO_THR(block_id) (CVMX_ADD_IO_SEG(0x00011800C80004F8ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_OMSG_SP_MRX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000490ull) + (((offset) & 1) + ((block_id) & 3) * 0x40000ull) * 64)
+#define CVMX_SRIOX_PRIOX_IN_USE(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C80003C0ull) + (((offset) & 3) + ((block_id) & 3) * 0x200000ull) * 8)
+#define CVMX_SRIOX_RX_BELL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000308ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_RX_BELL_SEQ(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000300ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_RX_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000380ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_S2M_TYPEX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000180ull) + (((offset) & 15) + ((block_id) & 3) * 0x200000ull) * 8)
+#define CVMX_SRIOX_SEQ(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000278ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_STATUS_REG(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000100ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_TAG_CTRL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000178ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_TLP_CREDITS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000150ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_TX_BELL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000280ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_TX_BELL_INFO(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000288ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_TX_CTRL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000170ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_TX_EMPHASIS(block_id) (CVMX_ADD_IO_SEG(0x00011800C80003F0ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_TX_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000388ull) + ((block_id) & 3) * 0x1000000ull)
+#define CVMX_SRIOX_WR_DONE_COUNTS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000340ull) + ((block_id) & 3) * 0x1000000ull)
+
+union cvmx_sriox_acc_ctrl {
+       uint64_t u64;
+       struct cvmx_sriox_acc_ctrl_s {
+               uint64_t reserved_7_63:57;
+               uint64_t deny_adr2:1;
+               uint64_t deny_adr1:1;
+               uint64_t deny_adr0:1;
+               uint64_t reserved_3_3:1;
+               uint64_t deny_bar2:1;
+               uint64_t deny_bar1:1;
+               uint64_t deny_bar0:1;
+       } s;
+       struct cvmx_sriox_acc_ctrl_cn63xx {
+               uint64_t reserved_3_63:61;
+               uint64_t deny_bar2:1;
+               uint64_t deny_bar1:1;
+               uint64_t deny_bar0:1;
+       } cn63xx;
+       struct cvmx_sriox_acc_ctrl_cn63xx cn63xxp1;
+       struct cvmx_sriox_acc_ctrl_s cn66xx;
+};
+
+union cvmx_sriox_asmbly_id {
+       uint64_t u64;
+       struct cvmx_sriox_asmbly_id_s {
+               uint64_t reserved_32_63:32;
+               uint64_t assy_id:16;
+               uint64_t assy_ven:16;
+       } s;
+       struct cvmx_sriox_asmbly_id_s cn63xx;
+       struct cvmx_sriox_asmbly_id_s cn63xxp1;
+       struct cvmx_sriox_asmbly_id_s cn66xx;
+};
+
+union cvmx_sriox_asmbly_info {
+       uint64_t u64;
+       struct cvmx_sriox_asmbly_info_s {
+               uint64_t reserved_32_63:32;
+               uint64_t assy_rev:16;
+               uint64_t reserved_0_15:16;
+       } s;
+       struct cvmx_sriox_asmbly_info_s cn63xx;
+       struct cvmx_sriox_asmbly_info_s cn63xxp1;
+       struct cvmx_sriox_asmbly_info_s cn66xx;
+};
+
+union cvmx_sriox_bell_resp_ctrl {
+       uint64_t u64;
+       struct cvmx_sriox_bell_resp_ctrl_s {
+               uint64_t reserved_6_63:58;
+               uint64_t rp1_sid:1;
+               uint64_t rp0_sid:2;
+               uint64_t rp1_pid:1;
+               uint64_t rp0_pid:2;
+       } s;
+       struct cvmx_sriox_bell_resp_ctrl_s cn63xx;
+       struct cvmx_sriox_bell_resp_ctrl_s cn63xxp1;
+       struct cvmx_sriox_bell_resp_ctrl_s cn66xx;
+};
+
+union cvmx_sriox_bist_status {
+       uint64_t u64;
+       struct cvmx_sriox_bist_status_s {
+               uint64_t reserved_45_63:19;
+               uint64_t lram:1;
+               uint64_t mram:2;
+               uint64_t cram:2;
+               uint64_t bell:2;
+               uint64_t otag:2;
+               uint64_t itag:1;
+               uint64_t ofree:1;
+               uint64_t rtn:2;
+               uint64_t obulk:4;
+               uint64_t optrs:4;
+               uint64_t oarb2:2;
+               uint64_t rxbuf2:2;
+               uint64_t oarb:2;
+               uint64_t ispf:1;
+               uint64_t ospf:1;
+               uint64_t txbuf:2;
+               uint64_t rxbuf:2;
+               uint64_t imsg:5;
+               uint64_t omsg:7;
+       } s;
+       struct cvmx_sriox_bist_status_cn63xx {
+               uint64_t reserved_44_63:20;
+               uint64_t mram:2;
+               uint64_t cram:2;
+               uint64_t bell:2;
+               uint64_t otag:2;
+               uint64_t itag:1;
+               uint64_t ofree:1;
+               uint64_t rtn:2;
+               uint64_t obulk:4;
+               uint64_t optrs:4;
+               uint64_t oarb2:2;
+               uint64_t rxbuf2:2;
+               uint64_t oarb:2;
+               uint64_t ispf:1;
+               uint64_t ospf:1;
+               uint64_t txbuf:2;
+               uint64_t rxbuf:2;
+               uint64_t imsg:5;
+               uint64_t omsg:7;
+       } cn63xx;
+       struct cvmx_sriox_bist_status_cn63xxp1 {
+               uint64_t reserved_44_63:20;
+               uint64_t mram:2;
+               uint64_t cram:2;
+               uint64_t bell:2;
+               uint64_t otag:2;
+               uint64_t itag:1;
+               uint64_t ofree:1;
+               uint64_t rtn:2;
+               uint64_t obulk:4;
+               uint64_t optrs:4;
+               uint64_t reserved_20_23:4;
+               uint64_t oarb:2;
+               uint64_t ispf:1;
+               uint64_t ospf:1;
+               uint64_t txbuf:2;
+               uint64_t rxbuf:2;
+               uint64_t imsg:5;
+               uint64_t omsg:7;
+       } cn63xxp1;
+       struct cvmx_sriox_bist_status_s cn66xx;
+};
+
+union cvmx_sriox_imsg_ctrl {
+       uint64_t u64;
+       struct cvmx_sriox_imsg_ctrl_s {
+               uint64_t reserved_32_63:32;
+               uint64_t to_mode:1;
+               uint64_t reserved_30_30:1;
+               uint64_t rsp_thr:6;
+               uint64_t reserved_22_23:2;
+               uint64_t rp1_sid:1;
+               uint64_t rp0_sid:2;
+               uint64_t rp1_pid:1;
+               uint64_t rp0_pid:2;
+               uint64_t reserved_15_15:1;
+               uint64_t prt_sel:3;
+               uint64_t lttr:4;
+               uint64_t prio:4;
+               uint64_t mbox:4;
+       } s;
+       struct cvmx_sriox_imsg_ctrl_s cn63xx;
+       struct cvmx_sriox_imsg_ctrl_s cn63xxp1;
+       struct cvmx_sriox_imsg_ctrl_s cn66xx;
+};
+
+union cvmx_sriox_imsg_inst_hdrx {
+       uint64_t u64;
+       struct cvmx_sriox_imsg_inst_hdrx_s {
+               uint64_t r:1;
+               uint64_t reserved_58_62:5;
+               uint64_t pm:2;
+               uint64_t reserved_55_55:1;
+               uint64_t sl:7;
+               uint64_t reserved_46_47:2;
+               uint64_t nqos:1;
+               uint64_t ngrp:1;
+               uint64_t ntt:1;
+               uint64_t ntag:1;
+               uint64_t reserved_35_41:7;
+               uint64_t rs:1;
+               uint64_t tt:2;
+               uint64_t tag:32;
+       } s;
+       struct cvmx_sriox_imsg_inst_hdrx_s cn63xx;
+       struct cvmx_sriox_imsg_inst_hdrx_s cn63xxp1;
+       struct cvmx_sriox_imsg_inst_hdrx_s cn66xx;
+};
+
+union cvmx_sriox_imsg_qos_grpx {
+       uint64_t u64;
+       struct cvmx_sriox_imsg_qos_grpx_s {
+               uint64_t reserved_63_63:1;
+               uint64_t qos7:3;
+               uint64_t grp7:4;
+               uint64_t reserved_55_55:1;
+               uint64_t qos6:3;
+               uint64_t grp6:4;
+               uint64_t reserved_47_47:1;
+               uint64_t qos5:3;
+               uint64_t grp5:4;
+               uint64_t reserved_39_39:1;
+               uint64_t qos4:3;
+               uint64_t grp4:4;
+               uint64_t reserved_31_31:1;
+               uint64_t qos3:3;
+               uint64_t grp3:4;
+               uint64_t reserved_23_23:1;
+               uint64_t qos2:3;
+               uint64_t grp2:4;
+               uint64_t reserved_15_15:1;
+               uint64_t qos1:3;
+               uint64_t grp1:4;
+               uint64_t reserved_7_7:1;
+               uint64_t qos0:3;
+               uint64_t grp0:4;
+       } s;
+       struct cvmx_sriox_imsg_qos_grpx_s cn63xx;
+       struct cvmx_sriox_imsg_qos_grpx_s cn63xxp1;
+       struct cvmx_sriox_imsg_qos_grpx_s cn66xx;
+};
+
+union cvmx_sriox_imsg_statusx {
+       uint64_t u64;
+       struct cvmx_sriox_imsg_statusx_s {
+               uint64_t val1:1;
+               uint64_t err1:1;
+               uint64_t toe1:1;
+               uint64_t toc1:1;
+               uint64_t prt1:1;
+               uint64_t reserved_58_58:1;
+               uint64_t tt1:1;
+               uint64_t dis1:1;
+               uint64_t seg1:4;
+               uint64_t mbox1:2;
+               uint64_t lttr1:2;
+               uint64_t sid1:16;
+               uint64_t val0:1;
+               uint64_t err0:1;
+               uint64_t toe0:1;
+               uint64_t toc0:1;
+               uint64_t prt0:1;
+               uint64_t reserved_26_26:1;
+               uint64_t tt0:1;
+               uint64_t dis0:1;
+               uint64_t seg0:4;
+               uint64_t mbox0:2;
+               uint64_t lttr0:2;
+               uint64_t sid0:16;
+       } s;
+       struct cvmx_sriox_imsg_statusx_s cn63xx;
+       struct cvmx_sriox_imsg_statusx_s cn63xxp1;
+       struct cvmx_sriox_imsg_statusx_s cn66xx;
+};
+
+union cvmx_sriox_imsg_vport_thr {
+       uint64_t u64;
+       struct cvmx_sriox_imsg_vport_thr_s {
+               uint64_t reserved_54_63:10;
+               uint64_t max_tot:6;
+               uint64_t reserved_46_47:2;
+               uint64_t max_s1:6;
+               uint64_t reserved_38_39:2;
+               uint64_t max_s0:6;
+               uint64_t sp_vport:1;
+               uint64_t reserved_20_30:11;
+               uint64_t buf_thr:4;
+               uint64_t reserved_14_15:2;
+               uint64_t max_p1:6;
+               uint64_t reserved_6_7:2;
+               uint64_t max_p0:6;
+       } s;
+       struct cvmx_sriox_imsg_vport_thr_s cn63xx;
+       struct cvmx_sriox_imsg_vport_thr_s cn63xxp1;
+       struct cvmx_sriox_imsg_vport_thr_s cn66xx;
+};
+
+union cvmx_sriox_imsg_vport_thr2 {
+       uint64_t u64;
+       struct cvmx_sriox_imsg_vport_thr2_s {
+               uint64_t reserved_46_63:18;
+               uint64_t max_s3:6;
+               uint64_t reserved_38_39:2;
+               uint64_t max_s2:6;
+               uint64_t reserved_0_31:32;
+       } s;
+       struct cvmx_sriox_imsg_vport_thr2_s cn66xx;
+};
+
+union cvmx_sriox_int2_enable {
+       uint64_t u64;
+       struct cvmx_sriox_int2_enable_s {
+               uint64_t reserved_1_63:63;
+               uint64_t pko_rst:1;
+       } s;
+       struct cvmx_sriox_int2_enable_s cn63xx;
+       struct cvmx_sriox_int2_enable_s cn66xx;
+};
+
+union cvmx_sriox_int2_reg {
+       uint64_t u64;
+       struct cvmx_sriox_int2_reg_s {
+               uint64_t reserved_32_63:32;
+               uint64_t int_sum:1;
+               uint64_t reserved_1_30:30;
+               uint64_t pko_rst:1;
+       } s;
+       struct cvmx_sriox_int2_reg_s cn63xx;
+       struct cvmx_sriox_int2_reg_s cn66xx;
+};
+
+union cvmx_sriox_int_enable {
+       uint64_t u64;
+       struct cvmx_sriox_int_enable_s {
+               uint64_t reserved_27_63:37;
+               uint64_t zero_pkt:1;
+               uint64_t ttl_tout:1;
+               uint64_t fail:1;
+               uint64_t degrade:1;
+               uint64_t mac_buf:1;
+               uint64_t f_error:1;
+               uint64_t rtry_err:1;
+               uint64_t pko_err:1;
+               uint64_t omsg_err:1;
+               uint64_t omsg1:1;
+               uint64_t omsg0:1;
+               uint64_t link_up:1;
+               uint64_t link_dwn:1;
+               uint64_t phy_erb:1;
+               uint64_t log_erb:1;
+               uint64_t soft_rx:1;
+               uint64_t soft_tx:1;
+               uint64_t mce_rx:1;
+               uint64_t mce_tx:1;
+               uint64_t wr_done:1;
+               uint64_t sli_err:1;
+               uint64_t deny_wr:1;
+               uint64_t bar_err:1;
+               uint64_t maint_op:1;
+               uint64_t rxbell:1;
+               uint64_t bell_err:1;
+               uint64_t txbell:1;
+       } s;
+       struct cvmx_sriox_int_enable_s cn63xx;
+       struct cvmx_sriox_int_enable_cn63xxp1 {
+               uint64_t reserved_22_63:42;
+               uint64_t f_error:1;
+               uint64_t rtry_err:1;
+               uint64_t pko_err:1;
+               uint64_t omsg_err:1;
+               uint64_t omsg1:1;
+               uint64_t omsg0:1;
+               uint64_t link_up:1;
+               uint64_t link_dwn:1;
+               uint64_t phy_erb:1;
+               uint64_t log_erb:1;
+               uint64_t soft_rx:1;
+               uint64_t soft_tx:1;
+               uint64_t mce_rx:1;
+               uint64_t mce_tx:1;
+               uint64_t wr_done:1;
+               uint64_t sli_err:1;
+               uint64_t deny_wr:1;
+               uint64_t bar_err:1;
+               uint64_t maint_op:1;
+               uint64_t rxbell:1;
+               uint64_t bell_err:1;
+               uint64_t txbell:1;
+       } cn63xxp1;
+       struct cvmx_sriox_int_enable_s cn66xx;
+};
+
+union cvmx_sriox_int_info0 {
+       uint64_t u64;
+       struct cvmx_sriox_int_info0_s {
+               uint64_t cmd:4;
+               uint64_t type:4;
+               uint64_t tag:8;
+               uint64_t reserved_42_47:6;
+               uint64_t length:10;
+               uint64_t status:3;
+               uint64_t reserved_16_28:13;
+               uint64_t be0:8;
+               uint64_t be1:8;
+       } s;
+       struct cvmx_sriox_int_info0_s cn63xx;
+       struct cvmx_sriox_int_info0_s cn63xxp1;
+       struct cvmx_sriox_int_info0_s cn66xx;
+};
+
+union cvmx_sriox_int_info1 {
+       uint64_t u64;
+       struct cvmx_sriox_int_info1_s {
+               uint64_t info1:64;
+       } s;
+       struct cvmx_sriox_int_info1_s cn63xx;
+       struct cvmx_sriox_int_info1_s cn63xxp1;
+       struct cvmx_sriox_int_info1_s cn66xx;
+};
+
+union cvmx_sriox_int_info2 {
+       uint64_t u64;
+       struct cvmx_sriox_int_info2_s {
+               uint64_t prio:2;
+               uint64_t tt:1;
+               uint64_t sis:1;
+               uint64_t ssize:4;
+               uint64_t did:16;
+               uint64_t xmbox:4;
+               uint64_t mbox:2;
+               uint64_t letter:2;
+               uint64_t rsrvd:30;
+               uint64_t lns:1;
+               uint64_t intr:1;
+       } s;
+       struct cvmx_sriox_int_info2_s cn63xx;
+       struct cvmx_sriox_int_info2_s cn63xxp1;
+       struct cvmx_sriox_int_info2_s cn66xx;
+};
+
+union cvmx_sriox_int_info3 {
+       uint64_t u64;
+       struct cvmx_sriox_int_info3_s {
+               uint64_t prio:2;
+               uint64_t tt:2;
+               uint64_t type:4;
+               uint64_t other:48;
+               uint64_t reserved_0_7:8;
+       } s;
+       struct cvmx_sriox_int_info3_s cn63xx;
+       struct cvmx_sriox_int_info3_s cn63xxp1;
+       struct cvmx_sriox_int_info3_s cn66xx;
+};
+
+union cvmx_sriox_int_reg {
+       uint64_t u64;
+       struct cvmx_sriox_int_reg_s {
+               uint64_t reserved_32_63:32;
+               uint64_t int2_sum:1;
+               uint64_t reserved_27_30:4;
+               uint64_t zero_pkt:1;
+               uint64_t ttl_tout:1;
+               uint64_t fail:1;
+               uint64_t degrad:1;
+               uint64_t mac_buf:1;
+               uint64_t f_error:1;
+               uint64_t rtry_err:1;
+               uint64_t pko_err:1;
+               uint64_t omsg_err:1;
+               uint64_t omsg1:1;
+               uint64_t omsg0:1;
+               uint64_t link_up:1;
+               uint64_t link_dwn:1;
+               uint64_t phy_erb:1;
+               uint64_t log_erb:1;
+               uint64_t soft_rx:1;
+               uint64_t soft_tx:1;
+               uint64_t mce_rx:1;
+               uint64_t mce_tx:1;
+               uint64_t wr_done:1;
+               uint64_t sli_err:1;
+               uint64_t deny_wr:1;
+               uint64_t bar_err:1;
+               uint64_t maint_op:1;
+               uint64_t rxbell:1;
+               uint64_t bell_err:1;
+               uint64_t txbell:1;
+       } s;
+       struct cvmx_sriox_int_reg_s cn63xx;
+       struct cvmx_sriox_int_reg_cn63xxp1 {
+               uint64_t reserved_22_63:42;
+               uint64_t f_error:1;
+               uint64_t rtry_err:1;
+               uint64_t pko_err:1;
+               uint64_t omsg_err:1;
+               uint64_t omsg1:1;
+               uint64_t omsg0:1;
+               uint64_t link_up:1;
+               uint64_t link_dwn:1;
+               uint64_t phy_erb:1;
+               uint64_t log_erb:1;
+               uint64_t soft_rx:1;
+               uint64_t soft_tx:1;
+               uint64_t mce_rx:1;
+               uint64_t mce_tx:1;
+               uint64_t wr_done:1;
+               uint64_t sli_err:1;
+               uint64_t deny_wr:1;
+               uint64_t bar_err:1;
+               uint64_t maint_op:1;
+               uint64_t rxbell:1;
+               uint64_t bell_err:1;
+               uint64_t txbell:1;
+       } cn63xxp1;
+       struct cvmx_sriox_int_reg_s cn66xx;
+};
+
+union cvmx_sriox_ip_feature {
+       uint64_t u64;
+       struct cvmx_sriox_ip_feature_s {
+               uint64_t ops:32;
+               uint64_t reserved_15_31:17;
+               uint64_t no_vmin:1;
+               uint64_t a66:1;
+               uint64_t a50:1;
+               uint64_t reserved_11_11:1;
+               uint64_t tx_flow:1;
+               uint64_t pt_width:2;
+               uint64_t tx_pol:4;
+               uint64_t rx_pol:4;
+       } s;
+       struct cvmx_sriox_ip_feature_cn63xx {
+               uint64_t ops:32;
+               uint64_t reserved_14_31:18;
+               uint64_t a66:1;
+               uint64_t a50:1;
+               uint64_t reserved_11_11:1;
+               uint64_t tx_flow:1;
+               uint64_t pt_width:2;
+               uint64_t tx_pol:4;
+               uint64_t rx_pol:4;
+       } cn63xx;
+       struct cvmx_sriox_ip_feature_cn63xx cn63xxp1;
+       struct cvmx_sriox_ip_feature_s cn66xx;
+};
+
+union cvmx_sriox_mac_buffers {
+       uint64_t u64;
+       struct cvmx_sriox_mac_buffers_s {
+               uint64_t reserved_56_63:8;
+               uint64_t tx_enb:8;
+               uint64_t reserved_44_47:4;
+               uint64_t tx_inuse:4;
+               uint64_t tx_stat:8;
+               uint64_t reserved_24_31:8;
+               uint64_t rx_enb:8;
+               uint64_t reserved_12_15:4;
+               uint64_t rx_inuse:4;
+               uint64_t rx_stat:8;
+       } s;
+       struct cvmx_sriox_mac_buffers_s cn63xx;
+       struct cvmx_sriox_mac_buffers_s cn66xx;
+};
+
+union cvmx_sriox_maint_op {
+       uint64_t u64;
+       struct cvmx_sriox_maint_op_s {
+               uint64_t wr_data:32;
+               uint64_t reserved_27_31:5;
+               uint64_t fail:1;
+               uint64_t pending:1;
+               uint64_t op:1;
+               uint64_t addr:24;
+       } s;
+       struct cvmx_sriox_maint_op_s cn63xx;
+       struct cvmx_sriox_maint_op_s cn63xxp1;
+       struct cvmx_sriox_maint_op_s cn66xx;
+};
+
+union cvmx_sriox_maint_rd_data {
+       uint64_t u64;
+       struct cvmx_sriox_maint_rd_data_s {
+               uint64_t reserved_33_63:31;
+               uint64_t valid:1;
+               uint64_t rd_data:32;
+       } s;
+       struct cvmx_sriox_maint_rd_data_s cn63xx;
+       struct cvmx_sriox_maint_rd_data_s cn63xxp1;
+       struct cvmx_sriox_maint_rd_data_s cn66xx;
+};
+
+union cvmx_sriox_mce_tx_ctl {
+       uint64_t u64;
+       struct cvmx_sriox_mce_tx_ctl_s {
+               uint64_t reserved_1_63:63;
+               uint64_t mce:1;
+       } s;
+       struct cvmx_sriox_mce_tx_ctl_s cn63xx;
+       struct cvmx_sriox_mce_tx_ctl_s cn63xxp1;
+       struct cvmx_sriox_mce_tx_ctl_s cn66xx;
+};
+
+union cvmx_sriox_mem_op_ctrl {
+       uint64_t u64;
+       struct cvmx_sriox_mem_op_ctrl_s {
+               uint64_t reserved_10_63:54;
+               uint64_t rr_ro:1;
+               uint64_t w_ro:1;
+               uint64_t reserved_6_7:2;
+               uint64_t rp1_sid:1;
+               uint64_t rp0_sid:2;
+               uint64_t rp1_pid:1;
+               uint64_t rp0_pid:2;
+       } s;
+       struct cvmx_sriox_mem_op_ctrl_s cn63xx;
+       struct cvmx_sriox_mem_op_ctrl_s cn63xxp1;
+       struct cvmx_sriox_mem_op_ctrl_s cn66xx;
+};
+
+union cvmx_sriox_omsg_ctrlx {
+       uint64_t u64;
+       struct cvmx_sriox_omsg_ctrlx_s {
+               uint64_t testmode:1;
+               uint64_t reserved_37_62:26;
+               uint64_t silo_max:5;
+               uint64_t rtry_thr:16;
+               uint64_t rtry_en:1;
+               uint64_t reserved_11_14:4;
+               uint64_t idm_tt:1;
+               uint64_t idm_sis:1;
+               uint64_t idm_did:1;
+               uint64_t lttr_sp:4;
+               uint64_t lttr_mp:4;
+       } s;
+       struct cvmx_sriox_omsg_ctrlx_s cn63xx;
+       struct cvmx_sriox_omsg_ctrlx_cn63xxp1 {
+               uint64_t testmode:1;
+               uint64_t reserved_32_62:31;
+               uint64_t rtry_thr:16;
+               uint64_t rtry_en:1;
+               uint64_t reserved_11_14:4;
+               uint64_t idm_tt:1;
+               uint64_t idm_sis:1;
+               uint64_t idm_did:1;
+               uint64_t lttr_sp:4;
+               uint64_t lttr_mp:4;
+       } cn63xxp1;
+       struct cvmx_sriox_omsg_ctrlx_s cn66xx;
+};
+
+union cvmx_sriox_omsg_done_countsx {
+       uint64_t u64;
+       struct cvmx_sriox_omsg_done_countsx_s {
+               uint64_t reserved_32_63:32;
+               uint64_t bad:16;
+               uint64_t good:16;
+       } s;
+       struct cvmx_sriox_omsg_done_countsx_s cn63xx;
+       struct cvmx_sriox_omsg_done_countsx_s cn66xx;
+};
+
+union cvmx_sriox_omsg_fmp_mrx {
+       uint64_t u64;
+       struct cvmx_sriox_omsg_fmp_mrx_s {
+               uint64_t reserved_15_63:49;
+               uint64_t ctlr_sp:1;
+               uint64_t ctlr_fmp:1;
+               uint64_t ctlr_nmp:1;
+               uint64_t id_sp:1;
+               uint64_t id_fmp:1;
+               uint64_t id_nmp:1;
+               uint64_t id_psd:1;
+               uint64_t mbox_sp:1;
+               uint64_t mbox_fmp:1;
+               uint64_t mbox_nmp:1;
+               uint64_t mbox_psd:1;
+               uint64_t all_sp:1;
+               uint64_t all_fmp:1;
+               uint64_t all_nmp:1;
+               uint64_t all_psd:1;
+       } s;
+       struct cvmx_sriox_omsg_fmp_mrx_s cn63xx;
+       struct cvmx_sriox_omsg_fmp_mrx_s cn63xxp1;
+       struct cvmx_sriox_omsg_fmp_mrx_s cn66xx;
+};
+
+union cvmx_sriox_omsg_nmp_mrx {
+       uint64_t u64;
+       struct cvmx_sriox_omsg_nmp_mrx_s {
+               uint64_t reserved_15_63:49;
+               uint64_t ctlr_sp:1;
+               uint64_t ctlr_fmp:1;
+               uint64_t ctlr_nmp:1;
+               uint64_t id_sp:1;
+               uint64_t id_fmp:1;
+               uint64_t id_nmp:1;
+               uint64_t reserved_8_8:1;
+               uint64_t mbox_sp:1;
+               uint64_t mbox_fmp:1;
+               uint64_t mbox_nmp:1;
+               uint64_t reserved_4_4:1;
+               uint64_t all_sp:1;
+               uint64_t all_fmp:1;
+               uint64_t all_nmp:1;
+               uint64_t reserved_0_0:1;
+       } s;
+       struct cvmx_sriox_omsg_nmp_mrx_s cn63xx;
+       struct cvmx_sriox_omsg_nmp_mrx_s cn63xxp1;
+       struct cvmx_sriox_omsg_nmp_mrx_s cn66xx;
+};
+
+union cvmx_sriox_omsg_portx {
+       uint64_t u64;
+       struct cvmx_sriox_omsg_portx_s {
+               uint64_t reserved_32_63:32;
+               uint64_t enable:1;
+               uint64_t reserved_3_30:28;
+               uint64_t port:3;
+       } s;
+       struct cvmx_sriox_omsg_portx_cn63xx {
+               uint64_t reserved_32_63:32;
+               uint64_t enable:1;
+               uint64_t reserved_2_30:29;
+               uint64_t port:2;
+       } cn63xx;
+       struct cvmx_sriox_omsg_portx_cn63xx cn63xxp1;
+       struct cvmx_sriox_omsg_portx_s cn66xx;
+};
+
+union cvmx_sriox_omsg_silo_thr {
+       uint64_t u64;
+       struct cvmx_sriox_omsg_silo_thr_s {
+               uint64_t reserved_5_63:59;
+               uint64_t tot_silo:5;
+       } s;
+       struct cvmx_sriox_omsg_silo_thr_s cn63xx;
+       struct cvmx_sriox_omsg_silo_thr_s cn66xx;
+};
+
+union cvmx_sriox_omsg_sp_mrx {
+       uint64_t u64;
+       struct cvmx_sriox_omsg_sp_mrx_s {
+               uint64_t reserved_16_63:48;
+               uint64_t xmbox_sp:1;
+               uint64_t ctlr_sp:1;
+               uint64_t ctlr_fmp:1;
+               uint64_t ctlr_nmp:1;
+               uint64_t id_sp:1;
+               uint64_t id_fmp:1;
+               uint64_t id_nmp:1;
+               uint64_t id_psd:1;
+               uint64_t mbox_sp:1;
+               uint64_t mbox_fmp:1;
+               uint64_t mbox_nmp:1;
+               uint64_t mbox_psd:1;
+               uint64_t all_sp:1;
+               uint64_t all_fmp:1;
+               uint64_t all_nmp:1;
+               uint64_t all_psd:1;
+       } s;
+       struct cvmx_sriox_omsg_sp_mrx_s cn63xx;
+       struct cvmx_sriox_omsg_sp_mrx_s cn63xxp1;
+       struct cvmx_sriox_omsg_sp_mrx_s cn66xx;
+};
+
+union cvmx_sriox_priox_in_use {
+       uint64_t u64;
+       struct cvmx_sriox_priox_in_use_s {
+               uint64_t reserved_32_63:32;
+               uint64_t end_cnt:16;
+               uint64_t start_cnt:16;
+       } s;
+       struct cvmx_sriox_priox_in_use_s cn63xx;
+       struct cvmx_sriox_priox_in_use_s cn66xx;
+};
+
+union cvmx_sriox_rx_bell {
+       uint64_t u64;
+       struct cvmx_sriox_rx_bell_s {
+               uint64_t reserved_48_63:16;
+               uint64_t data:16;
+               uint64_t src_id:16;
+               uint64_t count:8;
+               uint64_t reserved_5_7:3;
+               uint64_t dest_id:1;
+               uint64_t id16:1;
+               uint64_t reserved_2_2:1;
+               uint64_t priority:2;
+       } s;
+       struct cvmx_sriox_rx_bell_s cn63xx;
+       struct cvmx_sriox_rx_bell_s cn63xxp1;
+       struct cvmx_sriox_rx_bell_s cn66xx;
+};
+
+union cvmx_sriox_rx_bell_seq {
+       uint64_t u64;
+       struct cvmx_sriox_rx_bell_seq_s {
+               uint64_t reserved_40_63:24;
+               uint64_t count:8;
+               uint64_t seq:32;
+       } s;
+       struct cvmx_sriox_rx_bell_seq_s cn63xx;
+       struct cvmx_sriox_rx_bell_seq_s cn63xxp1;
+       struct cvmx_sriox_rx_bell_seq_s cn66xx;
+};
+
+union cvmx_sriox_rx_status {
+       uint64_t u64;
+       struct cvmx_sriox_rx_status_s {
+               uint64_t rtn_pr3:8;
+               uint64_t rtn_pr2:8;
+               uint64_t rtn_pr1:8;
+               uint64_t reserved_28_39:12;
+               uint64_t mbox:4;
+               uint64_t comp:8;
+               uint64_t reserved_13_15:3;
+               uint64_t n_post:5;
+               uint64_t post:8;
+       } s;
+       struct cvmx_sriox_rx_status_s cn63xx;
+       struct cvmx_sriox_rx_status_s cn63xxp1;
+       struct cvmx_sriox_rx_status_s cn66xx;
+};
+
+union cvmx_sriox_s2m_typex {
+       uint64_t u64;
+       struct cvmx_sriox_s2m_typex_s {
+               uint64_t reserved_19_63:45;
+               uint64_t wr_op:3;
+               uint64_t reserved_15_15:1;
+               uint64_t rd_op:3;
+               uint64_t wr_prior:2;
+               uint64_t rd_prior:2;
+               uint64_t reserved_6_7:2;
+               uint64_t src_id:1;
+               uint64_t id16:1;
+               uint64_t reserved_2_3:2;
+               uint64_t iaow_sel:2;
+       } s;
+       struct cvmx_sriox_s2m_typex_s cn63xx;
+       struct cvmx_sriox_s2m_typex_s cn63xxp1;
+       struct cvmx_sriox_s2m_typex_s cn66xx;
+};
+
+union cvmx_sriox_seq {
+       uint64_t u64;
+       struct cvmx_sriox_seq_s {
+               uint64_t reserved_32_63:32;
+               uint64_t seq:32;
+       } s;
+       struct cvmx_sriox_seq_s cn63xx;
+       struct cvmx_sriox_seq_s cn63xxp1;
+       struct cvmx_sriox_seq_s cn66xx;
+};
+
+union cvmx_sriox_status_reg {
+       uint64_t u64;
+       struct cvmx_sriox_status_reg_s {
+               uint64_t reserved_2_63:62;
+               uint64_t access:1;
+               uint64_t srio:1;
+       } s;
+       struct cvmx_sriox_status_reg_s cn63xx;
+       struct cvmx_sriox_status_reg_s cn63xxp1;
+       struct cvmx_sriox_status_reg_s cn66xx;
+};
+
+union cvmx_sriox_tag_ctrl {
+       uint64_t u64;
+       struct cvmx_sriox_tag_ctrl_s {
+               uint64_t reserved_17_63:47;
+               uint64_t o_clr:1;
+               uint64_t reserved_13_15:3;
+               uint64_t otag:5;
+               uint64_t reserved_5_7:3;
+               uint64_t itag:5;
+       } s;
+       struct cvmx_sriox_tag_ctrl_s cn63xx;
+       struct cvmx_sriox_tag_ctrl_s cn63xxp1;
+       struct cvmx_sriox_tag_ctrl_s cn66xx;
+};
+
+union cvmx_sriox_tlp_credits {
+       uint64_t u64;
+       struct cvmx_sriox_tlp_credits_s {
+               uint64_t reserved_28_63:36;
+               uint64_t mbox:4;
+               uint64_t comp:8;
+               uint64_t reserved_13_15:3;
+               uint64_t n_post:5;
+               uint64_t post:8;
+       } s;
+       struct cvmx_sriox_tlp_credits_s cn63xx;
+       struct cvmx_sriox_tlp_credits_s cn63xxp1;
+       struct cvmx_sriox_tlp_credits_s cn66xx;
+};
+
+union cvmx_sriox_tx_bell {
+       uint64_t u64;
+       struct cvmx_sriox_tx_bell_s {
+               uint64_t reserved_48_63:16;
+               uint64_t data:16;
+               uint64_t dest_id:16;
+               uint64_t reserved_9_15:7;
+               uint64_t pending:1;
+               uint64_t reserved_5_7:3;
+               uint64_t src_id:1;
+               uint64_t id16:1;
+               uint64_t reserved_2_2:1;
+               uint64_t priority:2;
+       } s;
+       struct cvmx_sriox_tx_bell_s cn63xx;
+       struct cvmx_sriox_tx_bell_s cn63xxp1;
+       struct cvmx_sriox_tx_bell_s cn66xx;
+};
+
+union cvmx_sriox_tx_bell_info {
+       uint64_t u64;
+       struct cvmx_sriox_tx_bell_info_s {
+               uint64_t reserved_48_63:16;
+               uint64_t data:16;
+               uint64_t dest_id:16;
+               uint64_t reserved_8_15:8;
+               uint64_t timeout:1;
+               uint64_t error:1;
+               uint64_t retry:1;
+               uint64_t src_id:1;
+               uint64_t id16:1;
+               uint64_t reserved_2_2:1;
+               uint64_t priority:2;
+       } s;
+       struct cvmx_sriox_tx_bell_info_s cn63xx;
+       struct cvmx_sriox_tx_bell_info_s cn63xxp1;
+       struct cvmx_sriox_tx_bell_info_s cn66xx;
+};
+
+union cvmx_sriox_tx_ctrl {
+       uint64_t u64;
+       struct cvmx_sriox_tx_ctrl_s {
+               uint64_t reserved_53_63:11;
+               uint64_t tag_th2:5;
+               uint64_t reserved_45_47:3;
+               uint64_t tag_th1:5;
+               uint64_t reserved_37_39:3;
+               uint64_t tag_th0:5;
+               uint64_t reserved_20_31:12;
+               uint64_t tx_th2:4;
+               uint64_t reserved_12_15:4;
+               uint64_t tx_th1:4;
+               uint64_t reserved_4_7:4;
+               uint64_t tx_th0:4;
+       } s;
+       struct cvmx_sriox_tx_ctrl_s cn63xx;
+       struct cvmx_sriox_tx_ctrl_s cn63xxp1;
+       struct cvmx_sriox_tx_ctrl_s cn66xx;
+};
+
+union cvmx_sriox_tx_emphasis {
+       uint64_t u64;
+       struct cvmx_sriox_tx_emphasis_s {
+               uint64_t reserved_4_63:60;
+               uint64_t emph:4;
+       } s;
+       struct cvmx_sriox_tx_emphasis_s cn63xx;
+       struct cvmx_sriox_tx_emphasis_s cn66xx;
+};
+
+union cvmx_sriox_tx_status {
+       uint64_t u64;
+       struct cvmx_sriox_tx_status_s {
+               uint64_t reserved_32_63:32;
+               uint64_t s2m_pr3:8;
+               uint64_t s2m_pr2:8;
+               uint64_t s2m_pr1:8;
+               uint64_t s2m_pr0:8;
+       } s;
+       struct cvmx_sriox_tx_status_s cn63xx;
+       struct cvmx_sriox_tx_status_s cn63xxp1;
+       struct cvmx_sriox_tx_status_s cn66xx;
+};
+
+union cvmx_sriox_wr_done_counts {
+       uint64_t u64;
+       struct cvmx_sriox_wr_done_counts_s {
+               uint64_t reserved_32_63:32;
+               uint64_t bad:16;
+               uint64_t good:16;
+       } s;
+       struct cvmx_sriox_wr_done_counts_s cn63xx;
+       struct cvmx_sriox_wr_done_counts_s cn66xx;
+};
+
+#endif
index 7e1286706d4644e8b6393bc063d157ef142e8c68..740be97a32513cfd4ace7517d731ad6e68258422 100644 (file)
 #include <linux/kernel.h>
 #include <linux/string.h>
 
+enum cvmx_mips_space {
+       CVMX_MIPS_SPACE_XKSEG = 3LL,
+       CVMX_MIPS_SPACE_XKPHYS = 2LL,
+       CVMX_MIPS_SPACE_XSSEG = 1LL,
+       CVMX_MIPS_SPACE_XUSEG = 0LL
+};
+
+/* These macros for use when using 32 bit pointers. */
+#define CVMX_MIPS32_SPACE_KSEG0 1l
+#define CVMX_ADD_SEG32(segment, add) \
+       (((int32_t)segment << 31) | (int32_t)(add))
+
+#define CVMX_IO_SEG CVMX_MIPS_SPACE_XKPHYS
+
+/* These macros simplify the process of creating common IO addresses */
+#define CVMX_ADD_SEG(segment, add) \
+       ((((uint64_t)segment) << 62) | (add))
+#ifndef CVMX_ADD_IO_SEG
+#define CVMX_ADD_IO_SEG(add) CVMX_ADD_SEG(CVMX_IO_SEG, (add))
+#endif
+
 #include "cvmx-asm.h"
 #include "cvmx-packet.h"
 #include "cvmx-sysinfo.h"
@@ -129,27 +150,6 @@ static inline uint64_t cvmx_build_bits(uint64_t high_bit,
        return (value & cvmx_build_mask(high_bit - low_bit + 1)) << low_bit;
 }
 
-enum cvmx_mips_space {
-       CVMX_MIPS_SPACE_XKSEG = 3LL,
-       CVMX_MIPS_SPACE_XKPHYS = 2LL,
-       CVMX_MIPS_SPACE_XSSEG = 1LL,
-       CVMX_MIPS_SPACE_XUSEG = 0LL
-};
-
-/* These macros for use when using 32 bit pointers. */
-#define CVMX_MIPS32_SPACE_KSEG0 1l
-#define CVMX_ADD_SEG32(segment, add) \
-       (((int32_t)segment << 31) | (int32_t)(add))
-
-#define CVMX_IO_SEG CVMX_MIPS_SPACE_XKPHYS
-
-/* These macros simplify the process of creating common IO addresses */
-#define CVMX_ADD_SEG(segment, add) \
-       ((((uint64_t)segment) << 62) | (add))
-#ifndef CVMX_ADD_IO_SEG
-#define CVMX_ADD_IO_SEG(add) CVMX_ADD_SEG(CVMX_IO_SEG, (add))
-#endif
-
 /**
  * Convert a memory pointer (void*) into a hardware compatible
  * memory address (uint64_t). Octeon hardware widgets don't
index cba6fbed9f438249fde6cd3f346577a77fa7c3e2..8008da2f87794f2d4e564d891ebb93dac5a1022e 100644 (file)
 
 #ifndef __OCTEON_FEATURE_H__
 #define __OCTEON_FEATURE_H__
+#include <asm/octeon/cvmx-mio-defs.h>
+#include <asm/octeon/cvmx-rnm-defs.h>
 
 enum octeon_feature {
+        /* CN68XX uses port kinds for packet interface */
+       OCTEON_FEATURE_PKND,
+       /* CN68XX has different fields in word0 - word2 */
+       OCTEON_FEATURE_CN68XX_WQE,
        /*
         * Octeon models in the CN5XXX family and higher support
         * atomic add instructions to memory (saa/saad).
@@ -42,8 +48,13 @@ enum octeon_feature {
        OCTEON_FEATURE_ZIP,
        /* Does this Octeon support crypto acceleration using COP2? */
        OCTEON_FEATURE_CRYPTO,
+       OCTEON_FEATURE_DORM_CRYPTO,
        /* Does this Octeon support PCI express? */
        OCTEON_FEATURE_PCIE,
+        /* Does this Octeon support SRIOs */
+       OCTEON_FEATURE_SRIO,
+       /*  Does this Octeon support Interlaken */
+       OCTEON_FEATURE_ILK,
        /* Some Octeon models support internal memory for storing
         * cryptographic keys */
        OCTEON_FEATURE_KEY_MEMORY,
@@ -64,6 +75,15 @@ enum octeon_feature {
        /* Octeon MDIO block supports clause 45 transactions for 10
         * Gig support */
        OCTEON_FEATURE_MDIO_CLAUSE_45,
+        /*
+        *  CN52XX and CN56XX used a block named NPEI for PCIe
+        *  access. Newer chips replaced this with SLI+DPI.
+        */
+       OCTEON_FEATURE_NPEI,
+       OCTEON_FEATURE_HFA,
+       OCTEON_FEATURE_DFM,
+       OCTEON_FEATURE_CIU2,
+       OCTEON_MAX_FEATURE
 };
 
 static inline int cvmx_fuse_read(int fuse);
@@ -96,30 +116,78 @@ static inline int octeon_has_feature(enum octeon_feature feature)
                        return !cvmx_fuse_read(121);
 
        case OCTEON_FEATURE_CRYPTO:
-               return !cvmx_fuse_read(90);
+               if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
+                       union cvmx_mio_fus_dat2 fus_2;
+                       fus_2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2);
+                       if (fus_2.s.nocrypto || fus_2.s.nomul) {
+                               return 0;
+                       } else if (!fus_2.s.dorm_crypto) {
+                               return 1;
+                       } else {
+                               union cvmx_rnm_ctl_status st;
+                               st.u64 = cvmx_read_csr(CVMX_RNM_CTL_STATUS);
+                               return st.s.eer_val;
+                       }
+               } else {
+                       return !cvmx_fuse_read(90);
+               }
+
+       case OCTEON_FEATURE_DORM_CRYPTO:
+               if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
+                       union cvmx_mio_fus_dat2 fus_2;
+                       fus_2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2);
+                       return !fus_2.s.nocrypto && !fus_2.s.nomul && fus_2.s.dorm_crypto;
+               } else {
+                       return 0;
+               }
 
        case OCTEON_FEATURE_PCIE:
-       case OCTEON_FEATURE_MGMT_PORT:
-       case OCTEON_FEATURE_RAID:
                return OCTEON_IS_MODEL(OCTEON_CN56XX)
-                       || OCTEON_IS_MODEL(OCTEON_CN52XX);
+                       || OCTEON_IS_MODEL(OCTEON_CN52XX)
+                       || OCTEON_IS_MODEL(OCTEON_CN6XXX);
+
+       case OCTEON_FEATURE_SRIO:
+               return OCTEON_IS_MODEL(OCTEON_CN63XX)
+                       || OCTEON_IS_MODEL(OCTEON_CN66XX);
+
+       case OCTEON_FEATURE_ILK:
+               return (OCTEON_IS_MODEL(OCTEON_CN68XX));
 
        case OCTEON_FEATURE_KEY_MEMORY:
+               return OCTEON_IS_MODEL(OCTEON_CN38XX)
+                       || OCTEON_IS_MODEL(OCTEON_CN58XX)
+                       || OCTEON_IS_MODEL(OCTEON_CN56XX)
+                       || OCTEON_IS_MODEL(OCTEON_CN6XXX);
+
        case OCTEON_FEATURE_LED_CONTROLLER:
                return OCTEON_IS_MODEL(OCTEON_CN38XX)
                        || OCTEON_IS_MODEL(OCTEON_CN58XX)
                        || OCTEON_IS_MODEL(OCTEON_CN56XX);
+
        case OCTEON_FEATURE_TRA:
                return !(OCTEON_IS_MODEL(OCTEON_CN30XX)
                         || OCTEON_IS_MODEL(OCTEON_CN50XX));
+       case OCTEON_FEATURE_MGMT_PORT:
+               return OCTEON_IS_MODEL(OCTEON_CN56XX)
+                       || OCTEON_IS_MODEL(OCTEON_CN52XX)
+                       || OCTEON_IS_MODEL(OCTEON_CN6XXX);
+
+       case OCTEON_FEATURE_RAID:
+               return OCTEON_IS_MODEL(OCTEON_CN56XX)
+                       || OCTEON_IS_MODEL(OCTEON_CN52XX)
+                       || OCTEON_IS_MODEL(OCTEON_CN6XXX);
+
        case OCTEON_FEATURE_USB:
                return !(OCTEON_IS_MODEL(OCTEON_CN38XX)
                         || OCTEON_IS_MODEL(OCTEON_CN58XX));
+
        case OCTEON_FEATURE_NO_WPTR:
                return (OCTEON_IS_MODEL(OCTEON_CN56XX)
-                        || OCTEON_IS_MODEL(OCTEON_CN52XX))
-                       && !OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
-                       && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X);
+                       || OCTEON_IS_MODEL(OCTEON_CN52XX)
+                       || OCTEON_IS_MODEL(OCTEON_CN6XXX))
+                         && !OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
+                         && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X);
+
        case OCTEON_FEATURE_DFA:
                if (!OCTEON_IS_MODEL(OCTEON_CN38XX)
                    && !OCTEON_IS_MODEL(OCTEON_CN31XX)
@@ -127,14 +195,42 @@ static inline int octeon_has_feature(enum octeon_feature feature)
                        return 0;
                else if (OCTEON_IS_MODEL(OCTEON_CN3020))
                        return 0;
-               else if (OCTEON_IS_MODEL(OCTEON_CN38XX_PASS1))
-                       return 1;
                else
                        return !cvmx_fuse_read(120);
+
+       case OCTEON_FEATURE_HFA:
+               if (!OCTEON_IS_MODEL(OCTEON_CN6XXX))
+                       return 0;
+               else
+                       return !cvmx_fuse_read(90);
+
+       case OCTEON_FEATURE_DFM:
+               if (!(OCTEON_IS_MODEL(OCTEON_CN63XX)
+                     || OCTEON_IS_MODEL(OCTEON_CN66XX)))
+                       return 0;
+               else
+                       return !cvmx_fuse_read(90);
+
        case OCTEON_FEATURE_MDIO_CLAUSE_45:
                return !(OCTEON_IS_MODEL(OCTEON_CN3XXX)
                         || OCTEON_IS_MODEL(OCTEON_CN58XX)
                         || OCTEON_IS_MODEL(OCTEON_CN50XX));
+
+       case OCTEON_FEATURE_NPEI:
+               return OCTEON_IS_MODEL(OCTEON_CN56XX)
+                       || OCTEON_IS_MODEL(OCTEON_CN52XX);
+
+       case OCTEON_FEATURE_PKND:
+               return OCTEON_IS_MODEL(OCTEON_CN68XX);
+
+       case OCTEON_FEATURE_CN68XX_WQE:
+               return OCTEON_IS_MODEL(OCTEON_CN68XX);
+
+       case OCTEON_FEATURE_CIU2:
+               return OCTEON_IS_MODEL(OCTEON_CN68XX);
+
+       default:
+               break;
        }
        return 0;
 }
index 700f88e31cad8a14b5a10741dc5b5c369bc75e27..4e338a4d94242edc5fa913da82954076142aac51 100644 (file)
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
  * This file may also be available under a different license from Cavium.
  * Contact Cavium Networks for more information
  ***********************license end**************************************/
-
-/*
- *
- * File defining different Octeon model IDs and macros to
- * compare them.
- *
- */
-
 #ifndef __OCTEON_MODEL_H__
 #define __OCTEON_MODEL_H__
 
@@ -52,6 +44,8 @@
  * for internal use only, and may change without notice.
  */
 
+#define OCTEON_FAMILY_MASK      0x00ffff00
+
 /* Flag bits in top byte */
 /* Ignores revision in model checks */
 #define OM_IGNORE_REVISION        0x01000000
 #define OM_IGNORE_MINOR_REVISION  0x08000000
 #define OM_FLAG_MASK              0xff000000
 
-#define OM_MATCH_5XXX_FAMILY_MODELS     0x20000000 /* Match all cn5XXX Octeon models. */
-#define OM_MATCH_6XXX_FAMILY_MODELS     0x40000000 /* Match all cn6XXX Octeon models. */
+/* Match all cn5XXX Octeon models. */
+#define OM_MATCH_5XXX_FAMILY_MODELS     0x20000000
+/* Match all cn6XXX Octeon models. */
+#define OM_MATCH_6XXX_FAMILY_MODELS     0x40000000
 
 /*
  * CN6XXX models with new revision encoding
  */
+#define OCTEON_CN68XX_PASS1_0   0x000d9100
+#define OCTEON_CN68XX_PASS1_1   0x000d9101
+#define OCTEON_CN68XX_PASS1_2   0x000d9102
+#define OCTEON_CN68XX_PASS2_0   0x000d9108
+
+#define OCTEON_CN68XX           (OCTEON_CN68XX_PASS2_0 | OM_IGNORE_REVISION)
+#define OCTEON_CN68XX_PASS1_X   (OCTEON_CN68XX_PASS1_0 | OM_IGNORE_MINOR_REVISION)
+#define OCTEON_CN68XX_PASS2_X   (OCTEON_CN68XX_PASS2_0 | OM_IGNORE_MINOR_REVISION)
+
+#define OCTEON_CN68XX_PASS1    OCTEON_CN68XX_PASS1_X
+#define OCTEON_CN68XX_PASS2    OCTEON_CN68XX_PASS2_X
+
+#define OCTEON_CN66XX_PASS1_0   0x000d9200
+#define OCTEON_CN66XX_PASS1_2   0x000d9202
+
+#define OCTEON_CN66XX           (OCTEON_CN66XX_PASS1_0 | OM_IGNORE_REVISION)
+#define OCTEON_CN66XX_PASS1_X   (OCTEON_CN66XX_PASS1_0 | OM_IGNORE_MINOR_REVISION)
+
 #define OCTEON_CN63XX_PASS1_0   0x000d9000
 #define OCTEON_CN63XX_PASS1_1   0x000d9001
 #define OCTEON_CN63XX_PASS1_2   0x000d9002
 #define OCTEON_CN63XX_PASS2_0   0x000d9008
+#define OCTEON_CN63XX_PASS2_1   0x000d9009
+#define OCTEON_CN63XX_PASS2_2   0x000d900a
 
 #define OCTEON_CN63XX           (OCTEON_CN63XX_PASS2_0 | OM_IGNORE_REVISION)
 #define OCTEON_CN63XX_PASS1_X   (OCTEON_CN63XX_PASS1_0 | OM_IGNORE_MINOR_REVISION)
 #define OCTEON_CN63XX_PASS2_X   (OCTEON_CN63XX_PASS2_0 | OM_IGNORE_MINOR_REVISION)
 
+#define OCTEON_CN61XX_PASS1_0   0x000d9300
+
+#define OCTEON_CN61XX           (OCTEON_CN61XX_PASS1_0 | OM_IGNORE_REVISION)
+#define OCTEON_CN61XX_PASS1_X   (OCTEON_CN61XX_PASS1_0 | OM_IGNORE_MINOR_REVISION)
+
 /*
  * CN5XXX models with new revision encoding
  */
 #define OCTEON_CN58XX_PASS2_3   0x000d030b
 
 #define OCTEON_CN58XX           (OCTEON_CN58XX_PASS1_0 | OM_IGNORE_REVISION)
-#define OCTEON_CN58XX_PASS1_X   (OCTEON_CN58XX_PASS1_0 \
-                                | OM_IGNORE_MINOR_REVISION)
-#define OCTEON_CN58XX_PASS2_X   (OCTEON_CN58XX_PASS2_0 \
-                                | OM_IGNORE_MINOR_REVISION)
+#define OCTEON_CN58XX_PASS1_X   (OCTEON_CN58XX_PASS1_0 | OM_IGNORE_MINOR_REVISION)
+#define OCTEON_CN58XX_PASS2_X   (OCTEON_CN58XX_PASS2_0 | OM_IGNORE_MINOR_REVISION)
 #define OCTEON_CN58XX_PASS1     OCTEON_CN58XX_PASS1_X
 #define OCTEON_CN58XX_PASS2     OCTEON_CN58XX_PASS2_X
 
 #define OCTEON_CN56XX_PASS2_1   0x000d0409
 
 #define OCTEON_CN56XX           (OCTEON_CN56XX_PASS2_0 | OM_IGNORE_REVISION)
-#define OCTEON_CN56XX_PASS1_X   (OCTEON_CN56XX_PASS1_0 \
-                                | OM_IGNORE_MINOR_REVISION)
-#define OCTEON_CN56XX_PASS2_X   (OCTEON_CN56XX_PASS2_0 \
-                                | OM_IGNORE_MINOR_REVISION)
+#define OCTEON_CN56XX_PASS1_X   (OCTEON_CN56XX_PASS1_0 | OM_IGNORE_MINOR_REVISION)
+#define OCTEON_CN56XX_PASS2_X   (OCTEON_CN56XX_PASS2_0 | OM_IGNORE_MINOR_REVISION)
 #define OCTEON_CN56XX_PASS1     OCTEON_CN56XX_PASS1_X
 #define OCTEON_CN56XX_PASS2     OCTEON_CN56XX_PASS2_X
 
 #define OCTEON_CN50XX_PASS1_0   0x000d0600
 
 #define OCTEON_CN50XX           (OCTEON_CN50XX_PASS1_0 | OM_IGNORE_REVISION)
-#define OCTEON_CN50XX_PASS1_X   (OCTEON_CN50XX_PASS1_0 \
-                                | OM_IGNORE_MINOR_REVISION)
+#define OCTEON_CN50XX_PASS1_X   (OCTEON_CN50XX_PASS1_0 | OM_IGNORE_MINOR_REVISION)
 #define OCTEON_CN50XX_PASS1     OCTEON_CN50XX_PASS1_X
 
 /*
 #define OCTEON_CN52XX_PASS2_0   0x000d0708
 
 #define OCTEON_CN52XX           (OCTEON_CN52XX_PASS2_0 | OM_IGNORE_REVISION)
-#define OCTEON_CN52XX_PASS1_X   (OCTEON_CN52XX_PASS1_0 \
-                                | OM_IGNORE_MINOR_REVISION)
-#define OCTEON_CN52XX_PASS2_X   (OCTEON_CN52XX_PASS2_0 \
-                                | OM_IGNORE_MINOR_REVISION)
+#define OCTEON_CN52XX_PASS1_X   (OCTEON_CN52XX_PASS1_0 | OM_IGNORE_MINOR_REVISION)
+#define OCTEON_CN52XX_PASS2_X   (OCTEON_CN52XX_PASS2_0 | OM_IGNORE_MINOR_REVISION)
 #define OCTEON_CN52XX_PASS1     OCTEON_CN52XX_PASS1_X
 #define OCTEON_CN52XX_PASS2     OCTEON_CN52XX_PASS2_X
 
 #define OCTEON_CN3005_PASS1     (0x000d0210 | OM_CHECK_SUBMODEL)
 #define OCTEON_CN3005_PASS1_0   (0x000d0210 | OM_CHECK_SUBMODEL)
 #define OCTEON_CN3005_PASS1_1   (0x000d0212 | OM_CHECK_SUBMODEL)
-#define OCTEON_CN3005           (OCTEON_CN3005_PASS1 | OM_IGNORE_REVISION \
-                                | OM_CHECK_SUBMODEL)
+#define OCTEON_CN3005           (OCTEON_CN3005_PASS1 | OM_IGNORE_REVISION | OM_CHECK_SUBMODEL)
 
 #define OCTEON_CN3010_PASS1     (0x000d0200 | OM_CHECK_SUBMODEL)
 #define OCTEON_CN3010_PASS1_0   (0x000d0200 | OM_CHECK_SUBMODEL)
 #define OCTEON_CN3010_PASS1_1   (0x000d0202 | OM_CHECK_SUBMODEL)
-#define OCTEON_CN3010           (OCTEON_CN3010_PASS1 | OM_IGNORE_REVISION \
-                                | OM_CHECK_SUBMODEL)
+#define OCTEON_CN3010           (OCTEON_CN3010_PASS1 | OM_IGNORE_REVISION | OM_CHECK_SUBMODEL)
 
 #define OCTEON_CN3020_PASS1     (0x000d0110 | OM_CHECK_SUBMODEL)
 #define OCTEON_CN3020_PASS1_0   (0x000d0110 | OM_CHECK_SUBMODEL)
 #define OCTEON_CN3020_PASS1_1   (0x000d0112 | OM_CHECK_SUBMODEL)
-#define OCTEON_CN3020           (OCTEON_CN3020_PASS1 | OM_IGNORE_REVISION \
-                                | OM_CHECK_SUBMODEL)
-
-
-
-/* This matches the complete family of CN3xxx CPUs, and not subsequent models */
-#define OCTEON_CN3XXX           (OCTEON_CN58XX_PASS1_0 \
-                                | OM_MATCH_PREVIOUS_MODELS \
-                                | OM_IGNORE_REVISION)
+#define OCTEON_CN3020           (OCTEON_CN3020_PASS1 | OM_IGNORE_REVISION | OM_CHECK_SUBMODEL)
 
+/*
+ * This matches the complete family of CN3xxx CPUs, and not subsequent
+ * models
+ */
+#define OCTEON_CN3XXX           (OCTEON_CN58XX_PASS1_0 | OM_MATCH_PREVIOUS_MODELS | OM_IGNORE_REVISION)
 #define OCTEON_CN5XXX           (OCTEON_CN58XX_PASS1_0 | OM_MATCH_5XXX_FAMILY_MODELS)
 #define OCTEON_CN6XXX           (OCTEON_CN63XX_PASS1_0 | OM_MATCH_6XXX_FAMILY_MODELS)
 
 #define OCTEON_38XX_FAMILY_MASK      0x00ffff00
 #define OCTEON_38XX_FAMILY_REV_MASK  0x00ffff0f
 #define OCTEON_38XX_MODEL_MASK       0x00ffff10
-#define OCTEON_38XX_MODEL_REV_MASK   (OCTEON_38XX_FAMILY_REV_MASK \
-                                     | OCTEON_38XX_MODEL_MASK)
+#define OCTEON_38XX_MODEL_REV_MASK   (OCTEON_38XX_FAMILY_REV_MASK | OCTEON_38XX_MODEL_MASK)
 
 /* CN5XXX and later use different layout of bits in the revision ID field */
 #define OCTEON_58XX_FAMILY_MASK      OCTEON_38XX_FAMILY_MASK
 #define OCTEON_58XX_FAMILY_REV_MASK  0x00ffff3f
 #define OCTEON_58XX_MODEL_MASK       0x00ffffc0
-#define OCTEON_58XX_MODEL_REV_MASK   (OCTEON_58XX_FAMILY_REV_MASK \
-                                     | OCTEON_58XX_MODEL_MASK)
-#define OCTEON_58XX_MODEL_MINOR_REV_MASK (OCTEON_58XX_MODEL_REV_MASK \
-                                         & 0x00fffff8)
+#define OCTEON_58XX_MODEL_REV_MASK   (OCTEON_58XX_FAMILY_REV_MASK | OCTEON_58XX_MODEL_MASK)
+#define OCTEON_58XX_MODEL_MINOR_REV_MASK (OCTEON_58XX_MODEL_REV_MASK & 0x00fffff8)
 #define OCTEON_5XXX_MODEL_MASK       0x00ff0fc0
 
-#define __OCTEON_MATCH_MASK__(x, y, z) (((x) & (z)) == ((y) & (z)))
-
-/* NOTE: This is for internal (to this file) use only. */
-static inline int __OCTEON_IS_MODEL_COMPILE__(uint32_t arg_model,
-                                             uint32_t chip_model)
-{
-       uint32_t rev_and_sub = OM_IGNORE_REVISION | OM_CHECK_SUBMODEL;
-
-       if ((arg_model & OCTEON_38XX_FAMILY_MASK) < OCTEON_CN58XX_PASS1_0) {
-               if (((arg_model & OM_FLAG_MASK) == rev_and_sub) &&
-                   __OCTEON_MATCH_MASK__(chip_model, arg_model,
-                                         OCTEON_38XX_MODEL_MASK))
-                       return 1;
-               if (((arg_model & OM_FLAG_MASK) == 0) &&
-                   __OCTEON_MATCH_MASK__(chip_model, arg_model,
-                                         OCTEON_38XX_FAMILY_REV_MASK))
-                       return 1;
-               if (((arg_model & OM_FLAG_MASK) == OM_IGNORE_REVISION) &&
-                   __OCTEON_MATCH_MASK__(chip_model, arg_model,
-                                         OCTEON_38XX_FAMILY_MASK))
-                       return 1;
-               if (((arg_model & OM_FLAG_MASK) == OM_CHECK_SUBMODEL) &&
-                   __OCTEON_MATCH_MASK__((chip_model), (arg_model),
-                                         OCTEON_38XX_MODEL_REV_MASK))
-                       return 1;
-               if ((arg_model & OM_MATCH_PREVIOUS_MODELS) &&
-                   ((chip_model & OCTEON_38XX_MODEL_MASK) <
-                           (arg_model & OCTEON_38XX_MODEL_MASK)))
-                       return 1;
-       } else {
-               if (((arg_model & OM_FLAG_MASK) == rev_and_sub) &&
-                   __OCTEON_MATCH_MASK__((chip_model), (arg_model),
-                                         OCTEON_58XX_MODEL_MASK))
-                       return 1;
-               if (((arg_model & OM_FLAG_MASK) == 0) &&
-                   __OCTEON_MATCH_MASK__((chip_model), (arg_model),
-                                         OCTEON_58XX_FAMILY_REV_MASK))
-                       return 1;
-               if (((arg_model & OM_FLAG_MASK) == OM_IGNORE_MINOR_REVISION) &&
-                   __OCTEON_MATCH_MASK__((chip_model), (arg_model),
-                                         OCTEON_58XX_MODEL_MINOR_REV_MASK))
-                       return 1;
-               if (((arg_model & OM_FLAG_MASK) == OM_IGNORE_REVISION) &&
-                   __OCTEON_MATCH_MASK__((chip_model), (arg_model),
-                                         OCTEON_58XX_FAMILY_MASK))
-                       return 1;
-               if (((arg_model & OM_FLAG_MASK) == OM_CHECK_SUBMODEL) &&
-                   __OCTEON_MATCH_MASK__((chip_model), (arg_model),
-                                         OCTEON_58XX_MODEL_REV_MASK))
-                       return 1;
-
-               if (((arg_model & OM_MATCH_5XXX_FAMILY_MODELS) == OM_MATCH_5XXX_FAMILY_MODELS) &&
-                   ((chip_model) >= OCTEON_CN58XX_PASS1_0) && ((chip_model) < OCTEON_CN63XX_PASS1_0))
-                       return 1;
-
-               if (((arg_model & OM_MATCH_6XXX_FAMILY_MODELS) == OM_MATCH_6XXX_FAMILY_MODELS) &&
-                   ((chip_model) >= OCTEON_CN63XX_PASS1_0))
-                       return 1;
-
-               if ((arg_model & OM_MATCH_PREVIOUS_MODELS) &&
-                   ((chip_model & OCTEON_58XX_MODEL_MASK) <
-                           (arg_model & OCTEON_58XX_MODEL_MASK)))
-                       return 1;
-       }
-       return 0;
-}
-
 /* forward declarations */
 static inline uint32_t cvmx_get_proc_id(void) __attribute__ ((pure));
 static inline uint64_t cvmx_read_csr(uint64_t csr_addr);
 
+#define __OCTEON_MATCH_MASK__(x, y, z) (((x) & (z)) == ((y) & (z)))
+
+/* NOTE: This for internal use only! */
+#define __OCTEON_IS_MODEL_COMPILE__(arg_model, chip_model)             \
+((((arg_model & OCTEON_38XX_FAMILY_MASK) < OCTEON_CN58XX_PASS1_0)  && (        \
+               ((((arg_model) & (OM_FLAG_MASK)) == (OM_IGNORE_REVISION | OM_CHECK_SUBMODEL)) \
+                       && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_38XX_MODEL_MASK)) || \
+               ((((arg_model) & (OM_FLAG_MASK)) == 0)                  \
+                       && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_38XX_FAMILY_REV_MASK)) || \
+               ((((arg_model) & (OM_FLAG_MASK)) == OM_IGNORE_REVISION) \
+                       && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_38XX_FAMILY_MASK)) || \
+               ((((arg_model) & (OM_FLAG_MASK)) == OM_CHECK_SUBMODEL)  \
+                       && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_38XX_MODEL_REV_MASK)) || \
+               ((((arg_model) & (OM_MATCH_PREVIOUS_MODELS)) == OM_MATCH_PREVIOUS_MODELS) \
+                       && (((chip_model) & OCTEON_38XX_MODEL_MASK) < ((arg_model) & OCTEON_38XX_MODEL_MASK))) \
+               )) ||                                                   \
+       (((arg_model & OCTEON_38XX_FAMILY_MASK) >= OCTEON_CN58XX_PASS1_0)  && ( \
+               ((((arg_model) & (OM_FLAG_MASK)) == (OM_IGNORE_REVISION | OM_CHECK_SUBMODEL)) \
+                       && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_58XX_MODEL_MASK)) || \
+               ((((arg_model) & (OM_FLAG_MASK)) == 0)                  \
+                       && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_58XX_FAMILY_REV_MASK)) || \
+               ((((arg_model) & (OM_FLAG_MASK)) == OM_IGNORE_MINOR_REVISION) \
+                       && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_58XX_MODEL_MINOR_REV_MASK)) || \
+               ((((arg_model) & (OM_FLAG_MASK)) == OM_IGNORE_REVISION) \
+                       && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_58XX_FAMILY_MASK)) || \
+               ((((arg_model) & (OM_FLAG_MASK)) == OM_CHECK_SUBMODEL)  \
+                       && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_58XX_MODEL_REV_MASK)) || \
+               ((((arg_model) & (OM_MATCH_5XXX_FAMILY_MODELS)) == OM_MATCH_5XXX_FAMILY_MODELS) \
+                       && ((chip_model) >= OCTEON_CN58XX_PASS1_0) && ((chip_model) < OCTEON_CN63XX_PASS1_0)) || \
+               ((((arg_model) & (OM_MATCH_6XXX_FAMILY_MODELS)) == OM_MATCH_6XXX_FAMILY_MODELS) \
+                       && ((chip_model) >= OCTEON_CN63XX_PASS1_0)) ||  \
+               ((((arg_model) & (OM_MATCH_PREVIOUS_MODELS)) == OM_MATCH_PREVIOUS_MODELS) \
+                       && (((chip_model) & OCTEON_58XX_MODEL_MASK) < ((arg_model) & OCTEON_58XX_MODEL_MASK))) \
+               )))
+
 /* NOTE: This for internal use only!!!!! */
 static inline int __octeon_is_model_runtime__(uint32_t model)
 {
@@ -312,22 +286,25 @@ static inline int __octeon_is_model_runtime__(uint32_t model)
 
        /*
         * Check for special case of mismarked 3005 samples. We only
-        * need to check if the sub model isn't being ignored.
+        * need to check if the sub model isn't being ignored
         */
        if ((model & OM_CHECK_SUBMODEL) == OM_CHECK_SUBMODEL) {
-               if (cpuid == OCTEON_CN3010_PASS1 \
-                   && (cvmx_read_csr(0x80011800800007B8ull) & (1ull << 34)))
+               if (cpuid == OCTEON_CN3010_PASS1 && (cvmx_read_csr(0x80011800800007B8ull) & (1ull << 34)))
                        cpuid |= 0x10;
        }
        return __OCTEON_IS_MODEL_COMPILE__(model, cpuid);
 }
 
 /*
- * The OCTEON_IS_MODEL macro should be used for all Octeon model
- * checking done in a program.  This should be kept runtime if at all
- * possible.  Any compile time (#if OCTEON_IS_MODEL) usage must be
- * condtionalized with OCTEON_IS_COMMON_BINARY() if runtime checking
- * support is required.
+ * The OCTEON_IS_MODEL macro should be used for all Octeon model checking done
+ * in a program.
+ * This should be kept runtime if at all possible  and must be conditionalized
+ * with OCTEON_IS_COMMON_BINARY() if runtime checking support is required.
+ *
+ * Use of the macro in preprocessor directives ( #if OCTEON_IS_MODEL(...) )
+ * is NOT SUPPORTED, and should be replaced with CVMX_COMPILED_FOR()
+ * I.e.:
+ *  #if OCTEON_IS_MODEL(OCTEON_CN56XX)  ->  #if CVMX_COMPILED_FOR(OCTEON_CN56XX)
  */
 #define OCTEON_IS_MODEL(x) __octeon_is_model_runtime__(x)
 #define OCTEON_IS_COMMON_BINARY() 1
index fba2ba200f587a885d559b71fbda755d2c92b5a9..c66734bd33821a1549d72eb1f7163e7fe5de108a 100644 (file)
@@ -56,7 +56,8 @@ enum octeon_dma_bar_type {
        OCTEON_DMA_BAR_TYPE_INVALID,
        OCTEON_DMA_BAR_TYPE_SMALL,
        OCTEON_DMA_BAR_TYPE_BIG,
-       OCTEON_DMA_BAR_TYPE_PCIE
+       OCTEON_DMA_BAR_TYPE_PCIE,
+       OCTEON_DMA_BAR_TYPE_PCIE2
 };
 
 /*
index e59cd1ac09c2f82eb8c91af1bdb0b6a520513d89..d41790928c648de70fb02a7404517f1fc7a94fba 100644 (file)
 #define HPAGE_SIZE     (_AC(1,UL) << HPAGE_SHIFT)
 #define HPAGE_MASK     (~(HPAGE_SIZE - 1))
 #define HUGETLB_PAGE_ORDER     (HPAGE_SHIFT - PAGE_SHIFT)
+#else /* !CONFIG_HUGETLB_PAGE */
+# ifndef BUILD_BUG
+#  define BUILD_BUG() do { extern void __build_bug(void); __build_bug(); } while (0)
+# endif
+#define HPAGE_SHIFT    ({BUILD_BUG(); 0; })
+#define HPAGE_SIZE     ({BUILD_BUG(); 0; })
+#define HPAGE_MASK     ({BUILD_BUG(); 0; })
+#define HUGETLB_PAGE_ORDER     ({BUILD_BUG(); 0; })
 #endif /* CONFIG_HUGETLB_PAGE */
 
 #ifndef __ASSEMBLY__
index 8a153d2fa62af5aa1d3666f232e850e985e2b0ef..5d56bb2303454e1ff3937d2acd0a99f97bba864f 100644 (file)
 #include <asm-generic/pgtable-nopmd.h>
 
 /*
- * - add_wired_entry() add a fixed TLB entry, and move wired register
- */
-extern void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
-                              unsigned long entryhi, unsigned long pagemask);
-
-/*
- * - add_temporary_entry() add a temporary TLB entry. We use TLB entries
- *     starting at the top and working down. This is for populating the
- *     TLB before trap_init() puts the TLB miss handler in place. It
- *     should be used only for entries matching the actual page tables,
- *     to prevent inconsistencies.
- */
-extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
-                              unsigned long entryhi, unsigned long pagemask);
-
-
-/* Basically we have the same two-level (which is the logical three level
+ * Basically we have the same two-level (which is the logical three level
  * Linux page table layout folded) page tables as the i386.  Some day
  * when we have proper page coloring support we can have a 1% quicker
  * tlb refill handling mechanism, but for now it is a bit slower but
index de39b1f343ea2537b459eed56f53ea9b35732554..4b7f5252d2fd31ba156723c23db11e57e983442b 100644 (file)
@@ -137,14 +137,26 @@ extern int ptrace_set_watch_regs(struct task_struct *child,
  */
 #define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER)
 
-#define regs_return_value(_regs) ((_regs)->regs[2])
+static inline int is_syscall_success(struct pt_regs *regs)
+{
+       return !regs->regs[7];
+}
+
+static inline long regs_return_value(struct pt_regs *regs)
+{
+       if (is_syscall_success(regs))
+               return regs->regs[2];
+       else
+               return -regs->regs[2];
+}
+
 #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 void syscall_trace_leave(struct pt_regs *regs);
 
-extern NORET_TYPE void die(const char *, struct pt_regs *) ATTRIB_NORET;
+extern void die(const char *, struct pt_regs *) __noreturn;
 
 static inline void die_if_kernel(const char *str, struct pt_regs *regs)
 {
diff --git a/arch/mips/include/asm/tlbmisc.h b/arch/mips/include/asm/tlbmisc.h
new file mode 100644 (file)
index 0000000..3a45228
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __ASM_TLBMISC_H
+#define __ASM_TLBMISC_H
+
+/*
+ * - add_wired_entry() add a fixed TLB entry, and move wired register
+ */
+extern void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+       unsigned long entryhi, unsigned long pagemask);
+
+#endif /* __ASM_TLBMISC_H */
index 90ff2f497c500f84d925773584c4c148356dd793..ff74aec3561a3f0a88829db33c15b87887fdcbc9 100644 (file)
@@ -24,5 +24,18 @@ extern int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
 extern void (*board_nmi_handler_setup)(void);
 extern void (*board_ejtag_handler_setup)(void);
 extern void (*board_bind_eic_interrupt)(int irq, int regset);
+extern void (*board_ebase_setup)(void);
+
+extern int register_nmi_notifier(struct notifier_block *nb);
+
+#define nmi_notifier(fn, pri)                                          \
+({                                                                     \
+       static struct notifier_block fn##_nb = {                        \
+               .notifier_call = fn,                                    \
+               .priority = pri                                         \
+       };                                                              \
+                                                                       \
+       register_nmi_notifier(&fn##_nb);                                \
+})
 
 #endif /* _ASM_TRAPS_H */
index 43bf70ebd3a2a8a79d7dff586c5810b5bcd55fb0..1228b25b290a39a049bf4ae50a3c26b2ca37b531 100644 (file)
  * We don't use int-l64.h for the kernel anymore but still use it for
  * userspace to avoid code changes.
  */
-#if (_MIPS_SZLONG == 64) && !defined(__KERNEL__)
-# include <asm-generic/int-l64.h>
-#else
+#ifdef __KERNEL__
 # include <asm-generic/int-ll64.h>
+#else
+# if _MIPS_SZLONG == 64
+#  include <asm-generic/int-l64.h>
+# else
+#  include <asm-generic/int-ll64.h>
+# endif
 #endif
 
 /*
index ca9bd206914257e2479e9b750653f05790ad887d..f21868b28b24e19575d49210bb709333d3653309 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/io.h>
 #include <asm/jazz.h>
 #include <asm/pgtable.h>
+#include <asm/tlbmisc.h>
 
 static DEFINE_RAW_SPINLOCK(r4030_lock);
 
@@ -133,7 +134,7 @@ static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction r4030_timer_irqaction = {
        .handler        = r4030_timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .flags          = IRQF_TIMER,
        .name           = "R4030 timer",
 };
 
index 0d0f054a02f4bfc309ad3b7290b83a90dae26cfd..820e926dacbc5856167fdd34893d4b1c59ead161 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/jazzdma.h>
 #include <asm/reboot.h>
 #include <asm/pgtable.h>
+#include <asm/tlbmisc.h>
 
 extern asmlinkage void jazz_handle_int(void);
 
index c3b04be3fb2bb4c056e2cb531b5c473d53d23c9f..639e3ce6c264d4f8af8137efffff5fdf280992cf 100644 (file)
@@ -488,7 +488,7 @@ static int __init qi_lb60_board_setup(void)
        board_gpio_setup();
 
        if (qi_lb60_init_platform_devices())
-               panic("Failed to initialize platform devices\n");
+               panic("Failed to initialize platform devices");
 
        return 0;
 }
index 1a966183e3531c4c9f5dd735310364e82526cf6d..0c6877ea900495f547e087be39c11870d1d95dd7 100644 (file)
@@ -55,9 +55,11 @@ obj-$(CONFIG_CPU_TX49XX)     += r4k_fpu.o r4k_switch.o
 obj-$(CONFIG_CPU_VR41XX)       += r4k_fpu.o r4k_switch.o
 obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += octeon_switch.o
 obj-$(CONFIG_CPU_XLR)          += r4k_fpu.o r4k_switch.o
+obj-$(CONFIG_CPU_XLP)          += r4k_fpu.o r4k_switch.o
 
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_SMP_UP)           += smp-up.o
+obj-$(CONFIG_CPU_BMIPS)                += smp-bmips.o bmips_vec.o
 
 obj-$(CONFIG_MIPS_MT)          += mips-mt.o
 obj-$(CONFIG_MIPS_MT_FPAFF)    += mips-mt-fpaff.o
diff --git a/arch/mips/kernel/bmips_vec.S b/arch/mips/kernel/bmips_vec.S
new file mode 100644 (file)
index 0000000..e908e81
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2011 by Kevin Cernekee (cernekee@gmail.com)
+ *
+ * Reset/NMI/re-entry vectors for BMIPS processors
+ */
+
+#include <linux/init.h>
+
+#include <asm/asm.h>
+#include <asm/asmmacro.h>
+#include <asm/cacheops.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+#include <asm/addrspace.h>
+#include <asm/hazards.h>
+#include <asm/bmips.h>
+
+       .macro  BARRIER
+       .set    mips32
+       _ssnop
+       _ssnop
+       _ssnop
+       .set    mips0
+       .endm
+
+       __CPUINIT
+
+/***********************************************************************
+ * Alternate CPU1 startup vector for BMIPS4350
+ *
+ * On some systems the bootloader has already started CPU1 and configured
+ * it to resume execution at 0x8000_0200 (!BEV IV vector) when it is
+ * triggered by the SW1 interrupt.  If that is the case we try to move
+ * it to a more convenient place: BMIPS_WARM_RESTART_VEC @ 0x8000_0380.
+ ***********************************************************************/
+
+LEAF(bmips_smp_movevec)
+       la      k0, 1f
+       li      k1, CKSEG1
+       or      k0, k1
+       jr      k0
+
+1:
+       /* clear IV, pending IPIs */
+       mtc0    zero, CP0_CAUSE
+
+       /* re-enable IRQs to wait for SW1 */
+       li      k0, ST0_IE | ST0_BEV | STATUSF_IP1
+       mtc0    k0, CP0_STATUS
+
+       /* set up CPU1 CBR; move BASE to 0xa000_0000 */
+       li      k0, 0xff400000
+       mtc0    k0, $22, 6
+       li      k1, CKSEG1 | BMIPS_RELO_VECTOR_CONTROL_1
+       or      k0, k1
+       li      k1, 0xa0080000
+       sw      k1, 0(k0)
+
+       /* wait here for SW1 interrupt from bmips_boot_secondary() */
+       wait
+
+       la      k0, bmips_reset_nmi_vec
+       li      k1, CKSEG1
+       or      k0, k1
+       jr      k0
+END(bmips_smp_movevec)
+
+/***********************************************************************
+ * Reset/NMI vector
+ * For BMIPS processors that can relocate their exception vectors, this
+ * entire function gets copied to 0x8000_0000.
+ ***********************************************************************/
+
+NESTED(bmips_reset_nmi_vec, PT_SIZE, sp)
+       .set    push
+       .set    noat
+       .align  4
+
+#ifdef CONFIG_SMP
+       /* if the NMI bit is clear, assume this is a CPU1 reset instead */
+       li      k1, (1 << 19)
+       mfc0    k0, CP0_STATUS
+       and     k0, k1
+       beqz    k0, bmips_smp_entry
+
+#if defined(CONFIG_CPU_BMIPS5000)
+       /* if we're not on core 0, this must be the SMP boot signal */
+       li      k1, (3 << 25)
+       mfc0    k0, $22
+       and     k0, k1
+       bnez    k0, bmips_smp_entry
+#endif
+#endif /* CONFIG_SMP */
+
+       /* nope, it's just a regular NMI */
+       SAVE_ALL
+       move    a0, sp
+
+       /* clear EXL, ERL, BEV so that TLB refills still work */
+       mfc0    k0, CP0_STATUS
+       li      k1, ST0_ERL | ST0_EXL | ST0_BEV | ST0_IE
+       or      k0, k1
+       xor     k0, k1
+       mtc0    k0, CP0_STATUS
+       BARRIER
+
+       /* jump to the NMI handler function */
+       la      k0, nmi_handler
+       jr      k0
+
+       RESTORE_ALL
+       .set    mips3
+       eret
+
+/***********************************************************************
+ * CPU1 reset vector (used for the initial boot only)
+ * This is still part of bmips_reset_nmi_vec().
+ ***********************************************************************/
+
+#ifdef CONFIG_SMP
+
+bmips_smp_entry:
+
+       /* set up CP0 STATUS; enable FPU */
+       li      k0, 0x30000000
+       mtc0    k0, CP0_STATUS
+       BARRIER
+
+       /* set local CP0 CONFIG to make kseg0 cacheable, write-back */
+       mfc0    k0, CP0_CONFIG
+       ori     k0, 0x07
+       xori    k0, 0x04
+       mtc0    k0, CP0_CONFIG
+
+#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
+       /* initialize CPU1's local I-cache */
+       li      k0, 0x80000000
+       li      k1, 0x80010000
+       mtc0    zero, $28
+       mtc0    zero, $28, 1
+       BARRIER
+
+1:     cache   Index_Store_Tag_I, 0(k0)
+       addiu   k0, 16
+       bne     k0, k1, 1b
+#elif defined(CONFIG_CPU_BMIPS5000)
+       /* set exception vector base */
+       la      k0, ebase
+       lw      k0, 0(k0)
+       mtc0    k0, $15, 1
+       BARRIER
+#endif
+
+       /* jump back to kseg0 in case we need to remap the kseg1 area */
+       la      k0, 1f
+       jr      k0
+1:
+       la      k0, bmips_enable_xks01
+       jalr    k0
+
+       /* use temporary stack to set up upper memory TLB */
+       li      sp, BMIPS_WARM_RESTART_VEC
+       la      k0, plat_wired_tlb_setup
+       jalr    k0
+
+       /* switch to permanent stack and continue booting */
+
+       .global bmips_secondary_reentry
+bmips_secondary_reentry:
+       la      k0, bmips_smp_boot_sp
+       lw      sp, 0(k0)
+       la      k0, bmips_smp_boot_gp
+       lw      gp, 0(k0)
+       la      k0, start_secondary
+       jr      k0
+
+#endif /* CONFIG_SMP */
+
+       .align  4
+       .global bmips_reset_nmi_vec_end
+bmips_reset_nmi_vec_end:
+
+END(bmips_reset_nmi_vec)
+
+       .set    pop
+       .previous
+
+/***********************************************************************
+ * CPU1 warm restart vector (used for second and subsequent boots).
+ * Also used for S2 standby recovery (PM).
+ * This entire function gets copied to (BMIPS_WARM_RESTART_VEC)
+ ***********************************************************************/
+
+LEAF(bmips_smp_int_vec)
+
+       .align  4
+       mfc0    k0, CP0_STATUS
+       ori     k0, 0x01
+       xori    k0, 0x01
+       mtc0    k0, CP0_STATUS
+       eret
+
+       .align  4
+       .global bmips_smp_int_vec_end
+bmips_smp_int_vec_end:
+
+END(bmips_smp_int_vec)
+
+/***********************************************************************
+ * XKS01 support
+ * Certain CPUs support extending kseg0 to 1024MB.
+ ***********************************************************************/
+
+       __CPUINIT
+
+LEAF(bmips_enable_xks01)
+
+#if defined(CONFIG_XKS01)
+
+#if defined(CONFIG_CPU_BMIPS4380)
+       mfc0    t0, $22, 3
+       li      t1, 0x1ff0
+       li      t2, (1 << 12) | (1 << 9)
+       or      t0, t1
+       xor     t0, t1
+       or      t0, t2
+       mtc0    t0, $22, 3
+       BARRIER
+#elif defined(CONFIG_CPU_BMIPS5000)
+       mfc0    t0, $22, 5
+       li      t1, 0x01ff
+       li      t2, (1 << 8) | (1 << 5)
+       or      t0, t1
+       xor     t0, t1
+       or      t0, t2
+       mtc0    t0, $22, 5
+       BARRIER
+#else
+
+#error Missing XKS01 setup
+
+#endif
+
+#endif /* defined(CONFIG_XKS01) */
+
+       jr      ra
+
+END(bmips_enable_xks01)
+
+       .previous
index 32103cc2a2576877592d91050b86c8944a2479d9..4d735d0e58f5c9caea2ae5936054e0ce1a66dd08 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
+#include <linux/module.h>
 #include <asm/branch.h>
 #include <asm/cpu.h>
 #include <asm/cpu-features.h>
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 
-/*
- * Compute the return address and do emulate branch simulation, if required.
+/**
+ * __compute_return_epc_for_insn - Computes the return address and do emulate
+ *                                 branch simulation, if required.
+ *
+ * @regs:      Pointer to pt_regs
+ * @insn:      branch instruction to decode
+ * @returns:   -EFAULT on error and forces SIGBUS, and on success
+ *             returns 0 or BRANCH_LIKELY_TAKEN as appropriate after
+ *             evaluating the branch.
  */
-int __compute_return_epc(struct pt_regs *regs)
+int __compute_return_epc_for_insn(struct pt_regs *regs,
+                                  union mips_instruction insn)
 {
-       unsigned int __user *addr;
        unsigned int bit, fcr31, dspcontrol;
-       long epc;
-       union mips_instruction insn;
-
-       epc = regs->cp0_epc;
-       if (epc & 3)
-               goto unaligned;
-
-       /*
-        * Read the instruction
-        */
-       addr = (unsigned int __user *) epc;
-       if (__get_user(insn.word, addr)) {
-               force_sig(SIGSEGV, current);
-               return -EFAULT;
-       }
+       long epc = regs->cp0_epc;
+       int ret = 0;
 
        switch (insn.i_format.opcode) {
        /*
@@ -64,18 +59,22 @@ int __compute_return_epc(struct pt_regs *regs)
                switch (insn.i_format.rt) {
                case bltz_op:
                case bltzl_op:
-                       if ((long)regs->regs[insn.i_format.rs] < 0)
+                       if ((long)regs->regs[insn.i_format.rs] < 0) {
                                epc = epc + 4 + (insn.i_format.simmediate << 2);
-                       else
+                               if (insn.i_format.rt == bltzl_op)
+                                       ret = BRANCH_LIKELY_TAKEN;
+                       } else
                                epc += 8;
                        regs->cp0_epc = epc;
                        break;
 
                case bgez_op:
                case bgezl_op:
-                       if ((long)regs->regs[insn.i_format.rs] >= 0)
+                       if ((long)regs->regs[insn.i_format.rs] >= 0) {
                                epc = epc + 4 + (insn.i_format.simmediate << 2);
-                       else
+                               if (insn.i_format.rt == bgezl_op)
+                                       ret = BRANCH_LIKELY_TAKEN;
+                       } else
                                epc += 8;
                        regs->cp0_epc = epc;
                        break;
@@ -83,9 +82,11 @@ int __compute_return_epc(struct pt_regs *regs)
                case bltzal_op:
                case bltzall_op:
                        regs->regs[31] = epc + 8;
-                       if ((long)regs->regs[insn.i_format.rs] < 0)
+                       if ((long)regs->regs[insn.i_format.rs] < 0) {
                                epc = epc + 4 + (insn.i_format.simmediate << 2);
-                       else
+                               if (insn.i_format.rt == bltzall_op)
+                                       ret = BRANCH_LIKELY_TAKEN;
+                       } else
                                epc += 8;
                        regs->cp0_epc = epc;
                        break;
@@ -93,12 +94,15 @@ int __compute_return_epc(struct pt_regs *regs)
                case bgezal_op:
                case bgezall_op:
                        regs->regs[31] = epc + 8;
-                       if ((long)regs->regs[insn.i_format.rs] >= 0)
+                       if ((long)regs->regs[insn.i_format.rs] >= 0) {
                                epc = epc + 4 + (insn.i_format.simmediate << 2);
-                       else
+                               if (insn.i_format.rt == bgezall_op)
+                                       ret = BRANCH_LIKELY_TAKEN;
+                       } else
                                epc += 8;
                        regs->cp0_epc = epc;
                        break;
+
                case bposge32_op:
                        if (!cpu_has_dsp)
                                goto sigill;
@@ -133,9 +137,11 @@ int __compute_return_epc(struct pt_regs *regs)
        case beq_op:
        case beql_op:
                if (regs->regs[insn.i_format.rs] ==
-                   regs->regs[insn.i_format.rt])
+                   regs->regs[insn.i_format.rt]) {
                        epc = epc + 4 + (insn.i_format.simmediate << 2);
-               else
+                       if (insn.i_format.rt == beql_op)
+                               ret = BRANCH_LIKELY_TAKEN;
+               } else
                        epc += 8;
                regs->cp0_epc = epc;
                break;
@@ -143,9 +149,11 @@ int __compute_return_epc(struct pt_regs *regs)
        case bne_op:
        case bnel_op:
                if (regs->regs[insn.i_format.rs] !=
-                   regs->regs[insn.i_format.rt])
+                   regs->regs[insn.i_format.rt]) {
                        epc = epc + 4 + (insn.i_format.simmediate << 2);
-               else
+                       if (insn.i_format.rt == bnel_op)
+                               ret = BRANCH_LIKELY_TAKEN;
+               } else
                        epc += 8;
                regs->cp0_epc = epc;
                break;
@@ -153,9 +161,11 @@ int __compute_return_epc(struct pt_regs *regs)
        case blez_op: /* not really i_format */
        case blezl_op:
                /* rt field assumed to be zero */
-               if ((long)regs->regs[insn.i_format.rs] <= 0)
+               if ((long)regs->regs[insn.i_format.rs] <= 0) {
                        epc = epc + 4 + (insn.i_format.simmediate << 2);
-               else
+                       if (insn.i_format.rt == bnel_op)
+                               ret = BRANCH_LIKELY_TAKEN;
+               } else
                        epc += 8;
                regs->cp0_epc = epc;
                break;
@@ -163,9 +173,11 @@ int __compute_return_epc(struct pt_regs *regs)
        case bgtz_op:
        case bgtzl_op:
                /* rt field assumed to be zero */
-               if ((long)regs->regs[insn.i_format.rs] > 0)
+               if ((long)regs->regs[insn.i_format.rs] > 0) {
                        epc = epc + 4 + (insn.i_format.simmediate << 2);
-               else
+                       if (insn.i_format.rt == bnel_op)
+                               ret = BRANCH_LIKELY_TAKEN;
+               } else
                        epc += 8;
                regs->cp0_epc = epc;
                break;
@@ -187,18 +199,22 @@ int __compute_return_epc(struct pt_regs *regs)
                switch (insn.i_format.rt & 3) {
                case 0: /* bc1f */
                case 2: /* bc1fl */
-                       if (~fcr31 & (1 << bit))
+                       if (~fcr31 & (1 << bit)) {
                                epc = epc + 4 + (insn.i_format.simmediate << 2);
-                       else
+                               if (insn.i_format.rt == 2)
+                                       ret = BRANCH_LIKELY_TAKEN;
+                       } else
                                epc += 8;
                        regs->cp0_epc = epc;
                        break;
 
                case 1: /* bc1t */
                case 3: /* bc1tl */
-                       if (fcr31 & (1 << bit))
+                       if (fcr31 & (1 << bit)) {
                                epc = epc + 4 + (insn.i_format.simmediate << 2);
-                       else
+                               if (insn.i_format.rt == 3)
+                                       ret = BRANCH_LIKELY_TAKEN;
+                       } else
                                epc += 8;
                        regs->cp0_epc = epc;
                        break;
@@ -239,15 +255,39 @@ int __compute_return_epc(struct pt_regs *regs)
 #endif
        }
 
-       return 0;
+       return ret;
 
-unaligned:
-       printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
+sigill:
+       printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
        force_sig(SIGBUS, current);
        return -EFAULT;
+}
+EXPORT_SYMBOL_GPL(__compute_return_epc_for_insn);
 
-sigill:
-       printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
+int __compute_return_epc(struct pt_regs *regs)
+{
+       unsigned int __user *addr;
+       long epc;
+       union mips_instruction insn;
+
+       epc = regs->cp0_epc;
+       if (epc & 3)
+               goto unaligned;
+
+       /*
+        * Read the instruction
+        */
+       addr = (unsigned int __user *) epc;
+       if (__get_user(insn.word, addr)) {
+               force_sig(SIGSEGV, current);
+               return -EFAULT;
+       }
+
+       return __compute_return_epc_for_insn(regs, insn);
+
+unaligned:
+       printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
        force_sig(SIGBUS, current);
        return -EFAULT;
+
 }
index 36c3898b76dbb01182184744fec80056c1132cd8..69bbfae183bcfafd46f4c4b559e3368233085df2 100644 (file)
@@ -145,7 +145,7 @@ void __cpuinit sb1480_clockevent_init(void)
        bcm1480_unmask_irq(cpu, irq);
 
        action->handler = sibyte_counter_handler;
-       action->flags   = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER;
+       action->flags   = IRQF_PERCPU | IRQF_TIMER;
        action->name    = name;
        action->dev_id  = cd;
 
index 939157e397b940fd811d348997840c9dc34a0a0b..ed648cb5a69fcc9229fcecbdcb70f30d55c55656 100644 (file)
@@ -108,7 +108,7 @@ static irqreturn_t ds1287_interrupt(int irq, void *dev_id)
 
 static struct irqaction ds1287_irqaction = {
        .handler        = ds1287_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags          = IRQF_PERCPU | IRQF_TIMER,
        .name           = "ds1287",
 };
 
index 339f3639b90e463d41931b7b127c3173e74297af..831b47585b7ceac273790c2cfa92ffff4160e0c4 100644 (file)
@@ -114,7 +114,7 @@ static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id)
 
 static struct irqaction gt641xx_timer0_irqaction = {
        .handler        = gt641xx_timer0_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags          = IRQF_PERCPU | IRQF_TIMER,
        .name           = "gt641xx_timer0",
 };
 
index e2d8e199be323345a6feaf3eb03a738e515dd5f5..51095dd9599d307605caeb8c2aca9e99a0e8dce1 100644 (file)
@@ -84,7 +84,7 @@ out:
 
 struct irqaction c0_compare_irqaction = {
        .handler = c0_compare_interrupt,
-       .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags = IRQF_PERCPU | IRQF_TIMER,
        .name = "timer",
 };
 
index 590c54f28a81772f961b2513fef1147d4d581f62..e73439fd685078114996819991dac66a4181fe9e 100644 (file)
@@ -144,7 +144,7 @@ void __cpuinit sb1250_clockevent_init(void)
        sb1250_unmask_irq(cpu, irq);
 
        action->handler = sibyte_counter_handler;
-       action->flags   = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER;
+       action->flags   = IRQF_PERCPU | IRQF_TIMER;
        action->name    = name;
        action->dev_id  = cd;
 
index f0ab92a1b0573b49637f648b9e36c91adf14ae48..e5c30b1d0860f5e1e669070619833f4605cfef1c 100644 (file)
@@ -146,7 +146,7 @@ static irqreturn_t txx9tmr_interrupt(int irq, void *dev_id)
 
 static struct irqaction txx9tmr_irq = {
        .handler        = txx9tmr_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags          = IRQF_PERCPU | IRQF_TIMER,
        .name           = "txx9tmr",
        .dev_id         = &txx9_clock_event_device,
 };
index c7d3cf1ce46e275b11df8c210f1553c5eb0bd74c..0bab464b8e33be322e64dacc1263189c71dbb1ac 100644 (file)
@@ -191,6 +191,8 @@ void __init check_wait(void)
        case CPU_CAVIUM_OCTEON_PLUS:
        case CPU_CAVIUM_OCTEON2:
        case CPU_JZRISC:
+       case CPU_XLR:
+       case CPU_XLP:
                cpu_wait = r4k_wait;
                break;
 
@@ -1014,6 +1016,13 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
 {
        decode_configs(c);
 
+       if ((c->processor_id & 0xff00) == PRID_IMP_NETLOGIC_AU13XX) {
+               c->cputype = CPU_ALCHEMY;
+               __cpu_name[cpu] = "Au1300";
+               /* following stuff is not for Alchemy */
+               return;
+       }
+
        c->options = (MIPS_CPU_TLB       |
                        MIPS_CPU_4KEX    |
                        MIPS_CPU_COUNTER |
@@ -1023,6 +1032,12 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
                        MIPS_CPU_LLSC);
 
        switch (c->processor_id & 0xff00) {
+       case PRID_IMP_NETLOGIC_XLP8XX:
+       case PRID_IMP_NETLOGIC_XLP3XX:
+               c->cputype = CPU_XLP;
+               __cpu_name[cpu] = "Netlogic XLP";
+               break;
+
        case PRID_IMP_NETLOGIC_XLR732:
        case PRID_IMP_NETLOGIC_XLR716:
        case PRID_IMP_NETLOGIC_XLR532:
@@ -1053,14 +1068,21 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
                break;
 
        default:
-               printk(KERN_INFO "Unknown Netlogic chip id [%02x]!\n",
+               pr_info("Unknown Netlogic chip id [%02x]!\n",
                       c->processor_id);
                c->cputype = CPU_XLR;
                break;
        }
 
-       c->isa_level = MIPS_CPU_ISA_M64R1;
-       c->tlbsize = ((read_c0_config1() >> 25) & 0x3f) + 1;
+       if (c->cputype == CPU_XLP) {
+               c->isa_level = MIPS_CPU_ISA_M64R2;
+               c->options |= (MIPS_CPU_FPU | MIPS_CPU_ULRI | MIPS_CPU_MCHECK);
+               /* This will be updated again after all threads are woken up */
+               c->tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1;
+       } else {
+               c->isa_level = MIPS_CPU_ISA_M64R1;
+               c->tlbsize = ((read_c0_config1() >> 25) & 0x3f) + 1;
+       }
 }
 
 #ifdef CONFIG_64BIT
index 7047bff35ea52829a85a9fc94e8f33ad05ead786..c5bc344fc745c4b45a0daa40ea09447f49834cd4 100644 (file)
@@ -19,7 +19,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction irq0  = {
        .handler = timer_interrupt,
-       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
+       .flags = IRQF_NOBALANCING | IRQF_TIMER,
        .name = "timer"
 };
 
index ee28683fc2acbb7168d437702f2f0fdf453a4a3d..158467da9bc1cd134d797ef4a6c3993617523d34 100644 (file)
 
 #include <linux/kprobes.h>
 #include <linux/preempt.h>
+#include <linux/uaccess.h>
 #include <linux/kdebug.h>
 #include <linux/slab.h>
 
 #include <asm/ptrace.h>
+#include <asm/branch.h>
 #include <asm/break.h>
 #include <asm/inst.h>
 
@@ -112,17 +114,49 @@ insn_ok:
        return 0;
 }
 
+/*
+ * insn_has_ll_or_sc function checks whether instruction is ll or sc
+ * one; putting breakpoint on top of atomic ll/sc pair is bad idea;
+ * so we need to prevent it and refuse kprobes insertion for such
+ * instructions; cannot do much about breakpoint in the middle of
+ * ll/sc pair; it is upto user to avoid those places
+ */
+static int __kprobes insn_has_ll_or_sc(union mips_instruction insn)
+{
+       int ret = 0;
+
+       switch (insn.i_format.opcode) {
+       case ll_op:
+       case lld_op:
+       case sc_op:
+       case scd_op:
+               ret = 1;
+               break;
+       default:
+               break;
+       }
+       return ret;
+}
+
 int __kprobes arch_prepare_kprobe(struct kprobe *p)
 {
        union mips_instruction insn;
        union mips_instruction prev_insn;
        int ret = 0;
 
-       prev_insn = p->addr[-1];
        insn = p->addr[0];
 
-       if (insn_has_delayslot(insn) || insn_has_delayslot(prev_insn)) {
-               pr_notice("Kprobes for branch and jump instructions are not supported\n");
+       if (insn_has_ll_or_sc(insn)) {
+               pr_notice("Kprobes for ll and sc instructions are not"
+                         "supported\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if ((probe_kernel_read(&prev_insn, p->addr - 1,
+                               sizeof(mips_instruction)) == 0) &&
+                               insn_has_delayslot(prev_insn)) {
+               pr_notice("Kprobes for branch delayslot are not supported\n");
                ret = -EINVAL;
                goto out;
        }
@@ -138,9 +172,20 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
         * In the kprobe->ainsn.insn[] array we store the original
         * instruction at index zero and a break trap instruction at
         * index one.
+        *
+        * On MIPS arch if the instruction at probed address is a
+        * branch instruction, we need to execute the instruction at
+        * Branch Delayslot (BD) at the time of probe hit. As MIPS also
+        * doesn't have single stepping support, the BD instruction can
+        * not be executed in-line and it would be executed on SSOL slot
+        * using a normal breakpoint instruction in the next slot.
+        * So, read the instruction and save it for later execution.
         */
+       if (insn_has_delayslot(insn))
+               memcpy(&p->ainsn.insn[0], p->addr + 1, sizeof(kprobe_opcode_t));
+       else
+               memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t));
 
-       memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t));
        p->ainsn.insn[1] = breakpoint2_insn;
        p->opcode = *p->addr;
 
@@ -191,16 +236,96 @@ static void set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
        kcb->kprobe_saved_epc = regs->cp0_epc;
 }
 
-static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
+/**
+ * evaluate_branch_instrucion -
+ *
+ * Evaluate the branch instruction at probed address during probe hit. The
+ * result of evaluation would be the updated epc. The insturction in delayslot
+ * would actually be single stepped using a normal breakpoint) on SSOL slot.
+ *
+ * The result is also saved in the kprobe control block for later use,
+ * in case we need to execute the delayslot instruction. The latter will be
+ * false for NOP instruction in dealyslot and the branch-likely instructions
+ * when the branch is taken. And for those cases we set a flag as
+ * SKIP_DELAYSLOT in the kprobe control block
+ */
+static int evaluate_branch_instruction(struct kprobe *p, struct pt_regs *regs,
+                                       struct kprobe_ctlblk *kcb)
 {
+       union mips_instruction insn = p->opcode;
+       long epc;
+       int ret = 0;
+
+       epc = regs->cp0_epc;
+       if (epc & 3)
+               goto unaligned;
+
+       if (p->ainsn.insn->word == 0)
+               kcb->flags |= SKIP_DELAYSLOT;
+       else
+               kcb->flags &= ~SKIP_DELAYSLOT;
+
+       ret = __compute_return_epc_for_insn(regs, insn);
+       if (ret < 0)
+               return ret;
+
+       if (ret == BRANCH_LIKELY_TAKEN)
+               kcb->flags |= SKIP_DELAYSLOT;
+
+       kcb->target_epc = regs->cp0_epc;
+
+       return 0;
+
+unaligned:
+       pr_notice("%s: unaligned epc - sending SIGBUS.\n", current->comm);
+       force_sig(SIGBUS, current);
+       return -EFAULT;
+
+}
+
+static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs,
+                                               struct kprobe_ctlblk *kcb)
+{
+       int ret = 0;
+
        regs->cp0_status &= ~ST0_IE;
 
        /* single step inline if the instruction is a break */
        if (p->opcode.word == breakpoint_insn.word ||
            p->opcode.word == breakpoint2_insn.word)
                regs->cp0_epc = (unsigned long)p->addr;
-       else
-               regs->cp0_epc = (unsigned long)&p->ainsn.insn[0];
+       else if (insn_has_delayslot(p->opcode)) {
+               ret = evaluate_branch_instruction(p, regs, kcb);
+               if (ret < 0) {
+                       pr_notice("Kprobes: Error in evaluating branch\n");
+                       return;
+               }
+       }
+       regs->cp0_epc = (unsigned long)&p->ainsn.insn[0];
+}
+
+/*
+ * Called after single-stepping.  p->addr is the address of the
+ * instruction whose first byte has been replaced by the "break 0"
+ * instruction.  To avoid the SMP problems that can occur when we
+ * temporarily put back the original opcode to single-step, we
+ * single-stepped a copy of the instruction.  The address of this
+ * copy is p->ainsn.insn.
+ *
+ * This function prepares to return from the post-single-step
+ * breakpoint trap. In case of branch instructions, the target
+ * epc to be restored.
+ */
+static void __kprobes resume_execution(struct kprobe *p,
+                                      struct pt_regs *regs,
+                                      struct kprobe_ctlblk *kcb)
+{
+       if (insn_has_delayslot(p->opcode))
+               regs->cp0_epc = kcb->target_epc;
+       else {
+               unsigned long orig_epc = kcb->kprobe_saved_epc;
+               regs->cp0_epc = orig_epc + 4;
+       }
 }
 
 static int __kprobes kprobe_handler(struct pt_regs *regs)
@@ -239,8 +364,13 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
                        save_previous_kprobe(kcb);
                        set_current_kprobe(p, regs, kcb);
                        kprobes_inc_nmissed_count(p);
-                       prepare_singlestep(p, regs);
+                       prepare_singlestep(p, regs, kcb);
                        kcb->kprobe_status = KPROBE_REENTER;
+                       if (kcb->flags & SKIP_DELAYSLOT) {
+                               resume_execution(p, regs, kcb);
+                               restore_previous_kprobe(kcb);
+                               preempt_enable_no_resched();
+                       }
                        return 1;
                } else {
                        if (addr->word != breakpoint_insn.word) {
@@ -284,8 +414,16 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
        }
 
 ss_probe:
-       prepare_singlestep(p, regs);
-       kcb->kprobe_status = KPROBE_HIT_SS;
+       prepare_singlestep(p, regs, kcb);
+       if (kcb->flags & SKIP_DELAYSLOT) {
+               kcb->kprobe_status = KPROBE_HIT_SSDONE;
+               if (p->post_handler)
+                       p->post_handler(p, regs, 0);
+               resume_execution(p, regs, kcb);
+               preempt_enable_no_resched();
+       } else
+               kcb->kprobe_status = KPROBE_HIT_SS;
+
        return 1;
 
 no_kprobe:
@@ -294,25 +432,6 @@ no_kprobe:
 
 }
 
-/*
- * Called after single-stepping.  p->addr is the address of the
- * instruction whose first byte has been replaced by the "break 0"
- * instruction.  To avoid the SMP problems that can occur when we
- * temporarily put back the original opcode to single-step, we
- * single-stepped a copy of the instruction.  The address of this
- * copy is p->ainsn.insn.
- *
- * This function prepares to return from the post-single-step
- * breakpoint trap.
- */
-static void __kprobes resume_execution(struct kprobe *p,
-                                      struct pt_regs *regs,
-                                      struct kprobe_ctlblk *kcb)
-{
-       unsigned long orig_epc = kcb->kprobe_saved_epc;
-       regs->cp0_epc = orig_epc + 4;
-}
-
 static inline int post_kprobe_handler(struct pt_regs *regs)
 {
        struct kprobe *cur = kprobe_running();
index 315fc0b250f8fe3373684f12f5c0437fd3d0b7b1..e3b897acfbc04b3db1cbd29a37a423ccca4df815 100644 (file)
@@ -621,11 +621,6 @@ static int mipspmu_event_init(struct perf_event *event)
                return -ENODEV;
 
        if (!atomic_inc_not_zero(&active_events)) {
-               if (atomic_read(&active_events) > MIPS_MAX_HWEVENTS) {
-                       atomic_dec(&active_events);
-                       return -EINVAL;
-               }
-
                mutex_lock(&pmu_reserve_mutex);
                if (atomic_read(&active_events) == 0)
                        err = mipspmu_get_irq();
@@ -638,11 +633,7 @@ static int mipspmu_event_init(struct perf_event *event)
        if (err)
                return err;
 
-       err = __hw_perf_event_init(event);
-       if (err)
-               hw_perf_event_destroy(event);
-
-       return err;
+       return __hw_perf_event_init(event);
 }
 
 static struct pmu pmu = {
@@ -712,18 +703,6 @@ static const struct mips_perf_event *mipspmu_map_cache_event(u64 config)
 
 }
 
-static int validate_event(struct cpu_hw_events *cpuc,
-              struct perf_event *event)
-{
-       struct hw_perf_event fake_hwc = event->hw;
-
-       /* Allow mixed event group. So return 1 to pass validation. */
-       if (event->pmu != &pmu || event->state <= PERF_EVENT_STATE_OFF)
-               return 1;
-
-       return mipsxx_pmu_alloc_counter(cpuc, &fake_hwc) >= 0;
-}
-
 static int validate_group(struct perf_event *event)
 {
        struct perf_event *sibling, *leader = event->group_leader;
@@ -731,15 +710,15 @@ static int validate_group(struct perf_event *event)
 
        memset(&fake_cpuc, 0, sizeof(fake_cpuc));
 
-       if (!validate_event(&fake_cpuc, leader))
+       if (mipsxx_pmu_alloc_counter(&fake_cpuc, &leader->hw) < 0)
                return -EINVAL;
 
        list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
-               if (!validate_event(&fake_cpuc, sibling))
+               if (mipsxx_pmu_alloc_counter(&fake_cpuc, &sibling->hw) < 0)
                        return -EINVAL;
        }
 
-       if (!validate_event(&fake_cpuc, event))
+       if (mipsxx_pmu_alloc_counter(&fake_cpuc, &event->hw) < 0)
                return -EINVAL;
 
        return 0;
@@ -1279,13 +1258,14 @@ static int __hw_perf_event_init(struct perf_event *event)
        }
 
        err = 0;
-       if (event->group_leader != event) {
+       if (event->group_leader != event)
                err = validate_group(event);
-               if (err)
-                       return -EINVAL;
-       }
 
        event->destroy = hw_perf_event_destroy;
+
+       if (err)
+               event->destroy(event);
+
        return err;
 }
 
@@ -1380,20 +1360,10 @@ static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev)
 }
 
 /* 24K */
-#define IS_UNSUPPORTED_24K_EVENT(r, b)                                 \
-       ((b) == 12 || (r) == 151 || (r) == 152 || (b) == 26 ||          \
-        (b) == 27 || (r) == 28 || (r) == 158 || (b) == 31 ||           \
-        (b) == 32 || (b) == 34 || (b) == 36 || (r) == 168 ||           \
-        (r) == 172 || (b) == 47 || ((b) >= 56 && (b) <= 63) ||         \
-        ((b) >= 68 && (b) <= 127))
 #define IS_BOTH_COUNTERS_24K_EVENT(b)                                  \
        ((b) == 0 || (b) == 1 || (b) == 11)
 
 /* 34K */
-#define IS_UNSUPPORTED_34K_EVENT(r, b)                                 \
-       ((b) == 12 || (r) == 27 || (r) == 158 || (b) == 36 ||           \
-        (b) == 38 || (r) == 175 || ((b) >= 56 && (b) <= 63) ||         \
-        ((b) >= 68 && (b) <= 127))
 #define IS_BOTH_COUNTERS_34K_EVENT(b)                                  \
        ((b) == 0 || (b) == 1 || (b) == 11)
 #ifdef CONFIG_MIPS_MT_SMP
@@ -1406,20 +1376,10 @@ static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev)
 #endif
 
 /* 74K */
-#define IS_UNSUPPORTED_74K_EVENT(r, b)                                 \
-       ((r) == 5 || ((r) >= 135 && (r) <= 137) ||                      \
-        ((b) >= 10 && (b) <= 12) || (b) == 22 || (b) == 27 ||          \
-        (b) == 33 || (b) == 34 || ((b) >= 47 && (b) <= 49) ||          \
-        (r) == 178 || (b) == 55 || (b) == 57 || (b) == 60 ||           \
-        (b) == 61 || (r) == 62 || (r) == 191 ||                        \
-        ((b) >= 64 && (b) <= 127))
 #define IS_BOTH_COUNTERS_74K_EVENT(b)                                  \
        ((b) == 0 || (b) == 1)
 
 /* 1004K */
-#define IS_UNSUPPORTED_1004K_EVENT(r, b)                               \
-       ((b) == 12 || (r) == 27 || (r) == 158 || (b) == 38 ||           \
-        (r) == 175 || (b) == 63 || ((b) >= 68 && (b) <= 127))
 #define IS_BOTH_COUNTERS_1004K_EVENT(b)                                        \
        ((b) == 0 || (b) == 1 || (b) == 11)
 #ifdef CONFIG_MIPS_MT_SMP
@@ -1445,11 +1405,10 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
        unsigned int raw_id = config & 0xff;
        unsigned int base_id = raw_id & 0x7f;
 
+       raw_event.event_id = base_id;
+
        switch (current_cpu_type()) {
        case CPU_24K:
-               if (IS_UNSUPPORTED_24K_EVENT(raw_id, base_id))
-                       return ERR_PTR(-EOPNOTSUPP);
-               raw_event.event_id = base_id;
                if (IS_BOTH_COUNTERS_24K_EVENT(base_id))
                        raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
                else
@@ -1464,9 +1423,6 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
 #endif
                break;
        case CPU_34K:
-               if (IS_UNSUPPORTED_34K_EVENT(raw_id, base_id))
-                       return ERR_PTR(-EOPNOTSUPP);
-               raw_event.event_id = base_id;
                if (IS_BOTH_COUNTERS_34K_EVENT(base_id))
                        raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
                else
@@ -1482,9 +1438,6 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
 #endif
                break;
        case CPU_74K:
-               if (IS_UNSUPPORTED_74K_EVENT(raw_id, base_id))
-                       return ERR_PTR(-EOPNOTSUPP);
-               raw_event.event_id = base_id;
                if (IS_BOTH_COUNTERS_74K_EVENT(base_id))
                        raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
                else
@@ -1495,9 +1448,6 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
 #endif
                break;
        case CPU_1004K:
-               if (IS_UNSUPPORTED_1004K_EVENT(raw_id, base_id))
-                       return ERR_PTR(-EOPNOTSUPP);
-               raw_event.event_id = base_id;
                if (IS_BOTH_COUNTERS_1004K_EVENT(base_id))
                        raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
                else
index 4e6ea1ffad46617b3e1c0880c4061371f7aa5885..7786b608d9322289ce23a83eb5205b50b57f3cb6 100644 (file)
@@ -560,10 +560,9 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs)
        }
 
 out:
-       if (unlikely(current->audit_context))
-               audit_syscall_entry(audit_arch(), regs->regs[2],
-                                   regs->regs[4], regs->regs[5],
-                                   regs->regs[6], regs->regs[7]);
+       audit_syscall_entry(audit_arch(), regs->regs[2],
+                           regs->regs[4], regs->regs[5],
+                           regs->regs[6], regs->regs[7]);
 }
 
 /*
@@ -572,9 +571,7 @@ out:
  */
 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
 {
-       if (unlikely(current->audit_context))
-               audit_syscall_exit(AUDITSC_RESULT(regs->regs[7]),
-                                  -regs->regs[2]);
+       audit_syscall_exit(regs);
 
        if (!(current->ptrace & PT_PTRACED))
                return;
index 933166f44a6d8647c4f75deaf13b11a02e04adaf..a9d801dec6b03c77b0ab5a1d05fa691798f59be1 100644 (file)
@@ -473,7 +473,6 @@ static const struct file_operations rtlx_fops = {
 
 static struct irqaction rtlx_irq = {
        .handler        = rtlx_interrupt,
-       .flags          = IRQF_DISABLED,
        .name           = "RTLX",
 };
 
index b1cb8f87d7b438186d50bd82ed955a20a165b6a8..058e964e730344dc51adc3ed9737c97d0b4fc51f 100644 (file)
@@ -122,6 +122,9 @@ static void __init print_memory_map(void)
                case BOOT_MEM_RAM:
                        printk(KERN_CONT "(usable)\n");
                        break;
+               case BOOT_MEM_INIT_RAM:
+                       printk(KERN_CONT "(usable after init)\n");
+                       break;
                case BOOT_MEM_ROM_DATA:
                        printk(KERN_CONT "(ROM data)\n");
                        break;
@@ -362,15 +365,24 @@ static void __init bootmem_init(void)
        for (i = 0; i < boot_mem_map.nr_map; i++) {
                unsigned long start, end, size;
 
+               start = PFN_UP(boot_mem_map.map[i].addr);
+               end   = PFN_DOWN(boot_mem_map.map[i].addr
+                                   + boot_mem_map.map[i].size);
+
                /*
                 * Reserve usable memory.
                 */
-               if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
+               switch (boot_mem_map.map[i].type) {
+               case BOOT_MEM_RAM:
+                       break;
+               case BOOT_MEM_INIT_RAM:
+                       memory_present(0, start, end);
                        continue;
+               default:
+                       /* Not usable memory */
+                       continue;
+               }
 
-               start = PFN_UP(boot_mem_map.map[i].addr);
-               end   = PFN_DOWN(boot_mem_map.map[i].addr
-                                   + boot_mem_map.map[i].size);
                /*
                 * We are rounding up the start address of usable memory
                 * and at the end of the usable range downwards.
@@ -456,11 +468,33 @@ early_param("mem", early_parse_mem);
 
 static void __init arch_mem_init(char **cmdline_p)
 {
+       phys_t init_mem, init_end, init_size;
+
        extern void plat_mem_setup(void);
 
        /* call board setup routine */
        plat_mem_setup();
 
+       init_mem = PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT;
+       init_end = PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT;
+       init_size = init_end - init_mem;
+       if (init_size) {
+               /* Make sure it is in the boot_mem_map */
+               int i, found;
+               found = 0;
+               for (i = 0; i < boot_mem_map.nr_map; i++) {
+                       if (init_mem >= boot_mem_map.map[i].addr &&
+                           init_mem < (boot_mem_map.map[i].addr +
+                                       boot_mem_map.map[i].size)) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found)
+                       add_memory_region(init_mem, init_size,
+                                         BOOT_MEM_INIT_RAM);
+       }
+
        pr_info("Determined physical RAM map:\n");
        print_memory_map();
 
@@ -524,6 +558,7 @@ static void __init resource_init(void)
                res = alloc_bootmem(sizeof(struct resource));
                switch (boot_mem_map.map[i].type) {
                case BOOT_MEM_RAM:
+               case BOOT_MEM_INIT_RAM:
                case BOOT_MEM_ROM_DATA:
                        res->name = "System RAM";
                        break;
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
new file mode 100644 (file)
index 0000000..58fe71a
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2011 by Kevin Cernekee (cernekee@gmail.com)
+ *
+ * SMP support for BMIPS
+ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/reboot.h>
+#include <linux/io.h>
+#include <linux/compiler.h>
+#include <linux/linkage.h>
+#include <linux/bug.h>
+#include <linux/kernel.h>
+
+#include <asm/time.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/bootinfo.h>
+#include <asm/pmon.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/mipsregs.h>
+#include <asm/bmips.h>
+#include <asm/traps.h>
+#include <asm/barrier.h>
+
+static int __maybe_unused max_cpus = 1;
+
+/* these may be configured by the platform code */
+int bmips_smp_enabled = 1;
+int bmips_cpu_offset;
+cpumask_t bmips_booted_mask;
+
+#ifdef CONFIG_SMP
+
+/* initial $sp, $gp - used by arch/mips/kernel/bmips_vec.S */
+unsigned long bmips_smp_boot_sp;
+unsigned long bmips_smp_boot_gp;
+
+static void bmips_send_ipi_single(int cpu, unsigned int action);
+static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id);
+
+/* SW interrupts 0,1 are used for interprocessor signaling */
+#define IPI0_IRQ                       (MIPS_CPU_IRQ_BASE + 0)
+#define IPI1_IRQ                       (MIPS_CPU_IRQ_BASE + 1)
+
+#define CPUNUM(cpu, shift)             (((cpu) + bmips_cpu_offset) << (shift))
+#define ACTION_CLR_IPI(cpu, ipi)       (0x2000 | CPUNUM(cpu, 9) | ((ipi) << 8))
+#define ACTION_SET_IPI(cpu, ipi)       (0x3000 | CPUNUM(cpu, 9) | ((ipi) << 8))
+#define ACTION_BOOT_THREAD(cpu)                (0x08 | CPUNUM(cpu, 0))
+
+static void __init bmips_smp_setup(void)
+{
+       int i;
+
+#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
+       /* arbitration priority */
+       clear_c0_brcm_cmt_ctrl(0x30);
+
+       /* NBK and weak order flags */
+       set_c0_brcm_config_0(0x30000);
+
+       /*
+        * MIPS interrupts 0,1 (SW INT 0,1) cross over to the other thread
+        * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output
+        * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output
+        */
+       change_c0_brcm_cmt_intr(0xf8018000,
+               (0x02 << 27) | (0x03 << 15));
+
+       /* single core, 2 threads (2 pipelines) */
+       max_cpus = 2;
+#elif defined(CONFIG_CPU_BMIPS5000)
+       /* enable raceless SW interrupts */
+       set_c0_brcm_config(0x03 << 22);
+
+       /* route HW interrupt 0 to CPU0, HW interrupt 1 to CPU1 */
+       change_c0_brcm_mode(0x1f << 27, 0x02 << 27);
+
+       /* N cores, 2 threads per core */
+       max_cpus = (((read_c0_brcm_config() >> 6) & 0x03) + 1) << 1;
+
+       /* clear any pending SW interrupts */
+       for (i = 0; i < max_cpus; i++) {
+               write_c0_brcm_action(ACTION_CLR_IPI(i, 0));
+               write_c0_brcm_action(ACTION_CLR_IPI(i, 1));
+       }
+#endif
+
+       if (!bmips_smp_enabled)
+               max_cpus = 1;
+
+       /* this can be overridden by the BSP */
+       if (!board_ebase_setup)
+               board_ebase_setup = &bmips_ebase_setup;
+
+       for (i = 0; i < max_cpus; i++) {
+               __cpu_number_map[i] = 1;
+               __cpu_logical_map[i] = 1;
+               set_cpu_possible(i, 1);
+               set_cpu_present(i, 1);
+       }
+}
+
+/*
+ * IPI IRQ setup - runs on CPU0
+ */
+static void bmips_prepare_cpus(unsigned int max_cpus)
+{
+       if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, IRQF_PERCPU,
+                       "smp_ipi0", NULL))
+               panic("Can't request IPI0 interrupt\n");
+       if (request_irq(IPI1_IRQ, bmips_ipi_interrupt, IRQF_PERCPU,
+                       "smp_ipi1", NULL))
+               panic("Can't request IPI1 interrupt\n");
+}
+
+/*
+ * Tell the hardware to boot CPUx - runs on CPU0
+ */
+static void bmips_boot_secondary(int cpu, struct task_struct *idle)
+{
+       bmips_smp_boot_sp = __KSTK_TOS(idle);
+       bmips_smp_boot_gp = (unsigned long)task_thread_info(idle);
+       mb();
+
+       /*
+        * Initial boot sequence for secondary CPU:
+        *   bmips_reset_nmi_vec @ a000_0000 ->
+        *   bmips_smp_entry ->
+        *   plat_wired_tlb_setup (cached function call; optional) ->
+        *   start_secondary (cached jump)
+        *
+        * Warm restart sequence:
+        *   play_dead WAIT loop ->
+        *   bmips_smp_int_vec @ BMIPS_WARM_RESTART_VEC ->
+        *   eret to play_dead ->
+        *   bmips_secondary_reentry ->
+        *   start_secondary
+        */
+
+       pr_info("SMP: Booting CPU%d...\n", cpu);
+
+       if (cpumask_test_cpu(cpu, &bmips_booted_mask))
+               bmips_send_ipi_single(cpu, 0);
+       else {
+#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
+               set_c0_brcm_cmt_ctrl(0x01);
+#elif defined(CONFIG_CPU_BMIPS5000)
+               if (cpu & 0x01)
+                       write_c0_brcm_action(ACTION_BOOT_THREAD(cpu));
+               else {
+                       /*
+                        * core N thread 0 was already booted; just
+                        * pulse the NMI line
+                        */
+                       bmips_write_zscm_reg(0x210, 0xc0000000);
+                       udelay(10);
+                       bmips_write_zscm_reg(0x210, 0x00);
+               }
+#endif
+               cpumask_set_cpu(cpu, &bmips_booted_mask);
+       }
+}
+
+/*
+ * Early setup - runs on secondary CPU after cache probe
+ */
+static void bmips_init_secondary(void)
+{
+       /* move NMI vector to kseg0, in case XKS01 is enabled */
+
+#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
+       void __iomem *cbr = BMIPS_GET_CBR();
+       unsigned long old_vec;
+
+       old_vec = __raw_readl(cbr + BMIPS_RELO_VECTOR_CONTROL_1);
+       __raw_writel(old_vec & ~0x20000000, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
+
+       clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0);
+#elif defined(CONFIG_CPU_BMIPS5000)
+       write_c0_brcm_bootvec(read_c0_brcm_bootvec() &
+               (smp_processor_id() & 0x01 ? ~0x20000000 : ~0x2000));
+
+       write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0));
+#endif
+
+       /* make sure there won't be a timer interrupt for a little while */
+       write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
+
+       irq_enable_hazard();
+       set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ1 | IE_IRQ5 | ST0_IE);
+       irq_enable_hazard();
+}
+
+/*
+ * Late setup - runs on secondary CPU before entering the idle loop
+ */
+static void bmips_smp_finish(void)
+{
+       pr_info("SMP: CPU%d is running\n", smp_processor_id());
+}
+
+/*
+ * Runs on CPU0 after all CPUs have been booted
+ */
+static void bmips_cpus_done(void)
+{
+}
+
+#if defined(CONFIG_CPU_BMIPS5000)
+
+/*
+ * BMIPS5000 raceless IPIs
+ *
+ * Each CPU has two inbound SW IRQs which are independent of all other CPUs.
+ * IPI0 is used for SMP_RESCHEDULE_YOURSELF
+ * IPI1 is used for SMP_CALL_FUNCTION
+ */
+
+static void bmips_send_ipi_single(int cpu, unsigned int action)
+{
+       write_c0_brcm_action(ACTION_SET_IPI(cpu, action == SMP_CALL_FUNCTION));
+}
+
+static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id)
+{
+       int action = irq - IPI0_IRQ;
+
+       write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), action));
+
+       if (action == 0)
+               scheduler_ipi();
+       else
+               smp_call_function_interrupt();
+
+       return IRQ_HANDLED;
+}
+
+#else
+
+/*
+ * BMIPS43xx racey IPIs
+ *
+ * We use one inbound SW IRQ for each CPU.
+ *
+ * A spinlock must be held in order to keep CPUx from accidentally clearing
+ * an incoming IPI when it writes CP0 CAUSE to raise an IPI on CPUy.  The
+ * same spinlock is used to protect the action masks.
+ */
+
+static DEFINE_SPINLOCK(ipi_lock);
+static DEFINE_PER_CPU(int, ipi_action_mask);
+
+static void bmips_send_ipi_single(int cpu, unsigned int action)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ipi_lock, flags);
+       set_c0_cause(cpu ? C_SW1 : C_SW0);
+       per_cpu(ipi_action_mask, cpu) |= action;
+       irq_enable_hazard();
+       spin_unlock_irqrestore(&ipi_lock, flags);
+}
+
+static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id)
+{
+       unsigned long flags;
+       int action, cpu = irq - IPI0_IRQ;
+
+       spin_lock_irqsave(&ipi_lock, flags);
+       action = __get_cpu_var(ipi_action_mask);
+       per_cpu(ipi_action_mask, cpu) = 0;
+       clear_c0_cause(cpu ? C_SW1 : C_SW0);
+       spin_unlock_irqrestore(&ipi_lock, flags);
+
+       if (action & SMP_RESCHEDULE_YOURSELF)
+               scheduler_ipi();
+       if (action & SMP_CALL_FUNCTION)
+               smp_call_function_interrupt();
+
+       return IRQ_HANDLED;
+}
+
+#endif /* BMIPS type */
+
+static void bmips_send_ipi_mask(const struct cpumask *mask,
+       unsigned int action)
+{
+       unsigned int i;
+
+       for_each_cpu(i, mask)
+               bmips_send_ipi_single(i, action);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+static int bmips_cpu_disable(void)
+{
+       unsigned int cpu = smp_processor_id();
+
+       if (cpu == 0)
+               return -EBUSY;
+
+       pr_info("SMP: CPU%d is offline\n", cpu);
+
+       cpu_clear(cpu, cpu_online_map);
+       cpu_clear(cpu, cpu_callin_map);
+
+       local_flush_tlb_all();
+       local_flush_icache_range(0, ~0);
+
+       return 0;
+}
+
+static void bmips_cpu_die(unsigned int cpu)
+{
+}
+
+void __ref play_dead(void)
+{
+       idle_task_exit();
+
+       /* flush data cache */
+       _dma_cache_wback_inv(0, ~0);
+
+       /*
+        * Wakeup is on SW0 or SW1; disable everything else
+        * Use BEV !IV (BMIPS_WARM_RESTART_VEC) to avoid the regular Linux
+        * IRQ handlers; this clears ST0_IE and returns immediately.
+        */
+       clear_c0_cause(CAUSEF_IV | C_SW0 | C_SW1);
+       change_c0_status(IE_IRQ5 | IE_IRQ1 | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV,
+               IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV);
+       irq_disable_hazard();
+
+       /*
+        * wait for SW interrupt from bmips_boot_secondary(), then jump
+        * back to start_secondary()
+        */
+       __asm__ __volatile__(
+       "       wait\n"
+       "       j       bmips_secondary_reentry\n"
+       : : : "memory");
+}
+
+#endif /* CONFIG_HOTPLUG_CPU */
+
+struct plat_smp_ops bmips_smp_ops = {
+       .smp_setup              = bmips_smp_setup,
+       .prepare_cpus           = bmips_prepare_cpus,
+       .boot_secondary         = bmips_boot_secondary,
+       .smp_finish             = bmips_smp_finish,
+       .init_secondary         = bmips_init_secondary,
+       .cpus_done              = bmips_cpus_done,
+       .send_ipi_single        = bmips_send_ipi_single,
+       .send_ipi_mask          = bmips_send_ipi_mask,
+#ifdef CONFIG_HOTPLUG_CPU
+       .cpu_disable            = bmips_cpu_disable,
+       .cpu_die                = bmips_cpu_die,
+#endif
+};
+
+#endif /* CONFIG_SMP */
+
+/***********************************************************************
+ * BMIPS vector relocation
+ * This is primarily used for SMP boot, but it is applicable to some
+ * UP BMIPS systems as well.
+ ***********************************************************************/
+
+static void __cpuinit bmips_wr_vec(unsigned long dst, char *start, char *end)
+{
+       memcpy((void *)dst, start, end - start);
+       dma_cache_wback((unsigned long)start, end - start);
+       local_flush_icache_range(dst, dst + (end - start));
+       instruction_hazard();
+}
+
+static inline void __cpuinit bmips_nmi_handler_setup(void)
+{
+       bmips_wr_vec(BMIPS_NMI_RESET_VEC, &bmips_reset_nmi_vec,
+               &bmips_reset_nmi_vec_end);
+       bmips_wr_vec(BMIPS_WARM_RESTART_VEC, &bmips_smp_int_vec,
+               &bmips_smp_int_vec_end);
+}
+
+void __cpuinit bmips_ebase_setup(void)
+{
+       unsigned long new_ebase = ebase;
+       void __iomem __maybe_unused *cbr;
+
+       BUG_ON(ebase != CKSEG0);
+
+#if defined(CONFIG_CPU_BMIPS4350)
+       /*
+        * BMIPS4350 cannot relocate the normal vectors, but it
+        * can relocate the BEV=1 vectors.  So CPU1 starts up at
+        * the relocated BEV=1, IV=0 general exception vector @
+        * 0xa000_0380.
+        *
+        * set_uncached_handler() is used here because:
+        *  - CPU1 will run this from uncached space
+        *  - None of the cacheflush functions are set up yet
+        */
+       set_uncached_handler(BMIPS_WARM_RESTART_VEC - CKSEG0,
+               &bmips_smp_int_vec, 0x80);
+       __sync();
+       return;
+#elif defined(CONFIG_CPU_BMIPS4380)
+       /*
+        * 0x8000_0000: reset/NMI (initially in kseg1)
+        * 0x8000_0400: normal vectors
+        */
+       new_ebase = 0x80000400;
+       cbr = BMIPS_GET_CBR();
+       __raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0);
+       __raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
+#elif defined(CONFIG_CPU_BMIPS5000)
+       /*
+        * 0x8000_0000: reset/NMI (initially in kseg1)
+        * 0x8000_1000: normal vectors
+        */
+       new_ebase = 0x80001000;
+       write_c0_brcm_bootvec(0xa0088008);
+       write_c0_ebase(new_ebase);
+       if (max_cpus > 2)
+               bmips_write_zscm_reg(0xa0, 0xa008a008);
+#else
+       return;
+#endif
+       board_nmi_handler_setup = &bmips_nmi_handler_setup;
+       ebase = new_ebase;
+}
+
+asmlinkage void __weak plat_wired_tlb_setup(void)
+{
+       /*
+        * Called when starting/restarting a secondary CPU.
+        * Kernel stacks and other important data might only be accessible
+        * once the wired entries are present.
+        */
+}
index f0895e70e283b3982c18a672ad8875a8b1e6ad55..0a42ff3ff6a111992da86c13d726501b68b6d9da 100644 (file)
@@ -559,7 +559,7 @@ void smtc_prepare_cpus(int cpus)
 
        pipi = kmalloc(nipi *sizeof(struct smtc_ipi), GFP_KERNEL);
        if (pipi == NULL)
-               panic("kmalloc of IPI message buffers failed\n");
+               panic("kmalloc of IPI message buffers failed");
        else
                printk("IPI buffer pool of %d buffers\n", nipi);
        for (i = 0; i < nipi; i++) {
@@ -813,7 +813,7 @@ void smtc_send_ipi(int cpu, int type, unsigned int action)
        if (pipi == NULL) {
                bust_spinlocks(1);
                mips_mt_regdump(dvpe());
-               panic("IPI Msg. Buffers Depleted\n");
+               panic("IPI Msg. Buffers Depleted");
        }
        pipi->type = type;
        pipi->arg = (void *)action;
@@ -1130,7 +1130,7 @@ static void ipi_irq_dispatch(void)
 
 static struct irqaction irq_ipi = {
        .handler        = ipi_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU,
+       .flags          = IRQF_PERCPU,
        .name           = "SMTC_IPI"
 };
 
index 5c8a49d55054dffce696066bad88d1863c5e7f35..cc4a3f120f54d6f036e66812cf47e5c35e7dbff9 100644 (file)
@@ -91,6 +91,7 @@ int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
 void (*board_nmi_handler_setup)(void);
 void (*board_ejtag_handler_setup)(void);
 void (*board_bind_eic_interrupt)(int irq, int regset);
+void (*board_ebase_setup)(void);
 
 
 static void show_raw_backtrace(unsigned long reg29)
@@ -400,7 +401,7 @@ void __noreturn die(const char *str, struct pt_regs *regs)
                panic("Fatal exception in interrupt");
 
        if (panic_on_oops) {
-               printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
+               printk(KERN_EMERG "Fatal exception: panic in 5 seconds");
                ssleep(5);
                panic("Fatal exception");
        }
@@ -1150,7 +1151,7 @@ asmlinkage void do_mt(struct pt_regs *regs)
 asmlinkage void do_dsp(struct pt_regs *regs)
 {
        if (cpu_has_dsp)
-               panic("Unexpected DSP exception\n");
+               panic("Unexpected DSP exception");
 
        force_sig(SIGILL, current);
 }
@@ -1339,9 +1340,18 @@ void ejtag_exception_handler(struct pt_regs *regs)
 
 /*
  * NMI exception handler.
+ * No lock; only written during early bootup by CPU 0.
  */
-NORET_TYPE void ATTRIB_NORET nmi_exception_handler(struct pt_regs *regs)
+static RAW_NOTIFIER_HEAD(nmi_chain);
+
+int register_nmi_notifier(struct notifier_block *nb)
+{
+       return raw_notifier_chain_register(&nmi_chain, nb);
+}
+
+void __noreturn nmi_exception_handler(struct pt_regs *regs)
 {
+       raw_notifier_call_chain(&nmi_chain, 0, regs);
        bust_spinlocks(1);
        printk("NMI taken!!!!\n");
        die("NMI", regs);
@@ -1682,6 +1692,8 @@ void __init trap_init(void)
                        ebase += (read_c0_ebase() & 0x3ffff000);
        }
 
+       if (board_ebase_setup)
+               board_ebase_setup();
        per_cpu_trap_init();
 
        /*
index 77ed70fc2fe5953cd9bf31aa2514820b41e2bbd6..412814fdd3ee239ce5f7cfc6e6c7f6ead93ed9fa 100644 (file)
@@ -134,11 +134,11 @@ void __init plat_time_init(void)
        struct clk *clk;
 
        if (insert_resource(&iomem_resource, &ltq_cgu_resource) < 0)
-               panic("Failed to insert cgu memory\n");
+               panic("Failed to insert cgu memory");
 
        if (request_mem_region(ltq_cgu_resource.start,
                        resource_size(&ltq_cgu_resource), "cgu") < 0)
-               panic("Failed to request cgu memory\n");
+               panic("Failed to request cgu memory");
 
        ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start,
                                resource_size(&ltq_cgu_resource));
index f9737bb3c5ab7442b055a6d0d7aa0e7529b37b6d..d673731c538a4d7c6328d00d8249b1290d51dd91 100644 (file)
@@ -240,7 +240,6 @@ out:
 
 static struct irqaction cascade = {
        .handler = no_action,
-       .flags = IRQF_DISABLED,
        .name = "cascade",
 };
 
@@ -249,28 +248,28 @@ void __init arch_init_irq(void)
        int i;
 
        if (insert_resource(&iomem_resource, &ltq_icu_resource) < 0)
-               panic("Failed to insert icu memory\n");
+               panic("Failed to insert icu memory");
 
        if (request_mem_region(ltq_icu_resource.start,
                        resource_size(&ltq_icu_resource), "icu") < 0)
-               panic("Failed to request icu memory\n");
+               panic("Failed to request icu memory");
 
        ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start,
                                resource_size(&ltq_icu_resource));
        if (!ltq_icu_membase)
-               panic("Failed to remap icu memory\n");
+               panic("Failed to remap icu memory");
 
        if (insert_resource(&iomem_resource, &ltq_eiu_resource) < 0)
-               panic("Failed to insert eiu memory\n");
+               panic("Failed to insert eiu memory");
 
        if (request_mem_region(ltq_eiu_resource.start,
                        resource_size(&ltq_eiu_resource), "eiu") < 0)
-               panic("Failed to request eiu memory\n");
+               panic("Failed to request eiu memory");
 
        ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start,
                                resource_size(&ltq_eiu_resource));
        if (!ltq_eiu_membase)
-               panic("Failed to remap eiu memory\n");
+               panic("Failed to remap eiu memory");
 
        /* make sure all irqs are turned off by default */
        for (i = 0; i < 5; i++)
index cbb6ae5747b97f81c67c8d77916bd10bad34e125..b210e936c7c3a84900eeeb0c1ba628b7479ba71a 100644 (file)
@@ -222,17 +222,17 @@ ltq_dma_init(void)
 
        /* insert and request the memory region */
        if (insert_resource(&iomem_resource, &ltq_dma_resource) < 0)
-               panic("Failed to insert dma memory\n");
+               panic("Failed to insert dma memory");
 
        if (request_mem_region(ltq_dma_resource.start,
                        resource_size(&ltq_dma_resource), "dma") < 0)
-               panic("Failed to request dma memory\n");
+               panic("Failed to request dma memory");
 
        /* remap dma register range */
        ltq_dma_membase = ioremap_nocache(ltq_dma_resource.start,
                                resource_size(&ltq_dma_resource));
        if (!ltq_dma_membase)
-               panic("Failed to remap dma memory\n");
+               panic("Failed to remap dma memory");
 
        /* power up and reset the dma engine */
        ltq_pmu_enable(PMU_DMA);
index 033b3184c7a70d180dbed8950c0d7e4e594317dd..862e3e830680be5642dabaf84519801b63c8ae94 100644 (file)
@@ -32,17 +32,17 @@ static int __init lantiq_ebu_init(void)
 {
        /* insert and request the memory region */
        if (insert_resource(&iomem_resource, &ltq_ebu_resource) < 0)
-               panic("Failed to insert ebu memory\n");
+               panic("Failed to insert ebu memory");
 
        if (request_mem_region(ltq_ebu_resource.start,
                        resource_size(&ltq_ebu_resource), "ebu") < 0)
-               panic("Failed to request ebu memory\n");
+               panic("Failed to request ebu memory");
 
        /* remap ebu register range */
        ltq_ebu_membase = ioremap_nocache(ltq_ebu_resource.start,
                                resource_size(&ltq_ebu_resource));
        if (!ltq_ebu_membase)
-               panic("Failed to remap ebu memory\n");
+               panic("Failed to remap ebu memory");
 
        /* make sure to unprotect the memory region where flash is located */
        ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
index 39f0d2641cbfece73d507aa01b0d5e888e26b272..fe85361e032e1146887b9d7e183cc02819b3c1eb 100644 (file)
@@ -40,7 +40,7 @@ void ltq_pmu_enable(unsigned int module)
        do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module));
 
        if (!err)
-               panic("activating PMU module failed!\n");
+               panic("activating PMU module failed!");
 }
 EXPORT_SYMBOL(ltq_pmu_enable);
 
@@ -53,16 +53,16 @@ EXPORT_SYMBOL(ltq_pmu_disable);
 int __init ltq_pmu_init(void)
 {
        if (insert_resource(&iomem_resource, &ltq_pmu_resource) < 0)
-               panic("Failed to insert pmu memory\n");
+               panic("Failed to insert pmu memory");
 
        if (request_mem_region(ltq_pmu_resource.start,
                        resource_size(&ltq_pmu_resource), "pmu") < 0)
-               panic("Failed to request pmu memory\n");
+               panic("Failed to request pmu memory");
 
        ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start,
                                resource_size(&ltq_pmu_resource));
        if (!ltq_pmu_membase)
-               panic("Failed to remap pmu memory\n");
+               panic("Failed to remap pmu memory");
        return 0;
 }
 
index 3d41f0bb5bf73f0d84108129a979642770e632f7..8b66bd87f0c1cbf4a698c47cf78721da799aee0f 100644 (file)
@@ -69,17 +69,17 @@ static int __init mips_reboot_setup(void)
 {
        /* insert and request the memory region */
        if (insert_resource(&iomem_resource, &ltq_rcu_resource) < 0)
-               panic("Failed to insert rcu memory\n");
+               panic("Failed to insert rcu memory");
 
        if (request_mem_region(ltq_rcu_resource.start,
                        resource_size(&ltq_rcu_resource), "rcu") < 0)
-               panic("Failed to request rcu memory\n");
+               panic("Failed to request rcu memory");
 
        /* remap rcu register range */
        ltq_rcu_membase = ioremap_nocache(ltq_rcu_resource.start,
                                resource_size(&ltq_rcu_resource));
        if (!ltq_rcu_membase)
-               panic("Failed to remap rcu memory\n");
+               panic("Failed to remap rcu memory");
 
        _machine_restart = ltq_machine_restart;
        _machine_halt = ltq_machine_halt;
index b2cad4fd5fc4a6720c3eae65384f1c94b62f7f8f..2a7c74fc15fcef917d183201d9f6eac9046fcbf7 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_CPU_TX49XX)      += dump_tlb.o
 obj-$(CONFIG_CPU_VR41XX)       += dump_tlb.o
 obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += dump_tlb.o
 obj-$(CONFIG_CPU_XLR)          += dump_tlb.o
+obj-$(CONFIG_CPU_XLP)          += dump_tlb.o
 
 # libgcc-style stuff needed in the kernel
 obj-y += ashldi3.o ashrdi3.o cmpdi2.o lshrdi3.o ucmpdi2.o
index 0cb1b9760e34f32c19b57f8a0de4f9442766190e..5d1f48fa1a527a22bde62471e8c9fd3321b11225 100644 (file)
@@ -111,7 +111,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction irq5 = {
        .handler = timer_interrupt,
-       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
+       .flags = IRQF_NOBALANCING | IRQF_TIMER,
        .name = "timer"
 };
 
index dbf2f93a50911b5914a295a82b3179c36562013f..a03bf00a1a9cf096226b0ce09a590450018ba62f 100644 (file)
@@ -245,7 +245,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                 */
                emulpc = xcp->cp0_epc + 4;      /* Snapshot emulation target */
 
-               if (__compute_return_epc(xcp)) {
+               if (__compute_return_epc(xcp) < 0) {
 #ifdef CP1DBG
                        printk("failed to emulate branch at %p\n",
                                (void *) (xcp->cp0_epc));
index 4d8c1623eee2978a00bb792a6e714bfe668f27d7..4aa20280613ea3954db6e7925cc2fead924b0b78 100644 (file)
@@ -3,8 +3,8 @@
 #
 
 obj-y                          += cache.o dma-default.o extable.o fault.o \
-                                  init.o mmap.o tlbex.o tlbex-fault.o uasm.o \
-                                  page.o
+                                  gup.o init.o mmap.o page.o tlbex.o \
+                                  tlbex-fault.o uasm.o
 
 obj-$(CONFIG_32BIT)            += ioremap.o pgtable-32.o
 obj-$(CONFIG_64BIT)            += pgtable-64.o
@@ -31,6 +31,7 @@ obj-$(CONFIG_CPU_TX49XX)      += c-r4k.o cex-gen.o tlb-r4k.o
 obj-$(CONFIG_CPU_VR41XX)       += c-r4k.o cex-gen.o tlb-r4k.o
 obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += c-octeon.o cex-oct.o tlb-r4k.o
 obj-$(CONFIG_CPU_XLR)          += c-r4k.o tlb-r4k.o cex-gen.o
+obj-$(CONFIG_CPU_XLP)          += c-r4k.o tlb-r4k.o cex-gen.o
 
 obj-$(CONFIG_IP22_CPU_SCACHE)  += sc-ip22.o
 obj-$(CONFIG_R5000_CPU_SCACHE)  += sc-r5k.o
index daa81f7284ac89a5411b88d86f77ff6df1585f55..cf7895db0739023629992e82e425fbf74389eb95 100644 (file)
@@ -223,7 +223,7 @@ static void __cpuinit probe_octeon(void)
                break;
 
        default:
-               panic("Unsupported Cavium Networks CPU type\n");
+               panic("Unsupported Cavium Networks CPU type");
                break;
        }
 
index a79fe9aa7721aa56f05d8ab7995b6503cd98f618..4f9eb0b2303621419ee7482e12edbf9beb6059e2 100644 (file)
@@ -1235,6 +1235,9 @@ static void __cpuinit setup_scache(void)
                loongson2_sc_init();
                return;
 #endif
+       case CPU_XLP:
+               /* don't need to worry about L2, fully coherent */
+               return;
 
        default:
                if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
diff --git a/arch/mips/mm/gup.c b/arch/mips/mm/gup.c
new file mode 100644 (file)
index 0000000..33aadbc
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Lockless get_user_pages_fast for MIPS
+ *
+ * Copyright (C) 2008 Nick Piggin
+ * Copyright (C) 2008 Novell Inc.
+ * Copyright (C) 2011 Ralf Baechle
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmstat.h>
+#include <linux/highmem.h>
+#include <linux/swap.h>
+#include <linux/hugetlb.h>
+
+#include <asm/pgtable.h>
+
+static inline pte_t gup_get_pte(pte_t *ptep)
+{
+#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
+       pte_t pte;
+
+retry:
+       pte.pte_low = ptep->pte_low;
+       smp_rmb();
+       pte.pte_high = ptep->pte_high;
+       smp_rmb();
+       if (unlikely(pte.pte_low != ptep->pte_low))
+               goto retry;
+
+       return pte;
+#else
+       return ACCESS_ONCE(*ptep);
+#endif
+}
+
+static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
+                       int write, struct page **pages, int *nr)
+{
+       pte_t *ptep = pte_offset_map(&pmd, addr);
+       do {
+               pte_t pte = gup_get_pte(ptep);
+               struct page *page;
+
+               if (!pte_present(pte) ||
+                   pte_special(pte) || (write && !pte_write(pte))) {
+                       pte_unmap(ptep);
+                       return 0;
+               }
+               VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+               page = pte_page(pte);
+               get_page(page);
+               SetPageReferenced(page);
+               pages[*nr] = page;
+               (*nr)++;
+
+       } while (ptep++, addr += PAGE_SIZE, addr != end);
+
+       pte_unmap(ptep - 1);
+       return 1;
+}
+
+static inline void get_head_page_multiple(struct page *page, int nr)
+{
+       VM_BUG_ON(page != compound_head(page));
+       VM_BUG_ON(page_count(page) == 0);
+       atomic_add(nr, &page->_count);
+       SetPageReferenced(page);
+}
+
+static int gup_huge_pmd(pmd_t pmd, unsigned long addr, unsigned long end,
+                       int write, struct page **pages, int *nr)
+{
+       pte_t pte = *(pte_t *)&pmd;
+       struct page *head, *page;
+       int refs;
+
+       if (write && !pte_write(pte))
+               return 0;
+       /* hugepages are never "special" */
+       VM_BUG_ON(pte_special(pte));
+       VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+
+       refs = 0;
+       head = pte_page(pte);
+       page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
+       do {
+               VM_BUG_ON(compound_head(page) != head);
+               pages[*nr] = page;
+               if (PageTail(page))
+                       get_huge_page_tail(page);
+               (*nr)++;
+               page++;
+               refs++;
+       } while (addr += PAGE_SIZE, addr != end);
+
+       get_head_page_multiple(head, refs);
+       return 1;
+}
+
+static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
+                       int write, struct page **pages, int *nr)
+{
+       unsigned long next;
+       pmd_t *pmdp;
+
+       pmdp = pmd_offset(&pud, addr);
+       do {
+               pmd_t pmd = *pmdp;
+
+               next = pmd_addr_end(addr, end);
+               /*
+                * The pmd_trans_splitting() check below explains why
+                * pmdp_splitting_flush has to flush the tlb, to stop
+                * this gup-fast code from running while we set the
+                * splitting bit in the pmd. Returning zero will take
+                * the slow path that will call wait_split_huge_page()
+                * if the pmd is still in splitting state. gup-fast
+                * can't because it has irq disabled and
+                * wait_split_huge_page() would never return as the
+                * tlb flush IPI wouldn't run.
+                */
+               if (pmd_none(pmd) || pmd_trans_splitting(pmd))
+                       return 0;
+               if (unlikely(pmd_huge(pmd))) {
+                       if (!gup_huge_pmd(pmd, addr, next, write, pages,nr))
+                               return 0;
+               } else {
+                       if (!gup_pte_range(pmd, addr, next, write, pages,nr))
+                               return 0;
+               }
+       } while (pmdp++, addr = next, addr != end);
+
+       return 1;
+}
+
+static int gup_huge_pud(pud_t pud, unsigned long addr, unsigned long end,
+                       int write, struct page **pages, int *nr)
+{
+       pte_t pte = *(pte_t *)&pud;
+       struct page *head, *page;
+       int refs;
+
+       if (write && !pte_write(pte))
+               return 0;
+       /* hugepages are never "special" */
+       VM_BUG_ON(pte_special(pte));
+       VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+
+       refs = 0;
+       head = pte_page(pte);
+       page = head + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
+       do {
+               VM_BUG_ON(compound_head(page) != head);
+               pages[*nr] = page;
+               (*nr)++;
+               page++;
+               refs++;
+       } while (addr += PAGE_SIZE, addr != end);
+
+       get_head_page_multiple(head, refs);
+       return 1;
+}
+
+static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
+                       int write, struct page **pages, int *nr)
+{
+       unsigned long next;
+       pud_t *pudp;
+
+       pudp = pud_offset(&pgd, addr);
+       do {
+               pud_t pud = *pudp;
+
+               next = pud_addr_end(addr, end);
+               if (pud_none(pud))
+                       return 0;
+               if (unlikely(pud_huge(pud))) {
+                       if (!gup_huge_pud(pud, addr, next, write, pages,nr))
+                               return 0;
+               } else {
+                       if (!gup_pmd_range(pud, addr, next, write, pages,nr))
+                               return 0;
+               }
+       } while (pudp++, addr = next, addr != end);
+
+       return 1;
+}
+
+/*
+ * Like get_user_pages_fast() except its IRQ-safe in that it won't fall
+ * back to the regular GUP.
+ */
+int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
+                         struct page **pages)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long addr, len, end;
+       unsigned long next;
+       unsigned long flags;
+       pgd_t *pgdp;
+       int nr = 0;
+
+       start &= PAGE_MASK;
+       addr = start;
+       len = (unsigned long) nr_pages << PAGE_SHIFT;
+       end = start + len;
+       if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
+                                       (void __user *)start, len)))
+               return 0;
+
+       /*
+        * XXX: batch / limit 'nr', to avoid large irq off latency
+        * needs some instrumenting to determine the common sizes used by
+        * important workloads (eg. DB2), and whether limiting the batch
+        * size will decrease performance.
+        *
+        * It seems like we're in the clear for the moment. Direct-IO is
+        * the main guy that batches up lots of get_user_pages, and even
+        * they are limited to 64-at-a-time which is not so many.
+        */
+       /*
+        * This doesn't prevent pagetable teardown, but does prevent
+        * the pagetables and pages from being freed.
+        *
+        * So long as we atomically load page table pointers versus teardown,
+        * we can follow the address down to the page and take a ref on it.
+        */
+       local_irq_save(flags);
+       pgdp = pgd_offset(mm, addr);
+       do {
+               pgd_t pgd = *pgdp;
+
+               next = pgd_addr_end(addr, end);
+               if (pgd_none(pgd))
+                       break;
+               if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+                       break;
+       } while (pgdp++, addr = next, addr != end);
+       local_irq_restore(flags);
+
+       return nr;
+}
+
+/**
+ * get_user_pages_fast() - pin user pages in memory
+ * @start:     starting user address
+ * @nr_pages:  number of pages from start to pin
+ * @write:     whether pages will be written to
+ * @pages:     array that receives pointers to the pages pinned.
+ *             Should be at least nr_pages long.
+ *
+ * Attempt to pin user pages in memory without taking mm->mmap_sem.
+ * If not successful, it will fall back to taking the lock and
+ * calling get_user_pages().
+ *
+ * Returns number of pages pinned. This may be fewer than the number
+ * requested. If nr_pages is 0 or negative, returns 0. If no pages
+ * were pinned, returns -errno.
+ */
+int get_user_pages_fast(unsigned long start, int nr_pages, int write,
+                       struct page **pages)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long addr, len, end;
+       unsigned long next;
+       pgd_t *pgdp;
+       int ret, nr = 0;
+
+       start &= PAGE_MASK;
+       addr = start;
+       len = (unsigned long) nr_pages << PAGE_SHIFT;
+
+       end = start + len;
+       if (end < start)
+               goto slow_irqon;
+
+       /* XXX: batch / limit 'nr' */
+       local_irq_disable();
+       pgdp = pgd_offset(mm, addr);
+       do {
+               pgd_t pgd = *pgdp;
+
+               next = pgd_addr_end(addr, end);
+               if (pgd_none(pgd))
+                       goto slow;
+               if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+                       goto slow;
+       } while (pgdp++, addr = next, addr != end);
+       local_irq_enable();
+
+       VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
+       return nr;
+slow:
+       local_irq_enable();
+
+slow_irqon:
+       /* Try to get the remaining pages with get_user_pages */
+       start += nr << PAGE_SHIFT;
+       pages += nr;
+
+       down_read(&mm->mmap_sem);
+       ret = get_user_pages(current, mm, start,
+                               (end - start) >> PAGE_SHIFT,
+                               write, 0, pages, NULL);
+       up_read(&mm->mmap_sem);
+
+       /* Have to be a bit careful with return values */
+       if (nr > 0) {
+               if (ret < 0)
+                       ret = nr;
+               else
+                       ret += nr;
+       }
+       return ret;
+}
index b7ebc4fa89bcd5b4b77465ab60919317b513bf79..3b3ffd439cd7d8811863f7d121c580f08578b3d7 100644 (file)
@@ -304,9 +304,14 @@ int page_is_ram(unsigned long pagenr)
        for (i = 0; i < boot_mem_map.nr_map; i++) {
                unsigned long addr, end;
 
-               if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
+               switch (boot_mem_map.map[i].type) {
+               case BOOT_MEM_RAM:
+               case BOOT_MEM_INIT_RAM:
+                       break;
+               default:
                        /* not usable memory */
                        continue;
+               }
 
                addr = PFN_UP(boot_mem_map.map[i].addr);
                end = PFN_DOWN(boot_mem_map.map[i].addr +
@@ -379,7 +384,7 @@ void __init mem_init(void)
 
        reservedpages = ram = 0;
        for (tmp = 0; tmp < max_low_pfn; tmp++)
-               if (page_is_ram(tmp)) {
+               if (page_is_ram(tmp) && pfn_valid(tmp)) {
                        ram++;
                        if (PageReserved(pfn_to_page(tmp)))
                                reservedpages++;
index 87bb85d8d537064d7e3b14b8cc5f342c589a484f..ed1fa460f84ec06b3a0c19e0fd93fd717286f7e0 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
 #include <asm/system.h>
+#include <asm/tlbmisc.h>
 #include <asm/isadep.h>
 #include <asm/io.h>
 #include <asm/bootinfo.h>
index 0d394e0e8837f640d84fa87003d763f0dc0bd10d..2dc625346c40f3b40f616310479b07c6695edd02 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
+#include <asm/tlbmisc.h>
 
 extern void build_tlb_refill_handler(void);
 
@@ -120,22 +121,30 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 
        if (cpu_context(cpu, mm) != 0) {
                unsigned long size, flags;
+               int huge = is_vm_hugetlb_page(vma);
 
                ENTER_CRITICAL(flags);
-               size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-               size = (size + 1) >> 1;
+               if (huge) {
+                       start = round_down(start, HPAGE_SIZE);
+                       end = round_up(end, HPAGE_SIZE);
+                       size = (end - start) >> HPAGE_SHIFT;
+               } else {
+                       start = round_down(start, PAGE_SIZE << 1);
+                       end = round_up(end, PAGE_SIZE << 1);
+                       size = (end - start) >> (PAGE_SHIFT + 1);
+               }
                if (size <= current_cpu_data.tlbsize/2) {
                        int oldpid = read_c0_entryhi();
                        int newpid = cpu_asid(cpu, mm);
 
-                       start &= (PAGE_MASK << 1);
-                       end += ((PAGE_SIZE << 1) - 1);
-                       end &= (PAGE_MASK << 1);
                        while (start < end) {
                                int idx;
 
                                write_c0_entryhi(start | newpid);
-                               start += (PAGE_SIZE << 1);
+                               if (huge)
+                                       start += HPAGE_SIZE;
+                               else
+                                       start += (PAGE_SIZE << 1);
                                mtc0_tlbw_hazard();
                                tlb_probe();
                                tlb_probe_hazard();
@@ -368,51 +377,6 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
        EXIT_CRITICAL(flags);
 }
 
-/*
- * Used for loading TLB entries before trap_init() has started, when we
- * don't actually want to add a wired entry which remains throughout the
- * lifetime of the system
- */
-
-static int temp_tlb_entry __cpuinitdata;
-
-__init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
-                              unsigned long entryhi, unsigned long pagemask)
-{
-       int ret = 0;
-       unsigned long flags;
-       unsigned long wired;
-       unsigned long old_pagemask;
-       unsigned long old_ctx;
-
-       ENTER_CRITICAL(flags);
-       /* Save old context and create impossible VPN2 value */
-       old_ctx = read_c0_entryhi();
-       old_pagemask = read_c0_pagemask();
-       wired = read_c0_wired();
-       if (--temp_tlb_entry < wired) {
-               printk(KERN_WARNING
-                      "No TLB space left for add_temporary_entry\n");
-               ret = -ENOSPC;
-               goto out;
-       }
-
-       write_c0_index(temp_tlb_entry);
-       write_c0_pagemask(pagemask);
-       write_c0_entryhi(entryhi);
-       write_c0_entrylo0(entrylo0);
-       write_c0_entrylo1(entrylo1);
-       mtc0_tlbw_hazard();
-       tlb_write_indexed();
-       tlbw_use_hazard();
-
-       write_c0_entryhi(old_ctx);
-       write_c0_pagemask(old_pagemask);
-out:
-       EXIT_CRITICAL(flags);
-       return ret;
-}
-
 static int __cpuinitdata ntlb;
 static int __init set_ntlb(char *str)
 {
@@ -450,8 +414,6 @@ void __cpuinit tlb_init(void)
                write_c0_pagegrain(pg);
        }
 
-       temp_tlb_entry = current_cpu_data.tlbsize - 1;
-
         /* From this point on the ARC firmware is dead.  */
        local_flush_tlb_all();
 
index d53ff91b277c8f358a96058ddffada9901345ba1..a588b5cef8d2a8bed4003ee9b0056932f81a78e0 100644 (file)
@@ -322,13 +322,13 @@ static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 
 static struct irqaction irq_resched = {
        .handler        = ipi_resched_interrupt,
-       .flags          = IRQF_DISABLED|IRQF_PERCPU,
+       .flags          = IRQF_PERCPU,
        .name           = "IPI_resched"
 };
 
 static struct irqaction irq_call = {
        .handler        = ipi_call_interrupt,
-       .flags          = IRQF_DISABLED|IRQF_PERCPU,
+       .flags          = IRQF_PERCPU,
        .name           = "IPI_call"
 };
 #endif /* CONFIG_MIPS_MT_SMP */
index a5ca743613f26149167c58a23e286cde17a960ab..75bec44b5856ee916a3c006af7744a0746242983 100644 (file)
@@ -1,5 +1,2 @@
 config NLM_COMMON
        bool
-
-config NLM_XLR
-       bool
diff --git a/arch/mips/netlogic/Makefile b/arch/mips/netlogic/Makefile
new file mode 100644 (file)
index 0000000..36d169b
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_NLM_COMMON)       +=      common/
+obj-$(CONFIG_CPU_XLR)          +=      xlr/
+obj-$(CONFIG_CPU_XLP)          +=      xlp/
index b648b487fd6674b2cdcedb1420e1d5759decba92..cdfc9abbbb7bc3905fbd0f8211ba74fa5d06f0dc 100644 (file)
@@ -1,16 +1,17 @@
 #
 # NETLOGIC includes
 #
-cflags-$(CONFIG_NLM_COMMON)  += -I$(srctree)/arch/mips/include/asm/mach-netlogic
-cflags-$(CONFIG_NLM_COMMON)  += -I$(srctree)/arch/mips/include/asm/netlogic
+cflags-$(CONFIG_NLM_COMMON)    += -I$(srctree)/arch/mips/include/asm/mach-netlogic
+cflags-$(CONFIG_NLM_COMMON)    += -I$(srctree)/arch/mips/include/asm/netlogic
 
 #
 # use mips64 if xlr is not available
 #
-cflags-$(CONFIG_NLM_XLR)       += $(call cc-option,-march=xlr,-march=mips64)
+cflags-$(CONFIG_CPU_XLR)       += $(call cc-option,-march=xlr,-march=mips64)
+cflags-$(CONFIG_CPU_XLP)       += $(call cc-option,-march=xlp,-march=mips64r2)
 
 #
-# NETLOGIC XLR/XLS SoC, Simulator and boards
+# NETLOGIC processor support
 #
-core-$(CONFIG_NLM_XLR)       += arch/mips/netlogic/xlr/
-load-$(CONFIG_NLM_XLR_BOARD)  += 0xffffffff84000000
+platform-$(CONFIG_NLM_COMMON)          += netlogic/
+load-$(CONFIG_NLM_COMMON)      += 0xffffffff80100000
diff --git a/arch/mips/netlogic/common/Makefile b/arch/mips/netlogic/common/Makefile
new file mode 100644 (file)
index 0000000..291372a
--- /dev/null
@@ -0,0 +1,3 @@
+obj-y                          += irq.o time.o
+obj-$(CONFIG_SMP)              += smp.o smpboot.o
+obj-$(CONFIG_EARLY_PRINTK)     += earlycons.o
diff --git a/arch/mips/netlogic/common/earlycons.c b/arch/mips/netlogic/common/earlycons.c
new file mode 100644 (file)
index 0000000..f193f7b
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/types.h>
+#include <linux/serial_reg.h>
+
+#include <asm/mipsregs.h>
+#include <asm/netlogic/haldefs.h>
+
+#if defined(CONFIG_CPU_XLP)
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/uart.h>
+#elif defined(CONFIG_CPU_XLR)
+#include <asm/netlogic/xlr/iomap.h>
+#endif
+
+void prom_putchar(char c)
+{
+       uint64_t uartbase;
+
+#if defined(CONFIG_CPU_XLP)
+       uartbase = nlm_get_uart_regbase(0, 0);
+#elif defined(CONFIG_CPU_XLR)
+       uartbase = nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET);
+#endif
+       while (nlm_read_reg(uartbase, UART_LSR) == 0)
+               ;
+       nlm_write_reg(uartbase, UART_TX, c);
+}
diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c
new file mode 100644 (file)
index 0000000..49a4f6c
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+
+#include <asm/errno.h>
+#include <asm/signal.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/mipsregs.h>
+#include <asm/thread_info.h>
+
+#include <asm/netlogic/mips-extns.h>
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/common.h>
+
+#if defined(CONFIG_CPU_XLP)
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/pic.h>
+#elif defined(CONFIG_CPU_XLR)
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/pic.h>
+#else
+#error "Unknown CPU"
+#endif
+/*
+ * These are the routines that handle all the low level interrupt stuff.
+ * Actions handled here are: initialization of the interrupt map, requesting of
+ * interrupt lines by handlers, dispatching if interrupts to handlers, probing
+ * for interrupt lines
+ */
+
+/* Globals */
+static uint64_t nlm_irq_mask;
+static DEFINE_SPINLOCK(nlm_pic_lock);
+
+static void xlp_pic_enable(struct irq_data *d)
+{
+       unsigned long flags;
+       int irt;
+
+       irt = nlm_irq_to_irt(d->irq);
+       if (irt == -1)
+               return;
+       spin_lock_irqsave(&nlm_pic_lock, flags);
+       nlm_pic_enable_irt(nlm_pic_base, irt);
+       spin_unlock_irqrestore(&nlm_pic_lock, flags);
+}
+
+static void xlp_pic_disable(struct irq_data *d)
+{
+       unsigned long flags;
+       int irt;
+
+       irt = nlm_irq_to_irt(d->irq);
+       if (irt == -1)
+               return;
+       spin_lock_irqsave(&nlm_pic_lock, flags);
+       nlm_pic_disable_irt(nlm_pic_base, irt);
+       spin_unlock_irqrestore(&nlm_pic_lock, flags);
+}
+
+static void xlp_pic_mask_ack(struct irq_data *d)
+{
+       uint64_t mask = 1ull << d->irq;
+
+       write_c0_eirr(mask);            /* ack by writing EIRR */
+}
+
+static void xlp_pic_unmask(struct irq_data *d)
+{
+       void *hd = irq_data_get_irq_handler_data(d);
+       int irt;
+
+       irt = nlm_irq_to_irt(d->irq);
+       if (irt == -1)
+               return;
+
+       if (hd) {
+               void (*extra_ack)(void *) = hd;
+               extra_ack(d);
+       }
+       /* Ack is a single write, no need to lock */
+       nlm_pic_ack(nlm_pic_base, irt);
+}
+
+static struct irq_chip xlp_pic = {
+       .name           = "XLP-PIC",
+       .irq_enable     = xlp_pic_enable,
+       .irq_disable    = xlp_pic_disable,
+       .irq_mask_ack   = xlp_pic_mask_ack,
+       .irq_unmask     = xlp_pic_unmask,
+};
+
+static void cpuintr_disable(struct irq_data *d)
+{
+       uint64_t eimr;
+       uint64_t mask = 1ull << d->irq;
+
+       eimr = read_c0_eimr();
+       write_c0_eimr(eimr & ~mask);
+}
+
+static void cpuintr_enable(struct irq_data *d)
+{
+       uint64_t eimr;
+       uint64_t mask = 1ull << d->irq;
+
+       eimr = read_c0_eimr();
+       write_c0_eimr(eimr | mask);
+}
+
+static void cpuintr_ack(struct irq_data *d)
+{
+       uint64_t mask = 1ull << d->irq;
+
+       write_c0_eirr(mask);
+}
+
+static void cpuintr_nop(struct irq_data *d)
+{
+       WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq);
+}
+
+/*
+ * Chip definition for CPU originated interrupts(timer, msg) and
+ * IPIs
+ */
+struct irq_chip nlm_cpu_intr = {
+       .name           = "XLP-CPU-INTR",
+       .irq_enable     = cpuintr_enable,
+       .irq_disable    = cpuintr_disable,
+       .irq_mask       = cpuintr_nop,
+       .irq_ack        = cpuintr_nop,
+       .irq_eoi        = cpuintr_ack,
+};
+
+void __init init_nlm_common_irqs(void)
+{
+       int i, irq, irt;
+
+       for (i = 0; i < PIC_IRT_FIRST_IRQ; i++)
+               irq_set_chip_and_handler(i, &nlm_cpu_intr, handle_percpu_irq);
+
+       for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ ; i++)
+               irq_set_chip_and_handler(i, &xlp_pic, handle_level_irq);
+
+#ifdef CONFIG_SMP
+       irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr,
+                        nlm_smp_function_ipi_handler);
+       irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr,
+                        nlm_smp_resched_ipi_handler);
+       nlm_irq_mask |=
+           ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE));
+#endif
+
+       for (irq = PIC_IRT_FIRST_IRQ; irq <= PIC_IRT_LAST_IRQ; irq++) {
+               irt = nlm_irq_to_irt(irq);
+               if (irt == -1)
+                       continue;
+               nlm_irq_mask |= (1ULL << irq);
+               nlm_pic_init_irt(nlm_pic_base, irt, irq, 0);
+       }
+
+       nlm_irq_mask |= (1ULL << IRQ_TIMER);
+}
+
+void __init arch_init_irq(void)
+{
+       /* Initialize the irq descriptors */
+       init_nlm_common_irqs();
+
+       write_c0_eimr(nlm_irq_mask);
+}
+
+void __cpuinit nlm_smp_irq_init(void)
+{
+       /* set interrupt mask for non-zero cpus */
+       write_c0_eimr(nlm_irq_mask);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+       uint64_t eirr;
+       int i;
+
+       eirr = read_c0_eirr() & read_c0_eimr();
+       if (eirr & (1 << IRQ_TIMER)) {
+               do_IRQ(IRQ_TIMER);
+               return;
+       }
+
+       i = __ilog2_u64(eirr);
+       if (i == -1)
+               return;
+
+       do_IRQ(i);
+}
similarity index 65%
rename from arch/mips/netlogic/xlr/smp.c
rename to arch/mips/netlogic/common/smp.c
index 080284ded508369241077d11c8d4176ea76cc825..db17f49886c26681b5fe1d61555e7c7b5f8602b9 100644 (file)
 
 #include <asm/netlogic/interrupt.h>
 #include <asm/netlogic/mips-extns.h>
-
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/common.h>
+
+#if defined(CONFIG_CPU_XLP)
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/pic.h>
+#elif defined(CONFIG_CPU_XLR)
 #include <asm/netlogic/xlr/iomap.h>
 #include <asm/netlogic/xlr/pic.h>
 #include <asm/netlogic/xlr/xlr.h>
+#else
+#error "Unknown CPU"
+#endif
 
-void core_send_ipi(int logical_cpu, unsigned int action)
+void nlm_send_ipi_single(int logical_cpu, unsigned int action)
 {
        int cpu = cpu_logical_map(logical_cpu);
-       u32 tid = cpu & 0x3;
-       u32 pid = (cpu >> 2) & 0x07;
-       u32 ipi = (tid << 16) | (pid << 20);
 
        if (action & SMP_CALL_FUNCTION)
-               ipi |= IRQ_IPI_SMP_FUNCTION;
-       else if (action & SMP_RESCHEDULE_YOURSELF)
-               ipi |= IRQ_IPI_SMP_RESCHEDULE;
-       else
-               return;
-
-       pic_send_ipi(ipi);
-}
-
-void nlm_send_ipi_single(int cpu, unsigned int action)
-{
-       core_send_ipi(cpu, action);
+               nlm_pic_send_ipi(nlm_pic_base, cpu, IRQ_IPI_SMP_FUNCTION, 0);
+       if (action & SMP_RESCHEDULE_YOURSELF)
+               nlm_pic_send_ipi(nlm_pic_base, cpu, IRQ_IPI_SMP_RESCHEDULE, 0);
 }
 
 void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action)
@@ -74,29 +72,35 @@ void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action)
        int cpu;
 
        for_each_cpu(cpu, mask) {
-               core_send_ipi(cpu, action);
+               nlm_send_ipi_single(cpu, action);
        }
 }
 
 /* IRQ_IPI_SMP_FUNCTION Handler */
 void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc)
 {
+       write_c0_eirr(1ull << irq);
        smp_call_function_interrupt();
 }
 
 /* IRQ_IPI_SMP_RESCHEDULE  handler */
 void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc)
 {
+       write_c0_eirr(1ull << irq);
        scheduler_ipi();
 }
 
 /*
  * Called before going into mips code, early cpu init
  */
-void nlm_early_init_secondary(void)
+void nlm_early_init_secondary(int cpu)
 {
+       change_c0_config(CONF_CM_CMASK, 0x3);
        write_c0_ebase((uint32_t)nlm_common_ebase);
-       /* TLB partition here later */
+#ifdef CONFIG_CPU_XLP
+       if (hard_smp_processor_id() % 4 == 0)
+               xlp_mmu_init();
+#endif
 }
 
 /*
@@ -104,9 +108,16 @@ void nlm_early_init_secondary(void)
  */
 static void __cpuinit nlm_init_secondary(void)
 {
+       current_cpu_data.core = hard_smp_processor_id() / 4;
        nlm_smp_irq_init();
 }
 
+void nlm_prepare_cpus(unsigned int max_cpus)
+{
+       /* declare we are SMT capable */
+       smp_num_siblings = nlm_threads_per_core;
+}
+
 void nlm_smp_finish(void)
 {
 #ifdef notyet
@@ -123,10 +134,10 @@ void nlm_cpus_done(void)
  * Boot all other cpus in the system, initialize them, and bring them into
  * the boot function
  */
-int nlm_cpu_unblock[NR_CPUS];
 int nlm_cpu_ready[NR_CPUS];
 unsigned long nlm_next_gp;
 unsigned long nlm_next_sp;
+
 cpumask_t phys_cpu_present_map;
 
 void nlm_boot_secondary(int logical_cpu, struct task_struct *idle)
@@ -140,7 +151,7 @@ void nlm_boot_secondary(int logical_cpu, struct task_struct *idle)
 
        /* barrier */
        __sync();
-       nlm_cpu_unblock[cpu] = 1;
+       nlm_pic_send_ipi(nlm_pic_base, cpu, 1, 1);
 }
 
 void __init nlm_smp_setup(void)
@@ -159,8 +170,8 @@ void __init nlm_smp_setup(void)
        num_cpus = 1;
        for (i = 0; i < NR_CPUS; i++) {
                /*
-                * BSP is not set in nlm_cpu_ready array, it is only for
-                * ASPs (goto see smpboot.S)
+                * nlm_cpu_ready array is not set for the boot_cpu,
+                * it is only set for ASPs (see smpboot.S)
                 */
                if (nlm_cpu_ready[i]) {
                        cpu_set(i, phys_cpu_present_map);
@@ -176,10 +187,75 @@ void __init nlm_smp_setup(void)
                (unsigned long)cpu_possible_map.bits[0]);
 
        pr_info("Detected %i Slave CPU(s)\n", num_cpus);
+       nlm_set_nmi_handler(nlm_boot_secondary_cpus);
 }
 
-void nlm_prepare_cpus(unsigned int max_cpus)
+static int nlm_parse_cpumask(u32 cpu_mask)
+{
+       uint32_t core0_thr_mask, core_thr_mask;
+       int threadmode, i;
+
+       core0_thr_mask = cpu_mask & 0xf;
+       switch (core0_thr_mask) {
+       case 1:
+               nlm_threads_per_core = 1;
+               threadmode = 0;
+               break;
+       case 3:
+               nlm_threads_per_core = 2;
+               threadmode = 2;
+               break;
+       case 0xf:
+               nlm_threads_per_core = 4;
+               threadmode = 3;
+               break;
+       default:
+               goto unsupp;
+       }
+
+       /* Verify other cores CPU masks */
+       nlm_coremask = 1;
+       nlm_cpumask = core0_thr_mask;
+       for (i = 1; i < 8; i++) {
+               core_thr_mask = (cpu_mask >> (i * 4)) & 0xf;
+               if (core_thr_mask) {
+                       if (core_thr_mask != core0_thr_mask)
+                               goto unsupp;
+                       nlm_coremask |= 1 << i;
+                       nlm_cpumask |= core0_thr_mask << (4 * i);
+               }
+       }
+       return threadmode;
+
+unsupp:
+       panic("Unsupported CPU mask %x\n", cpu_mask);
+       return 0;
+}
+
+int __cpuinit nlm_wakeup_secondary_cpus(u32 wakeup_mask)
 {
+       unsigned long reset_vec;
+       char *reset_data;
+       int threadmode;
+
+       /* Update reset entry point with CPU init code */
+       reset_vec = CKSEG1ADDR(RESET_VEC_PHYS);
+       memcpy((void *)reset_vec, (void *)nlm_reset_entry,
+                       (nlm_reset_entry_end - nlm_reset_entry));
+
+       /* verify the mask and setup core config variables */
+       threadmode = nlm_parse_cpumask(wakeup_mask);
+
+       /* Setup CPU init parameters */
+       reset_data = (char *)CKSEG1ADDR(RESET_DATA_PHYS);
+       *(int *)(reset_data + BOOT_THREAD_MODE) = threadmode;
+
+#ifdef CONFIG_CPU_XLP
+       xlp_wakeup_secondary_cpus();
+#else
+       xlr_wakeup_secondary_cpus();
+#endif
+       return 0;
 }
 
 struct plat_smp_ops nlm_smp_ops = {
@@ -192,29 +268,3 @@ struct plat_smp_ops nlm_smp_ops = {
        .smp_setup              = nlm_smp_setup,
        .prepare_cpus           = nlm_prepare_cpus,
 };
-
-unsigned long secondary_entry_point;
-
-int __cpuinit nlm_wakeup_secondary_cpus(u32 wakeup_mask)
-{
-       unsigned int tid, pid, ipi, i, boot_cpu;
-       void *reset_vec;
-
-       secondary_entry_point = (unsigned long)prom_pre_boot_secondary_cpus;
-       reset_vec = (void *)CKSEG1ADDR(0x1fc00000);
-       memcpy(reset_vec, nlm_boot_smp_nmi, 0x80);
-       boot_cpu = hard_smp_processor_id();
-
-       for (i = 0; i < NR_CPUS; i++) {
-               if (i == boot_cpu)
-                       continue;
-               if (wakeup_mask & (1u << i)) {
-                       tid = i & 0x3;
-                       pid = (i >> 2) & 0x7;
-                       ipi = (tid << 16) | (pid << 20) | (1 << 8);
-                       pic_send_ipi(ipi);
-               }
-       }
-
-       return 0;
-}
diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S
new file mode 100644 (file)
index 0000000..c138b1a
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/init.h>
+
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+#include <asm/asmmacro.h>
+#include <asm/addrspace.h>
+
+#include <asm/netlogic/common.h>
+
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/sys.h>
+#include <asm/netlogic/xlp-hal/cpucontrol.h>
+
+#define        CP0_EBASE       $15
+#define SYS_CPU_COHERENT_BASE(node)    CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \
+                       XLP_IO_SYS_OFFSET(node) + XLP_IO_PCI_HDRSZ + \
+                       SYS_CPU_NONCOHERENT_MODE * 4
+
+.macro __config_lsu
+       li      t0, LSU_DEFEATURE
+       mfcr    t1, t0
+
+       lui     t2, 0x4080  /* Enable Unaligned Access, L2HPE */
+       or      t1, t1, t2
+       li      t2, ~0xe    /* S1RCM */
+       and     t1, t1, t2
+       mtcr    t1, t0
+
+       li      t0, SCHED_DEFEATURE
+       lui     t1, 0x0100  /* Experimental: Disable BRU accepting ALU ops */
+       mtcr    t1, t0
+.endm
+
+/*
+ * The cores can come start when they are woken up. This is also the NMI
+ * entry, so check that first.
+ *
+ * The data corresponding to reset is stored at RESET_DATA_PHYS location,
+ * this will have the thread mask (used when core is woken up) and the
+ * current NMI handler in case we reached here for an NMI.
+ *
+ * When a core or thread is newly woken up, it loops in a 'wait'. When
+ * the CPU really needs waking up, we send an NMI to it, with the NMI
+ * handler set to prom_boot_secondary_cpus
+ */
+
+       .set    noreorder
+       .set    noat
+       .set    arch=xlr        /* for mfcr/mtcr, XLR is sufficient */
+
+FEXPORT(nlm_reset_entry)
+       dmtc0   k0, $22, 6
+       dmtc0   k1, $22, 7
+       mfc0    k0, CP0_STATUS
+       li      k1, 0x80000
+       and     k1, k0, k1
+       beqz    k1, 1f         /* go to real reset entry */
+       nop
+       li      k1, CKSEG1ADDR(RESET_DATA_PHYS)   /* NMI */
+       ld      k0, BOOT_NMI_HANDLER(k1)
+       jr      k0
+       nop
+
+1:     /* Entry point on core wakeup */
+       mfc0    t0, CP0_EBASE, 1
+       mfc0    t1, CP0_EBASE, 1
+       srl     t1, 5
+       andi    t1, 0x3                 /* t1 <- node */
+       li      t2, 0x40000
+       mul     t3, t2, t1              /* t3 = node * 0x40000 */
+       srl     t0, t0, 2
+       and     t0, t0, 0x7             /* t0 <- core */
+       li      t1, 0x1
+       sll     t0, t1, t0
+       nor     t0, t0, zero            /* t0 <- ~(1 << core) */
+       li      t2, SYS_CPU_COHERENT_BASE(0)
+       add     t2, t2, t3              /* t2 <- SYS offset for node */
+       lw      t1, 0(t2)
+       and     t1, t1, t0
+       sw      t1, 0(t2)
+
+       /* read back to ensure complete */
+       lw      t1, 0(t2)
+       sync
+
+       /* Configure LSU on Non-0 Cores. */
+       __config_lsu
+
+/*
+ * Wake up sibling threads from the initial thread in
+ * a core.
+ */
+EXPORT(nlm_boot_siblings)
+       li      t0, CKSEG1ADDR(RESET_DATA_PHYS)
+       lw      t1, BOOT_THREAD_MODE(t0)        /* t1 <- thread mode */
+       li      t0, ((CPU_BLOCKID_MAP << 8) | MAP_THREADMODE)
+       mfcr    t2, t0
+       or      t2, t2, t1
+       mtcr    t2, t0
+
+       /*
+        * The new hardware thread starts at the next instruction
+        * For all the cases other than core 0 thread 0, we will
+         * jump to the secondary wait function.
+         */
+       mfc0    v0, CP0_EBASE, 1
+       andi    v0, 0x7f                /* v0 <- node/core */
+
+#if 1
+       /* A0 errata - Write MMU_SETUP after changing thread mode register. */
+       andi    v1, v0, 0x3             /* v1 <- thread id */
+       bnez    v1, 2f
+       nop
+
+        li     t0, MMU_SETUP
+        li     t1, 0
+        mtcr   t1, t0
+       ehb
+#endif
+
+2:     beqz    v0, 4f
+       nop
+
+       /* setup status reg */
+       mfc0    t1, CP0_STATUS
+       li      t0, ST0_BEV
+       or      t1, t0
+       xor     t1, t0
+#ifdef CONFIG_64BIT
+       ori     t1, ST0_KX
+#endif
+       mtc0    t1, CP0_STATUS
+       /* mark CPU ready */
+       PTR_LA  t1, nlm_cpu_ready
+       sll     v1, v0, 2
+       PTR_ADDU t1, v1
+       li      t2, 1
+       sw      t2, 0(t1)
+       /* Wait until NMI hits */
+3:     wait
+       j       3b
+       nop
+
+       /*
+        * For the boot CPU, we have to restore registers and
+        * return
+        */
+4:     dmfc0   t0, $4, 2       /* restore SP from UserLocal */
+       li      t1, 0xfadebeef
+       dmtc0   t1, $4, 2       /* restore SP from UserLocal */
+       PTR_SUBU sp, t0, PT_SIZE
+       RESTORE_ALL
+       jr   ra
+       nop
+EXPORT(nlm_reset_entry_end)
+
+FEXPORT(xlp_boot_core0_siblings)       /* "Master" cpu starts from here */
+       __config_lsu
+       dmtc0   sp, $4, 2               /* SP saved in UserLocal */
+       SAVE_ALL
+       sync
+       /* find the location to which nlm_boot_siblings was relocated */
+       li      t0, CKSEG1ADDR(RESET_VEC_PHYS)
+       dla     t1, nlm_reset_entry
+       dla     t2, nlm_boot_siblings
+       dsubu   t2, t1
+       daddu   t2, t0
+       /* call it */
+       jr      t2
+       nop
+       /* not reached */
+
+       __CPUINIT
+NESTED(nlm_boot_secondary_cpus, 16, sp)
+       PTR_LA  t1, nlm_next_sp
+       PTR_L   sp, 0(t1)
+       PTR_LA  t1, nlm_next_gp
+       PTR_L   gp, 0(t1)
+
+       /* a0 has the processor id */
+       PTR_LA  t0, nlm_early_init_secondary
+       jalr    t0
+       nop
+
+       PTR_LA  t0, smp_bootstrap
+       jr      t0
+       nop
+END(nlm_boot_secondary_cpus)
+       __FINIT
+
+/*
+ * In case of RMIboot bootloader which is used on XLR boards, the CPUs
+ * be already woken up and waiting in bootloader code.
+ * This will get them out of the bootloader code and into linux. Needed
+ *  because the bootloader area will be taken and initialized by linux.
+ */
+       __CPUINIT
+NESTED(nlm_rmiboot_preboot, 16, sp)
+       mfc0    t0, $15, 1      # read ebase
+       andi    t0, 0x1f        # t0 has the processor_id()
+       andi    t2, t0, 0x3     # thread no
+       sll     t0, 2           # offset in cpu array
+
+       PTR_LA  t1, nlm_cpu_ready # mark CPU ready
+       PTR_ADDU t1, t0
+       li      t3, 1
+       sw      t3, 0(t1)
+
+       bnez    t2, 1f          # skip thread programming
+       nop                     # for non zero hw threads
+
+       /*
+        * MMU setup only for first thread in core
+        */
+       li      t0, 0x400
+       mfcr    t1, t0
+       li      t2, 6           # XLR thread mode mask
+       nor     t3, t2, zero
+       and     t2, t1, t2      # t2 - current thread mode
+       li      v0, CKSEG1ADDR(RESET_DATA_PHYS)
+       lw      v1, BOOT_THREAD_MODE(v0) # v1 - new thread mode
+       sll     v1, 1
+       beq     v1, t2, 1f      # same as request value
+       nop                     # nothing to do */
+
+       and     t2, t1, t3      # mask out old thread mode
+       or      t1, t2, v1      # put in new value
+       mtcr    t1, t0          # update core control
+
+1:     wait
+       j       1b
+       nop
+END(nlm_rmiboot_preboot)
+       __FINIT
similarity index 93%
rename from arch/mips/netlogic/xlr/time.c
rename to arch/mips/netlogic/common/time.c
index 0d81b262593c2a8f48009999146432c9f386d42f..bd3e498157ff064248face4992c91e845ce20978 100644 (file)
@@ -36,7 +36,7 @@
 
 #include <asm/time.h>
 #include <asm/netlogic/interrupt.h>
-#include <asm/netlogic/psb-bootinfo.h>
+#include <asm/netlogic/common.h>
 
 unsigned int __cpuinit get_c0_compare_int(void)
 {
@@ -45,7 +45,7 @@ unsigned int __cpuinit get_c0_compare_int(void)
 
 void __init plat_time_init(void)
 {
-       mips_hpt_frequency = nlm_prom_info.cpu_frequency;
+       mips_hpt_frequency = nlm_get_cpu_frequency();
        pr_info("MIPS counter frequency [%ld]\n",
-               (unsigned long)mips_hpt_frequency);
+                       (unsigned long)mips_hpt_frequency);
 }
diff --git a/arch/mips/netlogic/xlp/Makefile b/arch/mips/netlogic/xlp/Makefile
new file mode 100644 (file)
index 0000000..b93ed83
--- /dev/null
@@ -0,0 +1,2 @@
+obj-y                          += setup.o platform.o nlm_hal.o
+obj-$(CONFIG_SMP)              += wakeup.o
diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c
new file mode 100644 (file)
index 0000000..9428e71
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <asm/mipsregs.h>
+#include <asm/time.h>
+
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/pic.h>
+#include <asm/netlogic/xlp-hal/sys.h>
+
+/* These addresses are computed by the nlm_hal_init() */
+uint64_t nlm_io_base;
+uint64_t nlm_sys_base;
+uint64_t nlm_pic_base;
+
+/* Main initialization */
+void nlm_hal_init(void)
+{
+       nlm_io_base = CKSEG1ADDR(XLP_DEFAULT_IO_BASE);
+       nlm_sys_base = nlm_get_sys_regbase(0);  /* node 0 */
+       nlm_pic_base = nlm_get_pic_regbase(0);  /* node 0 */
+}
+
+int nlm_irq_to_irt(int irq)
+{
+       if (!PIC_IRQ_IS_IRT(irq))
+               return -1;
+
+       switch (irq) {
+       case PIC_UART_0_IRQ:
+               return PIC_IRT_UART_0_INDEX;
+       case PIC_UART_1_IRQ:
+               return PIC_IRT_UART_1_INDEX;
+       default:
+               return -1;
+       }
+}
+
+int nlm_irt_to_irq(int irt)
+{
+       switch (irt) {
+       case PIC_IRT_UART_0_INDEX:
+               return PIC_UART_0_IRQ;
+       case PIC_IRT_UART_1_INDEX:
+               return PIC_UART_1_IRQ;
+       default:
+               return -1;
+       }
+}
+
+unsigned int nlm_get_core_frequency(int core)
+{
+       unsigned int pll_divf, pll_divr, dfs_div, ext_div;
+       unsigned int rstval, dfsval, denom;
+       uint64_t num;
+
+       rstval = nlm_read_sys_reg(nlm_sys_base, SYS_POWER_ON_RESET_CFG);
+       dfsval = nlm_read_sys_reg(nlm_sys_base, SYS_CORE_DFS_DIV_VALUE);
+       pll_divf = ((rstval >> 10) & 0x7f) + 1;
+       pll_divr = ((rstval >> 8)  & 0x3) + 1;
+       ext_div  = ((rstval >> 30) & 0x3) + 1;
+       dfs_div  = ((dfsval >> (core * 4)) & 0xf) + 1;
+
+       num = 800000000ULL * pll_divf;
+       denom = 3 * pll_divr * ext_div * dfs_div;
+       do_div(num, denom);
+       return (unsigned int)num;
+}
+
+unsigned int nlm_get_cpu_frequency(void)
+{
+       return nlm_get_core_frequency(0);
+}
diff --git a/arch/mips/netlogic/xlp/platform.c b/arch/mips/netlogic/xlp/platform.c
new file mode 100644 (file)
index 0000000..1f5e4cb
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+#include <linux/pci.h>
+#include <linux/serial_reg.h>
+#include <linux/spinlock.h>
+
+#include <asm/time.h>
+#include <asm/addrspace.h>
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/pic.h>
+#include <asm/netlogic/xlp-hal/uart.h>
+
+static unsigned int nlm_xlp_uart_in(struct uart_port *p, int offset)
+{
+        return nlm_read_reg(p->iobase, offset);
+}
+
+static void nlm_xlp_uart_out(struct uart_port *p, int offset, int value)
+{
+       nlm_write_reg(p->iobase, offset, value);
+}
+
+#define PORT(_irq)                                     \
+       {                                               \
+               .irq            = _irq,                 \
+               .regshift       = 2,                    \
+               .iotype         = UPIO_MEM32,           \
+               .flags          = (UPF_SKIP_TEST|UPF_FIXED_TYPE|\
+                                       UPF_BOOT_AUTOCONF),     \
+               .uartclk        = XLP_IO_CLK,           \
+               .type           = PORT_16550A,          \
+               .serial_in      = nlm_xlp_uart_in,      \
+               .serial_out     = nlm_xlp_uart_out,     \
+       }
+
+static struct plat_serial8250_port xlp_uart_data[] = {
+       PORT(PIC_UART_0_IRQ),
+       PORT(PIC_UART_1_IRQ),
+       {},
+};
+
+static struct platform_device uart_device = {
+       .name           = "serial8250",
+       .id             = PLAT8250_DEV_PLATFORM,
+       .dev = {
+               .platform_data = xlp_uart_data,
+       },
+};
+
+static int __init nlm_platform_uart_init(void)
+{
+       unsigned long mmio;
+
+       mmio = (unsigned long)nlm_get_uart_regbase(0, 0);
+       xlp_uart_data[0].iobase = mmio;
+       xlp_uart_data[0].membase = (void __iomem *)mmio;
+       xlp_uart_data[0].mapbase = mmio;
+
+       mmio = (unsigned long)nlm_get_uart_regbase(0, 1);
+       xlp_uart_data[1].iobase = mmio;
+       xlp_uart_data[1].membase = (void __iomem *)mmio;
+       xlp_uart_data[1].mapbase = mmio;
+
+       return platform_device_register(&uart_device);
+}
+
+arch_initcall(nlm_platform_uart_init);
diff --git a/arch/mips/netlogic/xlp/setup.c b/arch/mips/netlogic/xlp/setup.c
new file mode 100644 (file)
index 0000000..acb677a
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/serial_8250.h>
+#include <linux/pm.h>
+
+#include <asm/reboot.h>
+#include <asm/time.h>
+#include <asm/bootinfo.h>
+
+#include <linux/of_fdt.h>
+
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/common.h>
+
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/sys.h>
+
+unsigned long nlm_common_ebase = 0x0;
+
+/* default to uniprocessor */
+uint32_t nlm_coremask = 1, nlm_cpumask  = 1;
+int  nlm_threads_per_core = 1;
+
+static void nlm_linux_exit(void)
+{
+       nlm_write_sys_reg(nlm_sys_base, SYS_CHIP_RESET, 1);
+       for ( ; ; )
+               cpu_wait();
+}
+
+void __init plat_mem_setup(void)
+{
+       panic_timeout   = 5;
+       _machine_restart = (void (*)(char *))nlm_linux_exit;
+       _machine_halt   = nlm_linux_exit;
+       pm_power_off    = nlm_linux_exit;
+}
+
+const char *get_system_type(void)
+{
+       return "Netlogic XLP Series";
+}
+
+void __init prom_free_prom_memory(void)
+{
+       /* Nothing yet */
+}
+
+void xlp_mmu_init(void)
+{
+       write_c0_config6(read_c0_config6() | 0x24);
+       current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1;
+       write_c0_config7(PM_DEFAULT_MASK >>
+               (13 + (ffz(PM_DEFAULT_MASK >> 13) / 2)));
+}
+
+void __init prom_init(void)
+{
+       void *fdtp;
+
+       fdtp = (void *)(long)fw_arg0;
+       xlp_mmu_init();
+       nlm_hal_init();
+       early_init_devtree(fdtp);
+
+       nlm_common_ebase = read_c0_ebase() & (~((1 << 12) - 1));
+#ifdef CONFIG_SMP
+       nlm_wakeup_secondary_cpus(0xffffffff);
+       register_smp_ops(&nlm_smp_ops);
+#endif
+}
diff --git a/arch/mips/netlogic/xlp/wakeup.c b/arch/mips/netlogic/xlp/wakeup.c
new file mode 100644 (file)
index 0000000..44d923f
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
+ * reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/threads.h>
+
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/string.h>
+
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/common.h>
+#include <asm/netlogic/mips-extns.h>
+
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/pic.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/sys.h>
+
+static void xlp_enable_secondary_cores(void)
+{
+       uint32_t core, value, coremask, syscoremask;
+       int count;
+
+       /* read cores in reset from SYS block */
+       syscoremask = nlm_read_sys_reg(nlm_sys_base, SYS_CPU_RESET);
+
+       /* update user specified */
+       nlm_coremask = nlm_coremask & (syscoremask | 1);
+
+       for (core = 1; core < 8; core++) {
+               coremask = 1 << core;
+               if ((nlm_coremask & coremask) == 0)
+                       continue;
+
+               /* Enable CPU clock */
+               value = nlm_read_sys_reg(nlm_sys_base, SYS_CORE_DFS_DIS_CTRL);
+               value &= ~coremask;
+               nlm_write_sys_reg(nlm_sys_base, SYS_CORE_DFS_DIS_CTRL, value);
+
+               /* Remove CPU Reset */
+               value = nlm_read_sys_reg(nlm_sys_base, SYS_CPU_RESET);
+               value &= ~coremask;
+               nlm_write_sys_reg(nlm_sys_base, SYS_CPU_RESET, value);
+
+               /* Poll for CPU to mark itself coherent */
+               count = 100000;
+               do {
+                       value = nlm_read_sys_reg(nlm_sys_base,
+                           SYS_CPU_NONCOHERENT_MODE);
+               } while ((value & coremask) != 0 && count-- > 0);
+
+               if (count == 0)
+                       pr_err("Failed to enable core %d\n", core);
+       }
+}
+
+void xlp_wakeup_secondary_cpus(void)
+{
+       /*
+        * In case of u-boot, the secondaries are in reset
+        * first wakeup core 0 threads
+        */
+       xlp_boot_core0_siblings();
+
+       /* now get other cores out of reset */
+       xlp_enable_secondary_cores();
+}
index 2dca585dd2f7eb71c002dc0942b1e44cec7af173..f01e4d7a060031e57de49439e3967067c71d4546 100644 (file)
@@ -1,5 +1,2 @@
-obj-y                          += setup.o platform.o irq.o setup.o time.o
-obj-$(CONFIG_SMP)              += smp.o smpboot.o
-obj-$(CONFIG_EARLY_PRINTK)     += xlr_console.o
-
-ccflags-y                      += -Werror
+obj-y                          += setup.o platform.o
+obj-$(CONFIG_SMP)              += wakeup.o
diff --git a/arch/mips/netlogic/xlr/irq.c b/arch/mips/netlogic/xlr/irq.c
deleted file mode 100644 (file)
index 521bb73..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
- * reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the NetLogic
- * license below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/linkage.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-
-#include <asm/mipsregs.h>
-
-#include <asm/netlogic/xlr/iomap.h>
-#include <asm/netlogic/xlr/pic.h>
-#include <asm/netlogic/xlr/xlr.h>
-
-#include <asm/netlogic/interrupt.h>
-#include <asm/netlogic/mips-extns.h>
-
-static u64 nlm_irq_mask;
-static DEFINE_SPINLOCK(nlm_pic_lock);
-
-static void xlr_pic_enable(struct irq_data *d)
-{
-       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
-       unsigned long flags;
-       nlm_reg_t reg;
-       int irq = d->irq;
-
-       WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq);
-
-       spin_lock_irqsave(&nlm_pic_lock, flags);
-       reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE);
-       netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE,
-                         reg | (1 << 6) | (1 << 30) | (1 << 31));
-       spin_unlock_irqrestore(&nlm_pic_lock, flags);
-}
-
-static void xlr_pic_mask(struct irq_data *d)
-{
-       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
-       unsigned long flags;
-       nlm_reg_t reg;
-       int irq = d->irq;
-
-       WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq);
-
-       spin_lock_irqsave(&nlm_pic_lock, flags);
-       reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE);
-       netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE,
-                         reg | (1 << 6) | (1 << 30) | (0 << 31));
-       spin_unlock_irqrestore(&nlm_pic_lock, flags);
-}
-
-#ifdef CONFIG_PCI
-/* Extra ACK needed for XLR on chip PCI controller */
-static void xlr_pci_ack(struct irq_data *d)
-{
-       nlm_reg_t *pci_mmio = netlogic_io_mmio(NETLOGIC_IO_PCIX_OFFSET);
-
-       netlogic_read_reg(pci_mmio, (0x140 >> 2));
-}
-
-/* Extra ACK needed for XLS on chip PCIe controller */
-static void xls_pcie_ack(struct irq_data *d)
-{
-       nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET);
-
-       switch (d->irq) {
-       case PIC_PCIE_LINK0_IRQ:
-               netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff);
-               break;
-       case PIC_PCIE_LINK1_IRQ:
-               netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff);
-               break;
-       case PIC_PCIE_LINK2_IRQ:
-               netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff);
-               break;
-       case PIC_PCIE_LINK3_IRQ:
-               netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff);
-               break;
-       }
-}
-
-/* For XLS B silicon, the 3,4 PCI interrupts are different */
-static void xls_pcie_ack_b(struct irq_data *d)
-{
-       nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET);
-
-       switch (d->irq) {
-       case PIC_PCIE_LINK0_IRQ:
-               netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff);
-               break;
-       case PIC_PCIE_LINK1_IRQ:
-               netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff);
-               break;
-       case PIC_PCIE_XLSB0_LINK2_IRQ:
-               netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff);
-               break;
-       case PIC_PCIE_XLSB0_LINK3_IRQ:
-               netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff);
-               break;
-       }
-}
-#endif
-
-static void xlr_pic_ack(struct irq_data *d)
-{
-       unsigned long flags;
-       nlm_reg_t *mmio;
-       int irq = d->irq;
-       void *hd = irq_data_get_irq_handler_data(d);
-
-       WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq);
-
-       if (hd) {
-               void (*extra_ack)(void *) = hd;
-               extra_ack(d);
-       }
-       mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
-       spin_lock_irqsave(&nlm_pic_lock, flags);
-       netlogic_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE)));
-       spin_unlock_irqrestore(&nlm_pic_lock, flags);
-}
-
-/*
- * This chip definition handles interrupts routed thru the XLR
- * hardware PIC, currently IRQs 8-39 are mapped to hardware intr
- * 0-31 wired the XLR PIC
- */
-static struct irq_chip xlr_pic = {
-       .name           = "XLR-PIC",
-       .irq_enable     = xlr_pic_enable,
-       .irq_mask       = xlr_pic_mask,
-       .irq_ack        = xlr_pic_ack,
-};
-
-static void rsvd_irq_handler(struct irq_data *d)
-{
-       WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq);
-}
-
-/*
- * Chip definition for CPU originated interrupts(timer, msg) and
- * IPIs
- */
-struct irq_chip nlm_cpu_intr = {
-       .name           = "XLR-CPU-INTR",
-       .irq_enable     = rsvd_irq_handler,
-       .irq_mask       = rsvd_irq_handler,
-       .irq_ack        = rsvd_irq_handler,
-};
-
-void __init init_xlr_irqs(void)
-{
-       nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
-       uint32_t thread_mask = 1;
-       int level, i;
-
-       pr_info("Interrupt thread mask [%x]\n", thread_mask);
-       for (i = 0; i < PIC_NUM_IRTS; i++) {
-               level = PIC_IRQ_IS_EDGE_TRIGGERED(i);
-
-               /* Bind all PIC irqs to boot cpu */
-               netlogic_write_reg(mmio, PIC_IRT_0_BASE + i, thread_mask);
-
-               /*
-                * Use local scheduling and high polarity for all IRTs
-                * Invalidate all IRTs, by default
-                */
-               netlogic_write_reg(mmio, PIC_IRT_1_BASE + i,
-                               (level << 30) | (1 << 6) | (PIC_IRQ_BASE + i));
-       }
-
-       /* Make all IRQs as level triggered by default */
-       for (i = 0; i < NR_IRQS; i++) {
-               if (PIC_IRQ_IS_IRT(i))
-                       irq_set_chip_and_handler(i, &xlr_pic, handle_level_irq);
-               else
-                       irq_set_chip_and_handler(i, &nlm_cpu_intr,
-                                               handle_percpu_irq);
-       }
-#ifdef CONFIG_SMP
-       irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr,
-                        nlm_smp_function_ipi_handler);
-       irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr,
-                        nlm_smp_resched_ipi_handler);
-       nlm_irq_mask |=
-           ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE));
-#endif
-
-#ifdef CONFIG_PCI
-       /*
-        * For PCI interrupts, we need to ack the PIC controller too, overload
-        * irq handler data to do this
-        */
-       if (nlm_chip_is_xls()) {
-               if (nlm_chip_is_xls_b()) {
-                       irq_set_handler_data(PIC_PCIE_LINK0_IRQ,
-                                                       xls_pcie_ack_b);
-                       irq_set_handler_data(PIC_PCIE_LINK1_IRQ,
-                                                       xls_pcie_ack_b);
-                       irq_set_handler_data(PIC_PCIE_XLSB0_LINK2_IRQ,
-                                                       xls_pcie_ack_b);
-                       irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ,
-                                                       xls_pcie_ack_b);
-               } else {
-                       irq_set_handler_data(PIC_PCIE_LINK0_IRQ, xls_pcie_ack);
-                       irq_set_handler_data(PIC_PCIE_LINK1_IRQ, xls_pcie_ack);
-                       irq_set_handler_data(PIC_PCIE_LINK2_IRQ, xls_pcie_ack);
-                       irq_set_handler_data(PIC_PCIE_LINK3_IRQ, xls_pcie_ack);
-               }
-       } else {
-               /* XLR PCI controller ACK */
-               irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack);
-       }
-#endif
-       /* unmask all PIC related interrupts. If no handler is installed by the
-        * drivers, it'll just ack the interrupt and return
-        */
-       for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++)
-               nlm_irq_mask |= (1ULL << i);
-
-       nlm_irq_mask |= (1ULL << IRQ_TIMER);
-}
-
-void __init arch_init_irq(void)
-{
-       /* Initialize the irq descriptors */
-       init_xlr_irqs();
-       write_c0_eimr(nlm_irq_mask);
-}
-
-void __cpuinit nlm_smp_irq_init(void)
-{
-       /* set interrupt mask for non-zero cpus */
-       write_c0_eimr(nlm_irq_mask);
-}
-
-asmlinkage void plat_irq_dispatch(void)
-{
-       uint64_t eirr;
-       int i;
-
-       eirr = read_c0_eirr() & read_c0_eimr();
-       if (!eirr)
-               return;
-
-       /* no need of EIRR here, writing compare clears interrupt */
-       if (eirr & (1 << IRQ_TIMER)) {
-               do_IRQ(IRQ_TIMER);
-               return;
-       }
-
-       /* use dcltz: optimize below code */
-       for (i = 63; i != -1; i--) {
-               if (eirr & (1ULL << i))
-                       break;
-       }
-       if (i == -1) {
-               pr_err("no interrupt !!\n");
-               return;
-       }
-
-       /* Ack eirr */
-       write_c0_eirr(1ULL << i);
-
-       do_IRQ(i);
-}
index 609ec2534642817ce6d59fae43ae35cc6c381f11..eab64b45dffdb197510ee23683667365cbf81d9c 100644 (file)
 #include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
 
+#include <asm/netlogic/haldefs.h>
 #include <asm/netlogic/xlr/iomap.h>
 #include <asm/netlogic/xlr/pic.h>
 #include <asm/netlogic/xlr/xlr.h>
 
 unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset)
 {
-       nlm_reg_t *mmio;
+       uint64_t uartbase;
        unsigned int value;
 
-       /* XLR uart does not need any mapping of regs */
-       mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift));
-       value = netlogic_read_reg(mmio, 0);
+       /* sign extend to 64 bits, if needed */
+       uartbase = (uint64_t)(long)p->membase;
+       value = nlm_read_reg(uartbase, offset);
 
        /* See XLR/XLS errata */
        if (offset == UART_MSR)
@@ -39,10 +40,10 @@ unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset)
 
 void nlm_xlr_uart_out(struct uart_port *p, int offset, int value)
 {
-       nlm_reg_t *mmio;
+       uint64_t uartbase;
 
-       /* XLR uart does not need any mapping of regs */
-       mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift));
+       /* sign extend to 64 bits, if needed */
+       uartbase = (uint64_t)(long)p->membase;
 
        /* See XLR/XLS errata */
        if (offset == UART_MSR)
@@ -50,7 +51,7 @@ void nlm_xlr_uart_out(struct uart_port *p, int offset, int value)
        else if (offset == UART_MCR)
                value ^= 0x3;
 
-       netlogic_write_reg(mmio, 0, value);
+       nlm_write_reg(uartbase, offset, value);
 }
 
 #define PORT(_irq)                                     \
@@ -82,15 +83,15 @@ static struct platform_device uart_device = {
 
 static int __init nlm_uart_init(void)
 {
-       nlm_reg_t *mmio;
+       unsigned long uartbase;
 
-       mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET);
-       xlr_uart_data[0].membase = (void __iomem *)mmio;
-       xlr_uart_data[0].mapbase = CPHYSADDR((unsigned long)mmio);
+       uartbase = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET);
+       xlr_uart_data[0].membase = (void __iomem *)uartbase;
+       xlr_uart_data[0].mapbase = CPHYSADDR(uartbase);
 
-       mmio = netlogic_io_mmio(NETLOGIC_IO_UART_1_OFFSET);
-       xlr_uart_data[1].membase = (void __iomem *)mmio;
-       xlr_uart_data[1].mapbase = CPHYSADDR((unsigned long)mmio);
+       uartbase = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_1_OFFSET);
+       xlr_uart_data[1].membase = (void __iomem *)uartbase;
+       xlr_uart_data[1].mapbase = CPHYSADDR(uartbase);
 
        return platform_device_register(&uart_device);
 }
index cee25ddd0887470ebe167b5e0cb6a91d2e5d3a1e..c9d066dedc4ec4f79601bd3a7cd1a60be4316f5b 100644 (file)
 #include <asm/reboot.h>
 #include <asm/time.h>
 #include <asm/bootinfo.h>
-#include <asm/smp-ops.h>
 
 #include <asm/netlogic/interrupt.h>
 #include <asm/netlogic/psb-bootinfo.h>
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/common.h>
 
 #include <asm/netlogic/xlr/xlr.h>
 #include <asm/netlogic/xlr/iomap.h>
 #include <asm/netlogic/xlr/pic.h>
 #include <asm/netlogic/xlr/gpio.h>
 
-unsigned long netlogic_io_base = (unsigned long)(DEFAULT_NETLOGIC_IO_BASE);
-unsigned long nlm_common_ebase = 0x0;
+uint64_t nlm_io_base = DEFAULT_NETLOGIC_IO_BASE;
+uint64_t nlm_pic_base;
 struct psb_info nlm_prom_info;
 
+unsigned long nlm_common_ebase = 0x0;
+
+/* default to uniprocessor */
+uint32_t nlm_coremask = 1, nlm_cpumask  = 1;
+int  nlm_threads_per_core = 1;
+
 static void __init nlm_early_serial_setup(void)
 {
        struct uart_port s;
-       nlm_reg_t *uart_base;
+       unsigned long uart_base;
 
-       uart_base = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET);
+       uart_base = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET);
        memset(&s, 0, sizeof(s));
        s.flags         = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
        s.iotype        = UPIO_MEM32;
@@ -67,18 +74,18 @@ static void __init nlm_early_serial_setup(void)
        s.uartclk       = PIC_CLKS_PER_SEC;
        s.serial_in     = nlm_xlr_uart_in;
        s.serial_out    = nlm_xlr_uart_out;
-       s.mapbase       = (unsigned long)uart_base;
+       s.mapbase       = uart_base;
        s.membase       = (unsigned char __iomem *)uart_base;
        early_serial_setup(&s);
 }
 
 static void nlm_linux_exit(void)
 {
-       nlm_reg_t *mmio;
+       uint64_t gpiobase;
 
-       mmio = netlogic_io_mmio(NETLOGIC_IO_GPIO_OFFSET);
+       gpiobase = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET);
        /* trigger a chip reset by writing 1 to GPIO_SWRESET_REG */
-       netlogic_write_reg(mmio, NETLOGIC_GPIO_SWRESET_REG, 1);
+       nlm_write_reg(gpiobase, NETLOGIC_GPIO_SWRESET_REG, 1);
        for ( ; ; )
                cpu_wait();
 }
@@ -96,6 +103,11 @@ const char *get_system_type(void)
        return "Netlogic XLR/XLS Series";
 }
 
+unsigned int nlm_get_cpu_frequency(void)
+{
+       return (unsigned int)nlm_prom_info.cpu_frequency;
+}
+
 void __init prom_free_prom_memory(void)
 {
        /* Nothing yet */
@@ -175,6 +187,7 @@ void __init prom_init(void)
        prom_infop = (struct psb_info *)(long)(int)fw_arg3;
 
        nlm_prom_info = *prom_infop;
+       nlm_pic_base = nlm_mmio_base(NETLOGIC_IO_PIC_OFFSET);
 
        nlm_early_serial_setup();
        build_arcs_cmdline(argv);
similarity index 60%
rename from arch/mips/netlogic/xlr/smpboot.S
rename to arch/mips/netlogic/xlr/wakeup.c
index 8cb7889ce0cca112bef5b2d9ea06ece68aae0689..db5d987d488182cc9964e244e8a4ef1a645aed6a 100644 (file)
  */
 
 #include <linux/init.h>
+#include <linux/threads.h>
 
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
-#include <asm/regdef.h>
 #include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/string.h>
 
-/*
- * Early code for secondary CPUs. This will get them out of the bootloader
- * code and into linux. Needed because the bootloader area will be taken
- * and initialized by linux.
- */
-       __CPUINIT
-NESTED(prom_pre_boot_secondary_cpus, 16, sp)
-       .set    mips64
-       mfc0    t0, $15, 1      # read ebase
-       andi    t0, 0x1f        # t0 has the processor_id()
-       sll     t0, 2           # offset in cpu array
-
-       PTR_LA  t1, nlm_cpu_ready # mark CPU ready
-       PTR_ADDU t1, t0
-       li      t2, 1
-       sw      t2, 0(t1)
-
-       PTR_LA  t1, nlm_cpu_unblock
-       PTR_ADDU t1, t0
-1:     lw      t2, 0(t1)       # wait till unblocked
-       beqz    t2, 1b
-       nop
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/common.h>
+#include <asm/netlogic/mips-extns.h>
 
-       PTR_LA  t1, nlm_next_sp
-       PTR_L   sp, 0(t1)
-       PTR_LA  t1, nlm_next_gp
-       PTR_L   gp, 0(t1)
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/pic.h>
 
-       PTR_LA  t0, nlm_early_init_secondary
-       jalr    t0
-       nop
-
-       PTR_LA  t0, smp_bootstrap
-       jr      t0
-       nop
-END(prom_pre_boot_secondary_cpus)
-       __FINIT
-
-/*
- * NMI code, used for CPU wakeup, copied to reset entry
- */
-NESTED(nlm_boot_smp_nmi, 0, sp)
-       .set push
-       .set noat
-       .set mips64
-       .set noreorder
+int __cpuinit xlr_wakeup_secondary_cpus(void)
+{
+       unsigned int i, boot_cpu;
 
-       /* Clear the  NMI and BEV bits */
-       MFC0    k0, CP0_STATUS
-       li      k1, 0xffb7ffff
-       and     k0, k0, k1
-       MTC0    k0, CP0_STATUS
+       /*
+        *  In case of RMI boot, hit with NMI to get the cores
+        *  from bootloader to linux code.
+        */
+       boot_cpu = hard_smp_processor_id();
+       nlm_set_nmi_handler(nlm_rmiboot_preboot);
+       for (i = 0; i < NR_CPUS; i++) {
+               if (i == boot_cpu || (nlm_cpumask & (1u << i)) == 0)
+                       continue;
+               nlm_pic_send_ipi(nlm_pic_base, i, 1, 1); /* send NMI */
+       }
 
-       PTR_LA  k1, secondary_entry_point
-       PTR_L   k0, 0(k1)
-       jr      k0
-       nop
-       .set pop
-END(nlm_boot_smp_nmi)
+       return 0;
+}
index bb82cbdbc62a8329a887dd275d56043a2f043b1e..c3ac4b086eb203738d2c2bfdbd32b61171ded9ab 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_BCM47XX)         += pci-bcm47xx.o
 obj-$(CONFIG_BCM63XX)          += pci-bcm63xx.o fixup-bcm63xx.o \
                                        ops-bcm63xx.o
 obj-$(CONFIG_MIPS_ALCHEMY)     += pci-alchemy.o
+obj-$(CONFIG_SOC_AR724X)       += pci-ath724x.o
 
 #
 # These are still pretty much in the old state, watch, go blind.
@@ -55,7 +56,7 @@ obj-$(CONFIG_ZAO_CAPCELLA)    += fixup-capcella.o
 obj-$(CONFIG_WR_PPMC)          += fixup-wrppmc.o
 obj-$(CONFIG_MIKROTIK_RB532)   += pci-rc32434.o ops-rc32434.o fixup-rc32434.o
 obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += pci-octeon.o pcie-octeon.o
-obj-$(CONFIG_NLM_XLR)          += pci-xlr.o
+obj-$(CONFIG_CPU_XLR)          += pci-xlr.o
 
 ifdef CONFIG_PCI_MSI
 obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += msi-octeon.o
index 5d530f89d87223e86965eb0b013923a461263d32..d37be36dc659b4df1f3b22787f84c6908bc5eb45 100644 (file)
@@ -162,7 +162,7 @@ msi_irq_allocated:
                msg.address_hi = (0 + CVMX_NPEI_PCIE_MSI_RCV) >> 32;
                break;
        default:
-               panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type\n");
+               panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type");
        }
        msg.data = irq - OCTEON_IRQ_MSI_BIT0;
 
index 8fbfbf2b931c66134491b48c57beb8a1481a05a2..389bf669d56e7d4a9cf4b4c04c537537bc0b3cc0 100644 (file)
@@ -405,7 +405,7 @@ int msp_pcibios_config_access(unsigned char access_type,
        if (pciirqflag == 0) {
                ret = request_irq(MSP_INT_PCI,/* Hardcoded internal MSP7120 wiring */
                                bpci_interrupt,
-                               IRQF_SHARED | IRQF_DISABLED,
+                               IRQF_SHARED,
                                "PMC MSP PCI Host",
                                preg);
                if (ret != 0)
index 6a3bdb5ffa8074e5ba3e978d6989115857e17e5b..02d64f77e967468d9117b1d7cd26b48cca4af313 100644 (file)
@@ -225,7 +225,7 @@ void __init tx3927_setup_pcierr_irq(void)
 {
        if (request_irq(TXX9_IRQ_BASE + TX3927_IR_PCI,
                        tx3927_pcierr_interrupt,
-                       IRQF_DISABLED, "PCI error",
+                       0, "PCI error",
                        (void *)TX3927_PCIC_REG))
                printk(KERN_WARNING "Failed to request irq for PCIERR\n");
 }
index b5ce041cdafb54667b7c11738892ab7e9020000a..ec125bed721c5f616fb45493cf827d465ca2ced1 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/syscore_ops.h>
 #include <linux/vmalloc.h>
 
 #include <asm/mach-au1x00/au1000.h>
+#include <asm/tlbmisc.h>
 
 #ifdef CONFIG_DEBUG_PCI
 #define DBG(x...) printk(KERN_DEBUG x)
@@ -41,6 +43,12 @@ struct alchemy_pci_context {
        int (*board_pci_idsel)(unsigned int devsel, int assert);
 };
 
+/* for syscore_ops. There's only one PCI controller on Alchemy chips, so this
+ * should suffice for now.
+ */
+static struct alchemy_pci_context *__alchemy_pci_ctx;
+
+
 /* IO/MEM resources for PCI. Keep the memres in sync with __fixup_bigphys_addr
  * in arch/mips/alchemy/common/setup.c
  */
@@ -99,18 +107,6 @@ static int config_access(unsigned char access_type, struct pci_bus *bus,
                return -1;
        }
 
-       /* YAMON on all db1xxx boards wipes the TLB and writes zero to C0_wired
-        * on resume, clearing our wired entry.  Unfortunately the ->resume()
-        * callback is called way way way too late (and ->suspend() too early)
-        * to have them destroy and recreate it.  Instead just test if c0_wired
-        * is now lower than the index we retrieved before suspending and then
-        * recreate the entry if necessary.  Of course this is totally bonkers
-        * and breaks as soon as someone else adds another wired entry somewhere
-        * else.  Anyone have any ideas how to handle this better?
-        */
-       if (unlikely(read_c0_wired() < ctx->wired_entry))
-               alchemy_pci_wired_entry(ctx);
-
        local_irq_save(flags);
        r = __raw_readl(ctx->regs + PCI_REG_STATCMD) & 0x0000ffff;
        r |= PCI_STATCMD_STATUS(0x2000);
@@ -304,6 +300,62 @@ static int alchemy_pci_def_idsel(unsigned int devsel, int assert)
        return 1;       /* success */
 }
 
+/* save PCI controller register contents. */
+static int alchemy_pci_suspend(void)
+{
+       struct alchemy_pci_context *ctx = __alchemy_pci_ctx;
+       if (!ctx)
+               return 0;
+
+       ctx->pm[0]  = __raw_readl(ctx->regs + PCI_REG_CMEM);
+       ctx->pm[1]  = __raw_readl(ctx->regs + PCI_REG_CONFIG) & 0x0009ffff;
+       ctx->pm[2]  = __raw_readl(ctx->regs + PCI_REG_B2BMASK_CCH);
+       ctx->pm[3]  = __raw_readl(ctx->regs + PCI_REG_B2BBASE0_VID);
+       ctx->pm[4]  = __raw_readl(ctx->regs + PCI_REG_B2BBASE1_SID);
+       ctx->pm[5]  = __raw_readl(ctx->regs + PCI_REG_MWMASK_DEV);
+       ctx->pm[6]  = __raw_readl(ctx->regs + PCI_REG_MWBASE_REV_CCL);
+       ctx->pm[7]  = __raw_readl(ctx->regs + PCI_REG_ID);
+       ctx->pm[8]  = __raw_readl(ctx->regs + PCI_REG_CLASSREV);
+       ctx->pm[9]  = __raw_readl(ctx->regs + PCI_REG_PARAM);
+       ctx->pm[10] = __raw_readl(ctx->regs + PCI_REG_MBAR);
+       ctx->pm[11] = __raw_readl(ctx->regs + PCI_REG_TIMEOUT);
+
+       return 0;
+}
+
+static void alchemy_pci_resume(void)
+{
+       struct alchemy_pci_context *ctx = __alchemy_pci_ctx;
+       if (!ctx)
+               return;
+
+       __raw_writel(ctx->pm[0],  ctx->regs + PCI_REG_CMEM);
+       __raw_writel(ctx->pm[2],  ctx->regs + PCI_REG_B2BMASK_CCH);
+       __raw_writel(ctx->pm[3],  ctx->regs + PCI_REG_B2BBASE0_VID);
+       __raw_writel(ctx->pm[4],  ctx->regs + PCI_REG_B2BBASE1_SID);
+       __raw_writel(ctx->pm[5],  ctx->regs + PCI_REG_MWMASK_DEV);
+       __raw_writel(ctx->pm[6],  ctx->regs + PCI_REG_MWBASE_REV_CCL);
+       __raw_writel(ctx->pm[7],  ctx->regs + PCI_REG_ID);
+       __raw_writel(ctx->pm[8],  ctx->regs + PCI_REG_CLASSREV);
+       __raw_writel(ctx->pm[9],  ctx->regs + PCI_REG_PARAM);
+       __raw_writel(ctx->pm[10], ctx->regs + PCI_REG_MBAR);
+       __raw_writel(ctx->pm[11], ctx->regs + PCI_REG_TIMEOUT);
+       wmb();
+       __raw_writel(ctx->pm[1],  ctx->regs + PCI_REG_CONFIG);
+       wmb();
+
+       /* YAMON on all db1xxx boards wipes the TLB and writes zero to C0_wired
+        * on resume, making it necessary to recreate it as soon as possible.
+        */
+       ctx->wired_entry = 8191;        /* impossibly high value */
+       alchemy_pci_wired_entry(ctx);   /* install it */
+}
+
+static struct syscore_ops alchemy_pci_pmops = {
+       .suspend        = alchemy_pci_suspend,
+       .resume         = alchemy_pci_resume,
+};
+
 static int __devinit alchemy_pci_probe(struct platform_device *pdev)
 {
        struct alchemy_pci_platdata *pd = pdev->dev.platform_data;
@@ -396,7 +448,8 @@ static int __devinit alchemy_pci_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto out4;
        }
-       ctx->wired_entry = 8192;        /* impossibly high value */
+       ctx->wired_entry = 8191;        /* impossibly high value */
+       alchemy_pci_wired_entry(ctx);   /* install it */
 
        set_io_port_base((unsigned long)ctx->alchemy_pci_ctrl.io_map_base);
 
@@ -408,7 +461,9 @@ static int __devinit alchemy_pci_probe(struct platform_device *pdev)
        __raw_writel(val, ctx->regs + PCI_REG_CONFIG);
        wmb();
 
+       __alchemy_pci_ctx = ctx;
        platform_set_drvdata(pdev, ctx);
+       register_syscore_ops(&alchemy_pci_pmops);
        register_pci_controller(&ctx->alchemy_pci_ctrl);
 
        return 0;
@@ -425,68 +480,11 @@ out:
        return ret;
 }
 
-
-#ifdef CONFIG_PM
-/* save PCI controller register contents. */
-static int alchemy_pci_suspend(struct device *dev)
-{
-       struct alchemy_pci_context *ctx = dev_get_drvdata(dev);
-
-       ctx->pm[0]  = __raw_readl(ctx->regs + PCI_REG_CMEM);
-       ctx->pm[1]  = __raw_readl(ctx->regs + PCI_REG_CONFIG) & 0x0009ffff;
-       ctx->pm[2]  = __raw_readl(ctx->regs + PCI_REG_B2BMASK_CCH);
-       ctx->pm[3]  = __raw_readl(ctx->regs + PCI_REG_B2BBASE0_VID);
-       ctx->pm[4]  = __raw_readl(ctx->regs + PCI_REG_B2BBASE1_SID);
-       ctx->pm[5]  = __raw_readl(ctx->regs + PCI_REG_MWMASK_DEV);
-       ctx->pm[6]  = __raw_readl(ctx->regs + PCI_REG_MWBASE_REV_CCL);
-       ctx->pm[7]  = __raw_readl(ctx->regs + PCI_REG_ID);
-       ctx->pm[8]  = __raw_readl(ctx->regs + PCI_REG_CLASSREV);
-       ctx->pm[9]  = __raw_readl(ctx->regs + PCI_REG_PARAM);
-       ctx->pm[10] = __raw_readl(ctx->regs + PCI_REG_MBAR);
-       ctx->pm[11] = __raw_readl(ctx->regs + PCI_REG_TIMEOUT);
-
-       return 0;
-}
-
-static int alchemy_pci_resume(struct device *dev)
-{
-       struct alchemy_pci_context *ctx = dev_get_drvdata(dev);
-
-       __raw_writel(ctx->pm[0],  ctx->regs + PCI_REG_CMEM);
-       __raw_writel(ctx->pm[2],  ctx->regs + PCI_REG_B2BMASK_CCH);
-       __raw_writel(ctx->pm[3],  ctx->regs + PCI_REG_B2BBASE0_VID);
-       __raw_writel(ctx->pm[4],  ctx->regs + PCI_REG_B2BBASE1_SID);
-       __raw_writel(ctx->pm[5],  ctx->regs + PCI_REG_MWMASK_DEV);
-       __raw_writel(ctx->pm[6],  ctx->regs + PCI_REG_MWBASE_REV_CCL);
-       __raw_writel(ctx->pm[7],  ctx->regs + PCI_REG_ID);
-       __raw_writel(ctx->pm[8],  ctx->regs + PCI_REG_CLASSREV);
-       __raw_writel(ctx->pm[9],  ctx->regs + PCI_REG_PARAM);
-       __raw_writel(ctx->pm[10], ctx->regs + PCI_REG_MBAR);
-       __raw_writel(ctx->pm[11], ctx->regs + PCI_REG_TIMEOUT);
-       wmb();
-       __raw_writel(ctx->pm[1],  ctx->regs + PCI_REG_CONFIG);
-       wmb();
-
-       return 0;
-}
-
-static const struct dev_pm_ops alchemy_pci_pmops = {
-       .suspend        = alchemy_pci_suspend,
-       .resume         = alchemy_pci_resume,
-};
-
-#define ALCHEMY_PCICTL_PM      (&alchemy_pci_pmops)
-
-#else
-#define ALCHEMY_PCICTL_PM      NULL
-#endif
-
 static struct platform_driver alchemy_pcictl_driver = {
        .probe          = alchemy_pci_probe,
        .driver = {
                .name   = "alchemy-pci",
                .owner  = THIS_MODULE,
-               .pm     = ALCHEMY_PCICTL_PM,
        },
 };
 
diff --git a/arch/mips/pci/pci-ath724x.c b/arch/mips/pci/pci-ath724x.c
new file mode 100644 (file)
index 0000000..a4dd24a
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *  Atheros 724x PCI support
+ *
+ *  Copyright (C) 2011 René Bolldorf <xsecute@googlemail.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/pci.h>
+#include <asm/mach-ath79/pci-ath724x.h>
+
+#define reg_read(_phys)                (*(unsigned int *) KSEG1ADDR(_phys))
+#define reg_write(_phys, _val) ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val))
+
+#define ATH724X_PCI_DEV_BASE   0x14000000
+#define ATH724X_PCI_MEM_BASE   0x10000000
+#define ATH724X_PCI_MEM_SIZE   0x08000000
+
+static DEFINE_SPINLOCK(ath724x_pci_lock);
+static struct ath724x_pci_data *pci_data;
+static int pci_data_size;
+
+static int ath724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
+                           int size, uint32_t *value)
+{
+       unsigned long flags, addr, tval, mask;
+
+       if (devfn)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       if (where & (size - 1))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       spin_lock_irqsave(&ath724x_pci_lock, flags);
+
+       switch (size) {
+       case 1:
+               addr = where & ~3;
+               mask = 0xff000000 >> ((where % 4) * 8);
+               tval = reg_read(ATH724X_PCI_DEV_BASE + addr);
+               tval = tval & ~mask;
+               *value = (tval >> ((4 - (where % 4))*8));
+               break;
+       case 2:
+               addr = where & ~3;
+               mask = 0xffff0000 >> ((where % 4)*8);
+               tval = reg_read(ATH724X_PCI_DEV_BASE + addr);
+               tval = tval & ~mask;
+               *value = (tval >> ((4 - (where % 4))*8));
+               break;
+       case 4:
+               *value = reg_read(ATH724X_PCI_DEV_BASE + where);
+               break;
+       default:
+               spin_unlock_irqrestore(&ath724x_pci_lock, flags);
+
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
+
+       spin_unlock_irqrestore(&ath724x_pci_lock, flags);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int ath724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
+                            int size, uint32_t value)
+{
+       unsigned long flags, tval, addr, mask;
+
+       if (devfn)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       if (where & (size - 1))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       spin_lock_irqsave(&ath724x_pci_lock, flags);
+
+       switch (size) {
+       case 1:
+               addr = (ATH724X_PCI_DEV_BASE + where) & ~3;
+               mask = 0xff000000 >> ((where % 4)*8);
+               tval = reg_read(addr);
+               tval = tval & ~mask;
+               tval |= (value << ((4 - (where % 4))*8)) & mask;
+               reg_write(addr, tval);
+               break;
+       case 2:
+               addr = (ATH724X_PCI_DEV_BASE + where) & ~3;
+               mask = 0xffff0000 >> ((where % 4)*8);
+               tval = reg_read(addr);
+               tval = tval & ~mask;
+               tval |= (value << ((4 - (where % 4))*8)) & mask;
+               reg_write(addr, tval);
+               break;
+       case 4:
+               reg_write((ATH724X_PCI_DEV_BASE + where), value);
+               break;
+       default:
+               spin_unlock_irqrestore(&ath724x_pci_lock, flags);
+
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
+
+       spin_unlock_irqrestore(&ath724x_pci_lock, flags);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops ath724x_pci_ops = {
+       .read   = ath724x_pci_read,
+       .write  = ath724x_pci_write,
+};
+
+static struct resource ath724x_io_resource = {
+       .name   = "PCI IO space",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_IO,
+};
+
+static struct resource ath724x_mem_resource = {
+       .name   = "PCI memory space",
+       .start  = ATH724X_PCI_MEM_BASE,
+       .end    = ATH724X_PCI_MEM_BASE + ATH724X_PCI_MEM_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct pci_controller ath724x_pci_controller = {
+       .pci_ops        = &ath724x_pci_ops,
+       .io_resource    = &ath724x_io_resource,
+       .mem_resource   = &ath724x_mem_resource,
+};
+
+void ath724x_pci_add_data(struct ath724x_pci_data *data, int size)
+{
+       pci_data        = data;
+       pci_data_size   = size;
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin)
+{
+       unsigned int devfn = dev->devfn;
+       int irq = -1;
+
+       if (devfn > pci_data_size - 1)
+               return irq;
+
+       irq = pci_data[devfn].irq;
+
+       return irq;
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       unsigned int devfn = dev->devfn;
+
+       if (devfn > pci_data_size - 1)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       dev->dev.platform_data = pci_data[devfn].pdata;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int __init ath724x_pcibios_init(void)
+{
+       register_pci_controller(&ath724x_pci_controller);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+arch_initcall(ath724x_pcibios_init);
index 82e0fde1dba045865351bfca891248f57ecb9106..39eb7c417e2fadf4b1d3999f9b2af9c91934de84 100644 (file)
@@ -99,7 +99,7 @@ static int __init bcm63xx_pci_init(void)
        unsigned int mem_size;
        u32 val;
 
-       if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358())
+       if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358() && !BCMCPU_IS_6368())
                return -ENODEV;
 
        if (!bcm63xx_pci_enabled)
@@ -159,7 +159,7 @@ static int __init bcm63xx_pci_init(void)
        /* setup PCI to local bus access, used by PCI device to target
         * local RAM while bus mastering */
        bcm63xx_int_cfg_writel(0, PCI_BASE_ADDRESS_3);
-       if (BCMCPU_IS_6358())
+       if (BCMCPU_IS_6358() || BCMCPU_IS_6368())
                val = MPI_SP0_REMAP_ENABLE_MASK;
        else
                val = 0;
index ed1c54284b8f27feb9966c7fea4b55c77d5997de..52a1ba70b3b600a11572ccb62783a89cde78e0ae 100644 (file)
@@ -99,7 +99,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
         */
        pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 / 4);
        /* Set latency timers for all devices */
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 48);
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
 
        /* Enable reporting System errors and parity errors on all devices */
        /* Enable parity checking and error reporting */
@@ -109,7 +109,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
 
        if (dev->subordinate) {
                /* Set latency timers on sub bridges */
-               pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 48);
+               pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 64);
                /* More bridge error detection */
                pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config);
                config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
@@ -121,14 +121,10 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
        if (pos) {
                /* Update Device Control */
                pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config);
-               /* Correctable Error Reporting */
-               config |= PCI_EXP_DEVCTL_CERE;
-               /* Non-Fatal Error Reporting */
-               config |= PCI_EXP_DEVCTL_NFERE;
-               /* Fatal Error Reporting */
-               config |= PCI_EXP_DEVCTL_FERE;
-               /* Unsupported Request */
-               config |= PCI_EXP_DEVCTL_URRE;
+               config |= PCI_EXP_DEVCTL_CERE; /* Correctable Error Reporting */
+               config |= PCI_EXP_DEVCTL_NFERE; /* Non-Fatal Error Reporting */
+               config |= PCI_EXP_DEVCTL_FERE;  /* Fatal Error Reporting */
+               config |= PCI_EXP_DEVCTL_URRE;  /* Unsupported Request */
                pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config);
        }
 
index a5807406a7f168bc62535319b84effd5756644e6..a032ae0a533dce2d8afc1d7fe94936037679661e 100644 (file)
@@ -85,7 +85,7 @@ void __init tx4927_setup_pcierr_irq(void)
 {
        if (request_irq(TXX9_IRQ_BASE + TX4927_IR_PCIERR,
                        tx4927_pcierr_interrupt,
-                       IRQF_DISABLED, "PCI error",
+                       0, "PCI error",
                        (void *)TX4927_PCIC_REG))
                printk(KERN_WARNING "Failed to request irq for PCIERR\n");
 }
index 20e45f30b2ef4274037dcac4ae63665a13c49c7f..141bba562488d1d37fef412804952c34dff45dd9 100644 (file)
@@ -136,7 +136,7 @@ void __init tx4938_setup_pcierr_irq(void)
 {
        if (request_irq(TXX9_IRQ_BASE + TX4938_IR_PCIERR,
                        tx4927_pcierr_interrupt,
-                       IRQF_DISABLED, "PCI error",
+                       0, "PCI error",
                        (void *)TX4927_PCIC_REG))
                printk(KERN_WARNING "Failed to request irq for PCIERR\n");
 }
index 9ef840693baf820fa336453d6fc47a4738c783a3..c10fbf2a19dc761ec16095e4f8fddb0c62e8cb3d 100644 (file)
@@ -101,7 +101,7 @@ void __init tx4939_setup_pcierr_irq(void)
 {
        if (request_irq(TXX9_IRQ_BASE + TX4939_IR_PCIERR,
                        tx4927_pcierr_interrupt,
-                       IRQF_DISABLED, "PCI error",
+                       0, "PCI error",
                        (void *)TX4939_PCIC_REG))
                pr_warning("Failed to request irq for PCIERR\n");
 }
index 38fece16c4357921ce42db7b49a4aea35841fdea..3d701a962ef409928e3c149f00e6b4ad7b6739e2 100644 (file)
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/msi.h>
 #include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
 #include <linux/console.h>
 
 #include <asm/io.h>
 
 #include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/haldefs.h>
+
+#include <asm/netlogic/xlr/msidef.h>
 #include <asm/netlogic/xlr/iomap.h>
 #include <asm/netlogic/xlr/pic.h>
 #include <asm/netlogic/xlr/xlr.h>
@@ -150,7 +156,7 @@ struct pci_controller nlm_pci_controller = {
        .io_offset      = 0x00000000UL,
 };
 
-int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int get_irq_vector(const struct pci_dev *dev)
 {
        if (!nlm_chip_is_xls())
                return  PIC_PCIX_IRQ;   /* for XLR just one IRQ*/
@@ -182,6 +188,101 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
        return 0;
 }
 
+#ifdef CONFIG_PCI_MSI
+void destroy_irq(unsigned int irq)
+{
+           /* nothing to do yet */
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+       destroy_irq(irq);
+}
+
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
+{
+       struct msi_msg msg;
+       int irq, ret;
+
+       irq = get_irq_vector(dev);
+       if (irq <= 0)
+               return 1;
+
+       msg.address_hi = MSI_ADDR_BASE_HI;
+       msg.address_lo = MSI_ADDR_BASE_LO   |
+               MSI_ADDR_DEST_MODE_PHYSICAL |
+               MSI_ADDR_REDIRECTION_CPU;
+
+       msg.data = MSI_DATA_TRIGGER_EDGE |
+               MSI_DATA_LEVEL_ASSERT    |
+               MSI_DATA_DELIVERY_FIXED;
+
+       ret = irq_set_msi_desc(irq, desc);
+       if (ret < 0) {
+               destroy_irq(irq);
+               return ret;
+       }
+
+       write_msi_msg(irq, &msg);
+       return 0;
+}
+#endif
+
+/* Extra ACK needed for XLR on chip PCI controller */
+static void xlr_pci_ack(struct irq_data *d)
+{
+       uint64_t pcibase = nlm_mmio_base(NETLOGIC_IO_PCIX_OFFSET);
+
+       nlm_read_reg(pcibase, (0x140 >> 2));
+}
+
+/* Extra ACK needed for XLS on chip PCIe controller */
+static void xls_pcie_ack(struct irq_data *d)
+{
+       uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET);
+
+       switch (d->irq) {
+       case PIC_PCIE_LINK0_IRQ:
+               nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff);
+               break;
+       case PIC_PCIE_LINK1_IRQ:
+               nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff);
+               break;
+       case PIC_PCIE_LINK2_IRQ:
+               nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff);
+               break;
+       case PIC_PCIE_LINK3_IRQ:
+               nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff);
+               break;
+       }
+}
+
+/* For XLS B silicon, the 3,4 PCI interrupts are different */
+static void xls_pcie_ack_b(struct irq_data *d)
+{
+       uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET);
+
+       switch (d->irq) {
+       case PIC_PCIE_LINK0_IRQ:
+               nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff);
+               break;
+       case PIC_PCIE_LINK1_IRQ:
+               nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff);
+               break;
+       case PIC_PCIE_XLSB0_LINK2_IRQ:
+               nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff);
+               break;
+       case PIC_PCIE_XLSB0_LINK3_IRQ:
+               nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff);
+               break;
+       }
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       return get_irq_vector(dev);
+}
+
 /* Do platform specific device initialization at pci_enable_device() time */
 int pcibios_plat_dev_init(struct pci_dev *dev)
 {
@@ -204,6 +305,31 @@ static int __init pcibios_init(void)
        pr_info("Registering XLR/XLS PCIX/PCIE Controller.\n");
        register_pci_controller(&nlm_pci_controller);
 
+       /*
+        * For PCI interrupts, we need to ack the PCI controller too, overload
+        * irq handler data to do this
+        */
+       if (nlm_chip_is_xls()) {
+               if (nlm_chip_is_xls_b()) {
+                       irq_set_handler_data(PIC_PCIE_LINK0_IRQ,
+                                                       xls_pcie_ack_b);
+                       irq_set_handler_data(PIC_PCIE_LINK1_IRQ,
+                                                       xls_pcie_ack_b);
+                       irq_set_handler_data(PIC_PCIE_XLSB0_LINK2_IRQ,
+                                                       xls_pcie_ack_b);
+                       irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ,
+                                                       xls_pcie_ack_b);
+               } else {
+                       irq_set_handler_data(PIC_PCIE_LINK0_IRQ, xls_pcie_ack);
+                       irq_set_handler_data(PIC_PCIE_LINK1_IRQ, xls_pcie_ack);
+                       irq_set_handler_data(PIC_PCIE_LINK2_IRQ, xls_pcie_ack);
+                       irq_set_handler_data(PIC_PCIE_LINK3_IRQ, xls_pcie_ack);
+               }
+       } else {
+               /* XLR PCI controller ACK */
+               irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack);
+       }
+
        return 0;
 }
 
index fa8e378413b1640ed1e2efaf17894efde23925da..aec2b111d35b0131f805e736bd80c2ca19d59cbf 100644 (file)
@@ -4,8 +4,11 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  *
- * Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2003, 04, 11 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2011 Wind River Systems,
+ *   written by Ralf Baechle (ralf@linux-mips.org)
  */
+#include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/bootmem.h>
@@ -14,6 +17,8 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 
+#include <asm/cpu-info.h>
+
 /*
  * Indicate whether we respect the PCI setup left by the firmware.
  *
@@ -157,10 +162,32 @@ out:
               "Skipping PCI bus scan due to resource conflict\n");
 }
 
+static void __init pcibios_set_cache_line_size(void)
+{
+       struct cpuinfo_mips *c = &current_cpu_data;
+       unsigned int lsize;
+
+       /*
+        * Set PCI cacheline size to that of the highest level in the
+        * cache hierarchy.
+        */
+       lsize = c->dcache.linesz;
+       lsize = c->scache.linesz ? : lsize;
+       lsize = c->tcache.linesz ? : lsize;
+
+       BUG_ON(!lsize);
+
+       pci_dfl_cache_line_size = lsize >> 2;
+
+       pr_debug("PCI: pci_cache_line_size set to %d bytes\n", lsize);
+}
+
 static int __init pcibios_init(void)
 {
        struct pci_controller *hose;
 
+       pcibios_set_cache_line_size();
+
        /* Scan all of the recorded PCI controllers.  */
        for (hose = hose_head; hose; hose = hose->next)
                pcibios_scanbus(hose);
index 0583c463e5f19137b794b2772910ad5b904e98d8..fdb4d558c0cc0d0b40332d6e38b37c33bc8a3169 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2007, 2008 Cavium Networks
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 Cavium Networks
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/time.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-npei-defs.h>
 #include <asm/octeon/cvmx-pciercx-defs.h>
 #include <asm/octeon/cvmx-pescx-defs.h>
 #include <asm/octeon/cvmx-pexp-defs.h>
+#include <asm/octeon/cvmx-pemx-defs.h>
+#include <asm/octeon/cvmx-dpi-defs.h>
+#include <asm/octeon/cvmx-sli-defs.h>
+#include <asm/octeon/cvmx-sriox-defs.h>
 #include <asm/octeon/cvmx-helper-errata.h>
 #include <asm/octeon/pci-octeon.h>
 
+#define MRRS_CN5XXX 0 /* 128 byte Max Read Request Size */
+#define MPS_CN5XXX  0 /* 128 byte Max Packet Size (Limit of most PCs) */
+#define MRRS_CN6XXX 3 /* 1024 byte Max Read Request Size */
+#define MPS_CN6XXX  0 /* 128 byte Max Packet Size (Limit of most PCs) */
+
+/* Module parameter to disable PCI probing */
+static int pcie_disable;
+module_param(pcie_disable, int, S_IRUGO);
+
+static int enable_pcie_14459_war;
+static int enable_pcie_bus_num_war[2];
+
 union cvmx_pcie_address {
        uint64_t u64;
        struct {
@@ -75,6 +92,8 @@ union cvmx_pcie_address {
        } mem;
 };
 
+static int cvmx_pcie_rc_initialize(int pcie_port);
+
 #include <dma-coherence.h>
 
 /**
@@ -154,12 +173,21 @@ static inline uint64_t cvmx_pcie_get_mem_size(int pcie_port)
  */
 static uint32_t cvmx_pcie_cfgx_read(int pcie_port, uint32_t cfg_offset)
 {
-       union cvmx_pescx_cfg_rd pescx_cfg_rd;
-       pescx_cfg_rd.u64 = 0;
-       pescx_cfg_rd.s.addr = cfg_offset;
-       cvmx_write_csr(CVMX_PESCX_CFG_RD(pcie_port), pescx_cfg_rd.u64);
-       pescx_cfg_rd.u64 = cvmx_read_csr(CVMX_PESCX_CFG_RD(pcie_port));
-       return pescx_cfg_rd.s.data;
+       if (octeon_has_feature(OCTEON_FEATURE_NPEI)) {
+               union cvmx_pescx_cfg_rd pescx_cfg_rd;
+               pescx_cfg_rd.u64 = 0;
+               pescx_cfg_rd.s.addr = cfg_offset;
+               cvmx_write_csr(CVMX_PESCX_CFG_RD(pcie_port), pescx_cfg_rd.u64);
+               pescx_cfg_rd.u64 = cvmx_read_csr(CVMX_PESCX_CFG_RD(pcie_port));
+               return pescx_cfg_rd.s.data;
+       } else {
+               union cvmx_pemx_cfg_rd pemx_cfg_rd;
+               pemx_cfg_rd.u64 = 0;
+               pemx_cfg_rd.s.addr = cfg_offset;
+               cvmx_write_csr(CVMX_PEMX_CFG_RD(pcie_port), pemx_cfg_rd.u64);
+               pemx_cfg_rd.u64 = cvmx_read_csr(CVMX_PEMX_CFG_RD(pcie_port));
+               return pemx_cfg_rd.s.data;
+       }
 }
 
 /**
@@ -173,11 +201,19 @@ static uint32_t cvmx_pcie_cfgx_read(int pcie_port, uint32_t cfg_offset)
 static void cvmx_pcie_cfgx_write(int pcie_port, uint32_t cfg_offset,
                                 uint32_t val)
 {
-       union cvmx_pescx_cfg_wr pescx_cfg_wr;
-       pescx_cfg_wr.u64 = 0;
-       pescx_cfg_wr.s.addr = cfg_offset;
-       pescx_cfg_wr.s.data = val;
-       cvmx_write_csr(CVMX_PESCX_CFG_WR(pcie_port), pescx_cfg_wr.u64);
+       if (octeon_has_feature(OCTEON_FEATURE_NPEI)) {
+               union cvmx_pescx_cfg_wr pescx_cfg_wr;
+               pescx_cfg_wr.u64 = 0;
+               pescx_cfg_wr.s.addr = cfg_offset;
+               pescx_cfg_wr.s.data = val;
+               cvmx_write_csr(CVMX_PESCX_CFG_WR(pcie_port), pescx_cfg_wr.u64);
+       } else {
+               union cvmx_pemx_cfg_wr pemx_cfg_wr;
+               pemx_cfg_wr.u64 = 0;
+               pemx_cfg_wr.s.addr = cfg_offset;
+               pemx_cfg_wr.s.data = val;
+               cvmx_write_csr(CVMX_PEMX_CFG_WR(pcie_port), pemx_cfg_wr.u64);
+       }
 }
 
 /**
@@ -348,7 +384,6 @@ static void cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int fn,
 static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)
 {
        union cvmx_pciercx_cfg030 pciercx_cfg030;
-       union cvmx_npei_ctl_status2 npei_ctl_status2;
        union cvmx_pciercx_cfg070 pciercx_cfg070;
        union cvmx_pciercx_cfg001 pciercx_cfg001;
        union cvmx_pciercx_cfg032 pciercx_cfg032;
@@ -365,21 +400,21 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)
        /* Max Read Request Size (PCIE*_CFG030[MRRS]) */
        /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */
        /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */
-       pciercx_cfg030.u32 =
-               cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port));
-       /*
-        * Max payload size = 128 bytes for best Octeon DMA
-        * performance.
-        */
-       pciercx_cfg030.s.mps = 0;
+
+       pciercx_cfg030.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port));
+       if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
+               pciercx_cfg030.s.mps = MPS_CN5XXX;
+               pciercx_cfg030.s.mrrs = MRRS_CN5XXX;
+       } else {
+               pciercx_cfg030.s.mps = MPS_CN6XXX;
+               pciercx_cfg030.s.mrrs = MRRS_CN6XXX;
+       }
        /*
-        * Max read request size = 128 bytes for best Octeon DMA
-        * performance.
+        * Enable relaxed order processing. This will allow devices to
+        * affect read response ordering.
         */
-       pciercx_cfg030.s.mrrs = 0;
-       /* Enable relaxed ordering. */
        pciercx_cfg030.s.ro_en = 1;
-       /* Enable no snoop. */
+       /* Enable no snoop processing. Not used by Octeon */
        pciercx_cfg030.s.ns_en = 1;
        /* Correctable error reporting enable. */
        pciercx_cfg030.s.ce_en = 1;
@@ -389,50 +424,67 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)
        pciercx_cfg030.s.fe_en = 1;
        /* Unsupported request reporting enable. */
        pciercx_cfg030.s.ur_en = 1;
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port),
-                            pciercx_cfg030.u32);
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), pciercx_cfg030.u32);
 
-       /*
-        * Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match
-        * PCIE*_CFG030[MPS]
-        *
-        * Max Read Request Size (NPEI_CTL_STATUS2[MRRS]) must not
-        * exceed PCIE*_CFG030[MRRS].
-        */
-       npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2);
-       /* Max payload size = 128 bytes for best Octeon DMA performance */
-       npei_ctl_status2.s.mps = 0;
-       /* Max read request size = 128 bytes for best Octeon DMA performance */
-       npei_ctl_status2.s.mrrs = 0;
-       if (pcie_port)
-               npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */
-       else
-               npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */
-       cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64);
+
+       if (octeon_has_feature(OCTEON_FEATURE_NPEI)) {
+               union cvmx_npei_ctl_status2 npei_ctl_status2;
+               /*
+                * Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match
+                * PCIE*_CFG030[MPS].  Max Read Request Size
+                * (NPEI_CTL_STATUS2[MRRS]) must not exceed
+                * PCIE*_CFG030[MRRS]
+                */
+               npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2);
+               /* Max payload size = 128 bytes for best Octeon DMA performance */
+               npei_ctl_status2.s.mps = MPS_CN5XXX;
+               /* Max read request size = 128 bytes for best Octeon DMA performance */
+               npei_ctl_status2.s.mrrs = MRRS_CN5XXX;
+               if (pcie_port)
+                       npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */
+               else
+                       npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */
+
+               cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64);
+       } else {
+               /*
+                * Max Payload Size (DPI_SLI_PRTX_CFG[MPS]) must match
+                * PCIE*_CFG030[MPS].  Max Read Request Size
+                * (DPI_SLI_PRTX_CFG[MRRS]) must not exceed
+                * PCIE*_CFG030[MRRS].
+                */
+               union cvmx_dpi_sli_prtx_cfg prt_cfg;
+               union cvmx_sli_s2m_portx_ctl sli_s2m_portx_ctl;
+               prt_cfg.u64 = cvmx_read_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port));
+               prt_cfg.s.mps = MPS_CN6XXX;
+               prt_cfg.s.mrrs = MRRS_CN6XXX;
+               /* Max outstanding load request. */
+               prt_cfg.s.molr = 32;
+               cvmx_write_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port), prt_cfg.u64);
+
+               sli_s2m_portx_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port));
+               sli_s2m_portx_ctl.s.mrrs = MRRS_CN6XXX;
+               cvmx_write_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port), sli_s2m_portx_ctl.u64);
+       }
 
        /* ECRC Generation (PCIE*_CFG070[GE,CE]) */
-       pciercx_cfg070.u32 =
-               cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port));
+       pciercx_cfg070.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port));
        pciercx_cfg070.s.ge = 1;        /* ECRC generation enable. */
        pciercx_cfg070.s.ce = 1;        /* ECRC check enable. */
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port),
-                            pciercx_cfg070.u32);
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), pciercx_cfg070.u32);
 
        /*
-        * Access Enables (PCIE*_CFG001[MSAE,ME]) ME and MSAE should
-        * always be set.
-        *
-        * Interrupt Disable (PCIE*_CFG001[I_DIS]) System Error
-        * Message Enable (PCIE*_CFG001[SEE])
+        * Access Enables (PCIE*_CFG001[MSAE,ME])
+        * ME and MSAE should always be set.
+        * Interrupt Disable (PCIE*_CFG001[I_DIS])
+        * System Error Message Enable (PCIE*_CFG001[SEE])
         */
-       pciercx_cfg001.u32 =
-               cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port));
+       pciercx_cfg001.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port));
        pciercx_cfg001.s.msae = 1;      /* Memory space enable. */
        pciercx_cfg001.s.me = 1;        /* Bus master enable. */
        pciercx_cfg001.s.i_dis = 1;     /* INTx assertion disable. */
        pciercx_cfg001.s.see = 1;       /* SERR# enable */
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port),
-                       pciercx_cfg001.u32);
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), pciercx_cfg001.u32);
 
        /* Advanced Error Recovery Message Enables */
        /* (PCIE*_CFG066,PCIE*_CFG067,PCIE*_CFG069) */
@@ -440,14 +492,11 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)
        /* Use CVMX_PCIERCX_CFG067 hardware default */
        cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG069(pcie_port), 0);
 
-       /* Active State Power Management (PCIE*_CFG032[ASLPC]) */
-       pciercx_cfg032.u32 =
-               cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
-       pciercx_cfg032.s.aslpc = 0;     /* Active state Link PM control. */
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port),
-                            pciercx_cfg032.u32);
 
-       /* Entrance Latencies (PCIE*_CFG451[L0EL,L1EL]) */
+       /* Active State Power Management (PCIE*_CFG032[ASLPC]) */
+       pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
+       pciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), pciercx_cfg032.u32);
 
        /*
         * Link Width Mode (PCIERCn_CFG452[LME]) - Set during
@@ -462,8 +511,8 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)
        pciercx_cfg006.s.pbnum = 1;
        pciercx_cfg006.s.sbnum = 1;
        pciercx_cfg006.s.subbnum = 1;
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port),
-                            pciercx_cfg006.u32);
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), pciercx_cfg006.u32);
+
 
        /*
         * Memory-mapped I/O BAR (PCIERCn_CFG008)
@@ -473,8 +522,8 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)
        pciercx_cfg008.u32 = 0;
        pciercx_cfg008.s.mb_addr = 0x100;
        pciercx_cfg008.s.ml_addr = 0;
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port),
-                            pciercx_cfg008.u32);
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), pciercx_cfg008.u32);
+
 
        /*
         * Prefetchable BAR (PCIERCn_CFG009,PCIERCn_CFG010,PCIERCn_CFG011)
@@ -482,72 +531,51 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)
         * PCIERCn_CFG011[UMEM_LIMIT],PCIERCn_CFG009[LMEM_LIMIT] <
         * PCIERCn_CFG010[UMEM_BASE],PCIERCn_CFG009[LMEM_BASE]
         */
-       pciercx_cfg009.u32 =
-               cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port));
-       pciercx_cfg010.u32 =
-               cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port));
-       pciercx_cfg011.u32 =
-               cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port));
+       pciercx_cfg009.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port));
+       pciercx_cfg010.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port));
+       pciercx_cfg011.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port));
        pciercx_cfg009.s.lmem_base = 0x100;
        pciercx_cfg009.s.lmem_limit = 0;
        pciercx_cfg010.s.umem_base = 0x100;
        pciercx_cfg011.s.umem_limit = 0;
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port),
-                            pciercx_cfg009.u32);
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port),
-                            pciercx_cfg010.u32);
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port),
-                            pciercx_cfg011.u32);
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), pciercx_cfg009.u32);
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), pciercx_cfg010.u32);
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), pciercx_cfg011.u32);
 
        /*
         * System Error Interrupt Enables (PCIERCn_CFG035[SECEE,SEFEE,SENFEE])
         * PME Interrupt Enables (PCIERCn_CFG035[PMEIE])
-        */
-       pciercx_cfg035.u32 =
-               cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port));
-       /* System error on correctable error enable. */
-       pciercx_cfg035.s.secee = 1;
-       /* System error on fatal error enable. */
-       pciercx_cfg035.s.sefee = 1;
-       /* System error on non-fatal error enable. */
-       pciercx_cfg035.s.senfee = 1;
-       /* PME interrupt enable. */
-       pciercx_cfg035.s.pmeie = 1;
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port),
-                            pciercx_cfg035.u32);
+       */
+       pciercx_cfg035.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port));
+       pciercx_cfg035.s.secee = 1; /* System error on correctable error enable. */
+       pciercx_cfg035.s.sefee = 1; /* System error on fatal error enable. */
+       pciercx_cfg035.s.senfee = 1; /* System error on non-fatal error enable. */
+       pciercx_cfg035.s.pmeie = 1; /* PME interrupt enable. */
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), pciercx_cfg035.u32);
 
        /*
         * Advanced Error Recovery Interrupt Enables
         * (PCIERCn_CFG075[CERE,NFERE,FERE])
         */
-       pciercx_cfg075.u32 =
-               cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port));
-       /* Correctable error reporting enable. */
-       pciercx_cfg075.s.cere = 1;
-       /* Non-fatal error reporting enable. */
-       pciercx_cfg075.s.nfere = 1;
-       /* Fatal error reporting enable. */
-       pciercx_cfg075.s.fere = 1;
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port),
-                            pciercx_cfg075.u32);
+       pciercx_cfg075.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port));
+       pciercx_cfg075.s.cere = 1; /* Correctable error reporting enable. */
+       pciercx_cfg075.s.nfere = 1; /* Non-fatal error reporting enable. */
+       pciercx_cfg075.s.fere = 1; /* Fatal error reporting enable. */
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), pciercx_cfg075.u32);
 
-       /* HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN],
+       /*
+        * HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN],
         * PCIERCn_CFG034[DLLS_EN,CCINT_EN])
         */
-       pciercx_cfg034.u32 =
-               cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port));
-       /* Hot-plug interrupt enable. */
-       pciercx_cfg034.s.hpint_en = 1;
-       /* Data Link Layer state changed enable */
-       pciercx_cfg034.s.dlls_en = 1;
-       /* Command completed interrupt enable. */
-       pciercx_cfg034.s.ccint_en = 1;
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port),
-                            pciercx_cfg034.u32);
+       pciercx_cfg034.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port));
+       pciercx_cfg034.s.hpint_en = 1; /* Hot-plug interrupt enable. */
+       pciercx_cfg034.s.dlls_en = 1; /* Data Link Layer state changed enable */
+       pciercx_cfg034.s.ccint_en = 1; /* Command completed interrupt enable. */
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), pciercx_cfg034.u32);
 }
 
 /**
- * Initialize a host mode PCIe link. This function takes a PCIe
+ * Initialize a host mode PCIe gen 1 link. This function takes a PCIe
  * port from reset to a link up state. Software can then begin
  * configuring the rest of the link.
  *
@@ -555,7 +583,7 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)
  *
  * Returns Zero on success
  */
-static int __cvmx_pcie_rc_initialize_link(int pcie_port)
+static int __cvmx_pcie_rc_initialize_link_gen1(int pcie_port)
 {
        uint64_t start_cycle;
        union cvmx_pescx_ctl_status pescx_ctl_status;
@@ -564,18 +592,15 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port)
        union cvmx_pciercx_cfg448 pciercx_cfg448;
 
        /* Set the lane width */
-       pciercx_cfg452.u32 =
-           cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port));
+       pciercx_cfg452.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port));
        pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port));
-       if (pescx_ctl_status.s.qlm_cfg == 0) {
+       if (pescx_ctl_status.s.qlm_cfg == 0)
                /* We're in 8 lane (56XX) or 4 lane (54XX) mode */
                pciercx_cfg452.s.lme = 0xf;
-       } else {
+       else
                /* We're in 4 lane (56XX) or 2 lane (52XX) mode */
                pciercx_cfg452.s.lme = 0x7;
-       }
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port),
-                            pciercx_cfg452.u32);
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), pciercx_cfg452.u32);
 
        /*
         * CN52XX pass 1.x has an errata where length mismatches on UR
@@ -584,19 +609,15 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port)
         */
        if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
                union cvmx_pciercx_cfg455 pciercx_cfg455;
-               pciercx_cfg455.u32 =
-                   cvmx_pcie_cfgx_read(pcie_port,
-                                       CVMX_PCIERCX_CFG455(pcie_port));
+               pciercx_cfg455.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG455(pcie_port));
                pciercx_cfg455.s.m_cpl_len_err = 1;
-               cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port),
-                                    pciercx_cfg455.u32);
+               cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), pciercx_cfg455.u32);
        }
 
        /* Lane swap needs to be manually enabled for CN52XX */
        if (OCTEON_IS_MODEL(OCTEON_CN52XX) && (pcie_port == 1)) {
                pescx_ctl_status.s.lane_swp = 1;
-               cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port),
-                              pescx_ctl_status.u64);
+               cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64);
        }
 
        /* Bring up the link */
@@ -612,24 +633,18 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port)
                __cvmx_helper_errata_qlm_disable_2nd_order_cdr(0);
 
        /* Wait for the link to come up */
-       cvmx_dprintf("PCIe: Waiting for port %d link\n", pcie_port);
        start_cycle = cvmx_get_cycle();
        do {
-               if (cvmx_get_cycle() - start_cycle >
-                   2 * cvmx_sysinfo_get()->cpu_clock_hz) {
-                       cvmx_dprintf("PCIe: Port %d link timeout\n",
-                                    pcie_port);
+               if (cvmx_get_cycle() - start_cycle > 2 * octeon_get_clock_rate()) {
+                       cvmx_dprintf("PCIe: Port %d link timeout\n", pcie_port);
                        return -1;
                }
                cvmx_wait(10000);
-               pciercx_cfg032.u32 =
-                   cvmx_pcie_cfgx_read(pcie_port,
-                                       CVMX_PCIERCX_CFG032(pcie_port));
+               pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
        } while (pciercx_cfg032.s.dlla == 0);
 
-       /* Display the link status */
-       cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port,
-                    pciercx_cfg032.s.nlw);
+       /* Clear all pending errors */
+       cvmx_write_csr(CVMX_PEXP_NPEI_INT_SUM, cvmx_read_csr(CVMX_PEXP_NPEI_INT_SUM));
 
        /*
         * Update the Replay Time Limit. Empirically, some PCIe
@@ -639,8 +654,7 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port)
         * our actual 256 byte MPS. The numbers below are directly
         * from the PCIe spec table 3-4.
         */
-       pciercx_cfg448.u32 =
-           cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port));
+       pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port));
        switch (pciercx_cfg032.s.nlw) {
        case 1:         /* 1 lane */
                pciercx_cfg448.s.rtl = 1677;
@@ -655,21 +669,28 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port)
                pciercx_cfg448.s.rtl = 258;
                break;
        }
-       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port),
-                            pciercx_cfg448.u32);
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32);
 
        return 0;
 }
 
+static void __cvmx_increment_ba(union cvmx_sli_mem_access_subidx *pmas)
+{
+       if (OCTEON_IS_MODEL(OCTEON_CN68XX))
+               pmas->cn68xx.ba++;
+       else
+               pmas->cn63xx.ba++;
+}
+
 /**
- * Initialize a PCIe port for use in host(RC) mode. It doesn't
+ * Initialize a PCIe gen 1 port for use in host(RC) mode. It doesn't
  * enumerate the bus.
  *
  * @pcie_port: PCIe port to initialize
  *
  * Returns Zero on success
  */
-static int cvmx_pcie_rc_initialize(int pcie_port)
+static int __cvmx_pcie_rc_initialize_gen1(int pcie_port)
 {
        int i;
        int base;
@@ -682,16 +703,17 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
        union cvmx_npei_mem_access_subidx mem_access_subid;
        union cvmx_npei_dbg_data npei_dbg_data;
        union cvmx_pescx_ctl_status2 pescx_ctl_status2;
+       union cvmx_pciercx_cfg032 pciercx_cfg032;
        union cvmx_npei_bar1_indexx bar1_index;
 
+retry:
        /*
         * Make sure we aren't trying to setup a target mode interface
         * in host mode.
         */
        npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS);
        if ((pcie_port == 0) && !npei_ctl_status.s.host_mode) {
-               cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called "
-                            "on port0, but port0 is not in host mode\n");
+               cvmx_dprintf("PCIe: Port %d in endpoint mode\n", pcie_port);
                return -1;
        }
 
@@ -702,9 +724,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
        if (OCTEON_IS_MODEL(OCTEON_CN52XX)) {
                npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
                if ((pcie_port == 1) && npei_dbg_data.cn52xx.qlm0_link_width) {
-                       cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() "
-                                    "called on port1, but port1 is "
-                                    "disabled\n");
+                       cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called on port1, but port1 is disabled\n");
                        return -1;
                }
        }
@@ -733,7 +753,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
                 * the board. As a workaround for this bug, we bring
                 * both PCIe ports out of reset at the same time
                 * instead of on separate calls. So for port 0, we
-                * bring both out of reset and do nothing on port 1.
+                * bring both out of reset and do nothing on port 1
                 */
                if (pcie_port == 0) {
                        ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
@@ -746,13 +766,10 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
                        if (ciu_soft_prst.s.soft_prst == 0) {
                                /* Reset the ports */
                                ciu_soft_prst.s.soft_prst = 1;
-                               cvmx_write_csr(CVMX_CIU_SOFT_PRST,
-                                              ciu_soft_prst.u64);
-                               ciu_soft_prst.u64 =
-                                   cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
+                               cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
+                               ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
                                ciu_soft_prst.s.soft_prst = 1;
-                               cvmx_write_csr(CVMX_CIU_SOFT_PRST1,
-                                              ciu_soft_prst.u64);
+                               cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
                                /* Wait until pcie resets the ports. */
                                udelay(2000);
                        }
@@ -782,11 +799,9 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
                        /* Reset the port */
                        ciu_soft_prst.s.soft_prst = 1;
                        if (pcie_port)
-                               cvmx_write_csr(CVMX_CIU_SOFT_PRST1,
-                                              ciu_soft_prst.u64);
+                               cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
                        else
-                               cvmx_write_csr(CVMX_CIU_SOFT_PRST,
-                                              ciu_soft_prst.u64);
+                               cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
                        /* Wait until pcie resets the ports. */
                        udelay(2000);
                }
@@ -808,25 +823,21 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
         */
        cvmx_wait(400000);
 
-       /* PESCX_BIST_STATUS2[PCLK_RUN] was missing on pass 1 of CN56XX and
-          CN52XX, so we only probe it on newer chips */
-       if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
-           && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
+       /*
+        * PESCX_BIST_STATUS2[PCLK_RUN] was missing on pass 1 of
+        * CN56XX and CN52XX, so we only probe it on newer chips
+        */
+       if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
                /* Clear PCLK_RUN so we can check if the clock is running */
-               pescx_ctl_status2.u64 =
-                   cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port));
+               pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port));
                pescx_ctl_status2.s.pclk_run = 1;
-               cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port),
-                              pescx_ctl_status2.u64);
-               /*
-                * Now that we cleared PCLK_RUN, wait for it to be set
-                * again telling us the clock is running.
+               cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port), pescx_ctl_status2.u64);
+               /* Now that we cleared PCLK_RUN, wait for it to be set
+                * again telling us the clock is running
                 */
                if (CVMX_WAIT_FOR_FIELD64(CVMX_PESCX_CTL_STATUS2(pcie_port),
-                                         union cvmx_pescx_ctl_status2,
-                                         pclk_run, ==, 1, 10000)) {
-                       cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n",
-                                    pcie_port);
+                                         union cvmx_pescx_ctl_status2, pclk_run, ==, 1, 10000)) {
+                       cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n", pcie_port);
                        return -1;
                }
        }
@@ -836,30 +847,26 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
         * the board probably hasn't wired the clocks up and the
         * interface should be skipped.
         */
-       pescx_ctl_status2.u64 =
-           cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port));
+       pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port));
        if (pescx_ctl_status2.s.pcierst) {
-               cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n",
-                            pcie_port);
+               cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", pcie_port);
                return -1;
        }
 
        /*
-        * Check BIST2 status. If any bits are set skip this interface. This
-        * is an attempt to catch PCIE-813 on pass 1 parts.
+        * Check BIST2 status. If any bits are set skip this
+        * interface. This is an attempt to catch PCIE-813 on pass 1
+        * parts.
         */
-       pescx_bist_status2.u64 =
-           cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port));
+       pescx_bist_status2.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port));
        if (pescx_bist_status2.u64) {
-               cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this "
-                            "port isn't hooked up, skipping.\n",
+               cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this port isn't hooked up, skipping.\n",
                             pcie_port);
                return -1;
        }
 
        /* Check BIST status */
-       pescx_bist_status.u64 =
-           cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port));
+       pescx_bist_status.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port));
        if (pescx_bist_status.u64)
                cvmx_dprintf("PCIe: BIST FAILED for port %d (0x%016llx)\n",
                             pcie_port, CAST64(pescx_bist_status.u64));
@@ -868,50 +875,37 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
        __cvmx_pcie_rc_initialize_config_space(pcie_port);
 
        /* Bring the link up */
-       if (__cvmx_pcie_rc_initialize_link(pcie_port)) {
-               cvmx_dprintf
-                   ("PCIe: ERROR: cvmx_pcie_rc_initialize_link() failed\n");
+       if (__cvmx_pcie_rc_initialize_link_gen1(pcie_port)) {
+               cvmx_dprintf("PCIe: Failed to initialize port %d, probably the slot is empty\n",
+                            pcie_port);
                return -1;
        }
 
        /* Store merge control (NPEI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */
        npei_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL);
-       /* Allow 16 words to combine */
-       npei_mem_access_ctl.s.max_word = 0;
-       /* Wait up to 127 cycles for more data */
-       npei_mem_access_ctl.s.timer = 127;
+       npei_mem_access_ctl.s.max_word = 0;     /* Allow 16 words to combine */
+       npei_mem_access_ctl.s.timer = 127;      /* Wait up to 127 cycles for more data */
        cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL, npei_mem_access_ctl.u64);
 
        /* Setup Mem access SubDIDs */
        mem_access_subid.u64 = 0;
-       /* Port the request is sent to. */
-       mem_access_subid.s.port = pcie_port;
-       /* Due to an errata on pass 1 chips, no merging is allowed. */
-       mem_access_subid.s.nmerge = 1;
-       /* Endian-swap for Reads. */
-       mem_access_subid.s.esr = 1;
-       /* Endian-swap for Writes. */
-       mem_access_subid.s.esw = 1;
-       /* No Snoop for Reads. */
-       mem_access_subid.s.nsr = 1;
-       /* No Snoop for Writes. */
-       mem_access_subid.s.nsw = 1;
-       /* Disable Relaxed Ordering for Reads. */
-       mem_access_subid.s.ror = 0;
-       /* Disable Relaxed Ordering for Writes. */
-       mem_access_subid.s.row = 0;
-       /* PCIe Address Bits <63:34>. */
-       mem_access_subid.s.ba = 0;
+       mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */
+       mem_access_subid.s.nmerge = 1;  /* Due to an errata on pass 1 chips, no merging is allowed. */
+       mem_access_subid.s.esr = 1;     /* Endian-swap for Reads. */
+       mem_access_subid.s.esw = 1;     /* Endian-swap for Writes. */
+       mem_access_subid.s.nsr = 0;     /* Enable Snooping for Reads. Octeon doesn't care, but devices might want this more conservative setting */
+       mem_access_subid.s.nsw = 0;     /* Enable Snoop for Writes. */
+       mem_access_subid.s.ror = 0;     /* Disable Relaxed Ordering for Reads. */
+       mem_access_subid.s.row = 0;     /* Disable Relaxed Ordering for Writes. */
+       mem_access_subid.s.ba = 0;      /* PCIe Adddress Bits <63:34>. */
 
        /*
         * Setup mem access 12-15 for port 0, 16-19 for port 1,
         * supplying 36 bits of address space.
         */
        for (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) {
-               cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i),
-                              mem_access_subid.u64);
-               /* Set each SUBID to extend the addressable range */
-               mem_access_subid.s.ba += 1;
+               cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64);
+               mem_access_subid.s.ba += 1; /* Set each SUBID to extend the addressable range */
        }
 
        /*
@@ -927,7 +921,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
        /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */
        cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0);
 
-       /* BAR1 follows BAR2 with a gap. */
+       /* BAR1 follows BAR2 with a gap so it has the same address as for gen2. */
        cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE);
 
        bar1_index.u32 = 0;
@@ -992,13 +986,473 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
                npei_ctl_port.s.waitl_com = 0;
                cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT0, npei_ctl_port.u64);
        }
+
+       /*
+        * Both pass 1 and pass 2 of CN52XX and CN56XX have an errata
+        * that causes TLP ordering to not be preserved after multiple
+        * PCIe port resets. This code detects this fault and corrects
+        * it by aligning the TLP counters properly. Another link
+        * reset is then performed. See PCIE-13340
+        */
+       if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS2_X) ||
+           OCTEON_IS_MODEL(OCTEON_CN52XX_PASS2_X) ||
+           OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) ||
+           OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
+               union cvmx_npei_dbg_data dbg_data;
+               int old_in_fif_p_count;
+               int in_fif_p_count;
+               int out_p_count;
+               int in_p_offset = (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) ? 4 : 1;
+               int i;
+
+               /*
+                * Choose a write address of 1MB. It should be
+                * harmless as all bars haven't been setup.
+                */
+               uint64_t write_address = (cvmx_pcie_get_mem_base_address(pcie_port) + 0x100000) | (1ull<<63);
+
+               /*
+                * Make sure at least in_p_offset have been executed before we try and
+                * read in_fif_p_count
+                */
+               i = in_p_offset;
+               while (i--) {
+                       cvmx_write64_uint32(write_address, 0);
+                       cvmx_wait(10000);
+               }
+
+               /*
+                * Read the IN_FIF_P_COUNT from the debug
+                * select. IN_FIF_P_COUNT can be unstable sometimes so
+                * read it twice with a write between the reads.  This
+                * way we can tell the value is good as it will
+                * increment by one due to the write
+                */
+               cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd7fc : 0xcffc);
+               cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT);
+               do {
+                       dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
+                       old_in_fif_p_count = dbg_data.s.data & 0xff;
+                       cvmx_write64_uint32(write_address, 0);
+                       cvmx_wait(10000);
+                       dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
+                       in_fif_p_count = dbg_data.s.data & 0xff;
+               } while (in_fif_p_count != ((old_in_fif_p_count+1) & 0xff));
+
+               /* Update in_fif_p_count for it's offset with respect to out_p_count */
+               in_fif_p_count = (in_fif_p_count + in_p_offset) & 0xff;
+
+               /* Read the OUT_P_COUNT from the debug select */
+               cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd00f : 0xc80f);
+               cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT);
+               dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
+               out_p_count = (dbg_data.s.data>>1) & 0xff;
+
+               /* Check that the two counters are aligned */
+               if (out_p_count != in_fif_p_count) {
+                       cvmx_dprintf("PCIe: Port %d aligning TLP counters as workaround to maintain ordering\n", pcie_port);
+                       while (in_fif_p_count != 0) {
+                               cvmx_write64_uint32(write_address, 0);
+                               cvmx_wait(10000);
+                               in_fif_p_count = (in_fif_p_count + 1) & 0xff;
+                       }
+                       /*
+                        * The EBH5200 board swapped the PCIe reset
+                        * lines on the board. This means we must
+                        * bring both links down and up, which will
+                        * cause the PCIe0 to need alignment
+                        * again. Lots of messages will be displayed,
+                        * but everything should work
+                        */
+                       if ((cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200) &&
+                               (pcie_port == 1))
+                               cvmx_pcie_rc_initialize(0);
+                       /* Rety bringing this port up */
+                       goto retry;
+               }
+       }
+
+       /* Display the link status */
+       pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
+       cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, pciercx_cfg032.s.nlw);
+
        return 0;
 }
 
+/**
+  * Initialize a host mode PCIe gen 2 link. This function takes a PCIe
+ * port from reset to a link up state. Software can then begin
+ * configuring the rest of the link.
+ *
+ * @pcie_port: PCIe port to initialize
+ *
+ * Return Zero on success.
+ */
+static int __cvmx_pcie_rc_initialize_link_gen2(int pcie_port)
+{
+       uint64_t start_cycle;
+       union cvmx_pemx_ctl_status pem_ctl_status;
+       union cvmx_pciercx_cfg032 pciercx_cfg032;
+       union cvmx_pciercx_cfg448 pciercx_cfg448;
 
-/* Above was cvmx-pcie.c, below original pcie.c */
+       /* Bring up the link */
+       pem_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port));
+       pem_ctl_status.s.lnk_enb = 1;
+       cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pem_ctl_status.u64);
+
+       /* Wait for the link to come up */
+       start_cycle = cvmx_get_cycle();
+       do {
+               if (cvmx_get_cycle() - start_cycle >  octeon_get_clock_rate())
+                       return -1;
+               cvmx_wait(10000);
+               pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
+       } while ((pciercx_cfg032.s.dlla == 0) || (pciercx_cfg032.s.lt == 1));
+
+       /*
+        * Update the Replay Time Limit. Empirically, some PCIe
+        * devices take a little longer to respond than expected under
+        * load. As a workaround for this we configure the Replay Time
+        * Limit to the value expected for a 512 byte MPS instead of
+        * our actual 256 byte MPS. The numbers below are directly
+        * from the PCIe spec table 3-4
+        */
+       pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port));
+       switch (pciercx_cfg032.s.nlw) {
+       case 1: /* 1 lane */
+               pciercx_cfg448.s.rtl = 1677;
+               break;
+       case 2: /* 2 lanes */
+               pciercx_cfg448.s.rtl = 867;
+               break;
+       case 4: /* 4 lanes */
+               pciercx_cfg448.s.rtl = 462;
+               break;
+       case 8: /* 8 lanes */
+               pciercx_cfg448.s.rtl = 258;
+               break;
+       }
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32);
+
+       return 0;
+}
 
 
+/**
+ * Initialize a PCIe gen 2 port for use in host(RC) mode. It doesn't enumerate
+ * the bus.
+ *
+ * @pcie_port: PCIe port to initialize
+ *
+ * Returns Zero on success.
+ */
+static int __cvmx_pcie_rc_initialize_gen2(int pcie_port)
+{
+       int i;
+       union cvmx_ciu_soft_prst ciu_soft_prst;
+       union cvmx_mio_rst_ctlx mio_rst_ctl;
+       union cvmx_pemx_bar_ctl pemx_bar_ctl;
+       union cvmx_pemx_ctl_status pemx_ctl_status;
+       union cvmx_pemx_bist_status pemx_bist_status;
+       union cvmx_pemx_bist_status2 pemx_bist_status2;
+       union cvmx_pciercx_cfg032 pciercx_cfg032;
+       union cvmx_pciercx_cfg515 pciercx_cfg515;
+       union cvmx_sli_ctl_portx sli_ctl_portx;
+       union cvmx_sli_mem_access_ctl sli_mem_access_ctl;
+       union cvmx_sli_mem_access_subidx mem_access_subid;
+       union cvmx_sriox_status_reg sriox_status_reg;
+       union cvmx_pemx_bar1_indexx bar1_index;
+
+       if (octeon_has_feature(OCTEON_FEATURE_SRIO)) {
+               /* Make sure this interface isn't SRIO */
+               if (OCTEON_IS_MODEL(OCTEON_CN66XX)) {
+                       /*
+                        * The CN66XX requires reading the
+                        * MIO_QLMX_CFG register to figure out the
+                        * port type.
+                        */
+                       union cvmx_mio_qlmx_cfg qlmx_cfg;
+                       qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(pcie_port));
+
+                       if (qlmx_cfg.s.qlm_spd == 15) {
+                               pr_notice("PCIe: Port %d is disabled, skipping.\n", pcie_port);
+                               return -1;
+                       }
+
+                       switch (qlmx_cfg.s.qlm_spd) {
+                       case 0x1: /* SRIO 1x4 short */
+                       case 0x3: /* SRIO 1x4 long */
+                       case 0x4: /* SRIO 2x2 short */
+                       case 0x6: /* SRIO 2x2 long */
+                               pr_notice("PCIe: Port %d is SRIO, skipping.\n", pcie_port);
+                               return -1;
+                       case 0x9: /* SGMII */
+                               pr_notice("PCIe: Port %d is SGMII, skipping.\n", pcie_port);
+                               return -1;
+                       case 0xb: /* XAUI */
+                               pr_notice("PCIe: Port %d is XAUI, skipping.\n", pcie_port);
+                               return -1;
+                       case 0x0: /* PCIE gen2 */
+                       case 0x8: /* PCIE gen2 (alias) */
+                       case 0x2: /* PCIE gen1 */
+                       case 0xa: /* PCIE gen1 (alias) */
+                               break;
+                       default:
+                               pr_notice("PCIe: Port %d is unknown, skipping.\n", pcie_port);
+                               return -1;
+                       }
+               } else {
+                       sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(pcie_port));
+                       if (sriox_status_reg.s.srio) {
+                               pr_notice("PCIe: Port %d is SRIO, skipping.\n", pcie_port);
+                               return -1;
+                       }
+               }
+       }
+
+#if 0
+    /* This code is so that the PCIe analyzer is able to see 63XX traffic */
+       pr_notice("PCIE : init for pcie analyzer.\n");
+       cvmx_helper_qlm_jtag_init();
+       cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85);
+       cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1);
+       cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86);
+       cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85);
+       cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1);
+       cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86);
+       cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85);
+       cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1);
+       cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86);
+       cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85);
+       cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1);
+       cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86);
+       cvmx_helper_qlm_jtag_update(pcie_port);
+#endif
+
+       /* Make sure we aren't trying to setup a target mode interface in host mode */
+       mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port));
+       if (!mio_rst_ctl.s.host_mode) {
+               pr_notice("PCIe: Port %d in endpoint mode.\n", pcie_port);
+               return -1;
+       }
+
+       /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */
+       if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0)) {
+               if (pcie_port) {
+                       union cvmx_ciu_qlm1 ciu_qlm;
+                       ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM1);
+                       ciu_qlm.s.txbypass = 1;
+                       ciu_qlm.s.txdeemph = 5;
+                       ciu_qlm.s.txmargin = 0x17;
+                       cvmx_write_csr(CVMX_CIU_QLM1, ciu_qlm.u64);
+               } else {
+                       union cvmx_ciu_qlm0 ciu_qlm;
+                       ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM0);
+                       ciu_qlm.s.txbypass = 1;
+                       ciu_qlm.s.txdeemph = 5;
+                       ciu_qlm.s.txmargin = 0x17;
+                       cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64);
+               }
+       }
+       /* Bring the PCIe out of reset */
+       if (pcie_port)
+               ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
+       else
+               ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
+       /*
+        * After a chip reset the PCIe will also be in reset. If it
+        * isn't, most likely someone is trying to init it again
+        * without a proper PCIe reset
+        */
+       if (ciu_soft_prst.s.soft_prst == 0) {
+               /* Reset the port */
+               ciu_soft_prst.s.soft_prst = 1;
+               if (pcie_port)
+                       cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
+               else
+                       cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
+               /* Wait until pcie resets the ports. */
+               udelay(2000);
+       }
+       if (pcie_port) {
+               ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);
+               ciu_soft_prst.s.soft_prst = 0;
+               cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);
+       } else {
+               ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST);
+               ciu_soft_prst.s.soft_prst = 0;
+               cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);
+       }
+
+       /* Wait for PCIe reset to complete */
+       udelay(1000);
+
+       /*
+        * Check and make sure PCIe came out of reset. If it doesn't
+        * the board probably hasn't wired the clocks up and the
+        * interface should be skipped.
+        */
+       if (CVMX_WAIT_FOR_FIELD64(CVMX_MIO_RST_CTLX(pcie_port), union cvmx_mio_rst_ctlx, rst_done, ==, 1, 10000)) {
+               pr_notice("PCIe: Port %d stuck in reset, skipping.\n", pcie_port);
+               return -1;
+       }
+
+       /* Check BIST status */
+       pemx_bist_status.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS(pcie_port));
+       if (pemx_bist_status.u64)
+               pr_notice("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status.u64));
+       pemx_bist_status2.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS2(pcie_port));
+       /* Errata PCIE-14766 may cause the lower 6 bits to be randomly set on CN63XXp1 */
+       if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
+               pemx_bist_status2.u64 &= ~0x3full;
+       if (pemx_bist_status2.u64)
+               pr_notice("PCIe: BIST2 FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status2.u64));
+
+       /* Initialize the config space CSRs */
+       __cvmx_pcie_rc_initialize_config_space(pcie_port);
+
+       /* Enable gen2 speed selection */
+       pciercx_cfg515.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG515(pcie_port));
+       pciercx_cfg515.s.dsc = 1;
+       cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG515(pcie_port), pciercx_cfg515.u32);
+
+       /* Bring the link up */
+       if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port)) {
+               /*
+                * Some gen1 devices don't handle the gen 2 training
+                * correctly. Disable gen2 and try again with only
+                * gen1
+                */
+               union cvmx_pciercx_cfg031 pciercx_cfg031;
+               pciercx_cfg031.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG031(pcie_port));
+               pciercx_cfg031.s.mls = 1;
+               cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG031(pcie_port), pciercx_cfg031.u32);
+               if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port)) {
+                       pr_notice("PCIe: Link timeout on port %d, probably the slot is empty\n", pcie_port);
+                       return -1;
+               }
+       }
+
+       /* Store merge control (SLI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */
+       sli_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL);
+       sli_mem_access_ctl.s.max_word = 0;      /* Allow 16 words to combine */
+       sli_mem_access_ctl.s.timer = 127;       /* Wait up to 127 cycles for more data */
+       cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL, sli_mem_access_ctl.u64);
+
+       /* Setup Mem access SubDIDs */
+       mem_access_subid.u64 = 0;
+       mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */
+       mem_access_subid.s.nmerge = 0;  /* Allow merging as it works on CN6XXX. */
+       mem_access_subid.s.esr = 1;     /* Endian-swap for Reads. */
+       mem_access_subid.s.esw = 1;     /* Endian-swap for Writes. */
+       mem_access_subid.s.wtype = 0;   /* "No snoop" and "Relaxed ordering" are not set */
+       mem_access_subid.s.rtype = 0;   /* "No snoop" and "Relaxed ordering" are not set */
+       /* PCIe Adddress Bits <63:34>. */
+       if (OCTEON_IS_MODEL(OCTEON_CN68XX))
+               mem_access_subid.cn68xx.ba = 0;
+       else
+               mem_access_subid.cn63xx.ba = 0;
+
+       /*
+        * Setup mem access 12-15 for port 0, 16-19 for port 1,
+        * supplying 36 bits of address space.
+        */
+       for (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) {
+               cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64);
+               /* Set each SUBID to extend the addressable range */
+               __cvmx_increment_ba(&mem_access_subid);
+       }
+
+       /*
+        * Disable the peer to peer forwarding register. This must be
+        * setup by the OS after it enumerates the bus and assigns
+        * addresses to the PCIe busses.
+        */
+       for (i = 0; i < 4; i++) {
+               cvmx_write_csr(CVMX_PEMX_P2P_BARX_START(i, pcie_port), -1);
+               cvmx_write_csr(CVMX_PEMX_P2P_BARX_END(i, pcie_port), -1);
+       }
+
+       /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */
+       cvmx_write_csr(CVMX_PEMX_P2N_BAR0_START(pcie_port), 0);
+
+       /*
+        * Set Octeon's BAR2 to decode 0-2^41. Bar0 and Bar1 take
+        * precedence where they overlap. It also overlaps with the
+        * device addresses, so make sure the peer to peer forwarding
+        * is set right.
+        */
+       cvmx_write_csr(CVMX_PEMX_P2N_BAR2_START(pcie_port), 0);
+
+       /*
+        * Setup BAR2 attributes
+        * Relaxed Ordering (NPEI_CTL_PORTn[PTLP_RO,CTLP_RO, WAIT_COM])
+        * - PTLP_RO,CTLP_RO should normally be set (except for debug).
+        * - WAIT_COM=0 will likely work for all applications.
+        * Load completion relaxed ordering (NPEI_CTL_PORTn[WAITL_COM])
+        */
+       pemx_bar_ctl.u64 = cvmx_read_csr(CVMX_PEMX_BAR_CTL(pcie_port));
+       pemx_bar_ctl.s.bar1_siz = 3;  /* 256MB BAR1*/
+       pemx_bar_ctl.s.bar2_enb = 1;
+       pemx_bar_ctl.s.bar2_esx = 1;
+       pemx_bar_ctl.s.bar2_cax = 0;
+       cvmx_write_csr(CVMX_PEMX_BAR_CTL(pcie_port), pemx_bar_ctl.u64);
+       sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port));
+       sli_ctl_portx.s.ptlp_ro = 1;
+       sli_ctl_portx.s.ctlp_ro = 1;
+       sli_ctl_portx.s.wait_com = 0;
+       sli_ctl_portx.s.waitl_com = 0;
+       cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port), sli_ctl_portx.u64);
+
+       /* BAR1 follows BAR2 */
+       cvmx_write_csr(CVMX_PEMX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE);
+
+       bar1_index.u64 = 0;
+       bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22);
+       bar1_index.s.ca = 1;       /* Not Cached */
+       bar1_index.s.end_swp = 1;  /* Endian Swap mode */
+       bar1_index.s.addr_v = 1;   /* Valid entry */
+
+       for (i = 0; i < 16; i++) {
+               cvmx_write_csr(CVMX_PEMX_BAR1_INDEXX(i, pcie_port), bar1_index.u64);
+               /* 256MB / 16 >> 22 == 4 */
+               bar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22);
+       }
+
+       /*
+        * Allow config retries for 250ms. Count is based off the 5Ghz
+        * SERDES clock.
+        */
+       pemx_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port));
+       pemx_ctl_status.s.cfg_rtry = 250 * 5000000 / 0x10000;
+       cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pemx_ctl_status.u64);
+
+       /* Display the link status */
+       pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));
+       pr_notice("PCIe: Port %d link active, %d lanes, speed gen%d\n", pcie_port, pciercx_cfg032.s.nlw, pciercx_cfg032.s.ls);
+
+       return 0;
+}
+
+/**
+ * Initialize a PCIe port for use in host(RC) mode. It doesn't enumerate the bus.
+ *
+ * @pcie_port: PCIe port to initialize
+ *
+ * Returns Zero on success
+ */
+static int cvmx_pcie_rc_initialize(int pcie_port)
+{
+       int result;
+       if (octeon_has_feature(OCTEON_FEATURE_NPEI))
+               result = __cvmx_pcie_rc_initialize_gen1(pcie_port);
+       else
+               result = __cvmx_pcie_rc_initialize_gen2(pcie_port);
+       return result;
+}
+
+/* Above was cvmx-pcie.c, below original pcie.c */
+
 /**
  * Map a PCI device to the appropriate interrupt line
  *
@@ -1027,11 +1481,12 @@ int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev,
                 */
                while (dev->bus && dev->bus->parent)
                        dev = to_pci_dev(dev->bus->bridge);
-               /* If the root bus is number 0 and the PEX 8114 is the
+               /*
+                * If the root bus is number 0 and the PEX 8114 is the
                 * root, assume we are behind the miswired bus. We
                 * need to correct the swizzle level by two. Yuck.
                 */
-               if ((dev->bus->number == 0) &&
+               if ((dev->bus->number == 1) &&
                    (dev->vendor == 0x10b5) && (dev->device == 0x8114)) {
                        /*
                         * The pin field is one based, not zero. We
@@ -1048,39 +1503,73 @@ int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev,
        return pin - 1 + OCTEON_IRQ_PCI_INT0;
 }
 
-/**
+static  void set_cfg_read_retry(u32 retry_cnt)
+{
+       union cvmx_pemx_ctl_status pemx_ctl;
+       pemx_ctl.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(1));
+       pemx_ctl.s.cfg_rtry = retry_cnt;
+       cvmx_write_csr(CVMX_PEMX_CTL_STATUS(1), pemx_ctl.u64);
+}
+
+
+static u32 disable_cfg_read_retry(void)
+{
+       u32 retry_cnt;
+
+       union cvmx_pemx_ctl_status pemx_ctl;
+       pemx_ctl.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(1));
+       retry_cnt =  pemx_ctl.s.cfg_rtry;
+       pemx_ctl.s.cfg_rtry = 0;
+       cvmx_write_csr(CVMX_PEMX_CTL_STATUS(1), pemx_ctl.u64);
+       return retry_cnt;
+}
+
+static int is_cfg_retry(void)
+{
+       union cvmx_pemx_int_sum pemx_int_sum;
+       pemx_int_sum.u64 = cvmx_read_csr(CVMX_PEMX_INT_SUM(1));
+       if (pemx_int_sum.s.crs_dr)
+               return 1;
+       return 0;
+}
+
+/*
  * Read a value from configuration space
  *
- * @bus:
- * @devfn:
- * @reg:
- * @size:
- * @val:
- * Returns
  */
-static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus,
-                                         unsigned int devfn, int reg, int size,
-                                         u32 *val)
+static int octeon_pcie_read_config(unsigned int pcie_port, struct pci_bus *bus,
+                                  unsigned int devfn, int reg, int size,
+                                  u32 *val)
 {
        union octeon_cvmemctl cvmmemctl;
        union octeon_cvmemctl cvmmemctl_save;
        int bus_number = bus->number;
+       int cfg_retry = 0;
+       int retry_cnt = 0;
+       int max_retry_cnt = 10;
+       u32 cfg_retry_cnt = 0;
 
+       cvmmemctl_save.u64 = 0;
+       BUG_ON(pcie_port >= ARRAY_SIZE(enable_pcie_bus_num_war));
        /*
         * For the top level bus make sure our hardware bus number
-        * matches the software one.
+        * matches the software one
         */
        if (bus->parent == NULL) {
-               union cvmx_pciercx_cfg006 pciercx_cfg006;
-               pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port,
-                       CVMX_PCIERCX_CFG006(pcie_port));
-               if (pciercx_cfg006.s.pbnum != bus_number) {
-                       pciercx_cfg006.s.pbnum = bus_number;
-                       pciercx_cfg006.s.sbnum = bus_number;
-                       pciercx_cfg006.s.subbnum = bus_number;
-                       cvmx_pcie_cfgx_write(pcie_port,
-                               CVMX_PCIERCX_CFG006(pcie_port),
-                               pciercx_cfg006.u32);
+               if (enable_pcie_bus_num_war[pcie_port])
+                       bus_number = 0;
+               else {
+                       union cvmx_pciercx_cfg006 pciercx_cfg006;
+                       pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port,
+                                            CVMX_PCIERCX_CFG006(pcie_port));
+                       if (pciercx_cfg006.s.pbnum != bus_number) {
+                               pciercx_cfg006.s.pbnum = bus_number;
+                               pciercx_cfg006.s.sbnum = bus_number;
+                               pciercx_cfg006.s.subbnum = bus_number;
+                               cvmx_pcie_cfgx_write(pcie_port,
+                                           CVMX_PCIERCX_CFG006(pcie_port),
+                                           pciercx_cfg006.u32);
+                       }
                }
        }
 
@@ -1116,29 +1605,52 @@ static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus,
                 */
 #if 1
                /* Use this option if you aren't using either slot */
-               if (bus_number == 1)
+               if (bus_number == 2)
                        return PCIBIOS_FUNC_NOT_SUPPORTED;
 #elif 0
                /*
                 * Use this option if you are using the first slot but
                 * not the second.
                 */
-               if ((bus_number == 1) && (devfn >> 3 != 2))
+               if ((bus_number == 2) && (devfn >> 3 != 2))
                        return PCIBIOS_FUNC_NOT_SUPPORTED;
 #elif 0
                /*
                 * Use this option if you are using the second slot
                 * but not the first.
                 */
-               if ((bus_number == 1) && (devfn >> 3 != 3))
+               if ((bus_number == 2) && (devfn >> 3 != 3))
                        return PCIBIOS_FUNC_NOT_SUPPORTED;
 #elif 0
                /* Use this opion if you are using both slots */
-               if ((bus_number == 1) &&
+               if ((bus_number == 2) &&
                    !((devfn == (2 << 3)) || (devfn == (3 << 3))))
                        return PCIBIOS_FUNC_NOT_SUPPORTED;
 #endif
 
+               /* The following #if gives a more complicated example. This is
+                  the required checks for running a Nitrox CN16XX-NHBX in the
+                  slot of the EBH5600. This card has a PLX PCIe bridge with
+                  four Nitrox PLX parts behind it */
+#if 0
+               /* PLX bridge with 4 ports */
+               if ((bus_number == 4) &&
+                   !((devfn >> 3 >= 1) && (devfn >> 3 <= 4)))
+                       return PCIBIOS_FUNC_NOT_SUPPORTED;
+               /* Nitrox behind PLX 1 */
+               if ((bus_number == 5) && (devfn >> 3 != 0))
+                       return PCIBIOS_FUNC_NOT_SUPPORTED;
+               /* Nitrox behind PLX 2 */
+               if ((bus_number == 6) && (devfn >> 3 != 0))
+                       return PCIBIOS_FUNC_NOT_SUPPORTED;
+               /* Nitrox behind PLX 3 */
+               if ((bus_number == 7) && (devfn >> 3 != 0))
+                       return PCIBIOS_FUNC_NOT_SUPPORTED;
+               /* Nitrox behind PLX 4 */
+               if ((bus_number == 8) && (devfn >> 3 != 0))
+                       return PCIBIOS_FUNC_NOT_SUPPORTED;
+#endif
+
                /*
                 * Shorten the DID timeout so bus errors for PCIe
                 * config reads from non existent devices happen
@@ -1152,26 +1664,48 @@ static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus,
                __write_64bit_c0_register($11, 7, cvmmemctl.u64);
        }
 
-       switch (size) {
-       case 4:
-               *val = cvmx_pcie_config_read32(pcie_port, bus_number,
-                                              devfn >> 3, devfn & 0x7, reg);
+       if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && (enable_pcie_14459_war))
+               cfg_retry_cnt = disable_cfg_read_retry();
+
+       pr_debug("pcie_cfg_rd port=%d b=%d devfn=0x%03x reg=0x%03x"
+                " size=%d ", pcie_port, bus_number, devfn, reg, size);
+       do {
+               switch (size) {
+               case 4:
+                       *val = cvmx_pcie_config_read32(pcie_port, bus_number,
+                               devfn >> 3, devfn & 0x7, reg);
                break;
-       case 2:
-               *val = cvmx_pcie_config_read16(pcie_port, bus_number,
-                                              devfn >> 3, devfn & 0x7, reg);
+               case 2:
+                       *val = cvmx_pcie_config_read16(pcie_port, bus_number,
+                               devfn >> 3, devfn & 0x7, reg);
                break;
-       case 1:
-               *val = cvmx_pcie_config_read8(pcie_port, bus_number, devfn >> 3,
-                                             devfn & 0x7, reg);
+               case 1:
+                       *val = cvmx_pcie_config_read8(pcie_port, bus_number,
+                               devfn >> 3, devfn & 0x7, reg);
                break;
-       default:
-               return PCIBIOS_FUNC_NOT_SUPPORTED;
-       }
+               default:
+                       if (OCTEON_IS_MODEL(OCTEON_CN63XX))
+                               set_cfg_read_retry(cfg_retry_cnt);
+                       return PCIBIOS_FUNC_NOT_SUPPORTED;
+               }
+               if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) &&
+                       (enable_pcie_14459_war)) {
+                       cfg_retry = is_cfg_retry();
+                       retry_cnt++;
+                       if (retry_cnt > max_retry_cnt) {
+                               pr_err(" pcie cfg_read retries failed. retry_cnt=%d\n",
+                                      retry_cnt);
+                               cfg_retry = 0;
+                       }
+               }
+       } while (cfg_retry);
 
+       if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && (enable_pcie_14459_war))
+               set_cfg_read_retry(cfg_retry_cnt);
+       pr_debug("val=%08x  : tries=%02d\n", *val, retry_cnt);
        if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1) ||
            OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_1))
-               __write_64bit_c0_register($11, 7, cvmmemctl_save.u64);
+               write_c0_cvmmemctl(cvmmemctl_save.u64);
        return PCIBIOS_SUCCESSFUL;
 }
 
@@ -1187,42 +1721,56 @@ static int octeon_pcie1_read_config(struct pci_bus *bus, unsigned int devfn,
        return octeon_pcie_read_config(1, bus, devfn, reg, size, val);
 }
 
+static int octeon_dummy_read_config(struct pci_bus *bus, unsigned int devfn,
+                                   int reg, int size, u32 *val)
+{
+       return PCIBIOS_FUNC_NOT_SUPPORTED;
+}
 
-
-/**
+/*
  * Write a value to PCI configuration space
- *
- * @bus:
- * @devfn:
- * @reg:
- * @size:
- * @val:
- * Returns
  */
-static inline int octeon_pcie_write_config(int pcie_port, struct pci_bus *bus,
-                                          unsigned int devfn, int reg,
-                                          int size, u32 val)
+static int octeon_pcie_write_config(unsigned int pcie_port, struct pci_bus *bus,
+                                   unsigned int devfn, int reg,
+                                   int size, u32 val)
 {
        int bus_number = bus->number;
 
+       BUG_ON(pcie_port >= ARRAY_SIZE(enable_pcie_bus_num_war));
+
+       if ((bus->parent == NULL) && (enable_pcie_bus_num_war[pcie_port]))
+               bus_number = 0;
+
+       pr_debug("pcie_cfg_wr port=%d b=%d devfn=0x%03x"
+                " reg=0x%03x size=%d val=%08x\n", pcie_port, bus_number, devfn,
+                reg, size, val);
+
+
        switch (size) {
        case 4:
                cvmx_pcie_config_write32(pcie_port, bus_number, devfn >> 3,
                                         devfn & 0x7, reg, val);
-               return PCIBIOS_SUCCESSFUL;
+               break;
        case 2:
                cvmx_pcie_config_write16(pcie_port, bus_number, devfn >> 3,
                                         devfn & 0x7, reg, val);
-               return PCIBIOS_SUCCESSFUL;
+               break;
        case 1:
                cvmx_pcie_config_write8(pcie_port, bus_number, devfn >> 3,
                                        devfn & 0x7, reg, val);
-               return PCIBIOS_SUCCESSFUL;
+               break;
+       default:
+               return PCIBIOS_FUNC_NOT_SUPPORTED;
        }
 #if PCI_CONFIG_SPACE_DELAY
+       /*
+        * Delay on writes so that devices have time to come up. Some
+        * bridges need this to allow time for the secondary busses to
+        * work
+        */
        udelay(PCI_CONFIG_SPACE_DELAY);
 #endif
-       return PCIBIOS_FUNC_NOT_SUPPORTED;
+       return PCIBIOS_SUCCESSFUL;
 }
 
 static int octeon_pcie0_write_config(struct pci_bus *bus, unsigned int devfn,
@@ -1237,6 +1785,12 @@ static int octeon_pcie1_write_config(struct pci_bus *bus, unsigned int devfn,
        return octeon_pcie_write_config(1, bus, devfn, reg, size, val);
 }
 
+static int octeon_dummy_write_config(struct pci_bus *bus, unsigned int devfn,
+                                    int reg, int size, u32 val)
+{
+       return PCIBIOS_FUNC_NOT_SUPPORTED;
+}
+
 static struct pci_ops octeon_pcie0_ops = {
        octeon_pcie0_read_config,
        octeon_pcie0_write_config,
@@ -1279,6 +1833,35 @@ static struct pci_controller octeon_pcie1_controller = {
        .io_resource = &octeon_pcie1_io_resource,
 };
 
+static struct pci_ops octeon_dummy_ops = {
+       octeon_dummy_read_config,
+       octeon_dummy_write_config,
+};
+
+static struct resource octeon_dummy_mem_resource = {
+       .name = "Virtual PCIe MEM",
+       .flags = IORESOURCE_MEM,
+};
+
+static struct resource octeon_dummy_io_resource = {
+       .name = "Virtual PCIe IO",
+       .flags = IORESOURCE_IO,
+};
+
+static struct pci_controller octeon_dummy_controller = {
+       .pci_ops = &octeon_dummy_ops,
+       .mem_resource = &octeon_dummy_mem_resource,
+       .io_resource = &octeon_dummy_io_resource,
+};
+
+static int device_needs_bus_num_war(uint32_t deviceid)
+{
+#define IDT_VENDOR_ID 0x111d
+
+       if ((deviceid  & 0xffff) == IDT_VENDOR_ID)
+               return 1;
+       return 0;
+}
 
 /**
  * Initialize the Octeon PCIe controllers
@@ -1287,19 +1870,27 @@ static struct pci_controller octeon_pcie1_controller = {
  */
 static int __init octeon_pcie_setup(void)
 {
-       union cvmx_npei_ctl_status npei_ctl_status;
        int result;
+       int host_mode;
+       int srio_war15205 = 0, port;
+       union cvmx_sli_ctl_portx sli_ctl_portx;
+       union cvmx_sriox_status_reg sriox_status_reg;
 
        /* These chips don't have PCIe */
        if (!octeon_has_feature(OCTEON_FEATURE_PCIE))
                return 0;
 
+       /* No PCIe simulation */
+       if (octeon_is_simulation())
+               return 0;
+
+       /* Disable PCI if instructed on the command line */
+       if (pcie_disable)
+               return 0;
+
        /* Point pcibios_map_irq() to the PCIe version of it */
        octeon_pcibios_map_irq = octeon_pcie_pcibios_map_irq;
 
-       /* Use the PCIe based DMA mappings */
-       octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE;
-
        /*
         * PCIe I/O range. It is based on port 0 but includes up until
         * port 1's end.
@@ -1310,11 +1901,43 @@ static int __init octeon_pcie_setup(void)
                cvmx_pcie_get_io_base_address(1) -
                cvmx_pcie_get_io_base_address(0) + cvmx_pcie_get_io_size(1) - 1;
 
-       npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS);
-       if (npei_ctl_status.s.host_mode) {
+       /*
+        * Create a dummy PCIe controller to swallow up bus 0. IDT bridges
+        * don't work if the primary bus number is zero. Here we add a fake
+        * PCIe controller that the kernel will give bus 0. This allows
+        * us to not change the normal kernel bus enumeration
+        */
+       octeon_dummy_controller.io_map_base = -1;
+       octeon_dummy_controller.mem_resource->start = (1ull<<48);
+       octeon_dummy_controller.mem_resource->end = (1ull<<48);
+       register_pci_controller(&octeon_dummy_controller);
+
+       if (octeon_has_feature(OCTEON_FEATURE_NPEI)) {
+               union cvmx_npei_ctl_status npei_ctl_status;
+               npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS);
+               host_mode = npei_ctl_status.s.host_mode;
+               octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE;
+       } else {
+               union cvmx_mio_rst_ctlx mio_rst_ctl;
+               mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(0));
+               host_mode = mio_rst_ctl.s.host_mode;
+               octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE2;
+       }
+
+       if (host_mode) {
                pr_notice("PCIe: Initializing port 0\n");
+               /* CN63XX pass 1_x/2.0 errata PCIe-15205 */
+               if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) ||
+                       OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) {
+                       sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(0));
+                       if (sriox_status_reg.s.srio) {
+                               srio_war15205 += 1;      /* Port is SRIO */
+                               port = 0;
+                       }
+               }
                result = cvmx_pcie_rc_initialize(0);
                if (result == 0) {
+                       uint32_t device0;
                        /* Memory offsets are physical addresses */
                        octeon_pcie0_controller.mem_offset =
                                cvmx_pcie_get_mem_base_address(0);
@@ -1343,60 +1966,134 @@ static int __init octeon_pcie_setup(void)
                        octeon_pcie0_controller.io_resource->start = 4 << 10;
                        octeon_pcie0_controller.io_resource->end =
                                cvmx_pcie_get_io_size(0) - 1;
+                       msleep(100); /* Some devices need extra time */
                        register_pci_controller(&octeon_pcie0_controller);
+                       device0 = cvmx_pcie_config_read32(0, 0, 0, 0, 0);
+                       enable_pcie_bus_num_war[0] =
+                               device_needs_bus_num_war(device0);
                }
        } else {
                pr_notice("PCIe: Port 0 in endpoint mode, skipping.\n");
+               /* CN63XX pass 1_x/2.0 errata PCIe-15205 */
+               if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) ||
+                       OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) {
+                       srio_war15205 += 1;
+                       port = 0;
+               }
        }
 
-       /* Skip the 2nd port on CN52XX if port 0 is in 4 lane mode */
-       if (OCTEON_IS_MODEL(OCTEON_CN52XX)) {
-               union cvmx_npei_dbg_data npei_dbg_data;
-               npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
-               if (npei_dbg_data.cn52xx.qlm0_link_width)
-                       return 0;
+       if (octeon_has_feature(OCTEON_FEATURE_NPEI)) {
+               host_mode = 1;
+               /* Skip the 2nd port on CN52XX if port 0 is in 4 lane mode */
+               if (OCTEON_IS_MODEL(OCTEON_CN52XX)) {
+                       union cvmx_npei_dbg_data dbg_data;
+                       dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);
+                       if (dbg_data.cn52xx.qlm0_link_width)
+                               host_mode = 0;
+               }
+       } else {
+               union cvmx_mio_rst_ctlx mio_rst_ctl;
+               mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(1));
+               host_mode = mio_rst_ctl.s.host_mode;
        }
 
-       pr_notice("PCIe: Initializing port 1\n");
-       result = cvmx_pcie_rc_initialize(1);
-       if (result == 0) {
-               /* Memory offsets are physical addresses */
-               octeon_pcie1_controller.mem_offset =
-                       cvmx_pcie_get_mem_base_address(1);
-               /* IO offsets are Mips virtual addresses */
-               octeon_pcie1_controller.io_map_base =
-                       CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(1));
-               octeon_pcie1_controller.io_offset =
-                       cvmx_pcie_get_io_base_address(1) -
-                       cvmx_pcie_get_io_base_address(0);
-               /*
-                * To keep things similar to PCI, we start device
-                * addresses at the same place as PCI uisng big bar
-                * support. This normally translates to 4GB-256MB,
-                * which is the same as most x86 PCs.
-                */
-               octeon_pcie1_controller.mem_resource->start =
-                       cvmx_pcie_get_mem_base_address(1) + (4ul << 30) -
-                       (OCTEON_PCI_BAR1_HOLE_SIZE << 20);
-               octeon_pcie1_controller.mem_resource->end =
-                       cvmx_pcie_get_mem_base_address(1) +
-                       cvmx_pcie_get_mem_size(1) - 1;
-               /*
-                * Ports must be above 16KB for the ISA bus filtering
-                * in the PCI-X to PCI bridge.
-                */
-               octeon_pcie1_controller.io_resource->start =
-                       cvmx_pcie_get_io_base_address(1) -
-                       cvmx_pcie_get_io_base_address(0);
-               octeon_pcie1_controller.io_resource->end =
-                       octeon_pcie1_controller.io_resource->start +
-                       cvmx_pcie_get_io_size(1) - 1;
-               register_pci_controller(&octeon_pcie1_controller);
+       if (host_mode) {
+               pr_notice("PCIe: Initializing port 1\n");
+               /* CN63XX pass 1_x/2.0 errata PCIe-15205 */
+               if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) ||
+                       OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) {
+                       sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(1));
+                       if (sriox_status_reg.s.srio) {
+                               srio_war15205 += 1;      /* Port is SRIO */
+                               port = 1;
+                       }
+               }
+               result = cvmx_pcie_rc_initialize(1);
+               if (result == 0) {
+                       uint32_t device0;
+                       /* Memory offsets are physical addresses */
+                       octeon_pcie1_controller.mem_offset =
+                               cvmx_pcie_get_mem_base_address(1);
+                       /*
+                        * To calculate the address for accessing the 2nd PCIe device,
+                        * either 'io_map_base' (pci_iomap()), or 'mips_io_port_base'
+                        * (ioport_map()) value is added to
+                        * pci_resource_start(dev,bar)). The 'mips_io_port_base' is set
+                        * only once based on first PCIe. Also changing 'io_map_base'
+                        * based on first slot's value so that both the routines will
+                        * work properly.
+                        */
+                       octeon_pcie1_controller.io_map_base =
+                               CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(0));
+                       /* IO offsets are Mips virtual addresses */
+                       octeon_pcie1_controller.io_offset =
+                               cvmx_pcie_get_io_base_address(1) -
+                               cvmx_pcie_get_io_base_address(0);
+                       /*
+                        * To keep things similar to PCI, we start device
+                        * addresses at the same place as PCI uisng big bar
+                        * support. This normally translates to 4GB-256MB,
+                        * which is the same as most x86 PCs.
+                        */
+                       octeon_pcie1_controller.mem_resource->start =
+                               cvmx_pcie_get_mem_base_address(1) + (4ul << 30) -
+                               (OCTEON_PCI_BAR1_HOLE_SIZE << 20);
+                       octeon_pcie1_controller.mem_resource->end =
+                               cvmx_pcie_get_mem_base_address(1) +
+                               cvmx_pcie_get_mem_size(1) - 1;
+                       /*
+                        * Ports must be above 16KB for the ISA bus filtering
+                        * in the PCI-X to PCI bridge.
+                        */
+                       octeon_pcie1_controller.io_resource->start =
+                               cvmx_pcie_get_io_base_address(1) -
+                               cvmx_pcie_get_io_base_address(0);
+                       octeon_pcie1_controller.io_resource->end =
+                               octeon_pcie1_controller.io_resource->start +
+                               cvmx_pcie_get_io_size(1) - 1;
+                       msleep(100); /* Some devices need extra time */
+                       register_pci_controller(&octeon_pcie1_controller);
+                       device0 = cvmx_pcie_config_read32(1, 0, 0, 0, 0);
+                       enable_pcie_bus_num_war[1] =
+                               device_needs_bus_num_war(device0);
+               }
+       } else {
+               pr_notice("PCIe: Port 1 not in root complex mode, skipping.\n");
+               /* CN63XX pass 1_x/2.0 errata PCIe-15205  */
+               if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) ||
+                       OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) {
+                       srio_war15205 += 1;
+                       port = 1;
+               }
+       }
+
+       /*
+        * CN63XX pass 1_x/2.0 errata PCIe-15205 requires setting all
+        * of SRIO MACs SLI_CTL_PORT*[INT*_MAP] to similar value and
+        * all of PCIe Macs SLI_CTL_PORT*[INT*_MAP] to different value
+        * from the previous set values
+        */
+       if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) ||
+               OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) {
+               if (srio_war15205 == 1) {
+                       sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(port));
+                       sli_ctl_portx.s.inta_map = 1;
+                       sli_ctl_portx.s.intb_map = 1;
+                       sli_ctl_portx.s.intc_map = 1;
+                       sli_ctl_portx.s.intd_map = 1;
+                       cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(port), sli_ctl_portx.u64);
+
+                       sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(!port));
+                       sli_ctl_portx.s.inta_map = 0;
+                       sli_ctl_portx.s.intb_map = 0;
+                       sli_ctl_portx.s.intc_map = 0;
+                       sli_ctl_portx.s.intd_map = 0;
+                       cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(!port), sli_ctl_portx.u64);
+               }
        }
 
        octeon_pci_dma_init();
 
        return 0;
 }
-
 arch_initcall(octeon_pcie_setup);
index c841f083a7f55644d1d62829591ef26cdf954c15..bb57ed9ea2bd73c01a139500614c70f61d531cd1 100644 (file)
@@ -149,7 +149,7 @@ static int msp_hwbutton_register(struct hwbutton_interrupt *hirq)
                CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
        *CIC_EXT_CFG_REG = cic_ext;
 
-       return request_irq(hirq->irq, hwbutton_handler, IRQF_DISABLED,
+       return request_irq(hirq->irq, hwbutton_handler, 0,
                           hirq->name, hirq);
 }
 
index 655308a4e1cda2c02c6d63f9202531cc7ffaabd8..7a834b2f8a5f0b9dcaaad87672eff98d42d906b3 100644 (file)
@@ -209,7 +209,7 @@ void __init prom_init(void)
        default:
                /* we don't recognize the machine */
                mips_machtype  = MACH_UNKNOWN;
-               panic("***Bogosity factor five***, exiting\n");
+               panic("***Bogosity factor five***, exiting");
                break;
        }
 
index bec17901ff03aae58814451a16d13487ed1b8ff9..10170580a2def4501bb4f149c707d050a900246f 100644 (file)
@@ -51,13 +51,13 @@ static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 
 static struct irqaction irq_resched = {
        .handler        = ipi_resched_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU,
+       .flags          = IRQF_PERCPU,
        .name           = "IPI_resched"
 };
 
 static struct irqaction irq_call = {
        .handler        = ipi_call_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU,
+       .flags          = IRQF_PERCPU,
        .name           = "IPI_call"
 };
 
index 1ebe22bdadc87668c35587687434af376876bafc..ec684b8c3f7990b65e4ccf974a8e102457edad66 100644 (file)
@@ -167,13 +167,13 @@ static struct irq_chip level_irq_type = {
 
 static struct irqaction gic_action = {
        .handler =      no_action,
-       .flags =        IRQF_DISABLED | IRQF_NO_THREAD,
+       .flags =        IRQF_NO_THREAD,
        .name =         "GIC",
 };
 
 static struct irqaction timer_action = {
        .handler =      no_action,
-       .flags =        IRQF_DISABLED | IRQF_TIMER,
+       .flags =        IRQF_TIMER,
        .name =         "Timer",
 };
 
index 8836c6203df0994fcdd1084fba3c681ed7b483c7..831d6b369e9c7c19d49e94c21cc8dad87b36018d 100644 (file)
@@ -59,7 +59,7 @@ static irqreturn_t pnx8xxx_timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction pnx8xxx_timer_irq = {
        .handler        = pnx8xxx_timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags          = IRQF_PERCPU | IRQF_TIMER,
        .name           = "pnx8xxx_timer",
 };
 
@@ -72,7 +72,7 @@ static irqreturn_t monotonic_interrupt(int irq, void *dev_id)
 
 static struct irqaction monotonic_irqaction = {
        .handler = monotonic_interrupt,
-       .flags = IRQF_DISABLED | IRQF_TIMER,
+       .flags = IRQF_TIMER,
        .name = "Monotonic timer",
 };
 
index cc538493cae16b54b144b5e87565fec8b21c9be7..411cda9ee030737850846e8b0ed33f01822c9a1e 100644 (file)
@@ -4,7 +4,7 @@
 #
 
 obj-y  += ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \
-          ip22-platform.o ip22-reset.o ip22-setup.o
+          ip22-platform.o ip22-reset.o ip22-setup.o ip22-gio.o
 
 obj-$(CONFIG_SGI_IP22) += ip22-berr.o
 obj-$(CONFIG_SGI_IP28) += ip28-berr.o
diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c
new file mode 100644 (file)
index 0000000..f5ebc09
--- /dev/null
@@ -0,0 +1,428 @@
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include <asm/addrspace.h>
+#include <asm/paccess.h>
+#include <asm/gio_device.h>
+#include <asm/sgi/gio.h>
+#include <asm/sgi/hpc3.h>
+#include <asm/sgi/mc.h>
+#include <asm/sgi/ip22.h>
+
+static struct bus_type gio_bus_type;
+
+static struct {
+       const char *name;
+       __u8       id;
+} gio_name_table[] = {
+       { .name = "SGI Impact", .id = 0x10 },
+       { .name = "Phobos G160", .id = 0x35 },
+       /* fake IDs */
+       { .name = "SGI Newport", .id = 0x7e },
+       { .name = "SGI GR2/GR3", .id = 0x7f },
+};
+
+static struct device gio_bus = {
+       .init_name = "gio",
+};
+
+/**
+ * gio_match_device - Tell if an of_device structure has a matching
+ * gio_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct gio_device_id *gio_match_device(const struct gio_device_id *match,
+                    const struct gio_device *dev)
+{
+       const struct gio_device_id *ids;
+
+       for (ids = match; ids->id != 0xff; ids++)
+               if (ids->id == dev->id.id)
+                       return ids;
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(gio_match_device);
+
+struct gio_device *gio_dev_get(struct gio_device *dev)
+{
+       struct device *tmp;
+
+       if (!dev)
+               return NULL;
+       tmp = get_device(&dev->dev);
+       if (tmp)
+               return to_gio_device(tmp);
+       else
+               return NULL;
+}
+EXPORT_SYMBOL_GPL(gio_dev_get);
+
+void gio_dev_put(struct gio_device *dev)
+{
+       if (dev)
+               put_device(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(gio_dev_put);
+
+/**
+ * gio_release_dev - free an gio device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this gio device are
+ * done.
+ */
+void gio_release_dev(struct device *dev)
+{
+       struct gio_device *giodev;
+
+       giodev = to_gio_device(dev);
+       kfree(giodev);
+}
+EXPORT_SYMBOL_GPL(gio_release_dev);
+
+int gio_device_register(struct gio_device *giodev)
+{
+       giodev->dev.bus = &gio_bus_type;
+       giodev->dev.parent = &gio_bus;
+       return device_register(&giodev->dev);
+}
+EXPORT_SYMBOL_GPL(gio_device_register);
+
+void gio_device_unregister(struct gio_device *giodev)
+{
+       device_unregister(&giodev->dev);
+}
+EXPORT_SYMBOL_GPL(gio_device_unregister);
+
+static int gio_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+       struct gio_driver *gio_drv = to_gio_driver(drv);
+
+       return gio_match_device(gio_drv->id_table, gio_dev) != NULL;
+}
+
+static int gio_device_probe(struct device *dev)
+{
+       int error = -ENODEV;
+       struct gio_driver *drv;
+       struct gio_device *gio_dev;
+       const struct gio_device_id *match;
+
+       drv = to_gio_driver(dev->driver);
+       gio_dev = to_gio_device(dev);
+
+       if (!drv->probe)
+               return error;
+
+       gio_dev_get(gio_dev);
+
+       match = gio_match_device(drv->id_table, gio_dev);
+       if (match)
+               error = drv->probe(gio_dev, match);
+       if (error)
+               gio_dev_put(gio_dev);
+
+       return error;
+}
+
+static int gio_device_remove(struct device *dev)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+       struct gio_driver *drv = to_gio_driver(dev->driver);
+
+       if (dev->driver && drv->remove)
+               drv->remove(gio_dev);
+       return 0;
+}
+
+static int gio_device_suspend(struct device *dev, pm_message_t state)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+       struct gio_driver *drv = to_gio_driver(dev->driver);
+       int error = 0;
+
+       if (dev->driver && drv->suspend)
+               error = drv->suspend(gio_dev, state);
+       return error;
+}
+
+static int gio_device_resume(struct device *dev)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+       struct gio_driver *drv = to_gio_driver(dev->driver);
+       int error = 0;
+
+       if (dev->driver && drv->resume)
+               error = drv->resume(gio_dev);
+       return error;
+}
+
+static void gio_device_shutdown(struct device *dev)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+       struct gio_driver *drv = to_gio_driver(dev->driver);
+
+       if (dev->driver && drv->shutdown)
+               drv->shutdown(gio_dev);
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+                            char *buf)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+       int len = snprintf(buf, PAGE_SIZE, "gio:%x\n", gio_dev->id.id);
+
+       return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static ssize_t name_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       struct gio_device *giodev;
+
+       giodev = to_gio_device(dev);
+       return sprintf(buf, "%s", giodev->name);
+}
+
+static ssize_t id_show(struct device *dev,
+                      struct device_attribute *attr, char *buf)
+{
+       struct gio_device *giodev;
+
+       giodev = to_gio_device(dev);
+       return sprintf(buf, "%x", giodev->id.id);
+}
+
+static struct device_attribute gio_dev_attrs[] = {
+       __ATTR_RO(modalias),
+       __ATTR_RO(name),
+       __ATTR_RO(id),
+       __ATTR_NULL,
+};
+
+static int gio_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct gio_device *gio_dev = to_gio_device(dev);
+
+       add_uevent_var(env, "MODALIAS=gio:%x", gio_dev->id.id);
+       return 0;
+}
+
+int gio_register_driver(struct gio_driver *drv)
+{
+       /* initialize common driver fields */
+       if (!drv->driver.name)
+               drv->driver.name = drv->name;
+       if (!drv->driver.owner)
+               drv->driver.owner = drv->owner;
+       drv->driver.bus = &gio_bus_type;
+
+       /* register with core */
+       return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(gio_register_driver);
+
+void gio_unregister_driver(struct gio_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(gio_unregister_driver);
+
+void gio_set_master(struct gio_device *dev)
+{
+       u32 tmp = sgimc->giopar;
+
+       switch (dev->slotno) {
+       case 0:
+               tmp |= SGIMC_GIOPAR_MASTERGFX;
+               break;
+       case 1:
+               tmp |= SGIMC_GIOPAR_MASTEREXP0;
+               break;
+       case 2:
+               tmp |= SGIMC_GIOPAR_MASTEREXP1;
+               break;
+       }
+       sgimc->giopar = tmp;
+}
+EXPORT_SYMBOL_GPL(gio_set_master);
+
+void ip22_gio_set_64bit(int slotno)
+{
+       u32 tmp = sgimc->giopar;
+
+       switch (slotno) {
+       case 0:
+               tmp |= SGIMC_GIOPAR_GFX64;
+               break;
+       case 1:
+               tmp |= SGIMC_GIOPAR_EXP064;
+               break;
+       case 2:
+               tmp |= SGIMC_GIOPAR_EXP164;
+               break;
+       }
+       sgimc->giopar = tmp;
+}
+
+static int ip22_gio_id(unsigned long addr, u32 *res)
+{
+       u8 tmp8;
+       u8 tmp16;
+       u32 tmp32;
+       u8 *ptr8;
+       u16 *ptr16;
+       u32 *ptr32;
+
+       ptr32 = (void *)CKSEG1ADDR(addr);
+       if (!get_dbe(tmp32, ptr32)) {
+               /*
+                * We got no DBE, but this doesn't mean anything.
+                * If GIO is pipelined (which can't be disabled
+                * for GFX slot) we don't get a DBE, but we see
+                * the transfer size as data. So we do an 8bit
+                * and a 16bit access and check whether the common
+                * data matches
+                */
+               ptr8 = (void *)CKSEG1ADDR(addr + 3);
+               get_dbe(tmp8, ptr8);
+               ptr16 = (void *)CKSEG1ADDR(addr + 2);
+               get_dbe(tmp16, ptr16);
+               if (tmp8 == (tmp16 & 0xff) &&
+                   tmp8 == (tmp32 & 0xff) &&
+                   tmp16 == (tmp32 & 0xffff)) {
+                       *res = tmp32;
+                       return 1;
+               }
+       }
+       return 0; /* nothing here */
+}
+
+#define HQ2_MYSTERY_OFFS       0x6A07C
+#define NEWPORT_USTATUS_OFFS   0xF133C
+
+static int ip22_is_gr2(unsigned long addr)
+{
+       u32 tmp;
+       u32 *ptr;
+
+       /* HQ2 only allows 32bit accesses */
+       ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS);
+       if (!get_dbe(tmp, ptr)) {
+               if (tmp == 0xdeadbeef)
+                       return 1;
+       }
+       return 0;
+}
+
+
+static void ip22_check_gio(int slotno, unsigned long addr)
+{
+       const char *name = "Unknown";
+       struct gio_device *gio_dev;
+       u32 tmp;
+       __u8 id;
+       int i;
+
+       /* first look for GR2/GR3 by checking mystery register */
+       if (ip22_is_gr2(addr))
+               tmp = 0x7f;
+       else {
+               if (!ip22_gio_id(addr, &tmp)) {
+                       /*
+                        * no GIO signature at start address of slot, but
+                        * Newport doesn't have one, so let's check usea
+                        * status register
+                        */
+                       if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp))
+                               tmp = 0x7e;
+                       else
+                               tmp = 0;
+               }
+       }
+       if (tmp) {
+               id = GIO_ID(tmp);
+               if (tmp & GIO_32BIT_ID) {
+                       if (tmp & GIO_64BIT_IFACE)
+                               ip22_gio_set_64bit(slotno);
+               }
+               for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) {
+                       if (id == gio_name_table[i].id) {
+                               name = gio_name_table[i].name;
+                               break;
+                       }
+               }
+               printk(KERN_INFO "GIO: slot %d : %s (id %x)\n",
+                      slotno, name, id);
+               gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL);
+               gio_dev->name = name;
+               gio_dev->slotno = slotno;
+               gio_dev->id.id = id;
+               gio_dev->resource.start = addr;
+               gio_dev->resource.end = addr + 0x3fffff;
+               gio_dev->resource.flags = IORESOURCE_MEM;
+               dev_set_name(&gio_dev->dev, "%d", slotno);
+               gio_device_register(gio_dev);
+       } else
+               printk(KERN_INFO "GIO: slot %d : Empty\n", slotno);
+}
+
+static struct bus_type gio_bus_type = {
+       .name      = "gio",
+       .dev_attrs = gio_dev_attrs,
+       .match     = gio_bus_match,
+       .probe     = gio_device_probe,
+       .remove    = gio_device_remove,
+       .suspend   = gio_device_suspend,
+       .resume    = gio_device_resume,
+       .shutdown  = gio_device_shutdown,
+       .uevent    = gio_device_uevent,
+};
+
+static struct resource gio_bus_resource = {
+       .start = GIO_SLOT_GFX_BASE,
+       .end   = GIO_SLOT_GFX_BASE + 0x9fffff,
+       .name  = "GIO Bus",
+       .flags = IORESOURCE_MEM,
+};
+
+int __init ip22_gio_init(void)
+{
+       unsigned int pbdma __maybe_unused;
+       int ret;
+
+       ret = device_register(&gio_bus);
+       if (ret)
+               return ret;
+
+       ret = bus_register(&gio_bus_type);
+       if (!ret) {
+               request_resource(&iomem_resource, &gio_bus_resource);
+               printk(KERN_INFO "GIO: Probing bus...\n");
+
+               if (ip22_is_fullhouse() ||
+                   !get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) {
+                       /* Indigo2 and ChallengeS */
+                       ip22_check_gio(0, GIO_SLOT_GFX_BASE);
+                       ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
+               } else {
+                       /* Indy */
+                       ip22_check_gio(0, GIO_SLOT_GFX_BASE);
+                       ip22_check_gio(1, GIO_SLOT_EXP0_BASE);
+                       ip22_check_gio(2, GIO_SLOT_EXP1_BASE);
+               }
+       } else
+               device_unregister(&gio_bus);
+
+       return ret;
+}
+
+subsys_initcall(ip22_gio_init);
index f72c336ea27b3b059ca4c6a169e3b1cefce23d47..3f2b7633f946a6bbe020d80f4643ad253789da82 100644 (file)
@@ -155,32 +155,32 @@ static void __irq_entry indy_buserror_irq(void)
 
 static struct irqaction local0_cascade = {
        .handler        = no_action,
-       .flags          = IRQF_DISABLED | IRQF_NO_THREAD,
+       .flags          = IRQF_NO_THREAD,
        .name           = "local0 cascade",
 };
 
 static struct irqaction local1_cascade = {
        .handler        = no_action,
-       .flags          = IRQF_DISABLED | IRQF_NO_THREAD,
+       .flags          = IRQF_NO_THREAD,
        .name           = "local1 cascade",
 };
 
 static struct irqaction buserr = {
        .handler        = no_action,
-       .flags          = IRQF_DISABLED | IRQF_NO_THREAD,
+       .flags          = IRQF_NO_THREAD,
        .name           = "Bus Error",
 };
 
 static struct irqaction map0_cascade = {
        .handler        = no_action,
-       .flags          = IRQF_DISABLED | IRQF_NO_THREAD,
+       .flags          = IRQF_NO_THREAD,
        .name           = "mapable0 cascade",
 };
 
 #ifdef USE_LIO3_IRQ
 static struct irqaction map1_cascade = {
        .handler        = no_action,
-       .flags          = IRQF_DISABLED | IRQF_NO_THREAD,
+       .flags          = IRQF_NO_THREAD,
        .name           = "mapable1 cascade",
 };
 #define SGI_INTERRUPTS SGINT_END
index d22262ee68533ccc949f27fe926d0741a3a575a2..75ada8a9713b355e4ae6a841a44fde5dff84731e 100644 (file)
@@ -139,11 +139,11 @@ void __init sgimc_init(void)
         *         zero.
         */
        /* don't touch parity settings for IP28 */
-#ifndef CONFIG_SGI_IP28
        tmp = sgimc->cpuctrl0;
-       tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM |
-               SGIMC_CCTRL0_R4KNOCHKPARR);
+#ifndef CONFIG_SGI_IP28
+       tmp |= SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM;
 #endif
+       tmp |= SGIMC_CCTRL0_R4KNOCHKPARR;
        sgimc->cpuctrl0 = tmp;
 
        /* Step 3: Setup the MC write buffer depth, this is controlled
@@ -178,7 +178,8 @@ void __init sgimc_init(void)
         */
 
        /* First the basic invariants across all GIO64 implementations. */
-       tmp = SGIMC_GIOPAR_HPC64;       /* All 1st HPC's interface at 64bits */
+       tmp = sgimc->giopar & SGIMC_GIOPAR_GFX64; /* keep gfx 64bit settings */
+       tmp |= SGIMC_GIOPAR_HPC64;      /* All 1st HPC's interface at 64bits */
        tmp |= SGIMC_GIOPAR_ONEBUS;     /* Only one physical GIO bus exists */
 
        if (ip22_is_fullhouse()) {
@@ -193,7 +194,6 @@ void __init sgimc_init(void)
                        tmp |= SGIMC_GIOPAR_PLINEEXP0;  /* exp[01] pipelined */
                        tmp |= SGIMC_GIOPAR_PLINEEXP1;
                        tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA masters */
-                       tmp |= SGIMC_GIOPAR_GFX64;      /* GFX at 64 bits */
                }
        } else {
                /* Guiness specific settings. */
index 5e6621349471daf28b2c65eeff0941257d69df59..c7bdfe43df5b312da20dc5b886748caa68d09605 100644 (file)
@@ -26,9 +26,6 @@
 #include <asm/sgi/hpc3.h>
 #include <asm/sgi/ip22.h>
 
-unsigned long sgi_gfxaddr;
-EXPORT_SYMBOL_GPL(sgi_gfxaddr);
-
 extern void ip22_be_init(void) __init;
 
 void __init plat_mem_setup(void)
@@ -78,22 +75,4 @@ void __init plat_mem_setup(void)
                prom_flags |= PROM_FLAG_USE_AS_CONSOLE;
                add_preferred_console("arc", 0, NULL);
        }
-
-#if defined(CONFIG_VT) && defined(CONFIG_SGI_NEWPORT_CONSOLE)
-       {
-               ULONG *gfxinfo;
-               ULONG * (*__vec)(void) = (void *) (long)
-                       *((_PULONG *)(long)((PROMBLOCK)->pvector + 0x20));
-
-               gfxinfo = __vec();
-               sgi_gfxaddr = ((gfxinfo[1] >= 0xa0000000
-                              && gfxinfo[1] <= 0xc0000000)
-                              ? gfxinfo[1] - 0xa0000000 : 0);
-
-               /* newport addresses? */
-               if (sgi_gfxaddr == 0x1f0f0000 || sgi_gfxaddr == 0x1f4f0000) {
-                       conswitchp = &newport_con;
-               }
-       }
-#endif
 }
index f90dce315e0477b960cd68e01002794612bbb101..23642238c6895296dc6a311ea52ba546c2eed460 100644 (file)
@@ -73,7 +73,7 @@ static inline int alloc_level(int cpu, int irq)
 
        level = find_first_zero_bit(hub->irq_alloc_mask, LEVELS_PER_SLICE);
        if (level >= LEVELS_PER_SLICE)
-               panic("Cpu %d flooded with devices\n", cpu);
+               panic("Cpu %d flooded with devices", cpu);
 
        __set_bit(level, hub->irq_alloc_mask);
        si->level_to_irq[level] = irq;
@@ -96,7 +96,7 @@ static inline int find_level(cpuid_t *cpunum, int irq)
                        }
        }
 
-       panic("Could not identify cpu/level for irq %d\n", irq);
+       panic("Could not identify cpu/level for irq %d", irq);
 }
 
 /*
@@ -116,7 +116,7 @@ static int ms1bit(unsigned long x)
 }
 
 /*
- * This code is unnecessarily complex, because we do IRQF_DISABLED
+ * This code is unnecessarily complex, because we do
  * intr enabling. Basically, once we grab the set of intrs we need
  * to service, we must mask _all_ these interrupts; firstly, to make
  * sure the same intr does not intr again, causing recursion that
index ef74f3267f9102bfa870e713311520d94fe6c723..13cfeab50528e7bdef1e384784ac9b6f7c19f699 100644 (file)
@@ -91,7 +91,7 @@ static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id)
 
 struct irqaction hub_rt_irqaction = {
        .handler        = hub_rt_counter_handler,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags          = IRQF_PERCPU | IRQF_TIMER,
        .name           = "hub-rt",
 };
 
index c65ea76d56c78a831b24603522b35207088c9a59..a092860d5196818b1f4942dc4070af4abdac1bdc 100644 (file)
@@ -113,13 +113,11 @@ extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id);
 
 static struct irqaction memerr_irq = {
        .handler = crime_memerr_intr,
-       .flags = IRQF_DISABLED,
        .name = "CRIME memory error",
 };
 
 static struct irqaction cpuerr_irq = {
        .handler = crime_cpuerr_intr,
-       .flags = IRQF_DISABLED,
        .name = "CRIME CPU error",
 };
 
index e8e72bb3a9afa13e2a0f91655be9af684f2d81fe..5a4ec75382e2eb301e302b5ab658a42ed565a56d 100644 (file)
@@ -42,7 +42,7 @@ static irqreturn_t sni_isa_irq_handler(int dummy, void *p)
 struct irqaction sni_isa_irq = {
        .handler = sni_isa_irq_handler,
        .name = "ISA",
-       .flags = IRQF_SHARED | IRQF_DISABLED
+       .flags = IRQF_SHARED
 };
 
 /*
index ec0be14996a41cc20dc4ba1e489a61edbdf5acf2..494c9e7847aa173bd2ff7c395cb538385106ba9b 100644 (file)
@@ -68,7 +68,7 @@ static irqreturn_t a20r_interrupt(int irq, void *dev_id)
 
 static struct irqaction a20r_irqaction = {
        .handler        = a20r_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+       .flags          = IRQF_PERCPU | IRQF_TIMER,
        .name           = "a20r-timer",
 };
 
index 85a87de17eb46f1197f92771a76b7812282aa4ff..682efb0c108d22576992c9f554653e9329916d3b 100644 (file)
@@ -262,7 +262,7 @@ txx9_i8259_irq_setup(int irq)
        int err;
 
        init_i8259_irqs();
-       err = request_irq(irq, &i8259_interrupt, IRQF_DISABLED|IRQF_SHARED,
+       err = request_irq(irq, &i8259_interrupt, IRQF_SHARED,
                          "cascade(i8259)", (void *)(long)irq);
        if (!err)
                printk(KERN_INFO "PCI-ISA bridge PIC (irq %d)\n", irq);
index ca3e20508c77556a77492b85da8697d8eba4ced6..95a4d42c3a06e6f23a814d333ab6ce111d2b86a5 100644 (file)
@@ -110,7 +110,7 @@ extern asmlinkage void nmi_handler(void);
 extern asmlinkage void misalignment(struct pt_regs *, enum exception_code);
 
 extern void die(const char *, struct pt_regs *, enum exception_code)
-       ATTRIB_NORET;
+       __noreturn;
 
 extern int die_if_no_fixup(const char *, struct pt_regs *, enum exception_code);
 
index 789b1df41fcb2f08edb73cc433cab3d868696eb4..02a0ca6f13cee992cefa459462206d6971be6db3 100644 (file)
 #ifndef _ASM_PARAM_H
 #define _ASM_PARAM_H
 
-#ifdef __KERNEL__
-#define HZ             CONFIG_HZ       /* Internal kernel timer frequency */
-#define USER_HZ                100             /* .. some user interfaces are in
-                                        * "ticks" */
-#define CLOCKS_PER_SEC (USER_HZ)       /* like times() */
-#endif
+#include <asm-generic/param.h>
 
-#ifndef HZ
-#define HZ             100
-#endif
-
-#define EXEC_PAGESIZE  4096
-
-#ifndef NOGROUP
-#define NOGROUP                (-1)
-#endif
-
-#define MAXHOSTNAMELEN 64      /* max length of hostname */
 #define COMMAND_LINE_SIZE 256
 
 #endif /* _ASM_PARAM_H */
index 98ca185097a519bb4bc58938ee848234e81db3b4..09958358601a3637ec4d811826b3f84fea1a6f96 100644 (file)
@@ -11,5 +11,5 @@ clean-files := *.dtb.S
 
 #DTC_FLAGS ?= -p 1024
 
-$(obj)/%.dtb: $(src)/dts/%.dts
-       $(call cmd,dtc)
+$(obj)/%.dtb: $(src)/dts/%.dts FORCE
+       $(call if_changed_dep,dtc)
index 9ce66e9d1c2b845275c41aaaf290a5fb5e123ba1..7213ec9e594cd4de25b912c17693dca742f46192 100644 (file)
@@ -196,7 +196,6 @@ typedef unsigned int elf_caddr_t;
        /* offset pc for priv. level */                 \
        pc |= 3;                                        \
                                                        \
-       set_fs(USER_DS);                                \
        regs->iasq[0] = spaceid;                        \
        regs->iasq[1] = spaceid;                        \
        regs->iaoq[0] = pc;                             \
@@ -299,7 +298,6 @@ on downward growing arches, it looks like this:
        elf_addr_t pc = (elf_addr_t)new_pc | 3;         \
        elf_caddr_t *argv = (elf_caddr_t *)bprm->exec + 1;      \
                                                        \
-       set_fs(USER_DS);                                \
        regs->iasq[0] = spaceid;                        \
        regs->iasq[1] = spaceid;                        \
        regs->iaoq[0] = pc;                             \
index 4b4b9181a1a0aef8df25667f4a0229bb275e8d7f..62c60b87d0395d66b02a929095fe37bbb33b849b 100644 (file)
@@ -192,7 +192,6 @@ void flush_thread(void)
        /* Only needs to handle fpu stuff or perf monitors.
        ** REVISIT: several arches implement a "lazy fpu state".
        */
-       set_fs(USER_DS);
 }
 
 void release_thread(struct task_struct *dead_task)
index 15986e70799ccbcb78d7aafc924d01bcf167a7a9..8844a17ce8ede20213d2c64d25d0d764587e834e 100644 (file)
@@ -345,8 +345,8 @@ $(obj)/treeImage.%: vmlinux $(obj)/%.dtb $(wrapperbits)
        $(call if_changed,wrap,treeboot-$*,,$(obj)/$*.dtb)
 
 # Rule to build device tree blobs
-$(obj)/%.dtb: $(src)/dts/%.dts
-       $(call cmd,dtc)
+$(obj)/%.dtb: $(src)/dts/%.dts FORCE
+       $(call if_changed_dep,dtc)
 
 # If there isn't a platform selected then just strip the vmlinux.
 ifeq (,$(image-y))
index 48223f9b8728d5e1433c6d13ab9c1c583780d2cb..78a205162fd7d48ad0b1a3de78bd42453dae5c0a 100644 (file)
@@ -86,7 +86,18 @@ struct pt_regs {
 #define instruction_pointer(regs) ((regs)->nip)
 #define user_stack_pointer(regs) ((regs)->gpr[1])
 #define kernel_stack_pointer(regs) ((regs)->gpr[1])
-#define regs_return_value(regs) ((regs)->gpr[3])
+static inline int is_syscall_success(struct pt_regs *regs)
+{
+       return !(regs->ccr & 0x10000000);
+}
+
+static inline long regs_return_value(struct pt_regs *regs)
+{
+       if (is_syscall_success(regs))
+               return regs->gpr[3];
+       else
+               return -regs->gpr[3];
+}
 
 #ifdef CONFIG_SMP
 extern unsigned long profile_pc(struct pt_regs *regs);
index 7c66ce13da89ff793a2ea18fa0e8d5b5448da41d..0a48bf5db6c84bfbf0152a9b3c52e83b9f43646d 100644 (file)
@@ -50,12 +50,6 @@ static int __init powersave_off(char *arg)
 }
 __setup("powersave=off", powersave_off);
 
-#if defined(CONFIG_PPC_PSERIES) && defined(CONFIG_TRACEPOINTS)
-static const bool idle_uses_rcu = 1;
-#else
-static const bool idle_uses_rcu;
-#endif
-
 /*
  * The body of the idle task.
  */
@@ -67,8 +61,7 @@ void cpu_idle(void)
        set_thread_flag(TIF_POLLING_NRFLAG);
        while (1) {
                tick_nohz_idle_enter();
-               if (!idle_uses_rcu)
-                       rcu_idle_enter();
+               rcu_idle_enter();
 
                while (!need_resched() && !cpu_should_die()) {
                        ppc64_runlatch_off();
@@ -106,8 +99,7 @@ void cpu_idle(void)
 
                HMT_medium();
                ppc64_runlatch_on();
-               if (!idle_uses_rcu)
-                       rcu_idle_exit();
+               rcu_idle_exit();
                tick_nohz_idle_exit();
                preempt_enable_no_resched();
                if (cpu_should_die())
index e63f2e7d2efb029fca417c344ecee0d9e96daf88..affe5dcce7f465bcfcae706e3c3a1ebb24b44dbe 100644 (file)
 #include <asm/hw_irq.h>
 #include <asm/io.h>
 
-typedef NORET_TYPE void (*relocate_new_kernel_t)(
+typedef void (*relocate_new_kernel_t)(
                                unsigned long indirection_page,
                                unsigned long reboot_code_buffer,
-                               unsigned long start_address) ATTRIB_NORET;
+                               unsigned long start_address) __noreturn;
 
 /*
  * This is a generic machine_kexec function suitable at least for
index 26ccbf77dd4124958f83808b002e3a0176b3f6d4..d7f609086a99925dc9b2a47b479079fbf5b466d4 100644 (file)
@@ -307,9 +307,9 @@ static union thread_union kexec_stack __init_task_data =
 struct paca_struct kexec_paca;
 
 /* Our assembly helper, in kexec_stub.S */
-extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start,
-                                       void *image, void *control,
-                                       void (*clear_all)(void)) ATTRIB_NORET;
+extern void kexec_sequence(void *newstack, unsigned long start,
+                          void *image, void *control,
+                          void (*clear_all)(void)) __noreturn;
 
 /* too late to fail here */
 void default_machine_kexec(struct kimage *image)
index 5de73dbd15c7e404a16257ae5239e9b1af293f65..5b43325402bcc8e5435c1e2804685e81cb24df72 100644 (file)
@@ -1724,22 +1724,20 @@ long do_syscall_trace_enter(struct pt_regs *regs)
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_enter(regs, regs->gpr[0]);
 
-       if (unlikely(current->audit_context)) {
 #ifdef CONFIG_PPC64
-               if (!is_32bit_task())
-                       audit_syscall_entry(AUDIT_ARCH_PPC64,
-                                           regs->gpr[0],
-                                           regs->gpr[3], regs->gpr[4],
-                                           regs->gpr[5], regs->gpr[6]);
-               else
+       if (!is_32bit_task())
+               audit_syscall_entry(AUDIT_ARCH_PPC64,
+                                   regs->gpr[0],
+                                   regs->gpr[3], regs->gpr[4],
+                                   regs->gpr[5], regs->gpr[6]);
+       else
 #endif
-                       audit_syscall_entry(AUDIT_ARCH_PPC,
-                                           regs->gpr[0],
-                                           regs->gpr[3] & 0xffffffff,
-                                           regs->gpr[4] & 0xffffffff,
-                                           regs->gpr[5] & 0xffffffff,
-                                           regs->gpr[6] & 0xffffffff);
-       }
+               audit_syscall_entry(AUDIT_ARCH_PPC,
+                                   regs->gpr[0],
+                                   regs->gpr[3] & 0xffffffff,
+                                   regs->gpr[4] & 0xffffffff,
+                                   regs->gpr[5] & 0xffffffff,
+                                   regs->gpr[6] & 0xffffffff);
 
        return ret ?: regs->gpr[0];
 }
@@ -1748,9 +1746,7 @@ void do_syscall_trace_leave(struct pt_regs *regs)
 {
        int step;
 
-       if (unlikely(current->audit_context))
-               audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
-                                  regs->result);
+       audit_syscall_exit(regs);
 
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_exit(regs, regs->result);
index 4ff3d8e411a76ce6ee53258bd63d42ea4f472863..3feefc3842a85471ae33c03307d4ad2907894856 100644 (file)
@@ -58,7 +58,7 @@ static int distance_lookup_table[MAX_NUMNODES][MAX_DISTANCE_REF_POINTS];
  * Allocate node_to_cpumask_map based on number of available nodes
  * Requires node_possible_map to be valid.
  *
- * Note: node_to_cpumask() is not valid until after this is done.
+ * Note: cpumask_of_node() is not valid until after this is done.
  */
 static void __init setup_node_to_cpumask_map(void)
 {
index fd05fdee576a8d13af9c1ce748754747478d56ec..3ce73d0052b17a2b2e934af3daf33499d0afd4ac 100644 (file)
@@ -36,6 +36,7 @@ BEGIN_FTR_SECTION;                                            \
        b       1f;                                             \
 END_FTR_SECTION(0, 1);                                         \
        ld      r12,hcall_tracepoint_refcount@toc(r2);          \
+       std     r12,32(r1);                                     \
        cmpdi   r12,0;                                          \
        beq+    1f;                                             \
        mflr    r0;                                             \
@@ -74,7 +75,7 @@ END_FTR_SECTION(0, 1);                                                \
 BEGIN_FTR_SECTION;                                             \
        b       1f;                                             \
 END_FTR_SECTION(0, 1);                                         \
-       ld      r12,hcall_tracepoint_refcount@toc(r2);          \
+       ld      r12,32(r1);                                     \
        cmpdi   r12,0;                                          \
        beq+    1f;                                             \
        mflr    r0;                                             \
index 948e0e3b3547a28624b0a524b2b0de54eccd9460..7bc73af6c7b9e875f489563192866a2a8abbfea3 100644 (file)
@@ -546,6 +546,13 @@ void __trace_hcall_entry(unsigned long opcode, unsigned long *args)
        unsigned long flags;
        unsigned int *depth;
 
+       /*
+        * We cannot call tracepoints inside RCU idle regions which
+        * means we must not trace H_CEDE.
+        */
+       if (opcode == H_CEDE)
+               return;
+
        local_irq_save(flags);
 
        depth = &__get_cpu_var(hcall_trace_depth);
@@ -556,8 +563,6 @@ void __trace_hcall_entry(unsigned long opcode, unsigned long *args)
        (*depth)++;
        preempt_disable();
        trace_hcall_entry(opcode, args);
-       if (opcode == H_CEDE)
-               rcu_idle_enter();
        (*depth)--;
 
 out:
@@ -570,6 +575,9 @@ void __trace_hcall_exit(long opcode, unsigned long retval,
        unsigned long flags;
        unsigned int *depth;
 
+       if (opcode == H_CEDE)
+               return;
+
        local_irq_save(flags);
 
        depth = &__get_cpu_var(hcall_trace_depth);
@@ -578,8 +586,6 @@ void __trace_hcall_exit(long opcode, unsigned long retval,
                goto out;
 
        (*depth)++;
-       if (opcode == H_CEDE)
-               rcu_idle_exit();
        trace_hcall_exit(opcode, retval, retbuf);
        preempt_enable();
        (*depth)--;
index 330a57b7c17ca48ee997fa2508c9ec29716efd5d..36f957f31842f60688a7485f297ed6181dc926c9 100644 (file)
@@ -638,7 +638,6 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
                /* These are almost always orderly shutdowns. */
                return;
        case KMSG_DUMP_OOPS:
-       case KMSG_DUMP_KEXEC:
                break;
        case KMSG_DUMP_PANIC:
                panicking = true;
index fc71d8a6709b53f34306fc6a286ad7d69770b372..8e88e2221771bf41f2c379d460da4e8fd3499cdd 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef _ASM_S390_CHPID_H
-#define _ASM_S390_CHPID_H _ASM_S390_CHPID_H
+#define _ASM_S390_CHPID_H
 
 #include <linux/string.h>
 #include <linux/types.h>
index a9bc5c36b32ae094678b6ac534c7795161f6443d..fb1bedd3dc0d7d3c42b41ae7af7d63ea13d26a0f 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef _ASM_S390_ITCW_H
-#define _ASM_S390_ITCW_H _ASM_S390_ITCW_H
+#define _ASM_S390_ITCW_H
 
 #include <linux/types.h>
 #include <asm/fcx.h>
index 4e9c8ae0a6375211d10119c8be241ac1543c68d0..d49760e63506dd401df1e2f81da69982ed6a468c 100644 (file)
 
 #include <asm-generic/mman.h>
 
-#if defined(__KERNEL__) && !defined(__ASSEMBLY__) && defined(CONFIG_64BIT)
+#if defined(__KERNEL__)
+#if !defined(__ASSEMBLY__) && defined(CONFIG_64BIT)
 int s390_mmap_check(unsigned long addr, unsigned long len);
 #define arch_mmap_check(addr,len,flags)        s390_mmap_check(addr,len)
 #endif
+#endif
 
 #endif /* __S390_MMAN_H__ */
index 27272f6a14c2fbecf4f9a6f1a29cba7986f3bb92..d25843a6a91512409aca2d56458d06cd9f90922f 100644 (file)
@@ -236,7 +236,7 @@ static inline unsigned long __rewind_psw(psw_t psw, unsigned long ilc)
 /*
  * Function to drop a processor into disabled wait state
  */
-static inline void ATTRIB_NORET disabled_wait(unsigned long code)
+static inline void __noreturn disabled_wait(unsigned long code)
 {
         unsigned long ctl_buf;
         psw_t dw_psw;
index 56da355678f4aa7feed766a016b84282381451ba..aeb77f01798504cd250aebbd8748516b8c64e113 100644 (file)
@@ -541,9 +541,13 @@ struct user_regs_struct
 #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
 #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
 #define user_stack_pointer(regs)((regs)->gprs[15])
-#define regs_return_value(regs)((regs)->gprs[2])
 #define profile_pc(regs) instruction_pointer(regs)
 
+static inline long regs_return_value(struct pt_regs *regs)
+{
+       return regs->gprs[2];
+}
+
 int regs_query_register_offset(const char *name);
 const char *regs_query_register_name(unsigned int offset);
 unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset);
index fab88431a06fcb70a92b4fdfe0f475d269be67a6..0fd2e863e114e161ced171368521a3512ea2571d 100644 (file)
@@ -30,7 +30,7 @@ struct mcck_struct {
 
 static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck);
 
-static NORET_TYPE void s390_handle_damage(char *msg)
+static void s390_handle_damage(char *msg)
 {
        smp_send_stop();
        disabled_wait((unsigned long) __builtin_return_address(0));
index 573bc29551ef471fee58b89d02df0ea0ff956503..9d82ed4bcb273a91bd6c4875d204218da2d420a2 100644 (file)
@@ -740,20 +740,17 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_enter(regs, regs->gprs[2]);
 
-       if (unlikely(current->audit_context))
-               audit_syscall_entry(is_compat_task() ?
-                                       AUDIT_ARCH_S390 : AUDIT_ARCH_S390X,
-                                   regs->gprs[2], regs->orig_gpr2,
-                                   regs->gprs[3], regs->gprs[4],
-                                   regs->gprs[5]);
+       audit_syscall_entry(is_compat_task() ?
+                               AUDIT_ARCH_S390 : AUDIT_ARCH_S390X,
+                           regs->gprs[2], regs->orig_gpr2,
+                           regs->gprs[3], regs->gprs[4],
+                           regs->gprs[5]);
        return ret ?: regs->gprs[2];
 }
 
 asmlinkage void do_syscall_trace_exit(struct pt_regs *regs)
 {
-       if (unlikely(current->audit_context))
-               audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]),
-                                  regs->gprs[2]);
+       audit_syscall_exit(regs);
 
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_exit(regs, regs->gprs[2]);
index 74d49c01783b26912f7e611b8d7f483020d27009..6418e95c2b6b87f3350cc735e20d7e3bcfab484c 100644 (file)
@@ -207,7 +207,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
        .clock_source = LCDC_CLK_EXTERNAL,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
-               .bpp = 16,
+               .fourcc = V4L2_PIX_FMT_RGB565,
                .interface_type = RGB18,
                .clock_divider = 1,
                .lcd_cfg = ap325rxa_lcdc_modes,
index 9a19fb07276cba9304c3a34fed5febd8414fd378..033ef2ba621f008c5c92ac0dace7808a5b21035b 100644 (file)
@@ -324,7 +324,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
        .ch[0] = {
                .interface_type = RGB18,
                .chan = LCDC_CHAN_MAINLCD,
-               .bpp = 16,
+               .fourcc = V4L2_PIX_FMT_RGB565,
                .lcd_size_cfg = { /* 7.0 inch */
                        .width = 152,
                        .height = 91,
index 5c3c713668480815b63cc24bc4896fc2689bf22f..2a18b06abdafcd8220cfc99c03fac52e98ca2efd 100644 (file)
@@ -143,7 +143,7 @@ static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = {
        .clock_source = LCDC_CLK_BUS,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
-               .bpp = 16,
+               .fourcc = V4L2_PIX_FMT_RGB565,
                .interface_type = SYS18,
                .clock_divider = 6,
                .flags = LCDC_FLAGS_DWPOL,
index f8f9377d5684ecfb9a817a35eab371d78400bb7e..68c3d6f4289665f5c4b7e38265d7f1ce5db6c81b 100644 (file)
@@ -241,7 +241,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = {
        .clock_source = LCDC_CLK_BUS,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
-               .bpp = 16,
+               .fourcc = V4L2_PIX_FMT_RGB565,
                .interface_type = RGB16,
                .clock_divider = 2,
                .lcd_cfg = migor_lcd_modes,
@@ -255,7 +255,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = {
        .clock_source = LCDC_CLK_PERIPHERAL,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
-               .bpp = 16,
+               .fourcc = V4L2_PIX_FMT_RGB565,
                .interface_type = SYS16A,
                .clock_divider = 10,
                .lcd_cfg = migor_lcd_modes,
index 2585733e9bce205a4f1a20638af38c88921e4e4a..036fe1adaef17b4367259a71d59e3ba642f9f64a 100644 (file)
@@ -179,7 +179,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
        .clock_source = LCDC_CLK_EXTERNAL,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
-               .bpp = 16,
+               .fourcc = V4L2_PIX_FMT_RGB565,
                .clock_divider = 1,
                .lcd_size_cfg = { /* 7.0 inch */
                        .width = 152,
index 6c2239cca1a2d86204a52ecef53ab5514f8a6073..2d3e906aa72252d3b827a12405546465127d5f78 100644 (file)
@@ -76,7 +76,10 @@ struct pt_dspregs {
 #ifdef __KERNEL__
 
 #define MAX_REG_OFFSET         offsetof(struct pt_regs, tra)
-#define regs_return_value(_regs)       ((_regs)->regs[0])
+static inline long regs_return_value(struct pt_regs *regs)
+{
+       return regs->regs[0];
+}
 
 #endif /* __KERNEL__ */
 
index bf9be7764d69f250978300cfb5c3e556e0d71e76..eb3fcceaf64b7bb5942a081637e78c5d479bad86 100644 (file)
@@ -13,7 +13,10 @@ struct pt_regs {
 #ifdef __KERNEL__
 
 #define MAX_REG_OFFSET         offsetof(struct pt_regs, tregs[7])
-#define regs_return_value(_regs)       ((_regs)->regs[3])
+static inline long regs_return_value(struct pt_regs *regs)
+{
+       return regs->regs[3];
+}
 
 #endif /* __KERNEL__ */
 
index aaf6d59c201227b52c431e6be891868d756a5fda..7ec6651781255e375f971c3645d73eb46f870063 100644 (file)
@@ -70,7 +70,7 @@ void show_regs(struct pt_regs * regs)
 /*
  * Create a kernel thread
  */
-ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
+__noreturn void kernel_thread_helper(void *arg, int (*fn)(void *))
 {
        do_exit(fn(arg));
 }
index 210c1cabcb7fd3fe0903442c40c56d37a34b2ccc..cbd4e4bb9fc526796fbbd8b79a60847e0493bfb2 100644 (file)
@@ -285,7 +285,7 @@ void show_regs(struct pt_regs *regs)
 /*
  * Create a kernel thread
  */
-ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
+__noreturn void kernel_thread_helper(void *arg, int (*fn)(void *))
 {
        do_exit(fn(arg));
 }
index 92b3c276339a3a50d95a027c1d2a2e902a507ee3..a3e651563763aaabf76818e68729a53bc98aeaf7 100644 (file)
@@ -518,10 +518,9 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_enter(regs, regs->regs[0]);
 
-       if (unlikely(current->audit_context))
-               audit_syscall_entry(audit_arch(), regs->regs[3],
-                                   regs->regs[4], regs->regs[5],
-                                   regs->regs[6], regs->regs[7]);
+       audit_syscall_entry(audit_arch(), regs->regs[3],
+                           regs->regs[4], regs->regs[5],
+                           regs->regs[6], regs->regs[7]);
 
        return ret ?: regs->regs[0];
 }
@@ -530,9 +529,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
 {
        int step;
 
-       if (unlikely(current->audit_context))
-               audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]),
-                                  regs->regs[0]);
+       audit_syscall_exit(regs);
 
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_exit(regs, regs->regs[0]);
index c8f97649f354b5f4b80366b79a95c9a9a0f4d4bb..3d0080b5c976bb9b19fbbc8ac5116239c7d841e3 100644 (file)
@@ -536,10 +536,9 @@ asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs)
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_enter(regs, regs->regs[9]);
 
-       if (unlikely(current->audit_context))
-               audit_syscall_entry(audit_arch(), regs->regs[1],
-                                   regs->regs[2], regs->regs[3],
-                                   regs->regs[4], regs->regs[5]);
+       audit_syscall_entry(audit_arch(), regs->regs[1],
+                           regs->regs[2], regs->regs[3],
+                           regs->regs[4], regs->regs[5]);
 
        return ret ?: regs->regs[9];
 }
@@ -548,9 +547,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
 {
        int step;
 
-       if (unlikely(current->audit_context))
-               audit_syscall_exit(AUDITSC_RESULT(regs->regs[9]),
-                                  regs->regs[9]);
+       audit_syscall_exit(regs);
 
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_exit(regs, regs->regs[9]);
index a0e1bcf843a1ed5f9931a89c6cc63d4cd636d4ae..c00c3b5c2806edfac2b2b7f44f79045ae1bfec01 100644 (file)
@@ -207,7 +207,15 @@ do {       current_thread_info()->syscall_noerror = 1; \
 #define instruction_pointer(regs) ((regs)->tpc)
 #define instruction_pointer_set(regs, val) ((regs)->tpc = (val))
 #define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP])
-#define regs_return_value(regs) ((regs)->u_regs[UREG_I0])
+static inline int is_syscall_success(struct pt_regs *regs)
+{
+       return !(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY));
+}
+
+static inline long regs_return_value(struct pt_regs *regs)
+{
+       return regs->u_regs[UREG_I0];
+}
 #ifdef CONFIG_SMP
 extern unsigned long profile_pc(struct pt_regs *);
 #else
index 988e5d8ed11a228f8fd985d15ab9ee4f2d54ba9c..215900fce21b0f4bfd637a83585a9540e30c4662 100644 (file)
@@ -16,8 +16,6 @@
 
 #ifdef __KERNEL__
 
-#include <linux/compat.h>
-
 #ifdef CONFIG_COMPAT
 
 struct compat_siginfo;
index 96ee50a806613b782ce11e8627f1911ede3fde3f..9388844cd88c5afa47f3a24027019a96d11895ba 100644 (file)
@@ -1071,32 +1071,22 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_enter(regs, regs->u_regs[UREG_G1]);
 
-       if (unlikely(current->audit_context) && !ret)
-               audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
-                                    AUDIT_ARCH_SPARC :
-                                    AUDIT_ARCH_SPARC64),
-                                   regs->u_regs[UREG_G1],
-                                   regs->u_regs[UREG_I0],
-                                   regs->u_regs[UREG_I1],
-                                   regs->u_regs[UREG_I2],
-                                   regs->u_regs[UREG_I3]);
+       audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
+                            AUDIT_ARCH_SPARC :
+                            AUDIT_ARCH_SPARC64),
+                           regs->u_regs[UREG_G1],
+                           regs->u_regs[UREG_I0],
+                           regs->u_regs[UREG_I1],
+                           regs->u_regs[UREG_I2],
+                           regs->u_regs[UREG_I3]);
 
        return ret;
 }
 
 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
 {
-#ifdef CONFIG_AUDITSYSCALL
-       if (unlikely(current->audit_context)) {
-               unsigned long tstate = regs->tstate;
-               int result = AUDITSC_SUCCESS;
+       audit_syscall_exit(regs);
 
-               if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
-                       result = AUDITSC_FAILURE;
-
-               audit_syscall_exit(result, regs->u_regs[UREG_I0]);
-       }
-#endif
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_exit(regs, regs->u_regs[UREG_G1]);
 
index 1e1e616783ebfdd50ba937df77391816026ecaff..1e5e49aad54877e5664f5a0d56964845f8ad4b76 100644 (file)
@@ -23,7 +23,8 @@
 
 #include <asm-generic/signal.h>
 
-#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+#if defined(__KERNEL__)
+#if !defined(__ASSEMBLY__)
 struct pt_regs;
 int restore_sigcontext(struct pt_regs *, struct sigcontext __user *);
 int setup_sigcontext(struct sigcontext __user *, struct pt_regs *);
@@ -33,5 +34,6 @@ void signal_fault(const char *type, struct pt_regs *,
 void trace_unhandled_signal(const char *type, struct pt_regs *regs,
                            unsigned long address, int signo);
 #endif
+#endif
 
 #endif /* _ASM_TILE_SIGNAL_H */
index e00d7179989e24946a20185709224d9afd97f1be..6255f2eab112c9fcae9f5f4cab1d9462a9e12477 100644 (file)
@@ -248,11 +248,11 @@ static void setup_quasi_va_is_pa(void)
 }
 
 
-NORET_TYPE void machine_kexec(struct kimage *image)
+void machine_kexec(struct kimage *image)
 {
        void *reboot_code_buffer;
-       NORET_TYPE void (*rnk)(unsigned long, void *, unsigned long)
-               ATTRIB_NORET;
+       void (*rnk)(unsigned long, void *, unsigned long)
+               __noreturn;
 
        /* Mask all interrupts before starting to reboot. */
        interrupt_mask_set_mask(~0ULL);
index 7730af6ec13feba4898ca3a8e85e3e416c57c33d..28688e6d96d795c3f860f5343524584b0cefb994 100644 (file)
@@ -64,7 +64,8 @@ USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -D__KERNEL__,,\
 #This will adjust *FLAGS accordingly to the platform.
 include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS)
 
-KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/include
+KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/include \
+                  -I$(HOST_DIR)/include/generated
 
 # -Derrno=kernel_errno - This turns all kernel references to errno into
 # kernel_errno to separate them from the libc errno.  This allows -fno-common
@@ -96,6 +97,10 @@ endef
 
 KBUILD_KCONFIG := $(HOST_DIR)/um/Kconfig
 
+archheaders:
+       $(Q)$(MAKE) -C '$(srctree)' KBUILD_SRC= \
+               ARCH=$(SUBARCH) O='$(objtree)' archheaders
+
 archprepare: include/generated/user_constants.h
 
 LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static
@@ -135,7 +140,7 @@ archclean:
 
 # Generated files
 
-$(HOST_DIR)/um/user-offsets.s: FORCE
+$(HOST_DIR)/um/user-offsets.s: __headers FORCE
        $(Q)$(MAKE) $(build)=$(HOST_DIR)/um $@
 
 define filechk_gen-asm-offsets
index c9da32b0c707015c19db39b49785cd8b0610a35a..06b190390505f848a095648d2c555bd9d996604d 100644 (file)
@@ -167,17 +167,15 @@ void syscall_trace(struct uml_pt_regs *regs, int entryexit)
        int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit;
        int tracesysgood;
 
-       if (unlikely(current->audit_context)) {
-               if (!entryexit)
-                       audit_syscall_entry(HOST_AUDIT_ARCH,
-                                           UPT_SYSCALL_NR(regs),
-                                           UPT_SYSCALL_ARG1(regs),
-                                           UPT_SYSCALL_ARG2(regs),
-                                           UPT_SYSCALL_ARG3(regs),
-                                           UPT_SYSCALL_ARG4(regs));
-               else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
-                                       UPT_SYSCALL_RET(regs));
-       }
+       if (!entryexit)
+               audit_syscall_entry(HOST_AUDIT_ARCH,
+                                   UPT_SYSCALL_NR(regs),
+                                   UPT_SYSCALL_ARG1(regs),
+                                   UPT_SYSCALL_ARG2(regs),
+                                   UPT_SYSCALL_ARG3(regs),
+                                   UPT_SYSCALL_ARG4(regs));
+       else
+               audit_syscall_exit(regs);
 
        /* Fake a debug trap */
        if (is_singlestep)
index 028079065af6c55ac518969a6b5c1d8ae321b6c3..7cab8c08e6d1d2eee802397c9bc17ea0f7b1bbc1 100644 (file)
@@ -1,3 +1,4 @@
 boot/compressed/vmlinux
 tools/test_get_len
+tools/insn_sanity
 
index a150f4c35e945035001047136e704f01fb7f1e73..864cc6e6ac8e300d35b45c6b749f2ee93555c891 100644 (file)
@@ -60,6 +60,9 @@ config X86
        select PERF_EVENTS
        select HAVE_PERF_EVENTS_NMI
        select ANON_INODES
+       select HAVE_ALIGNED_STRUCT_PAGE if SLUB && !M386
+       select HAVE_CMPXCHG_LOCAL if !M386
+       select HAVE_CMPXCHG_DOUBLE
        select HAVE_ARCH_KMEMCHECK
        select HAVE_USER_RETURN_NOTIFIER
        select ARCH_BINFMT_ELF_RANDOMIZE_PIE
@@ -122,16 +125,6 @@ config HAVE_LATENCYTOP_SUPPORT
 config MMU
        def_bool y
 
-config ZONE_DMA
-       bool "DMA memory allocation support" if EXPERT
-       default y
-       help
-         DMA memory allocation support allows devices with less than 32-bit
-         addressing to allocate within the first 16MB of address space.
-         Disable if no such devices will be used.
-
-         If unsure, say Y.
-
 config SBUS
        bool
 
@@ -252,6 +245,16 @@ source "kernel/Kconfig.freezer"
 
 menu "Processor type and features"
 
+config ZONE_DMA
+       bool "DMA memory allocation support" if EXPERT
+       default y
+       help
+         DMA memory allocation support allows devices with less than 32-bit
+         addressing to allocate within the first 16MB of address space.
+         Disable if no such devices will be used.
+
+         If unsure, say Y.
+
 source "kernel/time/Kconfig"
 
 config SMP
index e3ca7e0d858c9203fe787244b6022193c7bc7769..3c57033e22118f2ce7771d10fa8305193c94af20 100644 (file)
@@ -309,12 +309,6 @@ config X86_INTERNODE_CACHE_SHIFT
 config X86_CMPXCHG
        def_bool X86_64 || (X86_32 && !M386)
 
-config CMPXCHG_LOCAL
-       def_bool X86_64 || (X86_32 && !M386)
-
-config CMPXCHG_DOUBLE
-       def_bool y
-
 config X86_L1_CACHE_SHIFT
        int
        default "7" if MPENTIUM4 || MPSC
index b02e509072a790b1fbea3387f8749b5326beb822..209ba1294592c406bd735df889f43f6272acbddb 100644 (file)
@@ -117,6 +117,12 @@ KBUILD_CFLAGS += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,)
 KBUILD_CFLAGS += $(mflags-y)
 KBUILD_AFLAGS += $(mflags-y)
 
+###
+# Syscall table generation
+
+archheaders:
+       $(Q)$(MAKE) $(build)=arch/x86/syscalls all
+
 ###
 # Kernel objects
 
index 52d0ccfcf6eafbc84fe0d66270b165b34101639d..455646e0e53282ad97721c4c04420de09e36f3d2 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_signal.o
+obj-$(CONFIG_IA32_EMULATION) += nosyscall.o syscall_ia32.o
 
 sysv-$(CONFIG_SYSVIPC) := ipc32.o
 obj-$(CONFIG_IA32_EMULATION) += $(sysv-y)
index 3e274564f6bf0d89f06b489484eb7d86faa049d6..e3e734005e19c1849dfb6f6be7a5b26f2fc9b374 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/segment.h>
 #include <asm/irqflags.h>
 #include <linux/linkage.h>
+#include <linux/err.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
 #include <linux/elf-em.h>
@@ -27,8 +28,6 @@
 
        .section .entry.text, "ax"
 
-#define IA32_NR_syscalls ((ia32_syscall_end - ia32_sys_call_table)/8)
-
        .macro IA32_ARG_FIXUP noebp=0
        movl    %edi,%r8d
        .if \noebp
@@ -191,7 +190,7 @@ sysexit_from_sys_call:
        movl %ebx,%edx                  /* 3rd arg: 1st syscall arg */
        movl %eax,%esi                  /* 2nd arg: syscall number */
        movl $AUDIT_ARCH_I386,%edi      /* 1st arg: audit arch */
-       call audit_syscall_entry
+       call __audit_syscall_entry
        movl RAX-ARGOFFSET(%rsp),%eax   /* reload syscall number */
        cmpq $(IA32_NR_syscalls-1),%rax
        ja ia32_badsys
@@ -208,12 +207,13 @@ sysexit_from_sys_call:
        TRACE_IRQS_ON
        sti
        movl %eax,%esi          /* second arg, syscall return value */
-       cmpl $0,%eax            /* is it < 0? */
-       setl %al                /* 1 if so, 0 if not */
+       cmpl $-MAX_ERRNO,%eax   /* is it an error ? */
+       jbe 1f
+       movslq %eax, %rsi       /* if error sign extend to 64 bits */
+1:     setbe %al               /* 1 if error, 0 if not */
        movzbl %al,%edi         /* zero-extend that into %edi */
-       inc %edi /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */
-       call audit_syscall_exit
-       movl RAX-ARGOFFSET(%rsp),%eax   /* reload syscall return value */
+       call __audit_syscall_exit
+       movq RAX-ARGOFFSET(%rsp),%rax   /* reload syscall return value */
        movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi
        cli
        TRACE_IRQS_OFF
@@ -447,9 +447,6 @@ ia32_badsys:
        movq $-ENOSYS,%rax
        jmp ia32_sysret
 
-quiet_ni_syscall:
-       movq $-ENOSYS,%rax
-       ret
        CFI_ENDPROC
        
        .macro PTREGSCALL label, func, arg
@@ -494,357 +491,3 @@ ia32_ptregs_common:
        jmp  ia32_sysret        /* misbalances the return cache */
        CFI_ENDPROC
 END(ia32_ptregs_common)
-
-       .section .rodata,"a"
-       .align 8
-ia32_sys_call_table:
-       .quad sys_restart_syscall
-       .quad sys_exit
-       .quad stub32_fork
-       .quad sys_read
-       .quad sys_write
-       .quad compat_sys_open           /* 5 */
-       .quad sys_close
-       .quad sys32_waitpid
-       .quad sys_creat
-       .quad sys_link
-       .quad sys_unlink                /* 10 */
-       .quad stub32_execve
-       .quad sys_chdir
-       .quad compat_sys_time
-       .quad sys_mknod
-       .quad sys_chmod         /* 15 */
-       .quad sys_lchown16
-       .quad quiet_ni_syscall                  /* old break syscall holder */
-       .quad sys_stat
-       .quad sys32_lseek
-       .quad sys_getpid                /* 20 */
-       .quad compat_sys_mount  /* mount  */
-       .quad sys_oldumount     /* old_umount  */
-       .quad sys_setuid16
-       .quad sys_getuid16
-       .quad compat_sys_stime  /* stime */             /* 25 */
-       .quad compat_sys_ptrace /* ptrace */
-       .quad sys_alarm
-       .quad sys_fstat /* (old)fstat */
-       .quad sys_pause
-       .quad compat_sys_utime  /* 30 */
-       .quad quiet_ni_syscall  /* old stty syscall holder */
-       .quad quiet_ni_syscall  /* old gtty syscall holder */
-       .quad sys_access
-       .quad sys_nice  
-       .quad quiet_ni_syscall  /* 35 */        /* old ftime syscall holder */
-       .quad sys_sync
-       .quad sys32_kill
-       .quad sys_rename
-       .quad sys_mkdir
-       .quad sys_rmdir         /* 40 */
-       .quad sys_dup
-       .quad sys_pipe
-       .quad compat_sys_times
-       .quad quiet_ni_syscall                  /* old prof syscall holder */
-       .quad sys_brk           /* 45 */
-       .quad sys_setgid16
-       .quad sys_getgid16
-       .quad sys_signal
-       .quad sys_geteuid16
-       .quad sys_getegid16     /* 50 */
-       .quad sys_acct
-       .quad sys_umount                        /* new_umount */
-       .quad quiet_ni_syscall                  /* old lock syscall holder */
-       .quad compat_sys_ioctl
-       .quad compat_sys_fcntl64                /* 55 */
-       .quad quiet_ni_syscall                  /* old mpx syscall holder */
-       .quad sys_setpgid
-       .quad quiet_ni_syscall                  /* old ulimit syscall holder */
-       .quad sys_olduname
-       .quad sys_umask         /* 60 */
-       .quad sys_chroot
-       .quad compat_sys_ustat
-       .quad sys_dup2
-       .quad sys_getppid
-       .quad sys_getpgrp               /* 65 */
-       .quad sys_setsid
-       .quad sys32_sigaction
-       .quad sys_sgetmask
-       .quad sys_ssetmask
-       .quad sys_setreuid16    /* 70 */
-       .quad sys_setregid16
-       .quad sys32_sigsuspend
-       .quad compat_sys_sigpending
-       .quad sys_sethostname
-       .quad compat_sys_setrlimit      /* 75 */
-       .quad compat_sys_old_getrlimit  /* old_getrlimit */
-       .quad compat_sys_getrusage
-       .quad compat_sys_gettimeofday
-       .quad compat_sys_settimeofday
-       .quad sys_getgroups16   /* 80 */
-       .quad sys_setgroups16
-       .quad compat_sys_old_select
-       .quad sys_symlink
-       .quad sys_lstat
-       .quad sys_readlink              /* 85 */
-       .quad sys_uselib
-       .quad sys_swapon
-       .quad sys_reboot
-       .quad compat_sys_old_readdir
-       .quad sys32_mmap                /* 90 */
-       .quad sys_munmap
-       .quad sys_truncate
-       .quad sys_ftruncate
-       .quad sys_fchmod
-       .quad sys_fchown16              /* 95 */
-       .quad sys_getpriority
-       .quad sys_setpriority
-       .quad quiet_ni_syscall                  /* old profil syscall holder */
-       .quad compat_sys_statfs
-       .quad compat_sys_fstatfs                /* 100 */
-       .quad sys_ioperm
-       .quad compat_sys_socketcall
-       .quad sys_syslog
-       .quad compat_sys_setitimer
-       .quad compat_sys_getitimer      /* 105 */
-       .quad compat_sys_newstat
-       .quad compat_sys_newlstat
-       .quad compat_sys_newfstat
-       .quad sys_uname
-       .quad stub32_iopl               /* 110 */
-       .quad sys_vhangup
-       .quad quiet_ni_syscall  /* old "idle" system call */
-       .quad sys32_vm86_warning        /* vm86old */ 
-       .quad compat_sys_wait4
-       .quad sys_swapoff               /* 115 */
-       .quad compat_sys_sysinfo
-       .quad sys32_ipc
-       .quad sys_fsync
-       .quad stub32_sigreturn
-       .quad stub32_clone              /* 120 */
-       .quad sys_setdomainname
-       .quad sys_newuname
-       .quad sys_modify_ldt
-       .quad compat_sys_adjtimex
-       .quad sys32_mprotect            /* 125 */
-       .quad compat_sys_sigprocmask
-       .quad quiet_ni_syscall          /* create_module */
-       .quad sys_init_module
-       .quad sys_delete_module
-       .quad quiet_ni_syscall          /* 130  get_kernel_syms */
-       .quad sys32_quotactl
-       .quad sys_getpgid
-       .quad sys_fchdir
-       .quad quiet_ni_syscall  /* bdflush */
-       .quad sys_sysfs         /* 135 */
-       .quad sys_personality
-       .quad quiet_ni_syscall  /* for afs_syscall */
-       .quad sys_setfsuid16
-       .quad sys_setfsgid16
-       .quad sys_llseek                /* 140 */
-       .quad compat_sys_getdents
-       .quad compat_sys_select
-       .quad sys_flock
-       .quad sys_msync
-       .quad compat_sys_readv          /* 145 */
-       .quad compat_sys_writev
-       .quad sys_getsid
-       .quad sys_fdatasync
-       .quad compat_sys_sysctl /* sysctl */
-       .quad sys_mlock         /* 150 */
-       .quad sys_munlock
-       .quad sys_mlockall
-       .quad sys_munlockall
-       .quad sys_sched_setparam
-       .quad sys_sched_getparam   /* 155 */
-       .quad sys_sched_setscheduler
-       .quad sys_sched_getscheduler
-       .quad sys_sched_yield
-       .quad sys_sched_get_priority_max
-       .quad sys_sched_get_priority_min  /* 160 */
-       .quad sys32_sched_rr_get_interval
-       .quad compat_sys_nanosleep
-       .quad sys_mremap
-       .quad sys_setresuid16
-       .quad sys_getresuid16   /* 165 */
-       .quad sys32_vm86_warning        /* vm86 */ 
-       .quad quiet_ni_syscall  /* query_module */
-       .quad sys_poll
-       .quad quiet_ni_syscall /* old nfsservctl */
-       .quad sys_setresgid16   /* 170 */
-       .quad sys_getresgid16
-       .quad sys_prctl
-       .quad stub32_rt_sigreturn
-       .quad sys32_rt_sigaction
-       .quad sys32_rt_sigprocmask      /* 175 */
-       .quad sys32_rt_sigpending
-       .quad compat_sys_rt_sigtimedwait
-       .quad sys32_rt_sigqueueinfo
-       .quad sys_rt_sigsuspend
-       .quad sys32_pread               /* 180 */
-       .quad sys32_pwrite
-       .quad sys_chown16
-       .quad sys_getcwd
-       .quad sys_capget
-       .quad sys_capset
-       .quad stub32_sigaltstack
-       .quad sys32_sendfile
-       .quad quiet_ni_syscall          /* streams1 */
-       .quad quiet_ni_syscall          /* streams2 */
-       .quad stub32_vfork            /* 190 */
-       .quad compat_sys_getrlimit
-       .quad sys_mmap_pgoff
-       .quad sys32_truncate64
-       .quad sys32_ftruncate64
-       .quad sys32_stat64              /* 195 */
-       .quad sys32_lstat64
-       .quad sys32_fstat64
-       .quad sys_lchown
-       .quad sys_getuid
-       .quad sys_getgid                /* 200 */
-       .quad sys_geteuid
-       .quad sys_getegid
-       .quad sys_setreuid
-       .quad sys_setregid
-       .quad sys_getgroups     /* 205 */
-       .quad sys_setgroups
-       .quad sys_fchown
-       .quad sys_setresuid
-       .quad sys_getresuid
-       .quad sys_setresgid     /* 210 */
-       .quad sys_getresgid
-       .quad sys_chown
-       .quad sys_setuid
-       .quad sys_setgid
-       .quad sys_setfsuid              /* 215 */
-       .quad sys_setfsgid
-       .quad sys_pivot_root
-       .quad sys_mincore
-       .quad sys_madvise
-       .quad compat_sys_getdents64     /* 220 getdents64 */
-       .quad compat_sys_fcntl64        
-       .quad quiet_ni_syscall          /* tux */
-       .quad quiet_ni_syscall          /* security */
-       .quad sys_gettid        
-       .quad sys32_readahead   /* 225 */
-       .quad sys_setxattr
-       .quad sys_lsetxattr
-       .quad sys_fsetxattr
-       .quad sys_getxattr
-       .quad sys_lgetxattr     /* 230 */
-       .quad sys_fgetxattr
-       .quad sys_listxattr
-       .quad sys_llistxattr
-       .quad sys_flistxattr
-       .quad sys_removexattr   /* 235 */
-       .quad sys_lremovexattr
-       .quad sys_fremovexattr
-       .quad sys_tkill
-       .quad sys_sendfile64 
-       .quad compat_sys_futex          /* 240 */
-       .quad compat_sys_sched_setaffinity
-       .quad compat_sys_sched_getaffinity
-       .quad sys_set_thread_area
-       .quad sys_get_thread_area
-       .quad compat_sys_io_setup       /* 245 */
-       .quad sys_io_destroy
-       .quad compat_sys_io_getevents
-       .quad compat_sys_io_submit
-       .quad sys_io_cancel
-       .quad sys32_fadvise64           /* 250 */
-       .quad quiet_ni_syscall  /* free_huge_pages */
-       .quad sys_exit_group
-       .quad sys32_lookup_dcookie
-       .quad sys_epoll_create
-       .quad sys_epoll_ctl             /* 255 */
-       .quad sys_epoll_wait
-       .quad sys_remap_file_pages
-       .quad sys_set_tid_address
-       .quad compat_sys_timer_create
-       .quad compat_sys_timer_settime  /* 260 */
-       .quad compat_sys_timer_gettime
-       .quad sys_timer_getoverrun
-       .quad sys_timer_delete
-       .quad compat_sys_clock_settime
-       .quad compat_sys_clock_gettime  /* 265 */
-       .quad compat_sys_clock_getres
-       .quad compat_sys_clock_nanosleep
-       .quad compat_sys_statfs64
-       .quad compat_sys_fstatfs64
-       .quad sys_tgkill                /* 270 */
-       .quad compat_sys_utimes
-       .quad sys32_fadvise64_64
-       .quad quiet_ni_syscall  /* sys_vserver */
-       .quad sys_mbind
-       .quad compat_sys_get_mempolicy  /* 275 */
-       .quad sys_set_mempolicy
-       .quad compat_sys_mq_open
-       .quad sys_mq_unlink
-       .quad compat_sys_mq_timedsend
-       .quad compat_sys_mq_timedreceive        /* 280 */
-       .quad compat_sys_mq_notify
-       .quad compat_sys_mq_getsetattr
-       .quad compat_sys_kexec_load     /* reserved for kexec */
-       .quad compat_sys_waitid
-       .quad quiet_ni_syscall          /* 285: sys_altroot */
-       .quad sys_add_key
-       .quad sys_request_key
-       .quad sys_keyctl
-       .quad sys_ioprio_set
-       .quad sys_ioprio_get            /* 290 */
-       .quad sys_inotify_init
-       .quad sys_inotify_add_watch
-       .quad sys_inotify_rm_watch
-       .quad sys_migrate_pages
-       .quad compat_sys_openat         /* 295 */
-       .quad sys_mkdirat
-       .quad sys_mknodat
-       .quad sys_fchownat
-       .quad compat_sys_futimesat
-       .quad sys32_fstatat             /* 300 */
-       .quad sys_unlinkat
-       .quad sys_renameat
-       .quad sys_linkat
-       .quad sys_symlinkat
-       .quad sys_readlinkat            /* 305 */
-       .quad sys_fchmodat
-       .quad sys_faccessat
-       .quad compat_sys_pselect6
-       .quad compat_sys_ppoll
-       .quad sys_unshare               /* 310 */
-       .quad compat_sys_set_robust_list
-       .quad compat_sys_get_robust_list
-       .quad sys_splice
-       .quad sys32_sync_file_range
-       .quad sys_tee                   /* 315 */
-       .quad compat_sys_vmsplice
-       .quad compat_sys_move_pages
-       .quad sys_getcpu
-       .quad sys_epoll_pwait
-       .quad compat_sys_utimensat      /* 320 */
-       .quad compat_sys_signalfd
-       .quad sys_timerfd_create
-       .quad sys_eventfd
-       .quad sys32_fallocate
-       .quad compat_sys_timerfd_settime        /* 325 */
-       .quad compat_sys_timerfd_gettime
-       .quad compat_sys_signalfd4
-       .quad sys_eventfd2
-       .quad sys_epoll_create1
-       .quad sys_dup3                          /* 330 */
-       .quad sys_pipe2
-       .quad sys_inotify_init1
-       .quad compat_sys_preadv
-       .quad compat_sys_pwritev
-       .quad compat_sys_rt_tgsigqueueinfo      /* 335 */
-       .quad sys_perf_event_open
-       .quad compat_sys_recvmmsg
-       .quad sys_fanotify_init
-       .quad sys32_fanotify_mark
-       .quad sys_prlimit64             /* 340 */
-       .quad sys_name_to_handle_at
-       .quad compat_sys_open_by_handle_at
-       .quad compat_sys_clock_adjtime
-       .quad sys_syncfs
-       .quad compat_sys_sendmmsg       /* 345 */
-       .quad sys_setns
-       .quad compat_sys_process_vm_readv
-       .quad compat_sys_process_vm_writev
-ia32_syscall_end:
diff --git a/arch/x86/ia32/nosyscall.c b/arch/x86/ia32/nosyscall.c
new file mode 100644 (file)
index 0000000..51ecd5b
--- /dev/null
@@ -0,0 +1,7 @@
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+long compat_ni_syscall(void)
+{
+       return -ENOSYS;
+}
diff --git a/arch/x86/ia32/syscall_ia32.c b/arch/x86/ia32/syscall_ia32.c
new file mode 100644 (file)
index 0000000..4754ba0
--- /dev/null
@@ -0,0 +1,25 @@
+/* System call table for ia32 emulation. */
+
+#include <linux/linkage.h>
+#include <linux/sys.h>
+#include <linux/cache.h>
+#include <asm/asm-offsets.h>
+
+#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void compat(void) ;
+#include <asm/syscalls_32.h>
+#undef __SYSCALL_I386
+
+#define __SYSCALL_I386(nr, sym, compat) [nr] = compat,
+
+typedef void (*sys_call_ptr_t)(void);
+
+extern void compat_ni_syscall(void);
+
+const sys_call_ptr_t ia32_sys_call_table[__NR_ia32_syscall_max+1] = {
+       /*
+        * Smells like a compiler bug -- it doesn't work
+        * when the & below is removed.
+        */
+       [0 ... __NR_ia32_syscall_max] = &compat_ni_syscall,
+#include <asm/syscalls_32.h>
+};
index 6fa90a845e4ca9aa741034195f6a7026077bcadc..b57e6a43a37a1f9ebca3f4a4966f54b31753e605 100644 (file)
@@ -19,7 +19,8 @@ header-y += processor-flags.h
 header-y += ptrace-abi.h
 header-y += sigcontext32.h
 header-y += ucontext.h
-header-y += unistd_32.h
-header-y += unistd_64.h
 header-y += vm86.h
 header-y += vsyscall.h
+
+genhdr-y += unistd_32.h
+genhdr-y += unistd_64.h
index 24098aafce0de97cc64776391eda014945413558..fa13f0ec2874ef6034cdd9440a6a3e31e218b9ac 100644 (file)
@@ -82,7 +82,7 @@ static inline void atomic64_set(atomic64_t *v, long long i)
  *
  * Atomically reads the value of @v and returns it.
  */
-static inline long long atomic64_read(atomic64_t *v)
+static inline long long atomic64_read(const atomic64_t *v)
 {
        long long r;
        asm volatile(ATOMIC64_ALTERNATIVE(read)
index 078ad0caefc6115612d8ee60f8ba7da122346516..b903d5ea394111edc965c351103953a62b5357a6 100644 (file)
@@ -101,6 +101,28 @@ extern void aout_dump_debugregs(struct user *dump);
 
 extern void hw_breakpoint_restore(void);
 
+#ifdef CONFIG_X86_64
+DECLARE_PER_CPU(int, debug_stack_usage);
+static inline void debug_stack_usage_inc(void)
+{
+       __get_cpu_var(debug_stack_usage)++;
+}
+static inline void debug_stack_usage_dec(void)
+{
+       __get_cpu_var(debug_stack_usage)--;
+}
+int is_debug_stack(unsigned long addr);
+void debug_stack_set_zero(void);
+void debug_stack_reset(void);
+#else /* !X86_64 */
+static inline int is_debug_stack(unsigned long addr) { return 0; }
+static inline void debug_stack_set_zero(void) { }
+static inline void debug_stack_reset(void) { }
+static inline void debug_stack_usage_inc(void) { }
+static inline void debug_stack_usage_dec(void) { }
+#endif /* X86_64 */
+
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_X86_DEBUGREG_H */
index 41935fadfdfcca18be2ca724b34e1c45d3116ac1..e95822d683f4639f7211d4f3775975fcd87466ad 100644 (file)
@@ -35,6 +35,8 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in
 
 extern struct desc_ptr idt_descr;
 extern gate_desc idt_table[];
+extern struct desc_ptr nmi_idt_descr;
+extern gate_desc nmi_idt_table[];
 
 struct gdt_page {
        struct desc_struct gdt[GDT_ENTRIES];
@@ -307,6 +309,16 @@ static inline void set_desc_limit(struct desc_struct *desc, unsigned long limit)
        desc->limit = (limit >> 16) & 0xf;
 }
 
+#ifdef CONFIG_X86_64
+static inline void set_nmi_gate(int gate, void *addr)
+{
+       gate_desc s;
+
+       pack_gate(&s, GATE_INTERRUPT, (unsigned long)addr, 0, 0, __KERNEL_CS);
+       write_idt_entry(nmi_idt_table, gate, &s);
+}
+#endif
+
 static inline void _set_gate(int gate, unsigned type, void *addr,
                             unsigned dpl, unsigned ist, unsigned seg)
 {
index 976f6ecd2ce691da49d58e433f0b76b0348622b2..b0d5716ca1e4b6fd76b232554e7778c60d5c89c3 100644 (file)
@@ -2,17 +2,10 @@
 #define _ASM_X86_IA32_UNISTD_H
 
 /*
- * This file contains the system call numbers of the ia32 port,
+ * This file contains the system call numbers of the ia32 compat ABI,
  * this is for the kernel only.
- * Only add syscalls here where some part of the kernel needs to know
- * the number. This should be otherwise in sync with asm-x86/unistd_32.h. -AK
  */
-
-#define __NR_ia32_restart_syscall 0
-#define __NR_ia32_exit           1
-#define __NR_ia32_read           3
-#define __NR_ia32_write                  4
-#define __NR_ia32_sigreturn    119
-#define __NR_ia32_rt_sigreturn 173
+#define __SYSCALL_ia32_NR(x) (x)
+#include <asm/unistd_32_ia32.h>
 
 #endif /* _ASM_X86_IA32_UNISTD_H */
index f35ce43c1a7785bd0d555f0b3f6a65ab417bba3b..6aefb14cbbc5d9c40dcbf89322a5d4a77103b48e 100644 (file)
@@ -151,7 +151,7 @@ static inline void enable_p5_mce(void) {}
 
 void mce_setup(struct mce *m);
 void mce_log(struct mce *m);
-DECLARE_PER_CPU(struct device, mce_device);
+extern struct device *mce_device[CONFIG_NR_CPUS];
 
 /*
  * Maximum banks number.
index c4a348f7bd43de3932f88d0f8ddb5b66a7526863..d962e5652a7352498bd9654315f7819fb7d9d86b 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/sched.h>
 #include <linux/err.h>
+#include <asm/asm-offsets.h>   /* For NR_syscalls */
 
 extern const unsigned long sys_call_table[];
 
index 74047159d0ab517acc0213d5fd8b7149efa26d57..bc817cd8b44359b615e34f9b08aa67a61425cf29 100644 (file)
@@ -40,8 +40,8 @@ struct thread_info {
                                                */
        __u8                    supervisor_stack[0];
 #endif
-       int                     sig_on_uaccess_error:1;
-       int                     uaccess_err:1;  /* uaccess failed */
+       unsigned int            sig_on_uaccess_error:1;
+       unsigned int            uaccess_err:1;  /* uaccess failed */
 };
 
 #define INIT_THREAD_INFO(tsk)                  \
index 2a58ed3e51d8265627e185d5d8be3783c5ea9bf4..21f77b89e47a6aeea5ab00c01c28db2d54f0520b 100644 (file)
@@ -1,13 +1,60 @@
+#ifndef _ASM_X86_UNISTD_H
+#define _ASM_X86_UNISTD_H 1
+
 #ifdef __KERNEL__
 # ifdef CONFIG_X86_32
-#  include "unistd_32.h"
+
+#  include <asm/unistd_32.h>
+#  define __ARCH_WANT_IPC_PARSE_VERSION
+#  define __ARCH_WANT_STAT64
+#  define __ARCH_WANT_SYS_IPC
+#  define __ARCH_WANT_SYS_OLD_MMAP
+#  define __ARCH_WANT_SYS_OLD_SELECT
+
 # else
-#  include "unistd_64.h"
+
+#  include <asm/unistd_64.h>
+#  define __ARCH_WANT_COMPAT_SYS_TIME
+
 # endif
+
+# define __ARCH_WANT_OLD_READDIR
+# define __ARCH_WANT_OLD_STAT
+# define __ARCH_WANT_SYS_ALARM
+# define __ARCH_WANT_SYS_FADVISE64
+# define __ARCH_WANT_SYS_GETHOSTNAME
+# define __ARCH_WANT_SYS_GETPGRP
+# define __ARCH_WANT_SYS_LLSEEK
+# define __ARCH_WANT_SYS_NICE
+# define __ARCH_WANT_SYS_OLDUMOUNT
+# define __ARCH_WANT_SYS_OLD_GETRLIMIT
+# define __ARCH_WANT_SYS_OLD_UNAME
+# define __ARCH_WANT_SYS_PAUSE
+# define __ARCH_WANT_SYS_RT_SIGACTION
+# define __ARCH_WANT_SYS_RT_SIGSUSPEND
+# define __ARCH_WANT_SYS_SGETMASK
+# define __ARCH_WANT_SYS_SIGNAL
+# define __ARCH_WANT_SYS_SIGPENDING
+# define __ARCH_WANT_SYS_SIGPROCMASK
+# define __ARCH_WANT_SYS_SOCKETCALL
+# define __ARCH_WANT_SYS_TIME
+# define __ARCH_WANT_SYS_UTIME
+# define __ARCH_WANT_SYS_WAITPID
+
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+# define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
+
 #else
 # ifdef __i386__
-#  include "unistd_32.h"
+#  include <asm/unistd_32.h>
 # else
-#  include "unistd_64.h"
+#  include <asm/unistd_64.h>
 # endif
 #endif
+
+#endif /* _ASM_X86_UNISTD_H */
diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h
deleted file mode 100644 (file)
index 599c77d..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-#ifndef _ASM_X86_UNISTD_32_H
-#define _ASM_X86_UNISTD_32_H
-
-/*
- * This file contains the system call numbers.
- */
-
-#define __NR_restart_syscall      0
-#define __NR_exit                1
-#define __NR_fork                2
-#define __NR_read                3
-#define __NR_write               4
-#define __NR_open                5
-#define __NR_close               6
-#define __NR_waitpid             7
-#define __NR_creat               8
-#define __NR_link                9
-#define __NR_unlink             10
-#define __NR_execve             11
-#define __NR_chdir              12
-#define __NR_time               13
-#define __NR_mknod              14
-#define __NR_chmod              15
-#define __NR_lchown             16
-#define __NR_break              17
-#define __NR_oldstat            18
-#define __NR_lseek              19
-#define __NR_getpid             20
-#define __NR_mount              21
-#define __NR_umount             22
-#define __NR_setuid             23
-#define __NR_getuid             24
-#define __NR_stime              25
-#define __NR_ptrace             26
-#define __NR_alarm              27
-#define __NR_oldfstat           28
-#define __NR_pause              29
-#define __NR_utime              30
-#define __NR_stty               31
-#define __NR_gtty               32
-#define __NR_access             33
-#define __NR_nice               34
-#define __NR_ftime              35
-#define __NR_sync               36
-#define __NR_kill               37
-#define __NR_rename             38
-#define __NR_mkdir              39
-#define __NR_rmdir              40
-#define __NR_dup                41
-#define __NR_pipe               42
-#define __NR_times              43
-#define __NR_prof               44
-#define __NR_brk                45
-#define __NR_setgid             46
-#define __NR_getgid             47
-#define __NR_signal             48
-#define __NR_geteuid            49
-#define __NR_getegid            50
-#define __NR_acct               51
-#define __NR_umount2            52
-#define __NR_lock               53
-#define __NR_ioctl              54
-#define __NR_fcntl              55
-#define __NR_mpx                56
-#define __NR_setpgid            57
-#define __NR_ulimit             58
-#define __NR_oldolduname        59
-#define __NR_umask              60
-#define __NR_chroot             61
-#define __NR_ustat              62
-#define __NR_dup2               63
-#define __NR_getppid            64
-#define __NR_getpgrp            65
-#define __NR_setsid             66
-#define __NR_sigaction          67
-#define __NR_sgetmask           68
-#define __NR_ssetmask           69
-#define __NR_setreuid           70
-#define __NR_setregid           71
-#define __NR_sigsuspend                 72
-#define __NR_sigpending                 73
-#define __NR_sethostname        74
-#define __NR_setrlimit          75
-#define __NR_getrlimit          76   /* Back compatible 2Gig limited rlimit */
-#define __NR_getrusage          77
-#define __NR_gettimeofday       78
-#define __NR_settimeofday       79
-#define __NR_getgroups          80
-#define __NR_setgroups          81
-#define __NR_select             82
-#define __NR_symlink            83
-#define __NR_oldlstat           84
-#define __NR_readlink           85
-#define __NR_uselib             86
-#define __NR_swapon             87
-#define __NR_reboot             88
-#define __NR_readdir            89
-#define __NR_mmap               90
-#define __NR_munmap             91
-#define __NR_truncate           92
-#define __NR_ftruncate          93
-#define __NR_fchmod             94
-#define __NR_fchown             95
-#define __NR_getpriority        96
-#define __NR_setpriority        97
-#define __NR_profil             98
-#define __NR_statfs             99
-#define __NR_fstatfs           100
-#define __NR_ioperm            101
-#define __NR_socketcall                102
-#define __NR_syslog            103
-#define __NR_setitimer         104
-#define __NR_getitimer         105
-#define __NR_stat              106
-#define __NR_lstat             107
-#define __NR_fstat             108
-#define __NR_olduname          109
-#define __NR_iopl              110
-#define __NR_vhangup           111
-#define __NR_idle              112
-#define __NR_vm86old           113
-#define __NR_wait4             114
-#define __NR_swapoff           115
-#define __NR_sysinfo           116
-#define __NR_ipc               117
-#define __NR_fsync             118
-#define __NR_sigreturn         119
-#define __NR_clone             120
-#define __NR_setdomainname     121
-#define __NR_uname             122
-#define __NR_modify_ldt                123
-#define __NR_adjtimex          124
-#define __NR_mprotect          125
-#define __NR_sigprocmask       126
-#define __NR_create_module     127
-#define __NR_init_module       128
-#define __NR_delete_module     129
-#define __NR_get_kernel_syms   130
-#define __NR_quotactl          131
-#define __NR_getpgid           132
-#define __NR_fchdir            133
-#define __NR_bdflush           134
-#define __NR_sysfs             135
-#define __NR_personality       136
-#define __NR_afs_syscall       137 /* Syscall for Andrew File System */
-#define __NR_setfsuid          138
-#define __NR_setfsgid          139
-#define __NR__llseek           140
-#define __NR_getdents          141
-#define __NR__newselect                142
-#define __NR_flock             143
-#define __NR_msync             144
-#define __NR_readv             145
-#define __NR_writev            146
-#define __NR_getsid            147
-#define __NR_fdatasync         148
-#define __NR__sysctl           149
-#define __NR_mlock             150
-#define __NR_munlock           151
-#define __NR_mlockall          152
-#define __NR_munlockall                153
-#define __NR_sched_setparam            154
-#define __NR_sched_getparam            155
-#define __NR_sched_setscheduler                156
-#define __NR_sched_getscheduler                157
-#define __NR_sched_yield               158
-#define __NR_sched_get_priority_max    159
-#define __NR_sched_get_priority_min    160
-#define __NR_sched_rr_get_interval     161
-#define __NR_nanosleep         162
-#define __NR_mremap            163
-#define __NR_setresuid         164
-#define __NR_getresuid         165
-#define __NR_vm86              166
-#define __NR_query_module      167
-#define __NR_poll              168
-#define __NR_nfsservctl                169
-#define __NR_setresgid         170
-#define __NR_getresgid         171
-#define __NR_prctl              172
-#define __NR_rt_sigreturn      173
-#define __NR_rt_sigaction      174
-#define __NR_rt_sigprocmask    175
-#define __NR_rt_sigpending     176
-#define __NR_rt_sigtimedwait   177
-#define __NR_rt_sigqueueinfo   178
-#define __NR_rt_sigsuspend     179
-#define __NR_pread64           180
-#define __NR_pwrite64          181
-#define __NR_chown             182
-#define __NR_getcwd            183
-#define __NR_capget            184
-#define __NR_capset            185
-#define __NR_sigaltstack       186
-#define __NR_sendfile          187
-#define __NR_getpmsg           188     /* some people actually want streams */
-#define __NR_putpmsg           189     /* some people actually want streams */
-#define __NR_vfork             190
-#define __NR_ugetrlimit                191     /* SuS compliant getrlimit */
-#define __NR_mmap2             192
-#define __NR_truncate64                193
-#define __NR_ftruncate64       194
-#define __NR_stat64            195
-#define __NR_lstat64           196
-#define __NR_fstat64           197
-#define __NR_lchown32          198
-#define __NR_getuid32          199
-#define __NR_getgid32          200
-#define __NR_geteuid32         201
-#define __NR_getegid32         202
-#define __NR_setreuid32                203
-#define __NR_setregid32                204
-#define __NR_getgroups32       205
-#define __NR_setgroups32       206
-#define __NR_fchown32          207
-#define __NR_setresuid32       208
-#define __NR_getresuid32       209
-#define __NR_setresgid32       210
-#define __NR_getresgid32       211
-#define __NR_chown32           212
-#define __NR_setuid32          213
-#define __NR_setgid32          214
-#define __NR_setfsuid32                215
-#define __NR_setfsgid32                216
-#define __NR_pivot_root                217
-#define __NR_mincore           218
-#define __NR_madvise           219
-#define __NR_madvise1          219     /* delete when C lib stub is removed */
-#define __NR_getdents64                220
-#define __NR_fcntl64           221
-/* 223 is unused */
-#define __NR_gettid            224
-#define __NR_readahead         225
-#define __NR_setxattr          226
-#define __NR_lsetxattr         227
-#define __NR_fsetxattr         228
-#define __NR_getxattr          229
-#define __NR_lgetxattr         230
-#define __NR_fgetxattr         231
-#define __NR_listxattr         232
-#define __NR_llistxattr                233
-#define __NR_flistxattr                234
-#define __NR_removexattr       235
-#define __NR_lremovexattr      236
-#define __NR_fremovexattr      237
-#define __NR_tkill             238
-#define __NR_sendfile64                239
-#define __NR_futex             240
-#define __NR_sched_setaffinity 241
-#define __NR_sched_getaffinity 242
-#define __NR_set_thread_area   243
-#define __NR_get_thread_area   244
-#define __NR_io_setup          245
-#define __NR_io_destroy                246
-#define __NR_io_getevents      247
-#define __NR_io_submit         248
-#define __NR_io_cancel         249
-#define __NR_fadvise64         250
-/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */
-#define __NR_exit_group                252
-#define __NR_lookup_dcookie    253
-#define __NR_epoll_create      254
-#define __NR_epoll_ctl         255
-#define __NR_epoll_wait                256
-#define __NR_remap_file_pages  257
-#define __NR_set_tid_address   258
-#define __NR_timer_create      259
-#define __NR_timer_settime     (__NR_timer_create+1)
-#define __NR_timer_gettime     (__NR_timer_create+2)
-#define __NR_timer_getoverrun  (__NR_timer_create+3)
-#define __NR_timer_delete      (__NR_timer_create+4)
-#define __NR_clock_settime     (__NR_timer_create+5)
-#define __NR_clock_gettime     (__NR_timer_create+6)
-#define __NR_clock_getres      (__NR_timer_create+7)
-#define __NR_clock_nanosleep   (__NR_timer_create+8)
-#define __NR_statfs64          268
-#define __NR_fstatfs64         269
-#define __NR_tgkill            270
-#define __NR_utimes            271
-#define __NR_fadvise64_64      272
-#define __NR_vserver           273
-#define __NR_mbind             274
-#define __NR_get_mempolicy     275
-#define __NR_set_mempolicy     276
-#define __NR_mq_open           277
-#define __NR_mq_unlink         (__NR_mq_open+1)
-#define __NR_mq_timedsend      (__NR_mq_open+2)
-#define __NR_mq_timedreceive   (__NR_mq_open+3)
-#define __NR_mq_notify         (__NR_mq_open+4)
-#define __NR_mq_getsetattr     (__NR_mq_open+5)
-#define __NR_kexec_load                283
-#define __NR_waitid            284
-/* #define __NR_sys_setaltroot 285 */
-#define __NR_add_key           286
-#define __NR_request_key       287
-#define __NR_keyctl            288
-#define __NR_ioprio_set                289
-#define __NR_ioprio_get                290
-#define __NR_inotify_init      291
-#define __NR_inotify_add_watch 292
-#define __NR_inotify_rm_watch  293
-#define __NR_migrate_pages     294
-#define __NR_openat            295
-#define __NR_mkdirat           296
-#define __NR_mknodat           297
-#define __NR_fchownat          298
-#define __NR_futimesat         299
-#define __NR_fstatat64         300
-#define __NR_unlinkat          301
-#define __NR_renameat          302
-#define __NR_linkat            303
-#define __NR_symlinkat         304
-#define __NR_readlinkat                305
-#define __NR_fchmodat          306
-#define __NR_faccessat         307
-#define __NR_pselect6          308
-#define __NR_ppoll             309
-#define __NR_unshare           310
-#define __NR_set_robust_list   311
-#define __NR_get_robust_list   312
-#define __NR_splice            313
-#define __NR_sync_file_range   314
-#define __NR_tee               315
-#define __NR_vmsplice          316
-#define __NR_move_pages                317
-#define __NR_getcpu            318
-#define __NR_epoll_pwait       319
-#define __NR_utimensat         320
-#define __NR_signalfd          321
-#define __NR_timerfd_create    322
-#define __NR_eventfd           323
-#define __NR_fallocate         324
-#define __NR_timerfd_settime   325
-#define __NR_timerfd_gettime   326
-#define __NR_signalfd4         327
-#define __NR_eventfd2          328
-#define __NR_epoll_create1     329
-#define __NR_dup3              330
-#define __NR_pipe2             331
-#define __NR_inotify_init1     332
-#define __NR_preadv            333
-#define __NR_pwritev           334
-#define __NR_rt_tgsigqueueinfo 335
-#define __NR_perf_event_open   336
-#define __NR_recvmmsg          337
-#define __NR_fanotify_init     338
-#define __NR_fanotify_mark     339
-#define __NR_prlimit64         340
-#define __NR_name_to_handle_at 341
-#define __NR_open_by_handle_at  342
-#define __NR_clock_adjtime     343
-#define __NR_syncfs             344
-#define __NR_sendmmsg          345
-#define __NR_setns             346
-#define __NR_process_vm_readv  347
-#define __NR_process_vm_writev 348
-
-#ifdef __KERNEL__
-
-#define NR_syscalls 349
-
-#define __ARCH_WANT_IPC_PARSE_VERSION
-#define __ARCH_WANT_OLD_READDIR
-#define __ARCH_WANT_OLD_STAT
-#define __ARCH_WANT_STAT64
-#define __ARCH_WANT_SYS_ALARM
-#define __ARCH_WANT_SYS_GETHOSTNAME
-#define __ARCH_WANT_SYS_IPC
-#define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_SGETMASK
-#define __ARCH_WANT_SYS_SIGNAL
-#define __ARCH_WANT_SYS_TIME
-#define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_WAITPID
-#define __ARCH_WANT_SYS_SOCKETCALL
-#define __ARCH_WANT_SYS_FADVISE64
-#define __ARCH_WANT_SYS_GETPGRP
-#define __ARCH_WANT_SYS_LLSEEK
-#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
-#define __ARCH_WANT_SYS_OLD_UNAME
-#define __ARCH_WANT_SYS_OLD_MMAP
-#define __ARCH_WANT_SYS_OLD_SELECT
-#define __ARCH_WANT_SYS_OLDUMOUNT
-#define __ARCH_WANT_SYS_SIGPENDING
-#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
-
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#ifndef cond_syscall
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-#endif
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_X86_UNISTD_32_H */
diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h
deleted file mode 100644 (file)
index 0431f19..0000000
+++ /dev/null
@@ -1,732 +0,0 @@
-#ifndef _ASM_X86_UNISTD_64_H
-#define _ASM_X86_UNISTD_64_H
-
-#ifndef __SYSCALL
-#define __SYSCALL(a, b)
-#endif
-
-/*
- * This file contains the system call numbers.
- *
- * Note: holes are not allowed.
- */
-
-/* at least 8 syscall per cacheline */
-#define __NR_read                              0
-__SYSCALL(__NR_read, sys_read)
-#define __NR_write                             1
-__SYSCALL(__NR_write, sys_write)
-#define __NR_open                              2
-__SYSCALL(__NR_open, sys_open)
-#define __NR_close                             3
-__SYSCALL(__NR_close, sys_close)
-#define __NR_stat                              4
-__SYSCALL(__NR_stat, sys_newstat)
-#define __NR_fstat                             5
-__SYSCALL(__NR_fstat, sys_newfstat)
-#define __NR_lstat                             6
-__SYSCALL(__NR_lstat, sys_newlstat)
-#define __NR_poll                              7
-__SYSCALL(__NR_poll, sys_poll)
-
-#define __NR_lseek                             8
-__SYSCALL(__NR_lseek, sys_lseek)
-#define __NR_mmap                              9
-__SYSCALL(__NR_mmap, sys_mmap)
-#define __NR_mprotect                          10
-__SYSCALL(__NR_mprotect, sys_mprotect)
-#define __NR_munmap                            11
-__SYSCALL(__NR_munmap, sys_munmap)
-#define __NR_brk                               12
-__SYSCALL(__NR_brk, sys_brk)
-#define __NR_rt_sigaction                      13
-__SYSCALL(__NR_rt_sigaction, sys_rt_sigaction)
-#define __NR_rt_sigprocmask                    14
-__SYSCALL(__NR_rt_sigprocmask, sys_rt_sigprocmask)
-#define __NR_rt_sigreturn                      15
-__SYSCALL(__NR_rt_sigreturn, stub_rt_sigreturn)
-
-#define __NR_ioctl                             16
-__SYSCALL(__NR_ioctl, sys_ioctl)
-#define __NR_pread64                           17
-__SYSCALL(__NR_pread64, sys_pread64)
-#define __NR_pwrite64                          18
-__SYSCALL(__NR_pwrite64, sys_pwrite64)
-#define __NR_readv                             19
-__SYSCALL(__NR_readv, sys_readv)
-#define __NR_writev                            20
-__SYSCALL(__NR_writev, sys_writev)
-#define __NR_access                            21
-__SYSCALL(__NR_access, sys_access)
-#define __NR_pipe                              22
-__SYSCALL(__NR_pipe, sys_pipe)
-#define __NR_select                            23
-__SYSCALL(__NR_select, sys_select)
-
-#define __NR_sched_yield                       24
-__SYSCALL(__NR_sched_yield, sys_sched_yield)
-#define __NR_mremap                            25
-__SYSCALL(__NR_mremap, sys_mremap)
-#define __NR_msync                             26
-__SYSCALL(__NR_msync, sys_msync)
-#define __NR_mincore                           27
-__SYSCALL(__NR_mincore, sys_mincore)
-#define __NR_madvise                           28
-__SYSCALL(__NR_madvise, sys_madvise)
-#define __NR_shmget                            29
-__SYSCALL(__NR_shmget, sys_shmget)
-#define __NR_shmat                             30
-__SYSCALL(__NR_shmat, sys_shmat)
-#define __NR_shmctl                            31
-__SYSCALL(__NR_shmctl, sys_shmctl)
-
-#define __NR_dup                               32
-__SYSCALL(__NR_dup, sys_dup)
-#define __NR_dup2                              33
-__SYSCALL(__NR_dup2, sys_dup2)
-#define __NR_pause                             34
-__SYSCALL(__NR_pause, sys_pause)
-#define __NR_nanosleep                         35
-__SYSCALL(__NR_nanosleep, sys_nanosleep)
-#define __NR_getitimer                         36
-__SYSCALL(__NR_getitimer, sys_getitimer)
-#define __NR_alarm                             37
-__SYSCALL(__NR_alarm, sys_alarm)
-#define __NR_setitimer                         38
-__SYSCALL(__NR_setitimer, sys_setitimer)
-#define __NR_getpid                            39
-__SYSCALL(__NR_getpid, sys_getpid)
-
-#define __NR_sendfile                          40
-__SYSCALL(__NR_sendfile, sys_sendfile64)
-#define __NR_socket                            41
-__SYSCALL(__NR_socket, sys_socket)
-#define __NR_connect                           42
-__SYSCALL(__NR_connect, sys_connect)
-#define __NR_accept                            43
-__SYSCALL(__NR_accept, sys_accept)
-#define __NR_sendto                            44
-__SYSCALL(__NR_sendto, sys_sendto)
-#define __NR_recvfrom                          45
-__SYSCALL(__NR_recvfrom, sys_recvfrom)
-#define __NR_sendmsg                           46
-__SYSCALL(__NR_sendmsg, sys_sendmsg)
-#define __NR_recvmsg                           47
-__SYSCALL(__NR_recvmsg, sys_recvmsg)
-
-#define __NR_shutdown                          48
-__SYSCALL(__NR_shutdown, sys_shutdown)
-#define __NR_bind                              49
-__SYSCALL(__NR_bind, sys_bind)
-#define __NR_listen                            50
-__SYSCALL(__NR_listen, sys_listen)
-#define __NR_getsockname                       51
-__SYSCALL(__NR_getsockname, sys_getsockname)
-#define __NR_getpeername                       52
-__SYSCALL(__NR_getpeername, sys_getpeername)
-#define __NR_socketpair                                53
-__SYSCALL(__NR_socketpair, sys_socketpair)
-#define __NR_setsockopt                                54
-__SYSCALL(__NR_setsockopt, sys_setsockopt)
-#define __NR_getsockopt                                55
-__SYSCALL(__NR_getsockopt, sys_getsockopt)
-
-#define __NR_clone                             56
-__SYSCALL(__NR_clone, stub_clone)
-#define __NR_fork                              57
-__SYSCALL(__NR_fork, stub_fork)
-#define __NR_vfork                             58
-__SYSCALL(__NR_vfork, stub_vfork)
-#define __NR_execve                            59
-__SYSCALL(__NR_execve, stub_execve)
-#define __NR_exit                              60
-__SYSCALL(__NR_exit, sys_exit)
-#define __NR_wait4                             61
-__SYSCALL(__NR_wait4, sys_wait4)
-#define __NR_kill                              62
-__SYSCALL(__NR_kill, sys_kill)
-#define __NR_uname                             63
-__SYSCALL(__NR_uname, sys_newuname)
-
-#define __NR_semget                            64
-__SYSCALL(__NR_semget, sys_semget)
-#define __NR_semop                             65
-__SYSCALL(__NR_semop, sys_semop)
-#define __NR_semctl                            66
-__SYSCALL(__NR_semctl, sys_semctl)
-#define __NR_shmdt                             67
-__SYSCALL(__NR_shmdt, sys_shmdt)
-#define __NR_msgget                            68
-__SYSCALL(__NR_msgget, sys_msgget)
-#define __NR_msgsnd                            69
-__SYSCALL(__NR_msgsnd, sys_msgsnd)
-#define __NR_msgrcv                            70
-__SYSCALL(__NR_msgrcv, sys_msgrcv)
-#define __NR_msgctl                            71
-__SYSCALL(__NR_msgctl, sys_msgctl)
-
-#define __NR_fcntl                             72
-__SYSCALL(__NR_fcntl, sys_fcntl)
-#define __NR_flock                             73
-__SYSCALL(__NR_flock, sys_flock)
-#define __NR_fsync                             74
-__SYSCALL(__NR_fsync, sys_fsync)
-#define __NR_fdatasync                         75
-__SYSCALL(__NR_fdatasync, sys_fdatasync)
-#define __NR_truncate                          76
-__SYSCALL(__NR_truncate, sys_truncate)
-#define __NR_ftruncate                         77
-__SYSCALL(__NR_ftruncate, sys_ftruncate)
-#define __NR_getdents                          78
-__SYSCALL(__NR_getdents, sys_getdents)
-#define __NR_getcwd                            79
-__SYSCALL(__NR_getcwd, sys_getcwd)
-
-#define __NR_chdir                             80
-__SYSCALL(__NR_chdir, sys_chdir)
-#define __NR_fchdir                            81
-__SYSCALL(__NR_fchdir, sys_fchdir)
-#define __NR_rename                            82
-__SYSCALL(__NR_rename, sys_rename)
-#define __NR_mkdir                             83
-__SYSCALL(__NR_mkdir, sys_mkdir)
-#define __NR_rmdir                             84
-__SYSCALL(__NR_rmdir, sys_rmdir)
-#define __NR_creat                             85
-__SYSCALL(__NR_creat, sys_creat)
-#define __NR_link                              86
-__SYSCALL(__NR_link, sys_link)
-#define __NR_unlink                            87
-__SYSCALL(__NR_unlink, sys_unlink)
-
-#define __NR_symlink                           88
-__SYSCALL(__NR_symlink, sys_symlink)
-#define __NR_readlink                          89
-__SYSCALL(__NR_readlink, sys_readlink)
-#define __NR_chmod                             90
-__SYSCALL(__NR_chmod, sys_chmod)
-#define __NR_fchmod                            91
-__SYSCALL(__NR_fchmod, sys_fchmod)
-#define __NR_chown                             92
-__SYSCALL(__NR_chown, sys_chown)
-#define __NR_fchown                            93
-__SYSCALL(__NR_fchown, sys_fchown)
-#define __NR_lchown                            94
-__SYSCALL(__NR_lchown, sys_lchown)
-#define __NR_umask                             95
-__SYSCALL(__NR_umask, sys_umask)
-
-#define __NR_gettimeofday                      96
-__SYSCALL(__NR_gettimeofday, sys_gettimeofday)
-#define __NR_getrlimit                         97
-__SYSCALL(__NR_getrlimit, sys_getrlimit)
-#define __NR_getrusage                         98
-__SYSCALL(__NR_getrusage, sys_getrusage)
-#define __NR_sysinfo                           99
-__SYSCALL(__NR_sysinfo, sys_sysinfo)
-#define __NR_times                             100
-__SYSCALL(__NR_times, sys_times)
-#define __NR_ptrace                            101
-__SYSCALL(__NR_ptrace, sys_ptrace)
-#define __NR_getuid                            102
-__SYSCALL(__NR_getuid, sys_getuid)
-#define __NR_syslog                            103
-__SYSCALL(__NR_syslog, sys_syslog)
-
-/* at the very end the stuff that never runs during the benchmarks */
-#define __NR_getgid                            104
-__SYSCALL(__NR_getgid, sys_getgid)
-#define __NR_setuid                            105
-__SYSCALL(__NR_setuid, sys_setuid)
-#define __NR_setgid                            106
-__SYSCALL(__NR_setgid, sys_setgid)
-#define __NR_geteuid                           107
-__SYSCALL(__NR_geteuid, sys_geteuid)
-#define __NR_getegid                           108
-__SYSCALL(__NR_getegid, sys_getegid)
-#define __NR_setpgid                           109
-__SYSCALL(__NR_setpgid, sys_setpgid)
-#define __NR_getppid                           110
-__SYSCALL(__NR_getppid, sys_getppid)
-#define __NR_getpgrp                           111
-__SYSCALL(__NR_getpgrp, sys_getpgrp)
-
-#define __NR_setsid                            112
-__SYSCALL(__NR_setsid, sys_setsid)
-#define __NR_setreuid                          113
-__SYSCALL(__NR_setreuid, sys_setreuid)
-#define __NR_setregid                          114
-__SYSCALL(__NR_setregid, sys_setregid)
-#define __NR_getgroups                         115
-__SYSCALL(__NR_getgroups, sys_getgroups)
-#define __NR_setgroups                         116
-__SYSCALL(__NR_setgroups, sys_setgroups)
-#define __NR_setresuid                         117
-__SYSCALL(__NR_setresuid, sys_setresuid)
-#define __NR_getresuid                         118
-__SYSCALL(__NR_getresuid, sys_getresuid)
-#define __NR_setresgid                         119
-__SYSCALL(__NR_setresgid, sys_setresgid)
-
-#define __NR_getresgid                         120
-__SYSCALL(__NR_getresgid, sys_getresgid)
-#define __NR_getpgid                           121
-__SYSCALL(__NR_getpgid, sys_getpgid)
-#define __NR_setfsuid                          122
-__SYSCALL(__NR_setfsuid, sys_setfsuid)
-#define __NR_setfsgid                          123
-__SYSCALL(__NR_setfsgid, sys_setfsgid)
-#define __NR_getsid                            124
-__SYSCALL(__NR_getsid, sys_getsid)
-#define __NR_capget                            125
-__SYSCALL(__NR_capget, sys_capget)
-#define __NR_capset                            126
-__SYSCALL(__NR_capset, sys_capset)
-
-#define __NR_rt_sigpending                     127
-__SYSCALL(__NR_rt_sigpending, sys_rt_sigpending)
-#define __NR_rt_sigtimedwait                   128
-__SYSCALL(__NR_rt_sigtimedwait, sys_rt_sigtimedwait)
-#define __NR_rt_sigqueueinfo                   129
-__SYSCALL(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo)
-#define __NR_rt_sigsuspend                     130
-__SYSCALL(__NR_rt_sigsuspend, sys_rt_sigsuspend)
-#define __NR_sigaltstack                       131
-__SYSCALL(__NR_sigaltstack, stub_sigaltstack)
-#define __NR_utime                             132
-__SYSCALL(__NR_utime, sys_utime)
-#define __NR_mknod                             133
-__SYSCALL(__NR_mknod, sys_mknod)
-
-/* Only needed for a.out */
-#define __NR_uselib                            134
-__SYSCALL(__NR_uselib, sys_ni_syscall)
-#define __NR_personality                       135
-__SYSCALL(__NR_personality, sys_personality)
-
-#define __NR_ustat                             136
-__SYSCALL(__NR_ustat, sys_ustat)
-#define __NR_statfs                            137
-__SYSCALL(__NR_statfs, sys_statfs)
-#define __NR_fstatfs                           138
-__SYSCALL(__NR_fstatfs, sys_fstatfs)
-#define __NR_sysfs                             139
-__SYSCALL(__NR_sysfs, sys_sysfs)
-
-#define __NR_getpriority                       140
-__SYSCALL(__NR_getpriority, sys_getpriority)
-#define __NR_setpriority                       141
-__SYSCALL(__NR_setpriority, sys_setpriority)
-#define __NR_sched_setparam                    142
-__SYSCALL(__NR_sched_setparam, sys_sched_setparam)
-#define __NR_sched_getparam                    143
-__SYSCALL(__NR_sched_getparam, sys_sched_getparam)
-#define __NR_sched_setscheduler                        144
-__SYSCALL(__NR_sched_setscheduler, sys_sched_setscheduler)
-#define __NR_sched_getscheduler                        145
-__SYSCALL(__NR_sched_getscheduler, sys_sched_getscheduler)
-#define __NR_sched_get_priority_max            146
-__SYSCALL(__NR_sched_get_priority_max, sys_sched_get_priority_max)
-#define __NR_sched_get_priority_min            147
-__SYSCALL(__NR_sched_get_priority_min, sys_sched_get_priority_min)
-#define __NR_sched_rr_get_interval             148
-__SYSCALL(__NR_sched_rr_get_interval, sys_sched_rr_get_interval)
-
-#define __NR_mlock                             149
-__SYSCALL(__NR_mlock, sys_mlock)
-#define __NR_munlock                           150
-__SYSCALL(__NR_munlock, sys_munlock)
-#define __NR_mlockall                          151
-__SYSCALL(__NR_mlockall, sys_mlockall)
-#define __NR_munlockall                                152
-__SYSCALL(__NR_munlockall, sys_munlockall)
-
-#define __NR_vhangup                           153
-__SYSCALL(__NR_vhangup, sys_vhangup)
-
-#define __NR_modify_ldt                                154
-__SYSCALL(__NR_modify_ldt, sys_modify_ldt)
-
-#define __NR_pivot_root                                155
-__SYSCALL(__NR_pivot_root, sys_pivot_root)
-
-#define __NR__sysctl                           156
-__SYSCALL(__NR__sysctl, sys_sysctl)
-
-#define __NR_prctl                             157
-__SYSCALL(__NR_prctl, sys_prctl)
-#define __NR_arch_prctl                                158
-__SYSCALL(__NR_arch_prctl, sys_arch_prctl)
-
-#define __NR_adjtimex                          159
-__SYSCALL(__NR_adjtimex, sys_adjtimex)
-
-#define __NR_setrlimit                         160
-__SYSCALL(__NR_setrlimit, sys_setrlimit)
-
-#define __NR_chroot                            161
-__SYSCALL(__NR_chroot, sys_chroot)
-
-#define __NR_sync                              162
-__SYSCALL(__NR_sync, sys_sync)
-
-#define __NR_acct                              163
-__SYSCALL(__NR_acct, sys_acct)
-
-#define __NR_settimeofday                      164
-__SYSCALL(__NR_settimeofday, sys_settimeofday)
-
-#define __NR_mount                             165
-__SYSCALL(__NR_mount, sys_mount)
-#define __NR_umount2                           166
-__SYSCALL(__NR_umount2, sys_umount)
-
-#define __NR_swapon                            167
-__SYSCALL(__NR_swapon, sys_swapon)
-#define __NR_swapoff                           168
-__SYSCALL(__NR_swapoff, sys_swapoff)
-
-#define __NR_reboot                            169
-__SYSCALL(__NR_reboot, sys_reboot)
-
-#define __NR_sethostname                       170
-__SYSCALL(__NR_sethostname, sys_sethostname)
-#define __NR_setdomainname                     171
-__SYSCALL(__NR_setdomainname, sys_setdomainname)
-
-#define __NR_iopl                              172
-__SYSCALL(__NR_iopl, stub_iopl)
-#define __NR_ioperm                            173
-__SYSCALL(__NR_ioperm, sys_ioperm)
-
-#define __NR_create_module                     174
-__SYSCALL(__NR_create_module, sys_ni_syscall)
-#define __NR_init_module                       175
-__SYSCALL(__NR_init_module, sys_init_module)
-#define __NR_delete_module                     176
-__SYSCALL(__NR_delete_module, sys_delete_module)
-#define __NR_get_kernel_syms                   177
-__SYSCALL(__NR_get_kernel_syms, sys_ni_syscall)
-#define __NR_query_module                      178
-__SYSCALL(__NR_query_module, sys_ni_syscall)
-
-#define __NR_quotactl                          179
-__SYSCALL(__NR_quotactl, sys_quotactl)
-
-#define __NR_nfsservctl                                180
-__SYSCALL(__NR_nfsservctl, sys_ni_syscall)
-
-/* reserved for LiS/STREAMS */
-#define __NR_getpmsg                           181
-__SYSCALL(__NR_getpmsg, sys_ni_syscall)
-#define __NR_putpmsg                           182
-__SYSCALL(__NR_putpmsg, sys_ni_syscall)
-
-/* reserved for AFS */
-#define __NR_afs_syscall                       183
-__SYSCALL(__NR_afs_syscall, sys_ni_syscall)
-
-/* reserved for tux */
-#define __NR_tuxcall                           184
-__SYSCALL(__NR_tuxcall, sys_ni_syscall)
-
-#define __NR_security                          185
-__SYSCALL(__NR_security, sys_ni_syscall)
-
-#define __NR_gettid                            186
-__SYSCALL(__NR_gettid, sys_gettid)
-
-#define __NR_readahead                         187
-__SYSCALL(__NR_readahead, sys_readahead)
-#define __NR_setxattr                          188
-__SYSCALL(__NR_setxattr, sys_setxattr)
-#define __NR_lsetxattr                         189
-__SYSCALL(__NR_lsetxattr, sys_lsetxattr)
-#define __NR_fsetxattr                         190
-__SYSCALL(__NR_fsetxattr, sys_fsetxattr)
-#define __NR_getxattr                          191
-__SYSCALL(__NR_getxattr, sys_getxattr)
-#define __NR_lgetxattr                         192
-__SYSCALL(__NR_lgetxattr, sys_lgetxattr)
-#define __NR_fgetxattr                         193
-__SYSCALL(__NR_fgetxattr, sys_fgetxattr)
-#define __NR_listxattr                         194
-__SYSCALL(__NR_listxattr, sys_listxattr)
-#define __NR_llistxattr                                195
-__SYSCALL(__NR_llistxattr, sys_llistxattr)
-#define __NR_flistxattr                                196
-__SYSCALL(__NR_flistxattr, sys_flistxattr)
-#define __NR_removexattr                       197
-__SYSCALL(__NR_removexattr, sys_removexattr)
-#define __NR_lremovexattr                      198
-__SYSCALL(__NR_lremovexattr, sys_lremovexattr)
-#define __NR_fremovexattr                      199
-__SYSCALL(__NR_fremovexattr, sys_fremovexattr)
-#define __NR_tkill                             200
-__SYSCALL(__NR_tkill, sys_tkill)
-#define __NR_time                              201
-__SYSCALL(__NR_time, sys_time)
-#define __NR_futex                             202
-__SYSCALL(__NR_futex, sys_futex)
-#define __NR_sched_setaffinity                 203
-__SYSCALL(__NR_sched_setaffinity, sys_sched_setaffinity)
-#define __NR_sched_getaffinity                 204
-__SYSCALL(__NR_sched_getaffinity, sys_sched_getaffinity)
-#define __NR_set_thread_area                   205
-__SYSCALL(__NR_set_thread_area, sys_ni_syscall)        /* use arch_prctl */
-#define __NR_io_setup                          206
-__SYSCALL(__NR_io_setup, sys_io_setup)
-#define __NR_io_destroy                                207
-__SYSCALL(__NR_io_destroy, sys_io_destroy)
-#define __NR_io_getevents                      208
-__SYSCALL(__NR_io_getevents, sys_io_getevents)
-#define __NR_io_submit                         209
-__SYSCALL(__NR_io_submit, sys_io_submit)
-#define __NR_io_cancel                         210
-__SYSCALL(__NR_io_cancel, sys_io_cancel)
-#define __NR_get_thread_area                   211
-__SYSCALL(__NR_get_thread_area, sys_ni_syscall)        /* use arch_prctl */
-#define __NR_lookup_dcookie                    212
-__SYSCALL(__NR_lookup_dcookie, sys_lookup_dcookie)
-#define __NR_epoll_create                      213
-__SYSCALL(__NR_epoll_create, sys_epoll_create)
-#define __NR_epoll_ctl_old                     214
-__SYSCALL(__NR_epoll_ctl_old, sys_ni_syscall)
-#define __NR_epoll_wait_old                    215
-__SYSCALL(__NR_epoll_wait_old, sys_ni_syscall)
-#define __NR_remap_file_pages                  216
-__SYSCALL(__NR_remap_file_pages, sys_remap_file_pages)
-#define __NR_getdents64                                217
-__SYSCALL(__NR_getdents64, sys_getdents64)
-#define __NR_set_tid_address                   218
-__SYSCALL(__NR_set_tid_address, sys_set_tid_address)
-#define __NR_restart_syscall                   219
-__SYSCALL(__NR_restart_syscall, sys_restart_syscall)
-#define __NR_semtimedop                                220
-__SYSCALL(__NR_semtimedop, sys_semtimedop)
-#define __NR_fadvise64                         221
-__SYSCALL(__NR_fadvise64, sys_fadvise64)
-#define __NR_timer_create                      222
-__SYSCALL(__NR_timer_create, sys_timer_create)
-#define __NR_timer_settime                     223
-__SYSCALL(__NR_timer_settime, sys_timer_settime)
-#define __NR_timer_gettime                     224
-__SYSCALL(__NR_timer_gettime, sys_timer_gettime)
-#define __NR_timer_getoverrun                  225
-__SYSCALL(__NR_timer_getoverrun, sys_timer_getoverrun)
-#define __NR_timer_delete                      226
-__SYSCALL(__NR_timer_delete, sys_timer_delete)
-#define __NR_clock_settime                     227
-__SYSCALL(__NR_clock_settime, sys_clock_settime)
-#define __NR_clock_gettime                     228
-__SYSCALL(__NR_clock_gettime, sys_clock_gettime)
-#define __NR_clock_getres                      229
-__SYSCALL(__NR_clock_getres, sys_clock_getres)
-#define __NR_clock_nanosleep                   230
-__SYSCALL(__NR_clock_nanosleep, sys_clock_nanosleep)
-#define __NR_exit_group                                231
-__SYSCALL(__NR_exit_group, sys_exit_group)
-#define __NR_epoll_wait                                232
-__SYSCALL(__NR_epoll_wait, sys_epoll_wait)
-#define __NR_epoll_ctl                         233
-__SYSCALL(__NR_epoll_ctl, sys_epoll_ctl)
-#define __NR_tgkill                            234
-__SYSCALL(__NR_tgkill, sys_tgkill)
-#define __NR_utimes                            235
-__SYSCALL(__NR_utimes, sys_utimes)
-#define __NR_vserver                           236
-__SYSCALL(__NR_vserver, sys_ni_syscall)
-#define __NR_mbind                             237
-__SYSCALL(__NR_mbind, sys_mbind)
-#define __NR_set_mempolicy                     238
-__SYSCALL(__NR_set_mempolicy, sys_set_mempolicy)
-#define __NR_get_mempolicy                     239
-__SYSCALL(__NR_get_mempolicy, sys_get_mempolicy)
-#define __NR_mq_open                           240
-__SYSCALL(__NR_mq_open, sys_mq_open)
-#define __NR_mq_unlink                         241
-__SYSCALL(__NR_mq_unlink, sys_mq_unlink)
-#define __NR_mq_timedsend                      242
-__SYSCALL(__NR_mq_timedsend, sys_mq_timedsend)
-#define __NR_mq_timedreceive                   243
-__SYSCALL(__NR_mq_timedreceive, sys_mq_timedreceive)
-#define __NR_mq_notify                         244
-__SYSCALL(__NR_mq_notify, sys_mq_notify)
-#define __NR_mq_getsetattr                     245
-__SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr)
-#define __NR_kexec_load                                246
-__SYSCALL(__NR_kexec_load, sys_kexec_load)
-#define __NR_waitid                            247
-__SYSCALL(__NR_waitid, sys_waitid)
-#define __NR_add_key                           248
-__SYSCALL(__NR_add_key, sys_add_key)
-#define __NR_request_key                       249
-__SYSCALL(__NR_request_key, sys_request_key)
-#define __NR_keyctl                            250
-__SYSCALL(__NR_keyctl, sys_keyctl)
-#define __NR_ioprio_set                                251
-__SYSCALL(__NR_ioprio_set, sys_ioprio_set)
-#define __NR_ioprio_get                                252
-__SYSCALL(__NR_ioprio_get, sys_ioprio_get)
-#define __NR_inotify_init                      253
-__SYSCALL(__NR_inotify_init, sys_inotify_init)
-#define __NR_inotify_add_watch                 254
-__SYSCALL(__NR_inotify_add_watch, sys_inotify_add_watch)
-#define __NR_inotify_rm_watch                  255
-__SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch)
-#define __NR_migrate_pages                     256
-__SYSCALL(__NR_migrate_pages, sys_migrate_pages)
-#define __NR_openat                            257
-__SYSCALL(__NR_openat, sys_openat)
-#define __NR_mkdirat                           258
-__SYSCALL(__NR_mkdirat, sys_mkdirat)
-#define __NR_mknodat                           259
-__SYSCALL(__NR_mknodat, sys_mknodat)
-#define __NR_fchownat                          260
-__SYSCALL(__NR_fchownat, sys_fchownat)
-#define __NR_futimesat                         261
-__SYSCALL(__NR_futimesat, sys_futimesat)
-#define __NR_newfstatat                                262
-__SYSCALL(__NR_newfstatat, sys_newfstatat)
-#define __NR_unlinkat                          263
-__SYSCALL(__NR_unlinkat, sys_unlinkat)
-#define __NR_renameat                          264
-__SYSCALL(__NR_renameat, sys_renameat)
-#define __NR_linkat                            265
-__SYSCALL(__NR_linkat, sys_linkat)
-#define __NR_symlinkat                         266
-__SYSCALL(__NR_symlinkat, sys_symlinkat)
-#define __NR_readlinkat                                267
-__SYSCALL(__NR_readlinkat, sys_readlinkat)
-#define __NR_fchmodat                          268
-__SYSCALL(__NR_fchmodat, sys_fchmodat)
-#define __NR_faccessat                         269
-__SYSCALL(__NR_faccessat, sys_faccessat)
-#define __NR_pselect6                          270
-__SYSCALL(__NR_pselect6, sys_pselect6)
-#define __NR_ppoll                             271
-__SYSCALL(__NR_ppoll,  sys_ppoll)
-#define __NR_unshare                           272
-__SYSCALL(__NR_unshare,        sys_unshare)
-#define __NR_set_robust_list                   273
-__SYSCALL(__NR_set_robust_list, sys_set_robust_list)
-#define __NR_get_robust_list                   274
-__SYSCALL(__NR_get_robust_list, sys_get_robust_list)
-#define __NR_splice                            275
-__SYSCALL(__NR_splice, sys_splice)
-#define __NR_tee                               276
-__SYSCALL(__NR_tee, sys_tee)
-#define __NR_sync_file_range                   277
-__SYSCALL(__NR_sync_file_range, sys_sync_file_range)
-#define __NR_vmsplice                          278
-__SYSCALL(__NR_vmsplice, sys_vmsplice)
-#define __NR_move_pages                                279
-__SYSCALL(__NR_move_pages, sys_move_pages)
-#define __NR_utimensat                         280
-__SYSCALL(__NR_utimensat, sys_utimensat)
-#define __NR_epoll_pwait                       281
-__SYSCALL(__NR_epoll_pwait, sys_epoll_pwait)
-#define __NR_signalfd                          282
-__SYSCALL(__NR_signalfd, sys_signalfd)
-#define __NR_timerfd_create                    283
-__SYSCALL(__NR_timerfd_create, sys_timerfd_create)
-#define __NR_eventfd                           284
-__SYSCALL(__NR_eventfd, sys_eventfd)
-#define __NR_fallocate                         285
-__SYSCALL(__NR_fallocate, sys_fallocate)
-#define __NR_timerfd_settime                   286
-__SYSCALL(__NR_timerfd_settime, sys_timerfd_settime)
-#define __NR_timerfd_gettime                   287
-__SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime)
-#define __NR_accept4                           288
-__SYSCALL(__NR_accept4, sys_accept4)
-#define __NR_signalfd4                         289
-__SYSCALL(__NR_signalfd4, sys_signalfd4)
-#define __NR_eventfd2                          290
-__SYSCALL(__NR_eventfd2, sys_eventfd2)
-#define __NR_epoll_create1                     291
-__SYSCALL(__NR_epoll_create1, sys_epoll_create1)
-#define __NR_dup3                              292
-__SYSCALL(__NR_dup3, sys_dup3)
-#define __NR_pipe2                             293
-__SYSCALL(__NR_pipe2, sys_pipe2)
-#define __NR_inotify_init1                     294
-__SYSCALL(__NR_inotify_init1, sys_inotify_init1)
-#define __NR_preadv                            295
-__SYSCALL(__NR_preadv, sys_preadv)
-#define __NR_pwritev                           296
-__SYSCALL(__NR_pwritev, sys_pwritev)
-#define __NR_rt_tgsigqueueinfo                 297
-__SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo)
-#define __NR_perf_event_open                   298
-__SYSCALL(__NR_perf_event_open, sys_perf_event_open)
-#define __NR_recvmmsg                          299
-__SYSCALL(__NR_recvmmsg, sys_recvmmsg)
-#define __NR_fanotify_init                     300
-__SYSCALL(__NR_fanotify_init, sys_fanotify_init)
-#define __NR_fanotify_mark                     301
-__SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
-#define __NR_prlimit64                         302
-__SYSCALL(__NR_prlimit64, sys_prlimit64)
-#define __NR_name_to_handle_at                 303
-__SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at)
-#define __NR_open_by_handle_at                 304
-__SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at)
-#define __NR_clock_adjtime                     305
-__SYSCALL(__NR_clock_adjtime, sys_clock_adjtime)
-#define __NR_syncfs                             306
-__SYSCALL(__NR_syncfs, sys_syncfs)
-#define __NR_sendmmsg                          307
-__SYSCALL(__NR_sendmmsg, sys_sendmmsg)
-#define __NR_setns                             308
-__SYSCALL(__NR_setns, sys_setns)
-#define __NR_getcpu                            309
-__SYSCALL(__NR_getcpu, sys_getcpu)
-#define __NR_process_vm_readv                  310
-__SYSCALL(__NR_process_vm_readv, sys_process_vm_readv)
-#define __NR_process_vm_writev                 311
-__SYSCALL(__NR_process_vm_writev, sys_process_vm_writev)
-
-#ifndef __NO_STUBS
-#define __ARCH_WANT_OLD_READDIR
-#define __ARCH_WANT_OLD_STAT
-#define __ARCH_WANT_SYS_ALARM
-#define __ARCH_WANT_SYS_GETHOSTNAME
-#define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_SGETMASK
-#define __ARCH_WANT_SYS_SIGNAL
-#define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_WAITPID
-#define __ARCH_WANT_SYS_SOCKETCALL
-#define __ARCH_WANT_SYS_FADVISE64
-#define __ARCH_WANT_SYS_GETPGRP
-#define __ARCH_WANT_SYS_LLSEEK
-#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
-#define __ARCH_WANT_SYS_OLD_UNAME
-#define __ARCH_WANT_SYS_OLDUMOUNT
-#define __ARCH_WANT_SYS_SIGPENDING
-#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_TIME
-#define __ARCH_WANT_COMPAT_SYS_TIME
-#endif /* __NO_STUBS */
-
-#ifdef __KERNEL__
-
-#ifndef COMPILE_OFFSETS
-#include <asm/asm-offsets.h>
-#define NR_syscalls (__NR_syscall_max + 1)
-#endif
-
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-#endif /* __KERNEL__ */
-
-#endif /* _ASM_X86_UNISTD_64_H */
index 8e862aaf0d905555e23265df00e139346d9b6649..becf47b81735ef6731e0271d0de7c0d939a389a9 100644 (file)
@@ -65,7 +65,7 @@
  * UV2: Bit 19 selects between
  *  (0): 10 microsecond timebase and
  *  (1): 80 microseconds
- *  we're using 655us, similar to UV1: 65 units of 10us
+ *  we're using 560us, similar to UV1: 65 units of 10us
  */
 #define UV1_INTD_SOFT_ACK_TIMEOUT_PERIOD (9UL)
 #define UV2_INTD_SOFT_ACK_TIMEOUT_PERIOD (15UL)
 #define FLUSH_RETRY_TIMEOUT            2
 #define FLUSH_GIVEUP                   3
 #define FLUSH_COMPLETE                 4
+#define FLUSH_RETRY_BUSYBUG            5
 
 /*
  * tuning the action when the numalink network is extremely delayed
@@ -235,10 +236,10 @@ struct bau_msg_payload {
 
 
 /*
- * Message header:  16 bytes (128 bits) (bytes 0x30-0x3f of descriptor)
+ * UV1 Message header:  16 bytes (128 bits) (bytes 0x30-0x3f of descriptor)
  * see table 4.2.3.0.1 in broacast_assist spec.
  */
-struct bau_msg_header {
+struct uv1_bau_msg_header {
        unsigned int    dest_subnodeid:6;       /* must be 0x10, for the LB */
        /* bits 5:0 */
        unsigned int    base_dest_nasid:15;     /* nasid of the first bit */
@@ -317,20 +318,88 @@ struct bau_msg_header {
        /* bits 127:107 */
 };
 
+/*
+ * UV2 Message header:  16 bytes (128 bits) (bytes 0x30-0x3f of descriptor)
+ * see figure 9-2 of harp_sys.pdf
+ */
+struct uv2_bau_msg_header {
+       unsigned int    base_dest_nasid:15;     /* nasid of the first bit */
+       /* bits 14:0 */                         /* in uvhub map */
+       unsigned int    dest_subnodeid:5;       /* must be 0x10, for the LB */
+       /* bits 19:15 */
+       unsigned int    rsvd_1:1;               /* must be zero */
+       /* bit 20 */
+       /* Address bits 59:21 */
+       /* bits 25:2 of address (44:21) are payload */
+       /* these next 24 bits become bytes 12-14 of msg */
+       /* bits 28:21 land in byte 12 */
+       unsigned int    replied_to:1;           /* sent as 0 by the source to
+                                                  byte 12 */
+       /* bit 21 */
+       unsigned int    msg_type:3;             /* software type of the
+                                                  message */
+       /* bits 24:22 */
+       unsigned int    canceled:1;             /* message canceled, resource
+                                                  is to be freed*/
+       /* bit 25 */
+       unsigned int    payload_1:3;            /* not currently used */
+       /* bits 28:26 */
+
+       /* bits 36:29 land in byte 13 */
+       unsigned int    payload_2a:3;           /* not currently used */
+       unsigned int    payload_2b:5;           /* not currently used */
+       /* bits 36:29 */
+
+       /* bits 44:37 land in byte 14 */
+       unsigned int    payload_3:8;            /* not currently used */
+       /* bits 44:37 */
+
+       unsigned int    rsvd_2:7;               /* reserved */
+       /* bits 51:45 */
+       unsigned int    swack_flag:1;           /* software acknowledge flag */
+       /* bit 52 */
+       unsigned int    rsvd_3a:3;              /* must be zero */
+       unsigned int    rsvd_3b:8;              /* must be zero */
+       unsigned int    rsvd_3c:8;              /* must be zero */
+       unsigned int    rsvd_3d:3;              /* must be zero */
+       /* bits 74:53 */
+       unsigned int    fairness:3;             /* usually zero */
+       /* bits 77:75 */
+
+       unsigned int    sequence:16;            /* message sequence number */
+       /* bits 93:78  Suppl_A  */
+       unsigned int    chaining:1;             /* next descriptor is part of
+                                                  this activation*/
+       /* bit 94 */
+       unsigned int    multilevel:1;           /* multi-level multicast
+                                                  format */
+       /* bit 95 */
+       unsigned int    rsvd_4:24;              /* ordered / source node /
+                                                  source subnode / aging
+                                                  must be zero */
+       /* bits 119:96 */
+       unsigned int    command:8;              /* message type */
+       /* bits 127:120 */
+};
+
 /*
  * The activation descriptor:
  * The format of the message to send, plus all accompanying control
  * Should be 64 bytes
  */
 struct bau_desc {
-       struct pnmask                   distribution;
+       struct pnmask                           distribution;
        /*
         * message template, consisting of header and payload:
         */
-       struct bau_msg_header           header;
-       struct bau_msg_payload          payload;
+       union bau_msg_header {
+               struct uv1_bau_msg_header       uv1_hdr;
+               struct uv2_bau_msg_header       uv2_hdr;
+       } header;
+
+       struct bau_msg_payload                  payload;
 };
-/*
+/* UV1:
  *   -payload--    ---------header------
  *   bytes 0-11    bits 41-56  bits 58-81
  *       A           B  (2)      C (3)
@@ -340,6 +409,16 @@ struct bau_desc {
  *   bytes 0-11  bytes 12-14  bytes 16-17  (byte 15 filled in by hw as vector)
  *   ------------payload queue-----------
  */
+/* UV2:
+ *   -payload--    ---------header------
+ *   bytes 0-11    bits 70-78  bits 21-44
+ *       A           B  (2)      C (3)
+ *
+ *            A/B/C are moved to:
+ *       A            C          B
+ *   bytes 0-11  bytes 12-14  bytes 16-17  (byte 15 filled in by hw as vector)
+ *   ------------payload queue-----------
+ */
 
 /*
  * The payload queue on the destination side is an array of these.
@@ -385,7 +464,6 @@ struct bau_pq_entry {
 struct msg_desc {
        struct bau_pq_entry     *msg;
        int                     msg_slot;
-       int                     swack_slot;
        struct bau_pq_entry     *queue_first;
        struct bau_pq_entry     *queue_last;
 };
@@ -405,6 +483,7 @@ struct ptc_stats {
                                                   requests */
        unsigned long   s_stimeout;             /* source side timeouts */
        unsigned long   s_dtimeout;             /* destination side timeouts */
+       unsigned long   s_strongnacks;          /* number of strong nack's */
        unsigned long   s_time;                 /* time spent in sending side */
        unsigned long   s_retriesok;            /* successful retries */
        unsigned long   s_ntargcpu;             /* total number of cpu's
@@ -439,6 +518,9 @@ struct ptc_stats {
        unsigned long   s_retry_messages;       /* retry broadcasts */
        unsigned long   s_bau_reenabled;        /* for bau enable/disable */
        unsigned long   s_bau_disabled;         /* for bau enable/disable */
+       unsigned long   s_uv2_wars;             /* uv2 workaround, perm. busy */
+       unsigned long   s_uv2_wars_hw;          /* uv2 workaround, hiwater */
+       unsigned long   s_uv2_war_waits;        /* uv2 workaround, long waits */
        /* destination statistics */
        unsigned long   d_alltlb;               /* times all tlb's on this
                                                   cpu were flushed */
@@ -511,9 +593,12 @@ struct bau_control {
        short                   osnode;
        short                   uvhub_cpu;
        short                   uvhub;
+       short                   uvhub_version;
        short                   cpus_in_socket;
        short                   cpus_in_uvhub;
        short                   partition_base_pnode;
+       short                   using_desc; /* an index, like uvhub_cpu */
+       unsigned int            inuse_map;
        unsigned short          message_number;
        unsigned short          uvhub_quiesce;
        short                   socket_acknowledge_count[DEST_Q_SIZE];
@@ -531,6 +616,7 @@ struct bau_control {
        int                     cong_response_us;
        int                     cong_reps;
        int                     cong_period;
+       unsigned long           clocks_per_100_usec;
        cycles_t                period_time;
        long                    period_requests;
        struct hub_and_pnode    *thp;
@@ -591,6 +677,11 @@ static inline void write_mmr_sw_ack(unsigned long mr)
        uv_write_local_mmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, mr);
 }
 
+static inline void write_gmmr_sw_ack(int pnode, unsigned long mr)
+{
+       write_gmmr(pnode, UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, mr);
+}
+
 static inline unsigned long read_mmr_sw_ack(void)
 {
        return read_lmmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE);
index 02b2f05b371e9a8a8c84fb2f0bd5742b1d8d6963..5369059c07a907fac7e6a755aa24e7ae280bd6a0 100644 (file)
@@ -25,7 +25,8 @@ obj-$(CONFIG_IRQ_WORK)  += irq_work.o
 obj-y                  += probe_roms.o
 obj-$(CONFIG_X86_32)   += sys_i386_32.o i386_ksyms_32.o
 obj-$(CONFIG_X86_64)   += sys_x86_64.o x8664_ksyms_64.o
-obj-$(CONFIG_X86_64)   += syscall_64.o vsyscall_64.o
+obj-y                  += syscall_$(BITS).o
+obj-$(CONFIG_X86_64)   += vsyscall_64.o
 obj-$(CONFIG_X86_64)   += vsyscall_emu_64.o
 obj-y                  += bootflag.o e820.o
 obj-y                  += pci-dma.o quirks.o topology.o kdebugfs.o
index 9d59bbacd4e3cb7a76474a59e2965c739140d475..79b05b88aa193900ceead712dd2f36e3c6e25c9c 100644 (file)
@@ -769,7 +769,12 @@ void __init uv_system_init(void)
        for(i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++)
                uv_possible_blades +=
                  hweight64(uv_read_local_mmr( UVH_NODE_PRESENT_TABLE + i * 8));
-       printk(KERN_DEBUG "UV: Found %d blades\n", uv_num_possible_blades());
+
+       /* uv_num_possible_blades() is really the hub count */
+       printk(KERN_INFO "UV: Found %d blades, %d hubs\n",
+                       is_uv1_hub() ? uv_num_possible_blades() :
+                       (uv_num_possible_blades() + 1) / 2,
+                       uv_num_possible_blades());
 
        bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades();
        uv_blade_info = kzalloc(bytes, GFP_KERNEL);
index a46bd383953cd1dc299648e5c25e8b83744ae4f8..f76623cbe263ee0f95d847845118f84f56974be9 100644 (file)
@@ -383,21 +383,21 @@ static int ignore_sys_suspend;
 static int ignore_normal_resume;
 static int bounce_interval __read_mostly = DEFAULT_BOUNCE_INTERVAL;
 
-static int debug __read_mostly;
-static int smp __read_mostly;
+static bool debug __read_mostly;
+static bool smp __read_mostly;
 static int apm_disabled = -1;
 #ifdef CONFIG_SMP
-static int power_off;
+static bool power_off;
 #else
-static int power_off = 1;
+static bool power_off = 1;
 #endif
-static int realmode_power_off;
+static bool realmode_power_off;
 #ifdef CONFIG_APM_ALLOW_INTS
-static int allow_ints = 1;
+static bool allow_ints = 1;
 #else
-static int allow_ints;
+static bool allow_ints;
 #endif
-static int broken_psr;
+static bool broken_psr;
 
 static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
 static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
index 395a10e68067625e783b0ed1f8546231727ac230..85d98ab15cdcfd019c1d8bc6ece2f049ace07b65 100644 (file)
@@ -3,6 +3,11 @@
 #include <linux/lguest.h>
 #include "../../../drivers/lguest/lg.h"
 
+#define __SYSCALL_I386(nr, sym, compat) [nr] = 1,
+static char syscalls[] = {
+#include <asm/syscalls_32.h>
+};
+
 /* workaround for a warning with -Wmissing-prototypes */
 void foo(void);
 
@@ -76,4 +81,7 @@ void foo(void)
        OFFSET(LGUEST_PAGES_regs_errcode, lguest_pages, regs.errcode);
        OFFSET(LGUEST_PAGES_regs, lguest_pages, regs);
 #endif
+       BLANK();
+       DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
+       DEFINE(NR_syscalls, sizeof(syscalls));
 }
index e72a1194af22a76707a9f44865b8211b4b1e1e7c..834e897b1e25b66e864d010266e5df29fecfb892 100644 (file)
@@ -1,11 +1,12 @@
 #include <asm/ia32.h>
 
-#define __NO_STUBS 1
-#undef __SYSCALL
-#undef _ASM_X86_UNISTD_64_H
-#define __SYSCALL(nr, sym) [nr] = 1,
-static char syscalls[] = {
-#include <asm/unistd.h>
+#define __SYSCALL_64(nr, sym, compat) [nr] = 1,
+static char syscalls_64[] = {
+#include <asm/syscalls_64.h>
+};
+#define __SYSCALL_I386(nr, sym, compat) [nr] = 1,
+static char syscalls_ia32[] = {
+#include <asm/syscalls_32.h>
 };
 
 int main(void)
@@ -72,7 +73,11 @@ int main(void)
        OFFSET(TSS_ist, tss_struct, x86_tss.ist);
        BLANK();
 
-       DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
+       DEFINE(__NR_syscall_max, sizeof(syscalls_64) - 1);
+       DEFINE(NR_syscalls, sizeof(syscalls_64));
+
+       DEFINE(__NR_ia32_syscall_max, sizeof(syscalls_ia32) - 1);
+       DEFINE(IA32_NR_syscalls, sizeof(syscalls_ia32));
 
        return 0;
 }
index 850f2963a4209c8ab62a96d79c043e10f9689e87..d43cad74f1661c2180cc1f9277b9553b3de7cf63 100644 (file)
@@ -1021,6 +1021,8 @@ __setup("clearcpuid=", setup_disablecpuid);
 
 #ifdef CONFIG_X86_64
 struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table };
+struct desc_ptr nmi_idt_descr = { NR_VECTORS * 16 - 1,
+                                   (unsigned long) nmi_idt_table };
 
 DEFINE_PER_CPU_FIRST(union irq_stack_union,
                     irq_stack_union) __aligned(PAGE_SIZE);
@@ -1085,6 +1087,26 @@ unsigned long kernel_eflags;
  */
 DEFINE_PER_CPU(struct orig_ist, orig_ist);
 
+static DEFINE_PER_CPU(unsigned long, debug_stack_addr);
+DEFINE_PER_CPU(int, debug_stack_usage);
+
+int is_debug_stack(unsigned long addr)
+{
+       return __get_cpu_var(debug_stack_usage) ||
+               (addr <= __get_cpu_var(debug_stack_addr) &&
+                addr > (__get_cpu_var(debug_stack_addr) - DEBUG_STKSZ));
+}
+
+void debug_stack_set_zero(void)
+{
+       load_idt((const struct desc_ptr *)&nmi_idt_descr);
+}
+
+void debug_stack_reset(void)
+{
+       load_idt((const struct desc_ptr *)&idt_descr);
+}
+
 #else  /* CONFIG_X86_64 */
 
 DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
@@ -1212,6 +1234,8 @@ void __cpuinit cpu_init(void)
                        estacks += exception_stack_sizes[v];
                        oist->ist[v] = t->x86_tss.ist[v] =
                                        (unsigned long)estacks;
+                       if (v == DEBUG_STACK-1)
+                               per_cpu(debug_stack_addr, cpu) = (unsigned long)estacks;
                }
        }
 
index f22a9f7f6390a62ce3d028df8dba0723b232b28a..5a11ae2e9e917a07eae73246c7a73ace07edda39 100644 (file)
@@ -1859,7 +1859,7 @@ static struct bus_type mce_subsys = {
        .dev_name       = "machinecheck",
 };
 
-DEFINE_PER_CPU(struct device, mce_device);
+struct device *mce_device[CONFIG_NR_CPUS];
 
 __cpuinitdata
 void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
@@ -2001,19 +2001,27 @@ static struct device_attribute *mce_device_attrs[] = {
 
 static cpumask_var_t mce_device_initialized;
 
+static void mce_device_release(struct device *dev)
+{
+       kfree(dev);
+}
+
 /* Per cpu device init. All of the cpus still share the same ctrl bank: */
 static __cpuinit int mce_device_create(unsigned int cpu)
 {
-       struct device *dev = &per_cpu(mce_device, cpu);
+       struct device *dev;
        int err;
        int i, j;
 
        if (!mce_available(&boot_cpu_data))
                return -EIO;
 
-       memset(&dev->kobj, 0, sizeof(struct kobject));
+       dev = kzalloc(sizeof *dev, GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
        dev->id  = cpu;
        dev->bus = &mce_subsys;
+       dev->release = &mce_device_release;
 
        err = device_register(dev);
        if (err)
@@ -2030,6 +2038,7 @@ static __cpuinit int mce_device_create(unsigned int cpu)
                        goto error2;
        }
        cpumask_set_cpu(cpu, mce_device_initialized);
+       mce_device[cpu] = dev;
 
        return 0;
 error2:
@@ -2046,7 +2055,7 @@ error:
 
 static __cpuinit void mce_device_remove(unsigned int cpu)
 {
-       struct device *dev = &per_cpu(mce_device, cpu);
+       struct device *dev = mce_device[cpu];
        int i;
 
        if (!cpumask_test_cpu(cpu, mce_device_initialized))
@@ -2060,6 +2069,7 @@ static __cpuinit void mce_device_remove(unsigned int cpu)
 
        device_unregister(dev);
        cpumask_clear_cpu(cpu, mce_device_initialized);
+       mce_device[cpu] = NULL;
 }
 
 /* Make sure there are no machine checks on offlined CPUs. */
index ba0b94a7e2040fcbd09de26a8729628758fd3370..786e76a86322c99ffd67a6fd9ebf03f85b1d36a3 100644 (file)
@@ -523,6 +523,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
 {
        int i, err = 0;
        struct threshold_bank *b = NULL;
+       struct device *dev = mce_device[cpu];
        char name[32];
 
        sprintf(name, "threshold_bank%i", bank);
@@ -543,8 +544,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
                if (!b)
                        goto out;
 
-               err = sysfs_create_link(&per_cpu(mce_device, cpu).kobj,
-                                       b->kobj, name);
+               err = sysfs_create_link(&dev->kobj, b->kobj, name);
                if (err)
                        goto out;
 
@@ -565,7 +565,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
                goto out;
        }
 
-       b->kobj = kobject_create_and_add(name, &per_cpu(mce_device, cpu).kobj);
+       b->kobj = kobject_create_and_add(name, &dev->kobj);
        if (!b->kobj)
                goto out_free;
 
@@ -585,8 +585,9 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
                if (i == cpu)
                        continue;
 
-               err = sysfs_create_link(&per_cpu(mce_device, i).kobj,
-                                       b->kobj, name);
+               dev = mce_device[i];
+               if (dev)
+                       err = sysfs_create_link(&dev->kobj,b->kobj, name);
                if (err)
                        goto out;
 
@@ -649,6 +650,7 @@ static void deallocate_threshold_block(unsigned int cpu,
 static void threshold_remove_bank(unsigned int cpu, int bank)
 {
        struct threshold_bank *b;
+       struct device *dev;
        char name[32];
        int i = 0;
 
@@ -663,7 +665,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank)
 #ifdef CONFIG_SMP
        /* sibling symlink */
        if (shared_bank[bank] && b->blocks->cpu != cpu) {
-               sysfs_remove_link(&per_cpu(mce_device, cpu).kobj, name);
+               sysfs_remove_link(&mce_device[cpu]->kobj, name);
                per_cpu(threshold_banks, cpu)[bank] = NULL;
 
                return;
@@ -675,7 +677,9 @@ static void threshold_remove_bank(unsigned int cpu, int bank)
                if (i == cpu)
                        continue;
 
-               sysfs_remove_link(&per_cpu(mce_device, i).kobj, name);
+               dev = mce_device[i];
+               if (dev)
+                       sysfs_remove_link(&dev->kobj, name);
                per_cpu(threshold_banks, i)[bank] = NULL;
        }
 
index 174d938d576b347365f4fdab2de8e7b85fd36f53..62d61e9976eb0a83bca3aae5c979bb63505c0bbb 100644 (file)
@@ -703,7 +703,7 @@ void __init e820_mark_nosave_regions(unsigned long limit_pfn)
 }
 #endif
 
-#ifdef CONFIG_HIBERNATION
+#ifdef CONFIG_ACPI
 /**
  * Mark ACPI NVS memory region, so that we can save/restore it during
  * hibernation and the subsequent resume.
@@ -716,7 +716,7 @@ static int __init e820_mark_nvs_memory(void)
                struct e820entry *ei = &e820.map[i];
 
                if (ei->type == E820_NVS)
-                       suspend_nvs_register(ei->addr, ei->size);
+                       acpi_nvs_register(ei->addr, ei->size);
        }
 
        return 0;
index 22d0e21b4dd793fa509e52541bf9b57e7778d1d7..79d97e68f04238ac13993e89c016e67a7b647af6 100644 (file)
@@ -42,6 +42,7 @@
  */
 
 #include <linux/linkage.h>
+#include <linux/err.h>
 #include <asm/thread_info.h>
 #include <asm/irqflags.h>
 #include <asm/errno.h>
@@ -81,8 +82,6 @@
  * enough to patch inline, increasing performance.
  */
 
-#define nr_syscalls ((syscall_table_size)/4)
-
 #ifdef CONFIG_PREEMPT
 #define preempt_stop(clobbers) DISABLE_INTERRUPTS(clobbers); TRACE_IRQS_OFF
 #else
@@ -423,7 +422,7 @@ sysenter_past_esp:
        testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
        jnz sysenter_audit
 sysenter_do_call:
-       cmpl $(nr_syscalls), %eax
+       cmpl $(NR_syscalls), %eax
        jae syscall_badsys
        call *sys_call_table(,%eax,4)
        movl %eax,PT_EAX(%esp)
@@ -455,7 +454,7 @@ sysenter_audit:
        movl %ebx,%ecx                  /* 3rd arg: 1st syscall arg */
        movl %eax,%edx                  /* 2nd arg: syscall number */
        movl $AUDIT_ARCH_I386,%eax      /* 1st arg: audit arch */
-       call audit_syscall_entry
+       call __audit_syscall_entry
        pushl_cfi %ebx
        movl PT_EAX(%esp),%eax          /* reload syscall number */
        jmp sysenter_do_call
@@ -466,11 +465,10 @@ sysexit_audit:
        TRACE_IRQS_ON
        ENABLE_INTERRUPTS(CLBR_ANY)
        movl %eax,%edx          /* second arg, syscall return value */
-       cmpl $0,%eax            /* is it < 0? */
-       setl %al                /* 1 if so, 0 if not */
+       cmpl $-MAX_ERRNO,%eax   /* is it an error ? */
+       setbe %al               /* 1 if so, 0 if not */
        movzbl %al,%eax         /* zero-extend that */
-       inc %eax /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */
-       call audit_syscall_exit
+       call __audit_syscall_exit
        DISABLE_INTERRUPTS(CLBR_ANY)
        TRACE_IRQS_OFF
        movl TI_flags(%ebp), %ecx
@@ -504,7 +502,7 @@ ENTRY(system_call)
                                        # system call tracing in operation / emulation
        testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
        jnz syscall_trace_entry
-       cmpl $(nr_syscalls), %eax
+       cmpl $(NR_syscalls), %eax
        jae syscall_badsys
 syscall_call:
        call *sys_call_table(,%eax,4)
@@ -654,7 +652,7 @@ syscall_trace_entry:
        movl %esp, %eax
        call syscall_trace_enter
        /* What it returned is what we'll actually use.  */
-       cmpl $(nr_syscalls), %eax
+       cmpl $(NR_syscalls), %eax
        jnae syscall_call
        jmp syscall_exit
 END(syscall_trace_entry)
@@ -694,29 +692,28 @@ END(syscall_badsys)
  * System calls that need a pt_regs pointer.
  */
 #define PTREGSCALL0(name) \
-       ALIGN; \
-ptregs_##name: \
+ENTRY(ptregs_##name) ;  \
        leal 4(%esp),%eax; \
-       jmp sys_##name;
+       jmp sys_##name; \
+ENDPROC(ptregs_##name)
 
 #define PTREGSCALL1(name) \
-       ALIGN; \
-ptregs_##name: \
+ENTRY(ptregs_##name) ; \
        leal 4(%esp),%edx; \
        movl (PT_EBX+4)(%esp),%eax; \
-       jmp sys_##name;
+       jmp sys_##name; \
+ENDPROC(ptregs_##name)
 
 #define PTREGSCALL2(name) \
-       ALIGN; \
-ptregs_##name: \
+ENTRY(ptregs_##name) ; \
        leal 4(%esp),%ecx; \
        movl (PT_ECX+4)(%esp),%edx; \
        movl (PT_EBX+4)(%esp),%eax; \
-       jmp sys_##name;
+       jmp sys_##name; \
+ENDPROC(ptregs_##name)
 
 #define PTREGSCALL3(name) \
-       ALIGN; \
-ptregs_##name: \
+ENTRY(ptregs_##name) ; \
        CFI_STARTPROC; \
        leal 4(%esp),%eax; \
        pushl_cfi %eax; \
@@ -741,8 +738,7 @@ PTREGSCALL2(vm86)
 PTREGSCALL1(vm86old)
 
 /* Clone is an oddball.  The 4th arg is in %edi */
-       ALIGN;
-ptregs_clone:
+ENTRY(ptregs_clone)
        CFI_STARTPROC
        leal 4(%esp),%eax
        pushl_cfi %eax
@@ -1213,11 +1209,6 @@ return_to_handler:
        jmp *%ecx
 #endif
 
-.section .rodata,"a"
-#include "syscall_table_32.S"
-
-syscall_table_size=(.-sys_call_table)
-
 /*
  * Some functions should be protected against kprobes
  */
index a20e1cb9dc87fea597cbd69cda747d314f4ad68e..3fe8239fd8fbd8ef692f57517d0d1dbd37f284ae 100644 (file)
@@ -55,6 +55,7 @@
 #include <asm/paravirt.h>
 #include <asm/ftrace.h>
 #include <asm/percpu.h>
+#include <linux/err.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
 #include <linux/elf-em.h>
@@ -548,7 +549,7 @@ badsys:
 #ifdef CONFIG_AUDITSYSCALL
        /*
         * Fast path for syscall audit without full syscall trace.
-        * We just call audit_syscall_entry() directly, and then
+        * We just call __audit_syscall_entry() directly, and then
         * jump back to the normal fast path.
         */
 auditsys:
@@ -558,22 +559,21 @@ auditsys:
        movq %rdi,%rdx                  /* 3rd arg: 1st syscall arg */
        movq %rax,%rsi                  /* 2nd arg: syscall number */
        movl $AUDIT_ARCH_X86_64,%edi    /* 1st arg: audit arch */
-       call audit_syscall_entry
+       call __audit_syscall_entry
        LOAD_ARGS 0             /* reload call-clobbered registers */
        jmp system_call_fastpath
 
        /*
-        * Return fast path for syscall audit.  Call audit_syscall_exit()
+        * Return fast path for syscall audit.  Call __audit_syscall_exit()
         * directly and then jump back to the fast path with TIF_SYSCALL_AUDIT
         * masked off.
         */
 sysret_audit:
        movq RAX-ARGOFFSET(%rsp),%rsi   /* second arg, syscall return value */
-       cmpq $0,%rsi            /* is it < 0? */
-       setl %al                /* 1 if so, 0 if not */
+       cmpq $-MAX_ERRNO,%rsi   /* is it < -MAX_ERRNO? */
+       setbe %al               /* 1 if so, 0 if not */
        movzbl %al,%edi         /* zero-extend that into %edi */
-       inc %edi /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */
-       call audit_syscall_exit
+       call __audit_syscall_exit
        movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi
        jmp sysret_check
 #endif /* CONFIG_AUDITSYSCALL */
@@ -1480,62 +1480,214 @@ ENTRY(error_exit)
        CFI_ENDPROC
 END(error_exit)
 
+/*
+ * Test if a given stack is an NMI stack or not.
+ */
+       .macro test_in_nmi reg stack nmi_ret normal_ret
+       cmpq %\reg, \stack
+       ja \normal_ret
+       subq $EXCEPTION_STKSZ, %\reg
+       cmpq %\reg, \stack
+       jb \normal_ret
+       jmp \nmi_ret
+       .endm
 
        /* runs on exception stack */
 ENTRY(nmi)
        INTR_FRAME
        PARAVIRT_ADJUST_EXCEPTION_FRAME
-       pushq_cfi $-1
+       /*
+        * We allow breakpoints in NMIs. If a breakpoint occurs, then
+        * the iretq it performs will take us out of NMI context.
+        * This means that we can have nested NMIs where the next
+        * NMI is using the top of the stack of the previous NMI. We
+        * can't let it execute because the nested NMI will corrupt the
+        * stack of the previous NMI. NMI handlers are not re-entrant
+        * anyway.
+        *
+        * To handle this case we do the following:
+        *  Check the a special location on the stack that contains
+        *  a variable that is set when NMIs are executing.
+        *  The interrupted task's stack is also checked to see if it
+        *  is an NMI stack.
+        *  If the variable is not set and the stack is not the NMI
+        *  stack then:
+        *    o Set the special variable on the stack
+        *    o Copy the interrupt frame into a "saved" location on the stack
+        *    o Copy the interrupt frame into a "copy" location on the stack
+        *    o Continue processing the NMI
+        *  If the variable is set or the previous stack is the NMI stack:
+        *    o Modify the "copy" location to jump to the repeate_nmi
+        *    o return back to the first NMI
+        *
+        * Now on exit of the first NMI, we first clear the stack variable
+        * The NMI stack will tell any nested NMIs at that point that it is
+        * nested. Then we pop the stack normally with iret, and if there was
+        * a nested NMI that updated the copy interrupt stack frame, a
+        * jump will be made to the repeat_nmi code that will handle the second
+        * NMI.
+        */
+
+       /* Use %rdx as out temp variable throughout */
+       pushq_cfi %rdx
+
+       /*
+        * Check the special variable on the stack to see if NMIs are
+        * executing.
+        */
+       cmp $1, -8(%rsp)
+       je nested_nmi
+
+       /*
+        * Now test if the previous stack was an NMI stack.
+        * We need the double check. We check the NMI stack to satisfy the
+        * race when the first NMI clears the variable before returning.
+        * We check the variable because the first NMI could be in a
+        * breakpoint routine using a breakpoint stack.
+        */
+       lea 6*8(%rsp), %rdx
+       test_in_nmi rdx, 4*8(%rsp), nested_nmi, first_nmi
+
+nested_nmi:
+       /*
+        * Do nothing if we interrupted the fixup in repeat_nmi.
+        * It's about to repeat the NMI handler, so we are fine
+        * with ignoring this one.
+        */
+       movq $repeat_nmi, %rdx
+       cmpq 8(%rsp), %rdx
+       ja 1f
+       movq $end_repeat_nmi, %rdx
+       cmpq 8(%rsp), %rdx
+       ja nested_nmi_out
+
+1:
+       /* Set up the interrupted NMIs stack to jump to repeat_nmi */
+       leaq -6*8(%rsp), %rdx
+       movq %rdx, %rsp
+       CFI_ADJUST_CFA_OFFSET 6*8
+       pushq_cfi $__KERNEL_DS
+       pushq_cfi %rdx
+       pushfq_cfi
+       pushq_cfi $__KERNEL_CS
+       pushq_cfi $repeat_nmi
+
+       /* Put stack back */
+       addq $(11*8), %rsp
+       CFI_ADJUST_CFA_OFFSET -11*8
+
+nested_nmi_out:
+       popq_cfi %rdx
+
+       /* No need to check faults here */
+       INTERRUPT_RETURN
+
+first_nmi:
+       /*
+        * Because nested NMIs will use the pushed location that we
+        * stored in rdx, we must keep that space available.
+        * Here's what our stack frame will look like:
+        * +-------------------------+
+        * | original SS             |
+        * | original Return RSP     |
+        * | original RFLAGS         |
+        * | original CS             |
+        * | original RIP            |
+        * +-------------------------+
+        * | temp storage for rdx    |
+        * +-------------------------+
+        * | NMI executing variable  |
+        * +-------------------------+
+        * | Saved SS                |
+        * | Saved Return RSP        |
+        * | Saved RFLAGS            |
+        * | Saved CS                |
+        * | Saved RIP               |
+        * +-------------------------+
+        * | copied SS               |
+        * | copied Return RSP       |
+        * | copied RFLAGS           |
+        * | copied CS               |
+        * | copied RIP              |
+        * +-------------------------+
+        * | pt_regs                 |
+        * +-------------------------+
+        *
+        * The saved RIP is used to fix up the copied RIP that a nested
+        * NMI may zero out. The original stack frame and the temp storage
+        * is also used by nested NMIs and can not be trusted on exit.
+        */
+       /* Set the NMI executing variable on the stack. */
+       pushq_cfi $1
+
+       /* Copy the stack frame to the Saved frame */
+       .rept 5
+       pushq_cfi 6*8(%rsp)
+       .endr
+
+       /* Make another copy, this one may be modified by nested NMIs */
+       .rept 5
+       pushq_cfi 4*8(%rsp)
+       .endr
+
+       /* Do not pop rdx, nested NMIs will corrupt it */
+       movq 11*8(%rsp), %rdx
+
+       /*
+        * Everything below this point can be preempted by a nested
+        * NMI if the first NMI took an exception. Repeated NMIs
+        * caused by an exception and nested NMI will start here, and
+        * can still be preempted by another NMI.
+        */
+restart_nmi:
+       pushq_cfi $-1           /* ORIG_RAX: no syscall to restart */
        subq $ORIG_RAX-R15, %rsp
        CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
+       /*
+        * Use save_paranoid to handle SWAPGS, but no need to use paranoid_exit
+        * as we should not be calling schedule in NMI context.
+        * Even with normal interrupts enabled. An NMI should not be
+        * setting NEED_RESCHED or anything that normal interrupts and
+        * exceptions might do.
+        */
        call save_paranoid
        DEFAULT_FRAME 0
        /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
        movq %rsp,%rdi
        movq $-1,%rsi
        call do_nmi
-#ifdef CONFIG_TRACE_IRQFLAGS
-       /* paranoidexit; without TRACE_IRQS_OFF */
-       /* ebx: no swapgs flag */
-       DISABLE_INTERRUPTS(CLBR_NONE)
        testl %ebx,%ebx                         /* swapgs needed? */
        jnz nmi_restore
-       testl $3,CS(%rsp)
-       jnz nmi_userspace
 nmi_swapgs:
        SWAPGS_UNSAFE_STACK
 nmi_restore:
        RESTORE_ALL 8
+       /* Clear the NMI executing stack variable */
+       movq $0, 10*8(%rsp)
        jmp irq_return
-nmi_userspace:
-       GET_THREAD_INFO(%rcx)
-       movl TI_flags(%rcx),%ebx
-       andl $_TIF_WORK_MASK,%ebx
-       jz nmi_swapgs
-       movq %rsp,%rdi                  /* &pt_regs */
-       call sync_regs
-       movq %rax,%rsp                  /* switch stack for scheduling */
-       testl $_TIF_NEED_RESCHED,%ebx
-       jnz nmi_schedule
-       movl %ebx,%edx                  /* arg3: thread flags */
-       ENABLE_INTERRUPTS(CLBR_NONE)
-       xorl %esi,%esi                  /* arg2: oldset */
-       movq %rsp,%rdi                  /* arg1: &pt_regs */
-       call do_notify_resume
-       DISABLE_INTERRUPTS(CLBR_NONE)
-       jmp nmi_userspace
-nmi_schedule:
-       ENABLE_INTERRUPTS(CLBR_ANY)
-       call schedule
-       DISABLE_INTERRUPTS(CLBR_ANY)
-       jmp nmi_userspace
-       CFI_ENDPROC
-#else
-       jmp paranoid_exit
        CFI_ENDPROC
-#endif
 END(nmi)
 
+       /*
+        * If an NMI hit an iret because of an exception or breakpoint,
+        * it can lose its NMI context, and a nested NMI may come in.
+        * In that case, the nested NMI will change the preempted NMI's
+        * stack to jump to here when it does the final iret.
+        */
+repeat_nmi:
+       INTR_FRAME
+       /* Update the stack variable to say we are still in NMI */
+       movq $1, 5*8(%rsp)
+
+       /* copy the saved stack back to copy stack */
+       .rept 5
+       pushq_cfi 4*8(%rsp)
+       .endr
+
+       jmp restart_nmi
+       CFI_ENDPROC
+end_repeat_nmi:
+
 ENTRY(ignore_sysret)
        CFI_STARTPROC
        mov $-ENOSYS,%eax
index e11e39478a4978643559e650844cb9941c876523..40f4eb3766d1d2a669790d36d3c6e28eff42b87b 100644 (file)
@@ -417,6 +417,10 @@ ENTRY(phys_base)
 ENTRY(idt_table)
        .skip IDT_ENTRIES * 16
 
+       .align L1_CACHE_BYTES
+ENTRY(nmi_idt_table)
+       .skip IDT_ENTRIES * 16
+
        __PAGE_ALIGNED_BSS
        .align PAGE_SIZE
 ENTRY(empty_zero_page)
index e88f37b58dddeeaecfb8951649db799986b7e247..47acaf31916592d48995fa8fcb27ee9a0ce30139 100644 (file)
@@ -405,9 +405,108 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
                unknown_nmi_error(reason, regs);
 }
 
+/*
+ * NMIs can hit breakpoints which will cause it to lose its
+ * NMI context with the CPU when the breakpoint does an iret.
+ */
+#ifdef CONFIG_X86_32
+/*
+ * For i386, NMIs use the same stack as the kernel, and we can
+ * add a workaround to the iret problem in C. Simply have 3 states
+ * the NMI can be in.
+ *
+ *  1) not running
+ *  2) executing
+ *  3) latched
+ *
+ * When no NMI is in progress, it is in the "not running" state.
+ * When an NMI comes in, it goes into the "executing" state.
+ * Normally, if another NMI is triggered, it does not interrupt
+ * the running NMI and the HW will simply latch it so that when
+ * the first NMI finishes, it will restart the second NMI.
+ * (Note, the latch is binary, thus multiple NMIs triggering,
+ *  when one is running, are ignored. Only one NMI is restarted.)
+ *
+ * If an NMI hits a breakpoint that executes an iret, another
+ * NMI can preempt it. We do not want to allow this new NMI
+ * to run, but we want to execute it when the first one finishes.
+ * We set the state to "latched", and the first NMI will perform
+ * an cmpxchg on the state, and if it doesn't successfully
+ * reset the state to "not running" it will restart the next
+ * NMI.
+ */
+enum nmi_states {
+       NMI_NOT_RUNNING,
+       NMI_EXECUTING,
+       NMI_LATCHED,
+};
+static DEFINE_PER_CPU(enum nmi_states, nmi_state);
+
+#define nmi_nesting_preprocess(regs)                                   \
+       do {                                                            \
+               if (__get_cpu_var(nmi_state) != NMI_NOT_RUNNING) {      \
+                       __get_cpu_var(nmi_state) = NMI_LATCHED;         \
+                       return;                                         \
+               }                                                       \
+       nmi_restart:                                                    \
+               __get_cpu_var(nmi_state) = NMI_EXECUTING;               \
+       } while (0)
+
+#define nmi_nesting_postprocess()                                      \
+       do {                                                            \
+               if (cmpxchg(&__get_cpu_var(nmi_state),                  \
+                   NMI_EXECUTING, NMI_NOT_RUNNING) != NMI_EXECUTING)   \
+                       goto nmi_restart;                               \
+       } while (0)
+#else /* x86_64 */
+/*
+ * In x86_64 things are a bit more difficult. This has the same problem
+ * where an NMI hitting a breakpoint that calls iret will remove the
+ * NMI context, allowing a nested NMI to enter. What makes this more
+ * difficult is that both NMIs and breakpoints have their own stack.
+ * When a new NMI or breakpoint is executed, the stack is set to a fixed
+ * point. If an NMI is nested, it will have its stack set at that same
+ * fixed address that the first NMI had, and will start corrupting the
+ * stack. This is handled in entry_64.S, but the same problem exists with
+ * the breakpoint stack.
+ *
+ * If a breakpoint is being processed, and the debug stack is being used,
+ * if an NMI comes in and also hits a breakpoint, the stack pointer
+ * will be set to the same fixed address as the breakpoint that was
+ * interrupted, causing that stack to be corrupted. To handle this case,
+ * check if the stack that was interrupted is the debug stack, and if
+ * so, change the IDT so that new breakpoints will use the current stack
+ * and not switch to the fixed address. On return of the NMI, switch back
+ * to the original IDT.
+ */
+static DEFINE_PER_CPU(int, update_debug_stack);
+
+static inline void nmi_nesting_preprocess(struct pt_regs *regs)
+{
+       /*
+        * If we interrupted a breakpoint, it is possible that
+        * the nmi handler will have breakpoints too. We need to
+        * change the IDT such that breakpoints that happen here
+        * continue to use the NMI stack.
+        */
+       if (unlikely(is_debug_stack(regs->sp))) {
+               debug_stack_set_zero();
+               __get_cpu_var(update_debug_stack) = 1;
+       }
+}
+
+static inline void nmi_nesting_postprocess(void)
+{
+       if (unlikely(__get_cpu_var(update_debug_stack)))
+               debug_stack_reset();
+}
+#endif
+
 dotraplinkage notrace __kprobes void
 do_nmi(struct pt_regs *regs, long error_code)
 {
+       nmi_nesting_preprocess(regs);
+
        nmi_enter();
 
        inc_irq_stat(__nmi_count);
@@ -416,6 +515,9 @@ do_nmi(struct pt_regs *regs, long error_code)
                default_do_nmi(regs);
 
        nmi_exit();
+
+       /* On i386, may loop back to preprocess */
+       nmi_nesting_postprocess();
 }
 
 void stop_nmi(void)
index 89a04c7b5bb6f600ff764bf3c91900880e47db4e..50267386b7668d7761f14b2e98a6a032815a792f 100644 (file)
@@ -1392,20 +1392,18 @@ long syscall_trace_enter(struct pt_regs *regs)
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_enter(regs, regs->orig_ax);
 
-       if (unlikely(current->audit_context)) {
-               if (IS_IA32)
-                       audit_syscall_entry(AUDIT_ARCH_I386,
-                                           regs->orig_ax,
-                                           regs->bx, regs->cx,
-                                           regs->dx, regs->si);
+       if (IS_IA32)
+               audit_syscall_entry(AUDIT_ARCH_I386,
+                                   regs->orig_ax,
+                                   regs->bx, regs->cx,
+                                   regs->dx, regs->si);
 #ifdef CONFIG_X86_64
-               else
-                       audit_syscall_entry(AUDIT_ARCH_X86_64,
-                                           regs->orig_ax,
-                                           regs->di, regs->si,
-                                           regs->dx, regs->r10);
+       else
+               audit_syscall_entry(AUDIT_ARCH_X86_64,
+                                   regs->orig_ax,
+                                   regs->di, regs->si,
+                                   regs->dx, regs->r10);
 #endif
-       }
 
        return ret ?: regs->orig_ax;
 }
@@ -1414,8 +1412,7 @@ void syscall_trace_leave(struct pt_regs *regs)
 {
        bool step;
 
-       if (unlikely(current->audit_context))
-               audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
+       audit_syscall_exit(regs);
 
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_exit(regs, regs->ax);
diff --git a/arch/x86/kernel/syscall_32.c b/arch/x86/kernel/syscall_32.c
new file mode 100644 (file)
index 0000000..147fcd4
--- /dev/null
@@ -0,0 +1,25 @@
+/* System call table for i386. */
+
+#include <linux/linkage.h>
+#include <linux/sys.h>
+#include <linux/cache.h>
+#include <asm/asm-offsets.h>
+
+#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ;
+#include <asm/syscalls_32.h>
+#undef __SYSCALL_I386
+
+#define __SYSCALL_I386(nr, sym, compat) [nr] = sym,
+
+typedef asmlinkage void (*sys_call_ptr_t)(void);
+
+extern asmlinkage void sys_ni_syscall(void);
+
+const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
+       /*
+        * Smells like a compiler bug -- it doesn't work
+        * when the & below is removed.
+        */
+       [0 ... __NR_syscall_max] = &sys_ni_syscall,
+#include <asm/syscalls_32.h>
+};
index de87d6008295c5459aa1cbc9f41037829e1c82c8..7ac7943be02cb0bb69577daa0403b08372d82da4 100644 (file)
@@ -5,15 +5,11 @@
 #include <linux/cache.h>
 #include <asm/asm-offsets.h>
 
-#define __NO_STUBS
+#define __SYSCALL_64(nr, sym, compat) extern asmlinkage void sym(void) ;
+#include <asm/syscalls_64.h>
+#undef __SYSCALL_64
 
-#define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ;
-#undef _ASM_X86_UNISTD_64_H
-#include <asm/unistd_64.h>
-
-#undef __SYSCALL
-#define __SYSCALL(nr, sym) [nr] = sym,
-#undef _ASM_X86_UNISTD_64_H
+#define __SYSCALL_64(nr, sym, compat) [nr] = sym,
 
 typedef void (*sys_call_ptr_t)(void);
 
@@ -21,9 +17,9 @@ extern void sys_ni_syscall(void);
 
 const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
        /*
-       *Smells like a like a compiler bug -- it doesn't work
-       *when the & below is removed.
-       */
+        * Smells like a compiler bug -- it doesn't work
+        * when the & below is removed.
+        */
        [0 ... __NR_syscall_max] = &sys_ni_syscall,
-#include <asm/unistd_64.h>
+#include <asm/syscalls_64.h>
 };
diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S
deleted file mode 100644 (file)
index 9a0e312..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-ENTRY(sys_call_table)
-       .long sys_restart_syscall       /* 0 - old "setup()" system call, used for restarting */
-       .long sys_exit
-       .long ptregs_fork
-       .long sys_read
-       .long sys_write
-       .long sys_open          /* 5 */
-       .long sys_close
-       .long sys_waitpid
-       .long sys_creat
-       .long sys_link
-       .long sys_unlink        /* 10 */
-       .long ptregs_execve
-       .long sys_chdir
-       .long sys_time
-       .long sys_mknod
-       .long sys_chmod         /* 15 */
-       .long sys_lchown16
-       .long sys_ni_syscall    /* old break syscall holder */
-       .long sys_stat
-       .long sys_lseek
-       .long sys_getpid        /* 20 */
-       .long sys_mount
-       .long sys_oldumount
-       .long sys_setuid16
-       .long sys_getuid16
-       .long sys_stime         /* 25 */
-       .long sys_ptrace
-       .long sys_alarm
-       .long sys_fstat
-       .long sys_pause
-       .long sys_utime         /* 30 */
-       .long sys_ni_syscall    /* old stty syscall holder */
-       .long sys_ni_syscall    /* old gtty syscall holder */
-       .long sys_access
-       .long sys_nice
-       .long sys_ni_syscall    /* 35 - old ftime syscall holder */
-       .long sys_sync
-       .long sys_kill
-       .long sys_rename
-       .long sys_mkdir
-       .long sys_rmdir         /* 40 */
-       .long sys_dup
-       .long sys_pipe
-       .long sys_times
-       .long sys_ni_syscall    /* old prof syscall holder */
-       .long sys_brk           /* 45 */
-       .long sys_setgid16
-       .long sys_getgid16
-       .long sys_signal
-       .long sys_geteuid16
-       .long sys_getegid16     /* 50 */
-       .long sys_acct
-       .long sys_umount        /* recycled never used phys() */
-       .long sys_ni_syscall    /* old lock syscall holder */
-       .long sys_ioctl
-       .long sys_fcntl         /* 55 */
-       .long sys_ni_syscall    /* old mpx syscall holder */
-       .long sys_setpgid
-       .long sys_ni_syscall    /* old ulimit syscall holder */
-       .long sys_olduname
-       .long sys_umask         /* 60 */
-       .long sys_chroot
-       .long sys_ustat
-       .long sys_dup2
-       .long sys_getppid
-       .long sys_getpgrp       /* 65 */
-       .long sys_setsid
-       .long sys_sigaction
-       .long sys_sgetmask
-       .long sys_ssetmask
-       .long sys_setreuid16    /* 70 */
-       .long sys_setregid16
-       .long sys_sigsuspend
-       .long sys_sigpending
-       .long sys_sethostname
-       .long sys_setrlimit     /* 75 */
-       .long sys_old_getrlimit
-       .long sys_getrusage
-       .long sys_gettimeofday
-       .long sys_settimeofday
-       .long sys_getgroups16   /* 80 */
-       .long sys_setgroups16
-       .long sys_old_select
-       .long sys_symlink
-       .long sys_lstat
-       .long sys_readlink      /* 85 */
-       .long sys_uselib
-       .long sys_swapon
-       .long sys_reboot
-       .long sys_old_readdir
-       .long sys_old_mmap      /* 90 */
-       .long sys_munmap
-       .long sys_truncate
-       .long sys_ftruncate
-       .long sys_fchmod
-       .long sys_fchown16      /* 95 */
-       .long sys_getpriority
-       .long sys_setpriority
-       .long sys_ni_syscall    /* old profil syscall holder */
-       .long sys_statfs
-       .long sys_fstatfs       /* 100 */
-       .long sys_ioperm
-       .long sys_socketcall
-       .long sys_syslog
-       .long sys_setitimer
-       .long sys_getitimer     /* 105 */
-       .long sys_newstat
-       .long sys_newlstat
-       .long sys_newfstat
-       .long sys_uname
-       .long ptregs_iopl       /* 110 */
-       .long sys_vhangup
-       .long sys_ni_syscall    /* old "idle" system call */
-       .long ptregs_vm86old
-       .long sys_wait4
-       .long sys_swapoff       /* 115 */
-       .long sys_sysinfo
-       .long sys_ipc
-       .long sys_fsync
-       .long ptregs_sigreturn
-       .long ptregs_clone      /* 120 */
-       .long sys_setdomainname
-       .long sys_newuname
-       .long sys_modify_ldt
-       .long sys_adjtimex
-       .long sys_mprotect      /* 125 */
-       .long sys_sigprocmask
-       .long sys_ni_syscall    /* old "create_module" */
-       .long sys_init_module
-       .long sys_delete_module
-       .long sys_ni_syscall    /* 130: old "get_kernel_syms" */
-       .long sys_quotactl
-       .long sys_getpgid
-       .long sys_fchdir
-       .long sys_bdflush
-       .long sys_sysfs         /* 135 */
-       .long sys_personality
-       .long sys_ni_syscall    /* reserved for afs_syscall */
-       .long sys_setfsuid16
-       .long sys_setfsgid16
-       .long sys_llseek        /* 140 */
-       .long sys_getdents
-       .long sys_select
-       .long sys_flock
-       .long sys_msync
-       .long sys_readv         /* 145 */
-       .long sys_writev
-       .long sys_getsid
-       .long sys_fdatasync
-       .long sys_sysctl
-       .long sys_mlock         /* 150 */
-       .long sys_munlock
-       .long sys_mlockall
-       .long sys_munlockall
-       .long sys_sched_setparam
-       .long sys_sched_getparam   /* 155 */
-       .long sys_sched_setscheduler
-       .long sys_sched_getscheduler
-       .long sys_sched_yield
-       .long sys_sched_get_priority_max
-       .long sys_sched_get_priority_min  /* 160 */
-       .long sys_sched_rr_get_interval
-       .long sys_nanosleep
-       .long sys_mremap
-       .long sys_setresuid16
-       .long sys_getresuid16   /* 165 */
-       .long ptregs_vm86
-       .long sys_ni_syscall    /* Old sys_query_module */
-       .long sys_poll
-       .long sys_ni_syscall    /* Old nfsservctl */
-       .long sys_setresgid16   /* 170 */
-       .long sys_getresgid16
-       .long sys_prctl
-       .long ptregs_rt_sigreturn
-       .long sys_rt_sigaction
-       .long sys_rt_sigprocmask        /* 175 */
-       .long sys_rt_sigpending
-       .long sys_rt_sigtimedwait
-       .long sys_rt_sigqueueinfo
-       .long sys_rt_sigsuspend
-       .long sys_pread64       /* 180 */
-       .long sys_pwrite64
-       .long sys_chown16
-       .long sys_getcwd
-       .long sys_capget
-       .long sys_capset        /* 185 */
-       .long ptregs_sigaltstack
-       .long sys_sendfile
-       .long sys_ni_syscall    /* reserved for streams1 */
-       .long sys_ni_syscall    /* reserved for streams2 */
-       .long ptregs_vfork      /* 190 */
-       .long sys_getrlimit
-       .long sys_mmap_pgoff
-       .long sys_truncate64
-       .long sys_ftruncate64
-       .long sys_stat64        /* 195 */
-       .long sys_lstat64
-       .long sys_fstat64
-       .long sys_lchown
-       .long sys_getuid
-       .long sys_getgid        /* 200 */
-       .long sys_geteuid
-       .long sys_getegid
-       .long sys_setreuid
-       .long sys_setregid
-       .long sys_getgroups     /* 205 */
-       .long sys_setgroups
-       .long sys_fchown
-       .long sys_setresuid
-       .long sys_getresuid
-       .long sys_setresgid     /* 210 */
-       .long sys_getresgid
-       .long sys_chown
-       .long sys_setuid
-       .long sys_setgid
-       .long sys_setfsuid      /* 215 */
-       .long sys_setfsgid
-       .long sys_pivot_root
-       .long sys_mincore
-       .long sys_madvise
-       .long sys_getdents64    /* 220 */
-       .long sys_fcntl64
-       .long sys_ni_syscall    /* reserved for TUX */
-       .long sys_ni_syscall
-       .long sys_gettid
-       .long sys_readahead     /* 225 */
-       .long sys_setxattr
-       .long sys_lsetxattr
-       .long sys_fsetxattr
-       .long sys_getxattr
-       .long sys_lgetxattr     /* 230 */
-       .long sys_fgetxattr
-       .long sys_listxattr
-       .long sys_llistxattr
-       .long sys_flistxattr
-       .long sys_removexattr   /* 235 */
-       .long sys_lremovexattr
-       .long sys_fremovexattr
-       .long sys_tkill
-       .long sys_sendfile64
-       .long sys_futex         /* 240 */
-       .long sys_sched_setaffinity
-       .long sys_sched_getaffinity
-       .long sys_set_thread_area
-       .long sys_get_thread_area
-       .long sys_io_setup      /* 245 */
-       .long sys_io_destroy
-       .long sys_io_getevents
-       .long sys_io_submit
-       .long sys_io_cancel
-       .long sys_fadvise64     /* 250 */
-       .long sys_ni_syscall
-       .long sys_exit_group
-       .long sys_lookup_dcookie
-       .long sys_epoll_create
-       .long sys_epoll_ctl     /* 255 */
-       .long sys_epoll_wait
-       .long sys_remap_file_pages
-       .long sys_set_tid_address
-       .long sys_timer_create
-       .long sys_timer_settime         /* 260 */
-       .long sys_timer_gettime
-       .long sys_timer_getoverrun
-       .long sys_timer_delete
-       .long sys_clock_settime
-       .long sys_clock_gettime         /* 265 */
-       .long sys_clock_getres
-       .long sys_clock_nanosleep
-       .long sys_statfs64
-       .long sys_fstatfs64
-       .long sys_tgkill        /* 270 */
-       .long sys_utimes
-       .long sys_fadvise64_64
-       .long sys_ni_syscall    /* sys_vserver */
-       .long sys_mbind
-       .long sys_get_mempolicy
-       .long sys_set_mempolicy
-       .long sys_mq_open
-       .long sys_mq_unlink
-       .long sys_mq_timedsend
-       .long sys_mq_timedreceive       /* 280 */
-       .long sys_mq_notify
-       .long sys_mq_getsetattr
-       .long sys_kexec_load
-       .long sys_waitid
-       .long sys_ni_syscall            /* 285 */ /* available */
-       .long sys_add_key
-       .long sys_request_key
-       .long sys_keyctl
-       .long sys_ioprio_set
-       .long sys_ioprio_get            /* 290 */
-       .long sys_inotify_init
-       .long sys_inotify_add_watch
-       .long sys_inotify_rm_watch
-       .long sys_migrate_pages
-       .long sys_openat                /* 295 */
-       .long sys_mkdirat
-       .long sys_mknodat
-       .long sys_fchownat
-       .long sys_futimesat
-       .long sys_fstatat64             /* 300 */
-       .long sys_unlinkat
-       .long sys_renameat
-       .long sys_linkat
-       .long sys_symlinkat
-       .long sys_readlinkat            /* 305 */
-       .long sys_fchmodat
-       .long sys_faccessat
-       .long sys_pselect6
-       .long sys_ppoll
-       .long sys_unshare               /* 310 */
-       .long sys_set_robust_list
-       .long sys_get_robust_list
-       .long sys_splice
-       .long sys_sync_file_range
-       .long sys_tee                   /* 315 */
-       .long sys_vmsplice
-       .long sys_move_pages
-       .long sys_getcpu
-       .long sys_epoll_pwait
-       .long sys_utimensat             /* 320 */
-       .long sys_signalfd
-       .long sys_timerfd_create
-       .long sys_eventfd
-       .long sys_fallocate
-       .long sys_timerfd_settime       /* 325 */
-       .long sys_timerfd_gettime
-       .long sys_signalfd4
-       .long sys_eventfd2
-       .long sys_epoll_create1
-       .long sys_dup3                  /* 330 */
-       .long sys_pipe2
-       .long sys_inotify_init1
-       .long sys_preadv
-       .long sys_pwritev
-       .long sys_rt_tgsigqueueinfo     /* 335 */
-       .long sys_perf_event_open
-       .long sys_recvmmsg
-       .long sys_fanotify_init
-       .long sys_fanotify_mark
-       .long sys_prlimit64             /* 340 */
-       .long sys_name_to_handle_at
-       .long sys_open_by_handle_at
-       .long sys_clock_adjtime
-       .long sys_syncfs
-       .long sys_sendmmsg              /* 345 */
-       .long sys_setns
-       .long sys_process_vm_readv
-       .long sys_process_vm_writev
index fa1191fb679d5bcf3dbc44a259aee1fd143a4db5..482ec3af20671cb771b7b6c166f364144f2dcf64 100644 (file)
@@ -311,9 +311,15 @@ dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
                        == NOTIFY_STOP)
                return;
 
+       /*
+        * Let others (NMI) know that the debug stack is in use
+        * as we may switch to the interrupt stack.
+        */
+       debug_stack_usage_inc();
        preempt_conditional_sti(regs);
        do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
        preempt_conditional_cli(regs);
+       debug_stack_usage_dec();
 }
 
 #ifdef CONFIG_X86_64
@@ -406,6 +412,12 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
                                                        SIGTRAP) == NOTIFY_STOP)
                return;
 
+       /*
+        * Let others (NMI) know that the debug stack is in use
+        * as we may switch to the interrupt stack.
+        */
+       debug_stack_usage_inc();
+
        /* It's safe to allow irq's after DR6 has been saved */
        preempt_conditional_sti(regs);
 
@@ -413,6 +425,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
                handle_vm86_trap((struct kernel_vm86_regs *) regs,
                                error_code, 1);
                preempt_conditional_cli(regs);
+               debug_stack_usage_dec();
                return;
        }
 
@@ -432,6 +445,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
        if (tsk->thread.debugreg6 & (DR_STEP | DR_TRAP_BITS) || user_icebp)
                send_sigtrap(tsk, regs, error_code, si_code);
        preempt_conditional_cli(regs);
+       debug_stack_usage_dec();
 
        return;
 }
@@ -718,4 +732,10 @@ void __init trap_init(void)
        cpu_init();
 
        x86_init.irqs.trap_init();
+
+#ifdef CONFIG_X86_64
+       memcpy(&nmi_idt_table, &idt_table, IDT_ENTRIES * 16);
+       set_nmi_gate(1, &debug);
+       set_nmi_gate(3, &int3);
+#endif
 }
index c0dd5b603749057db73420caacc321d5d714338f..a62c201c97eccf31fa90d05dec5e5cf5102ead74 100644 (file)
@@ -290,14 +290,15 @@ static inline int pit_verify_msb(unsigned char val)
 static inline int pit_expect_msb(unsigned char val, u64 *tscp, unsigned long *deltap)
 {
        int count;
-       u64 tsc = 0;
+       u64 tsc = 0, prev_tsc = 0;
 
        for (count = 0; count < 50000; count++) {
                if (!pit_verify_msb(val))
                        break;
+               prev_tsc = tsc;
                tsc = get_cycles();
        }
-       *deltap = get_cycles() - tsc;
+       *deltap = get_cycles() - prev_tsc;
        *tscp = tsc;
 
        /*
@@ -311,9 +312,9 @@ static inline int pit_expect_msb(unsigned char val, u64 *tscp, unsigned long *de
  * How many MSB values do we want to see? We aim for
  * a maximum error rate of 500ppm (in practice the
  * real error is much smaller), but refuse to spend
- * more than 25ms on it.
+ * more than 50ms on it.
  */
-#define MAX_QUICK_PIT_MS 25
+#define MAX_QUICK_PIT_MS 50
 #define MAX_QUICK_PIT_ITERATIONS (MAX_QUICK_PIT_MS * PIT_TICK_RATE / 1000 / 256)
 
 static unsigned long quick_pit_calibrate(void)
@@ -383,15 +384,12 @@ success:
         *
         * As a result, we can depend on there not being
         * any odd delays anywhere, and the TSC reads are
-        * reliable (within the error). We also adjust the
-        * delta to the middle of the error bars, just
-        * because it looks nicer.
+        * reliable (within the error).
         *
         * kHz = ticks / time-in-seconds / 1000;
         * kHz = (t2 - t1) / (I * 256 / PIT_TICK_RATE) / 1000
         * kHz = ((t2 - t1) * PIT_TICK_RATE) / (I * 256 * 1000)
         */
-       delta += (long)(d2 - d1)/2;
        delta *= PIT_TICK_RATE;
        do_div(delta, i*256*1000);
        printk("Fast TSC calibration using PIT\n");
index 863f8753ab0ae696f8981ef30d9ee031dd0e310b..b466cab5ba15d171cb4b1fd61a1590bd0cca9956 100644 (file)
@@ -335,9 +335,11 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
        if (info->flags & VM86_SCREEN_BITMAP)
                mark_screen_rdonly(tsk->mm);
 
-       /*call audit_syscall_exit since we do not exit via the normal paths */
+       /*call __audit_syscall_exit since we do not exit via the normal paths */
+#ifdef CONFIG_AUDITSYSCALL
        if (unlikely(current->audit_context))
-               audit_syscall_exit(AUDITSC_RESULT(0), 0);
+               __audit_syscall_exit(1, 0);
+#endif
 
        __asm__ __volatile__(
                "movl %0,%%esp\n\t"
index 2a2a9b40db199dd49c99af48d9e2c25bc4acd440..224b02c3cda91683afed63cccc5e794fadef4559 100644 (file)
@@ -74,7 +74,7 @@ enum {
 #endif
 
 #ifdef MMU_DEBUG
-static int dbg = 0;
+static bool dbg = 0;
 module_param(dbg, bool, 0644);
 #endif
 
index 906a7e84200f7b96eedbe5647d613a9a5d375546..d29216c462b3ce56e33c3bf0ecf7595258b9705a 100644 (file)
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
-static int __read_mostly enable_vpid = 1;
+static bool __read_mostly enable_vpid = 1;
 module_param_named(vpid, enable_vpid, bool, 0444);
 
-static int __read_mostly flexpriority_enabled = 1;
+static bool __read_mostly flexpriority_enabled = 1;
 module_param_named(flexpriority, flexpriority_enabled, bool, S_IRUGO);
 
-static int __read_mostly enable_ept = 1;
+static bool __read_mostly enable_ept = 1;
 module_param_named(ept, enable_ept, bool, S_IRUGO);
 
-static int __read_mostly enable_unrestricted_guest = 1;
+static bool __read_mostly enable_unrestricted_guest = 1;
 module_param_named(unrestricted_guest,
                        enable_unrestricted_guest, bool, S_IRUGO);
 
-static int __read_mostly emulate_invalid_guest_state = 0;
+static bool __read_mostly emulate_invalid_guest_state = 0;
 module_param(emulate_invalid_guest_state, bool, S_IRUGO);
 
-static int __read_mostly vmm_exclusive = 1;
+static bool __read_mostly vmm_exclusive = 1;
 module_param(vmm_exclusive, bool, S_IRUGO);
 
-static int __read_mostly yield_on_hlt = 1;
+static bool __read_mostly yield_on_hlt = 1;
 module_param(yield_on_hlt, bool, S_IRUGO);
 
-static int __read_mostly fasteoi = 1;
+static bool __read_mostly fasteoi = 1;
 module_param(fasteoi, bool, S_IRUGO);
 
 /*
@@ -81,7 +81,7 @@ module_param(fasteoi, bool, S_IRUGO);
  * VMX and be a hypervisor for its own guests. If nested=0, guests may not
  * use VMX instructions.
  */
-static int __read_mostly nested = 0;
+static bool __read_mostly nested = 0;
 module_param(nested, bool, S_IRUGO);
 
 #define KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST                          \
index 1171def5f96b76a1119709e706b977be872f8082..14d6cadc4ba63b9ba3adf5b5e64fff461483de69 100644 (file)
@@ -88,8 +88,8 @@ static void process_nmi(struct kvm_vcpu *vcpu);
 struct kvm_x86_ops *kvm_x86_ops;
 EXPORT_SYMBOL_GPL(kvm_x86_ops);
 
-int ignore_msrs = 0;
-module_param_named(ignore_msrs, ignore_msrs, bool, S_IRUGO | S_IWUSR);
+static bool ignore_msrs = 0;
+module_param(ignore_msrs, bool, S_IRUGO | S_IWUSR);
 
 bool kvm_has_tsc_control;
 EXPORT_SYMBOL_GPL(kvm_has_tsc_control);
index cf4603ba866f7a10549ee7acdaf6fb2866e464ba..642d8805bc1bb967f03715d3585a9cd0fa99e5bb 100644 (file)
@@ -856,18 +856,23 @@ static void __init lguest_init_IRQ(void)
 }
 
 /*
- * With CONFIG_SPARSE_IRQ, interrupt descriptors are allocated as-needed, so
- * rather than set them in lguest_init_IRQ we are called here every time an
- * lguest device needs an interrupt.
- *
- * FIXME: irq_alloc_desc_at() can fail due to lack of memory, we should
- * pass that up!
+ * Interrupt descriptors are allocated as-needed, but low-numbered ones are
+ * reserved by the generic x86 code.  So we ignore irq_alloc_desc_at if it
+ * tells us the irq is already used: other errors (ie. ENOMEM) we take
+ * seriously.
  */
-void lguest_setup_irq(unsigned int irq)
+int lguest_setup_irq(unsigned int irq)
 {
-       irq_alloc_desc_at(irq, 0);
+       int err;
+
+       /* Returns -ve error or vector number. */
+       err = irq_alloc_desc_at(irq, 0);
+       if (err < 0 && err != -EEXIST)
+               return err;
+
        irq_set_chip_and_handler_name(irq, &lguest_irq_controller,
                                      handle_level_irq, "level");
+       return 0;
 }
 
 /*
index 5b83c51c12e02e8146aba31c0236ff1e7d42d4b0..819137904428a4f82444cf5a9d5055bb59dc6d80 100644 (file)
@@ -219,7 +219,9 @@ ab: STOS/W/D/Q Yv,rAX
 ac: LODS/B AL,Xb
 ad: LODS/W/D/Q rAX,Xv
 ae: SCAS/B AL,Yb
-af: SCAS/W/D/Q rAX,Xv
+# Note: The May 2011 Intel manual shows Xv for the second parameter of the
+# next instruction but Yv is correct
+af: SCAS/W/D/Q rAX,Yv
 # 0xb0 - 0xbf
 b0: MOV AL/R8L,Ib
 b1: MOV CL/R9L,Ib
@@ -729,8 +731,8 @@ de: VAESDEC Vdq,Hdq,Wdq (66),(v1)
 df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1)
 f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2)
 f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2)
-f3: ANDN Gy,By,Ey (v)
-f4: Grp17 (1A)
+f2: ANDN Gy,By,Ey (v)
+f3: Grp17 (1A)
 f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v)
 f6: MULX By,Gy,rDX,Ey (F2),(v)
 f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v)
index de54b9b278a7a1f6d55f545146317ab7763614e9..dc0b727742f475514a46348892cc0b2a5e5e4ac1 100644 (file)
@@ -75,8 +75,8 @@ static LIST_HEAD(trace_list);         /* struct remap_trace */
 
 /* module parameters */
 static unsigned long   filter_offset;
-static int             nommiotrace;
-static int             trace_pc;
+static bool            nommiotrace;
+static bool            trace_pc;
 
 module_param(filter_offset, ulong, 0);
 module_param(nommiotrace, bool, 0);
index 020cd2e808732408a31cad1294c5d8faa153fa5f..19d3fa08b1191493cda6415e56f8f26d86415bf7 100644 (file)
@@ -110,7 +110,7 @@ void __cpuinit numa_clear_node(int cpu)
  * Allocate node_to_cpumask_map based on number of available nodes
  * Requires node_possible_map to be valid.
  *
- * Note: node_to_cpumask() is not valid until after this is done.
+ * Note: cpumask_of_node() is not valid until after this is done.
  * (Use CONFIG_DEBUG_PER_CPU_MAPS to check this.)
  */
 void __init setup_node_to_cpumask_map(void)
index fd61b3fb73411f89b5a5d1b2805e133bcbd8be94..1c1c4f46a7c15c19c54923c815556d8c253b847c 100644 (file)
@@ -109,6 +109,8 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
        if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
                return;
        pxm = pa->proximity_domain_lo;
+       if (acpi_srat_revision >= 2)
+               pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8;
        node = setup_node(pxm);
        if (node < 0) {
                printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
@@ -160,6 +162,8 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
        start = ma->base_address;
        end = start + ma->length;
        pxm = ma->proximity_domain;
+       if (acpi_srat_revision <= 1)
+               pxm &= 0xff;
        node = setup_node(pxm);
        if (node < 0) {
                printk(KERN_ERR "SRAT: Too many proximity domains.\n");
index ca1973699d3d7002871d8de2a7c3db5a0315c136..dc5f1d32aced55b27ba532d92b1928e91a59c5b3 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <asm/geode.h>
 
-static int force = 0;
+static bool force = 0;
 module_param(force, bool, 0444);
 /* FIXME: Award bios is not automatically detected as Alix platform */
 MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform");
index 1ba7f5ed8c9b9e0675b612d358659be9d57dd82a..5917eb56b313b3442850d8d28eff32449a30f885 100644 (file)
@@ -42,7 +42,7 @@ MODULE_AUTHOR("Sébastien Hinderer <Sebastien.Hinderer@ens-lyon.org>");
 MODULE_DESCRIPTION("A power_off handler for Iris devices from EuroBraille");
 MODULE_SUPPORTED_DEVICE("Eurobraille/Iris");
 
-static int force;
+static bool force;
 
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Set to one to force poweroff handler installation.");
index 5b552198f774eb1e6c6ab3b9ef42276706d74328..9be4cff00a2d733712adeb2ac2d71ab035ddb794 100644 (file)
@@ -157,13 +157,14 @@ static int __init uvhub_to_first_apicid(int uvhub)
  * clear of the Timeout bit (as well) will free the resource. No reply will
  * be sent (the hardware will only do one reply per message).
  */
-static void reply_to_message(struct msg_desc *mdp, struct bau_control *bcp)
+static void reply_to_message(struct msg_desc *mdp, struct bau_control *bcp,
+                                               int do_acknowledge)
 {
        unsigned long dw;
        struct bau_pq_entry *msg;
 
        msg = mdp->msg;
-       if (!msg->canceled) {
+       if (!msg->canceled && do_acknowledge) {
                dw = (msg->swack_vec << UV_SW_ACK_NPENDING) | msg->swack_vec;
                write_mmr_sw_ack(dw);
        }
@@ -212,8 +213,8 @@ static void bau_process_retry_msg(struct msg_desc *mdp,
                        if (mmr & (msg_res << UV_SW_ACK_NPENDING)) {
                                unsigned long mr;
                                /*
-                                * is the resource timed out?
-                                * make everyone ignore the cancelled message.
+                                * Is the resource timed out?
+                                * Make everyone ignore the cancelled message.
                                 */
                                msg2->canceled = 1;
                                stat->d_canceled++;
@@ -231,8 +232,8 @@ static void bau_process_retry_msg(struct msg_desc *mdp,
  * Do all the things a cpu should do for a TLB shootdown message.
  * Other cpu's may come here at the same time for this message.
  */
-static void bau_process_message(struct msg_desc *mdp,
-                                       struct bau_control *bcp)
+static void bau_process_message(struct msg_desc *mdp, struct bau_control *bcp,
+                                               int do_acknowledge)
 {
        short socket_ack_count = 0;
        short *sp;
@@ -284,8 +285,9 @@ static void bau_process_message(struct msg_desc *mdp,
                if (msg_ack_count == bcp->cpus_in_uvhub) {
                        /*
                         * All cpus in uvhub saw it; reply
+                        * (unless we are in the UV2 workaround)
                         */
-                       reply_to_message(mdp, bcp);
+                       reply_to_message(mdp, bcp, do_acknowledge);
                }
        }
 
@@ -491,27 +493,138 @@ static int uv1_wait_completion(struct bau_desc *bau_desc,
 /*
  * UV2 has an extra bit of status in the ACTIVATION_STATUS_2 register.
  */
-static unsigned long uv2_read_status(unsigned long offset, int rshft, int cpu)
+static unsigned long uv2_read_status(unsigned long offset, int rshft, int desc)
 {
        unsigned long descriptor_status;
        unsigned long descriptor_status2;
 
        descriptor_status = ((read_lmmr(offset) >> rshft) & UV_ACT_STATUS_MASK);
-       descriptor_status2 = (read_mmr_uv2_status() >> cpu) & 0x1UL;
+       descriptor_status2 = (read_mmr_uv2_status() >> desc) & 0x1UL;
        descriptor_status = (descriptor_status << 1) | descriptor_status2;
        return descriptor_status;
 }
 
+/*
+ * Return whether the status of the descriptor that is normally used for this
+ * cpu (the one indexed by its hub-relative cpu number) is busy.
+ * The status of the original 32 descriptors is always reflected in the 64
+ * bits of UVH_LB_BAU_SB_ACTIVATION_STATUS_0.
+ * The bit provided by the activation_status_2 register is irrelevant to
+ * the status if it is only being tested for busy or not busy.
+ */
+int normal_busy(struct bau_control *bcp)
+{
+       int cpu = bcp->uvhub_cpu;
+       int mmr_offset;
+       int right_shift;
+
+       mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0;
+       right_shift = cpu * UV_ACT_STATUS_SIZE;
+       return (((((read_lmmr(mmr_offset) >> right_shift) &
+                               UV_ACT_STATUS_MASK)) << 1) == UV2H_DESC_BUSY);
+}
+
+/*
+ * Entered when a bau descriptor has gone into a permanent busy wait because
+ * of a hardware bug.
+ * Workaround the bug.
+ */
+int handle_uv2_busy(struct bau_control *bcp)
+{
+       int busy_one = bcp->using_desc;
+       int normal = bcp->uvhub_cpu;
+       int selected = -1;
+       int i;
+       unsigned long descriptor_status;
+       unsigned long status;
+       int mmr_offset;
+       struct bau_desc *bau_desc_old;
+       struct bau_desc *bau_desc_new;
+       struct bau_control *hmaster = bcp->uvhub_master;
+       struct ptc_stats *stat = bcp->statp;
+       cycles_t ttm;
+
+       stat->s_uv2_wars++;
+       spin_lock(&hmaster->uvhub_lock);
+       /* try for the original first */
+       if (busy_one != normal) {
+               if (!normal_busy(bcp))
+                       selected = normal;
+       }
+       if (selected < 0) {
+               /* can't use the normal, select an alternate */
+               mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1;
+               descriptor_status = read_lmmr(mmr_offset);
+
+               /* scan available descriptors 32-63 */
+               for (i = 0; i < UV_CPUS_PER_AS; i++) {
+                       if ((hmaster->inuse_map & (1 << i)) == 0) {
+                               status = ((descriptor_status >>
+                                               (i * UV_ACT_STATUS_SIZE)) &
+                                               UV_ACT_STATUS_MASK) << 1;
+                               if (status != UV2H_DESC_BUSY) {
+                                       selected = i + UV_CPUS_PER_AS;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       if (busy_one != normal)
+               /* mark the busy alternate as not in-use */
+               hmaster->inuse_map &= ~(1 << (busy_one - UV_CPUS_PER_AS));
+
+       if (selected >= 0) {
+               /* switch to the selected descriptor */
+               if (selected != normal) {
+                       /* set the selected alternate as in-use */
+                       hmaster->inuse_map |=
+                                       (1 << (selected - UV_CPUS_PER_AS));
+                       if (selected > stat->s_uv2_wars_hw)
+                               stat->s_uv2_wars_hw = selected;
+               }
+               bau_desc_old = bcp->descriptor_base;
+               bau_desc_old += (ITEMS_PER_DESC * busy_one);
+               bcp->using_desc = selected;
+               bau_desc_new = bcp->descriptor_base;
+               bau_desc_new += (ITEMS_PER_DESC * selected);
+               *bau_desc_new = *bau_desc_old;
+       } else {
+               /*
+                * All are busy. Wait for the normal one for this cpu to
+                * free up.
+                */
+               stat->s_uv2_war_waits++;
+               spin_unlock(&hmaster->uvhub_lock);
+               ttm = get_cycles();
+               do {
+                       cpu_relax();
+               } while (normal_busy(bcp));
+               spin_lock(&hmaster->uvhub_lock);
+               /* switch to the original descriptor */
+               bcp->using_desc = normal;
+               bau_desc_old = bcp->descriptor_base;
+               bau_desc_old += (ITEMS_PER_DESC * bcp->using_desc);
+               bcp->using_desc = (ITEMS_PER_DESC * normal);
+               bau_desc_new = bcp->descriptor_base;
+               bau_desc_new += (ITEMS_PER_DESC * normal);
+               *bau_desc_new = *bau_desc_old; /* copy the entire descriptor */
+       }
+       spin_unlock(&hmaster->uvhub_lock);
+       return FLUSH_RETRY_BUSYBUG;
+}
+
 static int uv2_wait_completion(struct bau_desc *bau_desc,
                                unsigned long mmr_offset, int right_shift,
                                struct bau_control *bcp, long try)
 {
        unsigned long descriptor_stat;
        cycles_t ttm;
-       int cpu = bcp->uvhub_cpu;
+       int desc = bcp->using_desc;
+       long busy_reps = 0;
        struct ptc_stats *stat = bcp->statp;
 
-       descriptor_stat = uv2_read_status(mmr_offset, right_shift, cpu);
+       descriptor_stat = uv2_read_status(mmr_offset, right_shift, desc);
 
        /* spin on the status MMR, waiting for it to go idle */
        while (descriptor_stat != UV2H_DESC_IDLE) {
@@ -522,32 +635,35 @@ static int uv2_wait_completion(struct bau_desc *bau_desc,
                 * our message and its state will stay IDLE.
                 */
                if ((descriptor_stat == UV2H_DESC_SOURCE_TIMEOUT) ||
-                   (descriptor_stat == UV2H_DESC_DEST_STRONG_NACK) ||
                    (descriptor_stat == UV2H_DESC_DEST_PUT_ERR)) {
                        stat->s_stimeout++;
                        return FLUSH_GIVEUP;
+               } else if (descriptor_stat == UV2H_DESC_DEST_STRONG_NACK) {
+                       stat->s_strongnacks++;
+                       bcp->conseccompletes = 0;
+                       return FLUSH_GIVEUP;
                } else if (descriptor_stat == UV2H_DESC_DEST_TIMEOUT) {
                        stat->s_dtimeout++;
-                       ttm = get_cycles();
-                       /*
-                        * Our retries may be blocked by all destination
-                        * swack resources being consumed, and a timeout
-                        * pending.  In that case hardware returns the
-                        * ERROR that looks like a destination timeout.
-                        */
-                       if (cycles_2_us(ttm - bcp->send_message) < timeout_us) {
-                               bcp->conseccompletes = 0;
-                               return FLUSH_RETRY_PLUGGED;
-                       }
                        bcp->conseccompletes = 0;
                        return FLUSH_RETRY_TIMEOUT;
                } else {
+                       busy_reps++;
+                       if (busy_reps > 1000000) {
+                               /* not to hammer on the clock */
+                               busy_reps = 0;
+                               ttm = get_cycles();
+                               if ((ttm - bcp->send_message) >
+                                       (bcp->clocks_per_100_usec)) {
+                                       return handle_uv2_busy(bcp);
+                               }
+                       }
                        /*
                         * descriptor_stat is still BUSY
                         */
                        cpu_relax();
                }
-               descriptor_stat = uv2_read_status(mmr_offset, right_shift, cpu);
+               descriptor_stat = uv2_read_status(mmr_offset, right_shift,
+                                                                       desc);
        }
        bcp->conseccompletes++;
        return FLUSH_COMPLETE;
@@ -563,17 +679,17 @@ static int wait_completion(struct bau_desc *bau_desc,
 {
        int right_shift;
        unsigned long mmr_offset;
-       int cpu = bcp->uvhub_cpu;
+       int desc = bcp->using_desc;
 
-       if (cpu < UV_CPUS_PER_AS) {
+       if (desc < UV_CPUS_PER_AS) {
                mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0;
-               right_shift = cpu * UV_ACT_STATUS_SIZE;
+               right_shift = desc * UV_ACT_STATUS_SIZE;
        } else {
                mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1;
-               right_shift = ((cpu - UV_CPUS_PER_AS) * UV_ACT_STATUS_SIZE);
+               right_shift = ((desc - UV_CPUS_PER_AS) * UV_ACT_STATUS_SIZE);
        }
 
-       if (is_uv1_hub())
+       if (bcp->uvhub_version == 1)
                return uv1_wait_completion(bau_desc, mmr_offset, right_shift,
                                                                bcp, try);
        else
@@ -752,19 +868,22 @@ static void handle_cmplt(int completion_status, struct bau_desc *bau_desc,
  * Returns 1 if it gives up entirely and the original cpu mask is to be
  * returned to the kernel.
  */
-int uv_flush_send_and_wait(struct bau_desc *bau_desc,
-                       struct cpumask *flush_mask, struct bau_control *bcp)
+int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp)
 {
        int seq_number = 0;
        int completion_stat = 0;
+       int uv1 = 0;
        long try = 0;
        unsigned long index;
        cycles_t time1;
        cycles_t time2;
        struct ptc_stats *stat = bcp->statp;
        struct bau_control *hmaster = bcp->uvhub_master;
+       struct uv1_bau_msg_header *uv1_hdr = NULL;
+       struct uv2_bau_msg_header *uv2_hdr = NULL;
+       struct bau_desc *bau_desc;
 
-       if (is_uv1_hub())
+       if (bcp->uvhub_version == 1)
                uv1_throttle(hmaster, stat);
 
        while (hmaster->uvhub_quiesce)
@@ -772,22 +891,39 @@ int uv_flush_send_and_wait(struct bau_desc *bau_desc,
 
        time1 = get_cycles();
        do {
-               if (try == 0) {
-                       bau_desc->header.msg_type = MSG_REGULAR;
+               bau_desc = bcp->descriptor_base;
+               bau_desc += (ITEMS_PER_DESC * bcp->using_desc);
+               if (bcp->uvhub_version == 1) {
+                       uv1 = 1;
+                       uv1_hdr = &bau_desc->header.uv1_hdr;
+               } else
+                       uv2_hdr = &bau_desc->header.uv2_hdr;
+               if ((try == 0) || (completion_stat == FLUSH_RETRY_BUSYBUG)) {
+                       if (uv1)
+                               uv1_hdr->msg_type = MSG_REGULAR;
+                       else
+                               uv2_hdr->msg_type = MSG_REGULAR;
                        seq_number = bcp->message_number++;
                } else {
-                       bau_desc->header.msg_type = MSG_RETRY;
+                       if (uv1)
+                               uv1_hdr->msg_type = MSG_RETRY;
+                       else
+                               uv2_hdr->msg_type = MSG_RETRY;
                        stat->s_retry_messages++;
                }
 
-               bau_desc->header.sequence = seq_number;
-               index = (1UL << AS_PUSH_SHIFT) | bcp->uvhub_cpu;
+               if (uv1)
+                       uv1_hdr->sequence = seq_number;
+               else
+                       uv2_hdr->sequence = seq_number;
+               index = (1UL << AS_PUSH_SHIFT) | bcp->using_desc;
                bcp->send_message = get_cycles();
 
                write_mmr_activation(index);
 
                try++;
                completion_stat = wait_completion(bau_desc, bcp, try);
+               /* UV2: wait_completion() may change the bcp->using_desc */
 
                handle_cmplt(completion_stat, bau_desc, bcp, hmaster, stat);
 
@@ -798,6 +934,7 @@ int uv_flush_send_and_wait(struct bau_desc *bau_desc,
                }
                cpu_relax();
        } while ((completion_stat == FLUSH_RETRY_PLUGGED) ||
+                (completion_stat == FLUSH_RETRY_BUSYBUG) ||
                 (completion_stat == FLUSH_RETRY_TIMEOUT));
 
        time2 = get_cycles();
@@ -812,6 +949,7 @@ int uv_flush_send_and_wait(struct bau_desc *bau_desc,
        record_send_stats(time1, time2, bcp, stat, completion_stat, try);
 
        if (completion_stat == FLUSH_GIVEUP)
+               /* FLUSH_GIVEUP will fall back to using IPI's for tlb flush */
                return 1;
        return 0;
 }
@@ -967,7 +1105,7 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
                stat->s_ntargself++;
 
        bau_desc = bcp->descriptor_base;
-       bau_desc += ITEMS_PER_DESC * bcp->uvhub_cpu;
+       bau_desc += (ITEMS_PER_DESC * bcp->using_desc);
        bau_uvhubs_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE);
        if (set_distrib_bits(flush_mask, bcp, bau_desc, &locals, &remotes))
                return NULL;
@@ -980,12 +1118,85 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
         * uv_flush_send_and_wait returns 0 if all cpu's were messaged,
         * or 1 if it gave up and the original cpumask should be returned.
         */
-       if (!uv_flush_send_and_wait(bau_desc, flush_mask, bcp))
+       if (!uv_flush_send_and_wait(flush_mask, bcp))
                return NULL;
        else
                return cpumask;
 }
 
+/*
+ * Search the message queue for any 'other' message with the same software
+ * acknowledge resource bit vector.
+ */
+struct bau_pq_entry *find_another_by_swack(struct bau_pq_entry *msg,
+                       struct bau_control *bcp, unsigned char swack_vec)
+{
+       struct bau_pq_entry *msg_next = msg + 1;
+
+       if (msg_next > bcp->queue_last)
+               msg_next = bcp->queue_first;
+       while ((msg_next->swack_vec != 0) && (msg_next != msg)) {
+               if (msg_next->swack_vec == swack_vec)
+                       return msg_next;
+               msg_next++;
+               if (msg_next > bcp->queue_last)
+                       msg_next = bcp->queue_first;
+       }
+       return NULL;
+}
+
+/*
+ * UV2 needs to work around a bug in which an arriving message has not
+ * set a bit in the UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE register.
+ * Such a message must be ignored.
+ */
+void process_uv2_message(struct msg_desc *mdp, struct bau_control *bcp)
+{
+       unsigned long mmr_image;
+       unsigned char swack_vec;
+       struct bau_pq_entry *msg = mdp->msg;
+       struct bau_pq_entry *other_msg;
+
+       mmr_image = read_mmr_sw_ack();
+       swack_vec = msg->swack_vec;
+
+       if ((swack_vec & mmr_image) == 0) {
+               /*
+                * This message was assigned a swack resource, but no
+                * reserved acknowlegment is pending.
+                * The bug has prevented this message from setting the MMR.
+                * And no other message has used the same sw_ack resource.
+                * Do the requested shootdown but do not reply to the msg.
+                * (the 0 means make no acknowledge)
+                */
+               bau_process_message(mdp, bcp, 0);
+               return;
+       }
+
+       /*
+        * Some message has set the MMR 'pending' bit; it might have been
+        * another message.  Look for that message.
+        */
+       other_msg = find_another_by_swack(msg, bcp, msg->swack_vec);
+       if (other_msg) {
+               /* There is another.  Do not ack the current one. */
+               bau_process_message(mdp, bcp, 0);
+               /*
+                * Let the natural processing of that message acknowledge
+                * it. Don't get the processing of sw_ack's out of order.
+                */
+               return;
+       }
+
+       /*
+        * There is no other message using this sw_ack, so it is safe to
+        * acknowledge it.
+        */
+       bau_process_message(mdp, bcp, 1);
+
+       return;
+}
+
 /*
  * The BAU message interrupt comes here. (registered by set_intr_gate)
  * See entry_64.S
@@ -1009,6 +1220,7 @@ void uv_bau_message_interrupt(struct pt_regs *regs)
        struct ptc_stats *stat;
        struct msg_desc msgdesc;
 
+       ack_APIC_irq();
        time_start = get_cycles();
 
        bcp = &per_cpu(bau_control, smp_processor_id());
@@ -1022,9 +1234,11 @@ void uv_bau_message_interrupt(struct pt_regs *regs)
                count++;
 
                msgdesc.msg_slot = msg - msgdesc.queue_first;
-               msgdesc.swack_slot = ffs(msg->swack_vec) - 1;
                msgdesc.msg = msg;
-               bau_process_message(&msgdesc, bcp);
+               if (bcp->uvhub_version == 2)
+                       process_uv2_message(&msgdesc, bcp);
+               else
+                       bau_process_message(&msgdesc, bcp, 1);
 
                msg++;
                if (msg > msgdesc.queue_last)
@@ -1036,8 +1250,6 @@ void uv_bau_message_interrupt(struct pt_regs *regs)
                stat->d_nomsg++;
        else if (count > 1)
                stat->d_multmsg++;
-
-       ack_APIC_irq();
 }
 
 /*
@@ -1083,7 +1295,7 @@ static void __init enable_timeouts(void)
                 */
                mmr_image |= (1L << SOFTACK_MSHIFT);
                if (is_uv2_hub()) {
-                       mmr_image |= (1L << UV2_LEG_SHFT);
+                       mmr_image &= ~(1L << UV2_LEG_SHFT);
                        mmr_image |= (1L << UV2_EXT_SHFT);
                }
                write_mmr_misc_control(pnode, mmr_image);
@@ -1136,13 +1348,13 @@ static int ptc_seq_show(struct seq_file *file, void *data)
                seq_printf(file,
                        "remotehub numuvhubs numuvhubs16 numuvhubs8 ");
                seq_printf(file,
-                       "numuvhubs4 numuvhubs2 numuvhubs1 dto retries rok ");
+                   "numuvhubs4 numuvhubs2 numuvhubs1 dto snacks retries rok ");
                seq_printf(file,
                        "resetp resett giveup sto bz throt swack recv rtime ");
                seq_printf(file,
                        "all one mult none retry canc nocan reset rcan ");
                seq_printf(file,
-                       "disable enable\n");
+                       "disable enable wars warshw warwaits\n");
        }
        if (cpu < num_possible_cpus() && cpu_online(cpu)) {
                stat = &per_cpu(ptcstats, cpu);
@@ -1154,10 +1366,10 @@ static int ptc_seq_show(struct seq_file *file, void *data)
                           stat->s_ntargremotes, stat->s_ntargcpu,
                           stat->s_ntarglocaluvhub, stat->s_ntargremoteuvhub,
                           stat->s_ntarguvhub, stat->s_ntarguvhub16);
-               seq_printf(file, "%ld %ld %ld %ld %ld ",
+               seq_printf(file, "%ld %ld %ld %ld %ld %ld ",
                           stat->s_ntarguvhub8, stat->s_ntarguvhub4,
                           stat->s_ntarguvhub2, stat->s_ntarguvhub1,
-                          stat->s_dtimeout);
+                          stat->s_dtimeout, stat->s_strongnacks);
                seq_printf(file, "%ld %ld %ld %ld %ld %ld %ld %ld ",
                           stat->s_retry_messages, stat->s_retriesok,
                           stat->s_resets_plug, stat->s_resets_timeout,
@@ -1173,8 +1385,10 @@ static int ptc_seq_show(struct seq_file *file, void *data)
                           stat->d_nomsg, stat->d_retries, stat->d_canceled,
                           stat->d_nocanceled, stat->d_resets,
                           stat->d_rcanceled);
-               seq_printf(file, "%ld %ld\n",
-                       stat->s_bau_disabled, stat->s_bau_reenabled);
+               seq_printf(file, "%ld %ld %ld %ld %ld\n",
+                       stat->s_bau_disabled, stat->s_bau_reenabled,
+                       stat->s_uv2_wars, stat->s_uv2_wars_hw,
+                       stat->s_uv2_war_waits);
        }
        return 0;
 }
@@ -1432,12 +1646,15 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode)
 {
        int i;
        int cpu;
+       int uv1 = 0;
        unsigned long gpa;
        unsigned long m;
        unsigned long n;
        size_t dsize;
        struct bau_desc *bau_desc;
        struct bau_desc *bd2;
+       struct uv1_bau_msg_header *uv1_hdr;
+       struct uv2_bau_msg_header *uv2_hdr;
        struct bau_control *bcp;
 
        /*
@@ -1451,6 +1668,8 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode)
        gpa = uv_gpa(bau_desc);
        n = uv_gpa_to_gnode(gpa);
        m = uv_gpa_to_offset(gpa);
+       if (is_uv1_hub())
+               uv1 = 1;
 
        /* the 14-bit pnode */
        write_mmr_descriptor_base(pnode, (n << UV_DESC_PSHIFT | m));
@@ -1461,21 +1680,33 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode)
         */
        for (i = 0, bd2 = bau_desc; i < (ADP_SZ * ITEMS_PER_DESC); i++, bd2++) {
                memset(bd2, 0, sizeof(struct bau_desc));
-               bd2->header.swack_flag =        1;
-               /*
-                * The base_dest_nasid set in the message header is the nasid
-                * of the first uvhub in the partition. The bit map will
-                * indicate destination pnode numbers relative to that base.
-                * They may not be consecutive if nasid striding is being used.
-                */
-               bd2->header.base_dest_nasid =   UV_PNODE_TO_NASID(base_pnode);
-               bd2->header.dest_subnodeid =    UV_LB_SUBNODEID;
-               bd2->header.command =           UV_NET_ENDPOINT_INTD;
-               bd2->header.int_both =          1;
-               /*
-                * all others need to be set to zero:
-                *   fairness chaining multilevel count replied_to
-                */
+               if (uv1) {
+                       uv1_hdr = &bd2->header.uv1_hdr;
+                       uv1_hdr->swack_flag =   1;
+                       /*
+                        * The base_dest_nasid set in the message header
+                        * is the nasid of the first uvhub in the partition.
+                        * The bit map will indicate destination pnode numbers
+                        * relative to that base. They may not be consecutive
+                        * if nasid striding is being used.
+                        */
+                       uv1_hdr->base_dest_nasid =
+                                               UV_PNODE_TO_NASID(base_pnode);
+                       uv1_hdr->dest_subnodeid =       UV_LB_SUBNODEID;
+                       uv1_hdr->command =              UV_NET_ENDPOINT_INTD;
+                       uv1_hdr->int_both =             1;
+                       /*
+                        * all others need to be set to zero:
+                        *   fairness chaining multilevel count replied_to
+                        */
+               } else {
+                       uv2_hdr = &bd2->header.uv2_hdr;
+                       uv2_hdr->swack_flag =   1;
+                       uv2_hdr->base_dest_nasid =
+                                               UV_PNODE_TO_NASID(base_pnode);
+                       uv2_hdr->dest_subnodeid =       UV_LB_SUBNODEID;
+                       uv2_hdr->command =              UV_NET_ENDPOINT_INTD;
+               }
        }
        for_each_present_cpu(cpu) {
                if (pnode != uv_blade_to_pnode(uv_cpu_to_blade_id(cpu)))
@@ -1531,6 +1762,7 @@ static void pq_init(int node, int pnode)
        write_mmr_payload_first(pnode, pn_first);
        write_mmr_payload_tail(pnode, first);
        write_mmr_payload_last(pnode, last);
+       write_gmmr_sw_ack(pnode, 0xffffUL);
 
        /* in effect, all msg_type's are set to MSG_NOOP */
        memset(pqp, 0, sizeof(struct bau_pq_entry) * DEST_Q_SIZE);
@@ -1584,14 +1816,14 @@ static int calculate_destination_timeout(void)
                ts_ns = base * mult1 * mult2;
                ret = ts_ns / 1000;
        } else {
-               /* 4 bits  0/1 for 10/80us, 3 bits of multiplier */
-               mmr_image = uv_read_local_mmr(UVH_AGING_PRESCALE_SEL);
+               /* 4 bits  0/1 for 10/80us base, 3 bits of multiplier */
+               mmr_image = uv_read_local_mmr(UVH_LB_BAU_MISC_CONTROL);
                mmr_image = (mmr_image & UV_SA_MASK) >> UV_SA_SHFT;
                if (mmr_image & (1L << UV2_ACK_UNITS_SHFT))
-                       mult1 = 80;
+                       base = 80;
                else
-                       mult1 = 10;
-               base = mmr_image & UV2_ACK_MASK;
+                       base = 10;
+               mult1 = mmr_image & UV2_ACK_MASK;
                ret = mult1 * base;
        }
        return ret;
@@ -1618,6 +1850,7 @@ static void __init init_per_cpu_tunables(void)
                bcp->cong_response_us           = congested_respns_us;
                bcp->cong_reps                  = congested_reps;
                bcp->cong_period                = congested_period;
+               bcp->clocks_per_100_usec =      usec_2_cycles(100);
        }
 }
 
@@ -1728,8 +1961,17 @@ static int scan_sock(struct socket_desc *sdp, struct uvhub_desc *bdp,
                bcp->cpus_in_socket = sdp->num_cpus;
                bcp->socket_master = *smasterp;
                bcp->uvhub = bdp->uvhub;
+               if (is_uv1_hub())
+                       bcp->uvhub_version = 1;
+               else if (is_uv2_hub())
+                       bcp->uvhub_version = 2;
+               else {
+                       printk(KERN_EMERG "uvhub version not 1 or 2\n");
+                       return 1;
+               }
                bcp->uvhub_master = *hmasterp;
                bcp->uvhub_cpu = uv_cpu_hub_info(cpu)->blade_processor_id;
+               bcp->using_desc = bcp->uvhub_cpu;
                if (bcp->uvhub_cpu >= MAX_CPUS_PER_UVHUB) {
                        printk(KERN_EMERG "%d cpus per uvhub invalid\n",
                                bcp->uvhub_cpu);
@@ -1845,6 +2087,8 @@ static int __init uv_bau_init(void)
                        uv_base_pnode = uv_blade_to_pnode(uvhub);
        }
 
+       enable_timeouts();
+
        if (init_per_cpu(nuvhubs, uv_base_pnode)) {
                nobau = 1;
                return 0;
@@ -1855,7 +2099,6 @@ static int __init uv_bau_init(void)
                if (uv_blade_nr_possible_cpus(uvhub))
                        init_uvhub(uvhub, vector, uv_base_pnode);
 
-       enable_timeouts();
        alloc_intr_gate(vector, uv_bau_message_intr1);
 
        for_each_possible_blade(uvhub) {
@@ -1867,7 +2110,8 @@ static int __init uv_bau_init(void)
                        val = 1L << 63;
                        write_gmmr_activation(pnode, val);
                        mmr = 1; /* should be 1 to broadcast to both sockets */
-                       write_mmr_data_broadcast(pnode, mmr);
+                       if (!is_uv1_hub())
+                               write_mmr_data_broadcast(pnode, mmr);
                }
        }
 
diff --git a/arch/x86/syscalls/Makefile b/arch/x86/syscalls/Makefile
new file mode 100644 (file)
index 0000000..564b247
--- /dev/null
@@ -0,0 +1,43 @@
+out := $(obj)/../include/generated/asm
+
+# Create output directory if not already present
+_dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)')
+
+syscall32 := $(srctree)/$(src)/syscall_32.tbl
+syscall64 := $(srctree)/$(src)/syscall_64.tbl
+
+syshdr := $(srctree)/$(src)/syscallhdr.sh
+systbl := $(srctree)/$(src)/syscalltbl.sh
+
+quiet_cmd_syshdr = SYSHDR  $@
+      cmd_syshdr = $(CONFIG_SHELL) '$(syshdr)' $< $@ \
+                  $(syshdr_abi_$(basetarget)) $(syshdr_pfx_$(basetarget))
+quiet_cmd_systbl = SYSTBL  $@
+      cmd_systbl = $(CONFIG_SHELL) '$(systbl)' $< $@
+
+syshdr_abi_unistd_32 := i386
+$(out)/unistd_32.h: $(syscall32) $(syshdr)
+       $(call if_changed,syshdr)
+
+syshdr_abi_unistd_32_ia32 := i386
+syshdr_pfx_unistd_32_ia32 := ia32_
+$(out)/unistd_32_ia32.h: $(syscall32) $(syshdr)
+       $(call if_changed,syshdr)
+
+syshdr_abi_unistd_64 := 64
+$(out)/unistd_64.h: $(syscall64) $(syshdr)
+       $(call if_changed,syshdr)
+
+$(out)/syscalls_32.h: $(syscall32) $(systbl)
+       $(call if_changed,systbl)
+$(out)/syscalls_64.h: $(syscall64) $(systbl)
+       $(call if_changed,systbl)
+
+syshdr-y                       += unistd_32.h unistd_64.h
+syshdr-y                       += syscalls_32.h
+syshdr-$(CONFIG_X86_64)                += unistd_32_ia32.h
+syshdr-$(CONFIG_X86_64)                += syscalls_64.h
+
+targets        += $(syshdr-y)
+
+all: $(addprefix $(out)/,$(targets))
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
new file mode 100644 (file)
index 0000000..ce98e28
--- /dev/null
@@ -0,0 +1,357 @@
+#
+# 32-bit system call numbers and entry vectors
+#
+# The format is:
+# <number> <abi> <name> <entry point> <compat entry point>
+#
+# The abi is always "i386" for this file.
+#
+0      i386    restart_syscall         sys_restart_syscall
+1      i386    exit                    sys_exit
+2      i386    fork                    ptregs_fork                     stub32_fork
+3      i386    read                    sys_read
+4      i386    write                   sys_write
+5      i386    open                    sys_open                        compat_sys_open
+6      i386    close                   sys_close
+7      i386    waitpid                 sys_waitpid                     sys32_waitpid
+8      i386    creat                   sys_creat
+9      i386    link                    sys_link
+10     i386    unlink                  sys_unlink
+11     i386    execve                  ptregs_execve                   stub32_execve
+12     i386    chdir                   sys_chdir
+13     i386    time                    sys_time                        compat_sys_time
+14     i386    mknod                   sys_mknod
+15     i386    chmod                   sys_chmod
+16     i386    lchown                  sys_lchown16
+17     i386    break
+18     i386    oldstat                 sys_stat
+19     i386    lseek                   sys_lseek                       sys32_lseek
+20     i386    getpid                  sys_getpid
+21     i386    mount                   sys_mount                       compat_sys_mount
+22     i386    umount                  sys_oldumount
+23     i386    setuid                  sys_setuid16
+24     i386    getuid                  sys_getuid16
+25     i386    stime                   sys_stime                       compat_sys_stime
+26     i386    ptrace                  sys_ptrace                      compat_sys_ptrace
+27     i386    alarm                   sys_alarm
+28     i386    oldfstat                sys_fstat
+29     i386    pause                   sys_pause
+30     i386    utime                   sys_utime                       compat_sys_utime
+31     i386    stty
+32     i386    gtty
+33     i386    access                  sys_access
+34     i386    nice                    sys_nice
+35     i386    ftime
+36     i386    sync                    sys_sync
+37     i386    kill                    sys_kill                        sys32_kill
+38     i386    rename                  sys_rename
+39     i386    mkdir                   sys_mkdir
+40     i386    rmdir                   sys_rmdir
+41     i386    dup                     sys_dup
+42     i386    pipe                    sys_pipe
+43     i386    times                   sys_times                       compat_sys_times
+44     i386    prof
+45     i386    brk                     sys_brk
+46     i386    setgid                  sys_setgid16
+47     i386    getgid                  sys_getgid16
+48     i386    signal                  sys_signal
+49     i386    geteuid                 sys_geteuid16
+50     i386    getegid                 sys_getegid16
+51     i386    acct                    sys_acct
+52     i386    umount2                 sys_umount
+53     i386    lock
+54     i386    ioctl                   sys_ioctl                       compat_sys_ioctl
+55     i386    fcntl                   sys_fcntl                       compat_sys_fcntl64
+56     i386    mpx
+57     i386    setpgid                 sys_setpgid
+58     i386    ulimit
+59     i386    oldolduname             sys_olduname
+60     i386    umask                   sys_umask
+61     i386    chroot                  sys_chroot
+62     i386    ustat                   sys_ustat                       compat_sys_ustat
+63     i386    dup2                    sys_dup2
+64     i386    getppid                 sys_getppid
+65     i386    getpgrp                 sys_getpgrp
+66     i386    setsid                  sys_setsid
+67     i386    sigaction               sys_sigaction                   sys32_sigaction
+68     i386    sgetmask                sys_sgetmask
+69     i386    ssetmask                sys_ssetmask
+70     i386    setreuid                sys_setreuid16
+71     i386    setregid                sys_setregid16
+72     i386    sigsuspend              sys_sigsuspend                  sys32_sigsuspend
+73     i386    sigpending              sys_sigpending                  compat_sys_sigpending
+74     i386    sethostname             sys_sethostname
+75     i386    setrlimit               sys_setrlimit                   compat_sys_setrlimit
+76     i386    getrlimit               sys_old_getrlimit               compat_sys_old_getrlimit
+77     i386    getrusage               sys_getrusage                   compat_sys_getrusage
+78     i386    gettimeofday            sys_gettimeofday                compat_sys_gettimeofday
+79     i386    settimeofday            sys_settimeofday                compat_sys_settimeofday
+80     i386    getgroups               sys_getgroups16
+81     i386    setgroups               sys_setgroups16
+82     i386    select                  sys_old_select                  compat_sys_old_select
+83     i386    symlink                 sys_symlink
+84     i386    oldlstat                sys_lstat
+85     i386    readlink                sys_readlink
+86     i386    uselib                  sys_uselib
+87     i386    swapon                  sys_swapon
+88     i386    reboot                  sys_reboot
+89     i386    readdir                 sys_old_readdir                 compat_sys_old_readdir
+90     i386    mmap                    sys_old_mmap                    sys32_mmap
+91     i386    munmap                  sys_munmap
+92     i386    truncate                sys_truncate
+93     i386    ftruncate               sys_ftruncate
+94     i386    fchmod                  sys_fchmod
+95     i386    fchown                  sys_fchown16
+96     i386    getpriority             sys_getpriority
+97     i386    setpriority             sys_setpriority
+98     i386    profil
+99     i386    statfs                  sys_statfs                      compat_sys_statfs
+100    i386    fstatfs                 sys_fstatfs                     compat_sys_fstatfs
+101    i386    ioperm                  sys_ioperm
+102    i386    socketcall              sys_socketcall                  compat_sys_socketcall
+103    i386    syslog                  sys_syslog
+104    i386    setitimer               sys_setitimer                   compat_sys_setitimer
+105    i386    getitimer               sys_getitimer                   compat_sys_getitimer
+106    i386    stat                    sys_newstat                     compat_sys_newstat
+107    i386    lstat                   sys_newlstat                    compat_sys_newlstat
+108    i386    fstat                   sys_newfstat                    compat_sys_newfstat
+109    i386    olduname                sys_uname
+110    i386    iopl                    ptregs_iopl                     stub32_iopl
+111    i386    vhangup                 sys_vhangup
+112    i386    idle
+113    i386    vm86old                 ptregs_vm86old                  sys32_vm86_warning
+114    i386    wait4                   sys_wait4                       compat_sys_wait4
+115    i386    swapoff                 sys_swapoff
+116    i386    sysinfo                 sys_sysinfo                     compat_sys_sysinfo
+117    i386    ipc                     sys_ipc                         sys32_ipc
+118    i386    fsync                   sys_fsync
+119    i386    sigreturn               ptregs_sigreturn                stub32_sigreturn
+120    i386    clone                   ptregs_clone                    stub32_clone
+121    i386    setdomainname           sys_setdomainname
+122    i386    uname                   sys_newuname
+123    i386    modify_ldt              sys_modify_ldt
+124    i386    adjtimex                sys_adjtimex                    compat_sys_adjtimex
+125    i386    mprotect                sys_mprotect                    sys32_mprotect
+126    i386    sigprocmask             sys_sigprocmask                 compat_sys_sigprocmask
+127    i386    create_module
+128    i386    init_module             sys_init_module
+129    i386    delete_module           sys_delete_module
+130    i386    get_kernel_syms
+131    i386    quotactl                sys_quotactl                    sys32_quotactl
+132    i386    getpgid                 sys_getpgid
+133    i386    fchdir                  sys_fchdir
+134    i386    bdflush                 sys_bdflush
+135    i386    sysfs                   sys_sysfs
+136    i386    personality             sys_personality
+137    i386    afs_syscall
+138    i386    setfsuid                sys_setfsuid16
+139    i386    setfsgid                sys_setfsgid16
+140    i386    _llseek                 sys_llseek
+141    i386    getdents                sys_getdents                    compat_sys_getdents
+142    i386    _newselect              sys_select                      compat_sys_select
+143    i386    flock                   sys_flock
+144    i386    msync                   sys_msync
+145    i386    readv                   sys_readv                       compat_sys_readv
+146    i386    writev                  sys_writev                      compat_sys_writev
+147    i386    getsid                  sys_getsid
+148    i386    fdatasync               sys_fdatasync
+149    i386    _sysctl                 sys_sysctl                      compat_sys_sysctl
+150    i386    mlock                   sys_mlock
+151    i386    munlock                 sys_munlock
+152    i386    mlockall                sys_mlockall
+153    i386    munlockall              sys_munlockall
+154    i386    sched_setparam          sys_sched_setparam
+155    i386    sched_getparam          sys_sched_getparam
+156    i386    sched_setscheduler      sys_sched_setscheduler
+157    i386    sched_getscheduler      sys_sched_getscheduler
+158    i386    sched_yield             sys_sched_yield
+159    i386    sched_get_priority_max  sys_sched_get_priority_max
+160    i386    sched_get_priority_min  sys_sched_get_priority_min
+161    i386    sched_rr_get_interval   sys_sched_rr_get_interval       sys32_sched_rr_get_interval
+162    i386    nanosleep               sys_nanosleep                   compat_sys_nanosleep
+163    i386    mremap                  sys_mremap
+164    i386    setresuid               sys_setresuid16
+165    i386    getresuid               sys_getresuid16
+166    i386    vm86                    ptregs_vm86                     sys32_vm86_warning
+167    i386    query_module
+168    i386    poll                    sys_poll
+169    i386    nfsservctl
+170    i386    setresgid               sys_setresgid16
+171    i386    getresgid               sys_getresgid16
+172    i386    prctl                   sys_prctl
+173    i386    rt_sigreturn            ptregs_rt_sigreturn             stub32_rt_sigreturn
+174    i386    rt_sigaction            sys_rt_sigaction                sys32_rt_sigaction
+175    i386    rt_sigprocmask          sys_rt_sigprocmask              sys32_rt_sigprocmask
+176    i386    rt_sigpending           sys_rt_sigpending               sys32_rt_sigpending
+177    i386    rt_sigtimedwait         sys_rt_sigtimedwait             compat_sys_rt_sigtimedwait
+178    i386    rt_sigqueueinfo         sys_rt_sigqueueinfo             sys32_rt_sigqueueinfo
+179    i386    rt_sigsuspend           sys_rt_sigsuspend
+180    i386    pread64                 sys_pread64                     sys32_pread
+181    i386    pwrite64                sys_pwrite64                    sys32_pwrite
+182    i386    chown                   sys_chown16
+183    i386    getcwd                  sys_getcwd
+184    i386    capget                  sys_capget
+185    i386    capset                  sys_capset
+186    i386    sigaltstack             ptregs_sigaltstack              stub32_sigaltstack
+187    i386    sendfile                sys_sendfile                    sys32_sendfile
+188    i386    getpmsg
+189    i386    putpmsg
+190    i386    vfork                   ptregs_vfork                    stub32_vfork
+191    i386    ugetrlimit              sys_getrlimit                   compat_sys_getrlimit
+192    i386    mmap2                   sys_mmap_pgoff
+193    i386    truncate64              sys_truncate64                  sys32_truncate64
+194    i386    ftruncate64             sys_ftruncate64                 sys32_ftruncate64
+195    i386    stat64                  sys_stat64                      sys32_stat64
+196    i386    lstat64                 sys_lstat64                     sys32_lstat64
+197    i386    fstat64                 sys_fstat64                     sys32_fstat64
+198    i386    lchown32                sys_lchown
+199    i386    getuid32                sys_getuid
+200    i386    getgid32                sys_getgid
+201    i386    geteuid32               sys_geteuid
+202    i386    getegid32               sys_getegid
+203    i386    setreuid32              sys_setreuid
+204    i386    setregid32              sys_setregid
+205    i386    getgroups32             sys_getgroups
+206    i386    setgroups32             sys_setgroups
+207    i386    fchown32                sys_fchown
+208    i386    setresuid32             sys_setresuid
+209    i386    getresuid32             sys_getresuid
+210    i386    setresgid32             sys_setresgid
+211    i386    getresgid32             sys_getresgid
+212    i386    chown32                 sys_chown
+213    i386    setuid32                sys_setuid
+214    i386    setgid32                sys_setgid
+215    i386    setfsuid32              sys_setfsuid
+216    i386    setfsgid32              sys_setfsgid
+217    i386    pivot_root              sys_pivot_root
+218    i386    mincore                 sys_mincore
+219    i386    madvise                 sys_madvise
+220    i386    getdents64              sys_getdents64                  compat_sys_getdents64
+221    i386    fcntl64                 sys_fcntl64                     compat_sys_fcntl64
+# 222 is unused
+# 223 is unused
+224    i386    gettid                  sys_gettid
+225    i386    readahead               sys_readahead                   sys32_readahead
+226    i386    setxattr                sys_setxattr
+227    i386    lsetxattr               sys_lsetxattr
+228    i386    fsetxattr               sys_fsetxattr
+229    i386    getxattr                sys_getxattr
+230    i386    lgetxattr               sys_lgetxattr
+231    i386    fgetxattr               sys_fgetxattr
+232    i386    listxattr               sys_listxattr
+233    i386    llistxattr              sys_llistxattr
+234    i386    flistxattr              sys_flistxattr
+235    i386    removexattr             sys_removexattr
+236    i386    lremovexattr            sys_lremovexattr
+237    i386    fremovexattr            sys_fremovexattr
+238    i386    tkill                   sys_tkill
+239    i386    sendfile64              sys_sendfile64
+240    i386    futex                   sys_futex                       compat_sys_futex
+241    i386    sched_setaffinity       sys_sched_setaffinity           compat_sys_sched_setaffinity
+242    i386    sched_getaffinity       sys_sched_getaffinity           compat_sys_sched_getaffinity
+243    i386    set_thread_area         sys_set_thread_area
+244    i386    get_thread_area         sys_get_thread_area
+245    i386    io_setup                sys_io_setup                    compat_sys_io_setup
+246    i386    io_destroy              sys_io_destroy
+247    i386    io_getevents            sys_io_getevents                compat_sys_io_getevents
+248    i386    io_submit               sys_io_submit                   compat_sys_io_submit
+249    i386    io_cancel               sys_io_cancel
+250    i386    fadvise64               sys_fadvise64                   sys32_fadvise64
+# 251 is available for reuse (was briefly sys_set_zone_reclaim)
+252    i386    exit_group              sys_exit_group
+253    i386    lookup_dcookie          sys_lookup_dcookie              sys32_lookup_dcookie
+254    i386    epoll_create            sys_epoll_create
+255    i386    epoll_ctl               sys_epoll_ctl
+256    i386    epoll_wait              sys_epoll_wait
+257    i386    remap_file_pages        sys_remap_file_pages
+258    i386    set_tid_address         sys_set_tid_address
+259    i386    timer_create            sys_timer_create                compat_sys_timer_create
+260    i386    timer_settime           sys_timer_settime               compat_sys_timer_settime
+261    i386    timer_gettime           sys_timer_gettime               compat_sys_timer_gettime
+262    i386    timer_getoverrun        sys_timer_getoverrun
+263    i386    timer_delete            sys_timer_delete
+264    i386    clock_settime           sys_clock_settime               compat_sys_clock_settime
+265    i386    clock_gettime           sys_clock_gettime               compat_sys_clock_gettime
+266    i386    clock_getres            sys_clock_getres                compat_sys_clock_getres
+267    i386    clock_nanosleep         sys_clock_nanosleep             compat_sys_clock_nanosleep
+268    i386    statfs64                sys_statfs64                    compat_sys_statfs64
+269    i386    fstatfs64               sys_fstatfs64                   compat_sys_fstatfs64
+270    i386    tgkill                  sys_tgkill
+271    i386    utimes                  sys_utimes                      compat_sys_utimes
+272    i386    fadvise64_64            sys_fadvise64_64                sys32_fadvise64_64
+273    i386    vserver
+274    i386    mbind                   sys_mbind
+275    i386    get_mempolicy           sys_get_mempolicy               compat_sys_get_mempolicy
+276    i386    set_mempolicy           sys_set_mempolicy
+277    i386    mq_open                 sys_mq_open                     compat_sys_mq_open
+278    i386    mq_unlink               sys_mq_unlink
+279    i386    mq_timedsend            sys_mq_timedsend                compat_sys_mq_timedsend
+280    i386    mq_timedreceive         sys_mq_timedreceive             compat_sys_mq_timedreceive
+281    i386    mq_notify               sys_mq_notify                   compat_sys_mq_notify
+282    i386    mq_getsetaddr           sys_mq_getsetattr               compat_sys_mq_getsetattr
+283    i386    kexec_load              sys_kexec_load                  compat_sys_kexec_load
+284    i386    waitid                  sys_waitid                      compat_sys_waitid
+# 285 sys_setaltroot
+286    i386    add_key                 sys_add_key
+287    i386    request_key             sys_request_key
+288    i386    keyctl                  sys_keyctl
+289    i386    ioprio_set              sys_ioprio_set
+290    i386    ioprio_get              sys_ioprio_get
+291    i386    inotify_init            sys_inotify_init
+292    i386    inotify_add_watch       sys_inotify_add_watch
+293    i386    inotify_rm_watch        sys_inotify_rm_watch
+294    i386    migrate_pages           sys_migrate_pages
+295    i386    openat                  sys_openat                      compat_sys_openat
+296    i386    mkdirat                 sys_mkdirat
+297    i386    mknodat                 sys_mknodat
+298    i386    fchownat                sys_fchownat
+299    i386    futimesat               sys_futimesat                   compat_sys_futimesat
+300    i386    fstatat64               sys_fstatat64                   sys32_fstatat
+301    i386    unlinkat                sys_unlinkat
+302    i386    renameat                sys_renameat
+303    i386    linkat                  sys_linkat
+304    i386    symlinkat               sys_symlinkat
+305    i386    readlinkat              sys_readlinkat
+306    i386    fchmodat                sys_fchmodat
+307    i386    faccessat               sys_faccessat
+308    i386    pselect6                sys_pselect6                    compat_sys_pselect6
+309    i386    ppoll                   sys_ppoll                       compat_sys_ppoll
+310    i386    unshare                 sys_unshare
+311    i386    set_robust_list         sys_set_robust_list             compat_sys_set_robust_list
+312    i386    get_robust_list         sys_get_robust_list             compat_sys_get_robust_list
+313    i386    splice                  sys_splice
+314    i386    sync_file_range         sys_sync_file_range             sys32_sync_file_range
+315    i386    tee                     sys_tee
+316    i386    vmsplice                sys_vmsplice                    compat_sys_vmsplice
+317    i386    move_pages              sys_move_pages                  compat_sys_move_pages
+318    i386    getcpu                  sys_getcpu
+319    i386    epoll_pwait             sys_epoll_pwait
+320    i386    utimensat               sys_utimensat                   compat_sys_utimensat
+321    i386    signalfd                sys_signalfd                    compat_sys_signalfd
+322    i386    timerfd_create          sys_timerfd_create
+323    i386    eventfd                 sys_eventfd
+324    i386    fallocate               sys_fallocate                   sys32_fallocate
+325    i386    timerfd_settime         sys_timerfd_settime             compat_sys_timerfd_settime
+326    i386    timerfd_gettime         sys_timerfd_gettime             compat_sys_timerfd_gettime
+327    i386    signalfd4               sys_signalfd4                   compat_sys_signalfd4
+328    i386    eventfd2                sys_eventfd2
+329    i386    epoll_create1           sys_epoll_create1
+330    i386    dup3                    sys_dup3
+331    i386    pipe2                   sys_pipe2
+332    i386    inotify_init1           sys_inotify_init1
+333    i386    preadv                  sys_preadv                      compat_sys_preadv
+334    i386    pwritev                 sys_pwritev                     compat_sys_pwritev
+335    i386    rt_tgsigqueueinfo       sys_rt_tgsigqueueinfo           compat_sys_rt_tgsigqueueinfo
+336    i386    perf_event_open         sys_perf_event_open
+337    i386    recvmmsg                sys_recvmmsg                    compat_sys_recvmmsg
+338    i386    fanotify_init           sys_fanotify_init
+339    i386    fanotify_mark           sys_fanotify_mark               sys32_fanotify_mark
+340    i386    prlimit64               sys_prlimit64
+341    i386    name_to_handle_at       sys_name_to_handle_at
+342    i386    open_by_handle_at       sys_open_by_handle_at           compat_sys_open_by_handle_at
+343    i386    clock_adjtime           sys_clock_adjtime               compat_sys_clock_adjtime
+344    i386    syncfs                  sys_syncfs
+345    i386    sendmmsg                sys_sendmmsg                    compat_sys_sendmmsg
+346    i386    setns                   sys_setns
+347    i386    process_vm_readv        sys_process_vm_readv            compat_sys_process_vm_readv
+348    i386    process_vm_writev       sys_process_vm_writev           compat_sys_process_vm_writev
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl
new file mode 100644 (file)
index 0000000..b440a8f
--- /dev/null
@@ -0,0 +1,320 @@
+#
+# 64-bit system call numbers and entry vectors
+#
+# The format is:
+# <number> <abi> <name> <entry point>
+#
+# The abi is always "64" for this file (for now.)
+#
+0      64      read                    sys_read
+1      64      write                   sys_write
+2      64      open                    sys_open
+3      64      close                   sys_close
+4      64      stat                    sys_newstat
+5      64      fstat                   sys_newfstat
+6      64      lstat                   sys_newlstat
+7      64      poll                    sys_poll
+8      64      lseek                   sys_lseek
+9      64      mmap                    sys_mmap
+10     64      mprotect                sys_mprotect
+11     64      munmap                  sys_munmap
+12     64      brk                     sys_brk
+13     64      rt_sigaction            sys_rt_sigaction
+14     64      rt_sigprocmask          sys_rt_sigprocmask
+15     64      rt_sigreturn            stub_rt_sigreturn
+16     64      ioctl                   sys_ioctl
+17     64      pread64                 sys_pread64
+18     64      pwrite64                sys_pwrite64
+19     64      readv                   sys_readv
+20     64      writev                  sys_writev
+21     64      access                  sys_access
+22     64      pipe                    sys_pipe
+23     64      select                  sys_select
+24     64      sched_yield             sys_sched_yield
+25     64      mremap                  sys_mremap
+26     64      msync                   sys_msync
+27     64      mincore                 sys_mincore
+28     64      madvise                 sys_madvise
+29     64      shmget                  sys_shmget
+30     64      shmat                   sys_shmat
+31     64      shmctl                  sys_shmctl
+32     64      dup                     sys_dup
+33     64      dup2                    sys_dup2
+34     64      pause                   sys_pause
+35     64      nanosleep               sys_nanosleep
+36     64      getitimer               sys_getitimer
+37     64      alarm                   sys_alarm
+38     64      setitimer               sys_setitimer
+39     64      getpid                  sys_getpid
+40     64      sendfile                sys_sendfile64
+41     64      socket                  sys_socket
+42     64      connect                 sys_connect
+43     64      accept                  sys_accept
+44     64      sendto                  sys_sendto
+45     64      recvfrom                sys_recvfrom
+46     64      sendmsg                 sys_sendmsg
+47     64      recvmsg                 sys_recvmsg
+48     64      shutdown                sys_shutdown
+49     64      bind                    sys_bind
+50     64      listen                  sys_listen
+51     64      getsockname             sys_getsockname
+52     64      getpeername             sys_getpeername
+53     64      socketpair              sys_socketpair
+54     64      setsockopt              sys_setsockopt
+55     64      getsockopt              sys_getsockopt
+56     64      clone                   stub_clone
+57     64      fork                    stub_fork
+58     64      vfork                   stub_vfork
+59     64      execve                  stub_execve
+60     64      exit                    sys_exit
+61     64      wait4                   sys_wait4
+62     64      kill                    sys_kill
+63     64      uname                   sys_newuname
+64     64      semget                  sys_semget
+65     64      semop                   sys_semop
+66     64      semctl                  sys_semctl
+67     64      shmdt                   sys_shmdt
+68     64      msgget                  sys_msgget
+69     64      msgsnd                  sys_msgsnd
+70     64      msgrcv                  sys_msgrcv
+71     64      msgctl                  sys_msgctl
+72     64      fcntl                   sys_fcntl
+73     64      flock                   sys_flock
+74     64      fsync                   sys_fsync
+75     64      fdatasync               sys_fdatasync
+76     64      truncate                sys_truncate
+77     64      ftruncate               sys_ftruncate
+78     64      getdents                sys_getdents
+79     64      getcwd                  sys_getcwd
+80     64      chdir                   sys_chdir
+81     64      fchdir                  sys_fchdir
+82     64      rename                  sys_rename
+83     64      mkdir                   sys_mkdir
+84     64      rmdir                   sys_rmdir
+85     64      creat                   sys_creat
+86     64      link                    sys_link
+87     64      unlink                  sys_unlink
+88     64      symlink                 sys_symlink
+89     64      readlink                sys_readlink
+90     64      chmod                   sys_chmod
+91     64      fchmod                  sys_fchmod
+92     64      chown                   sys_chown
+93     64      fchown                  sys_fchown
+94     64      lchown                  sys_lchown
+95     64      umask                   sys_umask
+96     64      gettimeofday            sys_gettimeofday
+97     64      getrlimit               sys_getrlimit
+98     64      getrusage               sys_getrusage
+99     64      sysinfo                 sys_sysinfo
+100    64      times                   sys_times
+101    64      ptrace                  sys_ptrace
+102    64      getuid                  sys_getuid
+103    64      syslog                  sys_syslog
+104    64      getgid                  sys_getgid
+105    64      setuid                  sys_setuid
+106    64      setgid                  sys_setgid
+107    64      geteuid                 sys_geteuid
+108    64      getegid                 sys_getegid
+109    64      setpgid                 sys_setpgid
+110    64      getppid                 sys_getppid
+111    64      getpgrp                 sys_getpgrp
+112    64      setsid                  sys_setsid
+113    64      setreuid                sys_setreuid
+114    64      setregid                sys_setregid
+115    64      getgroups               sys_getgroups
+116    64      setgroups               sys_setgroups
+117    64      setresuid               sys_setresuid
+118    64      getresuid               sys_getresuid
+119    64      setresgid               sys_setresgid
+120    64      getresgid               sys_getresgid
+121    64      getpgid                 sys_getpgid
+122    64      setfsuid                sys_setfsuid
+123    64      setfsgid                sys_setfsgid
+124    64      getsid                  sys_getsid
+125    64      capget                  sys_capget
+126    64      capset                  sys_capset
+127    64      rt_sigpending           sys_rt_sigpending
+128    64      rt_sigtimedwait         sys_rt_sigtimedwait
+129    64      rt_sigqueueinfo         sys_rt_sigqueueinfo
+130    64      rt_sigsuspend           sys_rt_sigsuspend
+131    64      sigaltstack             stub_sigaltstack
+132    64      utime                   sys_utime
+133    64      mknod                   sys_mknod
+134    64      uselib
+135    64      personality             sys_personality
+136    64      ustat                   sys_ustat
+137    64      statfs                  sys_statfs
+138    64      fstatfs                 sys_fstatfs
+139    64      sysfs                   sys_sysfs
+140    64      getpriority             sys_getpriority
+141    64      setpriority             sys_setpriority
+142    64      sched_setparam          sys_sched_setparam
+143    64      sched_getparam          sys_sched_getparam
+144    64      sched_setscheduler      sys_sched_setscheduler
+145    64      sched_getscheduler      sys_sched_getscheduler
+146    64      sched_get_priority_max  sys_sched_get_priority_max
+147    64      sched_get_priority_min  sys_sched_get_priority_min
+148    64      sched_rr_get_interval   sys_sched_rr_get_interval
+149    64      mlock                   sys_mlock
+150    64      munlock                 sys_munlock
+151    64      mlockall                sys_mlockall
+152    64      munlockall              sys_munlockall
+153    64      vhangup                 sys_vhangup
+154    64      modify_ldt              sys_modify_ldt
+155    64      pivot_root              sys_pivot_root
+156    64      _sysctl                 sys_sysctl
+157    64      prctl                   sys_prctl
+158    64      arch_prctl              sys_arch_prctl
+159    64      adjtimex                sys_adjtimex
+160    64      setrlimit               sys_setrlimit
+161    64      chroot                  sys_chroot
+162    64      sync                    sys_sync
+163    64      acct                    sys_acct
+164    64      settimeofday            sys_settimeofday
+165    64      mount                   sys_mount
+166    64      umount2                 sys_umount
+167    64      swapon                  sys_swapon
+168    64      swapoff                 sys_swapoff
+169    64      reboot                  sys_reboot
+170    64      sethostname             sys_sethostname
+171    64      setdomainname           sys_setdomainname
+172    64      iopl                    stub_iopl
+173    64      ioperm                  sys_ioperm
+174    64      create_module
+175    64      init_module             sys_init_module
+176    64      delete_module           sys_delete_module
+177    64      get_kernel_syms
+178    64      query_module
+179    64      quotactl                sys_quotactl
+180    64      nfsservctl
+181    64      getpmsg
+182    64      putpmsg
+183    64      afs_syscall
+184    64      tuxcall
+185    64      security
+186    64      gettid                  sys_gettid
+187    64      readahead               sys_readahead
+188    64      setxattr                sys_setxattr
+189    64      lsetxattr               sys_lsetxattr
+190    64      fsetxattr               sys_fsetxattr
+191    64      getxattr                sys_getxattr
+192    64      lgetxattr               sys_lgetxattr
+193    64      fgetxattr               sys_fgetxattr
+194    64      listxattr               sys_listxattr
+195    64      llistxattr              sys_llistxattr
+196    64      flistxattr              sys_flistxattr
+197    64      removexattr             sys_removexattr
+198    64      lremovexattr            sys_lremovexattr
+199    64      fremovexattr            sys_fremovexattr
+200    64      tkill                   sys_tkill
+201    64      time                    sys_time
+202    64      futex                   sys_futex
+203    64      sched_setaffinity       sys_sched_setaffinity
+204    64      sched_getaffinity       sys_sched_getaffinity
+205    64      set_thread_area
+206    64      io_setup                sys_io_setup
+207    64      io_destroy              sys_io_destroy
+208    64      io_getevents            sys_io_getevents
+209    64      io_submit               sys_io_submit
+210    64      io_cancel               sys_io_cancel
+211    64      get_thread_area
+212    64      lookup_dcookie          sys_lookup_dcookie
+213    64      epoll_create            sys_epoll_create
+214    64      epoll_ctl_old
+215    64      epoll_wait_old
+216    64      remap_file_pages        sys_remap_file_pages
+217    64      getdents64              sys_getdents64
+218    64      set_tid_address         sys_set_tid_address
+219    64      restart_syscall         sys_restart_syscall
+220    64      semtimedop              sys_semtimedop
+221    64      fadvise64               sys_fadvise64
+222    64      timer_create            sys_timer_create
+223    64      timer_settime           sys_timer_settime
+224    64      timer_gettime           sys_timer_gettime
+225    64      timer_getoverrun        sys_timer_getoverrun
+226    64      timer_delete            sys_timer_delete
+227    64      clock_settime           sys_clock_settime
+228    64      clock_gettime           sys_clock_gettime
+229    64      clock_getres            sys_clock_getres
+230    64      clock_nanosleep         sys_clock_nanosleep
+231    64      exit_group              sys_exit_group
+232    64      epoll_wait              sys_epoll_wait
+233    64      epoll_ctl               sys_epoll_ctl
+234    64      tgkill                  sys_tgkill
+235    64      utimes                  sys_utimes
+236    64      vserver
+237    64      mbind                   sys_mbind
+238    64      set_mempolicy           sys_set_mempolicy
+239    64      get_mempolicy           sys_get_mempolicy
+240    64      mq_open                 sys_mq_open
+241    64      mq_unlink               sys_mq_unlink
+242    64      mq_timedsend            sys_mq_timedsend
+243    64      mq_timedreceive         sys_mq_timedreceive
+244    64      mq_notify               sys_mq_notify
+245    64      mq_getsetattr           sys_mq_getsetattr
+246    64      kexec_load              sys_kexec_load
+247    64      waitid                  sys_waitid
+248    64      add_key                 sys_add_key
+249    64      request_key             sys_request_key
+250    64      keyctl                  sys_keyctl
+251    64      ioprio_set              sys_ioprio_set
+252    64      ioprio_get              sys_ioprio_get
+253    64      inotify_init            sys_inotify_init
+254    64      inotify_add_watch       sys_inotify_add_watch
+255    64      inotify_rm_watch        sys_inotify_rm_watch
+256    64      migrate_pages           sys_migrate_pages
+257    64      openat                  sys_openat
+258    64      mkdirat                 sys_mkdirat
+259    64      mknodat                 sys_mknodat
+260    64      fchownat                sys_fchownat
+261    64      futimesat               sys_futimesat
+262    64      newfstatat              sys_newfstatat
+263    64      unlinkat                sys_unlinkat
+264    64      renameat                sys_renameat
+265    64      linkat                  sys_linkat
+266    64      symlinkat               sys_symlinkat
+267    64      readlinkat              sys_readlinkat
+268    64      fchmodat                sys_fchmodat
+269    64      faccessat               sys_faccessat
+270    64      pselect6                sys_pselect6
+271    64      ppoll                   sys_ppoll
+272    64      unshare                 sys_unshare
+273    64      set_robust_list         sys_set_robust_list
+274    64      get_robust_list         sys_get_robust_list
+275    64      splice                  sys_splice
+276    64      tee                     sys_tee
+277    64      sync_file_range         sys_sync_file_range
+278    64      vmsplice                sys_vmsplice
+279    64      move_pages              sys_move_pages
+280    64      utimensat               sys_utimensat
+281    64      epoll_pwait             sys_epoll_pwait
+282    64      signalfd                sys_signalfd
+283    64      timerfd_create          sys_timerfd_create
+284    64      eventfd                 sys_eventfd
+285    64      fallocate               sys_fallocate
+286    64      timerfd_settime         sys_timerfd_settime
+287    64      timerfd_gettime         sys_timerfd_gettime
+288    64      accept4                 sys_accept4
+289    64      signalfd4               sys_signalfd4
+290    64      eventfd2                sys_eventfd2
+291    64      epoll_create1           sys_epoll_create1
+292    64      dup3                    sys_dup3
+293    64      pipe2                   sys_pipe2
+294    64      inotify_init1           sys_inotify_init1
+295    64      preadv                  sys_preadv
+296    64      pwritev                 sys_pwritev
+297    64      rt_tgsigqueueinfo       sys_rt_tgsigqueueinfo
+298    64      perf_event_open         sys_perf_event_open
+299    64      recvmmsg                sys_recvmmsg
+300    64      fanotify_init           sys_fanotify_init
+301    64      fanotify_mark           sys_fanotify_mark
+302    64      prlimit64               sys_prlimit64
+303    64      name_to_handle_at       sys_name_to_handle_at
+304    64      open_by_handle_at       sys_open_by_handle_at
+305    64      clock_adjtime           sys_clock_adjtime
+306    64      syncfs                  sys_syncfs
+307    64      sendmmsg                sys_sendmmsg
+308    64      setns                   sys_setns
+309    64      getcpu                  sys_getcpu
+310    64      process_vm_readv        sys_process_vm_readv
+311    64      process_vm_writev       sys_process_vm_writev
diff --git a/arch/x86/syscalls/syscallhdr.sh b/arch/x86/syscalls/syscallhdr.sh
new file mode 100644 (file)
index 0000000..31fd5f1
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+in="$1"
+out="$2"
+my_abis=`echo "($3)" | tr ',' '|'`
+prefix="$4"
+offset="$5"
+
+fileguard=_ASM_X86_`basename "$out" | sed \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
+    -e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g'`
+grep -E "^[0-9A-Fa-fXx]+[[:space:]]+${my_abis}" "$in" | sort -n | (
+    echo "#ifndef ${fileguard}"
+    echo "#define ${fileguard} 1"
+    echo ""
+
+    while read nr abi name entry ; do
+       if [ -z "$offset" ]; then
+           echo "#define __NR_${prefix}${name} $nr"
+       else
+           echo "#define __NR_${prefix}${name} ($offset + $nr)"
+        fi
+    done
+
+    echo ""
+    echo "#endif /* ${fileguard} */"
+) > "$out"
diff --git a/arch/x86/syscalls/syscalltbl.sh b/arch/x86/syscalls/syscalltbl.sh
new file mode 100644 (file)
index 0000000..0e7f8ec
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+in="$1"
+out="$2"
+
+grep '^[0-9]' "$in" | sort -n | (
+    while read nr abi name entry compat; do
+       abi=`echo "$abi" | tr '[a-z]' '[A-Z]'`
+       if [ -n "$compat" ]; then
+           echo "__SYSCALL_${abi}($nr, $entry, $compat)"
+       elif [ -n "$entry" ]; then
+           echo "__SYSCALL_${abi}($nr, $entry, $entry)"
+       fi
+    done
+) > "$out"
index 1d97bd84b6fbcfe684b559cf271f7fe72d75f92b..b2b54d2edf53979fb7daf770c0d4bf0215a73fe0 100644 (file)
@@ -6,14 +6,6 @@ menu "UML-specific options"
 
 menu "Host processor type and features"
 
-config CMPXCHG_LOCAL
-       bool
-       default n
-
-config CMPXCHG_DOUBLE
-       bool
-       default n
-
 source "arch/x86/Kconfig.cpu"
 
 endmenu
index 8fb58400e4155b32cb8281f6bd0a53d4b6a8d253..5d065b2222d370e13dd161a6b66e96590b747739 100644 (file)
@@ -37,7 +37,8 @@ subarch-$(CONFIG_MODULES) += ../kernel/module.o
 USER_OBJS := bugs_$(BITS).o ptrace_user.o fault.o
 
 extra-y += user-offsets.s
-$(obj)/user-offsets.s: c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS)
+$(obj)/user-offsets.s: c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) \
+       -Iarch/x86/include/generated
 
 UNPROFILE_OBJS := stub_segv.o
 CFLAGS_stub_segv.o := $(CFLAGS_NO_HARDENING)
index 711b1621747f2e45e8497a13c7c81b9bc260916f..2bbe1ec2d96ab1a4d8ae8ab540eae7f9360c2db4 100644 (file)
@@ -1,5 +1,15 @@
+#ifndef __SYSDEP_X86_PTRACE_H
+#define __SYSDEP_X86_PTRACE_H
+
 #ifdef __i386__
 #include "ptrace_32.h"
 #else
 #include "ptrace_64.h"
 #endif
+
+static inline long regs_return_value(struct uml_pt_regs *regs)
+{
+       return UPT_SYSCALL_RET(regs);
+}
+
+#endif /* __SYSDEP_X86_PTRACE_H */
diff --git a/arch/x86/um/sys_call_table_32.S b/arch/x86/um/sys_call_table_32.S
deleted file mode 100644 (file)
index a7ca80d..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#include <linux/linkage.h>
-/* Steal i386 syscall table for our purposes, but with some slight changes.*/
-
-#define sys_iopl sys_ni_syscall
-#define sys_ioperm sys_ni_syscall
-
-#define sys_vm86old sys_ni_syscall
-#define sys_vm86 sys_ni_syscall
-
-#define old_mmap sys_old_mmap
-
-#define ptregs_fork sys_fork
-#define ptregs_execve sys_execve
-#define ptregs_iopl sys_iopl
-#define ptregs_vm86old sys_vm86old
-#define ptregs_clone sys_clone
-#define ptregs_vm86 sys_vm86
-#define ptregs_sigaltstack sys_sigaltstack
-#define ptregs_vfork sys_vfork
-
-.section .rodata,"a"
-
-#include "../kernel/syscall_table_32.S"
-
-ENTRY(syscall_table_size)
-.long .-sys_call_table
diff --git a/arch/x86/um/sys_call_table_32.c b/arch/x86/um/sys_call_table_32.c
new file mode 100644 (file)
index 0000000..416bd40
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * System call table for UML/i386, copied from arch/x86/kernel/syscall_*.c
+ * with some changes for UML.
+ */
+
+#include <linux/linkage.h>
+#include <linux/sys.h>
+#include <linux/cache.h>
+#include <generated/user_constants.h>
+
+#define __NO_STUBS
+
+/*
+ * Below you can see, in terms of #define's, the differences between the x86-64
+ * and the UML syscall table.
+ */
+
+/* Not going to be implemented by UML, since we have no hardware. */
+#define sys_iopl sys_ni_syscall
+#define sys_ioperm sys_ni_syscall
+
+#define sys_vm86old sys_ni_syscall
+#define sys_vm86 sys_ni_syscall
+
+#define old_mmap sys_old_mmap
+
+#define ptregs_fork sys_fork
+#define ptregs_execve sys_execve
+#define ptregs_iopl sys_iopl
+#define ptregs_vm86old sys_vm86old
+#define ptregs_clone sys_clone
+#define ptregs_vm86 sys_vm86
+#define ptregs_sigaltstack sys_sigaltstack
+#define ptregs_vfork sys_vfork
+
+#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ;
+#include <asm/syscalls_32.h>
+
+#undef __SYSCALL_I386
+#define __SYSCALL_I386(nr, sym, compat) [ nr ] = sym,
+
+typedef void (*sys_call_ptr_t)(void);
+
+extern void sys_ni_syscall(void);
+
+const sys_call_ptr_t sys_call_table[] __cacheline_aligned = {
+       /*
+        * Smells like a compiler bug -- it doesn't work
+        * when the & below is removed.
+        */
+       [0 ... __NR_syscall_max] = &sys_ni_syscall,
+#include <asm/syscalls_32.h>
+};
+
+int syscall_table_size = sizeof(sys_call_table);
index 99522f78b16251e8cc222fcb96e1b56de153bba1..fe626c3ba01b280a6ddc9b2bc3fb894b7c504c3e 100644 (file)
@@ -1,11 +1,12 @@
 /*
- * System call table for UML/x86-64, copied from arch/x86_64/kernel/syscall.c
+ * System call table for UML/x86-64, copied from arch/x86/kernel/syscall_*.c
  * with some changes for UML.
  */
 
 #include <linux/linkage.h>
 #include <linux/sys.h>
 #include <linux/cache.h>
+#include <generated/user_constants.h>
 
 #define __NO_STUBS
 
 #define stub_sigaltstack sys_sigaltstack
 #define stub_rt_sigreturn sys_rt_sigreturn
 
-#define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ;
-#undef _ASM_X86_UNISTD_64_H
-#include "../../x86/include/asm/unistd_64.h"
+#define __SYSCALL_64(nr, sym, compat) extern asmlinkage void sym(void) ;
+#include <asm/syscalls_64.h>
 
-#undef __SYSCALL
-#define __SYSCALL(nr, sym) [ nr ] = sym,
-#undef _ASM_X86_UNISTD_64_H
+#undef __SYSCALL_64
+#define __SYSCALL_64(nr, sym, compat) [ nr ] = sym,
 
 typedef void (*sys_call_ptr_t)(void);
 
 extern void sys_ni_syscall(void);
 
-/*
- * We used to have a trick here which made sure that holes in the
- * x86_64 table were filled in with sys_ni_syscall, but a comment in
- * unistd_64.h says that holes aren't allowed, so the trick was
- * removed.
- * The trick looked like this
- *     [0 ... UM_NR_syscall_max] = &sys_ni_syscall
- * before including unistd_64.h - the later initializations overwrote
- * the sys_ni_syscall filler.
- */
-
-sys_call_ptr_t sys_call_table[] __cacheline_aligned = {
-#include <asm/unistd_64.h>
+const sys_call_ptr_t sys_call_table[] __cacheline_aligned = {
+       /*
+        * Smells like a compiler bug -- it doesn't work
+        * when the & below is removed.
+        */
+       [0 ... __NR_syscall_max] = &sys_ni_syscall,
+#include <asm/syscalls_64.h>
 };
 
 int syscall_table_size = sizeof(sys_call_table);
index ca49be8ddd0c7160821a4d4db06f18346f52b195..5edf4f4bbf531f2e3912a1068bf78f65de8cbcf8 100644 (file)
@@ -8,6 +8,18 @@
 #include <asm/ptrace.h>
 #include <asm/types.h>
 
+#ifdef __i386__
+#define __SYSCALL_I386(nr, sym, compat) [nr] = 1,
+static char syscalls[] = {
+#include <asm/syscalls_32.h>
+};
+#else
+#define __SYSCALL_64(nr, sym, compat) [nr] = 1,
+static char syscalls[] = {
+#include <asm/syscalls_64.h>
+};
+#endif
+
 #define DEFINE(sym, val) \
        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
 
@@ -77,4 +89,7 @@ void foo(void)
        DEFINE(UM_PROT_READ, PROT_READ);
        DEFINE(UM_PROT_WRITE, PROT_WRITE);
        DEFINE(UM_PROT_EXEC, PROT_EXEC);
+
+       DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
+       DEFINE(NR_syscalls, sizeof(syscalls));
 }
index a0d042aa296755e441fe4266a7103b315a581a34..2dff698ab02e5ce1642248afa0f582b8aa0f112f 100644 (file)
@@ -334,8 +334,7 @@ void do_syscall_trace_enter(struct pt_regs *regs)
                do_syscall_trace();
 
 #if 0
-       if (unlikely(current->audit_context))
-               audit_syscall_entry(current, AUDIT_ARCH_XTENSA..);
+       audit_syscall_entry(current, AUDIT_ARCH_XTENSA..);
 #endif
 }
 
index b8c143d68ee02664758df3e6d702c79fd594d8d4..fa8f26309444d2cdda41cae813cf6f5a70f1de06 100644 (file)
@@ -1655,11 +1655,12 @@ static void blkiocg_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
        struct io_context *ioc;
 
        cgroup_taskset_for_each(task, cgrp, tset) {
-               task_lock(task);
-               ioc = task->io_context;
-               if (ioc)
-                       ioc->cgroup_changed = 1;
-               task_unlock(task);
+               /* we don't lose anything even if ioc allocation fails */
+               ioc = get_task_io_context(task, GFP_ATOMIC, NUMA_NO_NODE);
+               if (ioc) {
+                       ioc_cgroup_changed(ioc);
+                       put_io_context(ioc, NULL);
+               }
        }
 }
 
index 15de223c7f9371a9da852825ea8857789d94ae70..e6c05a97ee2ba94538222d76273d0d2fbae644cc 100644 (file)
@@ -39,6 +39,8 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap);
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap);
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete);
 
+DEFINE_IDA(blk_queue_ida);
+
 /*
  * For the allocated request tables
  */
@@ -358,7 +360,8 @@ EXPORT_SYMBOL(blk_put_queue);
 void blk_drain_queue(struct request_queue *q, bool drain_all)
 {
        while (true) {
-               int nr_rqs;
+               bool drain = false;
+               int i;
 
                spin_lock_irq(q->queue_lock);
 
@@ -375,14 +378,25 @@ void blk_drain_queue(struct request_queue *q, bool drain_all)
                if (!list_empty(&q->queue_head))
                        __blk_run_queue(q);
 
-               if (drain_all)
-                       nr_rqs = q->rq.count[0] + q->rq.count[1];
-               else
-                       nr_rqs = q->rq.elvpriv;
+               drain |= q->rq.elvpriv;
+
+               /*
+                * Unfortunately, requests are queued at and tracked from
+                * multiple places and there's no single counter which can
+                * be drained.  Check all the queues and counters.
+                */
+               if (drain_all) {
+                       drain |= !list_empty(&q->queue_head);
+                       for (i = 0; i < 2; i++) {
+                               drain |= q->rq.count[i];
+                               drain |= q->in_flight[i];
+                               drain |= !list_empty(&q->flush_queue[i]);
+                       }
+               }
 
                spin_unlock_irq(q->queue_lock);
 
-               if (!nr_rqs)
+               if (!drain)
                        break;
                msleep(10);
        }
@@ -469,6 +483,10 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
        if (!q)
                return NULL;
 
+       q->id = ida_simple_get(&blk_queue_ida, 0, 0, GFP_KERNEL);
+       if (q->id < 0)
+               goto fail_q;
+
        q->backing_dev_info.ra_pages =
                        (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
        q->backing_dev_info.state = 0;
@@ -477,20 +495,17 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
        q->node = node_id;
 
        err = bdi_init(&q->backing_dev_info);
-       if (err) {
-               kmem_cache_free(blk_requestq_cachep, q);
-               return NULL;
-       }
+       if (err)
+               goto fail_id;
 
-       if (blk_throtl_init(q)) {
-               kmem_cache_free(blk_requestq_cachep, q);
-               return NULL;
-       }
+       if (blk_throtl_init(q))
+               goto fail_id;
 
        setup_timer(&q->backing_dev_info.laptop_mode_wb_timer,
                    laptop_mode_timer_fn, (unsigned long) q);
        setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
        INIT_LIST_HEAD(&q->timeout_list);
+       INIT_LIST_HEAD(&q->icq_list);
        INIT_LIST_HEAD(&q->flush_queue[0]);
        INIT_LIST_HEAD(&q->flush_queue[1]);
        INIT_LIST_HEAD(&q->flush_data_in_flight);
@@ -508,6 +523,12 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
        q->queue_lock = &q->__queue_lock;
 
        return q;
+
+fail_id:
+       ida_simple_remove(&blk_queue_ida, q->id);
+fail_q:
+       kmem_cache_free(blk_requestq_cachep, q);
+       return NULL;
 }
 EXPORT_SYMBOL(blk_alloc_queue_node);
 
@@ -605,26 +626,31 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
 }
 EXPORT_SYMBOL(blk_init_allocated_queue);
 
-int blk_get_queue(struct request_queue *q)
+bool blk_get_queue(struct request_queue *q)
 {
-       if (likely(!test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) {
-               kobject_get(&q->kobj);
-               return 0;
+       if (likely(!blk_queue_dead(q))) {
+               __blk_get_queue(q);
+               return true;
        }
 
-       return 1;
+       return false;
 }
 EXPORT_SYMBOL(blk_get_queue);
 
 static inline void blk_free_request(struct request_queue *q, struct request *rq)
 {
-       if (rq->cmd_flags & REQ_ELVPRIV)
+       if (rq->cmd_flags & REQ_ELVPRIV) {
                elv_put_request(q, rq);
+               if (rq->elv.icq)
+                       put_io_context(rq->elv.icq->ioc, q);
+       }
+
        mempool_free(rq, q->rq.rq_pool);
 }
 
 static struct request *
-blk_alloc_request(struct request_queue *q, unsigned int flags, gfp_t gfp_mask)
+blk_alloc_request(struct request_queue *q, struct io_cq *icq,
+                 unsigned int flags, gfp_t gfp_mask)
 {
        struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);
 
@@ -635,10 +661,15 @@ blk_alloc_request(struct request_queue *q, unsigned int flags, gfp_t gfp_mask)
 
        rq->cmd_flags = flags | REQ_ALLOCED;
 
-       if ((flags & REQ_ELVPRIV) &&
-           unlikely(elv_set_request(q, rq, gfp_mask))) {
-               mempool_free(rq, q->rq.rq_pool);
-               return NULL;
+       if (flags & REQ_ELVPRIV) {
+               rq->elv.icq = icq;
+               if (unlikely(elv_set_request(q, rq, gfp_mask))) {
+                       mempool_free(rq, q->rq.rq_pool);
+                       return NULL;
+               }
+               /* @rq->elv.icq holds on to io_context until @rq is freed */
+               if (icq)
+                       get_io_context(icq->ioc);
        }
 
        return rq;
@@ -750,11 +781,17 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
 {
        struct request *rq = NULL;
        struct request_list *rl = &q->rq;
-       struct io_context *ioc = NULL;
+       struct elevator_type *et;
+       struct io_context *ioc;
+       struct io_cq *icq = NULL;
        const bool is_sync = rw_is_sync(rw_flags) != 0;
+       bool retried = false;
        int may_queue;
+retry:
+       et = q->elevator->type;
+       ioc = current->io_context;
 
-       if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)))
+       if (unlikely(blk_queue_dead(q)))
                return NULL;
 
        may_queue = elv_may_queue(q, rw_flags);
@@ -763,7 +800,20 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
 
        if (rl->count[is_sync]+1 >= queue_congestion_on_threshold(q)) {
                if (rl->count[is_sync]+1 >= q->nr_requests) {
-                       ioc = current_io_context(GFP_ATOMIC, q->node);
+                       /*
+                        * We want ioc to record batching state.  If it's
+                        * not already there, creating a new one requires
+                        * dropping queue_lock, which in turn requires
+                        * retesting conditions to avoid queue hang.
+                        */
+                       if (!ioc && !retried) {
+                               spin_unlock_irq(q->queue_lock);
+                               create_io_context(current, gfp_mask, q->node);
+                               spin_lock_irq(q->queue_lock);
+                               retried = true;
+                               goto retry;
+                       }
+
                        /*
                         * The queue will fill after this allocation, so set
                         * it as full, and mark this process as "batching".
@@ -799,17 +849,36 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
        rl->count[is_sync]++;
        rl->starved[is_sync] = 0;
 
+       /*
+        * Decide whether the new request will be managed by elevator.  If
+        * so, mark @rw_flags and increment elvpriv.  Non-zero elvpriv will
+        * prevent the current elevator from being destroyed until the new
+        * request is freed.  This guarantees icq's won't be destroyed and
+        * makes creating new ones safe.
+        *
+        * Also, lookup icq while holding queue_lock.  If it doesn't exist,
+        * it will be created after releasing queue_lock.
+        */
        if (blk_rq_should_init_elevator(bio) &&
            !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags)) {
                rw_flags |= REQ_ELVPRIV;
                rl->elvpriv++;
+               if (et->icq_cache && ioc)
+                       icq = ioc_lookup_icq(ioc, q);
        }
 
        if (blk_queue_io_stat(q))
                rw_flags |= REQ_IO_STAT;
        spin_unlock_irq(q->queue_lock);
 
-       rq = blk_alloc_request(q, rw_flags, gfp_mask);
+       /* create icq if missing */
+       if (unlikely(et->icq_cache && !icq))
+               icq = ioc_create_icq(q, gfp_mask);
+
+       /* rqs are guaranteed to have icq on elv_set_request() if requested */
+       if (likely(!et->icq_cache || icq))
+               rq = blk_alloc_request(q, icq, rw_flags, gfp_mask);
+
        if (unlikely(!rq)) {
                /*
                 * Allocation failed presumably due to memory. Undo anything
@@ -871,10 +940,9 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags,
        rq = get_request(q, rw_flags, bio, GFP_NOIO);
        while (!rq) {
                DEFINE_WAIT(wait);
-               struct io_context *ioc;
                struct request_list *rl = &q->rq;
 
-               if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)))
+               if (unlikely(blk_queue_dead(q)))
                        return NULL;
 
                prepare_to_wait_exclusive(&rl->wait[is_sync], &wait,
@@ -891,8 +959,8 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags,
                 * up to a big batch of them for a small period time.
                 * See ioc_batching, ioc_set_batching
                 */
-               ioc = current_io_context(GFP_NOIO, q->node);
-               ioc_set_batching(q, ioc);
+               create_io_context(current, GFP_NOIO, q->node);
+               ioc_set_batching(q, current->io_context);
 
                spin_lock_irq(q->queue_lock);
                finish_wait(&rl->wait[is_sync], &wait);
@@ -1009,54 +1077,6 @@ static void add_acct_request(struct request_queue *q, struct request *rq,
        __elv_add_request(q, rq, where);
 }
 
-/**
- * blk_insert_request - insert a special request into a request queue
- * @q:         request queue where request should be inserted
- * @rq:                request to be inserted
- * @at_head:   insert request at head or tail of queue
- * @data:      private data
- *
- * Description:
- *    Many block devices need to execute commands asynchronously, so they don't
- *    block the whole kernel from preemption during request execution.  This is
- *    accomplished normally by inserting aritficial requests tagged as
- *    REQ_TYPE_SPECIAL in to the corresponding request queue, and letting them
- *    be scheduled for actual execution by the request queue.
- *
- *    We have the option of inserting the head or the tail of the queue.
- *    Typically we use the tail for new ioctls and so forth.  We use the head
- *    of the queue for things like a QUEUE_FULL message from a device, or a
- *    host that is unable to accept a particular command.
- */
-void blk_insert_request(struct request_queue *q, struct request *rq,
-                       int at_head, void *data)
-{
-       int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;
-       unsigned long flags;
-
-       /*
-        * tell I/O scheduler that this isn't a regular read/write (ie it
-        * must not attempt merges on this) and that it acts as a soft
-        * barrier
-        */
-       rq->cmd_type = REQ_TYPE_SPECIAL;
-
-       rq->special = data;
-
-       spin_lock_irqsave(q->queue_lock, flags);
-
-       /*
-        * If command is tagged, release the tag
-        */
-       if (blk_rq_tagged(rq))
-               blk_queue_end_tag(q, rq);
-
-       add_acct_request(q, rq, where);
-       __blk_run_queue(q);
-       spin_unlock_irqrestore(q->queue_lock, flags);
-}
-EXPORT_SYMBOL(blk_insert_request);
-
 static void part_round_stats_single(int cpu, struct hd_struct *part,
                                    unsigned long now)
 {
@@ -1766,6 +1786,10 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
                return -EIO;
 
        spin_lock_irqsave(q->queue_lock, flags);
+       if (unlikely(blk_queue_dead(q))) {
+               spin_unlock_irqrestore(q->queue_lock, flags);
+               return -ENODEV;
+       }
 
        /*
         * Submitting request must be dequeued before calling this function
@@ -2739,6 +2763,14 @@ static void queue_unplugged(struct request_queue *q, unsigned int depth,
 {
        trace_block_unplug(q, depth, !from_schedule);
 
+       /*
+        * Don't mess with dead queue.
+        */
+       if (unlikely(blk_queue_dead(q))) {
+               spin_unlock(q->queue_lock);
+               return;
+       }
+
        /*
         * If we are punting this to kblockd, then we can safely drop
         * the queue_lock before waking kblockd (which needs to take
@@ -2815,6 +2847,15 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
                        depth = 0;
                        spin_lock(q->queue_lock);
                }
+
+               /*
+                * Short-circuit if @q is dead
+                */
+               if (unlikely(blk_queue_dead(q))) {
+                       __blk_end_request_all(rq, -ENODEV);
+                       continue;
+               }
+
                /*
                 * rq is already accounted, so use raw insert
                 */
index a1ebceb332f963ee366aa7ebed60d69c4e1c11cb..fb2cbd551621d3f23be57210534ed98417d01489 100644 (file)
@@ -50,7 +50,11 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
 {
        int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;
 
-       if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) {
+       WARN_ON(irqs_disabled());
+       spin_lock_irq(q->queue_lock);
+
+       if (unlikely(blk_queue_dead(q))) {
+               spin_unlock_irq(q->queue_lock);
                rq->errors = -ENXIO;
                if (rq->end_io)
                        rq->end_io(rq, rq->errors);
@@ -59,8 +63,6 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
 
        rq->rq_disk = bd_disk;
        rq->end_io = done;
-       WARN_ON(irqs_disabled());
-       spin_lock_irq(q->queue_lock);
        __elv_add_request(q, rq, where);
        __blk_run_queue(q);
        /* the queue is stopped so it won't be run */
index 6f9bbd978653e631f4fdd5cb36eee160d6045031..27a06e00eaec4312c5596ad58ebaa7fcc8c438ef 100644 (file)
  */
 static struct kmem_cache *iocontext_cachep;
 
-static void cfq_dtor(struct io_context *ioc)
+/**
+ * get_io_context - increment reference count to io_context
+ * @ioc: io_context to get
+ *
+ * Increment reference count to @ioc.
+ */
+void get_io_context(struct io_context *ioc)
+{
+       BUG_ON(atomic_long_read(&ioc->refcount) <= 0);
+       atomic_long_inc(&ioc->refcount);
+}
+EXPORT_SYMBOL(get_io_context);
+
+/*
+ * Releasing ioc may nest into another put_io_context() leading to nested
+ * fast path release.  As the ioc's can't be the same, this is okay but
+ * makes lockdep whine.  Keep track of nesting and use it as subclass.
+ */
+#ifdef CONFIG_LOCKDEP
+#define ioc_release_depth(q)           ((q) ? (q)->ioc_release_depth : 0)
+#define ioc_release_depth_inc(q)       (q)->ioc_release_depth++
+#define ioc_release_depth_dec(q)       (q)->ioc_release_depth--
+#else
+#define ioc_release_depth(q)           0
+#define ioc_release_depth_inc(q)       do { } while (0)
+#define ioc_release_depth_dec(q)       do { } while (0)
+#endif
+
+static void icq_free_icq_rcu(struct rcu_head *head)
+{
+       struct io_cq *icq = container_of(head, struct io_cq, __rcu_head);
+
+       kmem_cache_free(icq->__rcu_icq_cache, icq);
+}
+
+/*
+ * Exit and free an icq.  Called with both ioc and q locked.
+ */
+static void ioc_exit_icq(struct io_cq *icq)
 {
-       if (!hlist_empty(&ioc->cic_list)) {
-               struct cfq_io_context *cic;
+       struct io_context *ioc = icq->ioc;
+       struct request_queue *q = icq->q;
+       struct elevator_type *et = q->elevator->type;
+
+       lockdep_assert_held(&ioc->lock);
+       lockdep_assert_held(q->queue_lock);
+
+       radix_tree_delete(&ioc->icq_tree, icq->q->id);
+       hlist_del_init(&icq->ioc_node);
+       list_del_init(&icq->q_node);
+
+       /*
+        * Both setting lookup hint to and clearing it from @icq are done
+        * under queue_lock.  If it's not pointing to @icq now, it never
+        * will.  Hint assignment itself can race safely.
+        */
+       if (rcu_dereference_raw(ioc->icq_hint) == icq)
+               rcu_assign_pointer(ioc->icq_hint, NULL);
 
-               cic = hlist_entry(ioc->cic_list.first, struct cfq_io_context,
-                                                               cic_list);
-               cic->dtor(ioc);
+       if (et->ops.elevator_exit_icq_fn) {
+               ioc_release_depth_inc(q);
+               et->ops.elevator_exit_icq_fn(icq);
+               ioc_release_depth_dec(q);
        }
+
+       /*
+        * @icq->q might have gone away by the time RCU callback runs
+        * making it impossible to determine icq_cache.  Record it in @icq.
+        */
+       icq->__rcu_icq_cache = et->icq_cache;
+       call_rcu(&icq->__rcu_head, icq_free_icq_rcu);
 }
 
 /*
- * IO Context helper functions. put_io_context() returns 1 if there are no
- * more users of this io context, 0 otherwise.
+ * Slow path for ioc release in put_io_context().  Performs double-lock
+ * dancing to unlink all icq's and then frees ioc.
  */
-int put_io_context(struct io_context *ioc)
+static void ioc_release_fn(struct work_struct *work)
 {
-       if (ioc == NULL)
-               return 1;
+       struct io_context *ioc = container_of(work, struct io_context,
+                                             release_work);
+       struct request_queue *last_q = NULL;
 
-       BUG_ON(atomic_long_read(&ioc->refcount) == 0);
+       spin_lock_irq(&ioc->lock);
 
-       if (atomic_long_dec_and_test(&ioc->refcount)) {
-               rcu_read_lock();
-               cfq_dtor(ioc);
-               rcu_read_unlock();
+       while (!hlist_empty(&ioc->icq_list)) {
+               struct io_cq *icq = hlist_entry(ioc->icq_list.first,
+                                               struct io_cq, ioc_node);
+               struct request_queue *this_q = icq->q;
 
-               kmem_cache_free(iocontext_cachep, ioc);
-               return 1;
+               if (this_q != last_q) {
+                       /*
+                        * Need to switch to @this_q.  Once we release
+                        * @ioc->lock, it can go away along with @cic.
+                        * Hold on to it.
+                        */
+                       __blk_get_queue(this_q);
+
+                       /*
+                        * blk_put_queue() might sleep thanks to kobject
+                        * idiocy.  Always release both locks, put and
+                        * restart.
+                        */
+                       if (last_q) {
+                               spin_unlock(last_q->queue_lock);
+                               spin_unlock_irq(&ioc->lock);
+                               blk_put_queue(last_q);
+                       } else {
+                               spin_unlock_irq(&ioc->lock);
+                       }
+
+                       last_q = this_q;
+                       spin_lock_irq(this_q->queue_lock);
+                       spin_lock(&ioc->lock);
+                       continue;
+               }
+               ioc_exit_icq(icq);
        }
-       return 0;
+
+       if (last_q) {
+               spin_unlock(last_q->queue_lock);
+               spin_unlock_irq(&ioc->lock);
+               blk_put_queue(last_q);
+       } else {
+               spin_unlock_irq(&ioc->lock);
+       }
+
+       kmem_cache_free(iocontext_cachep, ioc);
 }
-EXPORT_SYMBOL(put_io_context);
 
-static void cfq_exit(struct io_context *ioc)
+/**
+ * put_io_context - put a reference of io_context
+ * @ioc: io_context to put
+ * @locked_q: request_queue the caller is holding queue_lock of (hint)
+ *
+ * Decrement reference count of @ioc and release it if the count reaches
+ * zero.  If the caller is holding queue_lock of a queue, it can indicate
+ * that with @locked_q.  This is an optimization hint and the caller is
+ * allowed to pass in %NULL even when it's holding a queue_lock.
+ */
+void put_io_context(struct io_context *ioc, struct request_queue *locked_q)
 {
-       rcu_read_lock();
+       struct request_queue *last_q = locked_q;
+       unsigned long flags;
+
+       if (ioc == NULL)
+               return;
+
+       BUG_ON(atomic_long_read(&ioc->refcount) <= 0);
+       if (locked_q)
+               lockdep_assert_held(locked_q->queue_lock);
 
-       if (!hlist_empty(&ioc->cic_list)) {
-               struct cfq_io_context *cic;
+       if (!atomic_long_dec_and_test(&ioc->refcount))
+               return;
+
+       /*
+        * Destroy @ioc.  This is a bit messy because icq's are chained
+        * from both ioc and queue, and ioc->lock nests inside queue_lock.
+        * The inner ioc->lock should be held to walk our icq_list and then
+        * for each icq the outer matching queue_lock should be grabbed.
+        * ie. We need to do reverse-order double lock dancing.
+        *
+        * Another twist is that we are often called with one of the
+        * matching queue_locks held as indicated by @locked_q, which
+        * prevents performing double-lock dance for other queues.
+        *
+        * So, we do it in two stages.  The fast path uses the queue_lock
+        * the caller is holding and, if other queues need to be accessed,
+        * uses trylock to avoid introducing locking dependency.  This can
+        * handle most cases, especially if @ioc was performing IO on only
+        * single device.
+        *
+        * If trylock doesn't cut it, we defer to @ioc->release_work which
+        * can do all the double-locking dancing.
+        */
+       spin_lock_irqsave_nested(&ioc->lock, flags,
+                                ioc_release_depth(locked_q));
 
-               cic = hlist_entry(ioc->cic_list.first, struct cfq_io_context,
-                                                               cic_list);
-               cic->exit(ioc);
+       while (!hlist_empty(&ioc->icq_list)) {
+               struct io_cq *icq = hlist_entry(ioc->icq_list.first,
+                                               struct io_cq, ioc_node);
+               struct request_queue *this_q = icq->q;
+
+               if (this_q != last_q) {
+                       if (last_q && last_q != locked_q)
+                               spin_unlock(last_q->queue_lock);
+                       last_q = NULL;
+
+                       if (!spin_trylock(this_q->queue_lock))
+                               break;
+                       last_q = this_q;
+                       continue;
+               }
+               ioc_exit_icq(icq);
        }
-       rcu_read_unlock();
+
+       if (last_q && last_q != locked_q)
+               spin_unlock(last_q->queue_lock);
+
+       spin_unlock_irqrestore(&ioc->lock, flags);
+
+       /* if no icq is left, we're done; otherwise, kick release_work */
+       if (hlist_empty(&ioc->icq_list))
+               kmem_cache_free(iocontext_cachep, ioc);
+       else
+               schedule_work(&ioc->release_work);
 }
+EXPORT_SYMBOL(put_io_context);
 
 /* Called by the exiting task */
 void exit_io_context(struct task_struct *task)
@@ -74,86 +235,240 @@ void exit_io_context(struct task_struct *task)
        task->io_context = NULL;
        task_unlock(task);
 
-       if (atomic_dec_and_test(&ioc->nr_tasks))
-               cfq_exit(ioc);
+       atomic_dec(&ioc->nr_tasks);
+       put_io_context(ioc, NULL);
+}
+
+/**
+ * ioc_clear_queue - break any ioc association with the specified queue
+ * @q: request_queue being cleared
+ *
+ * Walk @q->icq_list and exit all io_cq's.  Must be called with @q locked.
+ */
+void ioc_clear_queue(struct request_queue *q)
+{
+       lockdep_assert_held(q->queue_lock);
+
+       while (!list_empty(&q->icq_list)) {
+               struct io_cq *icq = list_entry(q->icq_list.next,
+                                              struct io_cq, q_node);
+               struct io_context *ioc = icq->ioc;
 
-       put_io_context(ioc);
+               spin_lock(&ioc->lock);
+               ioc_exit_icq(icq);
+               spin_unlock(&ioc->lock);
+       }
 }
 
-struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
+void create_io_context_slowpath(struct task_struct *task, gfp_t gfp_flags,
+                               int node)
 {
        struct io_context *ioc;
 
-       ioc = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node);
-       if (ioc) {
-               atomic_long_set(&ioc->refcount, 1);
-               atomic_set(&ioc->nr_tasks, 1);
-               spin_lock_init(&ioc->lock);
-               ioc->ioprio_changed = 0;
-               ioc->ioprio = 0;
-               ioc->last_waited = 0; /* doesn't matter... */
-               ioc->nr_batch_requests = 0; /* because this is 0 */
-               INIT_RADIX_TREE(&ioc->radix_root, GFP_ATOMIC | __GFP_HIGH);
-               INIT_HLIST_HEAD(&ioc->cic_list);
-               ioc->ioc_data = NULL;
-#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE)
-               ioc->cgroup_changed = 0;
-#endif
-       }
+       ioc = kmem_cache_alloc_node(iocontext_cachep, gfp_flags | __GFP_ZERO,
+                                   node);
+       if (unlikely(!ioc))
+               return;
 
-       return ioc;
+       /* initialize */
+       atomic_long_set(&ioc->refcount, 1);
+       atomic_set(&ioc->nr_tasks, 1);
+       spin_lock_init(&ioc->lock);
+       INIT_RADIX_TREE(&ioc->icq_tree, GFP_ATOMIC | __GFP_HIGH);
+       INIT_HLIST_HEAD(&ioc->icq_list);
+       INIT_WORK(&ioc->release_work, ioc_release_fn);
+
+       /*
+        * Try to install.  ioc shouldn't be installed if someone else
+        * already did or @task, which isn't %current, is exiting.  Note
+        * that we need to allow ioc creation on exiting %current as exit
+        * path may issue IOs from e.g. exit_files().  The exit path is
+        * responsible for not issuing IO after exit_io_context().
+        */
+       task_lock(task);
+       if (!task->io_context &&
+           (task == current || !(task->flags & PF_EXITING)))
+               task->io_context = ioc;
+       else
+               kmem_cache_free(iocontext_cachep, ioc);
+       task_unlock(task);
 }
 
-/*
- * If the current task has no IO context then create one and initialise it.
- * Otherwise, return its existing IO context.
+/**
+ * get_task_io_context - get io_context of a task
+ * @task: task of interest
+ * @gfp_flags: allocation flags, used if allocation is necessary
+ * @node: allocation node, used if allocation is necessary
  *
- * This returned IO context doesn't have a specifically elevated refcount,
- * but since the current task itself holds a reference, the context can be
- * used in general code, so long as it stays within `current` context.
+ * Return io_context of @task.  If it doesn't exist, it is created with
+ * @gfp_flags and @node.  The returned io_context has its reference count
+ * incremented.
+ *
+ * This function always goes through task_lock() and it's better to use
+ * %current->io_context + get_io_context() for %current.
  */
-struct io_context *current_io_context(gfp_t gfp_flags, int node)
+struct io_context *get_task_io_context(struct task_struct *task,
+                                      gfp_t gfp_flags, int node)
 {
-       struct task_struct *tsk = current;
-       struct io_context *ret;
-
-       ret = tsk->io_context;
-       if (likely(ret))
-               return ret;
-
-       ret = alloc_io_context(gfp_flags, node);
-       if (ret) {
-               /* make sure set_task_ioprio() sees the settings above */
-               smp_wmb();
-               tsk->io_context = ret;
-       }
+       struct io_context *ioc;
 
-       return ret;
+       might_sleep_if(gfp_flags & __GFP_WAIT);
+
+       do {
+               task_lock(task);
+               ioc = task->io_context;
+               if (likely(ioc)) {
+                       get_io_context(ioc);
+                       task_unlock(task);
+                       return ioc;
+               }
+               task_unlock(task);
+       } while (create_io_context(task, gfp_flags, node));
+
+       return NULL;
 }
+EXPORT_SYMBOL(get_task_io_context);
 
-/*
- * If the current task has no IO context then create one and initialise it.
- * If it does have a context, take a ref on it.
+/**
+ * ioc_lookup_icq - lookup io_cq from ioc
+ * @ioc: the associated io_context
+ * @q: the associated request_queue
  *
- * This is always called in the context of the task which submitted the I/O.
+ * Look up io_cq associated with @ioc - @q pair from @ioc.  Must be called
+ * with @q->queue_lock held.
  */
-struct io_context *get_io_context(gfp_t gfp_flags, int node)
+struct io_cq *ioc_lookup_icq(struct io_context *ioc, struct request_queue *q)
 {
-       struct io_context *ioc = NULL;
+       struct io_cq *icq;
+
+       lockdep_assert_held(q->queue_lock);
 
        /*
-        * Check for unlikely race with exiting task. ioc ref count is
-        * zero when ioc is being detached.
+        * icq's are indexed from @ioc using radix tree and hint pointer,
+        * both of which are protected with RCU.  All removals are done
+        * holding both q and ioc locks, and we're holding q lock - if we
+        * find a icq which points to us, it's guaranteed to be valid.
         */
-       do {
-               ioc = current_io_context(gfp_flags, node);
-               if (unlikely(!ioc))
-                       break;
-       } while (!atomic_long_inc_not_zero(&ioc->refcount));
+       rcu_read_lock();
+       icq = rcu_dereference(ioc->icq_hint);
+       if (icq && icq->q == q)
+               goto out;
 
-       return ioc;
+       icq = radix_tree_lookup(&ioc->icq_tree, q->id);
+       if (icq && icq->q == q)
+               rcu_assign_pointer(ioc->icq_hint, icq); /* allowed to race */
+       else
+               icq = NULL;
+out:
+       rcu_read_unlock();
+       return icq;
 }
-EXPORT_SYMBOL(get_io_context);
+EXPORT_SYMBOL(ioc_lookup_icq);
+
+/**
+ * ioc_create_icq - create and link io_cq
+ * @q: request_queue of interest
+ * @gfp_mask: allocation mask
+ *
+ * Make sure io_cq linking %current->io_context and @q exists.  If either
+ * io_context and/or icq don't exist, they will be created using @gfp_mask.
+ *
+ * The caller is responsible for ensuring @ioc won't go away and @q is
+ * alive and will stay alive until this function returns.
+ */
+struct io_cq *ioc_create_icq(struct request_queue *q, gfp_t gfp_mask)
+{
+       struct elevator_type *et = q->elevator->type;
+       struct io_context *ioc;
+       struct io_cq *icq;
+
+       /* allocate stuff */
+       ioc = create_io_context(current, gfp_mask, q->node);
+       if (!ioc)
+               return NULL;
+
+       icq = kmem_cache_alloc_node(et->icq_cache, gfp_mask | __GFP_ZERO,
+                                   q->node);
+       if (!icq)
+               return NULL;
+
+       if (radix_tree_preload(gfp_mask) < 0) {
+               kmem_cache_free(et->icq_cache, icq);
+               return NULL;
+       }
+
+       icq->ioc = ioc;
+       icq->q = q;
+       INIT_LIST_HEAD(&icq->q_node);
+       INIT_HLIST_NODE(&icq->ioc_node);
+
+       /* lock both q and ioc and try to link @icq */
+       spin_lock_irq(q->queue_lock);
+       spin_lock(&ioc->lock);
+
+       if (likely(!radix_tree_insert(&ioc->icq_tree, q->id, icq))) {
+               hlist_add_head(&icq->ioc_node, &ioc->icq_list);
+               list_add(&icq->q_node, &q->icq_list);
+               if (et->ops.elevator_init_icq_fn)
+                       et->ops.elevator_init_icq_fn(icq);
+       } else {
+               kmem_cache_free(et->icq_cache, icq);
+               icq = ioc_lookup_icq(ioc, q);
+               if (!icq)
+                       printk(KERN_ERR "cfq: icq link failed!\n");
+       }
+
+       spin_unlock(&ioc->lock);
+       spin_unlock_irq(q->queue_lock);
+       radix_tree_preload_end();
+       return icq;
+}
+
+void ioc_set_changed(struct io_context *ioc, int which)
+{
+       struct io_cq *icq;
+       struct hlist_node *n;
+
+       hlist_for_each_entry(icq, n, &ioc->icq_list, ioc_node)
+               set_bit(which, &icq->changed);
+}
+
+/**
+ * ioc_ioprio_changed - notify ioprio change
+ * @ioc: io_context of interest
+ * @ioprio: new ioprio
+ *
+ * @ioc's ioprio has changed to @ioprio.  Set %ICQ_IOPRIO_CHANGED for all
+ * icq's.  iosched is responsible for checking the bit and applying it on
+ * request issue path.
+ */
+void ioc_ioprio_changed(struct io_context *ioc, int ioprio)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->lock, flags);
+       ioc->ioprio = ioprio;
+       ioc_set_changed(ioc, ICQ_IOPRIO_CHANGED);
+       spin_unlock_irqrestore(&ioc->lock, flags);
+}
+
+/**
+ * ioc_cgroup_changed - notify cgroup change
+ * @ioc: io_context of interest
+ *
+ * @ioc's cgroup has changed.  Set %ICQ_CGROUP_CHANGED for all icq's.
+ * iosched is responsible for checking the bit and applying it on request
+ * issue path.
+ */
+void ioc_cgroup_changed(struct io_context *ioc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioc->lock, flags);
+       ioc_set_changed(ioc, ICQ_CGROUP_CHANGED);
+       spin_unlock_irqrestore(&ioc->lock, flags);
+}
+EXPORT_SYMBOL(ioc_cgroup_changed);
 
 static int __init blk_ioc_init(void)
 {
index fa1eb0449a05f0db45de3ab8e6a01a2fc2a95238..d3234fc494adcd48ff1dd69c9feb117e93e333c0 100644 (file)
@@ -104,9 +104,7 @@ EXPORT_SYMBOL_GPL(blk_queue_lld_busy);
  * @lim:  the queue_limits structure to reset
  *
  * Description:
- *   Returns a queue_limit struct to its default state.  Can be used by
- *   stacking drivers like DM that stage table swaps and reuse an
- *   existing device queue.
+ *   Returns a queue_limit struct to its default state.
  */
 void blk_set_default_limits(struct queue_limits *lim)
 {
@@ -114,13 +112,12 @@ void blk_set_default_limits(struct queue_limits *lim)
        lim->max_integrity_segments = 0;
        lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
        lim->max_segment_size = BLK_MAX_SEGMENT_SIZE;
-       lim->max_sectors = BLK_DEF_MAX_SECTORS;
-       lim->max_hw_sectors = INT_MAX;
+       lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS;
        lim->max_discard_sectors = 0;
        lim->discard_granularity = 0;
        lim->discard_alignment = 0;
        lim->discard_misaligned = 0;
-       lim->discard_zeroes_data = 1;
+       lim->discard_zeroes_data = 0;
        lim->logical_block_size = lim->physical_block_size = lim->io_min = 512;
        lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT);
        lim->alignment_offset = 0;
@@ -130,6 +127,27 @@ void blk_set_default_limits(struct queue_limits *lim)
 }
 EXPORT_SYMBOL(blk_set_default_limits);
 
+/**
+ * blk_set_stacking_limits - set default limits for stacking devices
+ * @lim:  the queue_limits structure to reset
+ *
+ * Description:
+ *   Returns a queue_limit struct to its default state. Should be used
+ *   by stacking drivers like DM that have no internal limits.
+ */
+void blk_set_stacking_limits(struct queue_limits *lim)
+{
+       blk_set_default_limits(lim);
+
+       /* Inherit limits from component devices */
+       lim->discard_zeroes_data = 1;
+       lim->max_segments = USHRT_MAX;
+       lim->max_hw_sectors = UINT_MAX;
+
+       lim->max_sectors = BLK_DEF_MAX_SECTORS;
+}
+EXPORT_SYMBOL(blk_set_stacking_limits);
+
 /**
  * blk_queue_make_request - define an alternate make_request function for a device
  * @q:  the request queue for the device to be affected
@@ -165,8 +183,6 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
        q->nr_batching = BLK_BATCH_REQ;
 
        blk_set_default_limits(&q->limits);
-       blk_queue_max_hw_sectors(q, BLK_SAFE_MAX_SECTORS);
-       q->limits.discard_zeroes_data = 0;
 
        /*
         * by default assume old behaviour and bounce for any highmem page
index e7f9f657f10563216be47d8e30ff93acbf4fa312..cf150011d808bc71fee8ff894387de0581235f56 100644 (file)
@@ -425,7 +425,7 @@ queue_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
        if (!entry->show)
                return -EIO;
        mutex_lock(&q->sysfs_lock);
-       if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)) {
+       if (blk_queue_dead(q)) {
                mutex_unlock(&q->sysfs_lock);
                return -ENOENT;
        }
@@ -447,7 +447,7 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr,
 
        q = container_of(kobj, struct request_queue, kobj);
        mutex_lock(&q->sysfs_lock);
-       if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)) {
+       if (blk_queue_dead(q)) {
                mutex_unlock(&q->sysfs_lock);
                return -ENOENT;
        }
@@ -479,8 +479,12 @@ static void blk_release_queue(struct kobject *kobj)
 
        blk_sync_queue(q);
 
-       if (q->elevator)
+       if (q->elevator) {
+               spin_lock_irq(q->queue_lock);
+               ioc_clear_queue(q);
+               spin_unlock_irq(q->queue_lock);
                elevator_exit(q->elevator);
+       }
 
        blk_throtl_exit(q);
 
@@ -494,6 +498,8 @@ static void blk_release_queue(struct kobject *kobj)
        blk_trace_shutdown(q);
 
        bdi_destroy(&q->backing_dev_info);
+
+       ida_simple_remove(&blk_queue_ida, q->id);
        kmem_cache_free(blk_requestq_cachep, q);
 }
 
index 4553245d93175bc34ddd83966e640161ca81e89f..5eed6a76721d1d78e8105f4bbde30e41f20a66cd 100644 (file)
@@ -310,7 +310,7 @@ static struct throtl_grp * throtl_get_tg(struct throtl_data *td)
        struct request_queue *q = td->queue;
 
        /* no throttling for dead queue */
-       if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)))
+       if (unlikely(blk_queue_dead(q)))
                return NULL;
 
        rcu_read_lock();
@@ -335,7 +335,7 @@ static struct throtl_grp * throtl_get_tg(struct throtl_data *td)
        spin_lock_irq(q->queue_lock);
 
        /* Make sure @q is still alive */
-       if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) {
+       if (unlikely(blk_queue_dead(q))) {
                kfree(tg);
                return NULL;
        }
index 3f6551b3c92d7fa14edc1b1d85c1ef500561e789..7efd772336de998be8c53b01a1805ae63069de62 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef BLK_INTERNAL_H
 #define BLK_INTERNAL_H
 
+#include <linux/idr.h>
+
 /* Amount of time in which a process may batch requests */
 #define BLK_BATCH_TIME (HZ/50UL)
 
@@ -9,6 +11,12 @@
 
 extern struct kmem_cache *blk_requestq_cachep;
 extern struct kobj_type blk_queue_ktype;
+extern struct ida blk_queue_ida;
+
+static inline void __blk_get_queue(struct request_queue *q)
+{
+       kobject_get(&q->kobj);
+}
 
 void init_request_from_bio(struct request *req, struct bio *bio);
 void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
@@ -85,8 +93,8 @@ static inline struct request *__elv_next_request(struct request_queue *q)
                        q->flush_queue_delayed = 1;
                        return NULL;
                }
-               if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags) ||
-                   !q->elevator->ops->elevator_dispatch_fn(q, 0))
+               if (unlikely(blk_queue_dead(q)) ||
+                   !q->elevator->type->ops.elevator_dispatch_fn(q, 0))
                        return NULL;
        }
 }
@@ -95,16 +103,16 @@ static inline void elv_activate_rq(struct request_queue *q, struct request *rq)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->ops->elevator_activate_req_fn)
-               e->ops->elevator_activate_req_fn(q, rq);
+       if (e->type->ops.elevator_activate_req_fn)
+               e->type->ops.elevator_activate_req_fn(q, rq);
 }
 
 static inline void elv_deactivate_rq(struct request_queue *q, struct request *rq)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->ops->elevator_deactivate_req_fn)
-               e->ops->elevator_deactivate_req_fn(q, rq);
+       if (e->type->ops.elevator_deactivate_req_fn)
+               e->type->ops.elevator_deactivate_req_fn(q, rq);
 }
 
 #ifdef CONFIG_FAIL_IO_TIMEOUT
@@ -119,8 +127,6 @@ static inline int blk_should_fake_timeout(struct request_queue *q)
 }
 #endif
 
-struct io_context *current_io_context(gfp_t gfp_flags, int node);
-
 int ll_back_merge_fn(struct request_queue *q, struct request *req,
                     struct bio *bio);
 int ll_front_merge_fn(struct request_queue *q, struct request *req, 
@@ -189,6 +195,42 @@ static inline int blk_do_io_stat(struct request *rq)
                (rq->cmd_flags & REQ_DISCARD));
 }
 
+/*
+ * Internal io_context interface
+ */
+void get_io_context(struct io_context *ioc);
+struct io_cq *ioc_lookup_icq(struct io_context *ioc, struct request_queue *q);
+struct io_cq *ioc_create_icq(struct request_queue *q, gfp_t gfp_mask);
+void ioc_clear_queue(struct request_queue *q);
+
+void create_io_context_slowpath(struct task_struct *task, gfp_t gfp_mask,
+                               int node);
+
+/**
+ * create_io_context - try to create task->io_context
+ * @task: target task
+ * @gfp_mask: allocation mask
+ * @node: allocation node
+ *
+ * If @task->io_context is %NULL, allocate a new io_context and install it.
+ * Returns the current @task->io_context which may be %NULL if allocation
+ * failed.
+ *
+ * Note that this function can't be called with IRQ disabled because
+ * task_lock which protects @task->io_context is IRQ-unsafe.
+ */
+static inline struct io_context *create_io_context(struct task_struct *task,
+                                                  gfp_t gfp_mask, int node)
+{
+       WARN_ON_ONCE(irqs_disabled());
+       if (unlikely(!task->io_context))
+               create_io_context_slowpath(task, gfp_mask, node);
+       return task->io_context;
+}
+
+/*
+ * Internal throttling interface
+ */
 #ifdef CONFIG_BLK_DEV_THROTTLING
 extern bool blk_throtl_bio(struct request_queue *q, struct bio *bio);
 extern void blk_throtl_drain(struct request_queue *q);
index 9651ec7b87c22f1a14b9f5cbdad073006de222d1..4cf703fd98bb8916fe74ae3b42d4856958d57950 100644 (file)
@@ -769,12 +769,10 @@ static struct bsg_device *bsg_add_device(struct inode *inode,
                                         struct file *file)
 {
        struct bsg_device *bd;
-       int ret;
 #ifdef BSG_DEBUG
        unsigned char buf[32];
 #endif
-       ret = blk_get_queue(rq);
-       if (ret)
+       if (!blk_get_queue(rq))
                return ERR_PTR(-ENXIO);
 
        bd = bsg_alloc_device();
index 3548705b04e482a4405097217011256105c4bdca..ee55019066a19500c6df54addf90d91d2ace60fa 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/rbtree.h>
 #include <linux/ioprio.h>
 #include <linux/blktrace_api.h>
+#include "blk.h"
 #include "cfq.h"
 
 /*
@@ -53,20 +54,11 @@ static const int cfq_hist_divisor = 4;
 #define CFQQ_SECT_THR_NONROT   (sector_t)(2 * 32)
 #define CFQQ_SEEKY(cfqq)       (hweight32(cfqq->seek_history) > 32/8)
 
-#define RQ_CIC(rq)             \
-       ((struct cfq_io_context *) (rq)->elevator_private[0])
-#define RQ_CFQQ(rq)            (struct cfq_queue *) ((rq)->elevator_private[1])
-#define RQ_CFQG(rq)            (struct cfq_group *) ((rq)->elevator_private[2])
+#define RQ_CIC(rq)             icq_to_cic((rq)->elv.icq)
+#define RQ_CFQQ(rq)            (struct cfq_queue *) ((rq)->elv.priv[0])
+#define RQ_CFQG(rq)            (struct cfq_group *) ((rq)->elv.priv[1])
 
 static struct kmem_cache *cfq_pool;
-static struct kmem_cache *cfq_ioc_pool;
-
-static DEFINE_PER_CPU(unsigned long, cfq_ioc_count);
-static struct completion *ioc_gone;
-static DEFINE_SPINLOCK(ioc_gone_lock);
-
-static DEFINE_SPINLOCK(cic_index_lock);
-static DEFINE_IDA(cic_index_ida);
 
 #define CFQ_PRIO_LISTS         IOPRIO_BE_NR
 #define cfq_class_idle(cfqq)   ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
@@ -75,6 +67,14 @@ static DEFINE_IDA(cic_index_ida);
 #define sample_valid(samples)  ((samples) > 80)
 #define rb_entry_cfqg(node)    rb_entry((node), struct cfq_group, rb_node)
 
+struct cfq_ttime {
+       unsigned long last_end_request;
+
+       unsigned long ttime_total;
+       unsigned long ttime_samples;
+       unsigned long ttime_mean;
+};
+
 /*
  * Most of our rbtree usage is for sorting with min extraction, so
  * if we cache the leftmost node we don't have to walk down the tree
@@ -216,6 +216,12 @@ struct cfq_group {
        struct cfq_ttime ttime;
 };
 
+struct cfq_io_cq {
+       struct io_cq            icq;            /* must be the first member */
+       struct cfq_queue        *cfqq[2];
+       struct cfq_ttime        ttime;
+};
+
 /*
  * Per block device queue structure
  */
@@ -267,7 +273,7 @@ struct cfq_data {
        struct work_struct unplug_work;
 
        struct cfq_queue *active_queue;
-       struct cfq_io_context *active_cic;
+       struct cfq_io_cq *active_cic;
 
        /*
         * async queue for each priority case
@@ -290,9 +296,6 @@ struct cfq_data {
        unsigned int cfq_group_idle;
        unsigned int cfq_latency;
 
-       unsigned int cic_index;
-       struct list_head cic_list;
-
        /*
         * Fallback dummy cfqq for extreme OOM conditions
         */
@@ -464,37 +467,35 @@ static inline int cfqg_busy_async_queues(struct cfq_data *cfqd,
 static void cfq_dispatch_insert(struct request_queue *, struct request *);
 static struct cfq_queue *cfq_get_queue(struct cfq_data *, bool,
                                       struct io_context *, gfp_t);
-static struct cfq_io_context *cfq_cic_lookup(struct cfq_data *,
-                                               struct io_context *);
 
-static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic,
-                                           bool is_sync)
+static inline struct cfq_io_cq *icq_to_cic(struct io_cq *icq)
 {
-       return cic->cfqq[is_sync];
+       /* cic->icq is the first member, %NULL will convert to %NULL */
+       return container_of(icq, struct cfq_io_cq, icq);
 }
 
-static inline void cic_set_cfqq(struct cfq_io_context *cic,
-                               struct cfq_queue *cfqq, bool is_sync)
+static inline struct cfq_io_cq *cfq_cic_lookup(struct cfq_data *cfqd,
+                                              struct io_context *ioc)
 {
-       cic->cfqq[is_sync] = cfqq;
+       if (ioc)
+               return icq_to_cic(ioc_lookup_icq(ioc, cfqd->queue));
+       return NULL;
 }
 
-#define CIC_DEAD_KEY   1ul
-#define CIC_DEAD_INDEX_SHIFT   1
-
-static inline void *cfqd_dead_key(struct cfq_data *cfqd)
+static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_cq *cic, bool is_sync)
 {
-       return (void *)(cfqd->cic_index << CIC_DEAD_INDEX_SHIFT | CIC_DEAD_KEY);
+       return cic->cfqq[is_sync];
 }
 
-static inline struct cfq_data *cic_to_cfqd(struct cfq_io_context *cic)
+static inline void cic_set_cfqq(struct cfq_io_cq *cic, struct cfq_queue *cfqq,
+                               bool is_sync)
 {
-       struct cfq_data *cfqd = cic->key;
-
-       if (unlikely((unsigned long) cfqd & CIC_DEAD_KEY))
-               return NULL;
+       cic->cfqq[is_sync] = cfqq;
+}
 
-       return cfqd;
+static inline struct cfq_data *cic_to_cfqd(struct cfq_io_cq *cic)
+{
+       return cic->icq.q->elevator->elevator_data;
 }
 
 /*
@@ -1561,7 +1562,7 @@ static struct request *
 cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
 {
        struct task_struct *tsk = current;
-       struct cfq_io_context *cic;
+       struct cfq_io_cq *cic;
        struct cfq_queue *cfqq;
 
        cic = cfq_cic_lookup(cfqd, tsk->io_context);
@@ -1687,7 +1688,7 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
                           struct bio *bio)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
-       struct cfq_io_context *cic;
+       struct cfq_io_cq *cic;
        struct cfq_queue *cfqq;
 
        /*
@@ -1697,12 +1698,19 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
                return false;
 
        /*
-        * Lookup the cfqq that this bio will be queued with. Allow
-        * merge only if rq is queued there.
+        * Lookup the cfqq that this bio will be queued with and allow
+        * merge only if rq is queued there.  This function can be called
+        * from plug merge without queue_lock.  In such cases, ioc of @rq
+        * and %current are guaranteed to be equal.  Avoid lookup which
+        * requires queue_lock by using @rq's cic.
         */
-       cic = cfq_cic_lookup(cfqd, current->io_context);
-       if (!cic)
-               return false;
+       if (current->io_context == RQ_CIC(rq)->icq.ioc) {
+               cic = RQ_CIC(rq);
+       } else {
+               cic = cfq_cic_lookup(cfqd, current->io_context);
+               if (!cic)
+                       return false;
+       }
 
        cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
        return cfqq == RQ_CFQQ(rq);
@@ -1786,7 +1794,7 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                cfqd->active_queue = NULL;
 
        if (cfqd->active_cic) {
-               put_io_context(cfqd->active_cic->ioc);
+               put_io_context(cfqd->active_cic->icq.ioc, cfqd->queue);
                cfqd->active_cic = NULL;
        }
 }
@@ -2006,7 +2014,7 @@ static bool cfq_should_idle(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 static void cfq_arm_slice_timer(struct cfq_data *cfqd)
 {
        struct cfq_queue *cfqq = cfqd->active_queue;
-       struct cfq_io_context *cic;
+       struct cfq_io_cq *cic;
        unsigned long sl, group_idle = 0;
 
        /*
@@ -2041,7 +2049,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
         * task has exited, don't wait
         */
        cic = cfqd->active_cic;
-       if (!cic || !atomic_read(&cic->ioc->nr_tasks))
+       if (!cic || !atomic_read(&cic->icq.ioc->nr_tasks))
                return;
 
        /*
@@ -2592,9 +2600,9 @@ static bool cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq)
        cfq_dispatch_insert(cfqd->queue, rq);
 
        if (!cfqd->active_cic) {
-               struct cfq_io_context *cic = RQ_CIC(rq);
+               struct cfq_io_cq *cic = RQ_CIC(rq);
 
-               atomic_long_inc(&cic->ioc->refcount);
+               atomic_long_inc(&cic->icq.ioc->refcount);
                cfqd->active_cic = cic;
        }
 
@@ -2677,84 +2685,6 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
        cfq_put_cfqg(cfqg);
 }
 
-/*
- * Call func for each cic attached to this ioc.
- */
-static void
-call_for_each_cic(struct io_context *ioc,
-                 void (*func)(struct io_context *, struct cfq_io_context *))
-{
-       struct cfq_io_context *cic;
-       struct hlist_node *n;
-
-       rcu_read_lock();
-
-       hlist_for_each_entry_rcu(cic, n, &ioc->cic_list, cic_list)
-               func(ioc, cic);
-
-       rcu_read_unlock();
-}
-
-static void cfq_cic_free_rcu(struct rcu_head *head)
-{
-       struct cfq_io_context *cic;
-
-       cic = container_of(head, struct cfq_io_context, rcu_head);
-
-       kmem_cache_free(cfq_ioc_pool, cic);
-       elv_ioc_count_dec(cfq_ioc_count);
-
-       if (ioc_gone) {
-               /*
-                * CFQ scheduler is exiting, grab exit lock and check
-                * the pending io context count. If it hits zero,
-                * complete ioc_gone and set it back to NULL
-                */
-               spin_lock(&ioc_gone_lock);
-               if (ioc_gone && !elv_ioc_count_read(cfq_ioc_count)) {
-                       complete(ioc_gone);
-                       ioc_gone = NULL;
-               }
-               spin_unlock(&ioc_gone_lock);
-       }
-}
-
-static void cfq_cic_free(struct cfq_io_context *cic)
-{
-       call_rcu(&cic->rcu_head, cfq_cic_free_rcu);
-}
-
-static void cic_free_func(struct io_context *ioc, struct cfq_io_context *cic)
-{
-       unsigned long flags;
-       unsigned long dead_key = (unsigned long) cic->key;
-
-       BUG_ON(!(dead_key & CIC_DEAD_KEY));
-
-       spin_lock_irqsave(&ioc->lock, flags);
-       radix_tree_delete(&ioc->radix_root, dead_key >> CIC_DEAD_INDEX_SHIFT);
-       hlist_del_rcu(&cic->cic_list);
-       spin_unlock_irqrestore(&ioc->lock, flags);
-
-       cfq_cic_free(cic);
-}
-
-/*
- * Must be called with rcu_read_lock() held or preemption otherwise disabled.
- * Only two callers of this - ->dtor() which is called with the rcu_read_lock(),
- * and ->trim() which is called with the task lock held
- */
-static void cfq_free_io_context(struct io_context *ioc)
-{
-       /*
-        * ioc->refcount is zero here, or we are called from elv_unregister(),
-        * so no more cic's are allowed to be linked into this ioc.  So it
-        * should be ok to iterate over the known list, we will see all cic's
-        * since no new ones are added.
-        */
-       call_for_each_cic(ioc, cic_free_func);
-}
-
 static void cfq_put_cooperator(struct cfq_queue *cfqq)
 {
        struct cfq_queue *__cfqq, *next;
@@ -2788,27 +2718,17 @@ static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
        cfq_put_queue(cfqq);
 }
 
-static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
-                                        struct cfq_io_context *cic)
+static void cfq_init_icq(struct io_cq *icq)
 {
-       struct io_context *ioc = cic->ioc;
+       struct cfq_io_cq *cic = icq_to_cic(icq);
 
-       list_del_init(&cic->queue_list);
-
-       /*
-        * Make sure dead mark is seen for dead queues
-        */
-       smp_wmb();
-       cic->key = cfqd_dead_key(cfqd);
+       cic->ttime.last_end_request = jiffies;
+}
 
-       rcu_read_lock();
-       if (rcu_dereference(ioc->ioc_data) == cic) {
-               rcu_read_unlock();
-               spin_lock(&ioc->lock);
-               rcu_assign_pointer(ioc->ioc_data, NULL);
-               spin_unlock(&ioc->lock);
-       } else
-               rcu_read_unlock();
+static void cfq_exit_icq(struct io_cq *icq)
+{
+       struct cfq_io_cq *cic = icq_to_cic(icq);
+       struct cfq_data *cfqd = cic_to_cfqd(cic);
 
        if (cic->cfqq[BLK_RW_ASYNC]) {
                cfq_exit_cfqq(cfqd, cic->cfqq[BLK_RW_ASYNC]);
@@ -2821,57 +2741,6 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
        }
 }
 
-static void cfq_exit_single_io_context(struct io_context *ioc,
-                                      struct cfq_io_context *cic)
-{
-       struct cfq_data *cfqd = cic_to_cfqd(cic);
-
-       if (cfqd) {
-               struct request_queue *q = cfqd->queue;
-               unsigned long flags;
-
-               spin_lock_irqsave(q->queue_lock, flags);
-
-               /*
-                * Ensure we get a fresh copy of the ->key to prevent
-                * race between exiting task and queue
-                */
-               smp_read_barrier_depends();
-               if (cic->key == cfqd)
-                       __cfq_exit_single_io_context(cfqd, cic);
-
-               spin_unlock_irqrestore(q->queue_lock, flags);
-       }
-}
-
-/*
- * The process that ioc belongs to has exited, we need to clean up
- * and put the internal structures we have that belongs to that process.
- */
-static void cfq_exit_io_context(struct io_context *ioc)
-{
-       call_for_each_cic(ioc, cfq_exit_single_io_context);
-}
-
-static struct cfq_io_context *
-cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
-{
-       struct cfq_io_context *cic;
-
-       cic = kmem_cache_alloc_node(cfq_ioc_pool, gfp_mask | __GFP_ZERO,
-                                                       cfqd->queue->node);
-       if (cic) {
-               cic->ttime.last_end_request = jiffies;
-               INIT_LIST_HEAD(&cic->queue_list);
-               INIT_HLIST_NODE(&cic->cic_list);
-               cic->dtor = cfq_free_io_context;
-               cic->exit = cfq_exit_io_context;
-               elv_ioc_count_inc(cfq_ioc_count);
-       }
-
-       return cic;
-}
-
 static void cfq_init_prio_data(struct cfq_queue *cfqq, struct io_context *ioc)
 {
        struct task_struct *tsk = current;
@@ -2914,21 +2783,18 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq, struct io_context *ioc)
        cfq_clear_cfqq_prio_changed(cfqq);
 }
 
-static void changed_ioprio(struct io_context *ioc, struct cfq_io_context *cic)
+static void changed_ioprio(struct cfq_io_cq *cic)
 {
        struct cfq_data *cfqd = cic_to_cfqd(cic);
        struct cfq_queue *cfqq;
-       unsigned long flags;
 
        if (unlikely(!cfqd))
                return;
 
-       spin_lock_irqsave(cfqd->queue->queue_lock, flags);
-
        cfqq = cic->cfqq[BLK_RW_ASYNC];
        if (cfqq) {
                struct cfq_queue *new_cfqq;
-               new_cfqq = cfq_get_queue(cfqd, BLK_RW_ASYNC, cic->ioc,
+               new_cfqq = cfq_get_queue(cfqd, BLK_RW_ASYNC, cic->icq.ioc,
                                                GFP_ATOMIC);
                if (new_cfqq) {
                        cic->cfqq[BLK_RW_ASYNC] = new_cfqq;
@@ -2939,14 +2805,6 @@ static void changed_ioprio(struct io_context *ioc, struct cfq_io_context *cic)
        cfqq = cic->cfqq[BLK_RW_SYNC];
        if (cfqq)
                cfq_mark_cfqq_prio_changed(cfqq);
-
-       spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
-}
-
-static void cfq_ioc_set_ioprio(struct io_context *ioc)
-{
-       call_for_each_cic(ioc, changed_ioprio);
-       ioc->ioprio_changed = 0;
 }
 
 static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
@@ -2970,11 +2828,10 @@ static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
 }
 
 #ifdef CONFIG_CFQ_GROUP_IOSCHED
-static void changed_cgroup(struct io_context *ioc, struct cfq_io_context *cic)
+static void changed_cgroup(struct cfq_io_cq *cic)
 {
        struct cfq_queue *sync_cfqq = cic_to_cfqq(cic, 1);
        struct cfq_data *cfqd = cic_to_cfqd(cic);
-       unsigned long flags;
        struct request_queue *q;
 
        if (unlikely(!cfqd))
@@ -2982,8 +2839,6 @@ static void changed_cgroup(struct io_context *ioc, struct cfq_io_context *cic)
 
        q = cfqd->queue;
 
-       spin_lock_irqsave(q->queue_lock, flags);
-
        if (sync_cfqq) {
                /*
                 * Drop reference to sync queue. A new sync queue will be
@@ -2993,14 +2848,6 @@ static void changed_cgroup(struct io_context *ioc, struct cfq_io_context *cic)
                cic_set_cfqq(cic, NULL, 1);
                cfq_put_queue(sync_cfqq);
        }
-
-       spin_unlock_irqrestore(q->queue_lock, flags);
-}
-
-static void cfq_ioc_set_cgroup(struct io_context *ioc)
-{
-       call_for_each_cic(ioc, changed_cgroup);
-       ioc->cgroup_changed = 0;
 }
 #endif  /* CONFIG_CFQ_GROUP_IOSCHED */
 
@@ -3009,7 +2856,7 @@ cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync,
                     struct io_context *ioc, gfp_t gfp_mask)
 {
        struct cfq_queue *cfqq, *new_cfqq = NULL;
-       struct cfq_io_context *cic;
+       struct cfq_io_cq *cic;
        struct cfq_group *cfqg;
 
 retry:
@@ -3100,160 +2947,6 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct io_context *ioc,
        return cfqq;
 }
 
-/*
- * We drop cfq io contexts lazily, so we may find a dead one.
- */
-static void
-cfq_drop_dead_cic(struct cfq_data *cfqd, struct io_context *ioc,
-                 struct cfq_io_context *cic)
-{
-       unsigned long flags;
-
-       WARN_ON(!list_empty(&cic->queue_list));
-       BUG_ON(cic->key != cfqd_dead_key(cfqd));
-
-       spin_lock_irqsave(&ioc->lock, flags);
-
-       BUG_ON(rcu_dereference_check(ioc->ioc_data,
-               lockdep_is_held(&ioc->lock)) == cic);
-
-       radix_tree_delete(&ioc->radix_root, cfqd->cic_index);
-       hlist_del_rcu(&cic->cic_list);
-       spin_unlock_irqrestore(&ioc->lock, flags);
-
-       cfq_cic_free(cic);
-}
-
-static struct cfq_io_context *
-cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc)
-{
-       struct cfq_io_context *cic;
-       unsigned long flags;
-
-       if (unlikely(!ioc))
-               return NULL;
-
-       rcu_read_lock();
-
-       /*
-        * we maintain a last-hit cache, to avoid browsing over the tree
-        */
-       cic = rcu_dereference(ioc->ioc_data);
-       if (cic && cic->key == cfqd) {
-               rcu_read_unlock();
-               return cic;
-       }
-
-       do {
-               cic = radix_tree_lookup(&ioc->radix_root, cfqd->cic_index);
-               rcu_read_unlock();
-               if (!cic)
-                       break;
-               if (unlikely(cic->key != cfqd)) {
-                       cfq_drop_dead_cic(cfqd, ioc, cic);
-                       rcu_read_lock();
-                       continue;
-               }
-
-               spin_lock_irqsave(&ioc->lock, flags);
-               rcu_assign_pointer(ioc->ioc_data, cic);
-               spin_unlock_irqrestore(&ioc->lock, flags);
-               break;
-       } while (1);
-
-       return cic;
-}
-
-/*
- * Add cic into ioc, using cfqd as the search key. This enables us to lookup
- * the process specific cfq io context when entered from the block layer.
- * Also adds the cic to a per-cfqd list, used when this queue is removed.
- */
-static int cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc,
-                       struct cfq_io_context *cic, gfp_t gfp_mask)
-{
-       unsigned long flags;
-       int ret;
-
-       ret = radix_tree_preload(gfp_mask);
-       if (!ret) {
-               cic->ioc = ioc;
-               cic->key = cfqd;
-
-               spin_lock_irqsave(&ioc->lock, flags);
-               ret = radix_tree_insert(&ioc->radix_root,
-                                               cfqd->cic_index, cic);
-               if (!ret)
-                       hlist_add_head_rcu(&cic->cic_list, &ioc->cic_list);
-               spin_unlock_irqrestore(&ioc->lock, flags);
-
-               radix_tree_preload_end();
-
-               if (!ret) {
-                       spin_lock_irqsave(cfqd->queue->queue_lock, flags);
-                       list_add(&cic->queue_list, &cfqd->cic_list);
-                       spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
-               }
-       }
-
-       if (ret && ret != -EEXIST)
-               printk(KERN_ERR "cfq: cic link failed!\n");
-
-       return ret;
-}
-
-/*
- * Setup general io context and cfq io context. There can be several cfq
- * io contexts per general io context, if this process is doing io to more
- * than one device managed by cfq.
- */
-static struct cfq_io_context *
-cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
-{
-       struct io_context *ioc = NULL;
-       struct cfq_io_context *cic;
-       int ret;
-
-       might_sleep_if(gfp_mask & __GFP_WAIT);
-
-       ioc = get_io_context(gfp_mask, cfqd->queue->node);
-       if (!ioc)
-               return NULL;
-
-retry:
-       cic = cfq_cic_lookup(cfqd, ioc);
-       if (cic)
-               goto out;
-
-       cic = cfq_alloc_io_context(cfqd, gfp_mask);
-       if (cic == NULL)
-               goto err;
-
-       ret = cfq_cic_link(cfqd, ioc, cic, gfp_mask);
-       if (ret == -EEXIST) {
-               /* someone has linked cic to ioc already */
-               cfq_cic_free(cic);
-               goto retry;
-       } else if (ret)
-               goto err_free;
-
-out:
-       smp_read_barrier_depends();
-       if (unlikely(ioc->ioprio_changed))
-               cfq_ioc_set_ioprio(ioc);
-
-#ifdef CONFIG_CFQ_GROUP_IOSCHED
-       if (unlikely(ioc->cgroup_changed))
-               cfq_ioc_set_cgroup(ioc);
-#endif
-       return cic;
-err_free:
-       cfq_cic_free(cic);
-err:
-       put_io_context(ioc);
-       return NULL;
-}
-
 static void
 __cfq_update_io_thinktime(struct cfq_ttime *ttime, unsigned long slice_idle)
 {
@@ -3267,7 +2960,7 @@ __cfq_update_io_thinktime(struct cfq_ttime *ttime, unsigned long slice_idle)
 
 static void
 cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_queue *cfqq,
-       struct cfq_io_context *cic)
+                       struct cfq_io_cq *cic)
 {
        if (cfq_cfqq_sync(cfqq)) {
                __cfq_update_io_thinktime(&cic->ttime, cfqd->cfq_slice_idle);
@@ -3305,7 +2998,7 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_queue *cfqq,
  */
 static void
 cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
-                      struct cfq_io_context *cic)
+                      struct cfq_io_cq *cic)
 {
        int old_idle, enable_idle;
 
@@ -3322,8 +3015,9 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
 
        if (cfqq->next_rq && (cfqq->next_rq->cmd_flags & REQ_NOIDLE))
                enable_idle = 0;
-       else if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle ||
-           (!cfq_cfqq_deep(cfqq) && CFQQ_SEEKY(cfqq)))
+       else if (!atomic_read(&cic->icq.ioc->nr_tasks) ||
+                !cfqd->cfq_slice_idle ||
+                (!cfq_cfqq_deep(cfqq) && CFQQ_SEEKY(cfqq)))
                enable_idle = 0;
        else if (sample_valid(cic->ttime.ttime_samples)) {
                if (cic->ttime.ttime_mean > cfqd->cfq_slice_idle)
@@ -3423,18 +3117,17 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
  */
 static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
-       struct cfq_queue *old_cfqq = cfqd->active_queue;
-
        cfq_log_cfqq(cfqd, cfqq, "preempt");
-       cfq_slice_expired(cfqd, 1);
 
        /*
         * workload type is changed, don't save slice, otherwise preempt
         * doesn't happen
         */
-       if (cfqq_type(old_cfqq) != cfqq_type(cfqq))
+       if (cfqq_type(cfqd->active_queue) != cfqq_type(cfqq))
                cfqq->cfqg->saved_workload_slice = 0;
 
+       cfq_slice_expired(cfqd, 1);
+
        /*
         * Put the new queue at the front of the of the current list,
         * so we know that it will be selected next.
@@ -3455,7 +3148,7 @@ static void
 cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                struct request *rq)
 {
-       struct cfq_io_context *cic = RQ_CIC(rq);
+       struct cfq_io_cq *cic = RQ_CIC(rq);
 
        cfqd->rq_queued++;
        if (rq->cmd_flags & REQ_PRIO)
@@ -3508,7 +3201,7 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
        struct cfq_queue *cfqq = RQ_CFQQ(rq);
 
        cfq_log_cfqq(cfqd, cfqq, "insert_request");
-       cfq_init_prio_data(cfqq, RQ_CIC(rq)->ioc);
+       cfq_init_prio_data(cfqq, RQ_CIC(rq)->icq.ioc);
 
        rq_set_fifo_time(rq, jiffies + cfqd->cfq_fifo_expire[rq_is_sync(rq)]);
        list_add_tail(&rq->queuelist, &cfqq->fifo);
@@ -3558,7 +3251,7 @@ static void cfq_update_hw_tag(struct cfq_data *cfqd)
 
 static bool cfq_should_wait_busy(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
-       struct cfq_io_context *cic = cfqd->active_cic;
+       struct cfq_io_cq *cic = cfqd->active_cic;
 
        /* If the queue already has requests, don't wait */
        if (!RB_EMPTY_ROOT(&cfqq->sort_list))
@@ -3695,7 +3388,7 @@ static int cfq_may_queue(struct request_queue *q, int rw)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
        struct task_struct *tsk = current;
-       struct cfq_io_context *cic;
+       struct cfq_io_cq *cic;
        struct cfq_queue *cfqq;
 
        /*
@@ -3710,7 +3403,7 @@ static int cfq_may_queue(struct request_queue *q, int rw)
 
        cfqq = cic_to_cfqq(cic, rw_is_sync(rw));
        if (cfqq) {
-               cfq_init_prio_data(cfqq, cic->ioc);
+               cfq_init_prio_data(cfqq, cic->icq.ioc);
 
                return __cfq_may_queue(cfqq);
        }
@@ -3731,21 +3424,17 @@ static void cfq_put_request(struct request *rq)
                BUG_ON(!cfqq->allocated[rw]);
                cfqq->allocated[rw]--;
 
-               put_io_context(RQ_CIC(rq)->ioc);
-
-               rq->elevator_private[0] = NULL;
-               rq->elevator_private[1] = NULL;
-
                /* Put down rq reference on cfqg */
                cfq_put_cfqg(RQ_CFQG(rq));
-               rq->elevator_private[2] = NULL;
+               rq->elv.priv[0] = NULL;
+               rq->elv.priv[1] = NULL;
 
                cfq_put_queue(cfqq);
        }
 }
 
 static struct cfq_queue *
-cfq_merge_cfqqs(struct cfq_data *cfqd, struct cfq_io_context *cic,
+cfq_merge_cfqqs(struct cfq_data *cfqd, struct cfq_io_cq *cic,
                struct cfq_queue *cfqq)
 {
        cfq_log_cfqq(cfqd, cfqq, "merging with queue %p", cfqq->new_cfqq);
@@ -3760,7 +3449,7 @@ cfq_merge_cfqqs(struct cfq_data *cfqd, struct cfq_io_context *cic,
  * was the last process referring to said cfqq.
  */
 static struct cfq_queue *
-split_cfqq(struct cfq_io_context *cic, struct cfq_queue *cfqq)
+split_cfqq(struct cfq_io_cq *cic, struct cfq_queue *cfqq)
 {
        if (cfqq_process_refs(cfqq) == 1) {
                cfqq->pid = current->pid;
@@ -3783,25 +3472,29 @@ static int
 cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
-       struct cfq_io_context *cic;
+       struct cfq_io_cq *cic = icq_to_cic(rq->elv.icq);
        const int rw = rq_data_dir(rq);
        const bool is_sync = rq_is_sync(rq);
        struct cfq_queue *cfqq;
-       unsigned long flags;
 
        might_sleep_if(gfp_mask & __GFP_WAIT);
 
-       cic = cfq_get_io_context(cfqd, gfp_mask);
-
-       spin_lock_irqsave(q->queue_lock, flags);
+       spin_lock_irq(q->queue_lock);
 
-       if (!cic)
-               goto queue_fail;
+       /* handle changed notifications */
+       if (unlikely(cic->icq.changed)) {
+               if (test_and_clear_bit(ICQ_IOPRIO_CHANGED, &cic->icq.changed))
+                       changed_ioprio(cic);
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+               if (test_and_clear_bit(ICQ_CGROUP_CHANGED, &cic->icq.changed))
+                       changed_cgroup(cic);
+#endif
+       }
 
 new_queue:
        cfqq = cic_to_cfqq(cic, is_sync);
        if (!cfqq || cfqq == &cfqd->oom_cfqq) {
-               cfqq = cfq_get_queue(cfqd, is_sync, cic->ioc, gfp_mask);
+               cfqq = cfq_get_queue(cfqd, is_sync, cic->icq.ioc, gfp_mask);
                cic_set_cfqq(cic, cfqq, is_sync);
        } else {
                /*
@@ -3827,17 +3520,10 @@ new_queue:
        cfqq->allocated[rw]++;
 
        cfqq->ref++;
-       rq->elevator_private[0] = cic;
-       rq->elevator_private[1] = cfqq;
-       rq->elevator_private[2] = cfq_ref_get_cfqg(cfqq->cfqg);
-       spin_unlock_irqrestore(q->queue_lock, flags);
+       rq->elv.priv[0] = cfqq;
+       rq->elv.priv[1] = cfq_ref_get_cfqg(cfqq->cfqg);
+       spin_unlock_irq(q->queue_lock);
        return 0;
-
-queue_fail:
-       cfq_schedule_dispatch(cfqd);
-       spin_unlock_irqrestore(q->queue_lock, flags);
-       cfq_log(cfqd, "set_request fail");
-       return 1;
 }
 
 static void cfq_kick_queue(struct work_struct *work)
@@ -3941,14 +3627,6 @@ static void cfq_exit_queue(struct elevator_queue *e)
        if (cfqd->active_queue)
                __cfq_slice_expired(cfqd, cfqd->active_queue, 0);
 
-       while (!list_empty(&cfqd->cic_list)) {
-               struct cfq_io_context *cic = list_entry(cfqd->cic_list.next,
-                                                       struct cfq_io_context,
-                                                       queue_list);
-
-               __cfq_exit_single_io_context(cfqd, cic);
-       }
-
        cfq_put_async_queues(cfqd);
        cfq_release_cfq_groups(cfqd);
 
@@ -3963,10 +3641,6 @@ static void cfq_exit_queue(struct elevator_queue *e)
 
        cfq_shutdown_timer_wq(cfqd);
 
-       spin_lock(&cic_index_lock);
-       ida_remove(&cic_index_ida, cfqd->cic_index);
-       spin_unlock(&cic_index_lock);
-
        /*
         * Wait for cfqg->blkg->key accessors to exit their grace periods.
         * Do this wait only if there are other unlinked groups out
@@ -3988,24 +3662,6 @@ static void cfq_exit_queue(struct elevator_queue *e)
        kfree(cfqd);
 }
 
-static int cfq_alloc_cic_index(void)
-{
-       int index, error;
-
-       do {
-               if (!ida_pre_get(&cic_index_ida, GFP_KERNEL))
-                       return -ENOMEM;
-
-               spin_lock(&cic_index_lock);
-               error = ida_get_new(&cic_index_ida, &index);
-               spin_unlock(&cic_index_lock);
-               if (error && error != -EAGAIN)
-                       return error;
-       } while (error);
-
-       return index;
-}
-
 static void *cfq_init_queue(struct request_queue *q)
 {
        struct cfq_data *cfqd;
@@ -4013,23 +3669,9 @@ static void *cfq_init_queue(struct request_queue *q)
        struct cfq_group *cfqg;
        struct cfq_rb_root *st;
 
-       i = cfq_alloc_cic_index();
-       if (i < 0)
-               return NULL;
-
        cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node);
-       if (!cfqd) {
-               spin_lock(&cic_index_lock);
-               ida_remove(&cic_index_ida, i);
-               spin_unlock(&cic_index_lock);
+       if (!cfqd)
                return NULL;
-       }
-
-       /*
-        * Don't need take queue_lock in the routine, since we are
-        * initializing the ioscheduler, and nobody is using cfqd
-        */
-       cfqd->cic_index = i;
 
        /* Init root service tree */
        cfqd->grp_service_tree = CFQ_RB_ROOT;
@@ -4055,11 +3697,6 @@ static void *cfq_init_queue(struct request_queue *q)
 
        if (blkio_alloc_blkg_stats(&cfqg->blkg)) {
                kfree(cfqg);
-
-               spin_lock(&cic_index_lock);
-               ida_remove(&cic_index_ida, cfqd->cic_index);
-               spin_unlock(&cic_index_lock);
-
                kfree(cfqd);
                return NULL;
        }
@@ -4091,8 +3728,6 @@ static void *cfq_init_queue(struct request_queue *q)
        cfqd->oom_cfqq.ref++;
        cfq_link_cfqq_cfqg(&cfqd->oom_cfqq, &cfqd->root_group);
 
-       INIT_LIST_HEAD(&cfqd->cic_list);
-
        cfqd->queue = q;
 
        init_timer(&cfqd->idle_slice_timer);
@@ -4121,34 +3756,6 @@ static void *cfq_init_queue(struct request_queue *q)
        return cfqd;
 }
 
-static void cfq_slab_kill(void)
-{
-       /*
-        * Caller already ensured that pending RCU callbacks are completed,
-        * so we should have no busy allocations at this point.
-        */
-       if (cfq_pool)
-               kmem_cache_destroy(cfq_pool);
-       if (cfq_ioc_pool)
-               kmem_cache_destroy(cfq_ioc_pool);
-}
-
-static int __init cfq_slab_setup(void)
-{
-       cfq_pool = KMEM_CACHE(cfq_queue, 0);
-       if (!cfq_pool)
-               goto fail;
-
-       cfq_ioc_pool = KMEM_CACHE(cfq_io_context, 0);
-       if (!cfq_ioc_pool)
-               goto fail;
-
-       return 0;
-fail:
-       cfq_slab_kill();
-       return -ENOMEM;
-}
-
 /*
  * sysfs parts below -->
  */
@@ -4254,15 +3861,18 @@ static struct elevator_type iosched_cfq = {
                .elevator_completed_req_fn =    cfq_completed_request,
                .elevator_former_req_fn =       elv_rb_former_request,
                .elevator_latter_req_fn =       elv_rb_latter_request,
+               .elevator_init_icq_fn =         cfq_init_icq,
+               .elevator_exit_icq_fn =         cfq_exit_icq,
                .elevator_set_req_fn =          cfq_set_request,
                .elevator_put_req_fn =          cfq_put_request,
                .elevator_may_queue_fn =        cfq_may_queue,
                .elevator_init_fn =             cfq_init_queue,
                .elevator_exit_fn =             cfq_exit_queue,
-               .trim =                         cfq_free_io_context,
        },
+       .icq_size       =       sizeof(struct cfq_io_cq),
+       .icq_align      =       __alignof__(struct cfq_io_cq),
        .elevator_attrs =       cfq_attrs,
-       .elevator_name        "cfq",
+       .elevator_name  =       "cfq",
        .elevator_owner =       THIS_MODULE,
 };
 
@@ -4280,6 +3890,8 @@ static struct blkio_policy_type blkio_policy_cfq;
 
 static int __init cfq_init(void)
 {
+       int ret;
+
        /*
         * could be 0 on HZ < 1000 setups
         */
@@ -4294,10 +3906,16 @@ static int __init cfq_init(void)
 #else
                cfq_group_idle = 0;
 #endif
-       if (cfq_slab_setup())
+       cfq_pool = KMEM_CACHE(cfq_queue, 0);
+       if (!cfq_pool)
                return -ENOMEM;
 
-       elv_register(&iosched_cfq);
+       ret = elv_register(&iosched_cfq);
+       if (ret) {
+               kmem_cache_destroy(cfq_pool);
+               return ret;
+       }
+
        blkio_policy_register(&blkio_policy_cfq);
 
        return 0;
@@ -4305,21 +3923,9 @@ static int __init cfq_init(void)
 
 static void __exit cfq_exit(void)
 {
-       DECLARE_COMPLETION_ONSTACK(all_gone);
        blkio_policy_unregister(&blkio_policy_cfq);
        elv_unregister(&iosched_cfq);
-       ioc_gone = &all_gone;
-       /* ioc_gone's update must be visible before reading ioc_count */
-       smp_wmb();
-
-       /*
-        * this also protects us from entering cfq_slab_kill() with
-        * pending RCU callbacks
-        */
-       if (elv_ioc_count_read(cfq_ioc_count))
-               wait_for_completion(&all_gone);
-       ida_destroy(&cic_index_ida);
-       cfq_slab_kill();
+       kmem_cache_destroy(cfq_pool);
 }
 
 module_init(cfq_init);
index 7b725020823c82243418c7d0105b9f6d23260589..7c668c8a6f953e1b6c298c9fc8af400924d7368a 100644 (file)
@@ -719,6 +719,9 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        case BLKSECTGET:
                return compat_put_ushort(arg,
                                         queue_max_sectors(bdev_get_queue(bdev)));
+       case BLKROTATIONAL:
+               return compat_put_ushort(arg,
+                                        !blk_queue_nonrot(bdev_get_queue(bdev)));
        case BLKRASET: /* compatible, but no compat_ptr (!) */
        case BLKFRASET:
                if (!capable(CAP_SYS_ADMIN))
index c644137d9cd643b0e3b80750333dc42e92d1e964..7bf12d793fcdee25eb1ba178a59203b72d60ec2e 100644 (file)
@@ -448,9 +448,7 @@ static struct elevator_type iosched_deadline = {
 
 static int __init deadline_init(void)
 {
-       elv_register(&iosched_deadline);
-
-       return 0;
+       return elv_register(&iosched_deadline);
 }
 
 static void __exit deadline_exit(void)
index 66343d6917d0cc64bbeccb7f55572237b8f78aba..91e18f8af9becaace380cc687d279eb1f47cb79a 100644 (file)
@@ -61,8 +61,8 @@ static int elv_iosched_allow_merge(struct request *rq, struct bio *bio)
        struct request_queue *q = rq->q;
        struct elevator_queue *e = q->elevator;
 
-       if (e->ops->elevator_allow_merge_fn)
-               return e->ops->elevator_allow_merge_fn(q, rq, bio);
+       if (e->type->ops.elevator_allow_merge_fn)
+               return e->type->ops.elevator_allow_merge_fn(q, rq, bio);
 
        return 1;
 }
@@ -168,17 +168,13 @@ static struct elevator_type *elevator_get(const char *name)
        return e;
 }
 
-static void *elevator_init_queue(struct request_queue *q,
-                                struct elevator_queue *eq)
+static int elevator_init_queue(struct request_queue *q,
+                              struct elevator_queue *eq)
 {
-       return eq->ops->elevator_init_fn(q);
-}
-
-static void elevator_attach(struct request_queue *q, struct elevator_queue *eq,
-                          void *data)
-{
-       q->elevator = eq;
-       eq->elevator_data = data;
+       eq->elevator_data = eq->type->ops.elevator_init_fn(q);
+       if (eq->elevator_data)
+               return 0;
+       return -ENOMEM;
 }
 
 static char chosen_elevator[ELV_NAME_MAX];
@@ -207,8 +203,7 @@ static struct elevator_queue *elevator_alloc(struct request_queue *q,
        if (unlikely(!eq))
                goto err;
 
-       eq->ops = &e->ops;
-       eq->elevator_type = e;
+       eq->type = e;
        kobject_init(&eq->kobj, &elv_ktype);
        mutex_init(&eq->sysfs_lock);
 
@@ -232,7 +227,7 @@ static void elevator_release(struct kobject *kobj)
        struct elevator_queue *e;
 
        e = container_of(kobj, struct elevator_queue, kobj);
-       elevator_put(e->elevator_type);
+       elevator_put(e->type);
        kfree(e->hash);
        kfree(e);
 }
@@ -241,7 +236,7 @@ int elevator_init(struct request_queue *q, char *name)
 {
        struct elevator_type *e = NULL;
        struct elevator_queue *eq;
-       void *data;
+       int err;
 
        if (unlikely(q->elevator))
                return 0;
@@ -278,13 +273,13 @@ int elevator_init(struct request_queue *q, char *name)
        if (!eq)
                return -ENOMEM;
 
-       data = elevator_init_queue(q, eq);
-       if (!data) {
+       err = elevator_init_queue(q, eq);
+       if (err) {
                kobject_put(&eq->kobj);
-               return -ENOMEM;
+               return err;
        }
 
-       elevator_attach(q, eq, data);
+       q->elevator = eq;
        return 0;
 }
 EXPORT_SYMBOL(elevator_init);
@@ -292,9 +287,8 @@ EXPORT_SYMBOL(elevator_init);
 void elevator_exit(struct elevator_queue *e)
 {
        mutex_lock(&e->sysfs_lock);
-       if (e->ops->elevator_exit_fn)
-               e->ops->elevator_exit_fn(e);
-       e->ops = NULL;
+       if (e->type->ops.elevator_exit_fn)
+               e->type->ops.elevator_exit_fn(e);
        mutex_unlock(&e->sysfs_lock);
 
        kobject_put(&e->kobj);
@@ -504,8 +498,8 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
                return ELEVATOR_BACK_MERGE;
        }
 
-       if (e->ops->elevator_merge_fn)
-               return e->ops->elevator_merge_fn(q, req, bio);
+       if (e->type->ops.elevator_merge_fn)
+               return e->type->ops.elevator_merge_fn(q, req, bio);
 
        return ELEVATOR_NO_MERGE;
 }
@@ -548,8 +542,8 @@ void elv_merged_request(struct request_queue *q, struct request *rq, int type)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->ops->elevator_merged_fn)
-               e->ops->elevator_merged_fn(q, rq, type);
+       if (e->type->ops.elevator_merged_fn)
+               e->type->ops.elevator_merged_fn(q, rq, type);
 
        if (type == ELEVATOR_BACK_MERGE)
                elv_rqhash_reposition(q, rq);
@@ -563,8 +557,8 @@ void elv_merge_requests(struct request_queue *q, struct request *rq,
        struct elevator_queue *e = q->elevator;
        const int next_sorted = next->cmd_flags & REQ_SORTED;
 
-       if (next_sorted && e->ops->elevator_merge_req_fn)
-               e->ops->elevator_merge_req_fn(q, rq, next);
+       if (next_sorted && e->type->ops.elevator_merge_req_fn)
+               e->type->ops.elevator_merge_req_fn(q, rq, next);
 
        elv_rqhash_reposition(q, rq);
 
@@ -581,8 +575,8 @@ void elv_bio_merged(struct request_queue *q, struct request *rq,
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->ops->elevator_bio_merged_fn)
-               e->ops->elevator_bio_merged_fn(q, rq, bio);
+       if (e->type->ops.elevator_bio_merged_fn)
+               e->type->ops.elevator_bio_merged_fn(q, rq, bio);
 }
 
 void elv_requeue_request(struct request_queue *q, struct request *rq)
@@ -608,12 +602,12 @@ void elv_drain_elevator(struct request_queue *q)
 
        lockdep_assert_held(q->queue_lock);
 
-       while (q->elevator->ops->elevator_dispatch_fn(q, 1))
+       while (q->elevator->type->ops.elevator_dispatch_fn(q, 1))
                ;
        if (q->nr_sorted && printed++ < 10) {
                printk(KERN_ERR "%s: forced dispatching is broken "
                       "(nr_sorted=%u), please report this\n",
-                      q->elevator->elevator_type->elevator_name, q->nr_sorted);
+                      q->elevator->type->elevator_name, q->nr_sorted);
        }
 }
 
@@ -702,7 +696,7 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where)
                 * rq cannot be accessed after calling
                 * elevator_add_req_fn.
                 */
-               q->elevator->ops->elevator_add_req_fn(q, rq);
+               q->elevator->type->ops.elevator_add_req_fn(q, rq);
                break;
 
        case ELEVATOR_INSERT_FLUSH:
@@ -731,8 +725,8 @@ struct request *elv_latter_request(struct request_queue *q, struct request *rq)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->ops->elevator_latter_req_fn)
-               return e->ops->elevator_latter_req_fn(q, rq);
+       if (e->type->ops.elevator_latter_req_fn)
+               return e->type->ops.elevator_latter_req_fn(q, rq);
        return NULL;
 }
 
@@ -740,8 +734,8 @@ struct request *elv_former_request(struct request_queue *q, struct request *rq)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->ops->elevator_former_req_fn)
-               return e->ops->elevator_former_req_fn(q, rq);
+       if (e->type->ops.elevator_former_req_fn)
+               return e->type->ops.elevator_former_req_fn(q, rq);
        return NULL;
 }
 
@@ -749,10 +743,8 @@ int elv_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->ops->elevator_set_req_fn)
-               return e->ops->elevator_set_req_fn(q, rq, gfp_mask);
-
-       rq->elevator_private[0] = NULL;
+       if (e->type->ops.elevator_set_req_fn)
+               return e->type->ops.elevator_set_req_fn(q, rq, gfp_mask);
        return 0;
 }
 
@@ -760,16 +752,16 @@ void elv_put_request(struct request_queue *q, struct request *rq)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->ops->elevator_put_req_fn)
-               e->ops->elevator_put_req_fn(rq);
+       if (e->type->ops.elevator_put_req_fn)
+               e->type->ops.elevator_put_req_fn(rq);
 }
 
 int elv_may_queue(struct request_queue *q, int rw)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->ops->elevator_may_queue_fn)
-               return e->ops->elevator_may_queue_fn(q, rw);
+       if (e->type->ops.elevator_may_queue_fn)
+               return e->type->ops.elevator_may_queue_fn(q, rw);
 
        return ELV_MQUEUE_MAY;
 }
@@ -804,8 +796,8 @@ void elv_completed_request(struct request_queue *q, struct request *rq)
        if (blk_account_rq(rq)) {
                q->in_flight[rq_is_sync(rq)]--;
                if ((rq->cmd_flags & REQ_SORTED) &&
-                   e->ops->elevator_completed_req_fn)
-                       e->ops->elevator_completed_req_fn(q, rq);
+                   e->type->ops.elevator_completed_req_fn)
+                       e->type->ops.elevator_completed_req_fn(q, rq);
        }
 }
 
@@ -823,7 +815,7 @@ elv_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
 
        e = container_of(kobj, struct elevator_queue, kobj);
        mutex_lock(&e->sysfs_lock);
-       error = e->ops ? entry->show(e, page) : -ENOENT;
+       error = e->type ? entry->show(e, page) : -ENOENT;
        mutex_unlock(&e->sysfs_lock);
        return error;
 }
@@ -841,7 +833,7 @@ elv_attr_store(struct kobject *kobj, struct attribute *attr,
 
        e = container_of(kobj, struct elevator_queue, kobj);
        mutex_lock(&e->sysfs_lock);
-       error = e->ops ? entry->store(e, page, length) : -ENOENT;
+       error = e->type ? entry->store(e, page, length) : -ENOENT;
        mutex_unlock(&e->sysfs_lock);
        return error;
 }
@@ -856,14 +848,13 @@ static struct kobj_type elv_ktype = {
        .release        = elevator_release,
 };
 
-int elv_register_queue(struct request_queue *q)
+int __elv_register_queue(struct request_queue *q, struct elevator_queue *e)
 {
-       struct elevator_queue *e = q->elevator;
        int error;
 
        error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched");
        if (!error) {
-               struct elv_fs_entry *attr = e->elevator_type->elevator_attrs;
+               struct elv_fs_entry *attr = e->type->elevator_attrs;
                if (attr) {
                        while (attr->attr.name) {
                                if (sysfs_create_file(&e->kobj, &attr->attr))
@@ -876,31 +867,55 @@ int elv_register_queue(struct request_queue *q)
        }
        return error;
 }
-EXPORT_SYMBOL(elv_register_queue);
 
-static void __elv_unregister_queue(struct elevator_queue *e)
+int elv_register_queue(struct request_queue *q)
 {
-       kobject_uevent(&e->kobj, KOBJ_REMOVE);
-       kobject_del(&e->kobj);
-       e->registered = 0;
+       return __elv_register_queue(q, q->elevator);
 }
+EXPORT_SYMBOL(elv_register_queue);
 
 void elv_unregister_queue(struct request_queue *q)
 {
-       if (q)
-               __elv_unregister_queue(q->elevator);
+       if (q) {
+               struct elevator_queue *e = q->elevator;
+
+               kobject_uevent(&e->kobj, KOBJ_REMOVE);
+               kobject_del(&e->kobj);
+               e->registered = 0;
+       }
 }
 EXPORT_SYMBOL(elv_unregister_queue);
 
-void elv_register(struct elevator_type *e)
+int elv_register(struct elevator_type *e)
 {
        char *def = "";
 
+       /* create icq_cache if requested */
+       if (e->icq_size) {
+               if (WARN_ON(e->icq_size < sizeof(struct io_cq)) ||
+                   WARN_ON(e->icq_align < __alignof__(struct io_cq)))
+                       return -EINVAL;
+
+               snprintf(e->icq_cache_name, sizeof(e->icq_cache_name),
+                        "%s_io_cq", e->elevator_name);
+               e->icq_cache = kmem_cache_create(e->icq_cache_name, e->icq_size,
+                                                e->icq_align, 0, NULL);
+               if (!e->icq_cache)
+                       return -ENOMEM;
+       }
+
+       /* register, don't allow duplicate names */
        spin_lock(&elv_list_lock);
-       BUG_ON(elevator_find(e->elevator_name));
+       if (elevator_find(e->elevator_name)) {
+               spin_unlock(&elv_list_lock);
+               if (e->icq_cache)
+                       kmem_cache_destroy(e->icq_cache);
+               return -EBUSY;
+       }
        list_add_tail(&e->list, &elv_list);
        spin_unlock(&elv_list_lock);
 
+       /* print pretty message */
        if (!strcmp(e->elevator_name, chosen_elevator) ||
                        (!*chosen_elevator &&
                         !strcmp(e->elevator_name, CONFIG_DEFAULT_IOSCHED)))
@@ -908,30 +923,26 @@ void elv_register(struct elevator_type *e)
 
        printk(KERN_INFO "io scheduler %s registered%s\n", e->elevator_name,
                                                                def);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(elv_register);
 
 void elv_unregister(struct elevator_type *e)
 {
-       struct task_struct *g, *p;
+       /* unregister */
+       spin_lock(&elv_list_lock);
+       list_del_init(&e->list);
+       spin_unlock(&elv_list_lock);
 
        /*
-        * Iterate every thread in the process to remove the io contexts.
+        * Destroy icq_cache if it exists.  icq's are RCU managed.  Make
+        * sure all RCU operations are complete before proceeding.
         */
-       if (e->ops.trim) {
-               read_lock(&tasklist_lock);
-               do_each_thread(g, p) {
-                       task_lock(p);
-                       if (p->io_context)
-                               e->ops.trim(p->io_context);
-                       task_unlock(p);
-               } while_each_thread(g, p);
-               read_unlock(&tasklist_lock);
+       if (e->icq_cache) {
+               rcu_barrier();
+               kmem_cache_destroy(e->icq_cache);
+               e->icq_cache = NULL;
        }
-
-       spin_lock(&elv_list_lock);
-       list_del_init(&e->list);
-       spin_unlock(&elv_list_lock);
 }
 EXPORT_SYMBOL_GPL(elv_unregister);
 
@@ -944,54 +955,41 @@ EXPORT_SYMBOL_GPL(elv_unregister);
 static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
 {
        struct elevator_queue *old_elevator, *e;
-       void *data;
        int err;
 
-       /*
-        * Allocate new elevator
-        */
+       /* allocate new elevator */
        e = elevator_alloc(q, new_e);
        if (!e)
                return -ENOMEM;
 
-       data = elevator_init_queue(q, e);
-       if (!data) {
+       err = elevator_init_queue(q, e);
+       if (err) {
                kobject_put(&e->kobj);
-               return -ENOMEM;
+               return err;
        }
 
-       /*
-        * Turn on BYPASS and drain all requests w/ elevator private data
-        */
+       /* turn on BYPASS and drain all requests w/ elevator private data */
        elv_quiesce_start(q);
 
-       /*
-        * Remember old elevator.
-        */
-       old_elevator = q->elevator;
-
-       /*
-        * attach and start new elevator
-        */
-       spin_lock_irq(q->queue_lock);
-       elevator_attach(q, e, data);
-       spin_unlock_irq(q->queue_lock);
-
-       if (old_elevator->registered) {
-               __elv_unregister_queue(old_elevator);
-
-               err = elv_register_queue(q);
+       /* unregister old queue, register new one and kill old elevator */
+       if (q->elevator->registered) {
+               elv_unregister_queue(q);
+               err = __elv_register_queue(q, e);
                if (err)
                        goto fail_register;
        }
 
-       /*
-        * finally exit old elevator and turn off BYPASS.
-        */
+       /* done, clear io_cq's, switch elevators and turn off BYPASS */
+       spin_lock_irq(q->queue_lock);
+       ioc_clear_queue(q);
+       old_elevator = q->elevator;
+       q->elevator = e;
+       spin_unlock_irq(q->queue_lock);
+
        elevator_exit(old_elevator);
        elv_quiesce_end(q);
 
-       blk_add_trace_msg(q, "elv switch: %s", e->elevator_type->elevator_name);
+       blk_add_trace_msg(q, "elv switch: %s", e->type->elevator_name);
 
        return 0;
 
@@ -1001,7 +999,6 @@ fail_register:
         * one again (along with re-adding the sysfs dir)
         */
        elevator_exit(e);
-       q->elevator = old_elevator;
        elv_register_queue(q);
        elv_quiesce_end(q);
 
@@ -1026,7 +1023,7 @@ int elevator_change(struct request_queue *q, const char *name)
                return -EINVAL;
        }
 
-       if (!strcmp(elevator_name, q->elevator->elevator_type->elevator_name)) {
+       if (!strcmp(elevator_name, q->elevator->type->elevator_name)) {
                elevator_put(e);
                return 0;
        }
@@ -1061,7 +1058,7 @@ ssize_t elv_iosched_show(struct request_queue *q, char *name)
        if (!q->elevator || !blk_queue_stackable(q))
                return sprintf(name, "none\n");
 
-       elv = e->elevator_type;
+       elv = e->type;
 
        spin_lock(&elv_list_lock);
        list_for_each_entry(__e, &elv_list, list) {
index 83e7c04015e1f920c813917bff937b4735902480..23b4f7063322c303dd5a1ab15c66a3a62daca7ca 100644 (file)
@@ -614,7 +614,7 @@ void add_disk(struct gendisk *disk)
         * Take an extra ref on queue which will be put on disk_release()
         * so that it sticks around as long as @disk is there.
         */
-       WARN_ON_ONCE(blk_get_queue(disk->queue));
+       WARN_ON_ONCE(!blk_get_queue(disk->queue));
 
        retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,
                                   "bdi");
index 4828fa34981314f34555a2e85ed381d660d9fa3b..ba15b2dbfb98ea55911109543f35889ea7b615da 100644 (file)
@@ -296,6 +296,8 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
                return put_uint(arg, bdev_discard_zeroes_data(bdev));
        case BLKSECTGET:
                return put_ushort(arg, queue_max_sectors(bdev_get_queue(bdev)));
+       case BLKROTATIONAL:
+               return put_ushort(arg, !blk_queue_nonrot(bdev_get_queue(bdev)));
        case BLKRASET:
        case BLKFRASET:
                if(!capable(CAP_SYS_ADMIN))
index 06389e9ef96d552836a1509ddf86745d82c09762..413a0b1d788c745df932745a65adb36ec119afaa 100644 (file)
@@ -94,9 +94,7 @@ static struct elevator_type elevator_noop = {
 
 static int __init noop_init(void)
 {
-       elv_register(&elevator_noop);
-
-       return 0;
+       return elv_register(&elevator_noop);
 }
 
 static void __exit noop_exit(void)
index fbdf0d802ec43e5320d74c2279bd20cb37546a1c..260fa80ef5750f80f4ebc1415d06abc992e18b8a 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/capability.h>
 #include <linux/completion.h>
 #include <linux/cdrom.h>
+#include <linux/ratelimit.h>
 #include <linux/slab.h>
 #include <linux/times.h>
 #include <asm/uaccess.h>
@@ -690,6 +691,57 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod
 }
 EXPORT_SYMBOL(scsi_cmd_ioctl);
 
+int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd)
+{
+       if (bd && bd == bd->bd_contains)
+               return 0;
+
+       /* Actually none of these is particularly useful on a partition,
+        * but they are safe.
+        */
+       switch (cmd) {
+       case SCSI_IOCTL_GET_IDLUN:
+       case SCSI_IOCTL_GET_BUS_NUMBER:
+       case SCSI_IOCTL_GET_PCI:
+       case SCSI_IOCTL_PROBE_HOST:
+       case SG_GET_VERSION_NUM:
+       case SG_SET_TIMEOUT:
+       case SG_GET_TIMEOUT:
+       case SG_GET_RESERVED_SIZE:
+       case SG_SET_RESERVED_SIZE:
+       case SG_EMULATED_HOST:
+               return 0;
+       case CDROM_GET_CAPABILITY:
+               /* Keep this until we remove the printk below.  udev sends it
+                * and we do not want to spam dmesg about it.   CD-ROMs do
+                * not have partitions, so we get here only for disks.
+                */
+               return -ENOIOCTLCMD;
+       default:
+               break;
+       }
+
+       /* In particular, rule out all resets and host-specific ioctls.  */
+       printk_ratelimited(KERN_WARNING
+                          "%s: sending ioctl %x to a partition!\n", current->comm, cmd);
+
+       return capable(CAP_SYS_RAWIO) ? 0 : -ENOIOCTLCMD;
+}
+EXPORT_SYMBOL(scsi_verify_blk_ioctl);
+
+int scsi_cmd_blk_ioctl(struct block_device *bd, fmode_t mode,
+                      unsigned int cmd, void __user *arg)
+{
+       int ret;
+
+       ret = scsi_verify_blk_ioctl(bd, cmd);
+       if (ret < 0)
+               return ret;
+
+       return scsi_cmd_ioctl(bd->bd_disk->queue, bd->bd_disk, mode, cmd, arg);
+}
+EXPORT_SYMBOL(scsi_cmd_blk_ioctl);
+
 static int __init blk_scsi_ioctl_init(void)
 {
        blk_set_cmd_filter_defaults(&blk_default_cmd_filter);
index 3ba6ef508869d104db2657423e451c3922db5f45..16f8693cc147ff9d8c864cc769b6632d8d105e45 100644 (file)
@@ -382,7 +382,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        type -= CRYPTO_MSG_BASE;
        link = &crypto_dispatch[type];
 
-       if (security_netlink_recv(skb, CAP_NET_ADMIN))
+       if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
        if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
index 1b3142127bf5f7308f3e7fc9fb83ff88a4730f2e..c07be024b962aa9ad8cce1ef635f37acd0a18fae 100644 (file)
@@ -97,7 +97,7 @@ obj-$(CONFIG_EISA)            += eisa/
 obj-y                          += lguest/
 obj-$(CONFIG_CPU_FREQ)         += cpufreq/
 obj-$(CONFIG_CPU_IDLE)         += cpuidle/
-obj-$(CONFIG_MMC)              += mmc/
+obj-y                          += mmc/
 obj-$(CONFIG_MEMSTICK)         += memstick/
 obj-y                          += leds/
 obj-$(CONFIG_INFINIBAND)       += infiniband/
index cb423f5aef24b12247b1c604e021c421581cb4a9..c339a0880e6ee14ad2df04ecf8a91ae985bfe2d7 100644 (file)
@@ -44,7 +44,7 @@ MODULE_LICENSE("GPL");
  */
 
 /* Emit various sounds */
-static int sound;
+static bool sound;
 module_param(sound, bool, 0);
 MODULE_PARM_DESC(sound, "emit sounds");
 
index ecb26b4f29a0581d697a26c69fa9b52532e0f327..c07f44f05f9d988c4c66a22bdf894d7df6aee1eb 100644 (file)
@@ -20,11 +20,12 @@ obj-y                               += acpi.o \
 # All the builtin files are in the "acpi." module_param namespace.
 acpi-y                         += osl.o utils.o reboot.o
 acpi-y                         += atomicio.o
+acpi-y                         += nvs.o
 
 # sleep related files
 acpi-y                         += wakeup.o
 acpi-y                         += sleep.o
-acpi-$(CONFIG_ACPI_SLEEP)      += proc.o nvs.o
+acpi-$(CONFIG_ACPI_SLEEP)      += proc.o
 
 
 #
index 301bd2d388ad1dc7a6a00268ebbec4266470150a..0ca208b6dcf099e4b012ed29efa0d564227f20c6 100644 (file)
@@ -8,41 +8,151 @@ ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT
 # use acpi.o to put all files here into acpi.o modparam namespace
 obj-y  += acpi.o
 
-acpi-y := dsfield.o   dsmthdat.o  dsopcode.o  dswexec.o  dswscope.o \
-        dsmethod.o  dsobject.o  dsutils.o   dswload.o  dswstate.o \
-        dsinit.o dsargs.o dscontrol.o dswload2.o
+acpi-y :=              \
+       dsargs.o        \
+       dscontrol.o     \
+       dsfield.o       \
+       dsinit.o        \
+       dsmethod.o      \
+       dsmthdat.o      \
+       dsobject.o      \
+       dsopcode.o      \
+       dsutils.o       \
+       dswexec.o       \
+       dswload.o       \
+       dswload2.o      \
+       dswscope.o      \
+       dswstate.o
 
-acpi-y += evevent.o  evregion.o  evsci.o    evxfevnt.o \
-        evmisc.o   evrgnini.o  evxface.o  evxfregn.o \
-        evgpe.o    evgpeblk.o evgpeinit.o  evgpeutil.o evxfgpe.o evglock.o
+acpi-y +=              \
+       evevent.o       \
+       evgpe.o         \
+       evgpeblk.o      \
+       evgpeinit.o     \
+       evgpeutil.o     \
+       evglock.o       \
+       evmisc.o        \
+       evregion.o      \
+       evrgnini.o      \
+       evsci.o         \
+       evxface.o       \
+       evxfevnt.o      \
+       evxfgpe.o       \
+       evxfregn.o
 
-acpi-y += exconfig.o  exfield.o  exnames.o   exoparg6.o  exresolv.o  exstorob.o\
-        exconvrt.o  exfldio.o  exoparg1.o  exprep.o    exresop.o   exsystem.o\
-        excreate.o  exmisc.o   exoparg2.o  exregion.o  exstore.o   exutils.o \
-        exdump.o    exmutex.o  exoparg3.o  exresnte.o  exstoren.o  exdebug.o
+acpi-y +=              \
+       exconfig.o      \
+       exconvrt.o      \
+       excreate.o      \
+       exdebug.o       \
+       exdump.o        \
+       exfield.o       \
+       exfldio.o       \
+       exmutex.o       \
+       exnames.o       \
+       exoparg1.o      \
+       exoparg2.o      \
+       exoparg3.o      \
+       exoparg6.o      \
+       exprep.o        \
+       exmisc.o        \
+       exregion.o      \
+       exresnte.o      \
+       exresolv.o      \
+       exresop.o       \
+       exstore.o       \
+       exstoren.o      \
+       exstorob.o      \
+       exsystem.o      \
+       exutils.o
 
-acpi-y += hwacpi.o  hwgpe.o  hwregs.o  hwsleep.o hwxface.o hwvalid.o hwpci.o
+acpi-y +=              \
+       hwacpi.o        \
+       hwgpe.o         \
+       hwpci.o         \
+       hwregs.o        \
+       hwsleep.o       \
+       hwvalid.o       \
+       hwxface.o
 
 acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o
 
-acpi-y += nsaccess.o  nsload.o    nssearch.o  nsxfeval.o \
-        nsalloc.o   nseval.o    nsnames.o   nsutils.o   nsxfname.o \
-        nsdump.o    nsinit.o    nsobject.o  nswalk.o    nsxfobj.o  \
-        nsparse.o   nspredef.o  nsrepair.o  nsrepair2.o
+acpi-y +=              \
+       nsaccess.o      \
+       nsalloc.o       \
+       nsdump.o        \
+       nseval.o        \
+       nsinit.o        \
+       nsload.o        \
+       nsnames.o       \
+       nsobject.o      \
+       nsparse.o       \
+       nspredef.o      \
+       nsrepair.o      \
+       nsrepair2.o     \
+       nssearch.o      \
+       nsutils.o       \
+       nswalk.o        \
+       nsxfeval.o      \
+       nsxfname.o      \
+       nsxfobj.o
 
 acpi-$(ACPI_FUTURE_USAGE) += nsdumpdv.o
 
-acpi-y += psargs.o    psparse.o  psloop.o pstree.o   pswalk.o  \
-        psopcode.o  psscope.o  psutils.o  psxface.o
+acpi-y +=              \
+       psargs.o        \
+       psloop.o        \
+       psopcode.o      \
+       psparse.o       \
+       psscope.o       \
+       pstree.o        \
+       psutils.o       \
+       pswalk.o        \
+       psxface.o
 
-acpi-y += rsaddr.o rscreate.o rsinfo.o rsio.o rslist.o rsmisc.o rsxface.o \
-        rscalc.o  rsirq.o  rsmemory.o  rsutils.o
+acpi-y +=              \
+       rsaddr.o        \
+       rscalc.o        \
+       rscreate.o      \
+       rsinfo.o        \
+       rsio.o          \
+       rsirq.o         \
+       rslist.o        \
+       rsmemory.o      \
+       rsmisc.o        \
+       rsserial.o      \
+       rsutils.o       \
+       rsxface.o
 
 acpi-$(ACPI_FUTURE_USAGE) += rsdump.o
 
-acpi-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
+acpi-y +=              \
+       tbfadt.o        \
+       tbfind.o        \
+       tbinstal.o      \
+       tbutils.o       \
+       tbxface.o       \
+       tbxfroot.o
 
-acpi-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \
-               utcopy.o utdelete.o utglobal.o utmath.o utobject.o \
-               utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o \
-               utosi.o utxferror.o utdecode.o
+acpi-y +=              \
+       utaddress.o     \
+       utalloc.o       \
+       utcopy.o        \
+       utdebug.o       \
+       utdecode.o      \
+       utdelete.o      \
+       uteval.o        \
+       utglobal.o      \
+       utids.o         \
+       utinit.o        \
+       utlock.o        \
+       utmath.o        \
+       utmisc.o        \
+       utmutex.o       \
+       utobject.o      \
+       utosi.o         \
+       utresrc.o       \
+       utstate.o       \
+       utxface.o       \
+       utxferror.o     \
+       utxfmutex.o
index e0ba17f0a7c89acc590ab487e5c51c1360697579..a44bd424f9f4137b58a722e313d3454b0fbc2243 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f895a244ca7ea187588356475e6ca4d700804b52..1f30af613e87619d4ab7cfeec3d45dad1d15d386 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 
 #define ACPI_MAX_SLEEP                  2000   /* Two seconds */
 
+/* Address Range lists are per-space_id (Memory and I/O only) */
+
+#define ACPI_ADDRESS_RANGE_MAX          2
+
 /******************************************************************************
  *
  * ACPI Specification constants (Do not change unless the specification changes)
 #define ACPI_RSDP_CHECKSUM_LENGTH       20
 #define ACPI_RSDP_XCHECKSUM_LENGTH      36
 
-/* SMBus and IPMI bidirectional buffer size */
+/* SMBus, GSBus and IPMI bidirectional buffer size */
 
 #define ACPI_SMBUS_BUFFER_SIZE          34
+#define ACPI_GSBUS_BUFFER_SIZE          34
 #define ACPI_IPMI_BUFFER_SIZE           66
 
 /* _sx_d and _sx_w control methods */
index eb0b1f8dee6dca011b447504b7654ca5243b3f63..deaa8197956133850767828e05dd248ea41378cf 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2d1b7ffa377a030d9e30490bcdcfef225bdb1d89..5935ba6707e2614cddcd39d3bb0220a3bc9a2bd1 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index bea3b4899183bae0fce0ecfa44238160d438a9d3..c53caa521a30e90b46f3d6de1d70db4c7d4ea12b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -162,6 +162,7 @@ acpi_status acpi_ev_initialize_op_regions(void);
 
 acpi_status
 acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
+                              union acpi_operand_object *field_obj,
                               u32 function,
                               u32 region_offset, u32 bit_width, u64 *value);
 
index 76dc02f155748af02278d465e3948e7c1a214cf0..2853f7673f3bdf05235384b21a614bd1ac331084 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -108,7 +108,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE);
 /*
  * Optionally enable output from the AML Debug Object.
  */
-u32 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
+bool ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
 
 /*
  * Optionally copy the entire DSDT to local memory (instead of simply
@@ -140,8 +140,19 @@ u32 acpi_gbl_trace_flags;
 acpi_name acpi_gbl_trace_method_name;
 u8 acpi_gbl_system_awake_and_running;
 
+/*
+ * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning
+ * that the ACPI hardware is no longer required. A flag in the FADT indicates
+ * a reduced HW machine, and that flag is duplicated here for convenience.
+ */
+u8 acpi_gbl_reduced_hardware;
+
 #endif
 
+/* Do not disassemble buffers to resource descriptors */
+
+ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_no_resource_disassembly, FALSE);
+
 /*****************************************************************************
  *
  * Debug support
@@ -207,7 +218,7 @@ ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
 
 /*****************************************************************************
  *
- * Mutual exlusion within ACPICA subsystem
+ * Mutual exclusion within ACPICA subsystem
  *
  ****************************************************************************/
 
@@ -295,6 +306,8 @@ ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present;
 ACPI_EXTERN u8 acpi_gbl_events_initialized;
 ACPI_EXTERN u8 acpi_gbl_osi_data;
 ACPI_EXTERN struct acpi_interface_info *acpi_gbl_supported_interfaces;
+ACPI_EXTERN struct acpi_address_range
+    *acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX];
 
 #ifndef DEFINE_ACPI_GLOBALS
 
index e7213beaafc7914322f72520d40bcfd437b4ea5b..677793e938f5d83e31241206724b58fec3e01630 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3731e1c34b83b5d75ab25f08d0eefb706d7f85bc..eb308635da7247f0e1ae0554f322d082869b3eb9 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -468,6 +468,8 @@ void acpi_ex_eisa_id_to_string(char *dest, u64 compressed_id);
 
 void acpi_ex_integer_to_string(char *dest, u64 value);
 
+u8 acpi_is_valid_space_id(u8 space_id);
+
 /*
  * exregion - default op_region handlers
  */
index 5552125d8340ef11782f4aec94595e7444cb1774..3f24068837d5ad8e80c7603ac864fa86673bf7b3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -53,7 +53,7 @@ typedef u32 acpi_mutex_handle;
 
 /* Total number of aml opcodes defined */
 
-#define AML_NUM_OPCODES                 0x7F
+#define AML_NUM_OPCODES                 0x81
 
 /* Forward declarations */
 
@@ -249,12 +249,16 @@ struct acpi_create_field_info {
        struct acpi_namespace_node *field_node;
        struct acpi_namespace_node *register_node;
        struct acpi_namespace_node *data_register_node;
+       struct acpi_namespace_node *connection_node;
+       u8 *resource_buffer;
        u32 bank_value;
        u32 field_bit_position;
        u32 field_bit_length;
+       u16 resource_length;
        u8 field_flags;
        u8 attribute;
        u8 field_type;
+       u8 access_length;
 };
 
 typedef
@@ -315,7 +319,8 @@ struct acpi_name_info {
 
 /*
  * Used for ACPI_PTYPE1_FIXED, ACPI_PTYPE1_VAR, ACPI_PTYPE2,
- * ACPI_PTYPE2_MIN, ACPI_PTYPE2_PKG_COUNT, ACPI_PTYPE2_COUNT
+ * ACPI_PTYPE2_MIN, ACPI_PTYPE2_PKG_COUNT, ACPI_PTYPE2_COUNT,
+ * ACPI_PTYPE2_FIX_VAR
  */
 struct acpi_package_info {
        u8 type;
@@ -625,6 +630,15 @@ union acpi_generic_state {
 
 typedef acpi_status(*ACPI_EXECUTE_OP) (struct acpi_walk_state * walk_state);
 
+/* Address Range info block */
+
+struct acpi_address_range {
+       struct acpi_address_range *next;
+       struct acpi_namespace_node *region_node;
+       acpi_physical_address start_address;
+       acpi_physical_address end_address;
+};
+
 /*****************************************************************************
  *
  * Parser typedefs and structs
@@ -951,7 +965,7 @@ struct acpi_port_info {
 #define ACPI_RESOURCE_NAME_END_DEPENDENT        0x38
 #define ACPI_RESOURCE_NAME_IO                   0x40
 #define ACPI_RESOURCE_NAME_FIXED_IO             0x48
-#define ACPI_RESOURCE_NAME_RESERVED_S1          0x50
+#define ACPI_RESOURCE_NAME_FIXED_DMA            0x50
 #define ACPI_RESOURCE_NAME_RESERVED_S2          0x58
 #define ACPI_RESOURCE_NAME_RESERVED_S3          0x60
 #define ACPI_RESOURCE_NAME_RESERVED_S4          0x68
@@ -973,7 +987,9 @@ struct acpi_port_info {
 #define ACPI_RESOURCE_NAME_EXTENDED_IRQ         0x89
 #define ACPI_RESOURCE_NAME_ADDRESS64            0x8A
 #define ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64   0x8B
-#define ACPI_RESOURCE_NAME_LARGE_MAX            0x8B
+#define ACPI_RESOURCE_NAME_GPIO                 0x8C
+#define ACPI_RESOURCE_NAME_SERIAL_BUS           0x8E
+#define ACPI_RESOURCE_NAME_LARGE_MAX            0x8E
 
 /*****************************************************************************
  *
index b7491ee1fba642447242705c5a7ba48c677cce94..ef338a96f5b28761b77840851d73fedd8f25da8f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 79a598c67fe3ad30ae599aacaefa2f776b6d0303..2c9e0f049523120f4c03a094ab8b16e0563aea08 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1055769f2f01ae97f4f69780fd93b1015512d870..c065078ca83bbbb0f3a09a22a609121d0d7785d7 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -254,6 +254,7 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO};
        u32                             base_byte_offset;   /* Byte offset within containing object */\
        u32                             value;              /* Value to store into the Bank or Index register */\
        u8                              start_field_bit_offset;/* Bit offset within first field datum (0-63) */\
+       u8                              access_length;  /* For serial regions/fields */
 
 
 struct acpi_object_field_common {      /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */
@@ -261,7 +262,9 @@ struct acpi_object_field_common {   /* COMMON FIELD (for BUFFER, REGION, BANK, and
 };
 
 struct acpi_object_region_field {
-       ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Containing op_region object */
+       ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO u16 resource_length;
+       union acpi_operand_object *region_obj;  /* Containing op_region object */
+       u8 *resource_buffer;    /* resource_template for serial regions/fields */
 };
 
 struct acpi_object_bank_field {
@@ -358,6 +361,7 @@ typedef enum {
  */
 struct acpi_object_extra {
        ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *method_REG;       /* _REG method for this region (if any) */
+       struct acpi_namespace_node *scope_node;
        void *region_context;   /* Region-specific data */
        u8 *aml_start;
        u32 aml_length;
index bb2ccfad7376548569f99ed46653c4ee710f958e..9440d053fbb3f83e6f60217bb4fc6e08cafe4a98 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -93,6 +93,7 @@
 #define ARGP_CONCAT_OP                  ARGP_LIST3 (ARGP_TERMARG,    ARGP_TERMARG,       ARGP_TARGET)
 #define ARGP_CONCAT_RES_OP              ARGP_LIST3 (ARGP_TERMARG,    ARGP_TERMARG,       ARGP_TARGET)
 #define ARGP_COND_REF_OF_OP             ARGP_LIST2 (ARGP_SUPERNAME,  ARGP_SUPERNAME)
+#define ARGP_CONNECTFIELD_OP            ARGP_LIST1 (ARGP_NAMESTRING)
 #define ARGP_CONTINUE_OP                ARG_NONE
 #define ARGP_COPY_OP                    ARGP_LIST2 (ARGP_TERMARG,    ARGP_SIMPLENAME)
 #define ARGP_CREATE_BIT_FIELD_OP        ARGP_LIST3 (ARGP_TERMARG,    ARGP_TERMARG,       ARGP_NAME)
 #define ARGP_RETURN_OP                  ARGP_LIST1 (ARGP_TERMARG)
 #define ARGP_REVISION_OP                ARG_NONE
 #define ARGP_SCOPE_OP                   ARGP_LIST3 (ARGP_PKGLENGTH,  ARGP_NAME,          ARGP_TERMLIST)
+#define ARGP_SERIALFIELD_OP             ARGP_LIST1 (ARGP_NAMESTRING)
 #define ARGP_SHIFT_LEFT_OP              ARGP_LIST3 (ARGP_TERMARG,    ARGP_TERMARG,       ARGP_TARGET)
 #define ARGP_SHIFT_RIGHT_OP             ARGP_LIST3 (ARGP_TERMARG,    ARGP_TERMARG,       ARGP_TARGET)
 #define ARGP_SIGNAL_OP                  ARGP_LIST1 (ARGP_SUPERNAME)
 #define ARGI_CONCAT_OP                  ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA,   ARGI_TARGETREF)
 #define ARGI_CONCAT_RES_OP              ARGI_LIST3 (ARGI_BUFFER,     ARGI_BUFFER,        ARGI_TARGETREF)
 #define ARGI_COND_REF_OF_OP             ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF)
+#define ARGI_CONNECTFIELD_OP            ARGI_INVALID_OPCODE
 #define ARGI_CONTINUE_OP                ARGI_INVALID_OPCODE
 #define ARGI_COPY_OP                    ARGI_LIST2 (ARGI_ANYTYPE,    ARGI_SIMPLE_TARGET)
 #define ARGI_CREATE_BIT_FIELD_OP        ARGI_LIST3 (ARGI_BUFFER,     ARGI_INTEGER,       ARGI_REFERENCE)
 #define ARGI_RETURN_OP                  ARGI_INVALID_OPCODE
 #define ARGI_REVISION_OP                ARG_NONE
 #define ARGI_SCOPE_OP                   ARGI_INVALID_OPCODE
+#define ARGI_SERIALFIELD_OP             ARGI_INVALID_OPCODE
 #define ARGI_SHIFT_LEFT_OP              ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_SHIFT_RIGHT_OP             ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_SIGNAL_OP                  ARGI_LIST1 (ARGI_EVENT)
index 5ea1e06afa20637b652f87cbe9ee60b91fb62023..b725d780d34dafec0ecd1d2166a30dd8c078d1f0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c445cca490ea4b1489983ba4866b0fb746c3de21..bbb34c9be4e84de95f0d0922fe72ba5558f1b3e0 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * ACPI_PTYPE2_REV_FIXED: Revision at start, each subpackage is Fixed-length
  *      (Used for _ART, _FPS)
  *
+ * ACPI_PTYPE2_FIX_VAR: Each subpackage consists of some fixed-length elements
+ *      followed by an optional element
+ *      object type
+ *      count
+ *      object type
+ *      count = 0 (optional)
+ *      (Used for _DLM)
+ *
  *****************************************************************************/
 
 enum acpi_return_package_types {
@@ -105,7 +113,8 @@ enum acpi_return_package_types {
        ACPI_PTYPE2_PKG_COUNT = 6,
        ACPI_PTYPE2_FIXED = 7,
        ACPI_PTYPE2_MIN = 8,
-       ACPI_PTYPE2_REV_FIXED = 9
+       ACPI_PTYPE2_REV_FIXED = 9,
+       ACPI_PTYPE2_FIX_VAR = 10
 };
 
 #ifdef ACPI_CREATE_PREDEFINED_TABLE
@@ -154,6 +163,7 @@ static const union acpi_predefined_info predefined_names[] =
        {{"_AC8", 0, ACPI_RTYPE_INTEGER}},
        {{"_AC9", 0, ACPI_RTYPE_INTEGER}},
        {{"_ADR", 0, ACPI_RTYPE_INTEGER}},
+       {{"_AEI", 0, ACPI_RTYPE_BUFFER}},
        {{"_AL0", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
                          {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
 
@@ -229,6 +239,13 @@ static const union acpi_predefined_info predefined_names[] =
        {{"_CID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints/Strs) */
                          {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0,0}, 0,0}},
 
+       {{"_CLS", 0, ACPI_RTYPE_PACKAGE}},      /* Fixed-length (3 Int) */
+       {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0}, 0, 0}},
+
+       {{"_CPC", 0, ACPI_RTYPE_PACKAGE}},      /* Variable-length (Ints/Bufs) */
+       {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER, 0, 0}, 0,
+         0}},
+
        {{"_CRS", 0, ACPI_RTYPE_BUFFER}},
        {{"_CRT", 0, ACPI_RTYPE_INTEGER}},
        {{"_CSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n-1 Int) */
@@ -237,12 +254,21 @@ static const union acpi_predefined_info predefined_names[] =
        {{"_CST", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n Pkg (1 Buf/3 Int) */
                          {{{ACPI_PTYPE2_PKG_COUNT,ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_INTEGER}, 3,0}},
 
+       {{"_CWS", 1, ACPI_RTYPE_INTEGER}},
        {{"_DCK", 1, ACPI_RTYPE_INTEGER}},
        {{"_DCS", 0, ACPI_RTYPE_INTEGER}},
        {{"_DDC", 1, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER}},
        {{"_DDN", 0, ACPI_RTYPE_STRING}},
+       {{"_DEP", 0, ACPI_RTYPE_PACKAGE}},      /* Variable-length (Refs) */
+       {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}},
+
        {{"_DGS", 0, ACPI_RTYPE_INTEGER}},
        {{"_DIS", 0, 0}},
+
+       {{"_DLM", 0, ACPI_RTYPE_PACKAGE}},      /* Variable-length (Pkgs) each (1 Ref, 0/1 Optional Buf/Ref) */
+       {{{ACPI_PTYPE2_FIX_VAR, ACPI_RTYPE_REFERENCE, 1,
+          ACPI_RTYPE_REFERENCE | ACPI_RTYPE_BUFFER}, 0, 0}},
+
        {{"_DMA", 0, ACPI_RTYPE_BUFFER}},
        {{"_DOD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */
                          {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}},
@@ -262,6 +288,7 @@ static const union acpi_predefined_info predefined_names[] =
        {{"_EJ3", 1, 0}},
        {{"_EJ4", 1, 0}},
        {{"_EJD", 0, ACPI_RTYPE_STRING}},
+       {{"_EVT", 1, 0}},
        {{"_FDE", 0, ACPI_RTYPE_BUFFER}},
        {{"_FDI", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (16 Int) */
                          {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16,0}, 0,0}},
@@ -281,14 +308,17 @@ static const union acpi_predefined_info predefined_names[] =
        {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0}, 0, 0}},
 
        {{"_GAI", 0, ACPI_RTYPE_INTEGER}},
+       {{"_GCP", 0, ACPI_RTYPE_INTEGER}},
        {{"_GHL", 0, ACPI_RTYPE_INTEGER}},
        {{"_GLK", 0, ACPI_RTYPE_INTEGER}},
        {{"_GPD", 0, ACPI_RTYPE_INTEGER}},
        {{"_GPE", 0, ACPI_RTYPE_INTEGER}}, /* _GPE method, not _GPE scope */
+       {{"_GRT", 0, ACPI_RTYPE_BUFFER}},
        {{"_GSB", 0, ACPI_RTYPE_INTEGER}},
        {{"_GTF", 0, ACPI_RTYPE_BUFFER}},
        {{"_GTM", 0, ACPI_RTYPE_BUFFER}},
        {{"_GTS", 1, 0}},
+       {{"_GWS", 1, ACPI_RTYPE_INTEGER}},
        {{"_HID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}},
        {{"_HOT", 0, ACPI_RTYPE_INTEGER}},
        {{"_HPP", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */
@@ -303,6 +333,7 @@ static const union acpi_predefined_info predefined_names[] =
        {{"_HPX", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (var Ints) */
                          {{{ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5,0}, 0,0}},
 
+       {{"_HRV", 0, ACPI_RTYPE_INTEGER}},
        {{"_IFT", 0, ACPI_RTYPE_INTEGER}}, /* See IPMI spec */
        {{"_INI", 0, 0}},
        {{"_IRC", 0, 0}},
@@ -361,6 +392,9 @@ static const union acpi_predefined_info predefined_names[] =
        {{"_PR3", 0, ACPI_RTYPE_PACKAGE}},      /* Variable-length (Refs) */
        {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}},
 
+       {{"_PRE", 0, ACPI_RTYPE_PACKAGE}},      /* Variable-length (Refs) */
+       {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}},
+
        {{"_PRL", 0, ACPI_RTYPE_PACKAGE}},      /* Variable-length (Refs) */
        {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}},
 
@@ -391,6 +425,7 @@ static const union acpi_predefined_info predefined_names[] =
        {{"_PSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (5 Int) with count */
                          {{{ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER,0,0}, 0,0}},
 
+       {{"_PSE", 1, 0}},
        {{"_PSL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
                          {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
 
@@ -457,6 +492,7 @@ static const union acpi_predefined_info predefined_names[] =
        {{"_SLI", 0, ACPI_RTYPE_BUFFER}},
        {{"_SPD", 1, ACPI_RTYPE_INTEGER}},
        {{"_SRS", 1, 0}},
+       {{"_SRT", 1, ACPI_RTYPE_INTEGER}},
        {{"_SRV", 0, ACPI_RTYPE_INTEGER}}, /* See IPMI spec */
        {{"_SST", 1, 0}},
        {{"_STA", 0, ACPI_RTYPE_INTEGER}},
@@ -464,6 +500,7 @@ static const union acpi_predefined_info predefined_names[] =
        {{"_STP", 2, ACPI_RTYPE_INTEGER}},
        {{"_STR", 0, ACPI_RTYPE_BUFFER}},
        {{"_STV", 2, ACPI_RTYPE_INTEGER}},
+       {{"_SUB", 0, ACPI_RTYPE_STRING}},
        {{"_SUN", 0, ACPI_RTYPE_INTEGER}},
        {{"_SWS", 0, ACPI_RTYPE_INTEGER}},
        {{"_TC1", 0, ACPI_RTYPE_INTEGER}},
index f08b55b7f3a08f5dff5209ad52268e78b59cacc6..0347d099349708a6f21035467ac96e2eb5578105 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -73,28 +73,40 @@ typedef const struct acpi_rsconvert_info {
 
 /* Resource conversion opcodes */
 
-#define ACPI_RSC_INITGET                0
-#define ACPI_RSC_INITSET                1
-#define ACPI_RSC_FLAGINIT               2
-#define ACPI_RSC_1BITFLAG               3
-#define ACPI_RSC_2BITFLAG               4
-#define ACPI_RSC_COUNT                  5
-#define ACPI_RSC_COUNT16                6
-#define ACPI_RSC_LENGTH                 7
-#define ACPI_RSC_MOVE8                  8
-#define ACPI_RSC_MOVE16                 9
-#define ACPI_RSC_MOVE32                 10
-#define ACPI_RSC_MOVE64                 11
-#define ACPI_RSC_SET8                   12
-#define ACPI_RSC_DATA8                  13
-#define ACPI_RSC_ADDRESS                14
-#define ACPI_RSC_SOURCE                 15
-#define ACPI_RSC_SOURCEX                16
-#define ACPI_RSC_BITMASK                17
-#define ACPI_RSC_BITMASK16              18
-#define ACPI_RSC_EXIT_NE                19
-#define ACPI_RSC_EXIT_LE                20
-#define ACPI_RSC_EXIT_EQ                21
+typedef enum {
+       ACPI_RSC_INITGET = 0,
+       ACPI_RSC_INITSET,
+       ACPI_RSC_FLAGINIT,
+       ACPI_RSC_1BITFLAG,
+       ACPI_RSC_2BITFLAG,
+       ACPI_RSC_3BITFLAG,
+       ACPI_RSC_ADDRESS,
+       ACPI_RSC_BITMASK,
+       ACPI_RSC_BITMASK16,
+       ACPI_RSC_COUNT,
+       ACPI_RSC_COUNT16,
+       ACPI_RSC_COUNT_GPIO_PIN,
+       ACPI_RSC_COUNT_GPIO_RES,
+       ACPI_RSC_COUNT_GPIO_VEN,
+       ACPI_RSC_COUNT_SERIAL_RES,
+       ACPI_RSC_COUNT_SERIAL_VEN,
+       ACPI_RSC_DATA8,
+       ACPI_RSC_EXIT_EQ,
+       ACPI_RSC_EXIT_LE,
+       ACPI_RSC_EXIT_NE,
+       ACPI_RSC_LENGTH,
+       ACPI_RSC_MOVE_GPIO_PIN,
+       ACPI_RSC_MOVE_GPIO_RES,
+       ACPI_RSC_MOVE_SERIAL_RES,
+       ACPI_RSC_MOVE_SERIAL_VEN,
+       ACPI_RSC_MOVE8,
+       ACPI_RSC_MOVE16,
+       ACPI_RSC_MOVE32,
+       ACPI_RSC_MOVE64,
+       ACPI_RSC_SET8,
+       ACPI_RSC_SOURCE,
+       ACPI_RSC_SOURCEX
+} ACPI_RSCONVERT_OPCODES;
 
 /* Resource Conversion sub-opcodes */
 
@@ -106,6 +118,9 @@ typedef const struct acpi_rsconvert_info {
 #define ACPI_RS_OFFSET(f)               (u8) ACPI_OFFSET (struct acpi_resource,f)
 #define AML_OFFSET(f)                   (u8) ACPI_OFFSET (union aml_resource,f)
 
+/*
+ * Individual entry for the resource dump tables
+ */
 typedef const struct acpi_rsdump_info {
        u8 opcode;
        u8 offset;
@@ -116,20 +131,25 @@ typedef const struct acpi_rsdump_info {
 
 /* Values for the Opcode field above */
 
-#define ACPI_RSD_TITLE                  0
-#define ACPI_RSD_LITERAL                1
-#define ACPI_RSD_STRING                 2
-#define ACPI_RSD_UINT8                  3
-#define ACPI_RSD_UINT16                 4
-#define ACPI_RSD_UINT32                 5
-#define ACPI_RSD_UINT64                 6
-#define ACPI_RSD_1BITFLAG               7
-#define ACPI_RSD_2BITFLAG               8
-#define ACPI_RSD_SHORTLIST              9
-#define ACPI_RSD_LONGLIST               10
-#define ACPI_RSD_DWORDLIST              11
-#define ACPI_RSD_ADDRESS                12
-#define ACPI_RSD_SOURCE                 13
+typedef enum {
+       ACPI_RSD_TITLE = 0,
+       ACPI_RSD_1BITFLAG,
+       ACPI_RSD_2BITFLAG,
+       ACPI_RSD_3BITFLAG,
+       ACPI_RSD_ADDRESS,
+       ACPI_RSD_DWORDLIST,
+       ACPI_RSD_LITERAL,
+       ACPI_RSD_LONGLIST,
+       ACPI_RSD_SHORTLIST,
+       ACPI_RSD_SHORTLISTX,
+       ACPI_RSD_SOURCE,
+       ACPI_RSD_STRING,
+       ACPI_RSD_UINT8,
+       ACPI_RSD_UINT16,
+       ACPI_RSD_UINT32,
+       ACPI_RSD_UINT64,
+       ACPI_RSD_WORDLIST
+} ACPI_RSDUMP_OPCODES;
 
 /* restore default alignment */
 
@@ -138,13 +158,18 @@ typedef const struct acpi_rsdump_info {
 /* Resource tables indexed by internal resource type */
 
 extern const u8 acpi_gbl_aml_resource_sizes[];
+extern const u8 acpi_gbl_aml_resource_serial_bus_sizes[];
 extern struct acpi_rsconvert_info *acpi_gbl_set_resource_dispatch[];
 
 /* Resource tables indexed by raw AML resource descriptor type */
 
 extern const u8 acpi_gbl_resource_struct_sizes[];
+extern const u8 acpi_gbl_resource_struct_serial_bus_sizes[];
 extern struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[];
 
+extern struct acpi_rsconvert_info
+    *acpi_gbl_convert_resource_serial_bus_dispatch[];
+
 struct acpi_vendor_walk_info {
        struct acpi_vendor_uuid *uuid;
        struct acpi_buffer *buffer;
@@ -190,6 +215,10 @@ acpi_status
 acpi_rs_set_srs_method_data(struct acpi_namespace_node *node,
                            struct acpi_buffer *ret_buffer);
 
+acpi_status
+acpi_rs_get_aei_method_data(struct acpi_namespace_node *node,
+                           struct acpi_buffer *ret_buffer);
+
 /*
  * rscalc
  */
@@ -293,6 +322,11 @@ extern struct acpi_rsconvert_info acpi_rs_convert_address16[];
 extern struct acpi_rsconvert_info acpi_rs_convert_ext_irq[];
 extern struct acpi_rsconvert_info acpi_rs_convert_address64[];
 extern struct acpi_rsconvert_info acpi_rs_convert_ext_address64[];
+extern struct acpi_rsconvert_info acpi_rs_convert_gpio[];
+extern struct acpi_rsconvert_info acpi_rs_convert_fixed_dma[];
+extern struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[];
+extern struct acpi_rsconvert_info acpi_rs_convert_spi_serial_bus[];
+extern struct acpi_rsconvert_info acpi_rs_convert_uart_serial_bus[];
 
 /* These resources require separate get/set tables */
 
@@ -310,6 +344,7 @@ extern struct acpi_rsconvert_info acpi_rs_set_vendor[];
  * rsinfo
  */
 extern struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[];
+extern struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[];
 
 /*
  * rsdump
@@ -331,6 +366,12 @@ extern struct acpi_rsdump_info acpi_rs_dump_address64[];
 extern struct acpi_rsdump_info acpi_rs_dump_ext_address64[];
 extern struct acpi_rsdump_info acpi_rs_dump_ext_irq[];
 extern struct acpi_rsdump_info acpi_rs_dump_generic_reg[];
+extern struct acpi_rsdump_info acpi_rs_dump_gpio[];
+extern struct acpi_rsdump_info acpi_rs_dump_fixed_dma[];
+extern struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[];
+extern struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[];
+extern struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[];
+extern struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[];
 #endif
 
 #endif                         /* __ACRESRC_H__ */
index 1623b245dde23b226ae70d1c8233e89425b507d2..0404df605bc187940b0a82c51b5905bb83a4acc9 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 967f08124eba46ae53684bfd0347ca5da14f740f..d5bec304c823387bfc652cf7140b5e47dfb0516f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 99c140d8e348b38c364c94352af16c86de7b164d..925ccf22101b45adcb66817c736195adbcbf975f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,7 @@
 #define _ACUTILS_H
 
 extern const u8 acpi_gbl_resource_aml_sizes[];
+extern const u8 acpi_gbl_resource_aml_serial_bus_sizes[];
 
 /* Strings used by the disassembler and debugger resource dump routines */
 
@@ -578,6 +579,24 @@ acpi_ut_create_list(char *list_name,
 
 #endif                         /* ACPI_DBG_TRACK_ALLOCATIONS */
 
+/*
+ * utaddress - address range check
+ */
+acpi_status
+acpi_ut_add_address_range(acpi_adr_space_type space_id,
+                         acpi_physical_address address,
+                         u32 length, struct acpi_namespace_node *region_node);
+
+void
+acpi_ut_remove_address_range(acpi_adr_space_type space_id,
+                            struct acpi_namespace_node *region_node);
+
+u32
+acpi_ut_check_address_range(acpi_adr_space_type space_id,
+                           acpi_physical_address address, u32 length, u8 warn);
+
+void acpi_ut_delete_address_lists(void);
+
 /*
  * utxferror - various error/warning output functions
  */
index 1077f17859ed3d3fb74d2280966b2a847025e424..905280fec0fa0a132049318fa36953b347a0c324 100644 (file)
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define AML_LLESSEQUAL_OP           (u16) 0x9294
 #define AML_LNOTEQUAL_OP            (u16) 0x9293
 
+/*
+ * Opcodes for "Field" operators
+ */
+#define AML_FIELD_OFFSET_OP         (u8) 0x00
+#define AML_FIELD_ACCESS_OP         (u8) 0x01
+#define AML_FIELD_CONNECTION_OP     (u8) 0x02  /* ACPI 5.0 */
+#define AML_FIELD_EXT_ACCESS_OP     (u8) 0x03  /* ACPI 5.0 */
+
 /*
  * Internal opcodes
  * Use only "Unknown" AML opcodes, don't attempt to use
 #define AML_INT_METHODCALL_OP       (u16) 0x0035
 #define AML_INT_RETURN_VALUE_OP     (u16) 0x0036
 #define AML_INT_EVAL_SUBTREE_OP     (u16) 0x0037
+#define AML_INT_CONNECTION_OP       (u16) 0x0038
+#define AML_INT_EXTACCESSFIELD_OP   (u16) 0x0039
 
 #define ARG_NONE                    0x0
 
@@ -456,13 +466,16 @@ typedef enum {
  * access_as keyword
  */
 typedef enum {
-       AML_FIELD_ATTRIB_SMB_QUICK = 0x02,
-       AML_FIELD_ATTRIB_SMB_SEND_RCV = 0x04,
-       AML_FIELD_ATTRIB_SMB_BYTE = 0x06,
-       AML_FIELD_ATTRIB_SMB_WORD = 0x08,
-       AML_FIELD_ATTRIB_SMB_BLOCK = 0x0A,
-       AML_FIELD_ATTRIB_SMB_WORD_CALL = 0x0C,
-       AML_FIELD_ATTRIB_SMB_BLOCK_CALL = 0x0D
+       AML_FIELD_ATTRIB_QUICK = 0x02,
+       AML_FIELD_ATTRIB_SEND_RCV = 0x04,
+       AML_FIELD_ATTRIB_BYTE = 0x06,
+       AML_FIELD_ATTRIB_WORD = 0x08,
+       AML_FIELD_ATTRIB_BLOCK = 0x0A,
+       AML_FIELD_ATTRIB_MULTIBYTE = 0x0B,
+       AML_FIELD_ATTRIB_WORD_CALL = 0x0C,
+       AML_FIELD_ATTRIB_BLOCK_CALL = 0x0D,
+       AML_FIELD_ATTRIB_RAW_BYTES = 0x0E,
+       AML_FIELD_ATTRIB_RAW_PROCESS = 0x0F
 } AML_ACCESS_ATTRIBUTE;
 
 /* Bit fields in the AML method_flags byte */
index 59122cde247c2042e1121e6f33926eba1ec61cc1..7b2128f274e71a10f2331ca8d42abd78af166677 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define ACPI_RESTAG_TYPESPECIFICATTRIBUTES      "_ATT"
 #define ACPI_RESTAG_BASEADDRESS                 "_BAS"
 #define ACPI_RESTAG_BUSMASTER                   "_BM_" /* Master(1), Slave(0) */
+#define ACPI_RESTAG_DEBOUNCETIME                "_DBT"
 #define ACPI_RESTAG_DECODE                      "_DEC"
+#define ACPI_RESTAG_DEVICEPOLARITY              "_DPL"
 #define ACPI_RESTAG_DMA                         "_DMA"
 #define ACPI_RESTAG_DMATYPE                     "_TYP" /* Compatible(0), A(1), B(2), F(3) */
+#define ACPI_RESTAG_DRIVESTRENGTH               "_DRS"
+#define ACPI_RESTAG_ENDIANNESS                  "_END"
+#define ACPI_RESTAG_FLOWCONTROL                 "_FLC"
 #define ACPI_RESTAG_GRANULARITY                 "_GRA"
 #define ACPI_RESTAG_INTERRUPT                   "_INT"
 #define ACPI_RESTAG_INTERRUPTLEVEL              "_LL_" /* active_lo(1), active_hi(0) */
 #define ACPI_RESTAG_INTERRUPTSHARE              "_SHR" /* Shareable(1), no_share(0) */
 #define ACPI_RESTAG_INTERRUPTTYPE               "_HE_" /* Edge(1), Level(0) */
+#define ACPI_RESTAG_IORESTRICTION               "_IOR"
 #define ACPI_RESTAG_LENGTH                      "_LEN"
+#define ACPI_RESTAG_LINE                        "_LIN"
 #define ACPI_RESTAG_MEMATTRIBUTES               "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */
 #define ACPI_RESTAG_MEMTYPE                     "_MEM" /* non_cache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */
 #define ACPI_RESTAG_MAXADDR                     "_MAX"
 #define ACPI_RESTAG_MINADDR                     "_MIN"
 #define ACPI_RESTAG_MAXTYPE                     "_MAF"
 #define ACPI_RESTAG_MINTYPE                     "_MIF"
+#define ACPI_RESTAG_MODE                        "_MOD"
+#define ACPI_RESTAG_PARITY                      "_PAR"
+#define ACPI_RESTAG_PHASE                       "_PHA"
+#define ACPI_RESTAG_PIN                         "_PIN"
+#define ACPI_RESTAG_PINCONFIG                   "_PPI"
+#define ACPI_RESTAG_POLARITY                    "_POL"
 #define ACPI_RESTAG_REGISTERBITOFFSET           "_RBO"
 #define ACPI_RESTAG_REGISTERBITWIDTH            "_RBW"
 #define ACPI_RESTAG_RANGETYPE                   "_RNG"
 #define ACPI_RESTAG_READWRITETYPE               "_RW_" /* read_only(0), Writeable (1) */
+#define ACPI_RESTAG_LENGTH_RX                   "_RXL"
+#define ACPI_RESTAG_LENGTH_TX                   "_TXL"
+#define ACPI_RESTAG_SLAVEMODE                   "_SLV"
+#define ACPI_RESTAG_SPEED                       "_SPE"
+#define ACPI_RESTAG_STOPBITS                    "_STB"
 #define ACPI_RESTAG_TRANSLATION                 "_TRA"
 #define ACPI_RESTAG_TRANSTYPE                   "_TRS" /* Sparse(1), Dense(0) */
 #define ACPI_RESTAG_TYPE                        "_TTP" /* Translation(1), Static (0) */
 #define ACPI_RESTAG_XFERTYPE                    "_SIZ" /* 8(0), 8_and16(1), 16(2) */
+#define ACPI_RESTAG_VENDORDATA                  "_VEN"
 
 /* Default sizes for "small" resource descriptors */
 
 #define ASL_RDESC_END_DEPEND_SIZE               0x00
 #define ASL_RDESC_IO_SIZE                       0x07
 #define ASL_RDESC_FIXED_IO_SIZE                 0x03
+#define ASL_RDESC_FIXED_DMA_SIZE                0x05
 #define ASL_RDESC_END_TAG_SIZE                  0x01
 
 struct asl_resource_node {
@@ -164,6 +184,12 @@ struct aml_resource_end_tag {
        AML_RESOURCE_SMALL_HEADER_COMMON u8 checksum;
 };
 
+struct aml_resource_fixed_dma {
+       AML_RESOURCE_SMALL_HEADER_COMMON u16 request_lines;
+       u16 channels;
+       u8 width;
+};
+
 /*
  * LARGE descriptors
  */
@@ -263,6 +289,110 @@ struct aml_resource_generic_register {
        u64 address;
 };
 
+/* Common descriptor for gpio_int and gpio_io (ACPI 5.0) */
+
+struct aml_resource_gpio {
+       AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id;
+       u8 connection_type;
+       u16 flags;
+       u16 int_flags;
+       u8 pin_config;
+       u16 drive_strength;
+       u16 debounce_timeout;
+       u16 pin_table_offset;
+       u8 res_source_index;
+       u16 res_source_offset;
+       u16 vendor_offset;
+       u16 vendor_length;
+       /*
+        * Optional fields follow immediately:
+        * 1) PIN list (Words)
+        * 2) Resource Source String
+        * 3) Vendor Data bytes
+        */
+};
+
+#define AML_RESOURCE_GPIO_REVISION              1      /* ACPI 5.0 */
+
+/* Values for connection_type above */
+
+#define AML_RESOURCE_GPIO_TYPE_INT              0
+#define AML_RESOURCE_GPIO_TYPE_IO               1
+#define AML_RESOURCE_MAX_GPIOTYPE               1
+
+/* Common preamble for all serial descriptors (ACPI 5.0) */
+
+#define AML_RESOURCE_SERIAL_COMMON \
+       u8                              revision_id; \
+       u8                              res_source_index; \
+       u8                              type; \
+       u8                              flags; \
+       u16                             type_specific_flags; \
+       u8                              type_revision_id; \
+       u16                             type_data_length; \
+
+/* Values for the type field above */
+
+#define AML_RESOURCE_I2C_SERIALBUSTYPE          1
+#define AML_RESOURCE_SPI_SERIALBUSTYPE          2
+#define AML_RESOURCE_UART_SERIALBUSTYPE         3
+#define AML_RESOURCE_MAX_SERIALBUSTYPE          3
+#define AML_RESOURCE_VENDOR_SERIALBUSTYPE       192    /* Vendor defined is 0xC0-0xFF (NOT SUPPORTED) */
+
+struct aml_resource_common_serialbus {
+AML_RESOURCE_LARGE_HEADER_COMMON AML_RESOURCE_SERIAL_COMMON};
+
+struct aml_resource_i2c_serialbus {
+       AML_RESOURCE_LARGE_HEADER_COMMON
+           AML_RESOURCE_SERIAL_COMMON u32 connection_speed;
+       u16 slave_address;
+       /*
+        * Optional fields follow immediately:
+        * 1) Vendor Data bytes
+        * 2) Resource Source String
+        */
+};
+
+#define AML_RESOURCE_I2C_REVISION               1      /* ACPI 5.0 */
+#define AML_RESOURCE_I2C_TYPE_REVISION          1      /* ACPI 5.0 */
+#define AML_RESOURCE_I2C_MIN_DATA_LEN           6
+
+struct aml_resource_spi_serialbus {
+       AML_RESOURCE_LARGE_HEADER_COMMON
+           AML_RESOURCE_SERIAL_COMMON u32 connection_speed;
+       u8 data_bit_length;
+       u8 clock_phase;
+       u8 clock_polarity;
+       u16 device_selection;
+       /*
+        * Optional fields follow immediately:
+        * 1) Vendor Data bytes
+        * 2) Resource Source String
+        */
+};
+
+#define AML_RESOURCE_SPI_REVISION               1      /* ACPI 5.0 */
+#define AML_RESOURCE_SPI_TYPE_REVISION          1      /* ACPI 5.0 */
+#define AML_RESOURCE_SPI_MIN_DATA_LEN           9
+
+struct aml_resource_uart_serialbus {
+       AML_RESOURCE_LARGE_HEADER_COMMON
+           AML_RESOURCE_SERIAL_COMMON u32 default_baud_rate;
+       u16 rx_fifo_size;
+       u16 tx_fifo_size;
+       u8 parity;
+       u8 lines_enabled;
+       /*
+        * Optional fields follow immediately:
+        * 1) Vendor Data bytes
+        * 2) Resource Source String
+        */
+};
+
+#define AML_RESOURCE_UART_REVISION              1      /* ACPI 5.0 */
+#define AML_RESOURCE_UART_TYPE_REVISION         1      /* ACPI 5.0 */
+#define AML_RESOURCE_UART_MIN_DATA_LEN          10
+
 /* restore default alignment */
 
 #pragma pack()
@@ -284,6 +414,7 @@ union aml_resource {
        struct aml_resource_end_dependent end_dpf;
        struct aml_resource_io io;
        struct aml_resource_fixed_io fixed_io;
+       struct aml_resource_fixed_dma fixed_dma;
        struct aml_resource_vendor_small vendor_small;
        struct aml_resource_end_tag end_tag;
 
@@ -299,6 +430,11 @@ union aml_resource {
        struct aml_resource_address64 address64;
        struct aml_resource_extended_address64 ext_address64;
        struct aml_resource_extended_irq extended_irq;
+       struct aml_resource_gpio gpio;
+       struct aml_resource_i2c_serialbus i2c_serial_bus;
+       struct aml_resource_spi_serialbus spi_serial_bus;
+       struct aml_resource_uart_serialbus uart_serial_bus;
+       struct aml_resource_common_serialbus common_serial_bus;
 
        /* Utility overlays */
 
index 8c7b99728aa23163e77178a6748ddd5e699c8e45..80eb1900297f549f8191b8d3deb4b90ad80863b8 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -250,6 +250,13 @@ acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc)
        status = acpi_ds_execute_arguments(node, node->parent,
                                           extra_desc->extra.aml_length,
                                           extra_desc->extra.aml_start);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
+       status = acpi_ut_add_address_range(obj_desc->region.space_id,
+                                          obj_desc->region.address,
+                                          obj_desc->region.length, node);
        return_ACPI_STATUS(status);
 }
 
@@ -384,8 +391,15 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
 
        /* Execute the argument AML */
 
-       status = acpi_ds_execute_arguments(node, node->parent,
+       status = acpi_ds_execute_arguments(node, extra_desc->extra.scope_node,
                                           extra_desc->extra.aml_length,
                                           extra_desc->extra.aml_start);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
+       status = acpi_ut_add_address_range(obj_desc->region.space_id,
+                                          obj_desc->region.address,
+                                          obj_desc->region.length, node);
        return_ACPI_STATUS(status);
 }
index 26c49fff58da0fecbe83c2d70bfaa825eb2c90b2..effe4ca1133fd7cd93ebb1ab397d8be0ffe68e72 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 34be60c0e4484b880f6bf2da883e7ba1e7311ecd..cd243cf2cab2373f25c40f076b2d211b8f5641a2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -221,6 +221,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
 {
        acpi_status status;
        u64 position;
+       union acpi_parse_object *child;
 
        ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info);
 
@@ -232,10 +233,11 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
 
        while (arg) {
                /*
-                * Three types of field elements are handled:
-                * 1) Offset - specifies a bit offset
-                * 2) access_as - changes the access mode
-                * 3) Name - Enters a new named field into the namespace
+                * Four types of field elements are handled:
+                * 1) Name - Enters a new named field into the namespace
+                * 2) Offset - specifies a bit offset
+                * 3) access_as - changes the access mode/attributes
+                * 4) Connection - Associate a resource template with the field
                 */
                switch (arg->common.aml_opcode) {
                case AML_INT_RESERVEDFIELD_OP:
@@ -253,21 +255,70 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
                        break;
 
                case AML_INT_ACCESSFIELD_OP:
-
+               case AML_INT_EXTACCESSFIELD_OP:
                        /*
-                        * Get a new access_type and access_attribute -- to be used for all
-                        * field units that follow, until field end or another access_as
-                        * keyword.
+                        * Get new access_type, access_attribute, and access_length fields
+                        * -- to be used for all field units that follow, until the
+                        * end-of-field or another access_as keyword is encountered.
+                        * NOTE. These three bytes are encoded in the integer value
+                        * of the parseop for convenience.
                         *
                         * In field_flags, preserve the flag bits other than the
-                        * ACCESS_TYPE bits
+                        * ACCESS_TYPE bits.
                         */
+
+                       /* access_type (byte_acc, word_acc, etc.) */
+
                        info->field_flags = (u8)
                            ((info->
                              field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) |
-                            ((u8) ((u32) arg->common.value.integer >> 8)));
+                            ((u8)((u32)(arg->common.value.integer & 0x07))));
+
+                       /* access_attribute (attrib_quick, attrib_byte, etc.) */
+
+                       info->attribute =
+                           (u8)((arg->common.value.integer >> 8) & 0xFF);
+
+                       /* access_length (for serial/buffer protocols) */
+
+                       info->access_length =
+                           (u8)((arg->common.value.integer >> 16) & 0xFF);
+                       break;
+
+               case AML_INT_CONNECTION_OP:
+                       /*
+                        * Clear any previous connection. New connection is used for all
+                        * fields that follow, similar to access_as
+                        */
+                       info->resource_buffer = NULL;
+                       info->connection_node = NULL;
 
-                       info->attribute = (u8) (arg->common.value.integer);
+                       /*
+                        * A Connection() is either an actual resource descriptor (buffer)
+                        * or a named reference to a resource template
+                        */
+                       child = arg->common.value.arg;
+                       if (child->common.aml_opcode == AML_INT_BYTELIST_OP) {
+                               info->resource_buffer = child->named.data;
+                               info->resource_length =
+                                   (u16)child->named.value.integer;
+                       } else {
+                               /* Lookup the Connection() namepath, it should already exist */
+
+                               status = acpi_ns_lookup(walk_state->scope_info,
+                                                       child->common.value.
+                                                       name, ACPI_TYPE_ANY,
+                                                       ACPI_IMODE_EXECUTE,
+                                                       ACPI_NS_DONT_OPEN_SCOPE,
+                                                       walk_state,
+                                                       &info->connection_node);
+                               if (ACPI_FAILURE(status)) {
+                                       ACPI_ERROR_NAMESPACE(child->common.
+                                                            value.name,
+                                                            status);
+                                       return_ACPI_STATUS(status);
+                               }
+                       }
                        break;
 
                case AML_INT_NAMEDFIELD_OP:
@@ -374,6 +425,8 @@ acpi_ds_create_field(union acpi_parse_object *op,
                }
        }
 
+       ACPI_MEMSET(&info, 0, sizeof(struct acpi_create_field_info));
+
        /* Second arg is the field flags */
 
        arg = arg->common.next;
@@ -386,7 +439,6 @@ acpi_ds_create_field(union acpi_parse_object *op,
        info.region_node = region_node;
 
        status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
-
        return_ACPI_STATUS(status);
 }
 
@@ -474,8 +526,8 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
         */
        while (arg) {
                /*
-                * Ignore OFFSET and ACCESSAS terms here; we are only interested in the
-                * field names in order to enter them into the namespace.
+                * Ignore OFFSET/ACCESSAS/CONNECTION terms here; we are only interested
+                * in the field names in order to enter them into the namespace.
                 */
                if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
                        status = acpi_ns_lookup(walk_state->scope_info,
@@ -651,6 +703,5 @@ acpi_ds_create_index_field(union acpi_parse_object *op,
        info.region_node = region_node;
 
        status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
-
        return_ACPI_STATUS(status);
 }
index a7718bf2b9a18a24e0bdee7554736caa07976c2b..9e5ac7f780a7e1f006bd7bd1dd256a9367859e32 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5d797751e205b363a48e43b6484e2a9cc37fc317..00f5dab5bcc0e7414cb4ea910daf37a6536bbf5c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 905ce29a92e1784c82430c64e527d536e1c7f579..b40bd507be5dc33993e96667b5e2c50ad6395cff 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f42e17e5c252cc98331da46b45270090b093195c..d7045ca3e32a59269e036bac0e05893e0a5d4795 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c627a288e027644d5ef537eb1776098085811ed4..e5eff758510266c0c68a1b772c8004598d1fc2a1 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2c477ce172fad15d44218da1cc66e3377822590e..1abcda31037f20e6988fc073cdc00764f86d7357 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fe40e4c6554f2554310e055cfd96a289c1bf0d89..642f3c053e878e95d1a55fc9b149de42dce19f79 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 324acec1179abaef80d5bb6fdbbd50e2f4106469..552aa3a50c84882ce9c9aa152d1b231bf7f6cd20 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 976318138c56aa983f74f3786f4016040354d44c..ae71477247631074fcc627b1345e307e77b334a9 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 76a661fc1e0933cfa84aba0a6d90a449ac1e5da1..9e9490a9cbf0e22ab16bfa9c32972afbc1971962 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a6c374ef9914e8bb57ad092498ba55feef512145..c9c2ac13e7cc926d977ad8cb3052af532416badc 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d458b041e6510aec0c91cd4b20c0080147975524..6729ebe2f1e669b78f7a30e86efd6445720113e5 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -71,6 +71,12 @@ acpi_status acpi_ev_initialize_events(void)
 
        ACPI_FUNCTION_TRACE(ev_initialize_events);
 
+       /* If Hardware Reduced flag is set, there are no fixed events */
+
+       if (acpi_gbl_reduced_hardware) {
+               return_ACPI_STATUS(AE_OK);
+       }
+
        /*
         * Initialize the Fixed and General Purpose Events. This is done prior to
         * enabling SCIs to prevent interrupts from occurring before the handlers
@@ -111,6 +117,12 @@ acpi_status acpi_ev_install_xrupt_handlers(void)
 
        ACPI_FUNCTION_TRACE(ev_install_xrupt_handlers);
 
+       /* If Hardware Reduced flag is set, there is no ACPI h/w */
+
+       if (acpi_gbl_reduced_hardware) {
+               return_ACPI_STATUS(AE_OK);
+       }
+
        /* Install the SCI handler */
 
        status = acpi_ev_install_sci_handler();
index 56a562a1e5d7bde44f5d15b40dc250843b2de41f..5e5683cb1f0d9445e3d0e0330eaebe3335866cf2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -70,6 +70,12 @@ acpi_status acpi_ev_init_global_lock_handler(void)
 
        ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
 
+       /* If Hardware Reduced flag is set, there is no global lock */
+
+       if (acpi_gbl_reduced_hardware) {
+               return_ACPI_STATUS(AE_OK);
+       }
+
        /* Attempt installation of the global lock handler */
 
        status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
index 65c79add3b1982ae3432a830c4c94f37be60f39d..9e88cb6fb25ea6b05a0befc926b3986a66ac9fd3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ca2c41a5331177707e46bf7b0d4f9407e8a24478..be75339cd5dd2c31731187a791d94b1829b97945 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ce9aa9f9a9724e818d5d6e6fe568e35a3bf9d39c..adf7494da9dbdcfb03e1843ea559adbbf945a889 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 80a81d0c4a80d36049aceac84b78ead5dffe0481..25073932aa10d373d2e838d8517f7209fe0b4425 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d0b3318444273977a382afb74ffcc5a0ed2ddb65..84966f4164638573082ce23373460df4297b6eb2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f0edf5c43c035f0da64345ffe30894099beecc2d..1b0180a1b798bb0184241ac12d75937b55d74902 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -329,6 +329,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
  * FUNCTION:    acpi_ev_address_space_dispatch
  *
  * PARAMETERS:  region_obj          - Internal region object
+ *              field_obj           - Corresponding field. Can be NULL.
  *              Function            - Read or Write operation
  *              region_offset       - Where in the region to read or write
  *              bit_width           - Field width in bits (8, 16, 32, or 64)
@@ -344,6 +345,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
 
 acpi_status
 acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
+                              union acpi_operand_object *field_obj,
                               u32 function,
                               u32 region_offset, u32 bit_width, u64 *value)
 {
@@ -353,6 +355,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
        union acpi_operand_object *handler_desc;
        union acpi_operand_object *region_obj2;
        void *region_context = NULL;
+       struct acpi_connection_info *context;
 
        ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
 
@@ -375,6 +378,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                return_ACPI_STATUS(AE_NOT_EXIST);
        }
 
+       context = handler_desc->address_space.context;
+
        /*
         * It may be the case that the region has never been initialized.
         * Some types of regions require special init code
@@ -404,8 +409,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                acpi_ex_exit_interpreter();
 
                status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
-                                     handler_desc->address_space.context,
-                                     &region_context);
+                                     context, &region_context);
 
                /* Re-enter the interpreter */
 
@@ -455,6 +459,25 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                          acpi_ut_get_region_name(region_obj->region.
                                                  space_id)));
 
+       /*
+        * Special handling for generic_serial_bus and general_purpose_io:
+        * There are three extra parameters that must be passed to the
+        * handler via the context:
+        *   1) Connection buffer, a resource template from Connection() op.
+        *   2) Length of the above buffer.
+        *   3) Actual access length from the access_as() op.
+        */
+       if (((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) ||
+            (region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) &&
+           context && field_obj) {
+
+               /* Get the Connection (resource_template) buffer */
+
+               context->connection = field_obj->field.resource_buffer;
+               context->length = field_obj->field.resource_length;
+               context->access_length = field_obj->field.access_length;
+       }
+
        if (!(handler_desc->address_space.handler_flags &
              ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
                /*
@@ -469,7 +492,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
 
        status = handler(function,
                         (region_obj->region.address + region_offset),
-                        bit_width, value, handler_desc->address_space.context,
+                        bit_width, value, context,
                         region_obj2->extra.region_context);
 
        if (ACPI_FAILURE(status)) {
index 55a5d35ef34a0d2f85e86020b96d305dd25b356f..819c17f5897ab664b67f9656803986ae6912ad58 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2ebd40e1a3ef947ff7672afde21c6f211d33ae00..26065c612e7673d2c376741da9dbcef3dceefb2b 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f4f523bf59390108e5095a303038da3ce872f345..61944e89565a31aa7d82dcc291da7296e28a6c93 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 20516e599476c6b59cbb100d7dfdd01357ef0273..1768bbec10023613fdce37d84f400907a69c8f8b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f06a3ee356ba72048b8a2fac77faeaf0324ec5e0..33388fd69df448155c51154bfe1f5eb332580600 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index aee887e3ca5c6ca57ac76de607e622b581f60e03..6019208cd4b6f522227b70cb5577f13406b5b221 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 745a42b401f5030bc88b11b1b89aa2b21a455b14..c86d44e41bc85bf8935a56c4a2f5c4e348bd0dc7 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -297,9 +297,9 @@ acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer)
        /* Bytewise reads */
 
        for (i = 0; i < length; i++) {
-               status = acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
-                                                       region_offset, 8,
-                                                       &value);
+               status =
+                   acpi_ev_address_space_dispatch(obj_desc, NULL, ACPI_READ,
+                                                  region_offset, 8, &value);
                if (ACPI_FAILURE(status)) {
                        return status;
                }
index 74162a11817dc9b6bff8e30ba2d039a7c1ec47a9..e385436bd42422ef81ad64ca2decfa9a14eaeae7 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 110711afada8be5c0b769c693c6fd3b624251ef4..3f5bc998c1cb15fc7f9e212faa97552b0e87465e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -267,7 +267,7 @@ acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state)
  *
  * PARAMETERS:  aml_start           - Pointer to the region declaration AML
  *              aml_length          - Max length of the declaration AML
- *              region_space        - space_iD for the region
+ *              space_id            - Address space ID for the region
  *              walk_state          - Current state
  *
  * RETURN:      Status
@@ -279,7 +279,7 @@ acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state)
 acpi_status
 acpi_ex_create_region(u8 * aml_start,
                      u32 aml_length,
-                     u8 region_space, struct acpi_walk_state *walk_state)
+                     u8 space_id, struct acpi_walk_state *walk_state)
 {
        acpi_status status;
        union acpi_operand_object *obj_desc;
@@ -304,16 +304,19 @@ acpi_ex_create_region(u8 * aml_start,
         * Space ID must be one of the predefined IDs, or in the user-defined
         * range
         */
-       if ((region_space >= ACPI_NUM_PREDEFINED_REGIONS) &&
-           (region_space < ACPI_USER_REGION_BEGIN) &&
-           (region_space != ACPI_ADR_SPACE_DATA_TABLE)) {
-               ACPI_ERROR((AE_INFO, "Invalid AddressSpace type 0x%X",
-                           region_space));
-               return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
+       if (!acpi_is_valid_space_id(space_id)) {
+               /*
+                * Print an error message, but continue. We don't want to abort
+                * a table load for this exception. Instead, if the region is
+                * actually used at runtime, abort the executing method.
+                */
+               ACPI_ERROR((AE_INFO,
+                           "Invalid/unknown Address Space ID: 0x%2.2X",
+                           space_id));
        }
 
        ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Region Type - %s (0x%X)\n",
-                         acpi_ut_get_region_name(region_space), region_space));
+                         acpi_ut_get_region_name(space_id), space_id));
 
        /* Create the region descriptor */
 
@@ -330,10 +333,16 @@ acpi_ex_create_region(u8 * aml_start,
        region_obj2 = obj_desc->common.next_object;
        region_obj2->extra.aml_start = aml_start;
        region_obj2->extra.aml_length = aml_length;
+       if (walk_state->scope_info) {
+               region_obj2->extra.scope_node =
+                   walk_state->scope_info->scope.node;
+       } else {
+               region_obj2->extra.scope_node = node;
+       }
 
        /* Init the region from the operands */
 
-       obj_desc->region.space_id = region_space;
+       obj_desc->region.space_id = space_id;
        obj_desc->region.address = 0;
        obj_desc->region.length = 0;
        obj_desc->region.node = node;
index c7a2f1edd28276389d0a61bc5674ea6ee7e89b5d..e211e9c192159b10af4c9a68bc17dfba742b57fd 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 61b8c0e8b74d1b5bc115addeb1d04da535401b03..2a6ac0a3bc1e661b25876a1247fbe763279ef91d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -192,10 +192,13 @@ static struct acpi_exdump_info acpi_ex_dump_buffer_field[3] = {
         "Buffer Object"}
 };
 
-static struct acpi_exdump_info acpi_ex_dump_region_field[3] = {
+static struct acpi_exdump_info acpi_ex_dump_region_field[5] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_region_field), NULL},
        {ACPI_EXD_FIELD, 0, NULL},
-       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(field.region_obj), "Region Object"}
+       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(field.access_length), "AccessLength"},
+       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(field.region_obj), "Region Object"},
+       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(field.resource_buffer),
+        "ResourceBuffer"}
 };
 
 static struct acpi_exdump_info acpi_ex_dump_bank_field[5] = {
index 0bde2230c028ed0f0cc28689e98eacccd7a9bd8b..dc092f5b35d6b8ed0198535a39be122280d7828e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -100,18 +100,25 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
                   (obj_desc->field.region_obj->region.space_id ==
                    ACPI_ADR_SPACE_SMBUS
                    || obj_desc->field.region_obj->region.space_id ==
+                   ACPI_ADR_SPACE_GSBUS
+                   || obj_desc->field.region_obj->region.space_id ==
                    ACPI_ADR_SPACE_IPMI)) {
                /*
-                * This is an SMBus or IPMI read. We must create a buffer to hold
+                * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold
                 * the data and then directly access the region handler.
                 *
-                * Note: Smbus protocol value is passed in upper 16-bits of Function
+                * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function
                 */
                if (obj_desc->field.region_obj->region.space_id ==
                    ACPI_ADR_SPACE_SMBUS) {
                        length = ACPI_SMBUS_BUFFER_SIZE;
                        function =
                            ACPI_READ | (obj_desc->field.attribute << 16);
+               } else if (obj_desc->field.region_obj->region.space_id ==
+                          ACPI_ADR_SPACE_GSBUS) {
+                       length = ACPI_GSBUS_BUFFER_SIZE;
+                       function =
+                           ACPI_READ | (obj_desc->field.attribute << 16);
                } else {        /* IPMI */
 
                        length = ACPI_IPMI_BUFFER_SIZE;
@@ -248,21 +255,23 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
                   (obj_desc->field.region_obj->region.space_id ==
                    ACPI_ADR_SPACE_SMBUS
                    || obj_desc->field.region_obj->region.space_id ==
+                   ACPI_ADR_SPACE_GSBUS
+                   || obj_desc->field.region_obj->region.space_id ==
                    ACPI_ADR_SPACE_IPMI)) {
                /*
-                * This is an SMBus or IPMI write. We will bypass the entire field
+                * This is an SMBus, GSBus or IPMI write. We will bypass the entire field
                 * mechanism and handoff the buffer directly to the handler. For
                 * these address spaces, the buffer is bi-directional; on a write,
                 * return data is returned in the same buffer.
                 *
                 * Source must be a buffer of sufficient size:
-                * ACPI_SMBUS_BUFFER_SIZE or ACPI_IPMI_BUFFER_SIZE.
+                * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
                 *
-                * Note: SMBus protocol type is passed in upper 16-bits of Function
+                * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function
                 */
                if (source_desc->common.type != ACPI_TYPE_BUFFER) {
                        ACPI_ERROR((AE_INFO,
-                                   "SMBus or IPMI write requires Buffer, found type %s",
+                                   "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s",
                                    acpi_ut_get_object_type_name(source_desc)));
 
                        return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
@@ -273,6 +282,11 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
                        length = ACPI_SMBUS_BUFFER_SIZE;
                        function =
                            ACPI_WRITE | (obj_desc->field.attribute << 16);
+               } else if (obj_desc->field.region_obj->region.space_id ==
+                          ACPI_ADR_SPACE_GSBUS) {
+                       length = ACPI_GSBUS_BUFFER_SIZE;
+                       function =
+                           ACPI_WRITE | (obj_desc->field.attribute << 16);
                } else {        /* IPMI */
 
                        length = ACPI_IPMI_BUFFER_SIZE;
@@ -281,7 +295,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
 
                if (source_desc->buffer.length < length) {
                        ACPI_ERROR((AE_INFO,
-                                   "SMBus or IPMI write requires Buffer of length %u, found length %u",
+                                   "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u",
                                    length, source_desc->buffer.length));
 
                        return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
index f915a7f3f921ea6fd43d195425cb9783946cae60..149de45fdaddc659e134903e96689ce64289f31c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -86,6 +86,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
 {
        acpi_status status = AE_OK;
        union acpi_operand_object *rgn_desc;
+       u8 space_id;
 
        ACPI_FUNCTION_TRACE_U32(ex_setup_region, field_datum_byte_offset);
 
@@ -101,6 +102,17 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
                return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
        }
 
+       space_id = rgn_desc->region.space_id;
+
+       /* Validate the Space ID */
+
+       if (!acpi_is_valid_space_id(space_id)) {
+               ACPI_ERROR((AE_INFO,
+                           "Invalid/unknown Address Space ID: 0x%2.2X",
+                           space_id));
+               return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
+       }
+
        /*
         * If the Region Address and Length have not been previously evaluated,
         * evaluate them now and save the results.
@@ -119,11 +131,12 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc,
        }
 
        /*
-        * Exit now for SMBus or IPMI address space, it has a non-linear
+        * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear
         * address space and the request cannot be directly validated
         */
-       if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS ||
-           rgn_desc->region.space_id == ACPI_ADR_SPACE_IPMI) {
+       if (space_id == ACPI_ADR_SPACE_SMBUS ||
+           space_id == ACPI_ADR_SPACE_GSBUS ||
+           space_id == ACPI_ADR_SPACE_IPMI) {
 
                /* SMBus or IPMI has a non-linear address space */
 
@@ -271,11 +284,12 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
 
        /* Invoke the appropriate address_space/op_region handler */
 
-       status =
-           acpi_ev_address_space_dispatch(rgn_desc, function, region_offset,
-                                          ACPI_MUL_8(obj_desc->common_field.
-                                                     access_byte_width),
-                                          value);
+       status = acpi_ev_address_space_dispatch(rgn_desc, obj_desc,
+                                               function, region_offset,
+                                               ACPI_MUL_8(obj_desc->
+                                                          common_field.
+                                                          access_byte_width),
+                                               value);
 
        if (ACPI_FAILURE(status)) {
                if (status == AE_NOT_IMPLEMENTED) {
@@ -316,6 +330,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
 static u8
 acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value)
 {
+       ACPI_FUNCTION_NAME(ex_register_overflow);
 
        if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) {
                /*
@@ -330,6 +345,11 @@ acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value)
                 * The Value is larger than the maximum value that can fit into
                 * the register.
                 */
+               ACPI_ERROR((AE_INFO,
+                           "Index value 0x%8.8X%8.8X overflows field width 0x%X",
+                           ACPI_FORMAT_UINT64(value),
+                           obj_desc->common_field.bit_length));
+
                return (TRUE);
        }
 
index 703d88ed0b3df53dbcfede8511ee95e83d7658d4..0a0893310348e6ad35a8cf6cf1f56d9f1ba18961 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index be1c56ead6535e68b5b73bb22a3a9451506f840d..60933e9dc3c0a6cf07f207cdb8d86894ce03c0da 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 49ec049c157e6b4e86e0d9b1de72f60fe9452b40..fcc75fa27d323d4aa870f4c78c06473830653550 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 236ead14b7f7a2c84f4b381bad84b468f2119456..9ba8c73cea16c2018d2bd1b6baf15f847328add6 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2571b4a310f4bd31119f506a6441877886c1390b..879e8a277b9485ccb7e8deb0cba6742357744db9 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1b48d9d28c9ae055b92e53a06302ae66a079b08f..71fcc65c9ffae718495cb4862d3517e4b4581b62 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f4a2787e8e92b1c178dbbf85b97e2c7218f2054f..0786b86590610e5d64d8a7b8d75344733cbaac2d 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cc95e2000406c3a7a6ff6a9bf63b27752ce008fa..30157f5a12d7d774386ab834c6ee819232f23b2e 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,6 +47,7 @@
 #include "acinterp.h"
 #include "amlcode.h"
 #include "acnamesp.h"
+#include "acdispat.h"
 
 #define _COMPONENT          ACPI_EXECUTER
 ACPI_MODULE_NAME("exprep")
@@ -455,6 +456,30 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
                obj_desc->field.region_obj =
                    acpi_ns_get_attached_object(info->region_node);
 
+               /* Fields specific to generic_serial_bus fields */
+
+               obj_desc->field.access_length = info->access_length;
+
+               if (info->connection_node) {
+                       second_desc = info->connection_node->object;
+                       if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) {
+                               status =
+                                   acpi_ds_get_buffer_arguments(second_desc);
+                               if (ACPI_FAILURE(status)) {
+                                       acpi_ut_delete_object_desc(obj_desc);
+                                       return_ACPI_STATUS(status);
+                               }
+                       }
+
+                       obj_desc->field.resource_buffer =
+                           second_desc->buffer.pointer;
+                       obj_desc->field.resource_length =
+                           (u16)second_desc->buffer.length;
+               } else if (info->resource_buffer) {
+                       obj_desc->field.resource_buffer = info->resource_buffer;
+                       obj_desc->field.resource_length = info->resource_length;
+               }
+
                /* Allow full data read from EC address space */
 
                if ((obj_desc->field.region_obj->region.space_id ==
index f0d5e14f1f2c0040ff84c18a9a0dbaa6e73bcbed..12d51df6d3bf6ad354dc1dd9a3c095d725d61839 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 55997e46948bfed2843f4a603f3871223b8abb4a..fa50e77e64a8cedff0d23c49f9ed46ff11340156 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index db502cd7d9349c2e1b6617319023d3d9f1ed3a5a..6e335dc345285a1bd0523b82c1a3cb3406261b1c 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e3bb00ccdff5982338d5e422e3c4aa643523de1c..a67b1d925dddca807fe3525dd5e2dee4826a53ac 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c0c8842dd344b088649c3bc041d2df787f645ba5..c6cf843cc4c990492441b61fad0839bd6e89efd6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a979017d56b8e5cf23e7672574ed66f83c7b4a79..b35bed52e0616ec34ef94715d21f2e941631f3ee 100644 (file)
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index dc665cc554de762c455f801f57d1e03673c85e9d..65a45d8335c8418882c8dff45b69966406270c06 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index df66e7b686bec836ae4fb2e13e64ac0f21756473..191a129452263e858e35e27551f291156ebda12a 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8ad93146dd3282a984918a1a9b6a4b57b4e5ed41..eb6798ba8b59b092f88019d96d46a04b8637c27f 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -435,4 +435,29 @@ void acpi_ex_integer_to_string(char *out_string, u64 value)
        }
 }
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_is_valid_space_id
+ *
+ * PARAMETERS:  space_id            - ID to be validated
+ *
+ * RETURN:      TRUE if valid/supported ID.
+ *
+ * DESCRIPTION: Validate an operation region space_iD.
+ *
+ ******************************************************************************/
+
+u8 acpi_is_valid_space_id(u8 space_id)
+{
+
+       if ((space_id >= ACPI_NUM_PREDEFINED_REGIONS) &&
+           (space_id < ACPI_USER_REGION_BEGIN) &&
+           (space_id != ACPI_ADR_SPACE_DATA_TABLE) &&
+           (space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
+               return (FALSE);
+       }
+
+       return (TRUE);
+}
+
 #endif
index fc380d3d45ab0f01ca413b7c6795532d65e45ca3..d21ec5f0b3a9a3138da2cd21058b5ecdb7cc9259 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f610d88a66be86b823f6ceed6abd7e2876c3a81e..1a6894afef7972052a08abf756c52f5e8ccad828 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 050fd227951b6835d3be95bfa828fbae7951a3d5..1455ddcdc32ceebcfcdf309c8c1d6627d7d47559 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cc70f3fdcdd1a0f1d4222f6f7e6a84ca9ff7ebf5..4ea4eeb51bfdf588dcbc14e5b8830060e7a42378 100644 (file)
@@ -7,7 +7,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d52da307365006f36a067a3f033cad82fd93ff42..3c4a922a9fc2810b607e47ffd3d799277ffcea5e 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 50d21c40b5c1bdd9767aeee49851cd754f0c917b..d4973d9da9f1ce3ed876941609fda18a83928678 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5f1605874655a2f425aa0c0abd79befcb9684a3c..6e5c43a60bb723a54d7cc15543a11a89b8bcd056 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -134,6 +134,8 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width)
        /* Supported widths are 8/16/32 */
 
        if ((bit_width != 8) && (bit_width != 16) && (bit_width != 32)) {
+               ACPI_ERROR((AE_INFO,
+                           "Bad BitWidth parameter: %8.8X", bit_width));
                return AE_BAD_PARAMETER;
        }
 
index d707756228c2eaddec8d4c99cd00ce3d19b92da8..9d38eb6c0d0b9107866f355c4aa9419937ebb883 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d93172fd15a8cfb38f7102cb799527a0f5a4b2ff..61623f3f6826ccdb6286de6e61e4611be4f6675a 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1d0ef15d158ff72779f32c814238130f13954425..7c3d3ceb98b37798dedaaf059ff50ffedb6a4c8b 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b683cc2ff9d3cc15d0acd687f11a8d70bbcf17b3..b7f2b3be79ac110182f9c17a3d4cecee4462ebf4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2ed294b7a4db9c401d094071c6c104d0c7b974a4..30ea5bc53a78bf75572169b282752f1d70ebf37c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c1bd02b1a058746f820988639baecb4ed73fc2b8..f375cb82e321b7958932be9e4c5bc00e65e3e30c 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fd7c6380e2941b9cf61500ace2d3a6021b80affe..9d84ec2f0211bde65d30d10b6a79b5e0fd313fd0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5f7dc691c1838e0ea65d8d78ba5417e1a056c5ad..5cbf15ffe7d8ed38a38782b26f10114374b109cb 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d5fa520c3de5cb026ec5a4b4c09ff7a410da5552..b20e7c8c3ffbcc7414689f28c242ec8c266a1a21 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3bb8bf105ea2abb151f4e862db5d00339a9972a0..dd77a3ce6e508eb6bb6fa74d3be1a45e268d59f1 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b3234fa795b8591f62db87c30051c144ec250ee2..ec7ba2d3463ccd00a7f3986c8979bec197ff3e57 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c845c8089f39c4190f4896889d308ef546195549..bbe46a447d34d2c9597f0894060e6f05af1645de 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -620,6 +620,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
        case ACPI_PTYPE2_FIXED:
        case ACPI_PTYPE2_MIN:
        case ACPI_PTYPE2_COUNT:
+       case ACPI_PTYPE2_FIX_VAR:
 
                /*
                 * These types all return a single Package that consists of a
@@ -759,6 +760,34 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
                        }
                        break;
 
+               case ACPI_PTYPE2_FIX_VAR:
+                       /*
+                        * Each subpackage has a fixed number of elements and an
+                        * optional element
+                        */
+                       expected_count =
+                           package->ret_info.count1 + package->ret_info.count2;
+                       if (sub_package->package.count < expected_count) {
+                               goto package_too_small;
+                       }
+
+                       status =
+                           acpi_ns_check_package_elements(data, sub_elements,
+                                                          package->ret_info.
+                                                          object_type1,
+                                                          package->ret_info.
+                                                          count1,
+                                                          package->ret_info.
+                                                          object_type2,
+                                                          sub_package->package.
+                                                          count -
+                                                          package->ret_info.
+                                                          count1, 0);
+                       if (ACPI_FAILURE(status)) {
+                               return (status);
+                       }
+                       break;
+
                case ACPI_PTYPE2_FIXED:
 
                        /* Each sub-package has a fixed length */
index ac7b854b0bd740fb16ee73c6f5df978d79952900..9c35d20eb52b14fc9c4a5e238017852d934aee7c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -634,6 +634,7 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
        case ACPI_PTYPE2_FIXED:
        case ACPI_PTYPE2_MIN:
        case ACPI_PTYPE2_REV_FIXED:
+       case ACPI_PTYPE2_FIX_VAR:
                break;
 
        default:
index 024c4f263f872fc550567e56a5d4a32c369071de..726bc8e687f7a68bca895b881ce2bea09823fd87 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -467,11 +467,12 @@ acpi_ns_repair_HID(struct acpi_predefined_data *data,
        }
 
        /*
-        * Copy and uppercase the string. From the ACPI specification:
+        * Copy and uppercase the string. From the ACPI 5.0 specification:
         *
         * A valid PNP ID must be of the form "AAA####" where A is an uppercase
         * letter and # is a hex digit. A valid ACPI ID must be of the form
-        * "ACPI####" where # is a hex digit.
+        * "NNNN####" where N is an uppercase letter or decimal digit, and
+        * # is a hex digit.
         */
        for (dest = new_string->string.pointer; *source; dest++, source++) {
                *dest = (char)ACPI_TOUPPER(*source);
index 28b0d7a62b9976c5cf04e1043f5293f81f8189f0..507043d6611428e939182515449eb288fde51395 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cb1b104a69a20211804e8c5124f07c8d6c9ea9b9..a535b7afda5cc3daf2cb80a28fd03fa18c22a6df 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 345f0c3c6ad2a336a1e8982a318ec2ca7742ce7a..f69895a548957761476e6ee4f5f29805729b6187 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e7f016d1b226edcd295f5a60adc73a0632d8b3ac..71d15f61807ba312e9f60b617c215a23ce643f9e 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 83bf930243034608eeda0b5467883c1782c7c3c8..af401c9c4dfc04f51c5d2091b8aac799873fbd10 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 57e6d825ed8411c8d0bd16c1de6208686a920244..880a605cee20e24b59d8173c0010c9ed456b11c2 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e1fad0ee0136760806f8e3dcf1e1cb76b1509e7a..5ac36aba507c348192485115399f9cd8b02944fc 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -484,34 +484,54 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state,
 static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
                                                       *parser_state)
 {
-       u32 aml_offset = (u32)
-           ACPI_PTR_DIFF(parser_state->aml,
-                         parser_state->aml_start);
+       u32 aml_offset;
        union acpi_parse_object *field;
+       union acpi_parse_object *arg = NULL;
        u16 opcode;
        u32 name;
+       u8 access_type;
+       u8 access_attribute;
+       u8 access_length;
+       u32 pkg_length;
+       u8 *pkg_end;
+       u32 buffer_length;
 
        ACPI_FUNCTION_TRACE(ps_get_next_field);
 
+       aml_offset =
+           (u32)ACPI_PTR_DIFF(parser_state->aml, parser_state->aml_start);
+
        /* Determine field type */
 
        switch (ACPI_GET8(parser_state->aml)) {
-       default:
+       case AML_FIELD_OFFSET_OP:
 
-               opcode = AML_INT_NAMEDFIELD_OP;
+               opcode = AML_INT_RESERVEDFIELD_OP;
+               parser_state->aml++;
                break;
 
-       case 0x00:
+       case AML_FIELD_ACCESS_OP:
 
-               opcode = AML_INT_RESERVEDFIELD_OP;
+               opcode = AML_INT_ACCESSFIELD_OP;
                parser_state->aml++;
                break;
 
-       case 0x01:
+       case AML_FIELD_CONNECTION_OP:
 
-               opcode = AML_INT_ACCESSFIELD_OP;
+               opcode = AML_INT_CONNECTION_OP;
+               parser_state->aml++;
+               break;
+
+       case AML_FIELD_EXT_ACCESS_OP:
+
+               opcode = AML_INT_EXTACCESSFIELD_OP;
                parser_state->aml++;
                break;
+
+       default:
+
+               opcode = AML_INT_NAMEDFIELD_OP;
+               break;
        }
 
        /* Allocate a new field op */
@@ -549,16 +569,111 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
                break;
 
        case AML_INT_ACCESSFIELD_OP:
+       case AML_INT_EXTACCESSFIELD_OP:
 
                /*
                 * Get access_type and access_attrib and merge into the field Op
-                * access_type is first operand, access_attribute is second
+                * access_type is first operand, access_attribute is second. stuff
+                * these bytes into the node integer value for convenience.
                 */
-               field->common.value.integer =
-                   (((u32) ACPI_GET8(parser_state->aml) << 8));
+
+               /* Get the two bytes (Type/Attribute) */
+
+               access_type = ACPI_GET8(parser_state->aml);
                parser_state->aml++;
-               field->common.value.integer |= ACPI_GET8(parser_state->aml);
+               access_attribute = ACPI_GET8(parser_state->aml);
                parser_state->aml++;
+
+               field->common.value.integer = (u8)access_type;
+               field->common.value.integer |= (u16)(access_attribute << 8);
+
+               /* This opcode has a third byte, access_length */
+
+               if (opcode == AML_INT_EXTACCESSFIELD_OP) {
+                       access_length = ACPI_GET8(parser_state->aml);
+                       parser_state->aml++;
+
+                       field->common.value.integer |=
+                           (u32)(access_length << 16);
+               }
+               break;
+
+       case AML_INT_CONNECTION_OP:
+
+               /*
+                * Argument for Connection operator can be either a Buffer
+                * (resource descriptor), or a name_string.
+                */
+               if (ACPI_GET8(parser_state->aml) == AML_BUFFER_OP) {
+                       parser_state->aml++;
+
+                       pkg_end = parser_state->aml;
+                       pkg_length =
+                           acpi_ps_get_next_package_length(parser_state);
+                       pkg_end += pkg_length;
+
+                       if (parser_state->aml < pkg_end) {
+
+                               /* Non-empty list */
+
+                               arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP);
+                               if (!arg) {
+                                       return_PTR(NULL);
+                               }
+
+                               /* Get the actual buffer length argument */
+
+                               opcode = ACPI_GET8(parser_state->aml);
+                               parser_state->aml++;
+
+                               switch (opcode) {
+                               case AML_BYTE_OP:       /* AML_BYTEDATA_ARG */
+                                       buffer_length =
+                                           ACPI_GET8(parser_state->aml);
+                                       parser_state->aml += 1;
+                                       break;
+
+                               case AML_WORD_OP:       /* AML_WORDDATA_ARG */
+                                       buffer_length =
+                                           ACPI_GET16(parser_state->aml);
+                                       parser_state->aml += 2;
+                                       break;
+
+                               case AML_DWORD_OP:      /* AML_DWORDATA_ARG */
+                                       buffer_length =
+                                           ACPI_GET32(parser_state->aml);
+                                       parser_state->aml += 4;
+                                       break;
+
+                               default:
+                                       buffer_length = 0;
+                                       break;
+                               }
+
+                               /* Fill in bytelist data */
+
+                               arg->named.value.size = buffer_length;
+                               arg->named.data = parser_state->aml;
+                       }
+
+                       /* Skip to End of byte data */
+
+                       parser_state->aml = pkg_end;
+               } else {
+                       arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP);
+                       if (!arg) {
+                               return_PTR(NULL);
+                       }
+
+                       /* Get the Namestring argument */
+
+                       arg->common.value.name =
+                           acpi_ps_get_next_namestring(parser_state);
+               }
+
+               /* Link the buffer/namestring to parent (CONNECTION_OP) */
+
+               acpi_ps_append_arg(field, arg);
                break;
 
        default:
index 01dd70d1de514eb8e8a03dfbc94995e35a6f90e3..9547ad8a620bfc1e801e30a6bc8dfb1891288fb5 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index bed08de7528c20e1762a8c989e89fece2a368bdf..a0226fdcf75c0406e7f8bc0a9388000985d44637 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -638,7 +638,16 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = {
 
 /* 7E */ ACPI_OP("Timer", ARGP_TIMER_OP, ARGI_TIMER_OP, ACPI_TYPE_ANY,
                 AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R,
-                AML_FLAGS_EXEC_0A_0T_1R)
+                        AML_FLAGS_EXEC_0A_0T_1R),
+
+/* ACPI 5.0 opcodes */
+
+/* 7F */ ACPI_OP("-ConnectField-", ARGP_CONNECTFIELD_OP,
+                        ARGI_CONNECTFIELD_OP, ACPI_TYPE_ANY,
+                        AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS),
+/* 80 */ ACPI_OP("-ExtAccessField-", ARGP_CONNECTFIELD_OP,
+                        ARGI_CONNECTFIELD_OP, ACPI_TYPE_ANY,
+                        AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0)
 
 /*! [End] no source code translation !*/
 };
@@ -657,7 +666,7 @@ static const u8 acpi_gbl_short_op_index[256] = {
 /* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
 /* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX,
 /* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, 0x7D,
-/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x38 */ 0x7F, 0x80, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
 /* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
 /* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
 /* 0x50 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
index 9bb0cbd37b5e678d462702d909d7a165396f2342..2ff9c35a19686be19b16a1b203936a6ca45982bc 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a5faa1323a0290f77676419a07ccc05eed2313e5..c872aa4b926ec52bc1ddbec6921871529b97edcc 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f1464c03aa427865f4601cd01d58712ce7024b39..2b03cdbbe1c0dc49436b6bc089b5a7bd771904db 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -74,6 +74,12 @@ union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn)
 
        ACPI_FUNCTION_ENTRY();
 
+/*
+       if (Op->Common.aml_opcode == AML_INT_CONNECTION_OP)
+       {
+               return (Op->Common.Value.Arg);
+       }
+*/
        /* Get the info structure for this opcode */
 
        op_info = acpi_ps_get_opcode_info(op->common.aml_opcode);
index 7eda78503422b7d651b046c2b05a76ac895d1fb0..13bb131ae12517040401a7cbfa02b8c3c0735422 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3312d6368bf15bba6e193b14e2d3c47cf01dd804..ab96cf47896d33e9a28b7854306c5011dbfff970 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8086805d44946ba73f0f2819271d2077d3755721..9d98c5ff66a5f8c08a0704a658d962b1f2d82ff7 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9e66f90784269243cb5e30f815b50f299c16ccf9..a0305652394f1f03fbebc050e55ce5ad28bd1856 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3a8a89ec2ca4195d14a90b620918f6f4aa9cd881..3c6df4b7eb2ddc200575ea8849b905519efe6f87 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -313,6 +313,38 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed)
                                                          resource_source));
                        break;
 
+               case ACPI_RESOURCE_TYPE_GPIO:
+
+                       total_size =
+                           (acpi_rs_length) (total_size +
+                                             (resource->data.gpio.
+                                              pin_table_length * 2) +
+                                             resource->data.gpio.
+                                             resource_source.string_length +
+                                             resource->data.gpio.
+                                             vendor_length);
+
+                       break;
+
+               case ACPI_RESOURCE_TYPE_SERIAL_BUS:
+
+                       total_size =
+                           acpi_gbl_aml_resource_serial_bus_sizes[resource->
+                                                                  data.
+                                                                  common_serial_bus.
+                                                                  type];
+
+                       total_size = (acpi_rs_length) (total_size +
+                                                      resource->data.
+                                                      i2c_serial_bus.
+                                                      resource_source.
+                                                      string_length +
+                                                      resource->data.
+                                                      i2c_serial_bus.
+                                                      vendor_length);
+
+                       break;
+
                default:
                        break;
                }
@@ -362,10 +394,11 @@ acpi_rs_get_list_length(u8 * aml_buffer,
        u32 extra_struct_bytes;
        u8 resource_index;
        u8 minimum_aml_resource_length;
+       union aml_resource *aml_resource;
 
        ACPI_FUNCTION_TRACE(rs_get_list_length);
 
-       *size_needed = 0;
+       *size_needed = ACPI_RS_SIZE_MIN;        /* Minimum size is one end_tag */
        end_aml = aml_buffer + aml_buffer_length;
 
        /* Walk the list of AML resource descriptors */
@@ -376,9 +409,15 @@ acpi_rs_get_list_length(u8 * aml_buffer,
 
                status = acpi_ut_validate_resource(aml_buffer, &resource_index);
                if (ACPI_FAILURE(status)) {
+                       /*
+                        * Exit on failure. Cannot continue because the descriptor length
+                        * may be bogus also.
+                        */
                        return_ACPI_STATUS(status);
                }
 
+               aml_resource = (void *)aml_buffer;
+
                /* Get the resource length and base (minimum) AML size */
 
                resource_length = acpi_ut_get_resource_length(aml_buffer);
@@ -422,10 +461,8 @@ acpi_rs_get_list_length(u8 * aml_buffer,
 
                case ACPI_RESOURCE_NAME_END_TAG:
                        /*
-                        * End Tag:
-                        * This is the normal exit, add size of end_tag
+                        * End Tag: This is the normal exit
                         */
-                       *size_needed += ACPI_RS_SIZE_MIN;
                        return_ACPI_STATUS(AE_OK);
 
                case ACPI_RESOURCE_NAME_ADDRESS32:
@@ -457,6 +494,33 @@ acpi_rs_get_list_length(u8 * aml_buffer,
                                                         minimum_aml_resource_length);
                        break;
 
+               case ACPI_RESOURCE_NAME_GPIO:
+
+                       /* Vendor data is optional */
+
+                       if (aml_resource->gpio.vendor_length) {
+                               extra_struct_bytes +=
+                                   aml_resource->gpio.vendor_offset -
+                                   aml_resource->gpio.pin_table_offset +
+                                   aml_resource->gpio.vendor_length;
+                       } else {
+                               extra_struct_bytes +=
+                                   aml_resource->large_header.resource_length +
+                                   sizeof(struct aml_resource_large_header) -
+                                   aml_resource->gpio.pin_table_offset;
+                       }
+                       break;
+
+               case ACPI_RESOURCE_NAME_SERIAL_BUS:
+
+                       minimum_aml_resource_length =
+                           acpi_gbl_resource_aml_serial_bus_sizes
+                           [aml_resource->common_serial_bus.type];
+                       extra_struct_bytes +=
+                           aml_resource->common_serial_bus.resource_length -
+                           minimum_aml_resource_length;
+                       break;
+
                default:
                        break;
                }
@@ -467,9 +531,18 @@ acpi_rs_get_list_length(u8 * aml_buffer,
                 * Important: Round the size up for the appropriate alignment. This
                 * is a requirement on IA64.
                 */
-               buffer_size = acpi_gbl_resource_struct_sizes[resource_index] +
-                   extra_struct_bytes;
-               buffer_size = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size);
+               if (acpi_ut_get_resource_type(aml_buffer) ==
+                   ACPI_RESOURCE_NAME_SERIAL_BUS) {
+                       buffer_size =
+                           acpi_gbl_resource_struct_serial_bus_sizes
+                           [aml_resource->common_serial_bus.type] +
+                           extra_struct_bytes;
+               } else {
+                       buffer_size =
+                           acpi_gbl_resource_struct_sizes[resource_index] +
+                           extra_struct_bytes;
+               }
+               buffer_size = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size);
 
                *size_needed += buffer_size;
 
index 4ce6e1147e807993cccc251af32632d0eabca6e8..46d6eb38ae66f5598faba40c70ffaf4466e0459b 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define _COMPONENT          ACPI_RESOURCES
 ACPI_MODULE_NAME("rscreate")
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_buffer_to_resource
+ *
+ * PARAMETERS:  aml_buffer          - Pointer to the resource byte stream
+ *              aml_buffer_length   - Length of the aml_buffer
+ *              resource_ptr        - Where the converted resource is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Convert a raw AML buffer to a resource list
+ *
+ ******************************************************************************/
+acpi_status
+acpi_buffer_to_resource(u8 *aml_buffer,
+                       u16 aml_buffer_length,
+                       struct acpi_resource **resource_ptr)
+{
+       acpi_status status;
+       acpi_size list_size_needed;
+       void *resource;
+       void *current_resource_ptr;
+
+       /*
+        * Note: we allow AE_AML_NO_RESOURCE_END_TAG, since an end tag
+        * is not required here.
+        */
+
+       /* Get the required length for the converted resource */
+
+       status = acpi_rs_get_list_length(aml_buffer, aml_buffer_length,
+                                        &list_size_needed);
+       if (status == AE_AML_NO_RESOURCE_END_TAG) {
+               status = AE_OK;
+       }
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       /* Allocate a buffer for the converted resource */
+
+       resource = ACPI_ALLOCATE_ZEROED(list_size_needed);
+       current_resource_ptr = resource;
+       if (!resource) {
+               return (AE_NO_MEMORY);
+       }
+
+       /* Perform the AML-to-Resource conversion */
+
+       status = acpi_ut_walk_aml_resources(aml_buffer, aml_buffer_length,
+                                           acpi_rs_convert_aml_to_resources,
+                                           &current_resource_ptr);
+       if (status == AE_AML_NO_RESOURCE_END_TAG) {
+               status = AE_OK;
+       }
+       if (ACPI_FAILURE(status)) {
+               ACPI_FREE(resource);
+       } else {
+               *resource_ptr = resource;
+       }
+
+       return (status);
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_rs_create_resource_list
@@ -66,9 +130,10 @@ ACPI_MODULE_NAME("rscreate")
  *              of device resources.
  *
  ******************************************************************************/
+
 acpi_status
 acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer,
-                            struct acpi_buffer *output_buffer)
+                            struct acpi_buffer * output_buffer)
 {
 
        acpi_status status;
index 33db7520c74be0c2937b837b31512dcec49fde58..b4c5811323932324becf8a803a85fc542dc20579 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -61,11 +61,13 @@ static void acpi_rs_out_integer64(char *title, u64 value);
 
 static void acpi_rs_out_title(char *title);
 
-static void acpi_rs_dump_byte_list(u16 length, u8 * data);
+static void acpi_rs_dump_byte_list(u16 length, u8 *data);
 
-static void acpi_rs_dump_dword_list(u8 length, u32 * data);
+static void acpi_rs_dump_word_list(u16 length, u16 *data);
 
-static void acpi_rs_dump_short_byte_list(u8 length, u8 * data);
+static void acpi_rs_dump_dword_list(u8 length, u32 *data);
+
+static void acpi_rs_dump_short_byte_list(u8 length, u8 *data);
 
 static void
 acpi_rs_dump_resource_source(struct acpi_resource_source *resource_source);
@@ -309,6 +311,125 @@ struct acpi_rsdump_info acpi_rs_dump_generic_reg[6] = {
        {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(generic_reg.address), "Address", NULL}
 };
 
+struct acpi_rsdump_info acpi_rs_dump_gpio[16] = {
+       {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_gpio), "GPIO", NULL},
+       {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.revision_id), "RevisionId", NULL},
+       {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.connection_type),
+        "ConnectionType", acpi_gbl_ct_decode},
+       {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.producer_consumer),
+        "ProducerConsumer", acpi_gbl_consume_decode},
+       {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.pin_config), "PinConfig",
+        acpi_gbl_ppc_decode},
+       {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.sharable), "Sharable",
+        acpi_gbl_shr_decode},
+       {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.io_restriction),
+        "IoRestriction", acpi_gbl_ior_decode},
+       {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.triggering), "Triggering",
+        acpi_gbl_he_decode},
+       {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.polarity), "Polarity",
+        acpi_gbl_ll_decode},
+       {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.drive_strength), "DriveStrength",
+        NULL},
+       {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.debounce_timeout),
+        "DebounceTimeout", NULL},
+       {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(gpio.resource_source),
+        "ResourceSource", NULL},
+       {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.pin_table_length),
+        "PinTableLength", NULL},
+       {ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(gpio.pin_table), "PinTable", NULL},
+       {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.vendor_length), "VendorLength",
+        NULL},
+       {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(gpio.vendor_data), "VendorData",
+        NULL},
+};
+
+struct acpi_rsdump_info acpi_rs_dump_fixed_dma[4] = {
+       {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_dma),
+        "FixedDma", NULL},
+       {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.request_lines),
+        "RequestLines", NULL},
+       {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.channels), "Channels",
+        NULL},
+       {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(fixed_dma.width), "TransferWidth",
+        acpi_gbl_dts_decode},
+};
+
+#define ACPI_RS_DUMP_COMMON_SERIAL_BUS \
+       {ACPI_RSD_UINT8,    ACPI_RSD_OFFSET (common_serial_bus.revision_id),    "RevisionId",               NULL}, \
+       {ACPI_RSD_UINT8,    ACPI_RSD_OFFSET (common_serial_bus.type),           "Type",                     acpi_gbl_sbt_decode}, \
+       {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.producer_consumer), "ProducerConsumer",      acpi_gbl_consume_decode}, \
+       {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.slave_mode),     "SlaveMode",                acpi_gbl_sm_decode}, \
+       {ACPI_RSD_UINT8,    ACPI_RSD_OFFSET (common_serial_bus.type_revision_id), "TypeRevisionId",         NULL}, \
+       {ACPI_RSD_UINT16,   ACPI_RSD_OFFSET (common_serial_bus.type_data_length), "TypeDataLength",         NULL}, \
+       {ACPI_RSD_SOURCE,   ACPI_RSD_OFFSET (common_serial_bus.resource_source), "ResourceSource",          NULL}, \
+       {ACPI_RSD_UINT16,   ACPI_RSD_OFFSET (common_serial_bus.vendor_length),  "VendorLength",             NULL}, \
+       {ACPI_RSD_SHORTLISTX,ACPI_RSD_OFFSET (common_serial_bus.vendor_data),   "VendorData",               NULL},
+
+struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[10] = {
+       {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_common_serial_bus),
+        "Common Serial Bus", NULL},
+       ACPI_RS_DUMP_COMMON_SERIAL_BUS
+};
+
+struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[13] = {
+       {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_i2c_serial_bus),
+        "I2C Serial Bus", NULL},
+       ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG,
+                                       ACPI_RSD_OFFSET(i2c_serial_bus.
+                                                       access_mode),
+                                       "AccessMode", acpi_gbl_am_decode},
+       {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(i2c_serial_bus.connection_speed),
+        "ConnectionSpeed", NULL},
+       {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(i2c_serial_bus.slave_address),
+        "SlaveAddress", NULL},
+};
+
+struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[17] = {
+       {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_spi_serial_bus),
+        "Spi Serial Bus", NULL},
+       ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG,
+                                       ACPI_RSD_OFFSET(spi_serial_bus.
+                                                       wire_mode), "WireMode",
+                                       acpi_gbl_wm_decode},
+       {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(spi_serial_bus.device_polarity),
+        "DevicePolarity", acpi_gbl_dp_decode},
+       {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.data_bit_length),
+        "DataBitLength", NULL},
+       {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_phase),
+        "ClockPhase", acpi_gbl_cph_decode},
+       {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_polarity),
+        "ClockPolarity", acpi_gbl_cpo_decode},
+       {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(spi_serial_bus.device_selection),
+        "DeviceSelection", NULL},
+       {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(spi_serial_bus.connection_speed),
+        "ConnectionSpeed", NULL},
+};
+
+struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[19] = {
+       {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_uart_serial_bus),
+        "Uart Serial Bus", NULL},
+       ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_2BITFLAG,
+                                       ACPI_RSD_OFFSET(uart_serial_bus.
+                                                       flow_control),
+                                       "FlowControl", acpi_gbl_fc_decode},
+       {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.stop_bits),
+        "StopBits", acpi_gbl_sb_decode},
+       {ACPI_RSD_3BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.data_bits),
+        "DataBits", acpi_gbl_bpb_decode},
+       {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.endian), "Endian",
+        acpi_gbl_ed_decode},
+       {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.parity), "Parity",
+        acpi_gbl_pt_decode},
+       {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.lines_enabled),
+        "LinesEnabled", NULL},
+       {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.rx_fifo_size),
+        "RxFifoSize", NULL},
+       {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.tx_fifo_size),
+        "TxFifoSize", NULL},
+       {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(uart_serial_bus.default_baud_rate),
+        "ConnectionSpeed", NULL},
+};
+
 /*
  * Tables used for common address descriptor flag fields
  */
@@ -413,7 +534,14 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
                        /* Data items, 8/16/32/64 bit */
 
                case ACPI_RSD_UINT8:
-                       acpi_rs_out_integer8(name, ACPI_GET8(target));
+                       if (table->pointer) {
+                               acpi_rs_out_string(name, ACPI_CAST_PTR(char,
+                                                                      table->
+                                                                      pointer
+                                                                      [*target]));
+                       } else {
+                               acpi_rs_out_integer8(name, ACPI_GET8(target));
+                       }
                        break;
 
                case ACPI_RSD_UINT16:
@@ -444,6 +572,13 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
                                                                       0x03]));
                        break;
 
+               case ACPI_RSD_3BITFLAG:
+                       acpi_rs_out_string(name, ACPI_CAST_PTR(char,
+                                                              table->
+                                                              pointer[*target &
+                                                                      0x07]));
+                       break;
+
                case ACPI_RSD_SHORTLIST:
                        /*
                         * Short byte list (single line output) for DMA and IRQ resources
@@ -456,6 +591,20 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
                        }
                        break;
 
+               case ACPI_RSD_SHORTLISTX:
+                       /*
+                        * Short byte list (single line output) for GPIO vendor data
+                        * Note: The list length is obtained from the previous table entry
+                        */
+                       if (previous_target) {
+                               acpi_rs_out_title(name);
+                               acpi_rs_dump_short_byte_list(*previous_target,
+                                                            *
+                                                            (ACPI_CAST_INDIRECT_PTR
+                                                             (u8, target)));
+                       }
+                       break;
+
                case ACPI_RSD_LONGLIST:
                        /*
                         * Long byte list for Vendor resource data
@@ -480,6 +629,18 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
                        }
                        break;
 
+               case ACPI_RSD_WORDLIST:
+                       /*
+                        * Word list for GPIO Pin Table
+                        * Note: The list length is obtained from the previous table entry
+                        */
+                       if (previous_target) {
+                               acpi_rs_dump_word_list(*previous_target,
+                                                      *(ACPI_CAST_INDIRECT_PTR
+                                                        (u16, target)));
+                       }
+                       break;
+
                case ACPI_RSD_ADDRESS:
                        /*
                         * Common flags for all Address resources
@@ -627,14 +788,20 @@ void acpi_rs_dump_resource_list(struct acpi_resource *resource_list)
 
                /* Dump the resource descriptor */
 
-               acpi_rs_dump_descriptor(&resource_list->data,
-                                       acpi_gbl_dump_resource_dispatch[type]);
+               if (type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
+                       acpi_rs_dump_descriptor(&resource_list->data,
+                                               acpi_gbl_dump_serial_bus_dispatch
+                                               [resource_list->data.
+                                                common_serial_bus.type]);
+               } else {
+                       acpi_rs_dump_descriptor(&resource_list->data,
+                                               acpi_gbl_dump_resource_dispatch
+                                               [type]);
+               }
 
                /* Point to the next resource structure */
 
-               resource_list =
-                   ACPI_ADD_PTR(struct acpi_resource, resource_list,
-                                resource_list->length);
+               resource_list = ACPI_NEXT_RESOURCE(resource_list);
 
                /* Exit when END_TAG descriptor is reached */
 
@@ -768,4 +935,13 @@ static void acpi_rs_dump_dword_list(u8 length, u32 * data)
        }
 }
 
+static void acpi_rs_dump_word_list(u16 length, u16 *data)
+{
+       u16 i;
+
+       for (i = 0; i < length; i++) {
+               acpi_os_printf("%25s%2.2X : %4.4X\n", "Word", i, data[i]);
+       }
+}
+
 #endif
index f9ea60872aa4ddad8cf1cd77c20a61a0ec7c0b41..a9fa5158200b30712155cefbfc9987501cc4142e 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -76,7 +76,10 @@ struct acpi_rsconvert_info *acpi_gbl_set_resource_dispatch[] = {
        acpi_rs_convert_address64,      /* 0x0D, ACPI_RESOURCE_TYPE_ADDRESS64 */
        acpi_rs_convert_ext_address64,  /* 0x0E, ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */
        acpi_rs_convert_ext_irq,        /* 0x0F, ACPI_RESOURCE_TYPE_EXTENDED_IRQ */
-       acpi_rs_convert_generic_reg     /* 0x10, ACPI_RESOURCE_TYPE_GENERIC_REGISTER */
+       acpi_rs_convert_generic_reg,    /* 0x10, ACPI_RESOURCE_TYPE_GENERIC_REGISTER */
+       acpi_rs_convert_gpio,   /* 0x11, ACPI_RESOURCE_TYPE_GPIO */
+       acpi_rs_convert_fixed_dma,      /* 0x12, ACPI_RESOURCE_TYPE_FIXED_DMA */
+       NULL,                   /* 0x13, ACPI_RESOURCE_TYPE_SERIAL_BUS - Use subtype table below */
 };
 
 /* Dispatch tables for AML-to-resource (Get Resource) conversion functions */
@@ -94,7 +97,7 @@ struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[] = {
        acpi_rs_convert_end_dpf,        /* 0x07, ACPI_RESOURCE_NAME_END_DEPENDENT */
        acpi_rs_convert_io,     /* 0x08, ACPI_RESOURCE_NAME_IO */
        acpi_rs_convert_fixed_io,       /* 0x09, ACPI_RESOURCE_NAME_FIXED_IO */
-       NULL,                   /* 0x0A, Reserved */
+       acpi_rs_convert_fixed_dma,      /* 0x0A, ACPI_RESOURCE_NAME_FIXED_DMA */
        NULL,                   /* 0x0B, Reserved */
        NULL,                   /* 0x0C, Reserved */
        NULL,                   /* 0x0D, Reserved */
@@ -114,7 +117,19 @@ struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[] = {
        acpi_rs_convert_address16,      /* 0x08, ACPI_RESOURCE_NAME_ADDRESS16 */
        acpi_rs_convert_ext_irq,        /* 0x09, ACPI_RESOURCE_NAME_EXTENDED_IRQ */
        acpi_rs_convert_address64,      /* 0x0A, ACPI_RESOURCE_NAME_ADDRESS64 */
-       acpi_rs_convert_ext_address64   /* 0x0B, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 */
+       acpi_rs_convert_ext_address64,  /* 0x0B, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 */
+       acpi_rs_convert_gpio,   /* 0x0C, ACPI_RESOURCE_NAME_GPIO */
+       NULL,                   /* 0x0D, Reserved */
+       NULL,                   /* 0x0E, ACPI_RESOURCE_NAME_SERIAL_BUS - Use subtype table below */
+};
+
+/* Subtype table for serial_bus -- I2C, SPI, and UART */
+
+struct acpi_rsconvert_info *acpi_gbl_convert_resource_serial_bus_dispatch[] = {
+       NULL,
+       acpi_rs_convert_i2c_serial_bus,
+       acpi_rs_convert_spi_serial_bus,
+       acpi_rs_convert_uart_serial_bus,
 };
 
 #ifdef ACPI_FUTURE_USAGE
@@ -140,6 +155,16 @@ struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[] = {
        acpi_rs_dump_ext_address64,     /* ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */
        acpi_rs_dump_ext_irq,   /* ACPI_RESOURCE_TYPE_EXTENDED_IRQ */
        acpi_rs_dump_generic_reg,       /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */
+       acpi_rs_dump_gpio,      /* ACPI_RESOURCE_TYPE_GPIO */
+       acpi_rs_dump_fixed_dma, /* ACPI_RESOURCE_TYPE_FIXED_DMA */
+       NULL,                   /* ACPI_RESOURCE_TYPE_SERIAL_BUS */
+};
+
+struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[] = {
+       NULL,
+       acpi_rs_dump_i2c_serial_bus,    /* AML_RESOURCE_I2C_BUS_TYPE */
+       acpi_rs_dump_spi_serial_bus,    /* AML_RESOURCE_SPI_BUS_TYPE */
+       acpi_rs_dump_uart_serial_bus,   /* AML_RESOURCE_UART_BUS_TYPE */
 };
 #endif
 
@@ -166,7 +191,10 @@ const u8 acpi_gbl_aml_resource_sizes[] = {
        sizeof(struct aml_resource_address64),  /* ACPI_RESOURCE_TYPE_ADDRESS64 */
        sizeof(struct aml_resource_extended_address64), /*ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */
        sizeof(struct aml_resource_extended_irq),       /* ACPI_RESOURCE_TYPE_EXTENDED_IRQ */
-       sizeof(struct aml_resource_generic_register)    /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */
+       sizeof(struct aml_resource_generic_register),   /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */
+       sizeof(struct aml_resource_gpio),       /* ACPI_RESOURCE_TYPE_GPIO */
+       sizeof(struct aml_resource_fixed_dma),  /* ACPI_RESOURCE_TYPE_FIXED_DMA */
+       sizeof(struct aml_resource_common_serialbus),   /* ACPI_RESOURCE_TYPE_SERIAL_BUS */
 };
 
 const u8 acpi_gbl_resource_struct_sizes[] = {
@@ -182,7 +210,7 @@ const u8 acpi_gbl_resource_struct_sizes[] = {
        ACPI_RS_SIZE_MIN,
        ACPI_RS_SIZE(struct acpi_resource_io),
        ACPI_RS_SIZE(struct acpi_resource_fixed_io),
-       0,
+       ACPI_RS_SIZE(struct acpi_resource_fixed_dma),
        0,
        0,
        0,
@@ -202,5 +230,21 @@ const u8 acpi_gbl_resource_struct_sizes[] = {
        ACPI_RS_SIZE(struct acpi_resource_address16),
        ACPI_RS_SIZE(struct acpi_resource_extended_irq),
        ACPI_RS_SIZE(struct acpi_resource_address64),
-       ACPI_RS_SIZE(struct acpi_resource_extended_address64)
+       ACPI_RS_SIZE(struct acpi_resource_extended_address64),
+       ACPI_RS_SIZE(struct acpi_resource_gpio),
+       ACPI_RS_SIZE(struct acpi_resource_common_serialbus)
+};
+
+const u8 acpi_gbl_aml_resource_serial_bus_sizes[] = {
+       0,
+       sizeof(struct aml_resource_i2c_serialbus),
+       sizeof(struct aml_resource_spi_serialbus),
+       sizeof(struct aml_resource_uart_serialbus),
+};
+
+const u8 acpi_gbl_resource_struct_serial_bus_sizes[] = {
+       0,
+       ACPI_RS_SIZE(struct acpi_resource_i2c_serialbus),
+       ACPI_RS_SIZE(struct acpi_resource_spi_serialbus),
+       ACPI_RS_SIZE(struct acpi_resource_uart_serialbus),
 };
index 0c7efef008bed3c2bcd652fae16bf9d0ae80ca29..f6a081057a22d24ca6e06a40db2df63890eedd45 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 50b8ad21116736185832c802d63529bbfa9532cd..e23a9ec248cbc7c8b0e5bfbcc90f1b4d552865b2 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -264,3 +264,34 @@ struct acpi_rsconvert_info acpi_rs_convert_dma[6] = {
         AML_OFFSET(dma.dma_channel_mask),
         ACPI_RS_OFFSET(data.dma.channel_count)}
 };
+
+/*******************************************************************************
+ *
+ * acpi_rs_convert_fixed_dma
+ *
+ ******************************************************************************/
+
+struct acpi_rsconvert_info acpi_rs_convert_fixed_dma[4] = {
+       {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_FIXED_DMA,
+        ACPI_RS_SIZE(struct acpi_resource_fixed_dma),
+        ACPI_RSC_TABLE_SIZE(acpi_rs_convert_fixed_dma)},
+
+       {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_FIXED_DMA,
+        sizeof(struct aml_resource_fixed_dma),
+        0},
+
+       /*
+        * These fields are contiguous in both the source and destination:
+        * request_lines
+        * Channels
+        */
+
+       {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.fixed_dma.request_lines),
+        AML_OFFSET(fixed_dma.request_lines),
+        2},
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.fixed_dma.width),
+        AML_OFFSET(fixed_dma.width),
+        1},
+
+};
index 1bfcef736c5079695dd871d4490ae34bb612600b..9be129f5d6f4ec431469a4bebf76a6f0b900df9a 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -70,6 +70,8 @@ acpi_rs_convert_aml_to_resources(u8 * aml,
        struct acpi_resource **resource_ptr =
            ACPI_CAST_INDIRECT_PTR(struct acpi_resource, context);
        struct acpi_resource *resource;
+       union aml_resource *aml_resource;
+       struct acpi_rsconvert_info *conversion_table;
        acpi_status status;
 
        ACPI_FUNCTION_TRACE(rs_convert_aml_to_resources);
@@ -84,14 +86,37 @@ acpi_rs_convert_aml_to_resources(u8 * aml,
                              "Misaligned resource pointer %p", resource));
        }
 
+       /* Get the appropriate conversion info table */
+
+       aml_resource = ACPI_CAST_PTR(union aml_resource, aml);
+       if (acpi_ut_get_resource_type(aml) == ACPI_RESOURCE_NAME_SERIAL_BUS) {
+               if (aml_resource->common_serial_bus.type >
+                   AML_RESOURCE_MAX_SERIALBUSTYPE) {
+                       conversion_table = NULL;
+               } else {
+                       /* This is an I2C, SPI, or UART serial_bus descriptor */
+
+                       conversion_table =
+                           acpi_gbl_convert_resource_serial_bus_dispatch
+                           [aml_resource->common_serial_bus.type];
+               }
+       } else {
+               conversion_table =
+                   acpi_gbl_get_resource_dispatch[resource_index];
+       }
+
+       if (!conversion_table) {
+               ACPI_ERROR((AE_INFO,
+                           "Invalid/unsupported resource descriptor: Type 0x%2.2X",
+                           resource_index));
+               return (AE_AML_INVALID_RESOURCE_TYPE);
+       }
+
        /* Convert the AML byte stream resource to a local resource struct */
 
        status =
-           acpi_rs_convert_aml_to_resource(resource,
-                                           ACPI_CAST_PTR(union aml_resource,
-                                                         aml),
-                                           acpi_gbl_get_resource_dispatch
-                                           [resource_index]);
+           acpi_rs_convert_aml_to_resource(resource, aml_resource,
+                                           conversion_table);
        if (ACPI_FAILURE(status)) {
                ACPI_EXCEPTION((AE_INFO, status,
                                "Could not convert AML resource (Type 0x%X)",
@@ -106,7 +131,7 @@ acpi_rs_convert_aml_to_resources(u8 * aml,
 
        /* Point to the next structure in the output buffer */
 
-       *resource_ptr = ACPI_ADD_PTR(void, resource, resource->length);
+       *resource_ptr = ACPI_NEXT_RESOURCE(resource);
        return_ACPI_STATUS(AE_OK);
 }
 
@@ -135,6 +160,7 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource,
 {
        u8 *aml = output_buffer;
        u8 *end_aml = output_buffer + aml_size_needed;
+       struct acpi_rsconvert_info *conversion_table;
        acpi_status status;
 
        ACPI_FUNCTION_TRACE(rs_convert_resources_to_aml);
@@ -154,11 +180,34 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource,
 
                /* Perform the conversion */
 
-               status = acpi_rs_convert_resource_to_aml(resource, ACPI_CAST_PTR(union
-                                                                                aml_resource,
-                                                                                aml),
-                                                        acpi_gbl_set_resource_dispatch
-                                                        [resource->type]);
+               if (resource->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
+                       if (resource->data.common_serial_bus.type >
+                           AML_RESOURCE_MAX_SERIALBUSTYPE) {
+                               conversion_table = NULL;
+                       } else {
+                               /* This is an I2C, SPI, or UART serial_bus descriptor */
+
+                               conversion_table =
+                                   acpi_gbl_convert_resource_serial_bus_dispatch
+                                   [resource->data.common_serial_bus.type];
+                       }
+               } else {
+                       conversion_table =
+                           acpi_gbl_set_resource_dispatch[resource->type];
+               }
+
+               if (!conversion_table) {
+                       ACPI_ERROR((AE_INFO,
+                                   "Invalid/unsupported resource descriptor: Type 0x%2.2X",
+                                   resource->type));
+                       return (AE_AML_INVALID_RESOURCE_TYPE);
+               }
+
+               status = acpi_rs_convert_resource_to_aml(resource,
+                                                        ACPI_CAST_PTR(union
+                                                                      aml_resource,
+                                                                      aml),
+                                                        conversion_table);
                if (ACPI_FAILURE(status)) {
                        ACPI_EXCEPTION((AE_INFO, status,
                                        "Could not convert resource (type 0x%X) to AML",
@@ -192,9 +241,7 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource,
 
                /* Point to the next input resource descriptor */
 
-               resource =
-                   ACPI_ADD_PTR(struct acpi_resource, resource,
-                                resource->length);
+               resource = ACPI_NEXT_RESOURCE(resource);
        }
 
        /* Completed buffer, but did not find an end_tag resource descriptor */
index 7cc6d8625f1e66d488b3e8c0da0c885e2483db42..4fd611ad02b48d9d706cfe886d347c345f2bbdda 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 410264b22a296011108454e353b21dbaaf646b2c..8073b371cc7cd32b44a4cab6dba88e3ae19b149f 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -83,6 +83,10 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
 
        ACPI_FUNCTION_TRACE(rs_convert_aml_to_resource);
 
+       if (!info) {
+               return_ACPI_STATUS(AE_BAD_PARAMETER);
+       }
+
        if (((acpi_size) resource) & 0x3) {
 
                /* Each internal resource struct is expected to be 32-bit aligned */
@@ -101,7 +105,6 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
         * table length (# of table entries)
         */
        count = INIT_TABLE_LENGTH(info);
-
        while (count) {
                /*
                 * Source is the external AML byte stream buffer,
@@ -145,6 +148,14 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
                            ((ACPI_GET8(source) >> info->value) & 0x03);
                        break;
 
+               case ACPI_RSC_3BITFLAG:
+                       /*
+                        * Mask and shift the flag bits
+                        */
+                       ACPI_SET8(destination) = (u8)
+                           ((ACPI_GET8(source) >> info->value) & 0x07);
+                       break;
+
                case ACPI_RSC_COUNT:
 
                        item_count = ACPI_GET8(source);
@@ -163,6 +174,69 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
                            (info->value * (item_count - 1));
                        break;
 
+               case ACPI_RSC_COUNT_GPIO_PIN:
+
+                       target = ACPI_ADD_PTR(void, aml, info->value);
+                       item_count = ACPI_GET16(target) - ACPI_GET16(source);
+
+                       resource->length = resource->length + item_count;
+                       item_count = item_count / 2;
+                       ACPI_SET16(destination) = item_count;
+                       break;
+
+               case ACPI_RSC_COUNT_GPIO_VEN:
+
+                       item_count = ACPI_GET8(source);
+                       ACPI_SET8(destination) = (u8)item_count;
+
+                       resource->length = resource->length +
+                           (info->value * item_count);
+                       break;
+
+               case ACPI_RSC_COUNT_GPIO_RES:
+
+                       /*
+                        * Vendor data is optional (length/offset may both be zero)
+                        * Examine vendor data length field first
+                        */
+                       target = ACPI_ADD_PTR(void, aml, (info->value + 2));
+                       if (ACPI_GET16(target)) {
+
+                               /* Use vendor offset to get resource source length */
+
+                               target = ACPI_ADD_PTR(void, aml, info->value);
+                               item_count =
+                                   ACPI_GET16(target) - ACPI_GET16(source);
+                       } else {
+                               /* No vendor data to worry about */
+
+                               item_count = aml->large_header.resource_length +
+                                   sizeof(struct aml_resource_large_header) -
+                                   ACPI_GET16(source);
+                       }
+
+                       resource->length = resource->length + item_count;
+                       ACPI_SET16(destination) = item_count;
+                       break;
+
+               case ACPI_RSC_COUNT_SERIAL_VEN:
+
+                       item_count = ACPI_GET16(source) - info->value;
+
+                       resource->length = resource->length + item_count;
+                       ACPI_SET16(destination) = item_count;
+                       break;
+
+               case ACPI_RSC_COUNT_SERIAL_RES:
+
+                       item_count = (aml_resource_length +
+                                     sizeof(struct aml_resource_large_header))
+                           - ACPI_GET16(source) - info->value;
+
+                       resource->length = resource->length + item_count;
+                       ACPI_SET16(destination) = item_count;
+                       break;
+
                case ACPI_RSC_LENGTH:
 
                        resource->length = resource->length + info->value;
@@ -183,6 +257,72 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
                                          info->opcode);
                        break;
 
+               case ACPI_RSC_MOVE_GPIO_PIN:
+
+                       /* Generate and set the PIN data pointer */
+
+                       target = (char *)ACPI_ADD_PTR(void, resource,
+                                                     (resource->length -
+                                                      item_count * 2));
+                       *(u16 **)destination = ACPI_CAST_PTR(u16, target);
+
+                       /* Copy the PIN data */
+
+                       source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source));
+                       acpi_rs_move_data(target, source, item_count,
+                                         info->opcode);
+                       break;
+
+               case ACPI_RSC_MOVE_GPIO_RES:
+
+                       /* Generate and set the resource_source string pointer */
+
+                       target = (char *)ACPI_ADD_PTR(void, resource,
+                                                     (resource->length -
+                                                      item_count));
+                       *(u8 **)destination = ACPI_CAST_PTR(u8, target);
+
+                       /* Copy the resource_source string */
+
+                       source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source));
+                       acpi_rs_move_data(target, source, item_count,
+                                         info->opcode);
+                       break;
+
+               case ACPI_RSC_MOVE_SERIAL_VEN:
+
+                       /* Generate and set the Vendor Data pointer */
+
+                       target = (char *)ACPI_ADD_PTR(void, resource,
+                                                     (resource->length -
+                                                      item_count));
+                       *(u8 **)destination = ACPI_CAST_PTR(u8, target);
+
+                       /* Copy the Vendor Data */
+
+                       source = ACPI_ADD_PTR(void, aml, info->value);
+                       acpi_rs_move_data(target, source, item_count,
+                                         info->opcode);
+                       break;
+
+               case ACPI_RSC_MOVE_SERIAL_RES:
+
+                       /* Generate and set the resource_source string pointer */
+
+                       target = (char *)ACPI_ADD_PTR(void, resource,
+                                                     (resource->length -
+                                                      item_count));
+                       *(u8 **)destination = ACPI_CAST_PTR(u8, target);
+
+                       /* Copy the resource_source string */
+
+                       source =
+                           ACPI_ADD_PTR(void, aml,
+                                        (ACPI_GET16(source) + info->value));
+                       acpi_rs_move_data(target, source, item_count,
+                                         info->opcode);
+                       break;
+
                case ACPI_RSC_SET8:
 
                        ACPI_MEMSET(destination, info->aml_offset, info->value);
@@ -219,13 +359,18 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
                         * Optional resource_source (Index and String). This is the more
                         * complicated case used by the Interrupt() macro
                         */
-                       target =
-                           ACPI_ADD_PTR(char, resource,
-                                        info->aml_offset + (item_count * 4));
+                       target = ACPI_ADD_PTR(char, resource,
+                                             info->aml_offset +
+                                             (item_count * 4));
 
                        resource->length +=
                            acpi_rs_get_resource_source(aml_resource_length,
-                                                       (acpi_rs_length) (((item_count - 1) * sizeof(u32)) + info->value), destination, aml, target);
+                                                       (acpi_rs_length)
+                                                       (((item_count -
+                                                          1) * sizeof(u32)) +
+                                                        info->value),
+                                                       destination, aml,
+                                                       target);
                        break;
 
                case ACPI_RSC_BITMASK:
@@ -327,6 +472,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
 {
        void *source = NULL;
        void *destination;
+       char *target;
        acpi_rsdesc_size aml_length = 0;
        u8 count;
        u16 temp16 = 0;
@@ -334,6 +480,10 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
 
        ACPI_FUNCTION_TRACE(rs_convert_resource_to_aml);
 
+       if (!info) {
+               return_ACPI_STATUS(AE_BAD_PARAMETER);
+       }
+
        /*
         * First table entry must be ACPI_RSC_INITxxx and must contain the
         * table length (# of table entries)
@@ -383,6 +533,14 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
                            ((ACPI_GET8(source) & 0x03) << info->value);
                        break;
 
+               case ACPI_RSC_3BITFLAG:
+                       /*
+                        * Mask and shift the flag bits
+                        */
+                       ACPI_SET8(destination) |= (u8)
+                           ((ACPI_GET8(source) & 0x07) << info->value);
+                       break;
+
                case ACPI_RSC_COUNT:
 
                        item_count = ACPI_GET8(source);
@@ -400,6 +558,63 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
                        acpi_rs_set_resource_length(aml_length, aml);
                        break;
 
+               case ACPI_RSC_COUNT_GPIO_PIN:
+
+                       item_count = ACPI_GET16(source);
+                       ACPI_SET16(destination) = (u16)aml_length;
+
+                       aml_length = (u16)(aml_length + item_count * 2);
+                       target = ACPI_ADD_PTR(void, aml, info->value);
+                       ACPI_SET16(target) = (u16)aml_length;
+                       acpi_rs_set_resource_length(aml_length, aml);
+                       break;
+
+               case ACPI_RSC_COUNT_GPIO_VEN:
+
+                       item_count = ACPI_GET16(source);
+                       ACPI_SET16(destination) = (u16)item_count;
+
+                       aml_length =
+                           (u16)(aml_length + (info->value * item_count));
+                       acpi_rs_set_resource_length(aml_length, aml);
+                       break;
+
+               case ACPI_RSC_COUNT_GPIO_RES:
+
+                       /* Set resource source string length */
+
+                       item_count = ACPI_GET16(source);
+                       ACPI_SET16(destination) = (u16)aml_length;
+
+                       /* Compute offset for the Vendor Data */
+
+                       aml_length = (u16)(aml_length + item_count);
+                       target = ACPI_ADD_PTR(void, aml, info->value);
+
+                       /* Set vendor offset only if there is vendor data */
+
+                       if (resource->data.gpio.vendor_length) {
+                               ACPI_SET16(target) = (u16)aml_length;
+                       }
+
+                       acpi_rs_set_resource_length(aml_length, aml);
+                       break;
+
+               case ACPI_RSC_COUNT_SERIAL_VEN:
+
+                       item_count = ACPI_GET16(source);
+                       ACPI_SET16(destination) = item_count + info->value;
+                       aml_length = (u16)(aml_length + item_count);
+                       acpi_rs_set_resource_length(aml_length, aml);
+                       break;
+
+               case ACPI_RSC_COUNT_SERIAL_RES:
+
+                       item_count = ACPI_GET16(source);
+                       aml_length = (u16)(aml_length + item_count);
+                       acpi_rs_set_resource_length(aml_length, aml);
+                       break;
+
                case ACPI_RSC_LENGTH:
 
                        acpi_rs_set_resource_length(info->value, aml);
@@ -417,6 +632,48 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
                                          info->opcode);
                        break;
 
+               case ACPI_RSC_MOVE_GPIO_PIN:
+
+                       destination = (char *)ACPI_ADD_PTR(void, aml,
+                                                          ACPI_GET16
+                                                          (destination));
+                       source = *(u16 **)source;
+                       acpi_rs_move_data(destination, source, item_count,
+                                         info->opcode);
+                       break;
+
+               case ACPI_RSC_MOVE_GPIO_RES:
+
+                       /* Used for both resource_source string and vendor_data */
+
+                       destination = (char *)ACPI_ADD_PTR(void, aml,
+                                                          ACPI_GET16
+                                                          (destination));
+                       source = *(u8 **)source;
+                       acpi_rs_move_data(destination, source, item_count,
+                                         info->opcode);
+                       break;
+
+               case ACPI_RSC_MOVE_SERIAL_VEN:
+
+                       destination = (char *)ACPI_ADD_PTR(void, aml,
+                                                          (aml_length -
+                                                           item_count));
+                       source = *(u8 **)source;
+                       acpi_rs_move_data(destination, source, item_count,
+                                         info->opcode);
+                       break;
+
+               case ACPI_RSC_MOVE_SERIAL_RES:
+
+                       destination = (char *)ACPI_ADD_PTR(void, aml,
+                                                          (aml_length -
+                                                           item_count));
+                       source = *(u8 **)source;
+                       acpi_rs_move_data(destination, source, item_count,
+                                         info->opcode);
+                       break;
+
                case ACPI_RSC_ADDRESS:
 
                        /* Set the Resource Type, General Flags, and Type-Specific Flags */
diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c
new file mode 100644 (file)
index 0000000..9aa5e68
--- /dev/null
@@ -0,0 +1,441 @@
+/*******************************************************************************
+ *
+ * Module Name: rsserial - GPIO/serial_bus resource descriptors
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2012, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acresrc.h"
+
+#define _COMPONENT          ACPI_RESOURCES
+ACPI_MODULE_NAME("rsserial")
+
+/*******************************************************************************
+ *
+ * acpi_rs_convert_gpio
+ *
+ ******************************************************************************/
+struct acpi_rsconvert_info acpi_rs_convert_gpio[17] = {
+       {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_GPIO,
+        ACPI_RS_SIZE(struct acpi_resource_gpio),
+        ACPI_RSC_TABLE_SIZE(acpi_rs_convert_gpio)},
+
+       {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_GPIO,
+        sizeof(struct aml_resource_gpio),
+        0},
+
+       /*
+        * These fields are contiguous in both the source and destination:
+        * revision_id
+        * connection_type
+        */
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.gpio.revision_id),
+        AML_OFFSET(gpio.revision_id),
+        2},
+
+       {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.producer_consumer),
+        AML_OFFSET(gpio.flags),
+        0},
+
+       {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.sharable),
+        AML_OFFSET(gpio.int_flags),
+        3},
+
+       {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.io_restriction),
+        AML_OFFSET(gpio.int_flags),
+        0},
+
+       {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.triggering),
+        AML_OFFSET(gpio.int_flags),
+        0},
+
+       {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.polarity),
+        AML_OFFSET(gpio.int_flags),
+        1},
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.gpio.pin_config),
+        AML_OFFSET(gpio.pin_config),
+        1},
+
+       /*
+        * These fields are contiguous in both the source and destination:
+        * drive_strength
+        * debounce_timeout
+        */
+       {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.gpio.drive_strength),
+        AML_OFFSET(gpio.drive_strength),
+        2},
+
+       /* Pin Table */
+
+       {ACPI_RSC_COUNT_GPIO_PIN, ACPI_RS_OFFSET(data.gpio.pin_table_length),
+        AML_OFFSET(gpio.pin_table_offset),
+        AML_OFFSET(gpio.res_source_offset)},
+
+       {ACPI_RSC_MOVE_GPIO_PIN, ACPI_RS_OFFSET(data.gpio.pin_table),
+        AML_OFFSET(gpio.pin_table_offset),
+        0},
+
+       /* Resource Source */
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.gpio.resource_source.index),
+        AML_OFFSET(gpio.res_source_index),
+        1},
+
+       {ACPI_RSC_COUNT_GPIO_RES,
+        ACPI_RS_OFFSET(data.gpio.resource_source.string_length),
+        AML_OFFSET(gpio.res_source_offset),
+        AML_OFFSET(gpio.vendor_offset)},
+
+       {ACPI_RSC_MOVE_GPIO_RES,
+        ACPI_RS_OFFSET(data.gpio.resource_source.string_ptr),
+        AML_OFFSET(gpio.res_source_offset),
+        0},
+
+       /* Vendor Data */
+
+       {ACPI_RSC_COUNT_GPIO_VEN, ACPI_RS_OFFSET(data.gpio.vendor_length),
+        AML_OFFSET(gpio.vendor_length),
+        1},
+
+       {ACPI_RSC_MOVE_GPIO_RES, ACPI_RS_OFFSET(data.gpio.vendor_data),
+        AML_OFFSET(gpio.vendor_offset),
+        0},
+};
+
+/*******************************************************************************
+ *
+ * acpi_rs_convert_i2c_serial_bus
+ *
+ ******************************************************************************/
+
+struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[16] = {
+       {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS,
+        ACPI_RS_SIZE(struct acpi_resource_i2c_serialbus),
+        ACPI_RSC_TABLE_SIZE(acpi_rs_convert_i2c_serial_bus)},
+
+       {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS,
+        sizeof(struct aml_resource_i2c_serialbus),
+        0},
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.revision_id),
+        AML_OFFSET(common_serial_bus.revision_id),
+        1},
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.type),
+        AML_OFFSET(common_serial_bus.type),
+        1},
+
+       {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.common_serial_bus.slave_mode),
+        AML_OFFSET(common_serial_bus.flags),
+        0},
+
+       {ACPI_RSC_1BITFLAG,
+        ACPI_RS_OFFSET(data.common_serial_bus.producer_consumer),
+        AML_OFFSET(common_serial_bus.flags),
+        1},
+
+       {ACPI_RSC_MOVE8,
+        ACPI_RS_OFFSET(data.common_serial_bus.type_revision_id),
+        AML_OFFSET(common_serial_bus.type_revision_id),
+        1},
+
+       {ACPI_RSC_MOVE16,
+        ACPI_RS_OFFSET(data.common_serial_bus.type_data_length),
+        AML_OFFSET(common_serial_bus.type_data_length),
+        1},
+
+       /* Vendor data */
+
+       {ACPI_RSC_COUNT_SERIAL_VEN,
+        ACPI_RS_OFFSET(data.common_serial_bus.vendor_length),
+        AML_OFFSET(common_serial_bus.type_data_length),
+        AML_RESOURCE_I2C_MIN_DATA_LEN},
+
+       {ACPI_RSC_MOVE_SERIAL_VEN,
+        ACPI_RS_OFFSET(data.common_serial_bus.vendor_data),
+        0,
+        sizeof(struct aml_resource_i2c_serialbus)},
+
+       /* Resource Source */
+
+       {ACPI_RSC_MOVE8,
+        ACPI_RS_OFFSET(data.common_serial_bus.resource_source.index),
+        AML_OFFSET(common_serial_bus.res_source_index),
+        1},
+
+       {ACPI_RSC_COUNT_SERIAL_RES,
+        ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_length),
+        AML_OFFSET(common_serial_bus.type_data_length),
+        sizeof(struct aml_resource_common_serialbus)},
+
+       {ACPI_RSC_MOVE_SERIAL_RES,
+        ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_ptr),
+        AML_OFFSET(common_serial_bus.type_data_length),
+        sizeof(struct aml_resource_common_serialbus)},
+
+       /* I2C bus type specific */
+
+       {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.i2c_serial_bus.access_mode),
+        AML_OFFSET(i2c_serial_bus.type_specific_flags),
+        0},
+
+       {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.i2c_serial_bus.connection_speed),
+        AML_OFFSET(i2c_serial_bus.connection_speed),
+        1},
+
+       {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.i2c_serial_bus.slave_address),
+        AML_OFFSET(i2c_serial_bus.slave_address),
+        1},
+};
+
+/*******************************************************************************
+ *
+ * acpi_rs_convert_spi_serial_bus
+ *
+ ******************************************************************************/
+
+struct acpi_rsconvert_info acpi_rs_convert_spi_serial_bus[20] = {
+       {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS,
+        ACPI_RS_SIZE(struct acpi_resource_spi_serialbus),
+        ACPI_RSC_TABLE_SIZE(acpi_rs_convert_spi_serial_bus)},
+
+       {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS,
+        sizeof(struct aml_resource_spi_serialbus),
+        0},
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.revision_id),
+        AML_OFFSET(common_serial_bus.revision_id),
+        1},
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.type),
+        AML_OFFSET(common_serial_bus.type),
+        1},
+
+       {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.common_serial_bus.slave_mode),
+        AML_OFFSET(common_serial_bus.flags),
+        0},
+
+       {ACPI_RSC_1BITFLAG,
+        ACPI_RS_OFFSET(data.common_serial_bus.producer_consumer),
+        AML_OFFSET(common_serial_bus.flags),
+        1},
+
+       {ACPI_RSC_MOVE8,
+        ACPI_RS_OFFSET(data.common_serial_bus.type_revision_id),
+        AML_OFFSET(common_serial_bus.type_revision_id),
+        1},
+
+       {ACPI_RSC_MOVE16,
+        ACPI_RS_OFFSET(data.common_serial_bus.type_data_length),
+        AML_OFFSET(common_serial_bus.type_data_length),
+        1},
+
+       /* Vendor data */
+
+       {ACPI_RSC_COUNT_SERIAL_VEN,
+        ACPI_RS_OFFSET(data.common_serial_bus.vendor_length),
+        AML_OFFSET(common_serial_bus.type_data_length),
+        AML_RESOURCE_SPI_MIN_DATA_LEN},
+
+       {ACPI_RSC_MOVE_SERIAL_VEN,
+        ACPI_RS_OFFSET(data.common_serial_bus.vendor_data),
+        0,
+        sizeof(struct aml_resource_spi_serialbus)},
+
+       /* Resource Source */
+
+       {ACPI_RSC_MOVE8,
+        ACPI_RS_OFFSET(data.common_serial_bus.resource_source.index),
+        AML_OFFSET(common_serial_bus.res_source_index),
+        1},
+
+       {ACPI_RSC_COUNT_SERIAL_RES,
+        ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_length),
+        AML_OFFSET(common_serial_bus.type_data_length),
+        sizeof(struct aml_resource_common_serialbus)},
+
+       {ACPI_RSC_MOVE_SERIAL_RES,
+        ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_ptr),
+        AML_OFFSET(common_serial_bus.type_data_length),
+        sizeof(struct aml_resource_common_serialbus)},
+
+       /* Spi bus type specific  */
+
+       {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.spi_serial_bus.wire_mode),
+        AML_OFFSET(spi_serial_bus.type_specific_flags),
+        0},
+
+       {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.spi_serial_bus.device_polarity),
+        AML_OFFSET(spi_serial_bus.type_specific_flags),
+        1},
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.spi_serial_bus.data_bit_length),
+        AML_OFFSET(spi_serial_bus.data_bit_length),
+        1},
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.spi_serial_bus.clock_phase),
+        AML_OFFSET(spi_serial_bus.clock_phase),
+        1},
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.spi_serial_bus.clock_polarity),
+        AML_OFFSET(spi_serial_bus.clock_polarity),
+        1},
+
+       {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.spi_serial_bus.device_selection),
+        AML_OFFSET(spi_serial_bus.device_selection),
+        1},
+
+       {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.spi_serial_bus.connection_speed),
+        AML_OFFSET(spi_serial_bus.connection_speed),
+        1},
+};
+
+/*******************************************************************************
+ *
+ * acpi_rs_convert_uart_serial_bus
+ *
+ ******************************************************************************/
+
+struct acpi_rsconvert_info acpi_rs_convert_uart_serial_bus[22] = {
+       {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS,
+        ACPI_RS_SIZE(struct acpi_resource_uart_serialbus),
+        ACPI_RSC_TABLE_SIZE(acpi_rs_convert_uart_serial_bus)},
+
+       {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS,
+        sizeof(struct aml_resource_uart_serialbus),
+        0},
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.revision_id),
+        AML_OFFSET(common_serial_bus.revision_id),
+        1},
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.type),
+        AML_OFFSET(common_serial_bus.type),
+        1},
+
+       {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.common_serial_bus.slave_mode),
+        AML_OFFSET(common_serial_bus.flags),
+        0},
+
+       {ACPI_RSC_1BITFLAG,
+        ACPI_RS_OFFSET(data.common_serial_bus.producer_consumer),
+        AML_OFFSET(common_serial_bus.flags),
+        1},
+
+       {ACPI_RSC_MOVE8,
+        ACPI_RS_OFFSET(data.common_serial_bus.type_revision_id),
+        AML_OFFSET(common_serial_bus.type_revision_id),
+        1},
+
+       {ACPI_RSC_MOVE16,
+        ACPI_RS_OFFSET(data.common_serial_bus.type_data_length),
+        AML_OFFSET(common_serial_bus.type_data_length),
+        1},
+
+       /* Vendor data */
+
+       {ACPI_RSC_COUNT_SERIAL_VEN,
+        ACPI_RS_OFFSET(data.common_serial_bus.vendor_length),
+        AML_OFFSET(common_serial_bus.type_data_length),
+        AML_RESOURCE_UART_MIN_DATA_LEN},
+
+       {ACPI_RSC_MOVE_SERIAL_VEN,
+        ACPI_RS_OFFSET(data.common_serial_bus.vendor_data),
+        0,
+        sizeof(struct aml_resource_uart_serialbus)},
+
+       /* Resource Source */
+
+       {ACPI_RSC_MOVE8,
+        ACPI_RS_OFFSET(data.common_serial_bus.resource_source.index),
+        AML_OFFSET(common_serial_bus.res_source_index),
+        1},
+
+       {ACPI_RSC_COUNT_SERIAL_RES,
+        ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_length),
+        AML_OFFSET(common_serial_bus.type_data_length),
+        sizeof(struct aml_resource_common_serialbus)},
+
+       {ACPI_RSC_MOVE_SERIAL_RES,
+        ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_ptr),
+        AML_OFFSET(common_serial_bus.type_data_length),
+        sizeof(struct aml_resource_common_serialbus)},
+
+       /* Uart bus type specific  */
+
+       {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.flow_control),
+        AML_OFFSET(uart_serial_bus.type_specific_flags),
+        0},
+
+       {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.stop_bits),
+        AML_OFFSET(uart_serial_bus.type_specific_flags),
+        2},
+
+       {ACPI_RSC_3BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.data_bits),
+        AML_OFFSET(uart_serial_bus.type_specific_flags),
+        4},
+
+       {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.endian),
+        AML_OFFSET(uart_serial_bus.type_specific_flags),
+        7},
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.uart_serial_bus.parity),
+        AML_OFFSET(uart_serial_bus.parity),
+        1},
+
+       {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.uart_serial_bus.lines_enabled),
+        AML_OFFSET(uart_serial_bus.lines_enabled),
+        1},
+
+       {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.uart_serial_bus.rx_fifo_size),
+        AML_OFFSET(uart_serial_bus.rx_fifo_size),
+        1},
+
+       {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.uart_serial_bus.tx_fifo_size),
+        AML_OFFSET(uart_serial_bus.tx_fifo_size),
+        1},
+
+       {ACPI_RSC_MOVE32,
+        ACPI_RS_OFFSET(data.uart_serial_bus.default_baud_rate),
+        AML_OFFSET(uart_serial_bus.default_baud_rate),
+        1},
+};
index 231811e569399c5b75d2b7ba55be22bf82edbdbb..433a375deb9350e9635b103e3c593d6e7c3838da 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -144,6 +144,9 @@ acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type)
                         * since there are no alignment or endian issues
                         */
                case ACPI_RSC_MOVE8:
+               case ACPI_RSC_MOVE_GPIO_RES:
+               case ACPI_RSC_MOVE_SERIAL_VEN:
+               case ACPI_RSC_MOVE_SERIAL_RES:
                        ACPI_MEMCPY(destination, source, item_count);
                        return;
 
@@ -153,6 +156,7 @@ acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type)
                         * misaligned memory transfers
                         */
                case ACPI_RSC_MOVE16:
+               case ACPI_RSC_MOVE_GPIO_PIN:
                        ACPI_MOVE_16_TO_16(&ACPI_CAST_PTR(u16, destination)[i],
                                           &ACPI_CAST_PTR(u16, source)[i]);
                        break;
@@ -588,6 +592,56 @@ acpi_rs_get_prs_method_data(struct acpi_namespace_node *node,
 }
 #endif                         /*  ACPI_FUTURE_USAGE  */
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_rs_get_aei_method_data
+ *
+ * PARAMETERS:  Node            - Device node
+ *              ret_buffer      - Pointer to a buffer structure for the
+ *                                results
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: This function is called to get the _AEI value of an object
+ *              contained in an object specified by the handle passed in
+ *
+ *              If the function fails an appropriate status will be returned
+ *              and the contents of the callers buffer is undefined.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_get_aei_method_data(struct acpi_namespace_node *node,
+                           struct acpi_buffer *ret_buffer)
+{
+       union acpi_operand_object *obj_desc;
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE(rs_get_aei_method_data);
+
+       /* Parameters guaranteed valid by caller */
+
+       /* Execute the method, no parameters */
+
+       status = acpi_ut_evaluate_object(node, METHOD_NAME__AEI,
+                                        ACPI_BTYPE_BUFFER, &obj_desc);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
+       /*
+        * Make the call to create a resource linked list from the
+        * byte stream buffer that comes back from the _CRS method
+        * execution.
+        */
+       status = acpi_rs_create_resource_list(obj_desc, ret_buffer);
+
+       /* On exit, we must delete the object returned by evaluate_object */
+
+       acpi_ut_remove_reference(obj_desc);
+       return_ACPI_STATUS(status);
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_rs_get_method_data
index fe86b37b16ce657bd719b68c656ce252581a0452..f58c098c7aeb3fd5f5e35b532fbbd82da6eab42a 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -307,6 +307,46 @@ acpi_set_current_resources(acpi_handle device_handle,
 
 ACPI_EXPORT_SYMBOL(acpi_set_current_resources)
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_get_event_resources
+ *
+ * PARAMETERS:  device_handle   - Handle to the device object for the
+ *                                device we are getting resources
+ *              in_buffer       - Pointer to a buffer containing the
+ *                                resources to be set for the device
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: This function is called to get the event resources for a
+ *              specific device. The caller must first acquire a handle for
+ *              the desired device. The resource data is passed to the routine
+ *              the buffer pointed to by the in_buffer variable. Uses the
+ *              _AEI method.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_get_event_resources(acpi_handle device_handle,
+                        struct acpi_buffer *ret_buffer)
+{
+       acpi_status status;
+       struct acpi_namespace_node *node;
+
+       ACPI_FUNCTION_TRACE(acpi_get_event_resources);
+
+       /* Validate parameters then dispatch to internal routine */
+
+       status = acpi_rs_validate_parameters(device_handle, ret_buffer, &node);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
+       status = acpi_rs_get_aei_method_data(node, ret_buffer);
+       return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_get_event_resources)
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_resource_to_address64
@@ -486,8 +526,9 @@ acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context)
  *
  * PARAMETERS:  device_handle   - Handle to the device object for the
  *                                device we are querying
- *              Name            - Method name of the resources we want
- *                                (METHOD_NAME__CRS or METHOD_NAME__PRS)
+ *              Name            - Method name of the resources we want.
+ *                                (METHOD_NAME__CRS, METHOD_NAME__PRS, or
+ *                                METHOD_NAME__AEI)
  *              user_function   - Called for each resource
  *              Context         - Passed to user_function
  *
@@ -514,11 +555,12 @@ acpi_walk_resources(acpi_handle device_handle,
 
        if (!device_handle || !user_function || !name ||
            (!ACPI_COMPARE_NAME(name, METHOD_NAME__CRS) &&
-            !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS))) {
+            !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS) &&
+            !ACPI_COMPARE_NAME(name, METHOD_NAME__AEI))) {
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
-       /* Get the _CRS or _PRS resource list */
+       /* Get the _CRS/_PRS/_AEI resource list */
 
        buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
        status = acpi_rs_get_method_data(device_handle, name, &buffer);
index 6f5588e62c0ac24d396288f661fa3a959b52f734..c5d870406f4126adf7ce80ffa0635d175c1a772d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -63,14 +63,15 @@ static void acpi_tb_setup_fadt_registers(void);
 
 typedef struct acpi_fadt_info {
        char *name;
-       u8 address64;
-       u8 address32;
-       u8 length;
+       u16 address64;
+       u16 address32;
+       u16 length;
        u8 default_length;
        u8 type;
 
 } acpi_fadt_info;
 
+#define ACPI_FADT_OPTIONAL          0
 #define ACPI_FADT_REQUIRED          1
 #define ACPI_FADT_SEPARATE_LENGTH   2
 
@@ -87,7 +88,7 @@ static struct acpi_fadt_info fadt_info_table[] = {
         ACPI_FADT_OFFSET(pm1b_event_block),
         ACPI_FADT_OFFSET(pm1_event_length),
         ACPI_PM1_REGISTER_WIDTH * 2,   /* Enable + Status register */
-        0},
+        ACPI_FADT_OPTIONAL},
 
        {"Pm1aControlBlock",
         ACPI_FADT_OFFSET(xpm1a_control_block),
@@ -101,7 +102,7 @@ static struct acpi_fadt_info fadt_info_table[] = {
         ACPI_FADT_OFFSET(pm1b_control_block),
         ACPI_FADT_OFFSET(pm1_control_length),
         ACPI_PM1_REGISTER_WIDTH,
-        0},
+        ACPI_FADT_OPTIONAL},
 
        {"Pm2ControlBlock",
         ACPI_FADT_OFFSET(xpm2_control_block),
@@ -139,7 +140,7 @@ static struct acpi_fadt_info fadt_info_table[] = {
 
 typedef struct acpi_fadt_pm_info {
        struct acpi_generic_address *target;
-       u8 source;
+       u16 source;
        u8 register_num;
 
 } acpi_fadt_pm_info;
@@ -253,8 +254,13 @@ void acpi_tb_parse_fadt(u32 table_index)
        acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
                              ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
 
-       acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs,
-                             ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS);
+       /* If Hardware Reduced flag is set, there is no FACS */
+
+       if (!acpi_gbl_reduced_hardware) {
+               acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.
+                                     Xfacs, ACPI_SIG_FACS,
+                                     ACPI_TABLE_INDEX_FACS);
+       }
 }
 
 /*******************************************************************************
@@ -277,12 +283,12 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
 {
        /*
         * Check if the FADT is larger than the largest table that we expect
-        * (the ACPI 2.0/3.0 version). If so, truncate the table, and issue
+        * (the ACPI 5.0 version). If so, truncate the table, and issue
         * a warning.
         */
        if (length > sizeof(struct acpi_table_fadt)) {
                ACPI_WARNING((AE_INFO,
-                             "FADT (revision %u) is longer than ACPI 2.0 version, "
+                             "FADT (revision %u) is longer than ACPI 5.0 version, "
                              "truncating length %u to %u",
                              table->revision, length,
                              (u32)sizeof(struct acpi_table_fadt)));
@@ -297,6 +303,13 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
        ACPI_MEMCPY(&acpi_gbl_FADT, table,
                    ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
 
+       /* Take a copy of the Hardware Reduced flag */
+
+       acpi_gbl_reduced_hardware = FALSE;
+       if (acpi_gbl_FADT.flags & ACPI_FADT_HW_REDUCED) {
+               acpi_gbl_reduced_hardware = TRUE;
+       }
+
        /* Convert the local copy of the FADT to the common internal format */
 
        acpi_tb_convert_fadt();
@@ -502,6 +515,12 @@ static void acpi_tb_validate_fadt(void)
                acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt;
        }
 
+       /* If Hardware Reduced flag is set, we are all done */
+
+       if (acpi_gbl_reduced_hardware) {
+               return;
+       }
+
        /* Examine all of the 64-bit extended address fields (X fields) */
 
        for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
index a55cb2bb5abbfdee7b448ced5baf23bb37c68a4a..4903e36ea75a3f4f24930c43b497626b930d8f0e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 62365f6075dda417e7204d55105707ef1a64eaf9..1aecf7baa4e0c2f2a0f35c7ebc4ecd8bbbe161c7 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0f2d395feabadb20e8ce47d88f53ff8d786e2427..09ca39e143373c7dfeb11efc63f01540e62d3edb 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -135,6 +135,13 @@ acpi_status acpi_tb_initialize_facs(void)
 {
        acpi_status status;
 
+       /* If Hardware Reduced flag is set, there is no FACS */
+
+       if (acpi_gbl_reduced_hardware) {
+               acpi_gbl_FACS = NULL;
+               return (AE_OK);
+       }
+
        status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
                                         ACPI_CAST_INDIRECT_PTR(struct
                                                                acpi_table_header,
index e7d13f5d3f2da0f77d7b04a71e1118cb2793f7cd..abcc6412c24492129b8bb003963a7f7e826f80fc 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7eb6c6cc1edf76000d8842edc6a1a36bf261a43b..4258f647ca3d63cb20cf9ce2d0b01701f6d00e11 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c
new file mode 100644 (file)
index 0000000..67932ae
--- /dev/null
@@ -0,0 +1,294 @@
+/******************************************************************************
+ *
+ * Module Name: utaddress - op_region address range check
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2012, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_UTILITIES
+ACPI_MODULE_NAME("utaddress")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_add_address_range
+ *
+ * PARAMETERS:  space_id            - Address space ID
+ *              Address             - op_region start address
+ *              Length              - op_region length
+ *              region_node         - op_region namespace node
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Add the Operation Region address range to the global list.
+ *              The only supported Space IDs are Memory and I/O. Called when
+ *              the op_region address/length operands are fully evaluated.
+ *
+ * MUTEX:       Locks the namespace
+ *
+ * NOTE: Because this interface is only called when an op_region argument
+ * list is evaluated, there cannot be any duplicate region_nodes.
+ * Duplicate Address/Length values are allowed, however, so that multiple
+ * address conflicts can be detected.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_ut_add_address_range(acpi_adr_space_type space_id,
+                         acpi_physical_address address,
+                         u32 length, struct acpi_namespace_node *region_node)
+{
+       struct acpi_address_range *range_info;
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE(ut_add_address_range);
+
+       if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
+           (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
+               return_ACPI_STATUS(AE_OK);
+       }
+
+       /* Allocate/init a new info block, add it to the appropriate list */
+
+       range_info = ACPI_ALLOCATE(sizeof(struct acpi_address_range));
+       if (!range_info) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
+       }
+
+       range_info->start_address = address;
+       range_info->end_address = (address + length - 1);
+       range_info->region_node = region_node;
+
+       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+       if (ACPI_FAILURE(status)) {
+               ACPI_FREE(range_info);
+               return_ACPI_STATUS(status);
+       }
+
+       range_info->next = acpi_gbl_address_range_list[space_id];
+       acpi_gbl_address_range_list[space_id] = range_info;
+
+       ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
+                         "\nAdded [%4.4s] address range: 0x%p-0x%p\n",
+                         acpi_ut_get_node_name(range_info->region_node),
+                         ACPI_CAST_PTR(void, address),
+                         ACPI_CAST_PTR(void, range_info->end_address)));
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+       return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_remove_address_range
+ *
+ * PARAMETERS:  space_id            - Address space ID
+ *              region_node         - op_region namespace node
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Remove the Operation Region from the global list. The only
+ *              supported Space IDs are Memory and I/O. Called when an
+ *              op_region is deleted.
+ *
+ * MUTEX:       Assumes the namespace is locked
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_remove_address_range(acpi_adr_space_type space_id,
+                            struct acpi_namespace_node *region_node)
+{
+       struct acpi_address_range *range_info;
+       struct acpi_address_range *prev;
+
+       ACPI_FUNCTION_TRACE(ut_remove_address_range);
+
+       if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
+           (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
+               return_VOID;
+       }
+
+       /* Get the appropriate list head and check the list */
+
+       range_info = prev = acpi_gbl_address_range_list[space_id];
+       while (range_info) {
+               if (range_info->region_node == region_node) {
+                       if (range_info == prev) {       /* Found at list head */
+                               acpi_gbl_address_range_list[space_id] =
+                                   range_info->next;
+                       } else {
+                               prev->next = range_info->next;
+                       }
+
+                       ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
+                                         "\nRemoved [%4.4s] address range: 0x%p-0x%p\n",
+                                         acpi_ut_get_node_name(range_info->
+                                                               region_node),
+                                         ACPI_CAST_PTR(void,
+                                                       range_info->
+                                                       start_address),
+                                         ACPI_CAST_PTR(void,
+                                                       range_info->
+                                                       end_address)));
+
+                       ACPI_FREE(range_info);
+                       return_VOID;
+               }
+
+               prev = range_info;
+               range_info = range_info->next;
+       }
+
+       return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_check_address_range
+ *
+ * PARAMETERS:  space_id            - Address space ID
+ *              Address             - Start address
+ *              Length              - Length of address range
+ *              Warn                - TRUE if warning on overlap desired
+ *
+ * RETURN:      Count of the number of conflicts detected. Zero is always
+ *              returned for Space IDs other than Memory or I/O.
+ *
+ * DESCRIPTION: Check if the input address range overlaps any of the
+ *              ASL operation region address ranges. The only supported
+ *              Space IDs are Memory and I/O.
+ *
+ * MUTEX:       Assumes the namespace is locked.
+ *
+ ******************************************************************************/
+
+u32
+acpi_ut_check_address_range(acpi_adr_space_type space_id,
+                           acpi_physical_address address, u32 length, u8 warn)
+{
+       struct acpi_address_range *range_info;
+       acpi_physical_address end_address;
+       char *pathname;
+       u32 overlap_count = 0;
+
+       ACPI_FUNCTION_TRACE(ut_check_address_range);
+
+       if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
+           (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
+               return_UINT32(0);
+       }
+
+       range_info = acpi_gbl_address_range_list[space_id];
+       end_address = address + length - 1;
+
+       /* Check entire list for all possible conflicts */
+
+       while (range_info) {
+               /*
+                * Check if the requested Address/Length overlaps this address_range.
+                * Four cases to consider:
+                *
+                * 1) Input address/length is contained completely in the address range
+                * 2) Input address/length overlaps range at the range start
+                * 3) Input address/length overlaps range at the range end
+                * 4) Input address/length completely encompasses the range
+                */
+               if ((address <= range_info->end_address) &&
+                   (end_address >= range_info->start_address)) {
+
+                       /* Found an address range overlap */
+
+                       overlap_count++;
+                       if (warn) {     /* Optional warning message */
+                               pathname =
+                                   acpi_ns_get_external_pathname(range_info->
+                                                                 region_node);
+
+                               ACPI_WARNING((AE_INFO,
+                                             "0x%p-0x%p %s conflicts with Region %s %d",
+                                             ACPI_CAST_PTR(void, address),
+                                             ACPI_CAST_PTR(void, end_address),
+                                             acpi_ut_get_region_name(space_id),
+                                             pathname, overlap_count));
+                               ACPI_FREE(pathname);
+                       }
+               }
+
+               range_info = range_info->next;
+       }
+
+       return_UINT32(overlap_count);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_delete_address_lists
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Delete all global address range lists (called during
+ *              subsystem shutdown).
+ *
+ ******************************************************************************/
+
+void acpi_ut_delete_address_lists(void)
+{
+       struct acpi_address_range *next;
+       struct acpi_address_range *range_info;
+       int i;
+
+       /* Delete all elements in all address range lists */
+
+       for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) {
+               next = acpi_gbl_address_range_list[i];
+
+               while (next) {
+                       range_info = next;
+                       next = range_info->next;
+                       ACPI_FREE(range_info);
+               }
+
+               acpi_gbl_address_range_list[i] = NULL;
+       }
+}
index 0a697351cf6974474852370b843880ee3872ab7d..9982d2ea66fbbc382a4b6daaf64d1bdcf647b678 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index aded299a2fa842210a7ee9c616ff321573f8c5c4..3317c0a406ee539381e5f80f93983c6653f8697f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a1f8d7509e664f256bb03153319699915fc0bfef..a0998a886318dba8f286f93e393fc2994848d2b5 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8b087e2d64f4d9e331be57092e3c36395b58db8c..d42ede5260c77cac6f9b947ec625c252ebe027bc 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -171,7 +171,9 @@ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = {
        "SMBus",
        "SystemCMOS",
        "PCIBARTarget",
-       "IPMI"
+       "IPMI",
+       "GeneralPurposeIo",
+       "GenericSerialBus"
 };
 
 char *acpi_ut_get_region_name(u8 space_id)
index 31f5a7832ef135e94659179fbec6a927098b5fa3..2a6c3e183697ac68a6c6bca589116c20f8bf4520 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -215,11 +215,14 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
                ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
                                  "***** Region %p\n", object));
 
-               /* Invalidate the region address/length via the host OS */
-
-               acpi_os_invalidate_address(object->region.space_id,
-                                         object->region.address,
-                                         (acpi_size) object->region.length);
+               /*
+                * Update address_range list. However, only permanent regions
+                * are installed in this list. (Not created within a method)
+                */
+               if (!(object->region.node->flags & ANOBJ_TEMPORARY)) {
+                       acpi_ut_remove_address_range(object->region.space_id,
+                                                    object->region.node);
+               }
 
                second_desc = acpi_ns_get_secondary_object(object);
                if (second_desc) {
index 18f73c9d10bce26a71a469569a868c72bc75fabd..479f32b33415722742c10c7b125cebd682b4b054 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ffba0a39c3e8598d1aeceecd1a007ddf974213cd..4153584cf526a81bb3ab99bd3f5f59a37fb19f42 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -264,6 +264,12 @@ acpi_status acpi_ut_init_globals(void)
                return_ACPI_STATUS(status);
        }
 
+       /* Address Range lists */
+
+       for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) {
+               acpi_gbl_address_range_list[i] = NULL;
+       }
+
        /* Mutex locked flags */
 
        for (i = 0; i < ACPI_NUM_MUTEX; i++) {
index b679ea693545db6fd16703268c9cbd6354cecfcd..c92eb1d937859d673ff1c08293ef4ad94f861328 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 191b6828cce99d300a20fd01d559b21628a0189c..8359c0c5dc9830456ec2605f2bcc9114cd4a25cc 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -92,6 +92,7 @@ static void acpi_ut_terminate(void)
                gpe_xrupt_info = next_gpe_xrupt_info;
        }
 
+       acpi_ut_delete_address_lists();
        return_VOID;
 }
 
index f6bb75c6faf5ea4a653569e9653e3094a07b7056..155fd786d0f2a45b6174f210b621fee6b6b7436d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ce481da9bb451858da374fdee0e5f271196ab335..2491a552b0e69eeba847364f3ab643505f5afb09 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c33a852d4f42a5d9b9113840bcd918680a3836b8..86f19db74e0549949c9685e391166b282523b949 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7d797e2baecd11996ae49525bc99e79f1fbbd5e9..43174df3312100f0a5e9d4b58dfde1679c9a1fd3 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -293,14 +293,10 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
 
 acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
 {
-       acpi_thread_id this_thread_id;
-
        ACPI_FUNCTION_NAME(ut_release_mutex);
 
-       this_thread_id = acpi_os_get_thread_id();
-
        ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n",
-                         (u32)this_thread_id,
+                         (u32)acpi_os_get_thread_id(),
                          acpi_ut_get_mutex_name(mutex_id)));
 
        if (mutex_id > ACPI_MAX_MUTEX) {
@@ -329,7 +325,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
                 * the ACPI subsystem code.
                 */
                for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) {
-                       if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
+                       if (acpi_gbl_mutex_info[i].thread_id ==
+                           acpi_os_get_thread_id()) {
                                if (i == mutex_id) {
                                        continue;
                                }
index 188340a017b4036422e900ccac69d44f44754780..b112744fc9ae3018dd591b5904f94b8059ea6b10 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1fb10cb8f11dfdaa660c0bf4ee9095a79986bd55..2360cf70c18ccdcb810ccc08c2c520d3bcaf3948 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6ffd3a8bdaa5dadbdac41ede3dd0f6c95db8c0f4..9d441ea703052545c2b9f98f122de42a6acfb26e 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,7 @@
 
 #include <acpi/acpi.h>
 #include "accommon.h"
-#include "amlresrc.h"
+#include "acresrc.h"
 
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utresrc")
@@ -154,6 +154,138 @@ const char *acpi_gbl_typ_decode[] = {
        "TypeF"
 };
 
+const char *acpi_gbl_ppc_decode[] = {
+       "PullDefault",
+       "PullUp",
+       "PullDown",
+       "PullNone"
+};
+
+const char *acpi_gbl_ior_decode[] = {
+       "IoRestrictionNone",
+       "IoRestrictionInputOnly",
+       "IoRestrictionOutputOnly",
+       "IoRestrictionNoneAndPreserve"
+};
+
+const char *acpi_gbl_dts_decode[] = {
+       "Width8bit",
+       "Width16bit",
+       "Width32bit",
+       "Width64bit",
+       "Width128bit",
+       "Width256bit",
+};
+
+/* GPIO connection type */
+
+const char *acpi_gbl_ct_decode[] = {
+       "Interrupt",
+       "I/O"
+};
+
+/* Serial bus type */
+
+const char *acpi_gbl_sbt_decode[] = {
+       "/* UNKNOWN serial bus type */",
+       "I2C",
+       "SPI",
+       "UART"
+};
+
+/* I2C serial bus access mode */
+
+const char *acpi_gbl_am_decode[] = {
+       "AddressingMode7Bit",
+       "AddressingMode10Bit"
+};
+
+/* I2C serial bus slave mode */
+
+const char *acpi_gbl_sm_decode[] = {
+       "ControllerInitiated",
+       "DeviceInitiated"
+};
+
+/* SPI serial bus wire mode */
+
+const char *acpi_gbl_wm_decode[] = {
+       "FourWireMode",
+       "ThreeWireMode"
+};
+
+/* SPI serial clock phase */
+
+const char *acpi_gbl_cph_decode[] = {
+       "ClockPhaseFirst",
+       "ClockPhaseSecond"
+};
+
+/* SPI serial bus clock polarity */
+
+const char *acpi_gbl_cpo_decode[] = {
+       "ClockPolarityLow",
+       "ClockPolarityHigh"
+};
+
+/* SPI serial bus device polarity */
+
+const char *acpi_gbl_dp_decode[] = {
+       "PolarityLow",
+       "PolarityHigh"
+};
+
+/* UART serial bus endian */
+
+const char *acpi_gbl_ed_decode[] = {
+       "LittleEndian",
+       "BigEndian"
+};
+
+/* UART serial bus bits per byte */
+
+const char *acpi_gbl_bpb_decode[] = {
+       "DataBitsFive",
+       "DataBitsSix",
+       "DataBitsSeven",
+       "DataBitsEight",
+       "DataBitsNine",
+       "/* UNKNOWN Bits per byte */",
+       "/* UNKNOWN Bits per byte */",
+       "/* UNKNOWN Bits per byte */"
+};
+
+/* UART serial bus stop bits */
+
+const char *acpi_gbl_sb_decode[] = {
+       "StopBitsNone",
+       "StopBitsOne",
+       "StopBitsOnePlusHalf",
+       "StopBitsTwo"
+};
+
+/* UART serial bus flow control */
+
+const char *acpi_gbl_fc_decode[] = {
+       "FlowControlNone",
+       "FlowControlHardware",
+       "FlowControlXON",
+       "/* UNKNOWN flow control keyword */"
+};
+
+/* UART serial bus parity type */
+
+const char *acpi_gbl_pt_decode[] = {
+       "ParityTypeNone",
+       "ParityTypeEven",
+       "ParityTypeOdd",
+       "ParityTypeMark",
+       "ParityTypeSpace",
+       "/* UNKNOWN parity keyword */",
+       "/* UNKNOWN parity keyword */",
+       "/* UNKNOWN parity keyword */"
+};
+
 #endif
 
 /*
@@ -173,7 +305,7 @@ const u8 acpi_gbl_resource_aml_sizes[] = {
        ACPI_AML_SIZE_SMALL(struct aml_resource_end_dependent),
        ACPI_AML_SIZE_SMALL(struct aml_resource_io),
        ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_io),
-       0,
+       ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_dma),
        0,
        0,
        0,
@@ -193,7 +325,17 @@ const u8 acpi_gbl_resource_aml_sizes[] = {
        ACPI_AML_SIZE_LARGE(struct aml_resource_address16),
        ACPI_AML_SIZE_LARGE(struct aml_resource_extended_irq),
        ACPI_AML_SIZE_LARGE(struct aml_resource_address64),
-       ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64)
+       ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64),
+       ACPI_AML_SIZE_LARGE(struct aml_resource_gpio),
+       0,
+       ACPI_AML_SIZE_LARGE(struct aml_resource_common_serialbus),
+};
+
+const u8 acpi_gbl_resource_aml_serial_bus_sizes[] = {
+       0,
+       ACPI_AML_SIZE_LARGE(struct aml_resource_i2c_serialbus),
+       ACPI_AML_SIZE_LARGE(struct aml_resource_spi_serialbus),
+       ACPI_AML_SIZE_LARGE(struct aml_resource_uart_serialbus),
 };
 
 /*
@@ -209,35 +351,49 @@ static const u8 acpi_gbl_resource_types[] = {
        0,
        0,
        0,
-       ACPI_SMALL_VARIABLE_LENGTH,
-       ACPI_FIXED_LENGTH,
-       ACPI_SMALL_VARIABLE_LENGTH,
-       ACPI_FIXED_LENGTH,
-       ACPI_FIXED_LENGTH,
-       ACPI_FIXED_LENGTH,
-       0,
+       ACPI_SMALL_VARIABLE_LENGTH,     /* 04 IRQ */
+       ACPI_FIXED_LENGTH,      /* 05 DMA */
+       ACPI_SMALL_VARIABLE_LENGTH,     /* 06 start_dependent_functions */
+       ACPI_FIXED_LENGTH,      /* 07 end_dependent_functions */
+       ACPI_FIXED_LENGTH,      /* 08 IO */
+       ACPI_FIXED_LENGTH,      /* 09 fixed_iO */
+       ACPI_FIXED_LENGTH,      /* 0_a fixed_dMA */
        0,
        0,
        0,
-       ACPI_VARIABLE_LENGTH,
-       ACPI_FIXED_LENGTH,
+       ACPI_VARIABLE_LENGTH,   /* 0_e vendor_short */
+       ACPI_FIXED_LENGTH,      /* 0_f end_tag */
 
        /* Large descriptors */
 
        0,
-       ACPI_FIXED_LENGTH,
-       ACPI_FIXED_LENGTH,
+       ACPI_FIXED_LENGTH,      /* 01 Memory24 */
+       ACPI_FIXED_LENGTH,      /* 02 generic_register */
        0,
-       ACPI_VARIABLE_LENGTH,
-       ACPI_FIXED_LENGTH,
-       ACPI_FIXED_LENGTH,
-       ACPI_VARIABLE_LENGTH,
-       ACPI_VARIABLE_LENGTH,
-       ACPI_VARIABLE_LENGTH,
-       ACPI_VARIABLE_LENGTH,
-       ACPI_FIXED_LENGTH
+       ACPI_VARIABLE_LENGTH,   /* 04 vendor_long */
+       ACPI_FIXED_LENGTH,      /* 05 Memory32 */
+       ACPI_FIXED_LENGTH,      /* 06 memory32_fixed */
+       ACPI_VARIABLE_LENGTH,   /* 07 Dword* address */
+       ACPI_VARIABLE_LENGTH,   /* 08 Word* address */
+       ACPI_VARIABLE_LENGTH,   /* 09 extended_iRQ */
+       ACPI_VARIABLE_LENGTH,   /* 0_a Qword* address */
+       ACPI_FIXED_LENGTH,      /* 0_b Extended* address */
+       ACPI_VARIABLE_LENGTH,   /* 0_c Gpio* */
+       0,
+       ACPI_VARIABLE_LENGTH    /* 0_e *serial_bus */
 };
 
+/*
+ * For the i_aSL compiler/disassembler, we don't want any error messages
+ * because the disassembler uses the resource validation code to determine
+ * if Buffer objects are actually Resource Templates.
+ */
+#ifdef ACPI_ASL_COMPILER
+#define ACPI_RESOURCE_ERROR(plist)
+#else
+#define ACPI_RESOURCE_ERROR(plist)  ACPI_ERROR(plist)
+#endif
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_walk_aml_resources
@@ -265,6 +421,7 @@ acpi_ut_walk_aml_resources(u8 * aml,
        u8 resource_index;
        u32 length;
        u32 offset = 0;
+       u8 end_tag[2] = { 0x79, 0x00 };
 
        ACPI_FUNCTION_TRACE(ut_walk_aml_resources);
 
@@ -286,6 +443,10 @@ acpi_ut_walk_aml_resources(u8 * aml,
 
                status = acpi_ut_validate_resource(aml, &resource_index);
                if (ACPI_FAILURE(status)) {
+                       /*
+                        * Exit on failure. Cannot continue because the descriptor length
+                        * may be bogus also.
+                        */
                        return_ACPI_STATUS(status);
                }
 
@@ -300,7 +461,7 @@ acpi_ut_walk_aml_resources(u8 * aml,
                            user_function(aml, length, offset, resource_index,
                                          context);
                        if (ACPI_FAILURE(status)) {
-                               return (status);
+                               return_ACPI_STATUS(status);
                        }
                }
 
@@ -333,7 +494,19 @@ acpi_ut_walk_aml_resources(u8 * aml,
 
        /* Did not find an end_tag descriptor */
 
-       return (AE_AML_NO_RESOURCE_END_TAG);
+       if (user_function) {
+
+               /* Insert an end_tag anyway. acpi_rs_get_list_length always leaves room */
+
+               (void)acpi_ut_validate_resource(end_tag, &resource_index);
+               status =
+                   user_function(end_tag, 2, offset, resource_index, context);
+               if (ACPI_FAILURE(status)) {
+                       return_ACPI_STATUS(status);
+               }
+       }
+
+       return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
 }
 
 /*******************************************************************************
@@ -354,6 +527,7 @@ acpi_ut_walk_aml_resources(u8 * aml,
 
 acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
 {
+       union aml_resource *aml_resource;
        u8 resource_type;
        u8 resource_index;
        acpi_rs_length resource_length;
@@ -375,7 +549,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
                /* Verify the large resource type (name) against the max */
 
                if (resource_type > ACPI_RESOURCE_NAME_LARGE_MAX) {
-                       return (AE_AML_INVALID_RESOURCE_TYPE);
+                       goto invalid_resource;
                }
 
                /*
@@ -392,15 +566,17 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
                    ((resource_type & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3);
        }
 
-       /* Check validity of the resource type, zero indicates name is invalid */
-
+       /*
+        * Check validity of the resource type, via acpi_gbl_resource_types. Zero
+        * indicates an invalid resource.
+        */
        if (!acpi_gbl_resource_types[resource_index]) {
-               return (AE_AML_INVALID_RESOURCE_TYPE);
+               goto invalid_resource;
        }
 
        /*
-        * 2) Validate the resource_length field. This ensures that the length
-        *    is at least reasonable, and guarantees that it is non-zero.
+        * Validate the resource_length field. This ensures that the length
+        * is at least reasonable, and guarantees that it is non-zero.
         */
        resource_length = acpi_ut_get_resource_length(aml);
        minimum_resource_length = acpi_gbl_resource_aml_sizes[resource_index];
@@ -413,7 +589,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
                /* Fixed length resource, length must match exactly */
 
                if (resource_length != minimum_resource_length) {
-                       return (AE_AML_BAD_RESOURCE_LENGTH);
+                       goto bad_resource_length;
                }
                break;
 
@@ -422,7 +598,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
                /* Variable length resource, length must be at least the minimum */
 
                if (resource_length < minimum_resource_length) {
-                       return (AE_AML_BAD_RESOURCE_LENGTH);
+                       goto bad_resource_length;
                }
                break;
 
@@ -432,7 +608,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
 
                if ((resource_length > minimum_resource_length) ||
                    (resource_length < (minimum_resource_length - 1))) {
-                       return (AE_AML_BAD_RESOURCE_LENGTH);
+                       goto bad_resource_length;
                }
                break;
 
@@ -440,7 +616,23 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
 
                /* Shouldn't happen (because of validation earlier), but be sure */
 
-               return (AE_AML_INVALID_RESOURCE_TYPE);
+               goto invalid_resource;
+       }
+
+       aml_resource = ACPI_CAST_PTR(union aml_resource, aml);
+       if (resource_type == ACPI_RESOURCE_NAME_SERIAL_BUS) {
+
+               /* Validate the bus_type field */
+
+               if ((aml_resource->common_serial_bus.type == 0) ||
+                   (aml_resource->common_serial_bus.type >
+                    AML_RESOURCE_MAX_SERIALBUSTYPE)) {
+                       ACPI_RESOURCE_ERROR((AE_INFO,
+                                            "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X",
+                                            aml_resource->common_serial_bus.
+                                            type));
+                       return (AE_AML_INVALID_RESOURCE_TYPE);
+               }
        }
 
        /* Optionally return the resource table index */
@@ -450,6 +642,22 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
        }
 
        return (AE_OK);
+
+      invalid_resource:
+
+       ACPI_RESOURCE_ERROR((AE_INFO,
+                            "Invalid/unsupported resource descriptor: Type 0x%2.2X",
+                            resource_type));
+       return (AE_AML_INVALID_RESOURCE_TYPE);
+
+      bad_resource_length:
+
+       ACPI_RESOURCE_ERROR((AE_INFO,
+                            "Invalid resource descriptor length: Type "
+                            "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X",
+                            resource_type, resource_length,
+                            minimum_resource_length));
+       return (AE_AML_BAD_RESOURCE_LENGTH);
 }
 
 /*******************************************************************************
index 30c21e1a9360c79adad9516dbd12787f9e892bd8..4267477c2797b2558becff9b23683d24a3cfadd1 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 420ebfe08c7218b091e1050217524547b15284aa..644e8c8ebc4b30c6ea3ca607708e3478c806c4bc 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,7 @@
 #include "acnamesp.h"
 #include "acdebug.h"
 #include "actables.h"
+#include "acinterp.h"
 
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utxface")
@@ -640,4 +641,41 @@ acpi_status acpi_install_interface_handler(acpi_interface_handler handler)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_install_interface_handler)
+
+/*****************************************************************************
+ *
+ * FUNCTION:    acpi_check_address_range
+ *
+ * PARAMETERS:  space_id            - Address space ID
+ *              Address             - Start address
+ *              Length              - Length
+ *              Warn                - TRUE if warning on overlap desired
+ *
+ * RETURN:      Count of the number of conflicts detected.
+ *
+ * DESCRIPTION: Check if the input address range overlaps any of the
+ *              ASL operation region address ranges.
+ *
+ ****************************************************************************/
+u32
+acpi_check_address_range(acpi_adr_space_type space_id,
+                        acpi_physical_address address,
+                        acpi_size length, u8 warn)
+{
+       u32 overlaps;
+       acpi_status status;
+
+       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+       if (ACPI_FAILURE(status)) {
+               return (0);
+       }
+
+       overlaps = acpi_ut_check_address_range(space_id, address,
+                                              (u32)length, warn);
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+       return (overlaps);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_check_address_range)
 #endif                         /* !ACPI_ASL_COMPILER */
index 8d0245ec431525bbd62a030d82e1eea2bfcdb9bd..52b568af18199570446431a81638814b3cc6c99a 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2011, Intel Corp.
+ * Copyright (C) 2000 - 2012, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c
new file mode 100644 (file)
index 0000000..1427d19
--- /dev/null
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ *
+ * Module Name: utxfmutex - external AML mutex access functions
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2012, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_UTILITIES
+ACPI_MODULE_NAME("utxfmutex")
+
+/* Local prototypes */
+static acpi_status
+acpi_ut_get_mutex_object(acpi_handle handle,
+                        acpi_string pathname,
+                        union acpi_operand_object **ret_obj);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_get_mutex_object
+ *
+ * PARAMETERS:  Handle              - Mutex or prefix handle (optional)
+ *              Pathname            - Mutex pathname (optional)
+ *              ret_obj             - Where the mutex object is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get an AML mutex object. The mutex node is pointed to by
+ *              Handle:Pathname. Either Handle or Pathname can be NULL, but
+ *              not both.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ut_get_mutex_object(acpi_handle handle,
+                        acpi_string pathname,
+                        union acpi_operand_object **ret_obj)
+{
+       struct acpi_namespace_node *mutex_node;
+       union acpi_operand_object *mutex_obj;
+       acpi_status status;
+
+       /* Parameter validation */
+
+       if (!ret_obj || (!handle && !pathname)) {
+               return (AE_BAD_PARAMETER);
+       }
+
+       /* Get a the namespace node for the mutex */
+
+       mutex_node = handle;
+       if (pathname != NULL) {
+               status = acpi_get_handle(handle, pathname,
+                                        ACPI_CAST_PTR(acpi_handle,
+                                                      &mutex_node));
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
+       }
+
+       /* Ensure that we actually have a Mutex object */
+
+       if (!mutex_node || (mutex_node->type != ACPI_TYPE_MUTEX)) {
+               return (AE_TYPE);
+       }
+
+       /* Get the low-level mutex object */
+
+       mutex_obj = acpi_ns_get_attached_object(mutex_node);
+       if (!mutex_obj) {
+               return (AE_NULL_OBJECT);
+       }
+
+       *ret_obj = mutex_obj;
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_acquire_mutex
+ *
+ * PARAMETERS:  Handle              - Mutex or prefix handle (optional)
+ *              Pathname            - Mutex pathname (optional)
+ *              Timeout             - Max time to wait for the lock (millisec)
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Acquire an AML mutex. This is a device driver interface to
+ *              AML mutex objects, and allows for transaction locking between
+ *              drivers and AML code. The mutex node is pointed to by
+ *              Handle:Pathname. Either Handle or Pathname can be NULL, but
+ *              not both.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_acquire_mutex(acpi_handle handle, acpi_string pathname, u16 timeout)
+{
+       acpi_status status;
+       union acpi_operand_object *mutex_obj;
+
+       /* Get the low-level mutex associated with Handle:Pathname */
+
+       status = acpi_ut_get_mutex_object(handle, pathname, &mutex_obj);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       /* Acquire the OS mutex */
+
+       status = acpi_os_acquire_mutex(mutex_obj->mutex.os_mutex, timeout);
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_release_mutex
+ *
+ * PARAMETERS:  Handle              - Mutex or prefix handle (optional)
+ *              Pathname            - Mutex pathname (optional)
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Release an AML mutex. This is a device driver interface to
+ *              AML mutex objects, and allows for transaction locking between
+ *              drivers and AML code. The mutex node is pointed to by
+ *              Handle:Pathname. Either Handle or Pathname can be NULL, but
+ *              not both.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_release_mutex(acpi_handle handle, acpi_string pathname)
+{
+       acpi_status status;
+       union acpi_operand_object *mutex_obj;
+
+       /* Get the low-level mutex associated with Handle:Pathname */
+
+       status = acpi_ut_get_mutex_object(handle, pathname, &mutex_obj);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       /* Release the OS mutex */
+
+       acpi_os_release_mutex(mutex_obj->mutex.os_mutex);
+       return (AE_OK);
+}
index 61540360d5ce815f67e67250874ad357f3e328e6..e45350cb6ac8356f9bbc161344a5875a976f430b 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/acpi.h>
+#include <linux/acpi_io.h>
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/kref.h>
 #include <linux/rculist.h>
 #include <linux/interrupt.h>
 #include <linux/debugfs.h>
-#include <acpi/atomicio.h>
 
 #include "apei-internal.h"
 
@@ -70,7 +70,7 @@ int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val)
 {
        int rc;
 
-       rc = acpi_atomic_read(val, &entry->register_region);
+       rc = apei_read(val, &entry->register_region);
        if (rc)
                return rc;
        *val >>= entry->register_region.bit_offset;
@@ -116,13 +116,13 @@ int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val)
        val <<= entry->register_region.bit_offset;
        if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) {
                u64 valr = 0;
-               rc = acpi_atomic_read(&valr, &entry->register_region);
+               rc = apei_read(&valr, &entry->register_region);
                if (rc)
                        return rc;
                valr &= ~(entry->mask << entry->register_region.bit_offset);
                val |= valr;
        }
-       rc = acpi_atomic_write(val, &entry->register_region);
+       rc = apei_write(val, &entry->register_region);
 
        return rc;
 }
@@ -243,7 +243,7 @@ static int pre_map_gar_callback(struct apei_exec_context *ctx,
        u8 ins = entry->instruction;
 
        if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
-               return acpi_pre_map_gar(&entry->register_region);
+               return acpi_os_map_generic_address(&entry->register_region);
 
        return 0;
 }
@@ -276,7 +276,7 @@ static int post_unmap_gar_callback(struct apei_exec_context *ctx,
        u8 ins = entry->instruction;
 
        if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
-               acpi_post_unmap_gar(&entry->register_region);
+               acpi_os_unmap_generic_address(&entry->register_region);
 
        return 0;
 }
@@ -421,6 +421,17 @@ static int apei_resources_merge(struct apei_resources *resources1,
        return 0;
 }
 
+int apei_resources_add(struct apei_resources *resources,
+                      unsigned long start, unsigned long size,
+                      bool iomem)
+{
+       if (iomem)
+               return apei_res_add(&resources->iomem, start, size);
+       else
+               return apei_res_add(&resources->ioport, start, size);
+}
+EXPORT_SYMBOL_GPL(apei_resources_add);
+
 /*
  * EINJ has two groups of GARs (EINJ table entry and trigger table
  * entry), so common resources are subtracted from the trigger table
@@ -438,8 +449,19 @@ int apei_resources_sub(struct apei_resources *resources1,
 }
 EXPORT_SYMBOL_GPL(apei_resources_sub);
 
+static int apei_get_nvs_callback(__u64 start, __u64 size, void *data)
+{
+       struct apei_resources *resources = data;
+       return apei_res_add(&resources->iomem, start, size);
+}
+
+static int apei_get_nvs_resources(struct apei_resources *resources)
+{
+       return acpi_nvs_for_each_region(apei_get_nvs_callback, resources);
+}
+
 /*
- * IO memory/port rersource management mechanism is used to check
+ * IO memory/port resource management mechanism is used to check
  * whether memory/port area used by GARs conflicts with normal memory
  * or IO memory/port of devices.
  */
@@ -448,21 +470,35 @@ int apei_resources_request(struct apei_resources *resources,
 {
        struct apei_res *res, *res_bak = NULL;
        struct resource *r;
+       struct apei_resources nvs_resources;
        int rc;
 
        rc = apei_resources_sub(resources, &apei_resources_all);
        if (rc)
                return rc;
 
+       /*
+        * Some firmware uses ACPI NVS region, that has been marked as
+        * busy, so exclude it from APEI resources to avoid false
+        * conflict.
+        */
+       apei_resources_init(&nvs_resources);
+       rc = apei_get_nvs_resources(&nvs_resources);
+       if (rc)
+               goto res_fini;
+       rc = apei_resources_sub(resources, &nvs_resources);
+       if (rc)
+               goto res_fini;
+
        rc = -EINVAL;
        list_for_each_entry(res, &resources->iomem, list) {
                r = request_mem_region(res->start, res->end - res->start,
                                       desc);
                if (!r) {
                        pr_err(APEI_PFX
-               "Can not request iomem region <%016llx-%016llx> for GARs.\n",
+               "Can not request [mem %#010llx-%#010llx] for %s registers\n",
                               (unsigned long long)res->start,
-                              (unsigned long long)res->end);
+                              (unsigned long long)res->end - 1, desc);
                        res_bak = res;
                        goto err_unmap_iomem;
                }
@@ -472,9 +508,9 @@ int apei_resources_request(struct apei_resources *resources,
                r = request_region(res->start, res->end - res->start, desc);
                if (!r) {
                        pr_err(APEI_PFX
-               "Can not request ioport region <%016llx-%016llx> for GARs.\n",
+               "Can not request [io  %#06llx-%#06llx] for %s registers\n",
                               (unsigned long long)res->start,
-                              (unsigned long long)res->end);
+                              (unsigned long long)res->end - 1, desc);
                        res_bak = res;
                        goto err_unmap_ioport;
                }
@@ -500,6 +536,8 @@ err_unmap_iomem:
                        break;
                release_mem_region(res->start, res->end - res->start);
        }
+res_fini:
+       apei_resources_fini(&nvs_resources);
        return rc;
 }
 EXPORT_SYMBOL_GPL(apei_resources_request);
@@ -553,6 +591,96 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr)
        return 0;
 }
 
+/* read GAR in interrupt (including NMI) or process context */
+int apei_read(u64 *val, struct acpi_generic_address *reg)
+{
+       int rc;
+       u64 address;
+       u32 tmp, width = reg->bit_width;
+       acpi_status status;
+
+       rc = apei_check_gar(reg, &address);
+       if (rc)
+               return rc;
+
+       if (width == 64)
+               width = 32;     /* Break into two 32-bit transfers */
+
+       *val = 0;
+       switch(reg->space_id) {
+       case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+               status = acpi_os_read_memory((acpi_physical_address)
+                                            address, &tmp, width);
+               if (ACPI_FAILURE(status))
+                       return -EIO;
+               *val = tmp;
+
+               if (reg->bit_width == 64) {
+                       /* Read the top 32 bits */
+                       status = acpi_os_read_memory((acpi_physical_address)
+                                                    (address + 4), &tmp, 32);
+                       if (ACPI_FAILURE(status))
+                               return -EIO;
+                       *val |= ((u64)tmp << 32);
+               }
+               break;
+       case ACPI_ADR_SPACE_SYSTEM_IO:
+               status = acpi_os_read_port(address, (u32 *)val, reg->bit_width);
+               if (ACPI_FAILURE(status))
+                       return -EIO;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_read);
+
+/* write GAR in interrupt (including NMI) or process context */
+int apei_write(u64 val, struct acpi_generic_address *reg)
+{
+       int rc;
+       u64 address;
+       u32 width = reg->bit_width;
+       acpi_status status;
+
+       rc = apei_check_gar(reg, &address);
+       if (rc)
+               return rc;
+
+       if (width == 64)
+               width = 32;     /* Break into two 32-bit transfers */
+
+       switch (reg->space_id) {
+       case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+               status = acpi_os_write_memory((acpi_physical_address)
+                                             address, ACPI_LODWORD(val),
+                                             width);
+               if (ACPI_FAILURE(status))
+                       return -EIO;
+
+               if (reg->bit_width == 64) {
+                       status = acpi_os_write_memory((acpi_physical_address)
+                                                     (address + 4),
+                                                     ACPI_HIDWORD(val), 32);
+                       if (ACPI_FAILURE(status))
+                               return -EIO;
+               }
+               break;
+       case ACPI_ADR_SPACE_SYSTEM_IO:
+               status = acpi_os_write_port(address, val, reg->bit_width);
+               if (ACPI_FAILURE(status))
+                       return -EIO;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apei_write);
+
 static int collect_res_callback(struct apei_exec_context *ctx,
                                struct acpi_whea_header *entry,
                                void *data)
index f57050e7a5e756ceb1f8885ce01030d0ac593ea4..cca240a33038fe148ca5e9324214ba988c62c6c2 100644 (file)
@@ -68,6 +68,9 @@ static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 actio
 /* IP has been set in instruction function */
 #define APEI_EXEC_SET_IP       1
 
+int apei_read(u64 *val, struct acpi_generic_address *reg);
+int apei_write(u64 val, struct acpi_generic_address *reg);
+
 int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val);
 int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val);
 int apei_exec_read_register(struct apei_exec_context *ctx,
@@ -95,6 +98,9 @@ static inline void apei_resources_init(struct apei_resources *resources)
 }
 
 void apei_resources_fini(struct apei_resources *resources);
+int apei_resources_add(struct apei_resources *resources,
+                      unsigned long start, unsigned long size,
+                      bool iomem);
 int apei_resources_sub(struct apei_resources *resources1,
                       struct apei_resources *resources2);
 int apei_resources_request(struct apei_resources *resources,
index 589b96c38704db0bf803842aaf3c6b22b890cd06..5b898d4dda99930cc9e8282ab3abdc6c3f4d8b0e 100644 (file)
 /* Firmware should respond within 1 milliseconds */
 #define FIRMWARE_TIMEOUT       (1 * NSEC_PER_MSEC)
 
+/*
+ * ACPI version 5 provides a SET_ERROR_TYPE_WITH_ADDRESS action.
+ */
+static int acpi5;
+
+struct set_error_type_with_address {
+       u32     type;
+       u32     vendor_extension;
+       u32     flags;
+       u32     apicid;
+       u64     memory_address;
+       u64     memory_address_range;
+       u32     pcie_sbdf;
+};
+enum {
+       SETWA_FLAGS_APICID = 1,
+       SETWA_FLAGS_MEM = 2,
+       SETWA_FLAGS_PCIE_SBDF = 4,
+};
+
+/*
+ * Vendor extensions for platform specific operations
+ */
+struct vendor_error_type_extension {
+       u32     length;
+       u32     pcie_sbdf;
+       u16     vendor_id;
+       u16     device_id;
+       u8      rev_id;
+       u8      reserved[3];
+};
+
+static u32 vendor_flags;
+static struct debugfs_blob_wrapper vendor_blob;
+static char vendor_dev[64];
+
 /*
  * Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the
  * EINJ table through an unpublished extension. Use with caution as
@@ -103,7 +139,14 @@ static struct apei_exec_ins_type einj_ins_type[] = {
  */
 static DEFINE_MUTEX(einj_mutex);
 
-static struct einj_parameter *einj_param;
+static void *einj_param;
+
+#ifndef readq
+static inline __u64 readq(volatile void __iomem *addr)
+{
+       return ((__u64)readl(addr+4) << 32) + readl(addr);
+}
+#endif
 
 #ifndef writeq
 static inline void writeq(__u64 val, volatile void __iomem *addr)
@@ -158,10 +201,31 @@ static int einj_timedout(u64 *t)
        return 0;
 }
 
-static u64 einj_get_parameter_address(void)
+static void check_vendor_extension(u64 paddr,
+                                  struct set_error_type_with_address *v5param)
+{
+       int     offset = readl(&v5param->vendor_extension);
+       struct  vendor_error_type_extension *v;
+       u32     sbdf;
+
+       if (!offset)
+               return;
+       v = ioremap(paddr + offset, sizeof(*v));
+       if (!v)
+               return;
+       sbdf = readl(&v->pcie_sbdf);
+       sprintf(vendor_dev, "%x:%x:%x.%x vendor_id=%x device_id=%x rev_id=%x\n",
+               sbdf >> 24, (sbdf >> 16) & 0xff,
+               (sbdf >> 11) & 0x1f, (sbdf >> 8) & 0x7,
+                readw(&v->vendor_id), readw(&v->device_id),
+               readb(&v->rev_id));
+       iounmap(v);
+}
+
+static void *einj_get_parameter_address(void)
 {
        int i;
-       u64 paddr = 0;
+       u64 paddrv4 = 0, paddrv5 = 0;
        struct acpi_whea_header *entry;
 
        entry = EINJ_TAB_ENTRY(einj_tab);
@@ -170,12 +234,40 @@ static u64 einj_get_parameter_address(void)
                    entry->instruction == ACPI_EINJ_WRITE_REGISTER &&
                    entry->register_region.space_id ==
                    ACPI_ADR_SPACE_SYSTEM_MEMORY)
-                       memcpy(&paddr, &entry->register_region.address,
-                              sizeof(paddr));
+                       memcpy(&paddrv4, &entry->register_region.address,
+                              sizeof(paddrv4));
+               if (entry->action == ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS &&
+                   entry->instruction == ACPI_EINJ_WRITE_REGISTER &&
+                   entry->register_region.space_id ==
+                   ACPI_ADR_SPACE_SYSTEM_MEMORY)
+                       memcpy(&paddrv5, &entry->register_region.address,
+                              sizeof(paddrv5));
                entry++;
        }
+       if (paddrv5) {
+               struct set_error_type_with_address *v5param;
+
+               v5param = ioremap(paddrv5, sizeof(*v5param));
+               if (v5param) {
+                       acpi5 = 1;
+                       check_vendor_extension(paddrv5, v5param);
+                       return v5param;
+               }
+       }
+       if (paddrv4) {
+               struct einj_parameter *v4param;
+
+               v4param = ioremap(paddrv4, sizeof(*v4param));
+               if (!v4param)
+                       return 0;
+               if (readq(&v4param->reserved1) || readq(&v4param->reserved2)) {
+                       iounmap(v4param);
+                       return 0;
+               }
+               return v4param;
+       }
 
-       return paddr;
+       return 0;
 }
 
 /* do sanity check to trigger table */
@@ -194,8 +286,29 @@ static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab)
        return 0;
 }
 
+static struct acpi_generic_address *einj_get_trigger_parameter_region(
+       struct acpi_einj_trigger *trigger_tab, u64 param1, u64 param2)
+{
+       int i;
+       struct acpi_whea_header *entry;
+
+       entry = (struct acpi_whea_header *)
+               ((char *)trigger_tab + sizeof(struct acpi_einj_trigger));
+       for (i = 0; i < trigger_tab->entry_count; i++) {
+               if (entry->action == ACPI_EINJ_TRIGGER_ERROR &&
+               entry->instruction == ACPI_EINJ_WRITE_REGISTER_VALUE &&
+               entry->register_region.space_id ==
+                       ACPI_ADR_SPACE_SYSTEM_MEMORY &&
+               (entry->register_region.address & param2) == (param1 & param2))
+                       return &entry->register_region;
+               entry++;
+       }
+
+       return NULL;
+}
 /* Execute instructions in trigger error action table */
-static int __einj_error_trigger(u64 trigger_paddr)
+static int __einj_error_trigger(u64 trigger_paddr, u32 type,
+                               u64 param1, u64 param2)
 {
        struct acpi_einj_trigger *trigger_tab = NULL;
        struct apei_exec_context trigger_ctx;
@@ -204,14 +317,16 @@ static int __einj_error_trigger(u64 trigger_paddr)
        struct resource *r;
        u32 table_size;
        int rc = -EIO;
+       struct acpi_generic_address *trigger_param_region = NULL;
 
        r = request_mem_region(trigger_paddr, sizeof(*trigger_tab),
                               "APEI EINJ Trigger Table");
        if (!r) {
                pr_err(EINJ_PFX
-       "Can not request iomem region <%016llx-%016llx> for Trigger table.\n",
+       "Can not request [mem %#010llx-%#010llx] for Trigger table\n",
                       (unsigned long long)trigger_paddr,
-                      (unsigned long long)trigger_paddr+sizeof(*trigger_tab));
+                      (unsigned long long)trigger_paddr +
+                           sizeof(*trigger_tab) - 1);
                goto out;
        }
        trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab));
@@ -232,9 +347,9 @@ static int __einj_error_trigger(u64 trigger_paddr)
                               "APEI EINJ Trigger Table");
        if (!r) {
                pr_err(EINJ_PFX
-"Can not request iomem region <%016llx-%016llx> for Trigger Table Entry.\n",
-                      (unsigned long long)trigger_paddr+sizeof(*trigger_tab),
-                      (unsigned long long)trigger_paddr + table_size);
+"Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n",
+                      (unsigned long long)trigger_paddr + sizeof(*trigger_tab),
+                      (unsigned long long)trigger_paddr + table_size - 1);
                goto out_rel_header;
        }
        iounmap(trigger_tab);
@@ -255,6 +370,30 @@ static int __einj_error_trigger(u64 trigger_paddr)
        rc = apei_resources_sub(&trigger_resources, &einj_resources);
        if (rc)
                goto out_fini;
+       /*
+        * Some firmware will access target address specified in
+        * param1 to trigger the error when injecting memory error.
+        * This will cause resource conflict with regular memory.  So
+        * remove it from trigger table resources.
+        */
+       if (param_extension && (type & 0x0038) && param2) {
+               struct apei_resources addr_resources;
+               apei_resources_init(&addr_resources);
+               trigger_param_region = einj_get_trigger_parameter_region(
+                       trigger_tab, param1, param2);
+               if (trigger_param_region) {
+                       rc = apei_resources_add(&addr_resources,
+                               trigger_param_region->address,
+                               trigger_param_region->bit_width/8, true);
+                       if (rc)
+                               goto out_fini;
+                       rc = apei_resources_sub(&trigger_resources,
+                                       &addr_resources);
+               }
+               apei_resources_fini(&addr_resources);
+               if (rc)
+                       goto out_fini;
+       }
        rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger");
        if (rc)
                goto out_fini;
@@ -293,12 +432,56 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
        if (rc)
                return rc;
        apei_exec_ctx_set_input(&ctx, type);
-       rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE);
-       if (rc)
-               return rc;
-       if (einj_param) {
-               writeq(param1, &einj_param->param1);
-               writeq(param2, &einj_param->param2);
+       if (acpi5) {
+               struct set_error_type_with_address *v5param = einj_param;
+
+               writel(type, &v5param->type);
+               if (type & 0x80000000) {
+                       switch (vendor_flags) {
+                       case SETWA_FLAGS_APICID:
+                               writel(param1, &v5param->apicid);
+                               break;
+                       case SETWA_FLAGS_MEM:
+                               writeq(param1, &v5param->memory_address);
+                               writeq(param2, &v5param->memory_address_range);
+                               break;
+                       case SETWA_FLAGS_PCIE_SBDF:
+                               writel(param1, &v5param->pcie_sbdf);
+                               break;
+                       }
+                       writel(vendor_flags, &v5param->flags);
+               } else {
+                       switch (type) {
+                       case ACPI_EINJ_PROCESSOR_CORRECTABLE:
+                       case ACPI_EINJ_PROCESSOR_UNCORRECTABLE:
+                       case ACPI_EINJ_PROCESSOR_FATAL:
+                               writel(param1, &v5param->apicid);
+                               writel(SETWA_FLAGS_APICID, &v5param->flags);
+                               break;
+                       case ACPI_EINJ_MEMORY_CORRECTABLE:
+                       case ACPI_EINJ_MEMORY_UNCORRECTABLE:
+                       case ACPI_EINJ_MEMORY_FATAL:
+                               writeq(param1, &v5param->memory_address);
+                               writeq(param2, &v5param->memory_address_range);
+                               writel(SETWA_FLAGS_MEM, &v5param->flags);
+                               break;
+                       case ACPI_EINJ_PCIX_CORRECTABLE:
+                       case ACPI_EINJ_PCIX_UNCORRECTABLE:
+                       case ACPI_EINJ_PCIX_FATAL:
+                               writel(param1, &v5param->pcie_sbdf);
+                               writel(SETWA_FLAGS_PCIE_SBDF, &v5param->flags);
+                               break;
+                       }
+               }
+       } else {
+               rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE);
+               if (rc)
+                       return rc;
+               if (einj_param) {
+                       struct einj_parameter *v4param = einj_param;
+                       writeq(param1, &v4param->param1);
+                       writeq(param2, &v4param->param2);
+               }
        }
        rc = apei_exec_run(&ctx, ACPI_EINJ_EXECUTE_OPERATION);
        if (rc)
@@ -324,7 +507,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
        if (rc)
                return rc;
        trigger_paddr = apei_exec_ctx_get_output(&ctx);
-       rc = __einj_error_trigger(trigger_paddr);
+       rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
        if (rc)
                return rc;
        rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION);
@@ -408,15 +591,25 @@ static int error_type_set(void *data, u64 val)
 {
        int rc;
        u32 available_error_type = 0;
+       u32 tval, vendor;
+
+       /*
+        * Vendor defined types have 0x80000000 bit set, and
+        * are not enumerated by ACPI_EINJ_GET_ERROR_TYPE
+        */
+       vendor = val & 0x80000000;
+       tval = val & 0x7fffffff;
 
        /* Only one error type can be specified */
-       if (val & (val - 1))
-               return -EINVAL;
-       rc = einj_get_available_error_type(&available_error_type);
-       if (rc)
-               return rc;
-       if (!(val & available_error_type))
+       if (tval & (tval - 1))
                return -EINVAL;
+       if (!vendor) {
+               rc = einj_get_available_error_type(&available_error_type);
+               if (rc)
+                       return rc;
+               if (!(val & available_error_type))
+                       return -EINVAL;
+       }
        error_type = val;
 
        return 0;
@@ -455,7 +648,6 @@ static int einj_check_table(struct acpi_table_einj *einj_tab)
 static int __init einj_init(void)
 {
        int rc;
-       u64 param_paddr;
        acpi_status status;
        struct dentry *fentry;
        struct apei_exec_context ctx;
@@ -465,10 +657,9 @@ static int __init einj_init(void)
 
        status = acpi_get_table(ACPI_SIG_EINJ, 0,
                                (struct acpi_table_header **)&einj_tab);
-       if (status == AE_NOT_FOUND) {
-               pr_info(EINJ_PFX "Table is not found!\n");
+       if (status == AE_NOT_FOUND)
                return -ENODEV;
-       else if (ACPI_FAILURE(status)) {
+       else if (ACPI_FAILURE(status)) {
                const char *msg = acpi_format_exception(status);
                pr_err(EINJ_PFX "Failed to get table, %s\n", msg);
                return -EINVAL;
@@ -509,23 +700,30 @@ static int __init einj_init(void)
        rc = apei_exec_pre_map_gars(&ctx);
        if (rc)
                goto err_release;
-       if (param_extension) {
-               param_paddr = einj_get_parameter_address();
-               if (param_paddr) {
-                       einj_param = ioremap(param_paddr, sizeof(*einj_param));
-                       rc = -ENOMEM;
-                       if (!einj_param)
-                               goto err_unmap;
-                       fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR,
-                                                   einj_debug_dir, &error_param1);
-                       if (!fentry)
-                               goto err_unmap;
-                       fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR,
-                                                   einj_debug_dir, &error_param2);
-                       if (!fentry)
-                               goto err_unmap;
-               } else
-                       pr_warn(EINJ_PFX "Parameter extension is not supported.\n");
+
+       einj_param = einj_get_parameter_address();
+       if ((param_extension || acpi5) && einj_param) {
+               fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR,
+                                           einj_debug_dir, &error_param1);
+               if (!fentry)
+                       goto err_unmap;
+               fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR,
+                                           einj_debug_dir, &error_param2);
+               if (!fentry)
+                       goto err_unmap;
+       }
+
+       if (vendor_dev[0]) {
+               vendor_blob.data = vendor_dev;
+               vendor_blob.size = strlen(vendor_dev);
+               fentry = debugfs_create_blob("vendor", S_IRUSR,
+                                            einj_debug_dir, &vendor_blob);
+               if (!fentry)
+                       goto err_unmap;
+               fentry = debugfs_create_x32("vendor_flags", S_IRUSR | S_IWUSR,
+                                           einj_debug_dir, &vendor_flags);
+               if (!fentry)
+                       goto err_unmap;
        }
 
        pr_info(EINJ_PFX "Error INJection is initialized.\n");
index 6a9e3bad13f418d93572faff72d18a4df124f8e8..eb9fab5b96e4d3dca071e11e8dbdec2405b23508 100644 (file)
@@ -1127,10 +1127,9 @@ static int __init erst_init(void)
 
        status = acpi_get_table(ACPI_SIG_ERST, 0,
                                (struct acpi_table_header **)&erst_tab);
-       if (status == AE_NOT_FOUND) {
-               pr_info(ERST_PFX "Table is not found!\n");
+       if (status == AE_NOT_FOUND)
                goto err;
-       else if (ACPI_FAILURE(status)) {
+       else if (ACPI_FAILURE(status)) {
                const char *msg = acpi_format_exception(status);
                pr_err(ERST_PFX "Failed to get table, %s\n", msg);
                rc = -EINVAL;
index b8e08cb67a18a0b18dfa5d54d32a0177890f2b5b..9b3cac0abecc33c672c884ece470dfb494d1836c 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/acpi.h>
+#include <linux/acpi_io.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/timer.h>
@@ -45,8 +46,9 @@
 #include <linux/irq_work.h>
 #include <linux/llist.h>
 #include <linux/genalloc.h>
+#include <linux/pci.h>
+#include <linux/aer.h>
 #include <acpi/apei.h>
-#include <acpi/atomicio.h>
 #include <acpi/hed.h>
 #include <asm/mce.h>
 #include <asm/tlbflush.h>
@@ -118,7 +120,7 @@ struct ghes_estatus_cache {
        struct rcu_head rcu;
 };
 
-int ghes_disable;
+bool ghes_disable;
 module_param_named(disable, ghes_disable, bool, 0);
 
 static int ghes_panic_timeout  __read_mostly = 30;
@@ -299,7 +301,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
        if (!ghes)
                return ERR_PTR(-ENOMEM);
        ghes->generic = generic;
-       rc = acpi_pre_map_gar(&generic->error_status_address);
+       rc = acpi_os_map_generic_address(&generic->error_status_address);
        if (rc)
                goto err_free;
        error_block_length = generic->error_block_length;
@@ -319,7 +321,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
        return ghes;
 
 err_unmap:
-       acpi_post_unmap_gar(&generic->error_status_address);
+       acpi_os_unmap_generic_address(&generic->error_status_address);
 err_free:
        kfree(ghes);
        return ERR_PTR(rc);
@@ -328,7 +330,7 @@ err_free:
 static void ghes_fini(struct ghes *ghes)
 {
        kfree(ghes->estatus);
-       acpi_post_unmap_gar(&ghes->generic->error_status_address);
+       acpi_os_unmap_generic_address(&ghes->generic->error_status_address);
 }
 
 enum {
@@ -399,7 +401,7 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
        u32 len;
        int rc;
 
-       rc = acpi_atomic_read(&buf_paddr, &g->error_status_address);
+       rc = apei_read(&buf_paddr, &g->error_status_address);
        if (rc) {
                if (!silent && printk_ratelimit())
                        pr_warning(FW_WARN GHES_PFX
@@ -476,6 +478,27 @@ static void ghes_do_proc(const struct acpi_hest_generic_status *estatus)
                        }
 #endif
                }
+#ifdef CONFIG_ACPI_APEI_PCIEAER
+               else if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
+                                     CPER_SEC_PCIE)) {
+                       struct cper_sec_pcie *pcie_err;
+                       pcie_err = (struct cper_sec_pcie *)(gdata+1);
+                       if (sev == GHES_SEV_RECOVERABLE &&
+                           sec_sev == GHES_SEV_RECOVERABLE &&
+                           pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
+                           pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) {
+                               unsigned int devfn;
+                               int aer_severity;
+                               devfn = PCI_DEVFN(pcie_err->device_id.device,
+                                                 pcie_err->device_id.function);
+                               aer_severity = cper_severity_to_aer(sev);
+                               aer_recover_queue(pcie_err->device_id.segment,
+                                                 pcie_err->device_id.bus,
+                                                 devfn, aer_severity);
+                       }
+
+               }
+#endif
        }
 }
 
@@ -483,16 +506,22 @@ static void __ghes_print_estatus(const char *pfx,
                                 const struct acpi_hest_generic *generic,
                                 const struct acpi_hest_generic_status *estatus)
 {
+       static atomic_t seqno;
+       unsigned int curr_seqno;
+       char pfx_seq[64];
+
        if (pfx == NULL) {
                if (ghes_severity(estatus->error_severity) <=
                    GHES_SEV_CORRECTED)
-                       pfx = KERN_WARNING HW_ERR;
+                       pfx = KERN_WARNING;
                else
-                       pfx = KERN_ERR HW_ERR;
+                       pfx = KERN_ERR;
        }
+       curr_seqno = atomic_inc_return(&seqno);
+       snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, curr_seqno);
        printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n",
-              pfx, generic->header.source_id);
-       apei_estatus_print(pfx, estatus);
+              pfx_seq, generic->header.source_id);
+       apei_estatus_print(pfx_seq, estatus);
 }
 
 static int ghes_print_estatus(const char *pfx,
@@ -711,26 +740,34 @@ static int ghes_notify_sci(struct notifier_block *this,
        return ret;
 }
 
+static struct llist_node *llist_nodes_reverse(struct llist_node *llnode)
+{
+       struct llist_node *next, *tail = NULL;
+
+       while (llnode) {
+               next = llnode->next;
+               llnode->next = tail;
+               tail = llnode;
+               llnode = next;
+       }
+
+       return tail;
+}
+
 static void ghes_proc_in_irq(struct irq_work *irq_work)
 {
-       struct llist_node *llnode, *next, *tail = NULL;
+       struct llist_node *llnode, *next;
        struct ghes_estatus_node *estatus_node;
        struct acpi_hest_generic *generic;
        struct acpi_hest_generic_status *estatus;
        u32 len, node_len;
 
+       llnode = llist_del_all(&ghes_estatus_llist);
        /*
         * Because the time order of estatus in list is reversed,
         * revert it back to proper order.
         */
-       llnode = llist_del_all(&ghes_estatus_llist);
-       while (llnode) {
-               next = llnode->next;
-               llnode->next = tail;
-               tail = llnode;
-               llnode = next;
-       }
-       llnode = tail;
+       llnode = llist_nodes_reverse(llnode);
        while (llnode) {
                next = llnode->next;
                estatus_node = llist_entry(llnode, struct ghes_estatus_node,
@@ -750,6 +787,32 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
        }
 }
 
+static void ghes_print_queued_estatus(void)
+{
+       struct llist_node *llnode;
+       struct ghes_estatus_node *estatus_node;
+       struct acpi_hest_generic *generic;
+       struct acpi_hest_generic_status *estatus;
+       u32 len, node_len;
+
+       llnode = llist_del_all(&ghes_estatus_llist);
+       /*
+        * Because the time order of estatus in list is reversed,
+        * revert it back to proper order.
+        */
+       llnode = llist_nodes_reverse(llnode);
+       while (llnode) {
+               estatus_node = llist_entry(llnode, struct ghes_estatus_node,
+                                          llnode);
+               estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
+               len = apei_estatus_len(estatus);
+               node_len = GHES_ESTATUS_NODE_LEN(len);
+               generic = estatus_node->generic;
+               ghes_print_estatus(NULL, generic, estatus);
+               llnode = llnode->next;
+       }
+}
+
 static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
 {
        struct ghes *ghes, *ghes_global = NULL;
@@ -775,7 +838,8 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
 
        if (sev_global >= GHES_SEV_PANIC) {
                oops_begin();
-               __ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global->generic,
+               ghes_print_queued_estatus();
+               __ghes_print_estatus(KERN_EMERG, ghes_global->generic,
                                     ghes_global->estatus);
                /* reboot to log the error! */
                if (panic_timeout == 0)
index 05fee06f4d6e03019a3bc55bd3595b8967304669..7f00cf38098f21bdbe0d6a69ba624d18b00f7cb3 100644 (file)
@@ -41,7 +41,7 @@
 
 #define HEST_PFX "HEST: "
 
-int hest_disable;
+bool hest_disable;
 EXPORT_SYMBOL_GPL(hest_disable);
 
 /* HEST table parsing */
@@ -221,10 +221,9 @@ void __init acpi_hest_init(void)
 
        status = acpi_get_table(ACPI_SIG_HEST, 0,
                                (struct acpi_table_header **)&hest_tab);
-       if (status == AE_NOT_FOUND) {
-               pr_info(HEST_PFX "Table not found.\n");
+       if (status == AE_NOT_FOUND)
                goto err;
-       else if (ACPI_FAILURE(status)) {
+       else if (ACPI_FAILURE(status)) {
                const char *msg = acpi_format_exception(status);
                pr_err(HEST_PFX "Failed to get table, %s\n", msg);
                rc = -EINVAL;
index cfc0cc10af39f4e948d98a0d9de9d3e988a44fd1..d4a5b3d3657b61dc0a3159ad3b1cd37adc318242 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/rculist.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
 #include <acpi/atomicio.h>
 
 #define ACPI_PFX "ACPI: "
@@ -97,6 +99,37 @@ static void __iomem *__acpi_try_ioremap(phys_addr_t paddr,
                return NULL;
 }
 
+#ifndef CONFIG_IA64
+#define should_use_kmap(pfn)   page_is_ram(pfn)
+#else
+/* ioremap will take care of cache attributes */
+#define should_use_kmap(pfn)   0
+#endif
+
+static void __iomem *acpi_map(phys_addr_t pg_off, unsigned long pg_sz)
+{
+       unsigned long pfn;
+
+       pfn = pg_off >> PAGE_SHIFT;
+       if (should_use_kmap(pfn)) {
+               if (pg_sz > PAGE_SIZE)
+                       return NULL;
+               return (void __iomem __force *)kmap(pfn_to_page(pfn));
+       } else
+               return ioremap(pg_off, pg_sz);
+}
+
+static void acpi_unmap(phys_addr_t pg_off, void __iomem *vaddr)
+{
+       unsigned long pfn;
+
+       pfn = pg_off >> PAGE_SHIFT;
+       if (page_is_ram(pfn))
+               kunmap(pfn_to_page(pfn));
+       else
+               iounmap(vaddr);
+}
+
 /*
  * Used to pre-map the specified IO memory area. First try to find
  * whether the area is already pre-mapped, if it is, increase the
@@ -119,7 +152,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr,
 
        pg_off = paddr & PAGE_MASK;
        pg_sz = ((paddr + size + PAGE_SIZE - 1) & PAGE_MASK) - pg_off;
-       vaddr = ioremap(pg_off, pg_sz);
+       vaddr = acpi_map(pg_off, pg_sz);
        if (!vaddr)
                return NULL;
        map = kmalloc(sizeof(*map), GFP_KERNEL);
@@ -135,7 +168,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr,
        vaddr = __acpi_try_ioremap(paddr, size);
        if (vaddr) {
                spin_unlock_irqrestore(&acpi_iomaps_lock, flags);
-               iounmap(map->vaddr);
+               acpi_unmap(pg_off, map->vaddr);
                kfree(map);
                return vaddr;
        }
@@ -144,7 +177,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr,
 
        return map->vaddr + (paddr - map->paddr);
 err_unmap:
-       iounmap(vaddr);
+       acpi_unmap(pg_off, vaddr);
        return NULL;
 }
 
@@ -177,7 +210,7 @@ static void acpi_post_unmap(phys_addr_t paddr, unsigned long size)
                return;
 
        synchronize_rcu();
-       iounmap(map->vaddr);
+       acpi_unmap(map->paddr, map->vaddr);
        kfree(map);
 }
 
@@ -260,6 +293,21 @@ int acpi_post_unmap_gar(struct acpi_generic_address *reg)
 }
 EXPORT_SYMBOL_GPL(acpi_post_unmap_gar);
 
+#ifdef readq
+static inline u64 read64(const volatile void __iomem *addr)
+{
+       return readq(addr);
+}
+#else
+static inline u64 read64(const volatile void __iomem *addr)
+{
+       u64 l, h;
+       l = readl(addr);
+       h = readl(addr+4);
+       return l | (h << 32);
+}
+#endif
+
 /*
  * Can be used in atomic (including NMI) or process context. RCU read
  * lock can only be released after the IO memory area accessing.
@@ -280,11 +328,9 @@ static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width)
        case 32:
                *val = readl(addr);
                break;
-#ifdef readq
        case 64:
-               *val = readq(addr);
+               *val = read64(addr);
                break;
-#endif
        default:
                return -EINVAL;
        }
@@ -293,6 +339,19 @@ static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width)
        return 0;
 }
 
+#ifdef writeq
+static inline void write64(u64 val, volatile void __iomem *addr)
+{
+       writeq(val, addr);
+}
+#else
+static inline void write64(u64 val, volatile void __iomem *addr)
+{
+       writel(val, addr);
+       writel(val>>32, addr+4);
+}
+#endif
+
 static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width)
 {
        void __iomem *addr;
@@ -309,11 +368,9 @@ static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width)
        case 32:
                writel(val, addr);
                break;
-#ifdef writeq
        case 64:
-               writeq(val, addr);
+               write64(val, addr);
                break;
-#endif
        default:
                return -EINVAL;
        }
index 19a61136d8488460c1d7be2f96bb2c8dc88d0500..88eb14304667bc6bef8726e06ee0ecd8f339cca5 100644 (file)
@@ -43,7 +43,7 @@ MODULE_AUTHOR("Kristen Carlson Accardi");
 MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION);
 MODULE_LICENSE("GPL");
 
-static int immediate_undock = 1;
+static bool immediate_undock = 1;
 module_param(immediate_undock, bool, 0644);
 MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
        "undock immediately when the undock button is pressed, 0 will cause"
index 3b5c3189fd995e4cc200c532b2d05ba6b274fac7..e56f3be7b07d36fceb32dce25ede0fa35308f0e7 100644 (file)
@@ -45,6 +45,8 @@ static int pxm_to_node_map[MAX_PXM_DOMAINS]
 static int node_to_pxm_map[MAX_NUMNODES]
                        = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
 
+unsigned char acpi_srat_revision __initdata;
+
 int pxm_to_node(int pxm)
 {
        if (pxm < 0)
@@ -255,9 +257,13 @@ acpi_parse_memory_affinity(struct acpi_subtable_header * header,
 
 static int __init acpi_parse_srat(struct acpi_table_header *table)
 {
+       struct acpi_table_srat *srat;
        if (!table)
                return -EINVAL;
 
+       srat = (struct acpi_table_srat *)table;
+       acpi_srat_revision = srat->header.revision;
+
        /* Real work done in acpi_table_parse_srat below. */
 
        return 0;
index 096787b43c960a71afd971ed8f312ba39e7787a9..7a2035fa8c713d660a697d0d49e0a430476ed9fa 100644 (file)
 #include <linux/acpi_io.h>
 #include <acpi/acpiosxf.h>
 
+/* ACPI NVS regions, APEI may use it */
+
+struct nvs_region {
+       __u64 phys_start;
+       __u64 size;
+       struct list_head node;
+};
+
+static LIST_HEAD(nvs_region_list);
+
+#ifdef CONFIG_ACPI_SLEEP
+static int suspend_nvs_register(unsigned long start, unsigned long size);
+#else
+static inline int suspend_nvs_register(unsigned long a, unsigned long b)
+{
+       return 0;
+}
+#endif
+
+int acpi_nvs_register(__u64 start, __u64 size)
+{
+       struct nvs_region *region;
+
+       region = kmalloc(sizeof(*region), GFP_KERNEL);
+       if (!region)
+               return -ENOMEM;
+       region->phys_start = start;
+       region->size = size;
+       list_add_tail(&region->node, &nvs_region_list);
+
+       return suspend_nvs_register(start, size);
+}
+
+int acpi_nvs_for_each_region(int (*func)(__u64 start, __u64 size, void *data),
+                            void *data)
+{
+       int rc;
+       struct nvs_region *region;
+
+       list_for_each_entry(region, &nvs_region_list, node) {
+               rc = func(region->phys_start, region->size, data);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+
+#ifdef CONFIG_ACPI_SLEEP
 /*
  * Platforms, like ACPI, may want us to save some memory used by them during
  * suspend and to restore the contents of this memory during the subsequent
@@ -41,7 +91,7 @@ static LIST_HEAD(nvs_list);
  *     things so that the data from page-aligned addresses in this region will
  *     be copied into separate RAM pages.
  */
-int suspend_nvs_register(unsigned long start, unsigned long size)
+static int suspend_nvs_register(unsigned long start, unsigned long size)
 {
        struct nvs_page *entry, *next;
 
@@ -159,3 +209,4 @@ void suspend_nvs_restore(void)
                if (entry->data)
                        memcpy(entry->kaddr, entry->data, entry->size);
 }
+#endif
index f31c5c5f1b7e083351e013649f1e1d73fdd74fa6..fcc12d842bcc51cf0413e7316ac6dcf9e4cf0a1f 100644 (file)
@@ -83,19 +83,6 @@ static struct workqueue_struct *kacpi_notify_wq;
 struct workqueue_struct *kacpi_hotplug_wq;
 EXPORT_SYMBOL(kacpi_hotplug_wq);
 
-struct acpi_res_list {
-       resource_size_t start;
-       resource_size_t end;
-       acpi_adr_space_type resource_type; /* IO port, System memory, ...*/
-       char name[5];   /* only can have a length of 4 chars, make use of this
-                          one instead of res->name, no need to kalloc then */
-       struct list_head resource_list;
-       int count;
-};
-
-static LIST_HEAD(resource_list_head);
-static DEFINE_SPINLOCK(acpi_res_lock);
-
 /*
  * This list of permanent mappings is for memory that may be accessed from
  * interrupt context, where we can't do the ioremap().
@@ -166,17 +153,21 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported)
        return supported;
 }
 
-static void __init acpi_request_region (struct acpi_generic_address *addr,
+static void __init acpi_request_region (struct acpi_generic_address *gas,
        unsigned int length, char *desc)
 {
-       if (!addr->address || !length)
+       u64 addr;
+
+       /* Handle possible alignment issues */
+       memcpy(&addr, &gas->address, sizeof(addr));
+       if (!addr || !length)
                return;
 
        /* Resources are never freed */
-       if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
-               request_region(addr->address, length, desc);
-       else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
-               request_mem_region(addr->address, length, desc);
+       if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+               request_region(addr, length, desc);
+       else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+               request_mem_region(addr, length, desc);
 }
 
 static int __init acpi_reserve_resources(void)
@@ -427,35 +418,42 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
                __acpi_unmap_table(virt, size);
 }
 
-static int acpi_os_map_generic_address(struct acpi_generic_address *addr)
+int acpi_os_map_generic_address(struct acpi_generic_address *gas)
 {
+       u64 addr;
        void __iomem *virt;
 
-       if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
+       if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
                return 0;
 
-       if (!addr->address || !addr->bit_width)
+       /* Handle possible alignment issues */
+       memcpy(&addr, &gas->address, sizeof(addr));
+       if (!addr || !gas->bit_width)
                return -EINVAL;
 
-       virt = acpi_os_map_memory(addr->address, addr->bit_width / 8);
+       virt = acpi_os_map_memory(addr, gas->bit_width / 8);
        if (!virt)
                return -EIO;
 
        return 0;
 }
+EXPORT_SYMBOL(acpi_os_map_generic_address);
 
-static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr)
+void acpi_os_unmap_generic_address(struct acpi_generic_address *gas)
 {
+       u64 addr;
        struct acpi_ioremap *map;
 
-       if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
+       if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
                return;
 
-       if (!addr->address || !addr->bit_width)
+       /* Handle possible alignment issues */
+       memcpy(&addr, &gas->address, sizeof(addr));
+       if (!addr || !gas->bit_width)
                return;
 
        mutex_lock(&acpi_ioremap_lock);
-       map = acpi_map_lookup(addr->address, addr->bit_width / 8);
+       map = acpi_map_lookup(addr, gas->bit_width / 8);
        if (!map) {
                mutex_unlock(&acpi_ioremap_lock);
                return;
@@ -465,6 +463,7 @@ static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr)
 
        acpi_os_map_cleanup(map);
 }
+EXPORT_SYMBOL(acpi_os_unmap_generic_address);
 
 #ifdef ACPI_FUTURE_USAGE
 acpi_status
@@ -1278,44 +1277,28 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup);
  * drivers */
 int acpi_check_resource_conflict(const struct resource *res)
 {
-       struct acpi_res_list *res_list_elem;
-       int ioport = 0, clash = 0;
+       acpi_adr_space_type space_id;
+       acpi_size length;
+       u8 warn = 0;
+       int clash = 0;
 
        if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
                return 0;
        if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM))
                return 0;
 
-       ioport = res->flags & IORESOURCE_IO;
-
-       spin_lock(&acpi_res_lock);
-       list_for_each_entry(res_list_elem, &resource_list_head,
-                           resource_list) {
-               if (ioport && (res_list_elem->resource_type
-                              != ACPI_ADR_SPACE_SYSTEM_IO))
-                       continue;
-               if (!ioport && (res_list_elem->resource_type
-                               != ACPI_ADR_SPACE_SYSTEM_MEMORY))
-                       continue;
+       if (res->flags & IORESOURCE_IO)
+               space_id = ACPI_ADR_SPACE_SYSTEM_IO;
+       else
+               space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
 
-               if (res->end < res_list_elem->start
-                   || res_list_elem->end < res->start)
-                       continue;
-               clash = 1;
-               break;
-       }
-       spin_unlock(&acpi_res_lock);
+       length = res->end - res->start + 1;
+       if (acpi_enforce_resources != ENFORCE_RESOURCES_NO)
+               warn = 1;
+       clash = acpi_check_address_range(space_id, res->start, length, warn);
 
        if (clash) {
                if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
-                       printk(KERN_WARNING "ACPI: resource %s %pR"
-                              " conflicts with ACPI region %s "
-                              "[%s 0x%zx-0x%zx]\n",
-                              res->name, res, res_list_elem->name,
-                              (res_list_elem->resource_type ==
-                               ACPI_ADR_SPACE_SYSTEM_IO) ? "io" : "mem",
-                              (size_t) res_list_elem->start,
-                              (size_t) res_list_elem->end);
                        if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX)
                                printk(KERN_NOTICE "ACPI: This conflict may"
                                       " cause random problems and system"
@@ -1467,155 +1450,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
        kmem_cache_free(cache, object);
        return (AE_OK);
 }
-
-static inline int acpi_res_list_add(struct acpi_res_list *res)
-{
-       struct acpi_res_list *res_list_elem;
-
-       list_for_each_entry(res_list_elem, &resource_list_head,
-                           resource_list) {
-
-               if (res->resource_type == res_list_elem->resource_type &&
-                   res->start == res_list_elem->start &&
-                   res->end == res_list_elem->end) {
-
-                       /*
-                        * The Region(addr,len) already exist in the list,
-                        * just increase the count
-                        */
-
-                       res_list_elem->count++;
-                       return 0;
-               }
-       }
-
-       res->count = 1;
-       list_add(&res->resource_list, &resource_list_head);
-       return 1;
-}
-
-static inline void acpi_res_list_del(struct acpi_res_list *res)
-{
-       struct acpi_res_list *res_list_elem;
-
-       list_for_each_entry(res_list_elem, &resource_list_head,
-                           resource_list) {
-
-               if (res->resource_type == res_list_elem->resource_type &&
-                   res->start == res_list_elem->start &&
-                   res->end == res_list_elem->end) {
-
-                       /*
-                        * If the res count is decreased to 0,
-                        * remove and free it
-                        */
-
-                       if (--res_list_elem->count == 0) {
-                               list_del(&res_list_elem->resource_list);
-                               kfree(res_list_elem);
-                       }
-                       return;
-               }
-       }
-}
-
-acpi_status
-acpi_os_invalidate_address(
-    u8                   space_id,
-    acpi_physical_address   address,
-    acpi_size               length)
-{
-       struct acpi_res_list res;
-
-       switch (space_id) {
-       case ACPI_ADR_SPACE_SYSTEM_IO:
-       case ACPI_ADR_SPACE_SYSTEM_MEMORY:
-               /* Only interference checks against SystemIO and SystemMemory
-                  are needed */
-               res.start = address;
-               res.end = address + length - 1;
-               res.resource_type = space_id;
-               spin_lock(&acpi_res_lock);
-               acpi_res_list_del(&res);
-               spin_unlock(&acpi_res_lock);
-               break;
-       case ACPI_ADR_SPACE_PCI_CONFIG:
-       case ACPI_ADR_SPACE_EC:
-       case ACPI_ADR_SPACE_SMBUS:
-       case ACPI_ADR_SPACE_CMOS:
-       case ACPI_ADR_SPACE_PCI_BAR_TARGET:
-       case ACPI_ADR_SPACE_DATA_TABLE:
-       case ACPI_ADR_SPACE_FIXED_HARDWARE:
-               break;
-       }
-       return AE_OK;
-}
-
-/******************************************************************************
- *
- * FUNCTION:    acpi_os_validate_address
- *
- * PARAMETERS:  space_id             - ACPI space ID
- *              address             - Physical address
- *              length              - Address length
- *
- * RETURN:      AE_OK if address/length is valid for the space_id. Otherwise,
- *              should return AE_AML_ILLEGAL_ADDRESS.
- *
- * DESCRIPTION: Validate a system address via the host OS. Used to validate
- *              the addresses accessed by AML operation regions.
- *
- *****************************************************************************/
-
-acpi_status
-acpi_os_validate_address (
-    u8                   space_id,
-    acpi_physical_address   address,
-    acpi_size               length,
-    char *name)
-{
-       struct acpi_res_list *res;
-       int added;
-       if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
-               return AE_OK;
-
-       switch (space_id) {
-       case ACPI_ADR_SPACE_SYSTEM_IO:
-       case ACPI_ADR_SPACE_SYSTEM_MEMORY:
-               /* Only interference checks against SystemIO and SystemMemory
-                  are needed */
-               res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL);
-               if (!res)
-                       return AE_OK;
-               /* ACPI names are fixed to 4 bytes, still better use strlcpy */
-               strlcpy(res->name, name, 5);
-               res->start = address;
-               res->end = address + length - 1;
-               res->resource_type = space_id;
-               spin_lock(&acpi_res_lock);
-               added = acpi_res_list_add(res);
-               spin_unlock(&acpi_res_lock);
-               pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, "
-                        "name: %s\n", added ? "Added" : "Already exist",
-                        (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
-                        ? "SystemIO" : "System Memory",
-                        (unsigned long long)res->start,
-                        (unsigned long long)res->end,
-                        res->name);
-               if (!added)
-                       kfree(res);
-               break;
-       case ACPI_ADR_SPACE_PCI_CONFIG:
-       case ACPI_ADR_SPACE_EC:
-       case ACPI_ADR_SPACE_SMBUS:
-       case ACPI_ADR_SPACE_CMOS:
-       case ACPI_ADR_SPACE_PCI_BAR_TARGET:
-       case ACPI_ADR_SPACE_DATA_TABLE:
-       case ACPI_ADR_SPACE_FIXED_HARDWARE:
-               break;
-       }
-       return AE_OK;
-}
 #endif
 
 acpi_status __init acpi_os_initialize(void)
index 07f7fea8a4e26471ce6fabd4b90ade3c69ec9e43..e50e31a518afbf69ebc575ac3c579551e635b2f5 100644 (file)
@@ -34,7 +34,7 @@
 #include <acpi/acpi_drivers.h>
 #include <linux/dmi.h>
 
-static int debug;
+static bool debug;
 static int check_sta_before_sun;
 
 #define DRIVER_VERSION         "0.1"
index 3a0428e8435c0fcb0221540ded7f20d731d764ae..c850de4c9a146883a7d91f16c8cd8ddc3b694940 100644 (file)
@@ -173,8 +173,30 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
        apic_id = map_mat_entry(handle, type, acpi_id);
        if (apic_id == -1)
                apic_id = map_madt_entry(type, acpi_id);
-       if (apic_id == -1)
-               return apic_id;
+       if (apic_id == -1) {
+               /*
+                * On UP processor, there is no _MAT or MADT table.
+                * So above apic_id is always set to -1.
+                *
+                * BIOS may define multiple CPU handles even for UP processor.
+                * For example,
+                *
+                * Scope (_PR)
+                 * {
+                *     Processor (CPU0, 0x00, 0x00000410, 0x06) {}
+                *     Processor (CPU1, 0x01, 0x00000410, 0x06) {}
+                *     Processor (CPU2, 0x02, 0x00000410, 0x06) {}
+                *     Processor (CPU3, 0x03, 0x00000410, 0x06) {}
+                * }
+                *
+                * Ignores apic_id and always return 0 for CPU0's handle.
+                * Return -1 for other CPU's handle.
+                */
+               if (acpi_id == 0)
+                       return acpi_id;
+               else
+                       return apic_id;
+       }
 
 #ifdef CONFIG_SMP
        for_each_possible_cpu(i) {
index 20a68ca386de033dac092e74541f66f78cb21466..0034ede387103e4d32a649507bece321eae7d93f 100644 (file)
@@ -82,7 +82,7 @@ MODULE_LICENSE("GPL");
 static int acpi_processor_add(struct acpi_device *device);
 static int acpi_processor_remove(struct acpi_device *device, int type);
 static void acpi_processor_notify(struct acpi_device *device, u32 event);
-static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
+static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr);
 static int acpi_processor_handle_eject(struct acpi_processor *pr);
 
 
@@ -324,10 +324,8 @@ static int acpi_processor_get_info(struct acpi_device *device)
         *  they are physically not present.
         */
        if (pr->id == -1) {
-               if (ACPI_FAILURE
-                   (acpi_processor_hotadd_init(pr->handle, &pr->id))) {
+               if (ACPI_FAILURE(acpi_processor_hotadd_init(pr)))
                        return -ENODEV;
-               }
        }
        /*
         * On some boxes several processors use the same processor bus id.
@@ -539,6 +537,7 @@ err_thermal_unregister:
        thermal_cooling_device_unregister(pr->cdev);
 err_power_exit:
        acpi_processor_power_exit(pr, device);
+       sysfs_remove_link(&device->dev.kobj, "sysdev");
 err_free_cpumask:
        free_cpumask_var(pr->throttling.shared_cpu_map);
 
@@ -720,18 +719,19 @@ processor_walk_namespace_cb(acpi_handle handle,
        return (AE_OK);
 }
 
-static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu)
+static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
 {
+       acpi_handle handle = pr->handle;
 
        if (!is_processor_present(handle)) {
                return AE_ERROR;
        }
 
-       if (acpi_map_lsapic(handle, p_cpu))
+       if (acpi_map_lsapic(handle, &pr->id))
                return AE_ERROR;
 
-       if (arch_register_cpu(*p_cpu)) {
-               acpi_unmap_lsapic(*p_cpu);
+       if (arch_register_cpu(pr->id)) {
+               acpi_unmap_lsapic(pr->id);
                return AE_ERROR;
        }
 
@@ -748,7 +748,7 @@ static int acpi_processor_handle_eject(struct acpi_processor *pr)
        return (0);
 }
 #else
-static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu)
+static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
 {
        return AE_ERROR;
 }
@@ -827,8 +827,6 @@ static void __exit acpi_processor_exit(void)
 
        acpi_bus_unregister_driver(&acpi_processor_driver);
 
-       cpuidle_unregister_driver(&acpi_idle_driver);
-
        return;
 }
 
index 08a44b532f7c886dd45c703cb4cd159fb9d6e706..eaef02afc7cfce7004e3d74e25b733ee4d54cb97 100644 (file)
@@ -69,21 +69,21 @@ MODULE_AUTHOR("Bruno Ducrot");
 MODULE_DESCRIPTION("ACPI Video Driver");
 MODULE_LICENSE("GPL");
 
-static int brightness_switch_enabled = 1;
+static bool brightness_switch_enabled = 1;
 module_param(brightness_switch_enabled, bool, 0644);
 
 /*
  * By default, we don't allow duplicate ACPI video bus devices
  * under the same VGA controller
  */
-static int allow_duplicates;
+static bool allow_duplicates;
 module_param(allow_duplicates, bool, 0644);
 
 /*
  * Some BIOSes claim they use minimum backlight at boot,
  * and this may bring dimming screen after boot
  */
-static int use_bios_initial_backlight = 1;
+static bool use_bios_initial_backlight = 1;
 module_param(use_bios_initial_backlight, bool, 0644);
 
 static int register_count = 0;
index 69ac373c72abfc41e53304c0a8e2c7bb4fbf4e5c..fdf27b9fce43a882b706bf5148cd51a6a67f4f83 100644 (file)
@@ -1116,6 +1116,13 @@ static int piix_broken_suspend(void)
                                DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE U205"),
                        },
                },
+               {
+                       .ident = "Satellite Pro A120",
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "Satellite Pro A120"),
+                       },
+               },
                {
                        .ident = "Portege M500",
                        .matches = {
index 11c9aea4f4f7ea93a50fdc4b3547323d3728738d..c06e0ec11556d7696b620fa0b32e5af508863052 100644 (file)
@@ -4125,6 +4125,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
         * device and controller are SATA.
         */
        { "PIONEER DVD-RW  DVRTD08",    NULL,   ATA_HORKAGE_NOSETXFER },
+       { "PIONEER DVD-RW  DVRTD08A",   NULL,   ATA_HORKAGE_NOSETXFER },
+       { "PIONEER DVD-RW  DVR-215",    NULL,   ATA_HORKAGE_NOSETXFER },
        { "PIONEER DVD-RW  DVR-212D",   NULL,   ATA_HORKAGE_NOSETXFER },
        { "PIONEER DVD-RW  DVR-216D",   NULL,   ATA_HORKAGE_NOSETXFER },
 
index 9a7f0ea565df6c6066d7e64465c8385b81014a01..74aaee30e264ce1959c3807cb6a9e4c8bad27c95 100644 (file)
@@ -291,6 +291,7 @@ int ata_tport_add(struct device *parent,
                goto tport_err;
        }
 
+       device_enable_async_suspend(dev);
        pm_runtime_set_active(dev);
        pm_runtime_enable(dev);
 
index d6a4677fdf711801e4d09e74d6cc122db9a50904..1e65842e2ca719a0916bc371c676e68f27c096e2 100644 (file)
@@ -251,6 +251,8 @@ static const u32 udma_tenvmin = 20;
 static const u32 udma_tackmin = 20;
 static const u32 udma_tssmin = 50;
 
+#define BFIN_MAX_SG_SEGMENTS 4
+
 /**
  *
  *     Function:       num_clocks_min
@@ -829,79 +831,61 @@ static void bfin_set_devctl(struct ata_port *ap, u8 ctl)
 
 static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
 {
-       unsigned short config = WDSIZE_16;
+       struct ata_port *ap = qc->ap;
+       struct dma_desc_array *dma_desc_cpu = (struct dma_desc_array *)ap->bmdma_prd;
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       unsigned short config = DMAFLOW_ARRAY | NDSIZE_5 | RESTART | WDSIZE_16 | DMAEN;
        struct scatterlist *sg;
        unsigned int si;
+       unsigned int channel;
+       unsigned int dir;
+       unsigned int size = 0;
 
        dev_dbg(qc->ap->dev, "in atapi dma setup\n");
        /* Program the ATA_CTRL register with dir */
        if (qc->tf.flags & ATA_TFLAG_WRITE) {
-               /* fill the ATAPI DMA controller */
-               set_dma_config(CH_ATAPI_TX, config);
-               set_dma_x_modify(CH_ATAPI_TX, 2);
-               for_each_sg(qc->sg, sg, qc->n_elem, si) {
-                       set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg));
-                       set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1);
-               }
+               channel = CH_ATAPI_TX;
+               dir = DMA_TO_DEVICE;
        } else {
+               channel = CH_ATAPI_RX;
+               dir = DMA_FROM_DEVICE;
                config |= WNR;
-               /* fill the ATAPI DMA controller */
-               set_dma_config(CH_ATAPI_RX, config);
-               set_dma_x_modify(CH_ATAPI_RX, 2);
-               for_each_sg(qc->sg, sg, qc->n_elem, si) {
-                       set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg));
-                       set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1);
-               }
        }
-}
 
-/**
- *     bfin_bmdma_start - Start an IDE DMA transaction
- *     @qc: Info associated with this ATA transaction.
- *
- *     Note: Original code is ata_bmdma_start().
- */
+       dma_map_sg(ap->dev, qc->sg, qc->n_elem, dir);
 
-static void bfin_bmdma_start(struct ata_queued_cmd *qc)
-{
-       struct ata_port *ap = qc->ap;
-       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
-       struct scatterlist *sg;
-       unsigned int si;
+       /* fill the ATAPI DMA controller */
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
+               dma_desc_cpu[si].start_addr = sg_dma_address(sg);
+               dma_desc_cpu[si].cfg = config;
+               dma_desc_cpu[si].x_count = sg_dma_len(sg) >> 1;
+               dma_desc_cpu[si].x_modify = 2;
+               size += sg_dma_len(sg);
+       }
 
-       dev_dbg(qc->ap->dev, "in atapi dma start\n");
-       if (!(ap->udma_mask || ap->mwdma_mask))
-               return;
+       /* Set the last descriptor to stop mode */
+       dma_desc_cpu[qc->n_elem - 1].cfg &= ~(DMAFLOW | NDSIZE);
 
-       /* start ATAPI DMA controller*/
-       if (qc->tf.flags & ATA_TFLAG_WRITE) {
-               /*
-                * On blackfin arch, uncacheable memory is not
-                * allocated with flag GFP_DMA. DMA buffer from
-                * common kenel code should be flushed if WB
-                * data cache is enabled. Otherwise, this loop
-                * is an empty loop and optimized out.
-                */
-               for_each_sg(qc->sg, sg, qc->n_elem, si) {
-                       flush_dcache_range(sg_dma_address(sg),
-                               sg_dma_address(sg) + sg_dma_len(sg));
-               }
-               enable_dma(CH_ATAPI_TX);
-               dev_dbg(qc->ap->dev, "enable udma write\n");
+       flush_dcache_range((unsigned int)dma_desc_cpu,
+               (unsigned int)dma_desc_cpu +
+                       qc->n_elem * sizeof(struct dma_desc_array));
 
-               /* Send ATA DMA write command */
-               bfin_exec_command(ap, &qc->tf);
+       /* Enable ATA DMA operation*/
+       set_dma_curr_desc_addr(channel, (unsigned long *)ap->bmdma_prd_dma);
+       set_dma_x_count(channel, 0);
+       set_dma_x_modify(channel, 0);
+       set_dma_config(channel, config);
+
+       SSYNC();
+
+       /* Send ATA DMA command */
+       bfin_exec_command(ap, &qc->tf);
 
+       if (qc->tf.flags & ATA_TFLAG_WRITE) {
                /* set ATA DMA write direction */
                ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
                        | XFER_DIR));
        } else {
-               enable_dma(CH_ATAPI_RX);
-               dev_dbg(qc->ap->dev, "enable udma read\n");
-
-               /* Send ATA DMA read command */
-               bfin_exec_command(ap, &qc->tf);
-
                /* set ATA DMA read direction */
                ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
                        & ~XFER_DIR));
@@ -913,12 +897,28 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
        /* Set ATAPI state machine contorl in terminate sequence */
        ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | END_ON_TERM);
 
-       /* Set transfer length to buffer len */
-       for_each_sg(qc->sg, sg, qc->n_elem, si) {
-               ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
-       }
+       /* Set transfer length to the total size of sg buffers */
+       ATAPI_SET_XFER_LEN(base, size >> 1);
+}
 
-       /* Enable ATA DMA operation*/
+/**
+ *     bfin_bmdma_start - Start an IDE DMA transaction
+ *     @qc: Info associated with this ATA transaction.
+ *
+ *     Note: Original code is ata_bmdma_start().
+ */
+
+static void bfin_bmdma_start(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+       dev_dbg(qc->ap->dev, "in atapi dma start\n");
+
+       if (!(ap->udma_mask || ap->mwdma_mask))
+               return;
+
+       /* start ATAPI transfer*/
        if (ap->udma_mask)
                ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)
                        | ULTRA_START);
@@ -935,34 +935,23 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
 static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       struct scatterlist *sg;
-       unsigned int si;
+       unsigned int dir;
 
        dev_dbg(qc->ap->dev, "in atapi dma stop\n");
+
        if (!(ap->udma_mask || ap->mwdma_mask))
                return;
 
        /* stop ATAPI DMA controller*/
-       if (qc->tf.flags & ATA_TFLAG_WRITE)
+       if (qc->tf.flags & ATA_TFLAG_WRITE) {
+               dir = DMA_TO_DEVICE;
                disable_dma(CH_ATAPI_TX);
-       else {
+       } else {
+               dir = DMA_FROM_DEVICE;
                disable_dma(CH_ATAPI_RX);
-               if (ap->hsm_task_state & HSM_ST_LAST) {
-                       /*
-                        * On blackfin arch, uncacheable memory is not
-                        * allocated with flag GFP_DMA. DMA buffer from
-                        * common kenel code should be invalidated if
-                        * data cache is enabled. Otherwise, this loop
-                        * is an empty loop and optimized out.
-                        */
-                       for_each_sg(qc->sg, sg, qc->n_elem, si) {
-                               invalidate_dcache_range(
-                                       sg_dma_address(sg),
-                                       sg_dma_address(sg)
-                                       + sg_dma_len(sg));
-                       }
-               }
        }
+
+       dma_unmap_sg(ap->dev, qc->sg, qc->n_elem, dir);
 }
 
 /**
@@ -1260,6 +1249,11 @@ static void bfin_port_stop(struct ata_port *ap)
 {
        dev_dbg(ap->dev, "in atapi port stop\n");
        if (ap->udma_mask != 0 || ap->mwdma_mask != 0) {
+               dma_free_coherent(ap->dev,
+                       BFIN_MAX_SG_SEGMENTS * sizeof(struct dma_desc_array),
+                       ap->bmdma_prd,
+                       ap->bmdma_prd_dma);
+
                free_dma(CH_ATAPI_RX);
                free_dma(CH_ATAPI_TX);
        }
@@ -1271,14 +1265,29 @@ static int bfin_port_start(struct ata_port *ap)
        if (!(ap->udma_mask || ap->mwdma_mask))
                return 0;
 
+       ap->bmdma_prd = dma_alloc_coherent(ap->dev,
+                               BFIN_MAX_SG_SEGMENTS * sizeof(struct dma_desc_array),
+                               &ap->bmdma_prd_dma,
+                               GFP_KERNEL);
+
+       if (ap->bmdma_prd == NULL) {
+               dev_info(ap->dev, "Unable to allocate DMA descriptor array.\n");
+               goto out;
+       }
+
        if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) {
                if (request_dma(CH_ATAPI_TX,
                        "BFIN ATAPI TX DMA") >= 0)
                        return 0;
 
                free_dma(CH_ATAPI_RX);
+               dma_free_coherent(ap->dev,
+                       BFIN_MAX_SG_SEGMENTS * sizeof(struct dma_desc_array),
+                       ap->bmdma_prd,
+                       ap->bmdma_prd_dma);
        }
 
+out:
        ap->udma_mask = 0;
        ap->mwdma_mask = 0;
        dev_err(ap->dev, "Unable to request ATAPI DMA!"
@@ -1400,7 +1409,7 @@ static irqreturn_t bfin_ata_interrupt(int irq, void *dev_instance)
 
 static struct scsi_host_template bfin_sht = {
        ATA_BASE_SHT(DRV_NAME),
-       .sg_tablesize           = SG_NONE,
+       .sg_tablesize           = BFIN_MAX_SG_SEGMENTS,
        .dma_boundary           = ATA_DMA_BOUNDARY,
 };
 
index 5a2c95ba050a28caacbb4e3a799a0cdd176fcf47..0120b0d1e9a5aa838cee9a7347992377012d6c8c 100644 (file)
@@ -140,6 +140,7 @@ enum {
         */
        HCONTROL_ONLINE_PHY_RST = (1 << 31),
        HCONTROL_FORCE_OFFLINE = (1 << 30),
+       HCONTROL_LEGACY = (1 << 28),
        HCONTROL_PARITY_PROT_MOD = (1 << 14),
        HCONTROL_DPATH_PARITY = (1 << 12),
        HCONTROL_SNOOP_ENABLE = (1 << 10),
@@ -1223,6 +1224,10 @@ static int sata_fsl_init_controller(struct ata_host *host)
         * part of the port_start() callback
         */
 
+       /* sata controller to operate in enterprise mode */
+       temp = ioread32(hcr_base + HCONTROL);
+       iowrite32(temp & ~HCONTROL_LEGACY, hcr_base + HCONTROL);
+
        /* ack. any pending IRQs for this controller/port */
        temp = ioread32(hcr_base + HSTATUS);
        if (temp & 0x3F)
@@ -1421,6 +1426,12 @@ static int sata_fsl_resume(struct platform_device *op)
        /* Recovery the CHBA register in host controller cmd register set */
        iowrite32(pp->cmdslot_paddr & 0xffffffff, hcr_base + CHBA);
 
+       iowrite32((ioread32(hcr_base + HCONTROL)
+                               | HCONTROL_ONLINE_PHY_RST
+                               | HCONTROL_SNOOP_ENABLE
+                               | HCONTROL_PMP_ATTACHED),
+                       hcr_base + HCONTROL);
+
        ata_host_resume(host);
        return 0;
 }
index e0bc9646a38e65a11897e45e85a907adbbc03dd4..55d6179dde589fa0c9a8e66f9c4935137b756acc 100644 (file)
@@ -599,9 +599,9 @@ MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-static int adma_enabled;
-static int swncq_enabled = 1;
-static int msi_enabled;
+static bool adma_enabled;
+static bool swncq_enabled = 1;
+static bool msi_enabled;
 
 static void nv_adma_register_mode(struct ata_port *ap)
 {
index 1e9140626a8371eae9e846bb2fd9fb3a327136e6..e7e610aa9a7a4c6a9321671eec2002badadb17c0 100644 (file)
@@ -417,7 +417,7 @@ static struct ata_port_operations sil24_ops = {
 #endif
 };
 
-static int sata_sil24_msi;    /* Disable MSI */
+static bool sata_sil24_msi;    /* Disable MSI */
 module_param_named(msi, sata_sil24_msi, bool, S_IRUGO);
 MODULE_PARM_DESC(msi, "Enable MSI (Default: false)");
 
index 9a51df4f5b746518fd7e580882f1c261eb202500..b182c2f7d777c077806d79a261a600454a701438 100644 (file)
@@ -112,12 +112,12 @@ static u8 read_prom_byte(struct he_dev *he_dev, int addr);
 /* globals */
 
 static struct he_dev *he_devs;
-static int disable64;
+static bool disable64;
 static short nvpibits = -1;
 static short nvcibits = -1;
 static short rx_skb_reserve = 16;
-static int irq_coalesce = 1;
-static int sdh = 0;
+static bool irq_coalesce = 1;
+static bool sdh = 0;
 
 /* Read from EEPROM = 0000 0011b */
 static unsigned int readtab[] = {
index fcbec8ac134deadb942a09d7ba5d76c681b3a596..7be9f79018e9e722439a0055c8a23dcf58f79e97 100644 (file)
@@ -179,7 +179,7 @@ config GENERIC_CPU_DEVICES
 source "drivers/base/regmap/Kconfig"
 
 config DMA_SHARED_BUFFER
-       bool "Buffer framework to be shared between drivers"
+       bool
        default n
        select ANON_INODES
        depends on EXPERIMENTAL
index f17e3ea041c0565bc3b9e2af2798c196eeb4c4b2..ed5de58c340f25e7c20b6db4189b279dd3110a2f 100644 (file)
@@ -295,11 +295,22 @@ static int memory_block_change_state(struct memory_block *mem,
 
        ret = memory_block_action(mem->start_section_nr, to_state);
 
-       if (ret)
+       if (ret) {
                mem->state = from_state_req;
-       else
-               mem->state = to_state;
+               goto out;
+       }
 
+       mem->state = to_state;
+       switch (mem->state) {
+       case MEM_OFFLINE:
+               kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE);
+               break;
+       case MEM_ONLINE:
+               kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE);
+               break;
+       default:
+               break;
+       }
 out:
        mutex_unlock(&mem->state_mutex);
        return ret;
index 92e6a9048065eb567f3d9c857e689c2b4667dd15..978bbf7ac6af03bb26eed17329d3a24f6bf5337e 100644 (file)
@@ -1429,6 +1429,8 @@ static int pm_genpd_default_restore_state(struct device *dev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+
 /**
  * pm_genpd_default_suspend - Default "device suspend" for PM domians.
  * @dev: Device to handle.
@@ -1517,6 +1519,19 @@ static int pm_genpd_default_thaw(struct device *dev)
        return cb ? cb(dev) : pm_generic_thaw(dev);
 }
 
+#else /* !CONFIG_PM_SLEEP */
+
+#define pm_genpd_default_suspend       NULL
+#define pm_genpd_default_suspend_late  NULL
+#define pm_genpd_default_resume_early  NULL
+#define pm_genpd_default_resume                NULL
+#define pm_genpd_default_freeze                NULL
+#define pm_genpd_default_freeze_late   NULL
+#define pm_genpd_default_thaw_early    NULL
+#define pm_genpd_default_thaw          NULL
+
+#endif /* !CONFIG_PM_SLEEP */
+
 /**
  * pm_genpd_init - Initialize a generic I/O PM domain object.
  * @genpd: PM domain object to initialize.
index 51527ee92d101018680cd5b633265105a2952df1..66a265bf5867d1b516a03f34e8e50946db4c1e3e 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/pm_qos.h>
 #include <linux/hrtimer.h>
 
+#ifdef CONFIG_PM_RUNTIME
+
 /**
  * default_stop_ok - Default PM domain governor routine for stopping devices.
  * @dev: Device to check.
@@ -137,16 +139,28 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
        return true;
 }
 
-struct dev_power_governor simple_qos_governor = {
-       .stop_ok = default_stop_ok,
-       .power_down_ok = default_power_down_ok,
-};
-
 static bool always_on_power_down_ok(struct dev_pm_domain *domain)
 {
        return false;
 }
 
+#else /* !CONFIG_PM_RUNTIME */
+
+bool default_stop_ok(struct device *dev)
+{
+       return false;
+}
+
+#define default_power_down_ok  NULL
+#define always_on_power_down_ok        NULL
+
+#endif /* !CONFIG_PM_RUNTIME */
+
+struct dev_power_governor simple_qos_governor = {
+       .stop_ok = default_stop_ok,
+       .power_down_ok = default_power_down_ok,
+};
+
 /**
  * pm_genpd_gov_always_on - A governor implementing an always-on policy
  */
index fda56bde36b836cc7fa4a8bee2c1bc92b0e5a43d..0def898a1d159c12d2543df6ffd6264932a7affc 100644 (file)
@@ -19,6 +19,7 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
                                   struct bcma_device *core_cc,
                                   struct bcma_device *core_mips);
 #ifdef CONFIG_PM
+int bcma_bus_suspend(struct bcma_bus *bus);
 int bcma_bus_resume(struct bcma_bus *bus);
 #endif
 
index 443b83a2fd7aa012c1c6835137e2642a79499b41..f59244e3397137ca9b6a6d311612dd53db721646 100644 (file)
@@ -235,38 +235,32 @@ static void bcma_host_pci_remove(struct pci_dev *dev)
 }
 
 #ifdef CONFIG_PM
-static int bcma_host_pci_suspend(struct pci_dev *dev, pm_message_t state)
+static int bcma_host_pci_suspend(struct device *dev)
 {
-       /* Host specific */
-       pci_save_state(dev);
-       pci_disable_device(dev);
-       pci_set_power_state(dev, pci_choose_state(dev, state));
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct bcma_bus *bus = pci_get_drvdata(pdev);
 
-       return 0;
+       bus->mapped_core = NULL;
+
+       return bcma_bus_suspend(bus);
 }
 
-static int bcma_host_pci_resume(struct pci_dev *dev)
+static int bcma_host_pci_resume(struct device *dev)
 {
-       struct bcma_bus *bus = pci_get_drvdata(dev);
-       int err;
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct bcma_bus *bus = pci_get_drvdata(pdev);
 
-       /* Host specific */
-       pci_set_power_state(dev, 0);
-       err = pci_enable_device(dev);
-       if (err)
-               return err;
-       pci_restore_state(dev);
+       return bcma_bus_resume(bus);
+}
 
-       /* Bus specific */
-       err = bcma_bus_resume(bus);
-       if (err)
-               return err;
+static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bcma_host_pci_suspend,
+                        bcma_host_pci_resume);
+#define BCMA_PM_OPS    (&bcma_pm_ops)
 
-       return 0;
-}
 #else /* CONFIG_PM */
-# define bcma_host_pci_suspend NULL
-# define bcma_host_pci_resume  NULL
+
+#define BCMA_PM_OPS     NULL
+
 #endif /* CONFIG_PM */
 
 static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
@@ -284,8 +278,7 @@ static struct pci_driver bcma_pci_bridge_driver = {
        .id_table = bcma_pci_bridge_tbl,
        .probe = bcma_host_pci_probe,
        .remove = bcma_host_pci_remove,
-       .suspend = bcma_host_pci_suspend,
-       .resume = bcma_host_pci_resume,
+       .driver.pm = BCMA_PM_OPS,
 };
 
 int __init bcma_host_pci_init(void)
index 10f92b371e582bf6d371f425b17dd1dfe5629afd..febbc0a1222ae1444acea8312bab18b7163fbcdb 100644 (file)
@@ -241,6 +241,21 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
 }
 
 #ifdef CONFIG_PM
+int bcma_bus_suspend(struct bcma_bus *bus)
+{
+       struct bcma_device *core;
+
+       list_for_each_entry(core, &bus->cores, list) {
+               struct device_driver *drv = core->dev.driver;
+               if (drv) {
+                       struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
+                       if (adrv->suspend)
+                               adrv->suspend(core);
+               }
+       }
+       return 0;
+}
+
 int bcma_bus_resume(struct bcma_bus *bus)
 {
        struct bcma_device *core;
@@ -252,6 +267,15 @@ int bcma_bus_resume(struct bcma_bus *bus)
                bcma_core_chipcommon_init(&bus->drv_cc);
        }
 
+       list_for_each_entry(core, &bus->cores, list) {
+               struct device_driver *drv = core->dev.driver;
+               if (drv) {
+                       struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
+                       if (adrv->resume)
+                               adrv->resume(core);
+               }
+       }
+
        return 0;
 }
 #endif
index 6f07ec1c2f58d2dabd766463165e32728910faf6..4e4c8a4a5fd3fb4412a19fdbd3f62647b285fd6a 100644 (file)
@@ -116,6 +116,8 @@ config PARIDE
 
 source "drivers/block/paride/Kconfig"
 
+source "drivers/block/mtip32xx/Kconfig"
+
 config BLK_CPQ_DA
        tristate "Compaq SMART2 support"
        depends on PCI && VIRT_TO_BUS
@@ -315,6 +317,17 @@ config BLK_DEV_NBD
 
          If unsure, say N.
 
+config BLK_DEV_NVME
+       tristate "NVM Express block device"
+       depends on PCI
+       ---help---
+         The NVM Express driver is for solid state drives directly
+         connected to the PCI or PCI Express bus.  If you know you
+         don't have one of these, it is safe to answer N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called nvme.
+
 config BLK_DEV_OSD
        tristate "OSD object-as-blkdev support"
        depends on SCSI_OSD_ULD
index 76646e9a1c91528617c22e2c3f429201531acdf4..5b795059f8fb76107b5f2950dd88c5c9696ad4ee 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_XILINX_SYSACE)   += xsysace.o
 obj-$(CONFIG_CDROM_PKTCDVD)    += pktcdvd.o
 obj-$(CONFIG_MG_DISK)          += mg_disk.o
 obj-$(CONFIG_SUNVDC)           += sunvdc.o
+obj-$(CONFIG_BLK_DEV_NVME)     += nvme.o
 obj-$(CONFIG_BLK_DEV_OSD)      += osdblk.o
 
 obj-$(CONFIG_BLK_DEV_UMEM)     += umem.o
@@ -39,5 +40,6 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND)     += xen-blkfront.o
 obj-$(CONFIG_XEN_BLKDEV_BACKEND)       += xen-blkback/
 obj-$(CONFIG_BLK_DEV_DRBD)     += drbd/
 obj-$(CONFIG_BLK_DEV_RBD)     += rbd.o
+obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx/
 
 swim_mod-y     := swim.o swim_asm.o
index 587cce57adae23fcddb22270de69ae9ce2bff76b..b0f553b26d0f8d00f86f768f93aad27ebcb0529e 100644 (file)
@@ -1735,7 +1735,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
        case CCISS_BIG_PASSTHRU:
                return cciss_bigpassthru(h, argp);
 
-       /* scsi_cmd_ioctl handles these, below, though some are not */
+       /* scsi_cmd_blk_ioctl handles these, below, though some are not */
        /* very meaningful for cciss.  SG_IO is the main one people want. */
 
        case SG_GET_VERSION_NUM:
@@ -1746,9 +1746,9 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
        case SG_EMULATED_HOST:
        case SG_IO:
        case SCSI_IOCTL_SEND_COMMAND:
-               return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp);
+               return scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
 
-       /* scsi_cmd_ioctl would normally handle these, below, but */
+       /* scsi_cmd_blk_ioctl would normally handle these, below, but */
        /* they aren't a good fit for cciss, as CD-ROMs are */
        /* not supported, and we don't have any bus/target/lun */
        /* which we present to the kernel. */
index 9cf20355ceec72750e4d348520f4f977ead482af..8d680562ba73a1ca17120779c06aa834eea18f39 100644 (file)
@@ -59,8 +59,8 @@
 
 /* module parameter, defined in drbd_main.c */
 extern unsigned int minor_count;
-extern int disable_sendpage;
-extern int allow_oos;
+extern bool disable_sendpage;
+extern bool allow_oos;
 extern unsigned int cn_idx;
 
 #ifdef CONFIG_DRBD_FAULT_INJECTION
index 0358e55356c85f13ce96670f94b4cef626ce70ae..211fc44f84be6ddda0112dbf2ad8a55ca1810c47 100644 (file)
@@ -117,8 +117,8 @@ module_param(fault_devs, int, 0644);
 
 /* module parameter, defined */
 unsigned int minor_count = DRBD_MINOR_COUNT_DEF;
-int disable_sendpage;
-int allow_oos;
+bool disable_sendpage;
+bool allow_oos;
 unsigned int cn_idx = CN_IDX_DRBD;
 int proc_details;       /* Detail level in proc drbd*/
 
diff --git a/drivers/block/mtip32xx/Kconfig b/drivers/block/mtip32xx/Kconfig
new file mode 100644 (file)
index 0000000..b5dd14e
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# mtip32xx device driver configuration
+#
+
+config BLK_DEV_PCIESSD_MTIP32XX
+       tristate "Block Device Driver for Micron PCIe SSDs"
+       depends on HOTPLUG_PCI_PCIE
+       help
+          This enables the block driver for Micron PCIe SSDs.
diff --git a/drivers/block/mtip32xx/Makefile b/drivers/block/mtip32xx/Makefile
new file mode 100644 (file)
index 0000000..4fbef8c
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for  Block device driver for Micron PCIe SSD
+#
+
+obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx.o
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
new file mode 100644 (file)
index 0000000..b74eab7
--- /dev/null
@@ -0,0 +1,3651 @@
+/*
+ * Driver for the Micron P320 SSD
+ *   Copyright (C) 2011 Micron Technology, Inc.
+ *
+ * Portions of this code were derived from works subjected to the
+ * following copyright:
+ *    Copyright (C) 2009 Integrated Device Technology, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/ata.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/uaccess.h>
+#include <linux/random.h>
+#include <linux/smp.h>
+#include <linux/compat.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/dma-mapping.h>
+#include <linux/idr.h>
+#include <linux/kthread.h>
+#include <../drivers/ata/ahci.h>
+#include "mtip32xx.h"
+
+#define HW_CMD_SLOT_SZ         (MTIP_MAX_COMMAND_SLOTS * 32)
+#define HW_CMD_TBL_SZ          (AHCI_CMD_TBL_HDR_SZ + (MTIP_MAX_SG * 16))
+#define HW_CMD_TBL_AR_SZ       (HW_CMD_TBL_SZ * MTIP_MAX_COMMAND_SLOTS)
+#define HW_PORT_PRIV_DMA_SZ \
+               (HW_CMD_SLOT_SZ + HW_CMD_TBL_AR_SZ + AHCI_RX_FIS_SZ)
+
+#define HOST_HSORG             0xFC
+#define HSORG_DISABLE_SLOTGRP_INTR (1<<24)
+#define HSORG_DISABLE_SLOTGRP_PXIS (1<<16)
+#define HSORG_HWREV            0xFF00
+#define HSORG_STYLE            0x8
+#define HSORG_SLOTGROUPS       0x7
+
+#define PORT_COMMAND_ISSUE     0x38
+#define PORT_SDBV              0x7C
+
+#define PORT_OFFSET            0x100
+#define PORT_MEM_SIZE          0x80
+
+#define PORT_IRQ_ERR \
+       (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | PORT_IRQ_CONNECT | \
+        PORT_IRQ_PHYRDY | PORT_IRQ_UNK_FIS | PORT_IRQ_BAD_PMP | \
+        PORT_IRQ_TF_ERR | PORT_IRQ_HBUS_DATA_ERR | PORT_IRQ_IF_NONFATAL | \
+        PORT_IRQ_OVERFLOW)
+#define PORT_IRQ_LEGACY \
+       (PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS)
+#define PORT_IRQ_HANDLED \
+       (PORT_IRQ_SDB_FIS | PORT_IRQ_LEGACY | \
+        PORT_IRQ_TF_ERR | PORT_IRQ_IF_ERR | \
+        PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)
+#define DEF_PORT_IRQ \
+       (PORT_IRQ_ERR | PORT_IRQ_LEGACY | PORT_IRQ_SDB_FIS)
+
+/* product numbers */
+#define MTIP_PRODUCT_UNKNOWN   0x00
+#define MTIP_PRODUCT_ASICFPGA  0x11
+
+/* Device instance number, incremented each time a device is probed. */
+static int instance;
+
+/*
+ * Global variable used to hold the major block device number
+ * allocated in mtip_init().
+ */
+static int mtip_major;
+
+static DEFINE_SPINLOCK(rssd_index_lock);
+static DEFINE_IDA(rssd_index_ida);
+
+static int mtip_block_initialize(struct driver_data *dd);
+
+#ifdef CONFIG_COMPAT
+struct mtip_compat_ide_task_request_s {
+       __u8            io_ports[8];
+       __u8            hob_ports[8];
+       ide_reg_valid_t out_flags;
+       ide_reg_valid_t in_flags;
+       int             data_phase;
+       int             req_cmd;
+       compat_ulong_t  out_size;
+       compat_ulong_t  in_size;
+};
+#endif
+
+/*
+ * This function check_for_surprise_removal is called
+ * while card is removed from the system and it will
+ * read the vendor id from the configration space
+ *
+ * @pdev Pointer to the pci_dev structure.
+ *
+ * return value
+ *      true if device removed, else false
+ */
+static bool mtip_check_surprise_removal(struct pci_dev *pdev)
+{
+       u16 vendor_id = 0;
+
+       /* Read the vendorID from the configuration space */
+       pci_read_config_word(pdev, 0x00, &vendor_id);
+       if (vendor_id == 0xFFFF)
+               return true; /* device removed */
+
+       return false; /* device present */
+}
+
+/*
+ * This function is called for clean the pending command in the
+ * command slot during the surprise removal of device and return
+ * error to the upper layer.
+ *
+ * @dd Pointer to the DRIVER_DATA structure.
+ *
+ * return value
+ *     None
+ */
+static void mtip_command_cleanup(struct driver_data *dd)
+{
+       int group = 0, commandslot = 0, commandindex = 0;
+       struct mtip_cmd *command;
+       struct mtip_port *port = dd->port;
+
+       for (group = 0; group < 4; group++) {
+               for (commandslot = 0; commandslot < 32; commandslot++) {
+                       if (!(port->allocated[group] & (1 << commandslot)))
+                               continue;
+
+                       commandindex = group << 5 | commandslot;
+                       command = &port->commands[commandindex];
+
+                       if (atomic_read(&command->active)
+                           && (command->async_callback)) {
+                               command->async_callback(command->async_data,
+                                       -ENODEV);
+                               command->async_callback = NULL;
+                               command->async_data = NULL;
+                       }
+
+                       dma_unmap_sg(&port->dd->pdev->dev,
+                               command->sg,
+                               command->scatter_ents,
+                               command->direction);
+               }
+       }
+
+       up(&port->cmd_slot);
+
+       atomic_set(&dd->drv_cleanup_done, true);
+}
+
+/*
+ * Obtain an empty command slot.
+ *
+ * This function needs to be reentrant since it could be called
+ * at the same time on multiple CPUs. The allocation of the
+ * command slot must be atomic.
+ *
+ * @port Pointer to the port data structure.
+ *
+ * return value
+ *     >= 0    Index of command slot obtained.
+ *     -1      No command slots available.
+ */
+static int get_slot(struct mtip_port *port)
+{
+       int slot, i;
+       unsigned int num_command_slots = port->dd->slot_groups * 32;
+
+       /*
+        * Try 10 times, because there is a small race here.
+        *  that's ok, because it's still cheaper than a lock.
+        *
+        * Race: Since this section is not protected by lock, same bit
+        * could be chosen by different process contexts running in
+        * different processor. So instead of costly lock, we are going
+        * with loop.
+        */
+       for (i = 0; i < 10; i++) {
+               slot = find_next_zero_bit(port->allocated,
+                                        num_command_slots, 1);
+               if ((slot < num_command_slots) &&
+                   (!test_and_set_bit(slot, port->allocated)))
+                       return slot;
+       }
+       dev_warn(&port->dd->pdev->dev, "Failed to get a tag.\n");
+
+       if (mtip_check_surprise_removal(port->dd->pdev)) {
+               /* Device not present, clean outstanding commands */
+               mtip_command_cleanup(port->dd);
+       }
+       return -1;
+}
+
+/*
+ * Release a command slot.
+ *
+ * @port Pointer to the port data structure.
+ * @tag  Tag of command to release
+ *
+ * return value
+ *     None
+ */
+static inline void release_slot(struct mtip_port *port, int tag)
+{
+       smp_mb__before_clear_bit();
+       clear_bit(tag, port->allocated);
+       smp_mb__after_clear_bit();
+}
+
+/*
+ * Reset the HBA (without sleeping)
+ *
+ * Just like hba_reset, except does not call sleep, so can be
+ * run from interrupt/tasklet context.
+ *
+ * @dd Pointer to the driver data structure.
+ *
+ * return value
+ *     0       The reset was successful.
+ *     -1      The HBA Reset bit did not clear.
+ */
+static int hba_reset_nosleep(struct driver_data *dd)
+{
+       unsigned long timeout;
+
+       /* Chip quirk: quiesce any chip function */
+       mdelay(10);
+
+       /* Set the reset bit */
+       writel(HOST_RESET, dd->mmio + HOST_CTL);
+
+       /* Flush */
+       readl(dd->mmio + HOST_CTL);
+
+       /*
+        * Wait 10ms then spin for up to 1 second
+        * waiting for reset acknowledgement
+        */
+       timeout = jiffies + msecs_to_jiffies(1000);
+       mdelay(10);
+       while ((readl(dd->mmio + HOST_CTL) & HOST_RESET)
+                && time_before(jiffies, timeout))
+               mdelay(1);
+
+       if (readl(dd->mmio + HOST_CTL) & HOST_RESET)
+               return -1;
+
+       return 0;
+}
+
+/*
+ * Issue a command to the hardware.
+ *
+ * Set the appropriate bit in the s_active and Command Issue hardware
+ * registers, causing hardware command processing to begin.
+ *
+ * @port Pointer to the port structure.
+ * @tag  The tag of the command to be issued.
+ *
+ * return value
+ *      None
+ */
+static inline void mtip_issue_ncq_command(struct mtip_port *port, int tag)
+{
+       unsigned long flags = 0;
+
+       atomic_set(&port->commands[tag].active, 1);
+
+       spin_lock_irqsave(&port->cmd_issue_lock, flags);
+
+       writel((1 << MTIP_TAG_BIT(tag)),
+                       port->s_active[MTIP_TAG_INDEX(tag)]);
+       writel((1 << MTIP_TAG_BIT(tag)),
+                       port->cmd_issue[MTIP_TAG_INDEX(tag)]);
+
+       spin_unlock_irqrestore(&port->cmd_issue_lock, flags);
+}
+
+/*
+ * Enable/disable the reception of FIS
+ *
+ * @port   Pointer to the port data structure
+ * @enable 1 to enable, 0 to disable
+ *
+ * return value
+ *     Previous state: 1 enabled, 0 disabled
+ */
+static int mtip_enable_fis(struct mtip_port *port, int enable)
+{
+       u32 tmp;
+
+       /* enable FIS reception */
+       tmp = readl(port->mmio + PORT_CMD);
+       if (enable)
+               writel(tmp | PORT_CMD_FIS_RX, port->mmio + PORT_CMD);
+       else
+               writel(tmp & ~PORT_CMD_FIS_RX, port->mmio + PORT_CMD);
+
+       /* Flush */
+       readl(port->mmio + PORT_CMD);
+
+       return (((tmp & PORT_CMD_FIS_RX) == PORT_CMD_FIS_RX));
+}
+
+/*
+ * Enable/disable the DMA engine
+ *
+ * @port   Pointer to the port data structure
+ * @enable 1 to enable, 0 to disable
+ *
+ * return value
+ *     Previous state: 1 enabled, 0 disabled.
+ */
+static int mtip_enable_engine(struct mtip_port *port, int enable)
+{
+       u32 tmp;
+
+       /* enable FIS reception */
+       tmp = readl(port->mmio + PORT_CMD);
+       if (enable)
+               writel(tmp | PORT_CMD_START, port->mmio + PORT_CMD);
+       else
+               writel(tmp & ~PORT_CMD_START, port->mmio + PORT_CMD);
+
+       readl(port->mmio + PORT_CMD);
+       return (((tmp & PORT_CMD_START) == PORT_CMD_START));
+}
+
+/*
+ * Enables the port DMA engine and FIS reception.
+ *
+ * return value
+ *     None
+ */
+static inline void mtip_start_port(struct mtip_port *port)
+{
+       /* Enable FIS reception */
+       mtip_enable_fis(port, 1);
+
+       /* Enable the DMA engine */
+       mtip_enable_engine(port, 1);
+}
+
+/*
+ * Deinitialize a port by disabling port interrupts, the DMA engine,
+ * and FIS reception.
+ *
+ * @port Pointer to the port structure
+ *
+ * return value
+ *     None
+ */
+static inline void mtip_deinit_port(struct mtip_port *port)
+{
+       /* Disable interrupts on this port */
+       writel(0, port->mmio + PORT_IRQ_MASK);
+
+       /* Disable the DMA engine */
+       mtip_enable_engine(port, 0);
+
+       /* Disable FIS reception */
+       mtip_enable_fis(port, 0);
+}
+
+/*
+ * Initialize a port.
+ *
+ * This function deinitializes the port by calling mtip_deinit_port() and
+ * then initializes it by setting the command header and RX FIS addresses,
+ * clearing the SError register and any pending port interrupts before
+ * re-enabling the default set of port interrupts.
+ *
+ * @port Pointer to the port structure.
+ *
+ * return value
+ *     None
+ */
+static void mtip_init_port(struct mtip_port *port)
+{
+       int i;
+       mtip_deinit_port(port);
+
+       /* Program the command list base and FIS base addresses */
+       if (readl(port->dd->mmio + HOST_CAP) & HOST_CAP_64) {
+               writel((port->command_list_dma >> 16) >> 16,
+                        port->mmio + PORT_LST_ADDR_HI);
+               writel((port->rxfis_dma >> 16) >> 16,
+                        port->mmio + PORT_FIS_ADDR_HI);
+       }
+
+       writel(port->command_list_dma & 0xFFFFFFFF,
+                       port->mmio + PORT_LST_ADDR);
+       writel(port->rxfis_dma & 0xFFFFFFFF, port->mmio + PORT_FIS_ADDR);
+
+       /* Clear SError */
+       writel(readl(port->mmio + PORT_SCR_ERR), port->mmio + PORT_SCR_ERR);
+
+       /* reset the completed registers.*/
+       for (i = 0; i < port->dd->slot_groups; i++)
+               writel(0xFFFFFFFF, port->completed[i]);
+
+       /* Clear any pending interrupts for this port */
+       writel(readl(port->mmio + PORT_IRQ_STAT), port->mmio + PORT_IRQ_STAT);
+
+       /* Enable port interrupts */
+       writel(DEF_PORT_IRQ, port->mmio + PORT_IRQ_MASK);
+}
+
+/*
+ * Restart a port
+ *
+ * @port Pointer to the port data structure.
+ *
+ * return value
+ *     None
+ */
+static void mtip_restart_port(struct mtip_port *port)
+{
+       unsigned long timeout;
+
+       /* Disable the DMA engine */
+       mtip_enable_engine(port, 0);
+
+       /* Chip quirk: wait up to 500ms for PxCMD.CR == 0 */
+       timeout = jiffies + msecs_to_jiffies(500);
+       while ((readl(port->mmio + PORT_CMD) & PORT_CMD_LIST_ON)
+                && time_before(jiffies, timeout))
+               ;
+
+       /*
+        * Chip quirk: escalate to hba reset if
+        * PxCMD.CR not clear after 500 ms
+        */
+       if (readl(port->mmio + PORT_CMD) & PORT_CMD_LIST_ON) {
+               dev_warn(&port->dd->pdev->dev,
+                       "PxCMD.CR not clear, escalating reset\n");
+
+               if (hba_reset_nosleep(port->dd))
+                       dev_err(&port->dd->pdev->dev,
+                               "HBA reset escalation failed.\n");
+
+               /* 30 ms delay before com reset to quiesce chip */
+               mdelay(30);
+       }
+
+       dev_warn(&port->dd->pdev->dev, "Issuing COM reset\n");
+
+       /* Set PxSCTL.DET */
+       writel(readl(port->mmio + PORT_SCR_CTL) |
+                        1, port->mmio + PORT_SCR_CTL);
+       readl(port->mmio + PORT_SCR_CTL);
+
+       /* Wait 1 ms to quiesce chip function */
+       timeout = jiffies + msecs_to_jiffies(1);
+       while (time_before(jiffies, timeout))
+               ;
+
+       /* Clear PxSCTL.DET */
+       writel(readl(port->mmio + PORT_SCR_CTL) & ~1,
+                        port->mmio + PORT_SCR_CTL);
+       readl(port->mmio + PORT_SCR_CTL);
+
+       /* Wait 500 ms for bit 0 of PORT_SCR_STS to be set */
+       timeout = jiffies + msecs_to_jiffies(500);
+       while (((readl(port->mmio + PORT_SCR_STAT) & 0x01) == 0)
+                        && time_before(jiffies, timeout))
+               ;
+
+       if ((readl(port->mmio + PORT_SCR_STAT) & 0x01) == 0)
+               dev_warn(&port->dd->pdev->dev,
+                       "COM reset failed\n");
+
+       /* Clear SError, the PxSERR.DIAG.x should be set so clear it */
+       writel(readl(port->mmio + PORT_SCR_ERR), port->mmio + PORT_SCR_ERR);
+
+       /* Enable the DMA engine */
+       mtip_enable_engine(port, 1);
+}
+
+/*
+ * Called periodically to see if any read/write commands are
+ * taking too long to complete.
+ *
+ * @data Pointer to the PORT data structure.
+ *
+ * return value
+ *     None
+ */
+static void mtip_timeout_function(unsigned long int data)
+{
+       struct mtip_port *port = (struct mtip_port *) data;
+       struct host_to_dev_fis *fis;
+       struct mtip_cmd *command;
+       int tag, cmdto_cnt = 0;
+       unsigned int bit, group;
+       unsigned int num_command_slots = port->dd->slot_groups * 32;
+
+       if (unlikely(!port))
+               return;
+
+       if (atomic_read(&port->dd->resumeflag) == true) {
+               mod_timer(&port->cmd_timer,
+                       jiffies + msecs_to_jiffies(30000));
+               return;
+       }
+
+       for (tag = 0; tag < num_command_slots; tag++) {
+               /*
+                * Skip internal command slot as it has
+                * its own timeout mechanism
+                */
+               if (tag == MTIP_TAG_INTERNAL)
+                       continue;
+
+               if (atomic_read(&port->commands[tag].active) &&
+                  (time_after(jiffies, port->commands[tag].comp_time))) {
+                       group = tag >> 5;
+                       bit = tag & 0x1F;
+
+                       command = &port->commands[tag];
+                       fis = (struct host_to_dev_fis *) command->command;
+
+                       dev_warn(&port->dd->pdev->dev,
+                               "Timeout for command tag %d\n", tag);
+
+                       cmdto_cnt++;
+                       if (cmdto_cnt == 1)
+                               set_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags);
+
+                       /*
+                        * Clear the completed bit. This should prevent
+                        *  any interrupt handlers from trying to retire
+                        *  the command.
+                        */
+                       writel(1 << bit, port->completed[group]);
+
+                       /* Call the async completion callback. */
+                       if (likely(command->async_callback))
+                               command->async_callback(command->async_data,
+                                                        -EIO);
+                       command->async_callback = NULL;
+                       command->comp_func = NULL;
+
+                       /* Unmap the DMA scatter list entries */
+                       dma_unmap_sg(&port->dd->pdev->dev,
+                                       command->sg,
+                                       command->scatter_ents,
+                                       command->direction);
+
+                       /*
+                        * Clear the allocated bit and active tag for the
+                        * command.
+                        */
+                       atomic_set(&port->commands[tag].active, 0);
+                       release_slot(port, tag);
+
+                       up(&port->cmd_slot);
+               }
+       }
+
+       if (cmdto_cnt) {
+               dev_warn(&port->dd->pdev->dev,
+                       "%d commands timed out: restarting port",
+                       cmdto_cnt);
+               mtip_restart_port(port);
+               clear_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags);
+               wake_up_interruptible(&port->svc_wait);
+       }
+
+       /* Restart the timer */
+       mod_timer(&port->cmd_timer,
+               jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD));
+}
+
+/*
+ * IO completion function.
+ *
+ * This completion function is called by the driver ISR when a
+ * command that was issued by the kernel completes. It first calls the
+ * asynchronous completion function which normally calls back into the block
+ * layer passing the asynchronous callback data, then unmaps the
+ * scatter list associated with the completed command, and finally
+ * clears the allocated bit associated with the completed command.
+ *
+ * @port   Pointer to the port data structure.
+ * @tag    Tag of the command.
+ * @data   Pointer to driver_data.
+ * @status Completion status.
+ *
+ * return value
+ *     None
+ */
+static void mtip_async_complete(struct mtip_port *port,
+                               int tag,
+                               void *data,
+                               int status)
+{
+       struct mtip_cmd *command;
+       struct driver_data *dd = data;
+       int cb_status = status ? -EIO : 0;
+
+       if (unlikely(!dd) || unlikely(!port))
+               return;
+
+       command = &port->commands[tag];
+
+       if (unlikely(status == PORT_IRQ_TF_ERR)) {
+               dev_warn(&port->dd->pdev->dev,
+                       "Command tag %d failed due to TFE\n", tag);
+       }
+
+       /* Upper layer callback */
+       if (likely(command->async_callback))
+               command->async_callback(command->async_data, cb_status);
+
+       command->async_callback = NULL;
+       command->comp_func = NULL;
+
+       /* Unmap the DMA scatter list entries */
+       dma_unmap_sg(&dd->pdev->dev,
+               command->sg,
+               command->scatter_ents,
+               command->direction);
+
+       /* Clear the allocated and active bits for the command */
+       atomic_set(&port->commands[tag].active, 0);
+       release_slot(port, tag);
+
+       up(&port->cmd_slot);
+}
+
+/*
+ * Internal command completion callback function.
+ *
+ * This function is normally called by the driver ISR when an internal
+ * command completed. This function signals the command completion by
+ * calling complete().
+ *
+ * @port   Pointer to the port data structure.
+ * @tag    Tag of the command that has completed.
+ * @data   Pointer to a completion structure.
+ * @status Completion status.
+ *
+ * return value
+ *     None
+ */
+static void mtip_completion(struct mtip_port *port,
+                           int tag,
+                           void *data,
+                           int status)
+{
+       struct mtip_cmd *command = &port->commands[tag];
+       struct completion *waiting = data;
+       if (unlikely(status == PORT_IRQ_TF_ERR))
+               dev_warn(&port->dd->pdev->dev,
+                       "Internal command %d completed with TFE\n", tag);
+
+       command->async_callback = NULL;
+       command->comp_func = NULL;
+
+       complete(waiting);
+}
+
+/*
+ * Helper function for tag logging
+ */
+static void print_tags(struct driver_data *dd,
+                       char *msg,
+                       unsigned long *tagbits)
+{
+       unsigned int tag, count = 0;
+
+       for (tag = 0; tag < (dd->slot_groups) * 32; tag++) {
+               if (test_bit(tag, tagbits))
+                       count++;
+       }
+       if (count)
+               dev_info(&dd->pdev->dev, "%s [%i tags]\n", msg, count);
+}
+
+/*
+ * Handle an error.
+ *
+ * @dd Pointer to the DRIVER_DATA structure.
+ *
+ * return value
+ *     None
+ */
+static void mtip_handle_tfe(struct driver_data *dd)
+{
+       int group, tag, bit, reissue;
+       struct mtip_port *port;
+       struct mtip_cmd  *command;
+       u32 completed;
+       struct host_to_dev_fis *fis;
+       unsigned long tagaccum[SLOTBITS_IN_LONGS];
+
+       dev_warn(&dd->pdev->dev, "Taskfile error\n");
+
+       port = dd->port;
+
+       /* Stop the timer to prevent command timeouts. */
+       del_timer(&port->cmd_timer);
+
+       /* Set eh_active */
+       set_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags);
+
+       /* Loop through all the groups */
+       for (group = 0; group < dd->slot_groups; group++) {
+               completed = readl(port->completed[group]);
+
+               /* clear completed status register in the hardware.*/
+               writel(completed, port->completed[group]);
+
+               /* clear the tag accumulator */
+               memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long));
+
+               /* Process successfully completed commands */
+               for (bit = 0; bit < 32 && completed; bit++) {
+                       if (!(completed & (1<<bit)))
+                               continue;
+                       tag = (group << 5) + bit;
+
+                       /* Skip the internal command slot */
+                       if (tag == MTIP_TAG_INTERNAL)
+                               continue;
+
+                       command = &port->commands[tag];
+                       if (likely(command->comp_func)) {
+                               set_bit(tag, tagaccum);
+                               atomic_set(&port->commands[tag].active, 0);
+                               command->comp_func(port,
+                                        tag,
+                                        command->comp_data,
+                                        0);
+                       } else {
+                               dev_err(&port->dd->pdev->dev,
+                                       "Missing completion func for tag %d",
+                                       tag);
+                               if (mtip_check_surprise_removal(dd->pdev)) {
+                                       mtip_command_cleanup(dd);
+                                       /* don't proceed further */
+                                       return;
+                               }
+                       }
+               }
+       }
+       print_tags(dd, "TFE tags completed:", tagaccum);
+
+       /* Restart the port */
+       mdelay(20);
+       mtip_restart_port(port);
+
+       /* clear the tag accumulator */
+       memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long));
+
+       /* Loop through all the groups */
+       for (group = 0; group < dd->slot_groups; group++) {
+               for (bit = 0; bit < 32; bit++) {
+                       reissue = 1;
+                       tag = (group << 5) + bit;
+
+                       /* If the active bit is set re-issue the command */
+                       if (atomic_read(&port->commands[tag].active) == 0)
+                               continue;
+
+                       fis = (struct host_to_dev_fis *)
+                               port->commands[tag].command;
+
+                       /* Should re-issue? */
+                       if (tag == MTIP_TAG_INTERNAL ||
+                           fis->command == ATA_CMD_SET_FEATURES)
+                               reissue = 0;
+
+                       /*
+                        * First check if this command has
+                        *  exceeded its retries.
+                        */
+                       if (reissue &&
+                           (port->commands[tag].retries-- > 0)) {
+
+                               set_bit(tag, tagaccum);
+
+                               /* Update the timeout value. */
+                               port->commands[tag].comp_time =
+                                       jiffies + msecs_to_jiffies(
+                                       MTIP_NCQ_COMMAND_TIMEOUT_MS);
+                               /* Re-issue the command. */
+                               mtip_issue_ncq_command(port, tag);
+
+                               continue;
+                       }
+
+                       /* Retire a command that will not be reissued */
+                       dev_warn(&port->dd->pdev->dev,
+                               "retiring tag %d\n", tag);
+                       atomic_set(&port->commands[tag].active, 0);
+
+                       if (port->commands[tag].comp_func)
+                               port->commands[tag].comp_func(
+                                       port,
+                                       tag,
+                                       port->commands[tag].comp_data,
+                                       PORT_IRQ_TF_ERR);
+                       else
+                               dev_warn(&port->dd->pdev->dev,
+                                       "Bad completion for tag %d\n",
+                                       tag);
+               }
+       }
+       print_tags(dd, "TFE tags reissued:", tagaccum);
+
+       /* clear eh_active */
+       clear_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags);
+       wake_up_interruptible(&port->svc_wait);
+
+       mod_timer(&port->cmd_timer,
+                jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD));
+}
+
+/*
+ * Handle a set device bits interrupt
+ */
+static inline void mtip_process_sdbf(struct driver_data *dd)
+{
+       struct mtip_port  *port = dd->port;
+       int group, tag, bit;
+       u32 completed;
+       struct mtip_cmd *command;
+
+       /* walk all bits in all slot groups */
+       for (group = 0; group < dd->slot_groups; group++) {
+               completed = readl(port->completed[group]);
+
+               /* clear completed status register in the hardware.*/
+               writel(completed, port->completed[group]);
+
+               /* Process completed commands. */
+               for (bit = 0;
+                    (bit < 32) && completed;
+                    bit++, completed >>= 1) {
+                       if (completed & 0x01) {
+                               tag = (group << 5) | bit;
+
+                               /* skip internal command slot. */
+                               if (unlikely(tag == MTIP_TAG_INTERNAL))
+                                       continue;
+
+                               command = &port->commands[tag];
+                               /* make internal callback */
+                               if (likely(command->comp_func)) {
+                                       command->comp_func(
+                                               port,
+                                               tag,
+                                               command->comp_data,
+                                               0);
+                               } else {
+                                       dev_warn(&dd->pdev->dev,
+                                               "Null completion "
+                                               "for tag %d",
+                                               tag);
+
+                                       if (mtip_check_surprise_removal(
+                                               dd->pdev)) {
+                                               mtip_command_cleanup(dd);
+                                               return;
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+/*
+ * Process legacy pio and d2h interrupts
+ */
+static inline void mtip_process_legacy(struct driver_data *dd, u32 port_stat)
+{
+       struct mtip_port *port = dd->port;
+       struct mtip_cmd *cmd = &port->commands[MTIP_TAG_INTERNAL];
+
+       if (test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) &&
+           (cmd != NULL) && !(readl(port->cmd_issue[MTIP_TAG_INTERNAL])
+               & (1 << MTIP_TAG_INTERNAL))) {
+               if (cmd->comp_func) {
+                       cmd->comp_func(port,
+                               MTIP_TAG_INTERNAL,
+                               cmd->comp_data,
+                               0);
+                       return;
+               }
+       }
+
+       dev_warn(&dd->pdev->dev, "IRQ status 0x%x ignored.\n", port_stat);
+
+       return;
+}
+
+/*
+ * Demux and handle errors
+ */
+static inline void mtip_process_errors(struct driver_data *dd, u32 port_stat)
+{
+       if (likely(port_stat & (PORT_IRQ_TF_ERR | PORT_IRQ_IF_ERR)))
+               mtip_handle_tfe(dd);
+
+       if (unlikely(port_stat & PORT_IRQ_CONNECT)) {
+               dev_warn(&dd->pdev->dev,
+                       "Clearing PxSERR.DIAG.x\n");
+               writel((1 << 26), dd->port->mmio + PORT_SCR_ERR);
+       }
+
+       if (unlikely(port_stat & PORT_IRQ_PHYRDY)) {
+               dev_warn(&dd->pdev->dev,
+                       "Clearing PxSERR.DIAG.n\n");
+               writel((1 << 16), dd->port->mmio + PORT_SCR_ERR);
+       }
+
+       if (unlikely(port_stat & ~PORT_IRQ_HANDLED)) {
+               dev_warn(&dd->pdev->dev,
+                       "Port stat errors %x unhandled\n",
+                       (port_stat & ~PORT_IRQ_HANDLED));
+       }
+}
+
+static inline irqreturn_t mtip_handle_irq(struct driver_data *data)
+{
+       struct driver_data *dd = (struct driver_data *) data;
+       struct mtip_port *port = dd->port;
+       u32 hba_stat, port_stat;
+       int rv = IRQ_NONE;
+
+       hba_stat = readl(dd->mmio + HOST_IRQ_STAT);
+       if (hba_stat) {
+               rv = IRQ_HANDLED;
+
+               /* Acknowledge the interrupt status on the port.*/
+               port_stat = readl(port->mmio + PORT_IRQ_STAT);
+               writel(port_stat, port->mmio + PORT_IRQ_STAT);
+
+               /* Demux port status */
+               if (likely(port_stat & PORT_IRQ_SDB_FIS))
+                       mtip_process_sdbf(dd);
+
+               if (unlikely(port_stat & PORT_IRQ_ERR)) {
+                       if (unlikely(mtip_check_surprise_removal(dd->pdev))) {
+                               mtip_command_cleanup(dd);
+                               /* don't proceed further */
+                               return IRQ_HANDLED;
+                       }
+
+                       mtip_process_errors(dd, port_stat & PORT_IRQ_ERR);
+               }
+
+               if (unlikely(port_stat & PORT_IRQ_LEGACY))
+                       mtip_process_legacy(dd, port_stat & PORT_IRQ_LEGACY);
+       }
+
+       /* acknowledge interrupt */
+       writel(hba_stat, dd->mmio + HOST_IRQ_STAT);
+
+       return rv;
+}
+
+/*
+ * Wrapper for mtip_handle_irq
+ * (ignores return code)
+ */
+static void mtip_tasklet(unsigned long data)
+{
+       mtip_handle_irq((struct driver_data *) data);
+}
+
+/*
+ * HBA interrupt subroutine.
+ *
+ * @irq                IRQ number.
+ * @instance   Pointer to the driver data structure.
+ *
+ * return value
+ *     IRQ_HANDLED     A HBA interrupt was pending and handled.
+ *     IRQ_NONE        This interrupt was not for the HBA.
+ */
+static irqreturn_t mtip_irq_handler(int irq, void *instance)
+{
+       struct driver_data *dd = instance;
+       tasklet_schedule(&dd->tasklet);
+       return IRQ_HANDLED;
+}
+
+static void mtip_issue_non_ncq_command(struct mtip_port *port, int tag)
+{
+       atomic_set(&port->commands[tag].active, 1);
+       writel(1 << MTIP_TAG_BIT(tag),
+               port->cmd_issue[MTIP_TAG_INDEX(tag)]);
+}
+
+/*
+ * Wait for port to quiesce
+ *
+ * @port    Pointer to port data structure
+ * @timeout Max duration to wait (ms)
+ *
+ * return value
+ *     0       Success
+ *     -EBUSY  Commands still active
+ */
+static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout)
+{
+       unsigned long to;
+       unsigned int n;
+       unsigned int active = 1;
+
+       to = jiffies + msecs_to_jiffies(timeout);
+       do {
+               if (test_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags) &&
+                       test_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags)) {
+                       msleep(20);
+                       continue; /* svc thd is actively issuing commands */
+               }
+               /*
+                * Ignore s_active bit 0 of array element 0.
+                * This bit will always be set
+                */
+               active = readl(port->s_active[0]) & 0xFFFFFFFE;
+               for (n = 1; n < port->dd->slot_groups; n++)
+                       active |= readl(port->s_active[n]);
+
+               if (!active)
+                       break;
+
+               msleep(20);
+       } while (time_before(jiffies, to));
+
+       return active ? -EBUSY : 0;
+}
+
+/*
+ * Execute an internal command and wait for the completion.
+ *
+ * @port    Pointer to the port data structure.
+ * @fis     Pointer to the FIS that describes the command.
+ * @fis_len  Length in WORDS of the FIS.
+ * @buffer  DMA accessible for command data.
+ * @buf_len  Length, in bytes, of the data buffer.
+ * @opts    Command header options, excluding the FIS length
+ *             and the number of PRD entries.
+ * @timeout Time in ms to wait for the command to complete.
+ *
+ * return value
+ *     0        Command completed successfully.
+ *     -EFAULT  The buffer address is not correctly aligned.
+ *     -EBUSY   Internal command or other IO in progress.
+ *     -EAGAIN  Time out waiting for command to complete.
+ */
+static int mtip_exec_internal_command(struct mtip_port *port,
+                                       void *fis,
+                                       int fis_len,
+                                       dma_addr_t buffer,
+                                       int buf_len,
+                                       u32 opts,
+                                       gfp_t atomic,
+                                       unsigned long timeout)
+{
+       struct mtip_cmd_sg *command_sg;
+       DECLARE_COMPLETION_ONSTACK(wait);
+       int rv = 0;
+       struct mtip_cmd *int_cmd = &port->commands[MTIP_TAG_INTERNAL];
+
+       /* Make sure the buffer is 8 byte aligned. This is asic specific. */
+       if (buffer & 0x00000007) {
+               dev_err(&port->dd->pdev->dev,
+                       "SG buffer is not 8 byte aligned\n");
+               return -EFAULT;
+       }
+
+       /* Only one internal command should be running at a time */
+       if (test_and_set_bit(MTIP_TAG_INTERNAL, port->allocated)) {
+               dev_warn(&port->dd->pdev->dev,
+                       "Internal command already active\n");
+               return -EBUSY;
+       }
+       set_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags);
+
+       if (atomic == GFP_KERNEL) {
+               /* wait for io to complete if non atomic */
+               if (mtip_quiesce_io(port, 5000) < 0) {
+                       dev_warn(&port->dd->pdev->dev,
+                               "Failed to quiesce IO\n");
+                       release_slot(port, MTIP_TAG_INTERNAL);
+                       clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags);
+                       wake_up_interruptible(&port->svc_wait);
+                       return -EBUSY;
+               }
+
+               /* Set the completion function and data for the command. */
+               int_cmd->comp_data = &wait;
+               int_cmd->comp_func = mtip_completion;
+
+       } else {
+               /* Clear completion - we're going to poll */
+               int_cmd->comp_data = NULL;
+               int_cmd->comp_func = NULL;
+       }
+
+       /* Copy the command to the command table */
+       memcpy(int_cmd->command, fis, fis_len*4);
+
+       /* Populate the SG list */
+       int_cmd->command_header->opts =
+                __force_bit2int cpu_to_le32(opts | fis_len);
+       if (buf_len) {
+               command_sg = int_cmd->command + AHCI_CMD_TBL_HDR_SZ;
+
+               command_sg->info =
+                       __force_bit2int cpu_to_le32((buf_len-1) & 0x3FFFFF);
+               command_sg->dba =
+                       __force_bit2int cpu_to_le32(buffer & 0xFFFFFFFF);
+               command_sg->dba_upper =
+                       __force_bit2int cpu_to_le32((buffer >> 16) >> 16);
+
+               int_cmd->command_header->opts |=
+                       __force_bit2int cpu_to_le32((1 << 16));
+       }
+
+       /* Populate the command header */
+       int_cmd->command_header->byte_count = 0;
+
+       /* Issue the command to the hardware */
+       mtip_issue_non_ncq_command(port, MTIP_TAG_INTERNAL);
+
+       /* Poll if atomic, wait_for_completion otherwise */
+       if (atomic == GFP_KERNEL) {
+               /* Wait for the command to complete or timeout. */
+               if (wait_for_completion_timeout(
+                               &wait,
+                               msecs_to_jiffies(timeout)) == 0) {
+                       dev_err(&port->dd->pdev->dev,
+                               "Internal command did not complete [%d] "
+                               "within timeout of  %lu ms\n",
+                               atomic, timeout);
+                       rv = -EAGAIN;
+               }
+
+               if (readl(port->cmd_issue[MTIP_TAG_INTERNAL])
+                       & (1 << MTIP_TAG_INTERNAL)) {
+                       dev_warn(&port->dd->pdev->dev,
+                               "Retiring internal command but CI is 1.\n");
+               }
+
+       } else {
+               /* Spin for <timeout> checking if command still outstanding */
+               timeout = jiffies + msecs_to_jiffies(timeout);
+
+               while ((readl(
+                       port->cmd_issue[MTIP_TAG_INTERNAL])
+                       & (1 << MTIP_TAG_INTERNAL))
+                       && time_before(jiffies, timeout))
+                       ;
+
+               if (readl(port->cmd_issue[MTIP_TAG_INTERNAL])
+                       & (1 << MTIP_TAG_INTERNAL)) {
+                       dev_err(&port->dd->pdev->dev,
+                               "Internal command did not complete [%d]\n",
+                               atomic);
+                       rv = -EAGAIN;
+               }
+       }
+
+       /* Clear the allocated and active bits for the internal command. */
+       atomic_set(&int_cmd->active, 0);
+       release_slot(port, MTIP_TAG_INTERNAL);
+       clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags);
+       wake_up_interruptible(&port->svc_wait);
+
+       return rv;
+}
+
+/*
+ * Byte-swap ATA ID strings.
+ *
+ * ATA identify data contains strings in byte-swapped 16-bit words.
+ * They must be swapped (on all architectures) to be usable as C strings.
+ * This function swaps bytes in-place.
+ *
+ * @buf The buffer location of the string
+ * @len The number of bytes to swap
+ *
+ * return value
+ *     None
+ */
+static inline void ata_swap_string(u16 *buf, unsigned int len)
+{
+       int i;
+       for (i = 0; i < (len/2); i++)
+               be16_to_cpus(&buf[i]);
+}
+
+/*
+ * Request the device identity information.
+ *
+ * If a user space buffer is not specified, i.e. is NULL, the
+ * identify information is still read from the drive and placed
+ * into the identify data buffer (@e port->identify) in the
+ * port data structure.
+ * When the identify buffer contains valid identify information @e
+ * port->identify_valid is non-zero.
+ *
+ * @port        Pointer to the port structure.
+ * @user_buffer  A user space buffer where the identify data should be
+ *                    copied.
+ *
+ * return value
+ *     0       Command completed successfully.
+ *     -EFAULT An error occurred while coping data to the user buffer.
+ *     -1      Command failed.
+ */
+static int mtip_get_identify(struct mtip_port *port, void __user *user_buffer)
+{
+       int rv = 0;
+       struct host_to_dev_fis fis;
+
+       /* Build the FIS. */
+       memset(&fis, 0, sizeof(struct host_to_dev_fis));
+       fis.type        = 0x27;
+       fis.opts        = 1 << 7;
+       fis.command     = ATA_CMD_ID_ATA;
+
+       /* Set the identify information as invalid. */
+       port->identify_valid = 0;
+
+       /* Clear the identify information. */
+       memset(port->identify, 0, sizeof(u16) * ATA_ID_WORDS);
+
+       /* Execute the command. */
+       if (mtip_exec_internal_command(port,
+                               &fis,
+                               5,
+                               port->identify_dma,
+                               sizeof(u16) * ATA_ID_WORDS,
+                               0,
+                               GFP_KERNEL,
+                               MTIP_INTERNAL_COMMAND_TIMEOUT_MS)
+                               < 0) {
+               rv = -1;
+               goto out;
+       }
+
+       /*
+        * Perform any necessary byte-swapping.  Yes, the kernel does in fact
+        * perform field-sensitive swapping on the string fields.
+        * See the kernel use of ata_id_string() for proof of this.
+        */
+#ifdef __LITTLE_ENDIAN
+       ata_swap_string(port->identify + 27, 40);  /* model string*/
+       ata_swap_string(port->identify + 23, 8);   /* firmware string*/
+       ata_swap_string(port->identify + 10, 20);  /* serial# string*/
+#else
+       {
+               int i;
+               for (i = 0; i < ATA_ID_WORDS; i++)
+                       port->identify[i] = le16_to_cpu(port->identify[i]);
+       }
+#endif
+
+       /* Set the identify buffer as valid. */
+       port->identify_valid = 1;
+
+       if (user_buffer) {
+               if (copy_to_user(
+                       user_buffer,
+                       port->identify,
+                       ATA_ID_WORDS * sizeof(u16))) {
+                       rv = -EFAULT;
+                       goto out;
+               }
+       }
+
+out:
+       return rv;
+}
+
+/*
+ * Issue a standby immediate command to the device.
+ *
+ * @port Pointer to the port structure.
+ *
+ * return value
+ *     0       Command was executed successfully.
+ *     -1      An error occurred while executing the command.
+ */
+static int mtip_standby_immediate(struct mtip_port *port)
+{
+       int rv;
+       struct host_to_dev_fis  fis;
+
+       /* Build the FIS. */
+       memset(&fis, 0, sizeof(struct host_to_dev_fis));
+       fis.type        = 0x27;
+       fis.opts        = 1 << 7;
+       fis.command     = ATA_CMD_STANDBYNOW1;
+
+       /* Execute the command.  Use a 15-second timeout for large drives. */
+       rv = mtip_exec_internal_command(port,
+                                       &fis,
+                                       5,
+                                       0,
+                                       0,
+                                       0,
+                                       GFP_KERNEL,
+                                       15000);
+
+       return rv;
+}
+
+/*
+ * Get the drive capacity.
+ *
+ * @dd      Pointer to the device data structure.
+ * @sectors Pointer to the variable that will receive the sector count.
+ *
+ * return value
+ *     1 Capacity was returned successfully.
+ *     0 The identify information is invalid.
+ */
+static bool mtip_hw_get_capacity(struct driver_data *dd, sector_t *sectors)
+{
+       struct mtip_port *port = dd->port;
+       u64 total, raw0, raw1, raw2, raw3;
+       raw0 = port->identify[100];
+       raw1 = port->identify[101];
+       raw2 = port->identify[102];
+       raw3 = port->identify[103];
+       total = raw0 | raw1<<16 | raw2<<32 | raw3<<48;
+       *sectors = total;
+       return (bool) !!port->identify_valid;
+}
+
+/*
+ * Reset the HBA.
+ *
+ * Resets the HBA by setting the HBA Reset bit in the Global
+ * HBA Control register. After setting the HBA Reset bit the
+ * function waits for 1 second before reading the HBA Reset
+ * bit to make sure it has cleared. If HBA Reset is not clear
+ * an error is returned. Cannot be used in non-blockable
+ * context.
+ *
+ * @dd Pointer to the driver data structure.
+ *
+ * return value
+ *     0  The reset was successful.
+ *     -1 The HBA Reset bit did not clear.
+ */
+static int mtip_hba_reset(struct driver_data *dd)
+{
+       mtip_deinit_port(dd->port);
+
+       /* Set the reset bit */
+       writel(HOST_RESET, dd->mmio + HOST_CTL);
+
+       /* Flush */
+       readl(dd->mmio + HOST_CTL);
+
+       /* Wait for reset to clear */
+       ssleep(1);
+
+       /* Check the bit has cleared */
+       if (readl(dd->mmio + HOST_CTL) & HOST_RESET) {
+               dev_err(&dd->pdev->dev,
+                       "Reset bit did not clear.\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Display the identify command data.
+ *
+ * @port Pointer to the port data structure.
+ *
+ * return value
+ *     None
+ */
+static void mtip_dump_identify(struct mtip_port *port)
+{
+       sector_t sectors;
+       unsigned short revid;
+       char cbuf[42];
+
+       if (!port->identify_valid)
+               return;
+
+       strlcpy(cbuf, (char *)(port->identify+10), 21);
+       dev_info(&port->dd->pdev->dev,
+               "Serial No.: %s\n", cbuf);
+
+       strlcpy(cbuf, (char *)(port->identify+23), 9);
+       dev_info(&port->dd->pdev->dev,
+               "Firmware Ver.: %s\n", cbuf);
+
+       strlcpy(cbuf, (char *)(port->identify+27), 41);
+       dev_info(&port->dd->pdev->dev, "Model: %s\n", cbuf);
+
+       if (mtip_hw_get_capacity(port->dd, &sectors))
+               dev_info(&port->dd->pdev->dev,
+                       "Capacity: %llu sectors (%llu MB)\n",
+                        (u64)sectors,
+                        ((u64)sectors) * ATA_SECT_SIZE >> 20);
+
+       pci_read_config_word(port->dd->pdev, PCI_REVISION_ID, &revid);
+       switch (revid & 0xFF) {
+       case 0x1:
+               strlcpy(cbuf, "A0", 3);
+               break;
+       case 0x3:
+               strlcpy(cbuf, "A2", 3);
+               break;
+       default:
+               strlcpy(cbuf, "?", 2);
+               break;
+       }
+       dev_info(&port->dd->pdev->dev,
+               "Card Type: %s\n", cbuf);
+}
+
+/*
+ * Map the commands scatter list into the command table.
+ *
+ * @command Pointer to the command.
+ * @nents Number of scatter list entries.
+ *
+ * return value
+ *     None
+ */
+static inline void fill_command_sg(struct driver_data *dd,
+                               struct mtip_cmd *command,
+                               int nents)
+{
+       int n;
+       unsigned int dma_len;
+       struct mtip_cmd_sg *command_sg;
+       struct scatterlist *sg = command->sg;
+
+       command_sg = command->command + AHCI_CMD_TBL_HDR_SZ;
+
+       for (n = 0; n < nents; n++) {
+               dma_len = sg_dma_len(sg);
+               if (dma_len > 0x400000)
+                       dev_err(&dd->pdev->dev,
+                               "DMA segment length truncated\n");
+               command_sg->info = __force_bit2int
+                       cpu_to_le32((dma_len-1) & 0x3FFFFF);
+               command_sg->dba = __force_bit2int
+                       cpu_to_le32(sg_dma_address(sg));
+               command_sg->dba_upper = __force_bit2int
+                       cpu_to_le32((sg_dma_address(sg) >> 16) >> 16);
+               command_sg++;
+               sg++;
+       }
+}
+
+/*
+ * @brief Execute a drive command.
+ *
+ * return value 0 The command completed successfully.
+ * return value -1 An error occurred while executing the command.
+ */
+static int exec_drive_task(struct mtip_port *port, u8 *command)
+{
+       struct host_to_dev_fis  fis;
+       struct host_to_dev_fis *reply = (port->rxfis + RX_FIS_D2H_REG);
+
+       /* Build the FIS. */
+       memset(&fis, 0, sizeof(struct host_to_dev_fis));
+       fis.type        = 0x27;
+       fis.opts        = 1 << 7;
+       fis.command     = command[0];
+       fis.features    = command[1];
+       fis.sect_count  = command[2];
+       fis.sector      = command[3];
+       fis.cyl_low     = command[4];
+       fis.cyl_hi      = command[5];
+       fis.device      = command[6] & ~0x10; /* Clear the dev bit*/
+
+
+       dbg_printk(MTIP_DRV_NAME "%s: User Command: cmd %x, feat %x, "
+               "nsect %x, sect %x, lcyl %x, "
+               "hcyl %x, sel %x\n",
+               __func__,
+               command[0],
+               command[1],
+               command[2],
+               command[3],
+               command[4],
+               command[5],
+               command[6]);
+
+       /* Execute the command. */
+       if (mtip_exec_internal_command(port,
+                                &fis,
+                                5,
+                                0,
+                                0,
+                                0,
+                                GFP_KERNEL,
+                                MTIP_IOCTL_COMMAND_TIMEOUT_MS) < 0) {
+               return -1;
+       }
+
+       command[0] = reply->command; /* Status*/
+       command[1] = reply->features; /* Error*/
+       command[4] = reply->cyl_low;
+       command[5] = reply->cyl_hi;
+
+       dbg_printk(MTIP_DRV_NAME "%s: Completion Status: stat %x, "
+               "err %x , cyl_lo %x cyl_hi %x\n",
+               __func__,
+               command[0],
+               command[1],
+               command[4],
+               command[5]);
+
+       return 0;
+}
+
+/*
+ * @brief Execute a drive command.
+ *
+ * @param port Pointer to the port data structure.
+ * @param command Pointer to the user specified command parameters.
+ * @param user_buffer Pointer to the user space buffer where read sector
+ *                   data should be copied.
+ *
+ * return value 0 The command completed successfully.
+ * return value -EFAULT An error occurred while copying the completion
+ *                 data to the user space buffer.
+ * return value -1 An error occurred while executing the command.
+ */
+static int exec_drive_command(struct mtip_port *port, u8 *command,
+                               void __user *user_buffer)
+{
+       struct host_to_dev_fis  fis;
+       struct host_to_dev_fis *reply = (port->rxfis + RX_FIS_D2H_REG);
+
+       /* Build the FIS. */
+       memset(&fis, 0, sizeof(struct host_to_dev_fis));
+       fis.type                = 0x27;
+       fis.opts                = 1 << 7;
+       fis.command             = command[0];
+       fis.features    = command[2];
+       fis.sect_count  = command[3];
+       if (fis.command == ATA_CMD_SMART) {
+               fis.sector      = command[1];
+               fis.cyl_low     = 0x4F;
+               fis.cyl_hi      = 0xC2;
+       }
+
+       dbg_printk(MTIP_DRV_NAME
+               "%s: User Command: cmd %x, sect %x, "
+               "feat %x, sectcnt %x\n",
+               __func__,
+               command[0],
+               command[1],
+               command[2],
+               command[3]);
+
+       memset(port->sector_buffer, 0x00, ATA_SECT_SIZE);
+
+       /* Execute the command. */
+       if (mtip_exec_internal_command(port,
+                               &fis,
+                                5,
+                                port->sector_buffer_dma,
+                                (command[3] != 0) ? ATA_SECT_SIZE : 0,
+                                0,
+                                GFP_KERNEL,
+                                MTIP_IOCTL_COMMAND_TIMEOUT_MS)
+                                < 0) {
+               return -1;
+       }
+
+       /* Collect the completion status. */
+       command[0] = reply->command; /* Status*/
+       command[1] = reply->features; /* Error*/
+       command[2] = command[3];
+
+       dbg_printk(MTIP_DRV_NAME
+               "%s: Completion Status: stat %x, "
+               "err %x, cmd %x\n",
+               __func__,
+               command[0],
+               command[1],
+               command[2]);
+
+       if (user_buffer && command[3]) {
+               if (copy_to_user(user_buffer,
+                                port->sector_buffer,
+                                ATA_SECT_SIZE * command[3])) {
+                       return -EFAULT;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ *  Indicates whether a command has a single sector payload.
+ *
+ *  @command passed to the device to perform the certain event.
+ *  @features passed to the device to perform the certain event.
+ *
+ *  return value
+ *     1       command is one that always has a single sector payload,
+ *             regardless of the value in the Sector Count field.
+ *      0       otherwise
+ *
+ */
+static unsigned int implicit_sector(unsigned char command,
+                                   unsigned char features)
+{
+       unsigned int rv = 0;
+
+       /* list of commands that have an implicit sector count of 1 */
+       switch (command) {
+       case ATA_CMD_SEC_SET_PASS:
+       case ATA_CMD_SEC_UNLOCK:
+       case ATA_CMD_SEC_ERASE_PREP:
+       case ATA_CMD_SEC_ERASE_UNIT:
+       case ATA_CMD_SEC_FREEZE_LOCK:
+       case ATA_CMD_SEC_DISABLE_PASS:
+       case ATA_CMD_PMP_READ:
+       case ATA_CMD_PMP_WRITE:
+               rv = 1;
+               break;
+       case ATA_CMD_SET_MAX:
+               if (features == ATA_SET_MAX_UNLOCK)
+                       rv = 1;
+               break;
+       case ATA_CMD_SMART:
+               if ((features == ATA_SMART_READ_VALUES) ||
+                               (features == ATA_SMART_READ_THRESHOLDS))
+                       rv = 1;
+               break;
+       case ATA_CMD_CONF_OVERLAY:
+               if ((features == ATA_DCO_IDENTIFY) ||
+                               (features == ATA_DCO_SET))
+                       rv = 1;
+               break;
+       }
+       return rv;
+}
+
+/*
+ * Executes a taskfile
+ * See ide_taskfile_ioctl() for derivation
+ */
+static int exec_drive_taskfile(struct driver_data *dd,
+                              void __user *buf,
+                              ide_task_request_t *req_task,
+                              int outtotal)
+{
+       struct host_to_dev_fis  fis;
+       struct host_to_dev_fis *reply;
+       u8 *outbuf = NULL;
+       u8 *inbuf = NULL;
+       dma_addr_t outbuf_dma = 0;
+       dma_addr_t inbuf_dma = 0;
+       dma_addr_t dma_buffer = 0;
+       int err = 0;
+       unsigned int taskin = 0;
+       unsigned int taskout = 0;
+       u8 nsect = 0;
+       unsigned int timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS;
+       unsigned int force_single_sector;
+       unsigned int transfer_size;
+       unsigned long task_file_data;
+       int intotal = outtotal + req_task->out_size;
+
+       taskout = req_task->out_size;
+       taskin = req_task->in_size;
+       /* 130560 = 512 * 0xFF*/
+       if (taskin > 130560 || taskout > 130560) {
+               err = -EINVAL;
+               goto abort;
+       }
+
+       if (taskout) {
+               outbuf = kzalloc(taskout, GFP_KERNEL);
+               if (outbuf == NULL) {
+                       err = -ENOMEM;
+                       goto abort;
+               }
+               if (copy_from_user(outbuf, buf + outtotal, taskout)) {
+                       err = -EFAULT;
+                       goto abort;
+               }
+               outbuf_dma = pci_map_single(dd->pdev,
+                                        outbuf,
+                                        taskout,
+                                        DMA_TO_DEVICE);
+               if (outbuf_dma == 0) {
+                       err = -ENOMEM;
+                       goto abort;
+               }
+               dma_buffer = outbuf_dma;
+       }
+
+       if (taskin) {
+               inbuf = kzalloc(taskin, GFP_KERNEL);
+               if (inbuf == NULL) {
+                       err = -ENOMEM;
+                       goto abort;
+               }
+
+               if (copy_from_user(inbuf, buf + intotal, taskin)) {
+                       err = -EFAULT;
+                       goto abort;
+               }
+               inbuf_dma = pci_map_single(dd->pdev,
+                                        inbuf,
+                                        taskin, DMA_FROM_DEVICE);
+               if (inbuf_dma == 0) {
+                       err = -ENOMEM;
+                       goto abort;
+               }
+               dma_buffer = inbuf_dma;
+       }
+
+       /* only supports PIO and non-data commands from this ioctl. */
+       switch (req_task->data_phase) {
+       case TASKFILE_OUT:
+               nsect = taskout / ATA_SECT_SIZE;
+               reply = (dd->port->rxfis + RX_FIS_PIO_SETUP);
+               break;
+       case TASKFILE_IN:
+               reply = (dd->port->rxfis + RX_FIS_PIO_SETUP);
+               break;
+       case TASKFILE_NO_DATA:
+               reply = (dd->port->rxfis + RX_FIS_D2H_REG);
+               break;
+       default:
+               err = -EINVAL;
+               goto abort;
+       }
+
+       /* Build the FIS. */
+       memset(&fis, 0, sizeof(struct host_to_dev_fis));
+
+       fis.type        = 0x27;
+       fis.opts        = 1 << 7;
+       fis.command     = req_task->io_ports[7];
+       fis.features    = req_task->io_ports[1];
+       fis.sect_count  = req_task->io_ports[2];
+       fis.lba_low     = req_task->io_ports[3];
+       fis.lba_mid     = req_task->io_ports[4];
+       fis.lba_hi      = req_task->io_ports[5];
+        /* Clear the dev bit*/
+       fis.device      = req_task->io_ports[6] & ~0x10;
+
+       if ((req_task->in_flags.all == 0) && (req_task->out_flags.all & 1)) {
+               req_task->in_flags.all  =
+                       IDE_TASKFILE_STD_IN_FLAGS |
+                       (IDE_HOB_STD_IN_FLAGS << 8);
+               fis.lba_low_ex          = req_task->hob_ports[3];
+               fis.lba_mid_ex          = req_task->hob_ports[4];
+               fis.lba_hi_ex           = req_task->hob_ports[5];
+               fis.features_ex         = req_task->hob_ports[1];
+               fis.sect_cnt_ex         = req_task->hob_ports[2];
+
+       } else {
+               req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+       }
+
+       force_single_sector = implicit_sector(fis.command, fis.features);
+
+       if ((taskin || taskout) && (!fis.sect_count)) {
+               if (nsect)
+                       fis.sect_count = nsect;
+               else {
+                       if (!force_single_sector) {
+                               dev_warn(&dd->pdev->dev,
+                                       "data movement but "
+                                       "sect_count is 0\n");
+                                       err = -EINVAL;
+                                       goto abort;
+                       }
+               }
+       }
+
+       dbg_printk(MTIP_DRV_NAME
+               "taskfile: cmd %x, feat %x, nsect %x,"
+               " sect/lbal %x, lcyl/lbam %x, hcyl/lbah %x,"
+               " head/dev %x\n",
+               fis.command,
+               fis.features,
+               fis.sect_count,
+               fis.lba_low,
+               fis.lba_mid,
+               fis.lba_hi,
+               fis.device);
+
+       switch (fis.command) {
+       case ATA_CMD_DOWNLOAD_MICRO:
+               /* Change timeout for Download Microcode to 60 seconds.*/
+               timeout = 60000;
+               break;
+       case ATA_CMD_SEC_ERASE_UNIT:
+               /* Change timeout for Security Erase Unit to 4 minutes.*/
+               timeout = 240000;
+               break;
+       case ATA_CMD_STANDBYNOW1:
+               /* Change timeout for standby immediate to 10 seconds.*/
+               timeout = 10000;
+               break;
+       case 0xF7:
+       case 0xFA:
+               /* Change timeout for vendor unique command to 10 secs */
+               timeout = 10000;
+               break;
+       case ATA_CMD_SMART:
+               /* Change timeout for vendor unique command to 10 secs */
+               timeout = 10000;
+               break;
+       default:
+               timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS;
+               break;
+       }
+
+       /* Determine the correct transfer size.*/
+       if (force_single_sector)
+               transfer_size = ATA_SECT_SIZE;
+       else
+               transfer_size = ATA_SECT_SIZE * fis.sect_count;
+
+       /* Execute the command.*/
+       if (mtip_exec_internal_command(dd->port,
+                                &fis,
+                                5,
+                                dma_buffer,
+                                transfer_size,
+                                0,
+                                GFP_KERNEL,
+                                timeout) < 0) {
+               err = -EIO;
+               goto abort;
+       }
+
+       task_file_data = readl(dd->port->mmio+PORT_TFDATA);
+
+       if ((req_task->data_phase == TASKFILE_IN) && !(task_file_data & 1)) {
+               reply = dd->port->rxfis + RX_FIS_PIO_SETUP;
+               req_task->io_ports[7] = reply->control;
+       } else {
+               reply = dd->port->rxfis + RX_FIS_D2H_REG;
+               req_task->io_ports[7] = reply->command;
+       }
+
+       /* reclaim the DMA buffers.*/
+       if (inbuf_dma)
+               pci_unmap_single(dd->pdev, inbuf_dma,
+                       taskin, DMA_FROM_DEVICE);
+       if (outbuf_dma)
+               pci_unmap_single(dd->pdev, outbuf_dma,
+                       taskout, DMA_TO_DEVICE);
+       inbuf_dma  = 0;
+       outbuf_dma = 0;
+
+       /* return the ATA registers to the caller.*/
+       req_task->io_ports[1] = reply->features;
+       req_task->io_ports[2] = reply->sect_count;
+       req_task->io_ports[3] = reply->lba_low;
+       req_task->io_ports[4] = reply->lba_mid;
+       req_task->io_ports[5] = reply->lba_hi;
+       req_task->io_ports[6] = reply->device;
+
+       if (req_task->out_flags.all & 1)  {
+
+               req_task->hob_ports[3] = reply->lba_low_ex;
+               req_task->hob_ports[4] = reply->lba_mid_ex;
+               req_task->hob_ports[5] = reply->lba_hi_ex;
+               req_task->hob_ports[1] = reply->features_ex;
+               req_task->hob_ports[2] = reply->sect_cnt_ex;
+       }
+
+       /* Com rest after secure erase or lowlevel format */
+       if (((fis.command == ATA_CMD_SEC_ERASE_UNIT) ||
+               ((fis.command == 0xFC) &&
+                       (fis.features == 0x27 || fis.features == 0x72 ||
+                        fis.features == 0x62 || fis.features == 0x26))) &&
+                        !(reply->command & 1)) {
+               mtip_restart_port(dd->port);
+       }
+
+       dbg_printk(MTIP_DRV_NAME
+               "%s: Completion: stat %x,"
+               "err %x, sect_cnt %x, lbalo %x,"
+               "lbamid %x, lbahi %x, dev %x\n",
+               __func__,
+               req_task->io_ports[7],
+               req_task->io_ports[1],
+               req_task->io_ports[2],
+               req_task->io_ports[3],
+               req_task->io_ports[4],
+               req_task->io_ports[5],
+               req_task->io_ports[6]);
+
+       if (taskout) {
+               if (copy_to_user(buf + outtotal, outbuf, taskout)) {
+                       err = -EFAULT;
+                       goto abort;
+               }
+       }
+       if (taskin) {
+               if (copy_to_user(buf + intotal, inbuf, taskin)) {
+                       err = -EFAULT;
+                       goto abort;
+               }
+       }
+abort:
+       if (inbuf_dma)
+               pci_unmap_single(dd->pdev, inbuf_dma,
+                                       taskin, DMA_FROM_DEVICE);
+       if (outbuf_dma)
+               pci_unmap_single(dd->pdev, outbuf_dma,
+                                       taskout, DMA_TO_DEVICE);
+       kfree(outbuf);
+       kfree(inbuf);
+
+       return err;
+}
+
+/*
+ * Handle IOCTL calls from the Block Layer.
+ *
+ * This function is called by the Block Layer when it receives an IOCTL
+ * command that it does not understand. If the IOCTL command is not supported
+ * this function returns -ENOTTY.
+ *
+ * @dd  Pointer to the driver data structure.
+ * @cmd IOCTL command passed from the Block Layer.
+ * @arg IOCTL argument passed from the Block Layer.
+ *
+ * return value
+ *     0       The IOCTL completed successfully.
+ *     -ENOTTY The specified command is not supported.
+ *     -EFAULT An error occurred copying data to a user space buffer.
+ *     -EIO    An error occurred while executing the command.
+ */
+static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd,
+                        unsigned long arg)
+{
+       switch (cmd) {
+       case HDIO_GET_IDENTITY:
+               if (mtip_get_identify(dd->port, (void __user *) arg) < 0) {
+                       dev_warn(&dd->pdev->dev,
+                               "Unable to read identity\n");
+                       return -EIO;
+               }
+
+               break;
+       case HDIO_DRIVE_CMD:
+       {
+               u8 drive_command[4];
+
+               /* Copy the user command info to our buffer. */
+               if (copy_from_user(drive_command,
+                                        (void __user *) arg,
+                                        sizeof(drive_command)))
+                       return -EFAULT;
+
+               /* Execute the drive command. */
+               if (exec_drive_command(dd->port,
+                                        drive_command,
+                                        (void __user *) (arg+4)))
+                       return -EIO;
+
+               /* Copy the status back to the users buffer. */
+               if (copy_to_user((void __user *) arg,
+                                        drive_command,
+                                        sizeof(drive_command)))
+                       return -EFAULT;
+
+               break;
+       }
+       case HDIO_DRIVE_TASK:
+       {
+               u8 drive_command[7];
+
+               /* Copy the user command info to our buffer. */
+               if (copy_from_user(drive_command,
+                                        (void __user *) arg,
+                                        sizeof(drive_command)))
+                       return -EFAULT;
+
+               /* Execute the drive command. */
+               if (exec_drive_task(dd->port, drive_command))
+                       return -EIO;
+
+               /* Copy the status back to the users buffer. */
+               if (copy_to_user((void __user *) arg,
+                                        drive_command,
+                                        sizeof(drive_command)))
+                       return -EFAULT;
+
+               break;
+       }
+       case HDIO_DRIVE_TASKFILE: {
+               ide_task_request_t req_task;
+               int ret, outtotal;
+
+               if (copy_from_user(&req_task, (void __user *) arg,
+                                       sizeof(req_task)))
+                       return -EFAULT;
+
+               outtotal = sizeof(req_task);
+
+               ret = exec_drive_taskfile(dd, (void __user *) arg,
+                                               &req_task, outtotal);
+
+               if (copy_to_user((void __user *) arg, &req_task,
+                                                       sizeof(req_task)))
+                       return -EFAULT;
+
+               return ret;
+       }
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*
+ * Submit an IO to the hw
+ *
+ * This function is called by the block layer to issue an io
+ * to the device. Upon completion, the callback function will
+ * be called with the data parameter passed as the callback data.
+ *
+ * @dd       Pointer to the driver data structure.
+ * @start    First sector to read.
+ * @nsect    Number of sectors to read.
+ * @nents    Number of entries in scatter list for the read command.
+ * @tag      The tag of this read command.
+ * @callback Pointer to the function that should be called
+ *          when the read completes.
+ * @data     Callback data passed to the callback function
+ *          when the read completes.
+ * @barrier  If non-zero, this command must be completed before
+ *          issuing any other commands.
+ * @dir      Direction (read or write)
+ *
+ * return value
+ *     None
+ */
+static void mtip_hw_submit_io(struct driver_data *dd, sector_t start,
+                             int nsect, int nents, int tag, void *callback,
+                             void *data, int barrier, int dir)
+{
+       struct host_to_dev_fis  *fis;
+       struct mtip_port *port = dd->port;
+       struct mtip_cmd *command = &port->commands[tag];
+
+       /* Map the scatter list for DMA access */
+       if (dir == READ)
+               nents = dma_map_sg(&dd->pdev->dev, command->sg,
+                                       nents, DMA_FROM_DEVICE);
+       else
+               nents = dma_map_sg(&dd->pdev->dev, command->sg,
+                                       nents, DMA_TO_DEVICE);
+
+       command->scatter_ents = nents;
+
+       /*
+        * The number of retries for this command before it is
+        * reported as a failure to the upper layers.
+        */
+       command->retries = MTIP_MAX_RETRIES;
+
+       /* Fill out fis */
+       fis = command->command;
+       fis->type        = 0x27;
+       fis->opts        = 1 << 7;
+       fis->command     =
+               (dir == READ ? ATA_CMD_FPDMA_READ : ATA_CMD_FPDMA_WRITE);
+       *((unsigned int *) &fis->lba_low) = (start & 0xFFFFFF);
+       *((unsigned int *) &fis->lba_low_ex) = ((start >> 24) & 0xFFFFFF);
+       fis->device      = 1 << 6;
+       if (barrier)
+               fis->device |= FUA_BIT;
+       fis->features    = nsect & 0xFF;
+       fis->features_ex = (nsect >> 8) & 0xFF;
+       fis->sect_count  = ((tag << 3) | (tag >> 5));
+       fis->sect_cnt_ex = 0;
+       fis->control     = 0;
+       fis->res2        = 0;
+       fis->res3        = 0;
+       fill_command_sg(dd, command, nents);
+
+       /* Populate the command header */
+       command->command_header->opts =
+                       __force_bit2int cpu_to_le32(
+                               (nents << 16) | 5 | AHCI_CMD_PREFETCH);
+       command->command_header->byte_count = 0;
+
+       /*
+        * Set the completion function and data for the command
+        * within this layer.
+        */
+       command->comp_data = dd;
+       command->comp_func = mtip_async_complete;
+       command->direction = (dir == READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+
+       /*
+        * Set the completion function and data for the command passed
+        * from the upper layer.
+        */
+       command->async_data = data;
+       command->async_callback = callback;
+
+       /*
+        * To prevent this command from being issued
+        * if an internal command is in progress or error handling is active.
+        */
+       if (unlikely(test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) ||
+                       test_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags))) {
+               set_bit(tag, port->cmds_to_issue);
+               set_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags);
+               return;
+       }
+
+       /* Issue the command to the hardware */
+       mtip_issue_ncq_command(port, tag);
+
+       /* Set the command's timeout value.*/
+       port->commands[tag].comp_time = jiffies + msecs_to_jiffies(
+                                       MTIP_NCQ_COMMAND_TIMEOUT_MS);
+}
+
+/*
+ * Release a command slot.
+ *
+ * @dd  Pointer to the driver data structure.
+ * @tag Slot tag
+ *
+ * return value
+ *      None
+ */
+static void mtip_hw_release_scatterlist(struct driver_data *dd, int tag)
+{
+       release_slot(dd->port, tag);
+}
+
+/*
+ * Obtain a command slot and return its associated scatter list.
+ *
+ * @dd  Pointer to the driver data structure.
+ * @tag Pointer to an int that will receive the allocated command
+ *            slot tag.
+ *
+ * return value
+ *     Pointer to the scatter list for the allocated command slot
+ *     or NULL if no command slots are available.
+ */
+static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd,
+                                                  int *tag)
+{
+       /*
+        * It is possible that, even with this semaphore, a thread
+        * may think that no command slots are available. Therefore, we
+        * need to make an attempt to get_slot().
+        */
+       down(&dd->port->cmd_slot);
+       *tag = get_slot(dd->port);
+
+       if (unlikely(*tag < 0))
+               return NULL;
+
+       return dd->port->commands[*tag].sg;
+}
+
+/*
+ * Sysfs register/status dump.
+ *
+ * @dev  Pointer to the device structure, passed by the kernrel.
+ * @attr Pointer to the device_attribute structure passed by the kernel.
+ * @buf  Pointer to the char buffer that will receive the stats info.
+ *
+ * return value
+ *     The size, in bytes, of the data copied into buf.
+ */
+static ssize_t hw_show_registers(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       u32 group_allocated;
+       struct driver_data *dd = dev_to_disk(dev)->private_data;
+       int size = 0;
+       int n;
+
+       size += sprintf(&buf[size], "%s:\ns_active:\n", __func__);
+
+       for (n = 0; n < dd->slot_groups; n++)
+               size += sprintf(&buf[size], "0x%08x\n",
+                                        readl(dd->port->s_active[n]));
+
+       size += sprintf(&buf[size], "Command Issue:\n");
+
+       for (n = 0; n < dd->slot_groups; n++)
+               size += sprintf(&buf[size], "0x%08x\n",
+                                       readl(dd->port->cmd_issue[n]));
+
+       size += sprintf(&buf[size], "Allocated:\n");
+
+       for (n = 0; n < dd->slot_groups; n++) {
+               if (sizeof(long) > sizeof(u32))
+                       group_allocated =
+                               dd->port->allocated[n/2] >> (32*(n&1));
+               else
+                       group_allocated = dd->port->allocated[n];
+               size += sprintf(&buf[size], "0x%08x\n",
+                                group_allocated);
+       }
+
+       size += sprintf(&buf[size], "completed:\n");
+
+       for (n = 0; n < dd->slot_groups; n++)
+               size += sprintf(&buf[size], "0x%08x\n",
+                               readl(dd->port->completed[n]));
+
+       size += sprintf(&buf[size], "PORT_IRQ_STAT 0x%08x\n",
+                               readl(dd->port->mmio + PORT_IRQ_STAT));
+       size += sprintf(&buf[size], "HOST_IRQ_STAT 0x%08x\n",
+                               readl(dd->mmio + HOST_IRQ_STAT));
+
+       return size;
+}
+static DEVICE_ATTR(registers, S_IRUGO, hw_show_registers, NULL);
+
+/*
+ * Create the sysfs related attributes.
+ *
+ * @dd   Pointer to the driver data structure.
+ * @kobj Pointer to the kobj for the block device.
+ *
+ * return value
+ *     0       Operation completed successfully.
+ *     -EINVAL Invalid parameter.
+ */
+static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj)
+{
+       if (!kobj || !dd)
+               return -EINVAL;
+
+       if (sysfs_create_file(kobj, &dev_attr_registers.attr))
+               dev_warn(&dd->pdev->dev,
+                       "Error creating registers sysfs entry\n");
+       return 0;
+}
+
+/*
+ * Remove the sysfs related attributes.
+ *
+ * @dd   Pointer to the driver data structure.
+ * @kobj Pointer to the kobj for the block device.
+ *
+ * return value
+ *     0       Operation completed successfully.
+ *     -EINVAL Invalid parameter.
+ */
+static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj)
+{
+       if (!kobj || !dd)
+               return -EINVAL;
+
+       sysfs_remove_file(kobj, &dev_attr_registers.attr);
+
+       return 0;
+}
+
+/*
+ * Perform any init/resume time hardware setup
+ *
+ * @dd Pointer to the driver data structure.
+ *
+ * return value
+ *     None
+ */
+static inline void hba_setup(struct driver_data *dd)
+{
+       u32 hwdata;
+       hwdata = readl(dd->mmio + HOST_HSORG);
+
+       /* interrupt bug workaround: use only 1 IS bit.*/
+       writel(hwdata |
+               HSORG_DISABLE_SLOTGRP_INTR |
+               HSORG_DISABLE_SLOTGRP_PXIS,
+               dd->mmio + HOST_HSORG);
+}
+
+/*
+ * Detect the details of the product, and store anything needed
+ * into the driver data structure.  This includes product type and
+ * version and number of slot groups.
+ *
+ * @dd Pointer to the driver data structure.
+ *
+ * return value
+ *     None
+ */
+static void mtip_detect_product(struct driver_data *dd)
+{
+       u32 hwdata;
+       unsigned int rev, slotgroups;
+
+       /*
+        * HBA base + 0xFC [15:0] - vendor-specific hardware interface
+        * info register:
+        * [15:8] hardware/software interface rev#
+        * [   3] asic-style interface
+        * [ 2:0] number of slot groups, minus 1 (only valid for asic-style).
+        */
+       hwdata = readl(dd->mmio + HOST_HSORG);
+
+       dd->product_type = MTIP_PRODUCT_UNKNOWN;
+       dd->slot_groups = 1;
+
+       if (hwdata & 0x8) {
+               dd->product_type = MTIP_PRODUCT_ASICFPGA;
+               rev = (hwdata & HSORG_HWREV) >> 8;
+               slotgroups = (hwdata & HSORG_SLOTGROUPS) + 1;
+               dev_info(&dd->pdev->dev,
+                       "ASIC-FPGA design, HS rev 0x%x, "
+                       "%i slot groups [%i slots]\n",
+                        rev,
+                        slotgroups,
+                        slotgroups * 32);
+
+               if (slotgroups > MTIP_MAX_SLOT_GROUPS) {
+                       dev_warn(&dd->pdev->dev,
+                               "Warning: driver only supports "
+                               "%i slot groups.\n", MTIP_MAX_SLOT_GROUPS);
+                       slotgroups = MTIP_MAX_SLOT_GROUPS;
+               }
+               dd->slot_groups = slotgroups;
+               return;
+       }
+
+       dev_warn(&dd->pdev->dev, "Unrecognized product id\n");
+}
+
+/*
+ * Blocking wait for FTL rebuild to complete
+ *
+ * @dd Pointer to the DRIVER_DATA structure.
+ *
+ * return value
+ *     0       FTL rebuild completed successfully
+ *     -EFAULT FTL rebuild error/timeout/interruption
+ */
+static int mtip_ftl_rebuild_poll(struct driver_data *dd)
+{
+       unsigned long timeout, cnt = 0, start;
+
+       dev_warn(&dd->pdev->dev,
+               "FTL rebuild in progress. Polling for completion.\n");
+
+       start = jiffies;
+       dd->ftlrebuildflag = 1;
+       timeout = jiffies + msecs_to_jiffies(MTIP_FTL_REBUILD_TIMEOUT_MS);
+
+       do {
+               if (mtip_check_surprise_removal(dd->pdev))
+                       return -EFAULT;
+
+               if (mtip_get_identify(dd->port, NULL) < 0)
+                       return -EFAULT;
+
+               if (*(dd->port->identify + MTIP_FTL_REBUILD_OFFSET) ==
+                       MTIP_FTL_REBUILD_MAGIC) {
+                       ssleep(1);
+                       /* Print message every 3 minutes */
+                       if (cnt++ >= 180) {
+                               dev_warn(&dd->pdev->dev,
+                               "FTL rebuild in progress (%d secs).\n",
+                               jiffies_to_msecs(jiffies - start) / 1000);
+                               cnt = 0;
+                       }
+               } else {
+                       dev_warn(&dd->pdev->dev,
+                               "FTL rebuild complete (%d secs).\n",
+                       jiffies_to_msecs(jiffies - start) / 1000);
+                       dd->ftlrebuildflag = 0;
+                       mtip_block_initialize(dd);
+                       break;
+               }
+               ssleep(10);
+       } while (time_before(jiffies, timeout));
+
+       /* Check for timeout */
+       if (dd->ftlrebuildflag) {
+               dev_err(&dd->pdev->dev,
+               "Timed out waiting for FTL rebuild to complete (%d secs).\n",
+               jiffies_to_msecs(jiffies - start) / 1000);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+/*
+ * service thread to issue queued commands
+ *
+ * @data Pointer to the driver data structure.
+ *
+ * return value
+ *     0
+ */
+
+static int mtip_service_thread(void *data)
+{
+       struct driver_data *dd = (struct driver_data *)data;
+       unsigned long slot, slot_start, slot_wrap;
+       unsigned int num_cmd_slots = dd->slot_groups * 32;
+       struct mtip_port *port = dd->port;
+
+       while (1) {
+               /*
+                * the condition is to check neither an internal command is
+                * is in progress nor error handling is active
+                */
+               wait_event_interruptible(port->svc_wait, (port->flags) &&
+                       !test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) &&
+                       !test_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags));
+
+               if (kthread_should_stop())
+                       break;
+
+               set_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags);
+               if (test_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags)) {
+                       slot = 1;
+                       /* used to restrict the loop to one iteration */
+                       slot_start = num_cmd_slots;
+                       slot_wrap = 0;
+                       while (1) {
+                               slot = find_next_bit(port->cmds_to_issue,
+                                               num_cmd_slots, slot);
+                               if (slot_wrap == 1) {
+                                       if ((slot_start >= slot) ||
+                                               (slot >= num_cmd_slots))
+                                               break;
+                               }
+                               if (unlikely(slot_start == num_cmd_slots))
+                                       slot_start = slot;
+
+                               if (unlikely(slot == num_cmd_slots)) {
+                                       slot = 1;
+                                       slot_wrap = 1;
+                                       continue;
+                               }
+
+                               /* Issue the command to the hardware */
+                               mtip_issue_ncq_command(port, slot);
+
+                               /* Set the command's timeout value.*/
+                               port->commands[slot].comp_time = jiffies +
+                               msecs_to_jiffies(MTIP_NCQ_COMMAND_TIMEOUT_MS);
+
+                               clear_bit(slot, port->cmds_to_issue);
+                       }
+
+                       clear_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags);
+               } else if (test_bit(MTIP_FLAG_REBUILD_BIT, &port->flags)) {
+                       mtip_ftl_rebuild_poll(dd);
+                       clear_bit(MTIP_FLAG_REBUILD_BIT, &port->flags);
+               }
+               clear_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags);
+
+               if (test_bit(MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT, &port->flags))
+                       break;
+       }
+       return 0;
+}
+
+/*
+ * Called once for each card.
+ *
+ * @dd Pointer to the driver data structure.
+ *
+ * return value
+ *     0 on success, else an error code.
+ */
+static int mtip_hw_init(struct driver_data *dd)
+{
+       int i;
+       int rv;
+       unsigned int num_command_slots;
+
+       dd->mmio = pcim_iomap_table(dd->pdev)[MTIP_ABAR];
+
+       mtip_detect_product(dd);
+       if (dd->product_type == MTIP_PRODUCT_UNKNOWN) {
+               rv = -EIO;
+               goto out1;
+       }
+       num_command_slots = dd->slot_groups * 32;
+
+       hba_setup(dd);
+
+       tasklet_init(&dd->tasklet, mtip_tasklet, (unsigned long)dd);
+
+       dd->port = kzalloc(sizeof(struct mtip_port), GFP_KERNEL);
+       if (!dd->port) {
+               dev_err(&dd->pdev->dev,
+                       "Memory allocation: port structure\n");
+               return -ENOMEM;
+       }
+
+       /* Counting semaphore to track command slot usage */
+       sema_init(&dd->port->cmd_slot, num_command_slots - 1);
+
+       /* Spinlock to prevent concurrent issue */
+       spin_lock_init(&dd->port->cmd_issue_lock);
+
+       /* Set the port mmio base address. */
+       dd->port->mmio  = dd->mmio + PORT_OFFSET;
+       dd->port->dd    = dd;
+
+       /* Allocate memory for the command list. */
+       dd->port->command_list =
+               dmam_alloc_coherent(&dd->pdev->dev,
+                       HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2),
+                       &dd->port->command_list_dma,
+                       GFP_KERNEL);
+       if (!dd->port->command_list) {
+               dev_err(&dd->pdev->dev,
+                       "Memory allocation: command list\n");
+               rv = -ENOMEM;
+               goto out1;
+       }
+
+       /* Clear the memory we have allocated. */
+       memset(dd->port->command_list,
+               0,
+               HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2));
+
+       /* Setup the addresse of the RX FIS. */
+       dd->port->rxfis     = dd->port->command_list + HW_CMD_SLOT_SZ;
+       dd->port->rxfis_dma = dd->port->command_list_dma + HW_CMD_SLOT_SZ;
+
+       /* Setup the address of the command tables. */
+       dd->port->command_table   = dd->port->rxfis + AHCI_RX_FIS_SZ;
+       dd->port->command_tbl_dma = dd->port->rxfis_dma + AHCI_RX_FIS_SZ;
+
+       /* Setup the address of the identify data. */
+       dd->port->identify     = dd->port->command_table +
+                                       HW_CMD_TBL_AR_SZ;
+       dd->port->identify_dma = dd->port->command_tbl_dma +
+                                       HW_CMD_TBL_AR_SZ;
+
+       /* Setup the address of the sector buffer. */
+       dd->port->sector_buffer = (void *) dd->port->identify + ATA_SECT_SIZE;
+       dd->port->sector_buffer_dma = dd->port->identify_dma + ATA_SECT_SIZE;
+
+       /* Point the command headers at the command tables. */
+       for (i = 0; i < num_command_slots; i++) {
+               dd->port->commands[i].command_header =
+                                       dd->port->command_list +
+                                       (sizeof(struct mtip_cmd_hdr) * i);
+               dd->port->commands[i].command_header_dma =
+                                       dd->port->command_list_dma +
+                                       (sizeof(struct mtip_cmd_hdr) * i);
+
+               dd->port->commands[i].command =
+                       dd->port->command_table + (HW_CMD_TBL_SZ * i);
+               dd->port->commands[i].command_dma =
+                       dd->port->command_tbl_dma + (HW_CMD_TBL_SZ * i);
+
+               if (readl(dd->mmio + HOST_CAP) & HOST_CAP_64)
+                       dd->port->commands[i].command_header->ctbau =
+                       __force_bit2int cpu_to_le32(
+                       (dd->port->commands[i].command_dma >> 16) >> 16);
+               dd->port->commands[i].command_header->ctba =
+                       __force_bit2int cpu_to_le32(
+                       dd->port->commands[i].command_dma & 0xFFFFFFFF);
+
+               /*
+                * If this is not done, a bug is reported by the stock
+                * FC11 i386. Due to the fact that it has lots of kernel
+                * debugging enabled.
+                */
+               sg_init_table(dd->port->commands[i].sg, MTIP_MAX_SG);
+
+               /* Mark all commands as currently inactive.*/
+               atomic_set(&dd->port->commands[i].active, 0);
+       }
+
+       /* Setup the pointers to the extended s_active and CI registers. */
+       for (i = 0; i < dd->slot_groups; i++) {
+               dd->port->s_active[i] =
+                       dd->port->mmio + i*0x80 + PORT_SCR_ACT;
+               dd->port->cmd_issue[i] =
+                       dd->port->mmio + i*0x80 + PORT_COMMAND_ISSUE;
+               dd->port->completed[i] =
+                       dd->port->mmio + i*0x80 + PORT_SDBV;
+       }
+
+       /* Reset the HBA. */
+       if (mtip_hba_reset(dd) < 0) {
+               dev_err(&dd->pdev->dev,
+                       "Card did not reset within timeout\n");
+               rv = -EIO;
+               goto out2;
+       }
+
+       mtip_init_port(dd->port);
+       mtip_start_port(dd->port);
+
+       /* Setup the ISR and enable interrupts. */
+       rv = devm_request_irq(&dd->pdev->dev,
+                               dd->pdev->irq,
+                               mtip_irq_handler,
+                               IRQF_SHARED,
+                               dev_driver_string(&dd->pdev->dev),
+                               dd);
+
+       if (rv) {
+               dev_err(&dd->pdev->dev,
+                       "Unable to allocate IRQ %d\n", dd->pdev->irq);
+               goto out2;
+       }
+
+       /* Enable interrupts on the HBA. */
+       writel(readl(dd->mmio + HOST_CTL) | HOST_IRQ_EN,
+                                       dd->mmio + HOST_CTL);
+
+       init_timer(&dd->port->cmd_timer);
+       init_waitqueue_head(&dd->port->svc_wait);
+
+       dd->port->cmd_timer.data = (unsigned long int) dd->port;
+       dd->port->cmd_timer.function = mtip_timeout_function;
+       mod_timer(&dd->port->cmd_timer,
+               jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD));
+
+       if (mtip_get_identify(dd->port, NULL) < 0) {
+               rv = -EFAULT;
+               goto out3;
+       }
+
+       if (*(dd->port->identify + MTIP_FTL_REBUILD_OFFSET) ==
+               MTIP_FTL_REBUILD_MAGIC) {
+               set_bit(MTIP_FLAG_REBUILD_BIT, &dd->port->flags);
+               return MTIP_FTL_REBUILD_MAGIC;
+       }
+       mtip_dump_identify(dd->port);
+       return rv;
+
+out3:
+       del_timer_sync(&dd->port->cmd_timer);
+
+       /* Disable interrupts on the HBA. */
+       writel(readl(dd->mmio + HOST_CTL) & ~HOST_IRQ_EN,
+                       dd->mmio + HOST_CTL);
+
+       /*Release the IRQ. */
+       devm_free_irq(&dd->pdev->dev, dd->pdev->irq, dd);
+
+out2:
+       mtip_deinit_port(dd->port);
+
+       /* Free the command/command header memory. */
+       dmam_free_coherent(&dd->pdev->dev,
+                               HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2),
+                               dd->port->command_list,
+                               dd->port->command_list_dma);
+out1:
+       /* Free the memory allocated for the for structure. */
+       kfree(dd->port);
+
+       return rv;
+}
+
+/*
+ * Called to deinitialize an interface.
+ *
+ * @dd Pointer to the driver data structure.
+ *
+ * return value
+ *     0
+ */
+static int mtip_hw_exit(struct driver_data *dd)
+{
+       /*
+        * Send standby immediate (E0h) to the drive so that it
+        * saves its state.
+        */
+       if (atomic_read(&dd->drv_cleanup_done) != true) {
+
+               mtip_standby_immediate(dd->port);
+
+               /* de-initialize the port. */
+               mtip_deinit_port(dd->port);
+
+               /* Disable interrupts on the HBA. */
+               writel(readl(dd->mmio + HOST_CTL) & ~HOST_IRQ_EN,
+                               dd->mmio + HOST_CTL);
+       }
+
+       del_timer_sync(&dd->port->cmd_timer);
+
+       /* Release the IRQ. */
+       devm_free_irq(&dd->pdev->dev, dd->pdev->irq, dd);
+
+       /* Stop the bottom half tasklet. */
+       tasklet_kill(&dd->tasklet);
+
+       /* Free the command/command header memory. */
+       dmam_free_coherent(&dd->pdev->dev,
+                       HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2),
+                       dd->port->command_list,
+                       dd->port->command_list_dma);
+       /* Free the memory allocated for the for structure. */
+       kfree(dd->port);
+
+       return 0;
+}
+
+/*
+ * Issue a Standby Immediate command to the device.
+ *
+ * This function is called by the Block Layer just before the
+ * system powers off during a shutdown.
+ *
+ * @dd Pointer to the driver data structure.
+ *
+ * return value
+ *     0
+ */
+static int mtip_hw_shutdown(struct driver_data *dd)
+{
+       /*
+        * Send standby immediate (E0h) to the drive so that it
+        * saves its state.
+        */
+       mtip_standby_immediate(dd->port);
+
+       return 0;
+}
+
+/*
+ * Suspend function
+ *
+ * This function is called by the Block Layer just before the
+ * system hibernates.
+ *
+ * @dd Pointer to the driver data structure.
+ *
+ * return value
+ *     0       Suspend was successful
+ *     -EFAULT Suspend was not successful
+ */
+static int mtip_hw_suspend(struct driver_data *dd)
+{
+       /*
+        * Send standby immediate (E0h) to the drive
+        * so that it saves its state.
+        */
+       if (mtip_standby_immediate(dd->port) != 0) {
+               dev_err(&dd->pdev->dev,
+                       "Failed standby-immediate command\n");
+               return -EFAULT;
+       }
+
+       /* Disable interrupts on the HBA.*/
+       writel(readl(dd->mmio + HOST_CTL) & ~HOST_IRQ_EN,
+                       dd->mmio + HOST_CTL);
+       mtip_deinit_port(dd->port);
+
+       return 0;
+}
+
+/*
+ * Resume function
+ *
+ * This function is called by the Block Layer as the
+ * system resumes.
+ *
+ * @dd Pointer to the driver data structure.
+ *
+ * return value
+ *     0       Resume was successful
+ *      -EFAULT Resume was not successful
+ */
+static int mtip_hw_resume(struct driver_data *dd)
+{
+       /* Perform any needed hardware setup steps */
+       hba_setup(dd);
+
+       /* Reset the HBA */
+       if (mtip_hba_reset(dd) != 0) {
+               dev_err(&dd->pdev->dev,
+                       "Unable to reset the HBA\n");
+               return -EFAULT;
+       }
+
+       /*
+        * Enable the port, DMA engine, and FIS reception specific
+        * h/w in controller.
+        */
+       mtip_init_port(dd->port);
+       mtip_start_port(dd->port);
+
+       /* Enable interrupts on the HBA.*/
+       writel(readl(dd->mmio + HOST_CTL) | HOST_IRQ_EN,
+                       dd->mmio + HOST_CTL);
+
+       return 0;
+}
+
+/*
+ * Helper function for reusing disk name
+ * upon hot insertion.
+ */
+static int rssd_disk_name_format(char *prefix,
+                                int index,
+                                char *buf,
+                                int buflen)
+{
+       const int base = 'z' - 'a' + 1;
+       char *begin = buf + strlen(prefix);
+       char *end = buf + buflen;
+       char *p;
+       int unit;
+
+       p = end - 1;
+       *p = '\0';
+       unit = base;
+       do {
+               if (p == begin)
+                       return -EINVAL;
+               *--p = 'a' + (index % unit);
+               index = (index / unit) - 1;
+       } while (index >= 0);
+
+       memmove(begin, p, end - p);
+       memcpy(buf, prefix, strlen(prefix));
+
+       return 0;
+}
+
+/*
+ * Block layer IOCTL handler.
+ *
+ * @dev Pointer to the block_device structure.
+ * @mode ignored
+ * @cmd IOCTL command passed from the user application.
+ * @arg Argument passed from the user application.
+ *
+ * return value
+ *     0        IOCTL completed successfully.
+ *     -ENOTTY  IOCTL not supported or invalid driver data
+ *                 structure pointer.
+ */
+static int mtip_block_ioctl(struct block_device *dev,
+                           fmode_t mode,
+                           unsigned cmd,
+                           unsigned long arg)
+{
+       struct driver_data *dd = dev->bd_disk->private_data;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (!dd)
+               return -ENOTTY;
+
+       switch (cmd) {
+       case BLKFLSBUF:
+               return -ENOTTY;
+       default:
+               return mtip_hw_ioctl(dd, cmd, arg);
+       }
+}
+
+#ifdef CONFIG_COMPAT
+/*
+ * Block layer compat IOCTL handler.
+ *
+ * @dev Pointer to the block_device structure.
+ * @mode ignored
+ * @cmd IOCTL command passed from the user application.
+ * @arg Argument passed from the user application.
+ *
+ * return value
+ *     0        IOCTL completed successfully.
+ *     -ENOTTY  IOCTL not supported or invalid driver data
+ *                 structure pointer.
+ */
+static int mtip_block_compat_ioctl(struct block_device *dev,
+                           fmode_t mode,
+                           unsigned cmd,
+                           unsigned long arg)
+{
+       struct driver_data *dd = dev->bd_disk->private_data;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (!dd)
+               return -ENOTTY;
+
+       switch (cmd) {
+       case BLKFLSBUF:
+               return -ENOTTY;
+       case HDIO_DRIVE_TASKFILE: {
+               struct mtip_compat_ide_task_request_s __user *compat_req_task;
+               ide_task_request_t req_task;
+               int compat_tasksize, outtotal, ret;
+
+               compat_tasksize =
+                       sizeof(struct mtip_compat_ide_task_request_s);
+
+               compat_req_task =
+                       (struct mtip_compat_ide_task_request_s __user *) arg;
+
+               if (copy_from_user(&req_task, (void __user *) arg,
+                       compat_tasksize - (2 * sizeof(compat_long_t))))
+                       return -EFAULT;
+
+               if (get_user(req_task.out_size, &compat_req_task->out_size))
+                       return -EFAULT;
+
+               if (get_user(req_task.in_size, &compat_req_task->in_size))
+                       return -EFAULT;
+
+               outtotal = sizeof(struct mtip_compat_ide_task_request_s);
+
+               ret = exec_drive_taskfile(dd, (void __user *) arg,
+                                               &req_task, outtotal);
+
+               if (copy_to_user((void __user *) arg, &req_task,
+                               compat_tasksize -
+                               (2 * sizeof(compat_long_t))))
+                       return -EFAULT;
+
+               if (put_user(req_task.out_size, &compat_req_task->out_size))
+                       return -EFAULT;
+
+               if (put_user(req_task.in_size, &compat_req_task->in_size))
+                       return -EFAULT;
+
+               return ret;
+       }
+       default:
+               return mtip_hw_ioctl(dd, cmd, arg);
+       }
+}
+#endif
+
+/*
+ * Obtain the geometry of the device.
+ *
+ * You may think that this function is obsolete, but some applications,
+ * fdisk for example still used CHS values. This function describes the
+ * device as having 224 heads and 56 sectors per cylinder. These values are
+ * chosen so that each cylinder is aligned on a 4KB boundary. Since a
+ * partition is described in terms of a start and end cylinder this means
+ * that each partition is also 4KB aligned. Non-aligned partitions adversely
+ * affects performance.
+ *
+ * @dev Pointer to the block_device strucutre.
+ * @geo Pointer to a hd_geometry structure.
+ *
+ * return value
+ *     0       Operation completed successfully.
+ *     -ENOTTY An error occurred while reading the drive capacity.
+ */
+static int mtip_block_getgeo(struct block_device *dev,
+                               struct hd_geometry *geo)
+{
+       struct driver_data *dd = dev->bd_disk->private_data;
+       sector_t capacity;
+
+       if (!dd)
+               return -ENOTTY;
+
+       if (!(mtip_hw_get_capacity(dd, &capacity))) {
+               dev_warn(&dd->pdev->dev,
+                       "Could not get drive capacity.\n");
+               return -ENOTTY;
+       }
+
+       geo->heads = 224;
+       geo->sectors = 56;
+       sector_div(capacity, (geo->heads * geo->sectors));
+       geo->cylinders = capacity;
+       return 0;
+}
+
+/*
+ * Block device operation function.
+ *
+ * This structure contains pointers to the functions required by the block
+ * layer.
+ */
+static const struct block_device_operations mtip_block_ops = {
+       .ioctl          = mtip_block_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = mtip_block_compat_ioctl,
+#endif
+       .getgeo         = mtip_block_getgeo,
+       .owner          = THIS_MODULE
+};
+
+/*
+ * Block layer make request function.
+ *
+ * This function is called by the kernel to process a BIO for
+ * the P320 device.
+ *
+ * @queue Pointer to the request queue. Unused other than to obtain
+ *              the driver data structure.
+ * @bio   Pointer to the BIO.
+ *
+ */
+static void mtip_make_request(struct request_queue *queue, struct bio *bio)
+{
+       struct driver_data *dd = queue->queuedata;
+       struct scatterlist *sg;
+       struct bio_vec *bvec;
+       int nents = 0;
+       int tag = 0;
+
+       if (unlikely(!bio_has_data(bio))) {
+               blk_queue_flush(queue, 0);
+               bio_endio(bio, 0);
+               return;
+       }
+
+       sg = mtip_hw_get_scatterlist(dd, &tag);
+       if (likely(sg != NULL)) {
+               blk_queue_bounce(queue, &bio);
+
+               if (unlikely((bio)->bi_vcnt > MTIP_MAX_SG)) {
+                       dev_warn(&dd->pdev->dev,
+                               "Maximum number of SGL entries exceeded");
+                       bio_io_error(bio);
+                       mtip_hw_release_scatterlist(dd, tag);
+                       return;
+               }
+
+               /* Create the scatter list for this bio. */
+               bio_for_each_segment(bvec, bio, nents) {
+                       sg_set_page(&sg[nents],
+                                       bvec->bv_page,
+                                       bvec->bv_len,
+                                       bvec->bv_offset);
+               }
+
+               /* Issue the read/write. */
+               mtip_hw_submit_io(dd,
+                               bio->bi_sector,
+                               bio_sectors(bio),
+                               nents,
+                               tag,
+                               bio_endio,
+                               bio,
+                               bio->bi_rw & REQ_FUA,
+                               bio_data_dir(bio));
+       } else
+               bio_io_error(bio);
+}
+
+/*
+ * Block layer initialization function.
+ *
+ * This function is called once by the PCI layer for each P320
+ * device that is connected to the system.
+ *
+ * @dd Pointer to the driver data structure.
+ *
+ * return value
+ *     0 on success else an error code.
+ */
+static int mtip_block_initialize(struct driver_data *dd)
+{
+       int rv = 0, wait_for_rebuild = 0;
+       sector_t capacity;
+       unsigned int index = 0;
+       struct kobject *kobj;
+       unsigned char thd_name[16];
+
+       if (dd->disk)
+               goto skip_create_disk; /* hw init done, before rebuild */
+
+       /* Initialize the protocol layer. */
+       wait_for_rebuild = mtip_hw_init(dd);
+       if (wait_for_rebuild < 0) {
+               dev_err(&dd->pdev->dev,
+                       "Protocol layer initialization failed\n");
+               rv = -EINVAL;
+               goto protocol_init_error;
+       }
+
+       dd->disk = alloc_disk(MTIP_MAX_MINORS);
+       if (dd->disk  == NULL) {
+               dev_err(&dd->pdev->dev,
+                       "Unable to allocate gendisk structure\n");
+               rv = -EINVAL;
+               goto alloc_disk_error;
+       }
+
+       /* Generate the disk name, implemented same as in sd.c */
+       do {
+               if (!ida_pre_get(&rssd_index_ida, GFP_KERNEL))
+                       goto ida_get_error;
+
+               spin_lock(&rssd_index_lock);
+               rv = ida_get_new(&rssd_index_ida, &index);
+               spin_unlock(&rssd_index_lock);
+       } while (rv == -EAGAIN);
+
+       if (rv)
+               goto ida_get_error;
+
+       rv = rssd_disk_name_format("rssd",
+                               index,
+                               dd->disk->disk_name,
+                               DISK_NAME_LEN);
+       if (rv)
+               goto disk_index_error;
+
+       dd->disk->driverfs_dev  = &dd->pdev->dev;
+       dd->disk->major         = dd->major;
+       dd->disk->first_minor   = dd->instance * MTIP_MAX_MINORS;
+       dd->disk->fops          = &mtip_block_ops;
+       dd->disk->private_data  = dd;
+       dd->index               = index;
+
+       /*
+        * if rebuild pending, start the service thread, and delay the block
+        * queue creation and add_disk()
+        */
+       if (wait_for_rebuild == MTIP_FTL_REBUILD_MAGIC)
+               goto start_service_thread;
+
+skip_create_disk:
+       /* Allocate the request queue. */
+       dd->queue = blk_alloc_queue(GFP_KERNEL);
+       if (dd->queue == NULL) {
+               dev_err(&dd->pdev->dev,
+                       "Unable to allocate request queue\n");
+               rv = -ENOMEM;
+               goto block_queue_alloc_init_error;
+       }
+
+       /* Attach our request function to the request queue. */
+       blk_queue_make_request(dd->queue, mtip_make_request);
+
+       dd->disk->queue         = dd->queue;
+       dd->queue->queuedata    = dd;
+
+       /* Set device limits. */
+       set_bit(QUEUE_FLAG_NONROT, &dd->queue->queue_flags);
+       blk_queue_max_segments(dd->queue, MTIP_MAX_SG);
+       blk_queue_physical_block_size(dd->queue, 4096);
+       blk_queue_io_min(dd->queue, 4096);
+       blk_queue_flush(dd->queue, 0);
+
+       /* Set the capacity of the device in 512 byte sectors. */
+       if (!(mtip_hw_get_capacity(dd, &capacity))) {
+               dev_warn(&dd->pdev->dev,
+                       "Could not read drive capacity\n");
+               rv = -EIO;
+               goto read_capacity_error;
+       }
+       set_capacity(dd->disk, capacity);
+
+       /* Enable the block device and add it to /dev */
+       add_disk(dd->disk);
+
+       /*
+        * Now that the disk is active, initialize any sysfs attributes
+        * managed by the protocol layer.
+        */
+       kobj = kobject_get(&disk_to_dev(dd->disk)->kobj);
+       if (kobj) {
+               mtip_hw_sysfs_init(dd, kobj);
+               kobject_put(kobj);
+       }
+
+       if (dd->mtip_svc_handler)
+               return rv; /* service thread created for handling rebuild */
+
+start_service_thread:
+       sprintf(thd_name, "mtip_svc_thd_%02d", index);
+
+       dd->mtip_svc_handler = kthread_run(mtip_service_thread,
+                                               dd, thd_name);
+
+       if (IS_ERR(dd->mtip_svc_handler)) {
+               printk(KERN_ERR "mtip32xx: service thread failed to start\n");
+               dd->mtip_svc_handler = NULL;
+               rv = -EFAULT;
+               goto kthread_run_error;
+       }
+
+       return rv;
+
+kthread_run_error:
+       /* Delete our gendisk. This also removes the device from /dev */
+       del_gendisk(dd->disk);
+
+read_capacity_error:
+       blk_cleanup_queue(dd->queue);
+
+block_queue_alloc_init_error:
+disk_index_error:
+       spin_lock(&rssd_index_lock);
+       ida_remove(&rssd_index_ida, index);
+       spin_unlock(&rssd_index_lock);
+
+ida_get_error:
+       put_disk(dd->disk);
+
+alloc_disk_error:
+       mtip_hw_exit(dd); /* De-initialize the protocol layer. */
+
+protocol_init_error:
+       return rv;
+}
+
+/*
+ * Block layer deinitialization function.
+ *
+ * Called by the PCI layer as each P320 device is removed.
+ *
+ * @dd Pointer to the driver data structure.
+ *
+ * return value
+ *     0
+ */
+static int mtip_block_remove(struct driver_data *dd)
+{
+       struct kobject *kobj;
+
+       if (dd->mtip_svc_handler) {
+               set_bit(MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT, &dd->port->flags);
+               wake_up_interruptible(&dd->port->svc_wait);
+               kthread_stop(dd->mtip_svc_handler);
+       }
+
+       /* Clean up the sysfs attributes managed by the protocol layer. */
+       kobj = kobject_get(&disk_to_dev(dd->disk)->kobj);
+       if (kobj) {
+               mtip_hw_sysfs_exit(dd, kobj);
+               kobject_put(kobj);
+       }
+
+       /*
+        * Delete our gendisk structure. This also removes the device
+        * from /dev
+        */
+       del_gendisk(dd->disk);
+       blk_cleanup_queue(dd->queue);
+       dd->disk  = NULL;
+       dd->queue = NULL;
+
+       /* De-initialize the protocol layer. */
+       mtip_hw_exit(dd);
+
+       return 0;
+}
+
+/*
+ * Function called by the PCI layer when just before the
+ * machine shuts down.
+ *
+ * If a protocol layer shutdown function is present it will be called
+ * by this function.
+ *
+ * @dd Pointer to the driver data structure.
+ *
+ * return value
+ *     0
+ */
+static int mtip_block_shutdown(struct driver_data *dd)
+{
+       dev_info(&dd->pdev->dev,
+               "Shutting down %s ...\n", dd->disk->disk_name);
+
+       /* Delete our gendisk structure, and cleanup the blk queue. */
+       del_gendisk(dd->disk);
+       blk_cleanup_queue(dd->queue);
+       dd->disk  = NULL;
+       dd->queue = NULL;
+
+       mtip_hw_shutdown(dd);
+       return 0;
+}
+
+static int mtip_block_suspend(struct driver_data *dd)
+{
+       dev_info(&dd->pdev->dev,
+               "Suspending %s ...\n", dd->disk->disk_name);
+       mtip_hw_suspend(dd);
+       return 0;
+}
+
+static int mtip_block_resume(struct driver_data *dd)
+{
+       dev_info(&dd->pdev->dev, "Resuming %s ...\n",
+               dd->disk->disk_name);
+       mtip_hw_resume(dd);
+       return 0;
+}
+
+/*
+ * Called for each supported PCI device detected.
+ *
+ * This function allocates the private data structure, enables the
+ * PCI device and then calls the block layer initialization function.
+ *
+ * return value
+ *     0 on success else an error code.
+ */
+static int mtip_pci_probe(struct pci_dev *pdev,
+                       const struct pci_device_id *ent)
+{
+       int rv = 0;
+       struct driver_data *dd = NULL;
+
+       /* Allocate memory for this devices private data. */
+       dd = kzalloc(sizeof(struct driver_data), GFP_KERNEL);
+       if (dd == NULL) {
+               dev_err(&pdev->dev,
+                       "Unable to allocate memory for driver data\n");
+               return -ENOMEM;
+       }
+
+       /* Set the atomic variable as 1 in case of SRSI */
+       atomic_set(&dd->drv_cleanup_done, true);
+
+       atomic_set(&dd->resumeflag, false);
+
+       /* Attach the private data to this PCI device.  */
+       pci_set_drvdata(pdev, dd);
+
+       rv = pcim_enable_device(pdev);
+       if (rv < 0) {
+               dev_err(&pdev->dev, "Unable to enable device\n");
+               goto iomap_err;
+       }
+
+       /* Map BAR5 to memory. */
+       rv = pcim_iomap_regions(pdev, 1 << MTIP_ABAR, MTIP_DRV_NAME);
+       if (rv < 0) {
+               dev_err(&pdev->dev, "Unable to map regions\n");
+               goto iomap_err;
+       }
+
+       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+               rv = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+
+               if (rv) {
+                       rv = pci_set_consistent_dma_mask(pdev,
+                                               DMA_BIT_MASK(32));
+                       if (rv) {
+                               dev_warn(&pdev->dev,
+                                       "64-bit DMA enable failed\n");
+                               goto setmask_err;
+                       }
+               }
+       }
+
+       pci_set_master(pdev);
+
+       if (pci_enable_msi(pdev)) {
+               dev_warn(&pdev->dev,
+                       "Unable to enable MSI interrupt.\n");
+               goto block_initialize_err;
+       }
+
+       /* Copy the info we may need later into the private data structure. */
+       dd->major       = mtip_major;
+       dd->instance    = instance;
+       dd->pdev        = pdev;
+
+       /* Initialize the block layer. */
+       rv = mtip_block_initialize(dd);
+       if (rv < 0) {
+               dev_err(&pdev->dev,
+                       "Unable to initialize block layer\n");
+               goto block_initialize_err;
+       }
+
+       /*
+        * Increment the instance count so that each device has a unique
+        * instance number.
+        */
+       instance++;
+
+       goto done;
+
+block_initialize_err:
+       pci_disable_msi(pdev);
+
+setmask_err:
+       pcim_iounmap_regions(pdev, 1 << MTIP_ABAR);
+
+iomap_err:
+       kfree(dd);
+       pci_set_drvdata(pdev, NULL);
+       return rv;
+done:
+       /* Set the atomic variable as 0 in case of SRSI */
+       atomic_set(&dd->drv_cleanup_done, true);
+
+       return rv;
+}
+
+/*
+ * Called for each probed device when the device is removed or the
+ * driver is unloaded.
+ *
+ * return value
+ *     None
+ */
+static void mtip_pci_remove(struct pci_dev *pdev)
+{
+       struct driver_data *dd = pci_get_drvdata(pdev);
+       int counter = 0;
+
+       if (mtip_check_surprise_removal(pdev)) {
+               while (atomic_read(&dd->drv_cleanup_done) == false) {
+                       counter++;
+                       msleep(20);
+                       if (counter == 10) {
+                               /* Cleanup the outstanding commands */
+                               mtip_command_cleanup(dd);
+                               break;
+                       }
+               }
+       }
+       /* Set the atomic variable as 1 in case of SRSI */
+       atomic_set(&dd->drv_cleanup_done, true);
+
+       /* Clean up the block layer. */
+       mtip_block_remove(dd);
+
+       pci_disable_msi(pdev);
+
+       kfree(dd);
+       pcim_iounmap_regions(pdev, 1 << MTIP_ABAR);
+}
+
+/*
+ * Called for each probed device when the device is suspended.
+ *
+ * return value
+ *     0  Success
+ *     <0 Error
+ */
+static int mtip_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+       int rv = 0;
+       struct driver_data *dd = pci_get_drvdata(pdev);
+
+       if (!dd) {
+               dev_err(&pdev->dev,
+                       "Driver private datastructure is NULL\n");
+               return -EFAULT;
+       }
+
+       atomic_set(&dd->resumeflag, true);
+
+       /* Disable ports & interrupts then send standby immediate */
+       rv = mtip_block_suspend(dd);
+       if (rv < 0) {
+               dev_err(&pdev->dev,
+                       "Failed to suspend controller\n");
+               return rv;
+       }
+
+       /*
+        * Save the pci config space to pdev structure &
+        * disable the device
+        */
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+
+       /* Move to Low power state*/
+       pci_set_power_state(pdev, PCI_D3hot);
+
+       return rv;
+}
+
+/*
+ * Called for each probed device when the device is resumed.
+ *
+ * return value
+ *      0  Success
+ *      <0 Error
+ */
+static int mtip_pci_resume(struct pci_dev *pdev)
+{
+       int rv = 0;
+       struct driver_data *dd;
+
+       dd = pci_get_drvdata(pdev);
+       if (!dd) {
+               dev_err(&pdev->dev,
+                       "Driver private datastructure is NULL\n");
+               return -EFAULT;
+       }
+
+       /* Move the device to active State */
+       pci_set_power_state(pdev, PCI_D0);
+
+       /* Restore PCI configuration space */
+       pci_restore_state(pdev);
+
+       /* Enable the PCI device*/
+       rv = pcim_enable_device(pdev);
+       if (rv < 0) {
+               dev_err(&pdev->dev,
+                       "Failed to enable card during resume\n");
+               goto err;
+       }
+       pci_set_master(pdev);
+
+       /*
+        * Calls hbaReset, initPort, & startPort function
+        * then enables interrupts
+        */
+       rv = mtip_block_resume(dd);
+       if (rv < 0)
+               dev_err(&pdev->dev, "Unable to resume\n");
+
+err:
+       atomic_set(&dd->resumeflag, false);
+
+       return rv;
+}
+
+/*
+ * Shutdown routine
+ *
+ * return value
+ *      None
+ */
+static void mtip_pci_shutdown(struct pci_dev *pdev)
+{
+       struct driver_data *dd = pci_get_drvdata(pdev);
+       if (dd)
+               mtip_block_shutdown(dd);
+}
+
+/* Table of device ids supported by this driver. */
+static DEFINE_PCI_DEVICE_TABLE(mtip_pci_tbl) = {
+       {  PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320_DEVICE_ID) },
+       { 0 }
+};
+
+/* Structure that describes the PCI driver functions. */
+static struct pci_driver mtip_pci_driver = {
+       .name                   = MTIP_DRV_NAME,
+       .id_table               = mtip_pci_tbl,
+       .probe                  = mtip_pci_probe,
+       .remove                 = mtip_pci_remove,
+       .suspend                = mtip_pci_suspend,
+       .resume                 = mtip_pci_resume,
+       .shutdown               = mtip_pci_shutdown,
+};
+
+MODULE_DEVICE_TABLE(pci, mtip_pci_tbl);
+
+/*
+ * Module initialization function.
+ *
+ * Called once when the module is loaded. This function allocates a major
+ * block device number to the Cyclone devices and registers the PCI layer
+ * of the driver.
+ *
+ * Return value
+ *      0 on success else error code.
+ */
+static int __init mtip_init(void)
+{
+       printk(KERN_INFO MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n");
+
+       /* Allocate a major block device number to use with this driver. */
+       mtip_major = register_blkdev(0, MTIP_DRV_NAME);
+       if (mtip_major < 0) {
+               printk(KERN_ERR "Unable to register block device (%d)\n",
+               mtip_major);
+               return -EBUSY;
+       }
+
+       /* Register our PCI operations. */
+       return pci_register_driver(&mtip_pci_driver);
+}
+
+/*
+ * Module de-initialization function.
+ *
+ * Called once when the module is unloaded. This function deallocates
+ * the major block device number allocated by mtip_init() and
+ * unregisters the PCI layer of the driver.
+ *
+ * Return value
+ *      none
+ */
+static void __exit mtip_exit(void)
+{
+       /* Release the allocated major block device number. */
+       unregister_blkdev(mtip_major, MTIP_DRV_NAME);
+
+       /* Unregister the PCI driver. */
+       pci_unregister_driver(&mtip_pci_driver);
+}
+
+MODULE_AUTHOR("Micron Technology, Inc");
+MODULE_DESCRIPTION("Micron RealSSD PCIe Block Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MTIP_DRV_VERSION);
+
+module_init(mtip_init);
+module_exit(mtip_exit);
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h
new file mode 100644 (file)
index 0000000..723d7c4
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * mtip32xx.h - Header file for the P320 SSD Block Driver
+ *   Copyright (C) 2011 Micron Technology, Inc.
+ *
+ * Portions of this code were derived from works subjected to the
+ * following copyright:
+ *    Copyright (C) 2009 Integrated Device Technology, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MTIP32XX_H__
+#define __MTIP32XX_H__
+
+#include <linux/spinlock.h>
+#include <linux/rwsem.h>
+#include <linux/ata.h>
+#include <linux/interrupt.h>
+#include <linux/genhd.h>
+#include <linux/version.h>
+
+/* Offset of Subsystem Device ID in pci confoguration space */
+#define PCI_SUBSYSTEM_DEVICEID 0x2E
+
+/* offset of Device Control register in PCIe extended capabilites space */
+#define PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET  0x48
+
+/* # of times to retry timed out IOs */
+#define MTIP_MAX_RETRIES       5
+
+/* Various timeout values in ms */
+#define MTIP_NCQ_COMMAND_TIMEOUT_MS       5000
+#define MTIP_IOCTL_COMMAND_TIMEOUT_MS     5000
+#define MTIP_INTERNAL_COMMAND_TIMEOUT_MS  5000
+
+/* check for timeouts every 500ms */
+#define MTIP_TIMEOUT_CHECK_PERIOD      500
+
+/* ftl rebuild */
+#define MTIP_FTL_REBUILD_OFFSET                142
+#define MTIP_FTL_REBUILD_MAGIC         0xED51
+#define MTIP_FTL_REBUILD_TIMEOUT_MS    2400000
+
+/* Macro to extract the tag bit number from a tag value. */
+#define MTIP_TAG_BIT(tag)      (tag & 0x1F)
+
+/*
+ * Macro to extract the tag index from a tag value. The index
+ * is used to access the correct s_active/Command Issue register based
+ * on the tag value.
+ */
+#define MTIP_TAG_INDEX(tag)    (tag >> 5)
+
+/*
+ * Maximum number of scatter gather entries
+ * a single command may have.
+ */
+#define MTIP_MAX_SG            128
+
+/*
+ * Maximum number of slot groups (Command Issue & s_active registers)
+ * NOTE: This is the driver maximum; check dd->slot_groups for actual value.
+ */
+#define MTIP_MAX_SLOT_GROUPS   8
+
+/* Internal command tag. */
+#define MTIP_TAG_INTERNAL      0
+
+/* Micron Vendor ID & P320x SSD Device ID */
+#define PCI_VENDOR_ID_MICRON    0x1344
+#define P320_DEVICE_ID         0x5150
+
+/* Driver name and version strings */
+#define MTIP_DRV_NAME          "mtip32xx"
+#define MTIP_DRV_VERSION       "1.2.6os3"
+
+/* Maximum number of minor device numbers per device. */
+#define MTIP_MAX_MINORS                16
+
+/* Maximum number of supported command slots. */
+#define MTIP_MAX_COMMAND_SLOTS (MTIP_MAX_SLOT_GROUPS * 32)
+
+/*
+ * Per-tag bitfield size in longs.
+ * Linux bit manipulation functions
+ * (i.e. test_and_set_bit, find_next_zero_bit)
+ * manipulate memory in longs, so we try to make the math work.
+ * take the slot groups and find the number of longs, rounding up.
+ * Careful! i386 and x86_64 use different size longs!
+ */
+#define U32_PER_LONG   (sizeof(long) / sizeof(u32))
+#define SLOTBITS_IN_LONGS ((MTIP_MAX_SLOT_GROUPS + \
+                                       (U32_PER_LONG-1))/U32_PER_LONG)
+
+/* BAR number used to access the HBA registers. */
+#define MTIP_ABAR              5
+
+/* Forced Unit Access Bit */
+#define FUA_BIT                        0x80
+
+#ifdef DEBUG
+ #define dbg_printk(format, arg...)    \
+       printk(pr_fmt(format), ##arg);
+#else
+ #define dbg_printk(format, arg...)
+#endif
+
+#define __force_bit2int (unsigned int __force)
+
+/* below are bit numbers in 'flags' defined in mtip_port */
+#define MTIP_FLAG_IC_ACTIVE_BIT                        0
+#define MTIP_FLAG_EH_ACTIVE_BIT                        1
+#define MTIP_FLAG_SVC_THD_ACTIVE_BIT           2
+#define MTIP_FLAG_ISSUE_CMDS_BIT               4
+#define MTIP_FLAG_REBUILD_BIT                  5
+#define MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT      8
+
+/* Register Frame Information Structure (FIS), host to device. */
+struct host_to_dev_fis {
+       /*
+        * FIS type.
+        * - 27h Register FIS, host to device.
+        * - 34h Register FIS, device to host.
+        * - 39h DMA Activate FIS, device to host.
+        * - 41h DMA Setup FIS, bi-directional.
+        * - 46h Data FIS, bi-directional.
+        * - 58h BIST Activate FIS, bi-directional.
+        * - 5Fh PIO Setup FIS, device to host.
+        * - A1h Set Device Bits FIS, device to host.
+        */
+       unsigned char type;
+       unsigned char opts;
+       unsigned char command;
+       unsigned char features;
+
+       union {
+               unsigned char lba_low;
+               unsigned char sector;
+       };
+       union {
+               unsigned char lba_mid;
+               unsigned char cyl_low;
+       };
+       union {
+               unsigned char lba_hi;
+               unsigned char cyl_hi;
+       };
+       union {
+               unsigned char device;
+               unsigned char head;
+       };
+
+       union {
+               unsigned char lba_low_ex;
+               unsigned char sector_ex;
+       };
+       union {
+               unsigned char lba_mid_ex;
+               unsigned char cyl_low_ex;
+       };
+       union {
+               unsigned char lba_hi_ex;
+               unsigned char cyl_hi_ex;
+       };
+       unsigned char features_ex;
+
+       unsigned char sect_count;
+       unsigned char sect_cnt_ex;
+       unsigned char res2;
+       unsigned char control;
+
+       unsigned int res3;
+};
+
+/* Command header structure. */
+struct mtip_cmd_hdr {
+       /*
+        * Command options.
+        * - Bits 31:16 Number of PRD entries.
+        * - Bits 15:8 Unused in this implementation.
+        * - Bit 7 Prefetch bit, informs the drive to prefetch PRD entries.
+        * - Bit 6 Write bit, should be set when writing data to the device.
+        * - Bit 5 Unused in this implementation.
+        * - Bits 4:0 Length of the command FIS in DWords (DWord = 4 bytes).
+        */
+       unsigned int opts;
+       /* This field is unsed when using NCQ. */
+       union {
+               unsigned int byte_count;
+               unsigned int status;
+       };
+       /*
+        * Lower 32 bits of the command table address associated with this
+        * header. The command table addresses must be 128 byte aligned.
+        */
+       unsigned int ctba;
+       /*
+        * If 64 bit addressing is used this field is the upper 32 bits
+        * of the command table address associated with this command.
+        */
+       unsigned int ctbau;
+       /* Reserved and unused. */
+       unsigned int res[4];
+};
+
+/* Command scatter gather structure (PRD). */
+struct mtip_cmd_sg {
+       /*
+        * Low 32 bits of the data buffer address. For P320 this
+        * address must be 8 byte aligned signified by bits 2:0 being
+        * set to 0.
+        */
+       unsigned int dba;
+       /*
+        * When 64 bit addressing is used this field is the upper
+        * 32 bits of the data buffer address.
+        */
+       unsigned int dba_upper;
+       /* Unused. */
+       unsigned int reserved;
+       /*
+        * Bit 31: interrupt when this data block has been transferred.
+        * Bits 30..22: reserved
+        * Bits 21..0: byte count (minus 1).  For P320 the byte count must be
+        * 8 byte aligned signified by bits 2:0 being set to 1.
+        */
+       unsigned int info;
+};
+struct mtip_port;
+
+/* Structure used to describe a command. */
+struct mtip_cmd {
+
+       struct mtip_cmd_hdr *command_header; /* ptr to command header entry */
+
+       dma_addr_t command_header_dma; /* corresponding physical address */
+
+       void *command; /* ptr to command table entry */
+
+       dma_addr_t command_dma; /* corresponding physical address */
+
+       void *comp_data; /* data passed to completion function comp_func() */
+       /*
+        * Completion function called by the ISR upon completion of
+        * a command.
+        */
+       void (*comp_func)(struct mtip_port *port,
+                               int tag,
+                               void *data,
+                               int status);
+       /* Additional callback function that may be called by comp_func() */
+       void (*async_callback)(void *data, int status);
+
+       void *async_data; /* Addl. data passed to async_callback() */
+
+       int scatter_ents; /* Number of scatter list entries used */
+
+       struct scatterlist sg[MTIP_MAX_SG]; /* Scatter list entries */
+
+       int retries; /* The number of retries left for this command. */
+
+       int direction; /* Data transfer direction */
+
+       unsigned long comp_time; /* command completion time, in jiffies */
+
+       atomic_t active; /* declares if this command sent to the drive. */
+};
+
+/* Structure used to describe a port. */
+struct mtip_port {
+       /* Pointer back to the driver data for this port. */
+       struct driver_data *dd;
+       /*
+        * Used to determine if the data pointed to by the
+        * identify field is valid.
+        */
+       unsigned long identify_valid;
+       /* Base address of the memory mapped IO for the port. */
+       void __iomem *mmio;
+       /* Array of pointers to the memory mapped s_active registers. */
+       void __iomem *s_active[MTIP_MAX_SLOT_GROUPS];
+       /* Array of pointers to the memory mapped completed registers. */
+       void __iomem *completed[MTIP_MAX_SLOT_GROUPS];
+       /* Array of pointers to the memory mapped Command Issue registers. */
+       void __iomem *cmd_issue[MTIP_MAX_SLOT_GROUPS];
+       /*
+        * Pointer to the beginning of the command header memory as used
+        * by the driver.
+        */
+       void *command_list;
+       /*
+        * Pointer to the beginning of the command header memory as used
+        * by the DMA.
+        */
+       dma_addr_t command_list_dma;
+       /*
+        * Pointer to the beginning of the RX FIS memory as used
+        * by the driver.
+        */
+       void *rxfis;
+       /*
+        * Pointer to the beginning of the RX FIS memory as used
+        * by the DMA.
+        */
+       dma_addr_t rxfis_dma;
+       /*
+        * Pointer to the beginning of the command table memory as used
+        * by the driver.
+        */
+       void *command_table;
+       /*
+        * Pointer to the beginning of the command table memory as used
+        * by the DMA.
+        */
+       dma_addr_t command_tbl_dma;
+       /*
+        * Pointer to the beginning of the identify data memory as used
+        * by the driver.
+        */
+       u16 *identify;
+       /*
+        * Pointer to the beginning of the identify data memory as used
+        * by the DMA.
+        */
+       dma_addr_t identify_dma;
+       /*
+        * Pointer to the beginning of a sector buffer that is used
+        * by the driver when issuing internal commands.
+        */
+       u16 *sector_buffer;
+       /*
+        * Pointer to the beginning of a sector buffer that is used
+        * by the DMA when the driver issues internal commands.
+        */
+       dma_addr_t sector_buffer_dma;
+       /*
+        * Bit significant, used to determine if a command slot has
+        * been allocated. i.e. the slot is in use.  Bits are cleared
+        * when the command slot and all associated data structures
+        * are no longer needed.
+        */
+       unsigned long allocated[SLOTBITS_IN_LONGS];
+       /*
+        * used to queue commands when an internal command is in progress
+        * or error handling is active
+        */
+       unsigned long cmds_to_issue[SLOTBITS_IN_LONGS];
+       /*
+        * Array of command slots. Structure includes pointers to the
+        * command header and command table, and completion function and data
+        * pointers.
+        */
+       struct mtip_cmd commands[MTIP_MAX_COMMAND_SLOTS];
+       /* Used by mtip_service_thread to wait for an event */
+       wait_queue_head_t svc_wait;
+       /*
+        * indicates the state of the port. Also, helps the service thread
+        * to determine its action on wake up.
+        */
+       unsigned long flags;
+       /*
+        * Timer used to complete commands that have been active for too long.
+        */
+       struct timer_list cmd_timer;
+       /*
+        * Semaphore used to block threads if there are no
+        * command slots available.
+        */
+       struct semaphore cmd_slot;
+       /* Spinlock for working around command-issue bug. */
+       spinlock_t cmd_issue_lock;
+};
+
+/*
+ * Driver private data structure.
+ *
+ * One structure is allocated per probed device.
+ */
+struct driver_data {
+       void __iomem *mmio; /* Base address of the HBA registers. */
+
+       int major; /* Major device number. */
+
+       int instance; /* Instance number. First device probed is 0, ... */
+
+       struct gendisk *disk; /* Pointer to our gendisk structure. */
+
+       struct pci_dev *pdev; /* Pointer to the PCI device structure. */
+
+       struct request_queue *queue; /* Our request queue. */
+
+       struct mtip_port *port; /* Pointer to the port data structure. */
+
+       /* Tasklet used to process the bottom half of the ISR. */
+       struct tasklet_struct tasklet;
+
+       unsigned product_type; /* magic value declaring the product type */
+
+       unsigned slot_groups; /* number of slot groups the product supports */
+
+       atomic_t drv_cleanup_done; /* Atomic variable for SRSI */
+
+       unsigned long index; /* Index to determine the disk name */
+
+       unsigned int ftlrebuildflag; /* FTL rebuild flag */
+
+       atomic_t resumeflag; /* Atomic variable to track suspend/resume */
+
+       atomic_t eh_active; /* Flag for error handling tracking */
+
+       struct task_struct *mtip_svc_handler; /* task_struct of svc thd */
+};
+
+#endif
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
new file mode 100644 (file)
index 0000000..c1dc4d8
--- /dev/null
@@ -0,0 +1,1739 @@
+/*
+ * NVM Express device driver
+ * Copyright (c) 2011, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/nvme.h>
+#include <linux/bio.h>
+#include <linux/bitops.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kdev_t.h>
+#include <linux/kthread.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/poison.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+#define NVME_Q_DEPTH 1024
+#define SQ_SIZE(depth)         (depth * sizeof(struct nvme_command))
+#define CQ_SIZE(depth)         (depth * sizeof(struct nvme_completion))
+#define NVME_MINORS 64
+#define NVME_IO_TIMEOUT        (5 * HZ)
+#define ADMIN_TIMEOUT  (60 * HZ)
+
+static int nvme_major;
+module_param(nvme_major, int, 0);
+
+static int use_threaded_interrupts;
+module_param(use_threaded_interrupts, int, 0);
+
+static DEFINE_SPINLOCK(dev_list_lock);
+static LIST_HEAD(dev_list);
+static struct task_struct *nvme_thread;
+
+/*
+ * Represents an NVM Express device.  Each nvme_dev is a PCI function.
+ */
+struct nvme_dev {
+       struct list_head node;
+       struct nvme_queue **queues;
+       u32 __iomem *dbs;
+       struct pci_dev *pci_dev;
+       struct dma_pool *prp_page_pool;
+       struct dma_pool *prp_small_pool;
+       int instance;
+       int queue_count;
+       int db_stride;
+       u32 ctrl_config;
+       struct msix_entry *entry;
+       struct nvme_bar __iomem *bar;
+       struct list_head namespaces;
+       char serial[20];
+       char model[40];
+       char firmware_rev[8];
+};
+
+/*
+ * An NVM Express namespace is equivalent to a SCSI LUN
+ */
+struct nvme_ns {
+       struct list_head list;
+
+       struct nvme_dev *dev;
+       struct request_queue *queue;
+       struct gendisk *disk;
+
+       int ns_id;
+       int lba_shift;
+};
+
+/*
+ * An NVM Express queue.  Each device has at least two (one for admin
+ * commands and one for I/O commands).
+ */
+struct nvme_queue {
+       struct device *q_dmadev;
+       struct nvme_dev *dev;
+       spinlock_t q_lock;
+       struct nvme_command *sq_cmds;
+       volatile struct nvme_completion *cqes;
+       dma_addr_t sq_dma_addr;
+       dma_addr_t cq_dma_addr;
+       wait_queue_head_t sq_full;
+       wait_queue_t sq_cong_wait;
+       struct bio_list sq_cong;
+       u32 __iomem *q_db;
+       u16 q_depth;
+       u16 cq_vector;
+       u16 sq_head;
+       u16 sq_tail;
+       u16 cq_head;
+       u16 cq_phase;
+       unsigned long cmdid_data[];
+};
+
+/*
+ * Check we didin't inadvertently grow the command struct
+ */
+static inline void _nvme_check_size(void)
+{
+       BUILD_BUG_ON(sizeof(struct nvme_rw_command) != 64);
+       BUILD_BUG_ON(sizeof(struct nvme_create_cq) != 64);
+       BUILD_BUG_ON(sizeof(struct nvme_create_sq) != 64);
+       BUILD_BUG_ON(sizeof(struct nvme_delete_queue) != 64);
+       BUILD_BUG_ON(sizeof(struct nvme_features) != 64);
+       BUILD_BUG_ON(sizeof(struct nvme_command) != 64);
+       BUILD_BUG_ON(sizeof(struct nvme_id_ctrl) != 4096);
+       BUILD_BUG_ON(sizeof(struct nvme_id_ns) != 4096);
+       BUILD_BUG_ON(sizeof(struct nvme_lba_range_type) != 64);
+}
+
+typedef void (*nvme_completion_fn)(struct nvme_dev *, void *,
+                                               struct nvme_completion *);
+
+struct nvme_cmd_info {
+       nvme_completion_fn fn;
+       void *ctx;
+       unsigned long timeout;
+};
+
+static struct nvme_cmd_info *nvme_cmd_info(struct nvme_queue *nvmeq)
+{
+       return (void *)&nvmeq->cmdid_data[BITS_TO_LONGS(nvmeq->q_depth)];
+}
+
+/**
+ * alloc_cmdid() - Allocate a Command ID
+ * @nvmeq: The queue that will be used for this command
+ * @ctx: A pointer that will be passed to the handler
+ * @handler: The function to call on completion
+ *
+ * Allocate a Command ID for a queue.  The data passed in will
+ * be passed to the completion handler.  This is implemented by using
+ * the bottom two bits of the ctx pointer to store the handler ID.
+ * Passing in a pointer that's not 4-byte aligned will cause a BUG.
+ * We can change this if it becomes a problem.
+ *
+ * May be called with local interrupts disabled and the q_lock held,
+ * or with interrupts enabled and no locks held.
+ */
+static int alloc_cmdid(struct nvme_queue *nvmeq, void *ctx,
+                               nvme_completion_fn handler, unsigned timeout)
+{
+       int depth = nvmeq->q_depth - 1;
+       struct nvme_cmd_info *info = nvme_cmd_info(nvmeq);
+       int cmdid;
+
+       do {
+               cmdid = find_first_zero_bit(nvmeq->cmdid_data, depth);
+               if (cmdid >= depth)
+                       return -EBUSY;
+       } while (test_and_set_bit(cmdid, nvmeq->cmdid_data));
+
+       info[cmdid].fn = handler;
+       info[cmdid].ctx = ctx;
+       info[cmdid].timeout = jiffies + timeout;
+       return cmdid;
+}
+
+static int alloc_cmdid_killable(struct nvme_queue *nvmeq, void *ctx,
+                               nvme_completion_fn handler, unsigned timeout)
+{
+       int cmdid;
+       wait_event_killable(nvmeq->sq_full,
+               (cmdid = alloc_cmdid(nvmeq, ctx, handler, timeout)) >= 0);
+       return (cmdid < 0) ? -EINTR : cmdid;
+}
+
+/* Special values must be less than 0x1000 */
+#define CMD_CTX_BASE           ((void *)POISON_POINTER_DELTA)
+#define CMD_CTX_CANCELLED      (0x30C + CMD_CTX_BASE)
+#define CMD_CTX_COMPLETED      (0x310 + CMD_CTX_BASE)
+#define CMD_CTX_INVALID                (0x314 + CMD_CTX_BASE)
+#define CMD_CTX_FLUSH          (0x318 + CMD_CTX_BASE)
+
+static void special_completion(struct nvme_dev *dev, void *ctx,
+                                               struct nvme_completion *cqe)
+{
+       if (ctx == CMD_CTX_CANCELLED)
+               return;
+       if (ctx == CMD_CTX_FLUSH)
+               return;
+       if (ctx == CMD_CTX_COMPLETED) {
+               dev_warn(&dev->pci_dev->dev,
+                               "completed id %d twice on queue %d\n",
+                               cqe->command_id, le16_to_cpup(&cqe->sq_id));
+               return;
+       }
+       if (ctx == CMD_CTX_INVALID) {
+               dev_warn(&dev->pci_dev->dev,
+                               "invalid id %d completed on queue %d\n",
+                               cqe->command_id, le16_to_cpup(&cqe->sq_id));
+               return;
+       }
+
+       dev_warn(&dev->pci_dev->dev, "Unknown special completion %p\n", ctx);
+}
+
+/*
+ * Called with local interrupts disabled and the q_lock held.  May not sleep.
+ */
+static void *free_cmdid(struct nvme_queue *nvmeq, int cmdid,
+                                               nvme_completion_fn *fn)
+{
+       void *ctx;
+       struct nvme_cmd_info *info = nvme_cmd_info(nvmeq);
+
+       if (cmdid >= nvmeq->q_depth) {
+               *fn = special_completion;
+               return CMD_CTX_INVALID;
+       }
+       *fn = info[cmdid].fn;
+       ctx = info[cmdid].ctx;
+       info[cmdid].fn = special_completion;
+       info[cmdid].ctx = CMD_CTX_COMPLETED;
+       clear_bit(cmdid, nvmeq->cmdid_data);
+       wake_up(&nvmeq->sq_full);
+       return ctx;
+}
+
+static void *cancel_cmdid(struct nvme_queue *nvmeq, int cmdid,
+                                               nvme_completion_fn *fn)
+{
+       void *ctx;
+       struct nvme_cmd_info *info = nvme_cmd_info(nvmeq);
+       if (fn)
+               *fn = info[cmdid].fn;
+       ctx = info[cmdid].ctx;
+       info[cmdid].fn = special_completion;
+       info[cmdid].ctx = CMD_CTX_CANCELLED;
+       return ctx;
+}
+
+static struct nvme_queue *get_nvmeq(struct nvme_dev *dev)
+{
+       return dev->queues[get_cpu() + 1];
+}
+
+static void put_nvmeq(struct nvme_queue *nvmeq)
+{
+       put_cpu();
+}
+
+/**
+ * nvme_submit_cmd() - Copy a command into a queue and ring the doorbell
+ * @nvmeq: The queue to use
+ * @cmd: The command to send
+ *
+ * Safe to use from interrupt context
+ */
+static int nvme_submit_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd)
+{
+       unsigned long flags;
+       u16 tail;
+       spin_lock_irqsave(&nvmeq->q_lock, flags);
+       tail = nvmeq->sq_tail;
+       memcpy(&nvmeq->sq_cmds[tail], cmd, sizeof(*cmd));
+       if (++tail == nvmeq->q_depth)
+               tail = 0;
+       writel(tail, nvmeq->q_db);
+       nvmeq->sq_tail = tail;
+       spin_unlock_irqrestore(&nvmeq->q_lock, flags);
+
+       return 0;
+}
+
+/*
+ * The nvme_iod describes the data in an I/O, including the list of PRP
+ * entries.  You can't see it in this data structure because C doesn't let
+ * me express that.  Use nvme_alloc_iod to ensure there's enough space
+ * allocated to store the PRP list.
+ */
+struct nvme_iod {
+       void *private;          /* For the use of the submitter of the I/O */
+       int npages;             /* In the PRP list. 0 means small pool in use */
+       int offset;             /* Of PRP list */
+       int nents;              /* Used in scatterlist */
+       int length;             /* Of data, in bytes */
+       dma_addr_t first_dma;
+       struct scatterlist sg[0];
+};
+
+static __le64 **iod_list(struct nvme_iod *iod)
+{
+       return ((void *)iod) + iod->offset;
+}
+
+/*
+ * Will slightly overestimate the number of pages needed.  This is OK
+ * as it only leads to a small amount of wasted memory for the lifetime of
+ * the I/O.
+ */
+static int nvme_npages(unsigned size)
+{
+       unsigned nprps = DIV_ROUND_UP(size + PAGE_SIZE, PAGE_SIZE);
+       return DIV_ROUND_UP(8 * nprps, PAGE_SIZE - 8);
+}
+
+static struct nvme_iod *
+nvme_alloc_iod(unsigned nseg, unsigned nbytes, gfp_t gfp)
+{
+       struct nvme_iod *iod = kmalloc(sizeof(struct nvme_iod) +
+                               sizeof(__le64 *) * nvme_npages(nbytes) +
+                               sizeof(struct scatterlist) * nseg, gfp);
+
+       if (iod) {
+               iod->offset = offsetof(struct nvme_iod, sg[nseg]);
+               iod->npages = -1;
+               iod->length = nbytes;
+       }
+
+       return iod;
+}
+
+static void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod)
+{
+       const int last_prp = PAGE_SIZE / 8 - 1;
+       int i;
+       __le64 **list = iod_list(iod);
+       dma_addr_t prp_dma = iod->first_dma;
+
+       if (iod->npages == 0)
+               dma_pool_free(dev->prp_small_pool, list[0], prp_dma);
+       for (i = 0; i < iod->npages; i++) {
+               __le64 *prp_list = list[i];
+               dma_addr_t next_prp_dma = le64_to_cpu(prp_list[last_prp]);
+               dma_pool_free(dev->prp_page_pool, prp_list, prp_dma);
+               prp_dma = next_prp_dma;
+       }
+       kfree(iod);
+}
+
+static void requeue_bio(struct nvme_dev *dev, struct bio *bio)
+{
+       struct nvme_queue *nvmeq = get_nvmeq(dev);
+       if (bio_list_empty(&nvmeq->sq_cong))
+               add_wait_queue(&nvmeq->sq_full, &nvmeq->sq_cong_wait);
+       bio_list_add(&nvmeq->sq_cong, bio);
+       put_nvmeq(nvmeq);
+       wake_up_process(nvme_thread);
+}
+
+static void bio_completion(struct nvme_dev *dev, void *ctx,
+                                               struct nvme_completion *cqe)
+{
+       struct nvme_iod *iod = ctx;
+       struct bio *bio = iod->private;
+       u16 status = le16_to_cpup(&cqe->status) >> 1;
+
+       dma_unmap_sg(&dev->pci_dev->dev, iod->sg, iod->nents,
+                       bio_data_dir(bio) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+       nvme_free_iod(dev, iod);
+       if (status) {
+               bio_endio(bio, -EIO);
+       } else if (bio->bi_vcnt > bio->bi_idx) {
+               requeue_bio(dev, bio);
+       } else {
+               bio_endio(bio, 0);
+       }
+}
+
+/* length is in bytes.  gfp flags indicates whether we may sleep. */
+static int nvme_setup_prps(struct nvme_dev *dev,
+                       struct nvme_common_command *cmd, struct nvme_iod *iod,
+                       int total_len, gfp_t gfp)
+{
+       struct dma_pool *pool;
+       int length = total_len;
+       struct scatterlist *sg = iod->sg;
+       int dma_len = sg_dma_len(sg);
+       u64 dma_addr = sg_dma_address(sg);
+       int offset = offset_in_page(dma_addr);
+       __le64 *prp_list;
+       __le64 **list = iod_list(iod);
+       dma_addr_t prp_dma;
+       int nprps, i;
+
+       cmd->prp1 = cpu_to_le64(dma_addr);
+       length -= (PAGE_SIZE - offset);
+       if (length <= 0)
+               return total_len;
+
+       dma_len -= (PAGE_SIZE - offset);
+       if (dma_len) {
+               dma_addr += (PAGE_SIZE - offset);
+       } else {
+               sg = sg_next(sg);
+               dma_addr = sg_dma_address(sg);
+               dma_len = sg_dma_len(sg);
+       }
+
+       if (length <= PAGE_SIZE) {
+               cmd->prp2 = cpu_to_le64(dma_addr);
+               return total_len;
+       }
+
+       nprps = DIV_ROUND_UP(length, PAGE_SIZE);
+       if (nprps <= (256 / 8)) {
+               pool = dev->prp_small_pool;
+               iod->npages = 0;
+       } else {
+               pool = dev->prp_page_pool;
+               iod->npages = 1;
+       }
+
+       prp_list = dma_pool_alloc(pool, gfp, &prp_dma);
+       if (!prp_list) {
+               cmd->prp2 = cpu_to_le64(dma_addr);
+               iod->npages = -1;
+               return (total_len - length) + PAGE_SIZE;
+       }
+       list[0] = prp_list;
+       iod->first_dma = prp_dma;
+       cmd->prp2 = cpu_to_le64(prp_dma);
+       i = 0;
+       for (;;) {
+               if (i == PAGE_SIZE / 8) {
+                       __le64 *old_prp_list = prp_list;
+                       prp_list = dma_pool_alloc(pool, gfp, &prp_dma);
+                       if (!prp_list)
+                               return total_len - length;
+                       list[iod->npages++] = prp_list;
+                       prp_list[0] = old_prp_list[i - 1];
+                       old_prp_list[i - 1] = cpu_to_le64(prp_dma);
+                       i = 1;
+               }
+               prp_list[i++] = cpu_to_le64(dma_addr);
+               dma_len -= PAGE_SIZE;
+               dma_addr += PAGE_SIZE;
+               length -= PAGE_SIZE;
+               if (length <= 0)
+                       break;
+               if (dma_len > 0)
+                       continue;
+               BUG_ON(dma_len < 0);
+               sg = sg_next(sg);
+               dma_addr = sg_dma_address(sg);
+               dma_len = sg_dma_len(sg);
+       }
+
+       return total_len;
+}
+
+/* NVMe scatterlists require no holes in the virtual address */
+#define BIOVEC_NOT_VIRT_MERGEABLE(vec1, vec2)  ((vec2)->bv_offset || \
+                       (((vec1)->bv_offset + (vec1)->bv_len) % PAGE_SIZE))
+
+static int nvme_map_bio(struct device *dev, struct nvme_iod *iod,
+               struct bio *bio, enum dma_data_direction dma_dir, int psegs)
+{
+       struct bio_vec *bvec, *bvprv = NULL;
+       struct scatterlist *sg = NULL;
+       int i, old_idx, length = 0, nsegs = 0;
+
+       sg_init_table(iod->sg, psegs);
+       old_idx = bio->bi_idx;
+       bio_for_each_segment(bvec, bio, i) {
+               if (bvprv && BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) {
+                       sg->length += bvec->bv_len;
+               } else {
+                       if (bvprv && BIOVEC_NOT_VIRT_MERGEABLE(bvprv, bvec))
+                               break;
+                       sg = sg ? sg + 1 : iod->sg;
+                       sg_set_page(sg, bvec->bv_page, bvec->bv_len,
+                                                       bvec->bv_offset);
+                       nsegs++;
+               }
+               length += bvec->bv_len;
+               bvprv = bvec;
+       }
+       bio->bi_idx = i;
+       iod->nents = nsegs;
+       sg_mark_end(sg);
+       if (dma_map_sg(dev, iod->sg, iod->nents, dma_dir) == 0) {
+               bio->bi_idx = old_idx;
+               return -ENOMEM;
+       }
+       return length;
+}
+
+static int nvme_submit_flush(struct nvme_queue *nvmeq, struct nvme_ns *ns,
+                                                               int cmdid)
+{
+       struct nvme_command *cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail];
+
+       memset(cmnd, 0, sizeof(*cmnd));
+       cmnd->common.opcode = nvme_cmd_flush;
+       cmnd->common.command_id = cmdid;
+       cmnd->common.nsid = cpu_to_le32(ns->ns_id);
+
+       if (++nvmeq->sq_tail == nvmeq->q_depth)
+               nvmeq->sq_tail = 0;
+       writel(nvmeq->sq_tail, nvmeq->q_db);
+
+       return 0;
+}
+
+static int nvme_submit_flush_data(struct nvme_queue *nvmeq, struct nvme_ns *ns)
+{
+       int cmdid = alloc_cmdid(nvmeq, (void *)CMD_CTX_FLUSH,
+                                       special_completion, NVME_IO_TIMEOUT);
+       if (unlikely(cmdid < 0))
+               return cmdid;
+
+       return nvme_submit_flush(nvmeq, ns, cmdid);
+}
+
+/*
+ * Called with local interrupts disabled and the q_lock held.  May not sleep.
+ */
+static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns,
+                                                               struct bio *bio)
+{
+       struct nvme_command *cmnd;
+       struct nvme_iod *iod;
+       enum dma_data_direction dma_dir;
+       int cmdid, length, result = -ENOMEM;
+       u16 control;
+       u32 dsmgmt;
+       int psegs = bio_phys_segments(ns->queue, bio);
+
+       if ((bio->bi_rw & REQ_FLUSH) && psegs) {
+               result = nvme_submit_flush_data(nvmeq, ns);
+               if (result)
+                       return result;
+       }
+
+       iod = nvme_alloc_iod(psegs, bio->bi_size, GFP_ATOMIC);
+       if (!iod)
+               goto nomem;
+       iod->private = bio;
+
+       result = -EBUSY;
+       cmdid = alloc_cmdid(nvmeq, iod, bio_completion, NVME_IO_TIMEOUT);
+       if (unlikely(cmdid < 0))
+               goto free_iod;
+
+       if ((bio->bi_rw & REQ_FLUSH) && !psegs)
+               return nvme_submit_flush(nvmeq, ns, cmdid);
+
+       control = 0;
+       if (bio->bi_rw & REQ_FUA)
+               control |= NVME_RW_FUA;
+       if (bio->bi_rw & (REQ_FAILFAST_DEV | REQ_RAHEAD))
+               control |= NVME_RW_LR;
+
+       dsmgmt = 0;
+       if (bio->bi_rw & REQ_RAHEAD)
+               dsmgmt |= NVME_RW_DSM_FREQ_PREFETCH;
+
+       cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail];
+
+       memset(cmnd, 0, sizeof(*cmnd));
+       if (bio_data_dir(bio)) {
+               cmnd->rw.opcode = nvme_cmd_write;
+               dma_dir = DMA_TO_DEVICE;
+       } else {
+               cmnd->rw.opcode = nvme_cmd_read;
+               dma_dir = DMA_FROM_DEVICE;
+       }
+
+       result = nvme_map_bio(nvmeq->q_dmadev, iod, bio, dma_dir, psegs);
+       if (result < 0)
+               goto free_iod;
+       length = result;
+
+       cmnd->rw.command_id = cmdid;
+       cmnd->rw.nsid = cpu_to_le32(ns->ns_id);
+       length = nvme_setup_prps(nvmeq->dev, &cmnd->common, iod, length,
+                                                               GFP_ATOMIC);
+       cmnd->rw.slba = cpu_to_le64(bio->bi_sector >> (ns->lba_shift - 9));
+       cmnd->rw.length = cpu_to_le16((length >> ns->lba_shift) - 1);
+       cmnd->rw.control = cpu_to_le16(control);
+       cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt);
+
+       bio->bi_sector += length >> 9;
+
+       if (++nvmeq->sq_tail == nvmeq->q_depth)
+               nvmeq->sq_tail = 0;
+       writel(nvmeq->sq_tail, nvmeq->q_db);
+
+       return 0;
+
+ free_iod:
+       nvme_free_iod(nvmeq->dev, iod);
+ nomem:
+       return result;
+}
+
+static void nvme_make_request(struct request_queue *q, struct bio *bio)
+{
+       struct nvme_ns *ns = q->queuedata;
+       struct nvme_queue *nvmeq = get_nvmeq(ns->dev);
+       int result = -EBUSY;
+
+       spin_lock_irq(&nvmeq->q_lock);
+       if (bio_list_empty(&nvmeq->sq_cong))
+               result = nvme_submit_bio_queue(nvmeq, ns, bio);
+       if (unlikely(result)) {
+               if (bio_list_empty(&nvmeq->sq_cong))
+                       add_wait_queue(&nvmeq->sq_full, &nvmeq->sq_cong_wait);
+               bio_list_add(&nvmeq->sq_cong, bio);
+       }
+
+       spin_unlock_irq(&nvmeq->q_lock);
+       put_nvmeq(nvmeq);
+}
+
+static irqreturn_t nvme_process_cq(struct nvme_queue *nvmeq)
+{
+       u16 head, phase;
+
+       head = nvmeq->cq_head;
+       phase = nvmeq->cq_phase;
+
+       for (;;) {
+               void *ctx;
+               nvme_completion_fn fn;
+               struct nvme_completion cqe = nvmeq->cqes[head];
+               if ((le16_to_cpu(cqe.status) & 1) != phase)
+                       break;
+               nvmeq->sq_head = le16_to_cpu(cqe.sq_head);
+               if (++head == nvmeq->q_depth) {
+                       head = 0;
+                       phase = !phase;
+               }
+
+               ctx = free_cmdid(nvmeq, cqe.command_id, &fn);
+               fn(nvmeq->dev, ctx, &cqe);
+       }
+
+       /* If the controller ignores the cq head doorbell and continuously
+        * writes to the queue, it is theoretically possible to wrap around
+        * the queue twice and mistakenly return IRQ_NONE.  Linux only
+        * requires that 0.1% of your interrupts are handled, so this isn't
+        * a big problem.
+        */
+       if (head == nvmeq->cq_head && phase == nvmeq->cq_phase)
+               return IRQ_NONE;
+
+       writel(head, nvmeq->q_db + (1 << nvmeq->dev->db_stride));
+       nvmeq->cq_head = head;
+       nvmeq->cq_phase = phase;
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t nvme_irq(int irq, void *data)
+{
+       irqreturn_t result;
+       struct nvme_queue *nvmeq = data;
+       spin_lock(&nvmeq->q_lock);
+       result = nvme_process_cq(nvmeq);
+       spin_unlock(&nvmeq->q_lock);
+       return result;
+}
+
+static irqreturn_t nvme_irq_check(int irq, void *data)
+{
+       struct nvme_queue *nvmeq = data;
+       struct nvme_completion cqe = nvmeq->cqes[nvmeq->cq_head];
+       if ((le16_to_cpu(cqe.status) & 1) != nvmeq->cq_phase)
+               return IRQ_NONE;
+       return IRQ_WAKE_THREAD;
+}
+
+static void nvme_abort_command(struct nvme_queue *nvmeq, int cmdid)
+{
+       spin_lock_irq(&nvmeq->q_lock);
+       cancel_cmdid(nvmeq, cmdid, NULL);
+       spin_unlock_irq(&nvmeq->q_lock);
+}
+
+struct sync_cmd_info {
+       struct task_struct *task;
+       u32 result;
+       int status;
+};
+
+static void sync_completion(struct nvme_dev *dev, void *ctx,
+                                               struct nvme_completion *cqe)
+{
+       struct sync_cmd_info *cmdinfo = ctx;
+       cmdinfo->result = le32_to_cpup(&cqe->result);
+       cmdinfo->status = le16_to_cpup(&cqe->status) >> 1;
+       wake_up_process(cmdinfo->task);
+}
+
+/*
+ * Returns 0 on success.  If the result is negative, it's a Linux error code;
+ * if the result is positive, it's an NVM Express status code
+ */
+static int nvme_submit_sync_cmd(struct nvme_queue *nvmeq,
+                       struct nvme_command *cmd, u32 *result, unsigned timeout)
+{
+       int cmdid;
+       struct sync_cmd_info cmdinfo;
+
+       cmdinfo.task = current;
+       cmdinfo.status = -EINTR;
+
+       cmdid = alloc_cmdid_killable(nvmeq, &cmdinfo, sync_completion,
+                                                               timeout);
+       if (cmdid < 0)
+               return cmdid;
+       cmd->common.command_id = cmdid;
+
+       set_current_state(TASK_KILLABLE);
+       nvme_submit_cmd(nvmeq, cmd);
+       schedule();
+
+       if (cmdinfo.status == -EINTR) {
+               nvme_abort_command(nvmeq, cmdid);
+               return -EINTR;
+       }
+
+       if (result)
+               *result = cmdinfo.result;
+
+       return cmdinfo.status;
+}
+
+static int nvme_submit_admin_cmd(struct nvme_dev *dev, struct nvme_command *cmd,
+                                                               u32 *result)
+{
+       return nvme_submit_sync_cmd(dev->queues[0], cmd, result, ADMIN_TIMEOUT);
+}
+
+static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id)
+{
+       int status;
+       struct nvme_command c;
+
+       memset(&c, 0, sizeof(c));
+       c.delete_queue.opcode = opcode;
+       c.delete_queue.qid = cpu_to_le16(id);
+
+       status = nvme_submit_admin_cmd(dev, &c, NULL);
+       if (status)
+               return -EIO;
+       return 0;
+}
+
+static int adapter_alloc_cq(struct nvme_dev *dev, u16 qid,
+                                               struct nvme_queue *nvmeq)
+{
+       int status;
+       struct nvme_command c;
+       int flags = NVME_QUEUE_PHYS_CONTIG | NVME_CQ_IRQ_ENABLED;
+
+       memset(&c, 0, sizeof(c));
+       c.create_cq.opcode = nvme_admin_create_cq;
+       c.create_cq.prp1 = cpu_to_le64(nvmeq->cq_dma_addr);
+       c.create_cq.cqid = cpu_to_le16(qid);
+       c.create_cq.qsize = cpu_to_le16(nvmeq->q_depth - 1);
+       c.create_cq.cq_flags = cpu_to_le16(flags);
+       c.create_cq.irq_vector = cpu_to_le16(nvmeq->cq_vector);
+
+       status = nvme_submit_admin_cmd(dev, &c, NULL);
+       if (status)
+               return -EIO;
+       return 0;
+}
+
+static int adapter_alloc_sq(struct nvme_dev *dev, u16 qid,
+                                               struct nvme_queue *nvmeq)
+{
+       int status;
+       struct nvme_command c;
+       int flags = NVME_QUEUE_PHYS_CONTIG | NVME_SQ_PRIO_MEDIUM;
+
+       memset(&c, 0, sizeof(c));
+       c.create_sq.opcode = nvme_admin_create_sq;
+       c.create_sq.prp1 = cpu_to_le64(nvmeq->sq_dma_addr);
+       c.create_sq.sqid = cpu_to_le16(qid);
+       c.create_sq.qsize = cpu_to_le16(nvmeq->q_depth - 1);
+       c.create_sq.sq_flags = cpu_to_le16(flags);
+       c.create_sq.cqid = cpu_to_le16(qid);
+
+       status = nvme_submit_admin_cmd(dev, &c, NULL);
+       if (status)
+               return -EIO;
+       return 0;
+}
+
+static int adapter_delete_cq(struct nvme_dev *dev, u16 cqid)
+{
+       return adapter_delete_queue(dev, nvme_admin_delete_cq, cqid);
+}
+
+static int adapter_delete_sq(struct nvme_dev *dev, u16 sqid)
+{
+       return adapter_delete_queue(dev, nvme_admin_delete_sq, sqid);
+}
+
+static int nvme_identify(struct nvme_dev *dev, unsigned nsid, unsigned cns,
+                                                       dma_addr_t dma_addr)
+{
+       struct nvme_command c;
+
+       memset(&c, 0, sizeof(c));
+       c.identify.opcode = nvme_admin_identify;
+       c.identify.nsid = cpu_to_le32(nsid);
+       c.identify.prp1 = cpu_to_le64(dma_addr);
+       c.identify.cns = cpu_to_le32(cns);
+
+       return nvme_submit_admin_cmd(dev, &c, NULL);
+}
+
+static int nvme_get_features(struct nvme_dev *dev, unsigned fid,
+                               unsigned dword11, dma_addr_t dma_addr)
+{
+       struct nvme_command c;
+
+       memset(&c, 0, sizeof(c));
+       c.features.opcode = nvme_admin_get_features;
+       c.features.prp1 = cpu_to_le64(dma_addr);
+       c.features.fid = cpu_to_le32(fid);
+       c.features.dword11 = cpu_to_le32(dword11);
+
+       return nvme_submit_admin_cmd(dev, &c, NULL);
+}
+
+static int nvme_set_features(struct nvme_dev *dev, unsigned fid,
+                       unsigned dword11, dma_addr_t dma_addr, u32 *result)
+{
+       struct nvme_command c;
+
+       memset(&c, 0, sizeof(c));
+       c.features.opcode = nvme_admin_set_features;
+       c.features.prp1 = cpu_to_le64(dma_addr);
+       c.features.fid = cpu_to_le32(fid);
+       c.features.dword11 = cpu_to_le32(dword11);
+
+       return nvme_submit_admin_cmd(dev, &c, result);
+}
+
+static void nvme_free_queue(struct nvme_dev *dev, int qid)
+{
+       struct nvme_queue *nvmeq = dev->queues[qid];
+       int vector = dev->entry[nvmeq->cq_vector].vector;
+
+       irq_set_affinity_hint(vector, NULL);
+       free_irq(vector, nvmeq);
+
+       /* Don't tell the adapter to delete the admin queue */
+       if (qid) {
+               adapter_delete_sq(dev, qid);
+               adapter_delete_cq(dev, qid);
+       }
+
+       dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth),
+                               (void *)nvmeq->cqes, nvmeq->cq_dma_addr);
+       dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth),
+                                       nvmeq->sq_cmds, nvmeq->sq_dma_addr);
+       kfree(nvmeq);
+}
+
+static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
+                                                       int depth, int vector)
+{
+       struct device *dmadev = &dev->pci_dev->dev;
+       unsigned extra = (depth / 8) + (depth * sizeof(struct nvme_cmd_info));
+       struct nvme_queue *nvmeq = kzalloc(sizeof(*nvmeq) + extra, GFP_KERNEL);
+       if (!nvmeq)
+               return NULL;
+
+       nvmeq->cqes = dma_alloc_coherent(dmadev, CQ_SIZE(depth),
+                                       &nvmeq->cq_dma_addr, GFP_KERNEL);
+       if (!nvmeq->cqes)
+               goto free_nvmeq;
+       memset((void *)nvmeq->cqes, 0, CQ_SIZE(depth));
+
+       nvmeq->sq_cmds = dma_alloc_coherent(dmadev, SQ_SIZE(depth),
+                                       &nvmeq->sq_dma_addr, GFP_KERNEL);
+       if (!nvmeq->sq_cmds)
+               goto free_cqdma;
+
+       nvmeq->q_dmadev = dmadev;
+       nvmeq->dev = dev;
+       spin_lock_init(&nvmeq->q_lock);
+       nvmeq->cq_head = 0;
+       nvmeq->cq_phase = 1;
+       init_waitqueue_head(&nvmeq->sq_full);
+       init_waitqueue_entry(&nvmeq->sq_cong_wait, nvme_thread);
+       bio_list_init(&nvmeq->sq_cong);
+       nvmeq->q_db = &dev->dbs[qid << (dev->db_stride + 1)];
+       nvmeq->q_depth = depth;
+       nvmeq->cq_vector = vector;
+
+       return nvmeq;
+
+ free_cqdma:
+       dma_free_coherent(dmadev, CQ_SIZE(nvmeq->q_depth), (void *)nvmeq->cqes,
+                                                       nvmeq->cq_dma_addr);
+ free_nvmeq:
+       kfree(nvmeq);
+       return NULL;
+}
+
+static int queue_request_irq(struct nvme_dev *dev, struct nvme_queue *nvmeq,
+                                                       const char *name)
+{
+       if (use_threaded_interrupts)
+               return request_threaded_irq(dev->entry[nvmeq->cq_vector].vector,
+                                       nvme_irq_check, nvme_irq,
+                                       IRQF_DISABLED | IRQF_SHARED,
+                                       name, nvmeq);
+       return request_irq(dev->entry[nvmeq->cq_vector].vector, nvme_irq,
+                               IRQF_DISABLED | IRQF_SHARED, name, nvmeq);
+}
+
+static __devinit struct nvme_queue *nvme_create_queue(struct nvme_dev *dev,
+                                       int qid, int cq_size, int vector)
+{
+       int result;
+       struct nvme_queue *nvmeq = nvme_alloc_queue(dev, qid, cq_size, vector);
+
+       if (!nvmeq)
+               return ERR_PTR(-ENOMEM);
+
+       result = adapter_alloc_cq(dev, qid, nvmeq);
+       if (result < 0)
+               goto free_nvmeq;
+
+       result = adapter_alloc_sq(dev, qid, nvmeq);
+       if (result < 0)
+               goto release_cq;
+
+       result = queue_request_irq(dev, nvmeq, "nvme");
+       if (result < 0)
+               goto release_sq;
+
+       return nvmeq;
+
+ release_sq:
+       adapter_delete_sq(dev, qid);
+ release_cq:
+       adapter_delete_cq(dev, qid);
+ free_nvmeq:
+       dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth),
+                               (void *)nvmeq->cqes, nvmeq->cq_dma_addr);
+       dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth),
+                                       nvmeq->sq_cmds, nvmeq->sq_dma_addr);
+       kfree(nvmeq);
+       return ERR_PTR(result);
+}
+
+static int __devinit nvme_configure_admin_queue(struct nvme_dev *dev)
+{
+       int result;
+       u32 aqa;
+       u64 cap;
+       unsigned long timeout;
+       struct nvme_queue *nvmeq;
+
+       dev->dbs = ((void __iomem *)dev->bar) + 4096;
+
+       nvmeq = nvme_alloc_queue(dev, 0, 64, 0);
+       if (!nvmeq)
+               return -ENOMEM;
+
+       aqa = nvmeq->q_depth - 1;
+       aqa |= aqa << 16;
+
+       dev->ctrl_config = NVME_CC_ENABLE | NVME_CC_CSS_NVM;
+       dev->ctrl_config |= (PAGE_SHIFT - 12) << NVME_CC_MPS_SHIFT;
+       dev->ctrl_config |= NVME_CC_ARB_RR | NVME_CC_SHN_NONE;
+       dev->ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES;
+
+       writel(0, &dev->bar->cc);
+       writel(aqa, &dev->bar->aqa);
+       writeq(nvmeq->sq_dma_addr, &dev->bar->asq);
+       writeq(nvmeq->cq_dma_addr, &dev->bar->acq);
+       writel(dev->ctrl_config, &dev->bar->cc);
+
+       cap = readq(&dev->bar->cap);
+       timeout = ((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2) + jiffies;
+       dev->db_stride = NVME_CAP_STRIDE(cap);
+
+       while (!(readl(&dev->bar->csts) & NVME_CSTS_RDY)) {
+               msleep(100);
+               if (fatal_signal_pending(current))
+                       return -EINTR;
+               if (time_after(jiffies, timeout)) {
+                       dev_err(&dev->pci_dev->dev,
+                               "Device not ready; aborting initialisation\n");
+                       return -ENODEV;
+               }
+       }
+
+       result = queue_request_irq(dev, nvmeq, "nvme admin");
+       dev->queues[0] = nvmeq;
+       return result;
+}
+
+static struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write,
+                               unsigned long addr, unsigned length)
+{
+       int i, err, count, nents, offset;
+       struct scatterlist *sg;
+       struct page **pages;
+       struct nvme_iod *iod;
+
+       if (addr & 3)
+               return ERR_PTR(-EINVAL);
+       if (!length)
+               return ERR_PTR(-EINVAL);
+
+       offset = offset_in_page(addr);
+       count = DIV_ROUND_UP(offset + length, PAGE_SIZE);
+       pages = kcalloc(count, sizeof(*pages), GFP_KERNEL);
+
+       err = get_user_pages_fast(addr, count, 1, pages);
+       if (err < count) {
+               count = err;
+               err = -EFAULT;
+               goto put_pages;
+       }
+
+       iod = nvme_alloc_iod(count, length, GFP_KERNEL);
+       sg = iod->sg;
+       sg_init_table(sg, count);
+       for (i = 0; i < count; i++) {
+               sg_set_page(&sg[i], pages[i],
+                               min_t(int, length, PAGE_SIZE - offset), offset);
+               length -= (PAGE_SIZE - offset);
+               offset = 0;
+       }
+       sg_mark_end(&sg[i - 1]);
+       iod->nents = count;
+
+       err = -ENOMEM;
+       nents = dma_map_sg(&dev->pci_dev->dev, sg, count,
+                               write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+       if (!nents)
+               goto free_iod;
+
+       kfree(pages);
+       return iod;
+
+ free_iod:
+       kfree(iod);
+ put_pages:
+       for (i = 0; i < count; i++)
+               put_page(pages[i]);
+       kfree(pages);
+       return ERR_PTR(err);
+}
+
+static void nvme_unmap_user_pages(struct nvme_dev *dev, int write,
+                       struct nvme_iod *iod)
+{
+       int i;
+
+       dma_unmap_sg(&dev->pci_dev->dev, iod->sg, iod->nents,
+                               write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+       for (i = 0; i < iod->nents; i++)
+               put_page(sg_page(&iod->sg[i]));
+}
+
+static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
+{
+       struct nvme_dev *dev = ns->dev;
+       struct nvme_queue *nvmeq;
+       struct nvme_user_io io;
+       struct nvme_command c;
+       unsigned length;
+       int status;
+       struct nvme_iod *iod;
+
+       if (copy_from_user(&io, uio, sizeof(io)))
+               return -EFAULT;
+       length = (io.nblocks + 1) << ns->lba_shift;
+
+       switch (io.opcode) {
+       case nvme_cmd_write:
+       case nvme_cmd_read:
+       case nvme_cmd_compare:
+               iod = nvme_map_user_pages(dev, io.opcode & 1, io.addr, length);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (IS_ERR(iod))
+               return PTR_ERR(iod);
+
+       memset(&c, 0, sizeof(c));
+       c.rw.opcode = io.opcode;
+       c.rw.flags = io.flags;
+       c.rw.nsid = cpu_to_le32(ns->ns_id);
+       c.rw.slba = cpu_to_le64(io.slba);
+       c.rw.length = cpu_to_le16(io.nblocks);
+       c.rw.control = cpu_to_le16(io.control);
+       c.rw.dsmgmt = cpu_to_le16(io.dsmgmt);
+       c.rw.reftag = io.reftag;
+       c.rw.apptag = io.apptag;
+       c.rw.appmask = io.appmask;
+       /* XXX: metadata */
+       length = nvme_setup_prps(dev, &c.common, iod, length, GFP_KERNEL);
+
+       nvmeq = get_nvmeq(dev);
+       /*
+        * Since nvme_submit_sync_cmd sleeps, we can't keep preemption
+        * disabled.  We may be preempted at any point, and be rescheduled
+        * to a different CPU.  That will cause cacheline bouncing, but no
+        * additional races since q_lock already protects against other CPUs.
+        */
+       put_nvmeq(nvmeq);
+       if (length != (io.nblocks + 1) << ns->lba_shift)
+               status = -ENOMEM;
+       else
+               status = nvme_submit_sync_cmd(nvmeq, &c, NULL, NVME_IO_TIMEOUT);
+
+       nvme_unmap_user_pages(dev, io.opcode & 1, iod);
+       nvme_free_iod(dev, iod);
+       return status;
+}
+
+static int nvme_user_admin_cmd(struct nvme_ns *ns,
+                                       struct nvme_admin_cmd __user *ucmd)
+{
+       struct nvme_dev *dev = ns->dev;
+       struct nvme_admin_cmd cmd;
+       struct nvme_command c;
+       int status, length;
+       struct nvme_iod *iod;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+       if (copy_from_user(&cmd, ucmd, sizeof(cmd)))
+               return -EFAULT;
+
+       memset(&c, 0, sizeof(c));
+       c.common.opcode = cmd.opcode;
+       c.common.flags = cmd.flags;
+       c.common.nsid = cpu_to_le32(cmd.nsid);
+       c.common.cdw2[0] = cpu_to_le32(cmd.cdw2);
+       c.common.cdw2[1] = cpu_to_le32(cmd.cdw3);
+       c.common.cdw10[0] = cpu_to_le32(cmd.cdw10);
+       c.common.cdw10[1] = cpu_to_le32(cmd.cdw11);
+       c.common.cdw10[2] = cpu_to_le32(cmd.cdw12);
+       c.common.cdw10[3] = cpu_to_le32(cmd.cdw13);
+       c.common.cdw10[4] = cpu_to_le32(cmd.cdw14);
+       c.common.cdw10[5] = cpu_to_le32(cmd.cdw15);
+
+       length = cmd.data_len;
+       if (cmd.data_len) {
+               iod = nvme_map_user_pages(dev, cmd.opcode & 1, cmd.addr,
+                                                               length);
+               if (IS_ERR(iod))
+                       return PTR_ERR(iod);
+               length = nvme_setup_prps(dev, &c.common, iod, length,
+                                                               GFP_KERNEL);
+       }
+
+       if (length != cmd.data_len)
+               status = -ENOMEM;
+       else
+               status = nvme_submit_admin_cmd(dev, &c, NULL);
+
+       if (cmd.data_len) {
+               nvme_unmap_user_pages(dev, cmd.opcode & 1, iod);
+               nvme_free_iod(dev, iod);
+       }
+       return status;
+}
+
+static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
+                                                       unsigned long arg)
+{
+       struct nvme_ns *ns = bdev->bd_disk->private_data;
+
+       switch (cmd) {
+       case NVME_IOCTL_ID:
+               return ns->ns_id;
+       case NVME_IOCTL_ADMIN_CMD:
+               return nvme_user_admin_cmd(ns, (void __user *)arg);
+       case NVME_IOCTL_SUBMIT_IO:
+               return nvme_submit_io(ns, (void __user *)arg);
+       default:
+               return -ENOTTY;
+       }
+}
+
+static const struct block_device_operations nvme_fops = {
+       .owner          = THIS_MODULE,
+       .ioctl          = nvme_ioctl,
+       .compat_ioctl   = nvme_ioctl,
+};
+
+static void nvme_timeout_ios(struct nvme_queue *nvmeq)
+{
+       int depth = nvmeq->q_depth - 1;
+       struct nvme_cmd_info *info = nvme_cmd_info(nvmeq);
+       unsigned long now = jiffies;
+       int cmdid;
+
+       for_each_set_bit(cmdid, nvmeq->cmdid_data, depth) {
+               void *ctx;
+               nvme_completion_fn fn;
+               static struct nvme_completion cqe = { .status = cpu_to_le16(NVME_SC_ABORT_REQ) << 1, };
+
+               if (!time_after(now, info[cmdid].timeout))
+                       continue;
+               dev_warn(nvmeq->q_dmadev, "Timing out I/O %d\n", cmdid);
+               ctx = cancel_cmdid(nvmeq, cmdid, &fn);
+               fn(nvmeq->dev, ctx, &cqe);
+       }
+}
+
+static void nvme_resubmit_bios(struct nvme_queue *nvmeq)
+{
+       while (bio_list_peek(&nvmeq->sq_cong)) {
+               struct bio *bio = bio_list_pop(&nvmeq->sq_cong);
+               struct nvme_ns *ns = bio->bi_bdev->bd_disk->private_data;
+               if (nvme_submit_bio_queue(nvmeq, ns, bio)) {
+                       bio_list_add_head(&nvmeq->sq_cong, bio);
+                       break;
+               }
+               if (bio_list_empty(&nvmeq->sq_cong))
+                       remove_wait_queue(&nvmeq->sq_full,
+                                                       &nvmeq->sq_cong_wait);
+       }
+}
+
+static int nvme_kthread(void *data)
+{
+       struct nvme_dev *dev;
+
+       while (!kthread_should_stop()) {
+               __set_current_state(TASK_RUNNING);
+               spin_lock(&dev_list_lock);
+               list_for_each_entry(dev, &dev_list, node) {
+                       int i;
+                       for (i = 0; i < dev->queue_count; i++) {
+                               struct nvme_queue *nvmeq = dev->queues[i];
+                               if (!nvmeq)
+                                       continue;
+                               spin_lock_irq(&nvmeq->q_lock);
+                               if (nvme_process_cq(nvmeq))
+                                       printk("process_cq did something\n");
+                               nvme_timeout_ios(nvmeq);
+                               nvme_resubmit_bios(nvmeq);
+                               spin_unlock_irq(&nvmeq->q_lock);
+                       }
+               }
+               spin_unlock(&dev_list_lock);
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ);
+       }
+       return 0;
+}
+
+static DEFINE_IDA(nvme_index_ida);
+
+static int nvme_get_ns_idx(void)
+{
+       int index, error;
+
+       do {
+               if (!ida_pre_get(&nvme_index_ida, GFP_KERNEL))
+                       return -1;
+
+               spin_lock(&dev_list_lock);
+               error = ida_get_new(&nvme_index_ida, &index);
+               spin_unlock(&dev_list_lock);
+       } while (error == -EAGAIN);
+
+       if (error)
+               index = -1;
+       return index;
+}
+
+static void nvme_put_ns_idx(int index)
+{
+       spin_lock(&dev_list_lock);
+       ida_remove(&nvme_index_ida, index);
+       spin_unlock(&dev_list_lock);
+}
+
+static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, int nsid,
+                       struct nvme_id_ns *id, struct nvme_lba_range_type *rt)
+{
+       struct nvme_ns *ns;
+       struct gendisk *disk;
+       int lbaf;
+
+       if (rt->attributes & NVME_LBART_ATTRIB_HIDE)
+               return NULL;
+
+       ns = kzalloc(sizeof(*ns), GFP_KERNEL);
+       if (!ns)
+               return NULL;
+       ns->queue = blk_alloc_queue(GFP_KERNEL);
+       if (!ns->queue)
+               goto out_free_ns;
+       ns->queue->queue_flags = QUEUE_FLAG_DEFAULT;
+       queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, ns->queue);
+       queue_flag_set_unlocked(QUEUE_FLAG_NONROT, ns->queue);
+/*     queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue); */
+       blk_queue_make_request(ns->queue, nvme_make_request);
+       ns->dev = dev;
+       ns->queue->queuedata = ns;
+
+       disk = alloc_disk(NVME_MINORS);
+       if (!disk)
+               goto out_free_queue;
+       ns->ns_id = nsid;
+       ns->disk = disk;
+       lbaf = id->flbas & 0xf;
+       ns->lba_shift = id->lbaf[lbaf].ds;
+
+       disk->major = nvme_major;
+       disk->minors = NVME_MINORS;
+       disk->first_minor = NVME_MINORS * nvme_get_ns_idx();
+       disk->fops = &nvme_fops;
+       disk->private_data = ns;
+       disk->queue = ns->queue;
+       disk->driverfs_dev = &dev->pci_dev->dev;
+       sprintf(disk->disk_name, "nvme%dn%d", dev->instance, nsid);
+       set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
+
+       return ns;
+
+ out_free_queue:
+       blk_cleanup_queue(ns->queue);
+ out_free_ns:
+       kfree(ns);
+       return NULL;
+}
+
+static void nvme_ns_free(struct nvme_ns *ns)
+{
+       int index = ns->disk->first_minor / NVME_MINORS;
+       put_disk(ns->disk);
+       nvme_put_ns_idx(index);
+       blk_cleanup_queue(ns->queue);
+       kfree(ns);
+}
+
+static int set_queue_count(struct nvme_dev *dev, int count)
+{
+       int status;
+       u32 result;
+       u32 q_count = (count - 1) | ((count - 1) << 16);
+
+       status = nvme_set_features(dev, NVME_FEAT_NUM_QUEUES, q_count, 0,
+                                                               &result);
+       if (status)
+               return -EIO;
+       return min(result & 0xffff, result >> 16) + 1;
+}
+
+static int __devinit nvme_setup_io_queues(struct nvme_dev *dev)
+{
+       int result, cpu, i, nr_io_queues, db_bar_size;
+
+       nr_io_queues = num_online_cpus();
+       result = set_queue_count(dev, nr_io_queues);
+       if (result < 0)
+               return result;
+       if (result < nr_io_queues)
+               nr_io_queues = result;
+
+       /* Deregister the admin queue's interrupt */
+       free_irq(dev->entry[0].vector, dev->queues[0]);
+
+       db_bar_size = 4096 + ((nr_io_queues + 1) << (dev->db_stride + 3));
+       if (db_bar_size > 8192) {
+               iounmap(dev->bar);
+               dev->bar = ioremap(pci_resource_start(dev->pci_dev, 0),
+                                                               db_bar_size);
+               dev->dbs = ((void __iomem *)dev->bar) + 4096;
+               dev->queues[0]->q_db = dev->dbs;
+       }
+
+       for (i = 0; i < nr_io_queues; i++)
+               dev->entry[i].entry = i;
+       for (;;) {
+               result = pci_enable_msix(dev->pci_dev, dev->entry,
+                                                               nr_io_queues);
+               if (result == 0) {
+                       break;
+               } else if (result > 0) {
+                       nr_io_queues = result;
+                       continue;
+               } else {
+                       nr_io_queues = 1;
+                       break;
+               }
+       }
+
+       result = queue_request_irq(dev, dev->queues[0], "nvme admin");
+       /* XXX: handle failure here */
+
+       cpu = cpumask_first(cpu_online_mask);
+       for (i = 0; i < nr_io_queues; i++) {
+               irq_set_affinity_hint(dev->entry[i].vector, get_cpu_mask(cpu));
+               cpu = cpumask_next(cpu, cpu_online_mask);
+       }
+
+       for (i = 0; i < nr_io_queues; i++) {
+               dev->queues[i + 1] = nvme_create_queue(dev, i + 1,
+                                                       NVME_Q_DEPTH, i);
+               if (IS_ERR(dev->queues[i + 1]))
+                       return PTR_ERR(dev->queues[i + 1]);
+               dev->queue_count++;
+       }
+
+       for (; i < num_possible_cpus(); i++) {
+               int target = i % rounddown_pow_of_two(dev->queue_count - 1);
+               dev->queues[i + 1] = dev->queues[target + 1];
+       }
+
+       return 0;
+}
+
+static void nvme_free_queues(struct nvme_dev *dev)
+{
+       int i;
+
+       for (i = dev->queue_count - 1; i >= 0; i--)
+               nvme_free_queue(dev, i);
+}
+
+static int __devinit nvme_dev_add(struct nvme_dev *dev)
+{
+       int res, nn, i;
+       struct nvme_ns *ns, *next;
+       struct nvme_id_ctrl *ctrl;
+       struct nvme_id_ns *id_ns;
+       void *mem;
+       dma_addr_t dma_addr;
+
+       res = nvme_setup_io_queues(dev);
+       if (res)
+               return res;
+
+       mem = dma_alloc_coherent(&dev->pci_dev->dev, 8192, &dma_addr,
+                                                               GFP_KERNEL);
+
+       res = nvme_identify(dev, 0, 1, dma_addr);
+       if (res) {
+               res = -EIO;
+               goto out_free;
+       }
+
+       ctrl = mem;
+       nn = le32_to_cpup(&ctrl->nn);
+       memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn));
+       memcpy(dev->model, ctrl->mn, sizeof(ctrl->mn));
+       memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr));
+
+       id_ns = mem;
+       for (i = 1; i <= nn; i++) {
+               res = nvme_identify(dev, i, 0, dma_addr);
+               if (res)
+                       continue;
+
+               if (id_ns->ncap == 0)
+                       continue;
+
+               res = nvme_get_features(dev, NVME_FEAT_LBA_RANGE, i,
+                                                       dma_addr + 4096);
+               if (res)
+                       continue;
+
+               ns = nvme_alloc_ns(dev, i, mem, mem + 4096);
+               if (ns)
+                       list_add_tail(&ns->list, &dev->namespaces);
+       }
+       list_for_each_entry(ns, &dev->namespaces, list)
+               add_disk(ns->disk);
+
+       goto out;
+
+ out_free:
+       list_for_each_entry_safe(ns, next, &dev->namespaces, list) {
+               list_del(&ns->list);
+               nvme_ns_free(ns);
+       }
+
+ out:
+       dma_free_coherent(&dev->pci_dev->dev, 8192, mem, dma_addr);
+       return res;
+}
+
+static int nvme_dev_remove(struct nvme_dev *dev)
+{
+       struct nvme_ns *ns, *next;
+
+       spin_lock(&dev_list_lock);
+       list_del(&dev->node);
+       spin_unlock(&dev_list_lock);
+
+       /* TODO: wait all I/O finished or cancel them */
+
+       list_for_each_entry_safe(ns, next, &dev->namespaces, list) {
+               list_del(&ns->list);
+               del_gendisk(ns->disk);
+               nvme_ns_free(ns);
+       }
+
+       nvme_free_queues(dev);
+
+       return 0;
+}
+
+static int nvme_setup_prp_pools(struct nvme_dev *dev)
+{
+       struct device *dmadev = &dev->pci_dev->dev;
+       dev->prp_page_pool = dma_pool_create("prp list page", dmadev,
+                                               PAGE_SIZE, PAGE_SIZE, 0);
+       if (!dev->prp_page_pool)
+               return -ENOMEM;
+
+       /* Optimisation for I/Os between 4k and 128k */
+       dev->prp_small_pool = dma_pool_create("prp list 256", dmadev,
+                                               256, 256, 0);
+       if (!dev->prp_small_pool) {
+               dma_pool_destroy(dev->prp_page_pool);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void nvme_release_prp_pools(struct nvme_dev *dev)
+{
+       dma_pool_destroy(dev->prp_page_pool);
+       dma_pool_destroy(dev->prp_small_pool);
+}
+
+/* XXX: Use an ida or something to let remove / add work correctly */
+static void nvme_set_instance(struct nvme_dev *dev)
+{
+       static int instance;
+       dev->instance = instance++;
+}
+
+static void nvme_release_instance(struct nvme_dev *dev)
+{
+}
+
+static int __devinit nvme_probe(struct pci_dev *pdev,
+                                               const struct pci_device_id *id)
+{
+       int bars, result = -ENOMEM;
+       struct nvme_dev *dev;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+       dev->entry = kcalloc(num_possible_cpus(), sizeof(*dev->entry),
+                                                               GFP_KERNEL);
+       if (!dev->entry)
+               goto free;
+       dev->queues = kcalloc(num_possible_cpus() + 1, sizeof(void *),
+                                                               GFP_KERNEL);
+       if (!dev->queues)
+               goto free;
+
+       if (pci_enable_device_mem(pdev))
+               goto free;
+       pci_set_master(pdev);
+       bars = pci_select_bars(pdev, IORESOURCE_MEM);
+       if (pci_request_selected_regions(pdev, bars, "nvme"))
+               goto disable;
+
+       INIT_LIST_HEAD(&dev->namespaces);
+       dev->pci_dev = pdev;
+       pci_set_drvdata(pdev, dev);
+       dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+       dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+       nvme_set_instance(dev);
+       dev->entry[0].vector = pdev->irq;
+
+       result = nvme_setup_prp_pools(dev);
+       if (result)
+               goto disable_msix;
+
+       dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
+       if (!dev->bar) {
+               result = -ENOMEM;
+               goto disable_msix;
+       }
+
+       result = nvme_configure_admin_queue(dev);
+       if (result)
+               goto unmap;
+       dev->queue_count++;
+
+       spin_lock(&dev_list_lock);
+       list_add(&dev->node, &dev_list);
+       spin_unlock(&dev_list_lock);
+
+       result = nvme_dev_add(dev);
+       if (result)
+               goto delete;
+
+       return 0;
+
+ delete:
+       spin_lock(&dev_list_lock);
+       list_del(&dev->node);
+       spin_unlock(&dev_list_lock);
+
+       nvme_free_queues(dev);
+ unmap:
+       iounmap(dev->bar);
+ disable_msix:
+       pci_disable_msix(pdev);
+       nvme_release_instance(dev);
+       nvme_release_prp_pools(dev);
+ disable:
+       pci_disable_device(pdev);
+       pci_release_regions(pdev);
+ free:
+       kfree(dev->queues);
+       kfree(dev->entry);
+       kfree(dev);
+       return result;
+}
+
+static void __devexit nvme_remove(struct pci_dev *pdev)
+{
+       struct nvme_dev *dev = pci_get_drvdata(pdev);
+       nvme_dev_remove(dev);
+       pci_disable_msix(pdev);
+       iounmap(dev->bar);
+       nvme_release_instance(dev);
+       nvme_release_prp_pools(dev);
+       pci_disable_device(pdev);
+       pci_release_regions(pdev);
+       kfree(dev->queues);
+       kfree(dev->entry);
+       kfree(dev);
+}
+
+/* These functions are yet to be implemented */
+#define nvme_error_detected NULL
+#define nvme_dump_registers NULL
+#define nvme_link_reset NULL
+#define nvme_slot_reset NULL
+#define nvme_error_resume NULL
+#define nvme_suspend NULL
+#define nvme_resume NULL
+
+static struct pci_error_handlers nvme_err_handler = {
+       .error_detected = nvme_error_detected,
+       .mmio_enabled   = nvme_dump_registers,
+       .link_reset     = nvme_link_reset,
+       .slot_reset     = nvme_slot_reset,
+       .resume         = nvme_error_resume,
+};
+
+/* Move to pci_ids.h later */
+#define PCI_CLASS_STORAGE_EXPRESS      0x010802
+
+static DEFINE_PCI_DEVICE_TABLE(nvme_id_table) = {
+       { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) },
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, nvme_id_table);
+
+static struct pci_driver nvme_driver = {
+       .name           = "nvme",
+       .id_table       = nvme_id_table,
+       .probe          = nvme_probe,
+       .remove         = __devexit_p(nvme_remove),
+       .suspend        = nvme_suspend,
+       .resume         = nvme_resume,
+       .err_handler    = &nvme_err_handler,
+};
+
+static int __init nvme_init(void)
+{
+       int result = -EBUSY;
+
+       nvme_thread = kthread_run(nvme_kthread, NULL, "nvme");
+       if (IS_ERR(nvme_thread))
+               return PTR_ERR(nvme_thread);
+
+       nvme_major = register_blkdev(nvme_major, "nvme");
+       if (nvme_major <= 0)
+               goto kill_kthread;
+
+       result = pci_register_driver(&nvme_driver);
+       if (result)
+               goto unregister_blkdev;
+       return 0;
+
+ unregister_blkdev:
+       unregister_blkdev(nvme_major, "nvme");
+ kill_kthread:
+       kthread_stop(nvme_thread);
+       return result;
+}
+
+static void __exit nvme_exit(void)
+{
+       pci_unregister_driver(&nvme_driver);
+       unregister_blkdev(nvme_major, "nvme");
+       kthread_stop(nvme_thread);
+}
+
+MODULE_AUTHOR("Matthew Wilcox <willy@linux.intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.8");
+module_init(nvme_init);
+module_exit(nvme_exit);
index ad124525ac23f2d8edd34d80708b9518c177f306..ec64e7f5d1ce6398655aed2b589dd365b39337d2 100644 (file)
@@ -20,9 +20,6 @@
 */
 
 
-/* PARAMETERS */
-static int verbose; /* set this to 1 to see debugging messages and whatnot */
-
 #define BACKPACK_VERSION "2.0.2"
 
 #include <linux/module.h>
@@ -36,6 +33,8 @@ static int verbose; /* set this to 1 to see debugging messages and whatnot */
 #include "ppc6lnx.c"
 #include "paride.h"
 
+/* PARAMETERS */
+static bool verbose; /* set this to 1 to see debugging messages and whatnot */
  
 
 #define PPCSTRUCT(pi) ((Interface *)(pi->private))
index 46b8136c31bbe4aab3bccee9923ca755f6833ea8..ba2b6b5e591084f6ee6951cafb6d941130d6a229 100644 (file)
@@ -144,7 +144,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY};
 static DEFINE_MUTEX(pcd_mutex);
 static DEFINE_SPINLOCK(pcd_lock);
 
-module_param(verbose, bool, 0644);
+module_param(verbose, int, 0644);
 module_param(major, int, 0);
 module_param(name, charp, 0);
 module_param(nice, int, 0);
index 869e7676d46f47abcb1ffe1812efd3316d234f74..831e3ac156e625517df61fb3a1255973ea565ca7 100644 (file)
    by default.
 
 */
+#include <linux/types.h>
 
-static int verbose = 0;
+static bool verbose = 0;
 static int major = PD_MAJOR;
 static char *name = PD_NAME;
 static int cluster = 64;
index f21b520ef4195228713d34c2f2157ce1b928e37d..ec8f9ed6326eca34be8b837ce62aefecc1b4a25a 100644 (file)
 #define PF_NAME                "pf"
 #define PF_UNITS       4
 
+#include <linux/types.h>
+
 /* Here are things one can override from the insmod command.
    Most are autoprobed by paride unless set here.  Verbose is off
    by default.
 
 */
 
-static int verbose = 0;
+static bool verbose = 0;
 static int major = PF_MAJOR;
 static char *name = PF_NAME;
 static int cluster = 64;
index a79fb4f7ff622632809c2b93f47df93fb7561ccb..4a27b1de5fcb9fb0fef805fb51d0d2f1bc418a29 100644 (file)
 #define PI_PG  4
 #endif
 
+#include <linux/types.h>
 /* Here are things one can override from the insmod command.
    Most are autoprobed by paride unless set here.  Verbose is 0
    by default.
 
 */
 
-static int verbose = 0;
+static bool verbose = 0;
 static int major = PG_MAJOR;
 static char *name = PG_NAME;
 static int disable = 0;
index 7179f79d746838f24640ac7c59fadb41a1c5f024..2596042eb987c2d655e56f9f0448e565a843aa34 100644 (file)
 #define PT_NAME                "pt"
 #define PT_UNITS       4
 
+#include <linux/types.h>
+
 /* Here are things one can override from the insmod command.
    Most are autoprobed by paride unless set here.  Verbose is on
    by default.
 
 */
 
-static int verbose = 0;
+static bool verbose = 0;
 static int major = PT_MAJOR;
 static char *name = PT_NAME;
 static int disable = 0;
index 148ab944378d57bdaec596e96bed6dc131777a28..3fd31dec8c9c1980fcdc8f7aa95b28d23addcb5b 100644 (file)
@@ -2184,6 +2184,8 @@ static ssize_t rbd_add(struct bus_type *bus,
        INIT_LIST_HEAD(&rbd_dev->node);
        INIT_LIST_HEAD(&rbd_dev->snaps);
 
+       init_rwsem(&rbd_dev->header.snap_rwsem);
+
        /* generate unique id: find highest unique id, add one */
        mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
 
index b70f0fca9a42e724e3911d62cd64729a2f20ce4b..e7472f567c9de7bb640bf1cc5b56e51b7cf88471 100644 (file)
@@ -619,8 +619,10 @@ static int carm_array_info (struct carm_host *host, unsigned int array_idx)
               host->state == HST_DEV_SCAN);
        spin_unlock_irq(&host->lock);
 
-       DPRINTK("blk_insert_request, tag == %u\n", idx);
-       blk_insert_request(host->oob_q, crq->rq, 1, crq);
+       DPRINTK("blk_execute_rq_nowait, tag == %u\n", idx);
+       crq->rq->cmd_type = REQ_TYPE_SPECIAL;
+       crq->rq->special = crq;
+       blk_execute_rq_nowait(host->oob_q, NULL, crq->rq, true, NULL);
 
        return 0;
 
@@ -658,8 +660,10 @@ static int carm_send_special (struct carm_host *host, carm_sspc_t func)
        BUG_ON(rc < 0);
        crq->msg_bucket = (u32) rc;
 
-       DPRINTK("blk_insert_request, tag == %u\n", idx);
-       blk_insert_request(host->oob_q, crq->rq, 1, crq);
+       DPRINTK("blk_execute_rq_nowait, tag == %u\n", idx);
+       crq->rq->cmd_type = REQ_TYPE_SPECIAL;
+       crq->rq->special = crq;
+       blk_execute_rq_nowait(host->oob_q, NULL, crq->rq, true, NULL);
 
        return 0;
 }
index 0e376d46bdd1d6f73a61583882eec6faa654a832..7333b9e444113c9e2945cdcd99997c4fd3592275 100644 (file)
@@ -1744,12 +1744,11 @@ static int ub_bd_release(struct gendisk *disk, fmode_t mode)
 static int ub_bd_ioctl(struct block_device *bdev, fmode_t mode,
     unsigned int cmd, unsigned long arg)
 {
-       struct gendisk *disk = bdev->bd_disk;
        void __user *usermem = (void __user *) arg;
        int ret;
 
        mutex_lock(&ub_mutex);
-       ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, usermem);
+       ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, usermem);
        mutex_unlock(&ub_mutex);
 
        return ret;
index 4d0b70adf5f73356bb79fafc06927b5f33207a64..c4a60badf252caee7bffff38cc0cf115d0bd81a4 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/virtio.h>
 #include <linux/virtio_blk.h>
 #include <linux/scatterlist.h>
@@ -36,6 +37,12 @@ struct virtio_blk
        /* Process context for config space updates */
        struct work_struct config_work;
 
+       /* Lock for config space updates */
+       struct mutex config_lock;
+
+       /* enable config space updates */
+       bool config_enable;
+
        /* What host tells us, plus 2 for header & tailer. */
        unsigned int sg_elems;
 
@@ -172,7 +179,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
                }
        }
 
-       if (virtqueue_add_buf(vblk->vq, vblk->sg, out, in, vbr) < 0) {
+       if (virtqueue_add_buf(vblk->vq, vblk->sg, out, in, vbr, GFP_ATOMIC)<0) {
                mempool_free(vbr, vblk->pool);
                return false;
        }
@@ -243,8 +250,8 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
        if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI))
                return -ENOTTY;
 
-       return scsi_cmd_ioctl(disk->queue, disk, mode, cmd,
-                             (void __user *)data);
+       return scsi_cmd_blk_ioctl(bdev, mode, cmd,
+                                 (void __user *)data);
 }
 
 /* We provide getgeo only to please some old bootloader/partitioning tools */
@@ -318,6 +325,10 @@ static void virtblk_config_changed_work(struct work_struct *work)
        char cap_str_2[10], cap_str_10[10];
        u64 capacity, size;
 
+       mutex_lock(&vblk->config_lock);
+       if (!vblk->config_enable)
+               goto done;
+
        /* Host must always specify the capacity. */
        vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
                          &capacity, sizeof(capacity));
@@ -340,6 +351,8 @@ static void virtblk_config_changed_work(struct work_struct *work)
                  cap_str_10, cap_str_2);
 
        set_capacity(vblk->disk, capacity);
+done:
+       mutex_unlock(&vblk->config_lock);
 }
 
 static void virtblk_config_changed(struct virtio_device *vdev)
@@ -349,6 +362,18 @@ static void virtblk_config_changed(struct virtio_device *vdev)
        queue_work(virtblk_wq, &vblk->config_work);
 }
 
+static int init_vq(struct virtio_blk *vblk)
+{
+       int err = 0;
+
+       /* We expect one virtqueue, for output. */
+       vblk->vq = virtio_find_single_vq(vblk->vdev, blk_done, "requests");
+       if (IS_ERR(vblk->vq))
+               err = PTR_ERR(vblk->vq);
+
+       return err;
+}
+
 static int __devinit virtblk_probe(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk;
@@ -388,14 +413,13 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
        vblk->vdev = vdev;
        vblk->sg_elems = sg_elems;
        sg_init_table(vblk->sg, vblk->sg_elems);
+       mutex_init(&vblk->config_lock);
        INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
+       vblk->config_enable = true;
 
-       /* We expect one virtqueue, for output. */
-       vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests");
-       if (IS_ERR(vblk->vq)) {
-               err = PTR_ERR(vblk->vq);
+       err = init_vq(vblk);
+       if (err)
                goto out_free_vblk;
-       }
 
        vblk->pool = mempool_create_kmalloc_pool(1,sizeof(struct virtblk_req));
        if (!vblk->pool) {
@@ -542,7 +566,10 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
        struct virtio_blk *vblk = vdev->priv;
        int index = vblk->index;
 
-       flush_work(&vblk->config_work);
+       /* Prevent config work handler from accessing the device. */
+       mutex_lock(&vblk->config_lock);
+       vblk->config_enable = false;
+       mutex_unlock(&vblk->config_lock);
 
        /* Nothing should be pending. */
        BUG_ON(!list_empty(&vblk->reqs));
@@ -550,6 +577,8 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
        /* Stop all the virtqueues. */
        vdev->config->reset(vdev);
 
+       flush_work(&vblk->config_work);
+
        del_gendisk(vblk->disk);
        blk_cleanup_queue(vblk->disk->queue);
        put_disk(vblk->disk);
@@ -559,6 +588,46 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
        ida_simple_remove(&vd_index_ida, index);
 }
 
+#ifdef CONFIG_PM
+static int virtblk_freeze(struct virtio_device *vdev)
+{
+       struct virtio_blk *vblk = vdev->priv;
+
+       /* Ensure we don't receive any more interrupts */
+       vdev->config->reset(vdev);
+
+       /* Prevent config work handler from accessing the device. */
+       mutex_lock(&vblk->config_lock);
+       vblk->config_enable = false;
+       mutex_unlock(&vblk->config_lock);
+
+       flush_work(&vblk->config_work);
+
+       spin_lock_irq(vblk->disk->queue->queue_lock);
+       blk_stop_queue(vblk->disk->queue);
+       spin_unlock_irq(vblk->disk->queue->queue_lock);
+       blk_sync_queue(vblk->disk->queue);
+
+       vdev->config->del_vqs(vdev);
+       return 0;
+}
+
+static int virtblk_restore(struct virtio_device *vdev)
+{
+       struct virtio_blk *vblk = vdev->priv;
+       int ret;
+
+       vblk->config_enable = true;
+       ret = init_vq(vdev->priv);
+       if (!ret) {
+               spin_lock_irq(vblk->disk->queue->queue_lock);
+               blk_start_queue(vblk->disk->queue);
+               spin_unlock_irq(vblk->disk->queue->queue_lock);
+       }
+       return ret;
+}
+#endif
+
 static const struct virtio_device_id id_table[] = {
        { VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
        { 0 },
@@ -584,6 +653,10 @@ static struct virtio_driver __refdata virtio_blk = {
        .probe                  = virtblk_probe,
        .remove                 = __devexit_p(virtblk_remove),
        .config_changed         = virtblk_config_changed,
+#ifdef CONFIG_PM
+       .freeze                 = virtblk_freeze,
+       .restore                = virtblk_restore,
+#endif
 };
 
 static int __init init(void)
index 4abd2bcd20fb8b069362e2684c8eed2dcd6a0620..51a972704db503932d39e9ab917480af232bf4ce 100644 (file)
@@ -148,7 +148,7 @@ static volatile int xdc_busy;
 static struct timer_list xd_watchdog_int;
 
 static volatile u_char xd_error;
-static int nodma = XD_DONT_USE_DMA;
+static bool nodma = XD_DONT_USE_DMA;
 
 static struct request_queue *xd_queue;
 
index 15ec4db194d1bb793e4409dfed54563e4b71b080..0088bf60f3689db6a704c1856c4f94a682d7db44 100644 (file)
@@ -39,9 +39,6 @@
 #include <linux/list.h>
 #include <linux/delay.h>
 #include <linux/freezer.h>
-#include <linux/loop.h>
-#include <linux/falloc.h>
-#include <linux/fs.h>
 
 #include <xen/events.h>
 #include <xen/page.h>
@@ -362,7 +359,7 @@ static int xen_blkbk_map(struct blkif_request *req,
 {
        struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        int i;
-       int nseg = req->nr_segments;
+       int nseg = req->u.rw.nr_segments;
        int ret = 0;
 
        /*
@@ -416,30 +413,25 @@ static int xen_blkbk_map(struct blkif_request *req,
        return ret;
 }
 
-static void xen_blk_discard(struct xen_blkif *blkif, struct blkif_request *req)
+static int dispatch_discard_io(struct xen_blkif *blkif,
+                               struct blkif_request *req)
 {
        int err = 0;
        int status = BLKIF_RSP_OKAY;
        struct block_device *bdev = blkif->vbd.bdev;
 
-       if (blkif->blk_backend_type == BLKIF_BACKEND_PHY)
-               /* just forward the discard request */
+       blkif->st_ds_req++;
+
+       xen_blkif_get(blkif);
+       if (blkif->blk_backend_type == BLKIF_BACKEND_PHY ||
+           blkif->blk_backend_type == BLKIF_BACKEND_FILE) {
+               unsigned long secure = (blkif->vbd.discard_secure &&
+                       (req->u.discard.flag & BLKIF_DISCARD_SECURE)) ?
+                       BLKDEV_DISCARD_SECURE : 0;
                err = blkdev_issue_discard(bdev,
                                req->u.discard.sector_number,
                                req->u.discard.nr_sectors,
-                               GFP_KERNEL, 0);
-       else if (blkif->blk_backend_type == BLKIF_BACKEND_FILE) {
-               /* punch a hole in the backing file */
-               struct loop_device *lo = bdev->bd_disk->private_data;
-               struct file *file = lo->lo_backing_file;
-
-               if (file->f_op->fallocate)
-                       err = file->f_op->fallocate(file,
-                               FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
-                               req->u.discard.sector_number << 9,
-                               req->u.discard.nr_sectors << 9);
-               else
-                       err = -EOPNOTSUPP;
+                               GFP_KERNEL, secure);
        } else
                err = -EOPNOTSUPP;
 
@@ -449,7 +441,9 @@ static void xen_blk_discard(struct xen_blkif *blkif, struct blkif_request *req)
        } else if (err)
                status = BLKIF_RSP_ERROR;
 
-       make_response(blkif, req->id, req->operation, status);
+       make_response(blkif, req->u.discard.id, req->operation, status);
+       xen_blkif_put(blkif);
+       return err;
 }
 
 static void xen_blk_drain_io(struct xen_blkif *blkif)
@@ -573,8 +567,11 @@ __do_block_io_op(struct xen_blkif *blkif)
 
                /* Apply all sanity checks to /private copy/ of request. */
                barrier();
-
-               if (dispatch_rw_block_io(blkif, &req, pending_req))
+               if (unlikely(req.operation == BLKIF_OP_DISCARD)) {
+                       free_req(pending_req);
+                       if (dispatch_discard_io(blkif, &req))
+                               break;
+               } else if (dispatch_rw_block_io(blkif, &req, pending_req))
                        break;
 
                /* Yield point for this unbounded loop. */
@@ -633,10 +630,6 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
                blkif->st_f_req++;
                operation = WRITE_FLUSH;
                break;
-       case BLKIF_OP_DISCARD:
-               blkif->st_ds_req++;
-               operation = REQ_DISCARD;
-               break;
        default:
                operation = 0; /* make gcc happy */
                goto fail_response;
@@ -644,9 +637,9 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
        }
 
        /* Check that the number of segments is sane. */
-       nseg = req->nr_segments;
-       if (unlikely(nseg == 0 && operation != WRITE_FLUSH &&
-                               operation != REQ_DISCARD) ||
+       nseg = req->u.rw.nr_segments;
+
+       if (unlikely(nseg == 0 && operation != WRITE_FLUSH) ||
            unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
                pr_debug(DRV_PFX "Bad number of segments in request (%d)\n",
                         nseg);
@@ -654,12 +647,12 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
                goto fail_response;
        }
 
-       preq.dev           = req->handle;
+       preq.dev           = req->u.rw.handle;
        preq.sector_number = req->u.rw.sector_number;
        preq.nr_sects      = 0;
 
        pending_req->blkif     = blkif;
-       pending_req->id        = req->id;
+       pending_req->id        = req->u.rw.id;
        pending_req->operation = req->operation;
        pending_req->status    = BLKIF_RSP_OKAY;
        pending_req->nr_pages  = nseg;
@@ -707,7 +700,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
         * the hypercall to unmap the grants - that is all done in
         * xen_blkbk_unmap.
         */
-       if (operation != REQ_DISCARD && xen_blkbk_map(req, pending_req, seg))
+       if (xen_blkbk_map(req, pending_req, seg))
                goto fail_flush;
 
        /*
@@ -739,23 +732,16 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
 
        /* This will be hit if the operation was a flush or discard. */
        if (!bio) {
-               BUG_ON(operation != WRITE_FLUSH && operation != REQ_DISCARD);
+               BUG_ON(operation != WRITE_FLUSH);
 
-               if (operation == WRITE_FLUSH) {
-                       bio = bio_alloc(GFP_KERNEL, 0);
-                       if (unlikely(bio == NULL))
-                               goto fail_put_bio;
+               bio = bio_alloc(GFP_KERNEL, 0);
+               if (unlikely(bio == NULL))
+                       goto fail_put_bio;
 
-                       biolist[nbio++] = bio;
-                       bio->bi_bdev    = preq.bdev;
-                       bio->bi_private = pending_req;
-                       bio->bi_end_io  = end_block_io_op;
-               } else if (operation == REQ_DISCARD) {
-                       xen_blk_discard(blkif, req);
-                       xen_blkif_put(blkif);
-                       free_req(pending_req);
-                       return 0;
-               }
+               biolist[nbio++] = bio;
+               bio->bi_bdev    = preq.bdev;
+               bio->bi_private = pending_req;
+               bio->bi_end_io  = end_block_io_op;
        }
 
        /*
@@ -784,7 +770,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
        xen_blkbk_unmap(pending_req);
  fail_response:
        /* Haven't submitted any bio's yet. */
-       make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
+       make_response(blkif, req->u.rw.id, req->operation, BLKIF_RSP_ERROR);
        free_req(pending_req);
        msleep(1); /* back off a bit */
        return -EIO;
index dfb1b3a43a5ddc2edbe9310a1ab43af40a71c117..d0ee7edc9be8ad1819a91a491eb907f18d545fbf 100644 (file)
@@ -60,58 +60,66 @@ struct blkif_common_response {
        char dummy;
 };
 
-/* i386 protocol version */
-#pragma pack(push, 4)
-
 struct blkif_x86_32_request_rw {
+       uint8_t        nr_segments;  /* number of segments                   */
+       blkif_vdev_t   handle;       /* only for read/write requests         */
+       uint64_t       id;           /* private guest value, echoed in resp  */
        blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
        struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-};
+} __attribute__((__packed__));
 
 struct blkif_x86_32_request_discard {
+       uint8_t        flag;         /* BLKIF_DISCARD_SECURE or zero         */
+       blkif_vdev_t   _pad1;        /* was "handle" for read/write requests */
+       uint64_t       id;           /* private guest value, echoed in resp  */
        blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
-       uint64_t nr_sectors;
-};
+       uint64_t       nr_sectors;
+} __attribute__((__packed__));
 
 struct blkif_x86_32_request {
        uint8_t        operation;    /* BLKIF_OP_???                         */
-       uint8_t        nr_segments;  /* number of segments                   */
-       blkif_vdev_t   handle;       /* only for read/write requests         */
-       uint64_t       id;           /* private guest value, echoed in resp  */
        union {
                struct blkif_x86_32_request_rw rw;
                struct blkif_x86_32_request_discard discard;
        } u;
-};
+} __attribute__((__packed__));
+
+/* i386 protocol version */
+#pragma pack(push, 4)
 struct blkif_x86_32_response {
        uint64_t        id;              /* copied from request */
        uint8_t         operation;       /* copied from request */
        int16_t         status;          /* BLKIF_RSP_???       */
 };
 #pragma pack(pop)
-
 /* x86_64 protocol version */
 
 struct blkif_x86_64_request_rw {
+       uint8_t        nr_segments;  /* number of segments                   */
+       blkif_vdev_t   handle;       /* only for read/write requests         */
+       uint32_t       _pad1;        /* offsetof(blkif_reqest..,u.rw.id)==8  */
+       uint64_t       id;
        blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
        struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-};
+} __attribute__((__packed__));
 
 struct blkif_x86_64_request_discard {
+       uint8_t        flag;         /* BLKIF_DISCARD_SECURE or zero         */
+       blkif_vdev_t   _pad1;        /* was "handle" for read/write requests */
+        uint32_t       _pad2;        /* offsetof(blkif_..,u.discard.id)==8   */
+       uint64_t       id;
        blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
-       uint64_t nr_sectors;
-};
+       uint64_t       nr_sectors;
+} __attribute__((__packed__));
 
 struct blkif_x86_64_request {
        uint8_t        operation;    /* BLKIF_OP_???                         */
-       uint8_t        nr_segments;  /* number of segments                   */
-       blkif_vdev_t   handle;       /* only for read/write requests         */
-       uint64_t       __attribute__((__aligned__(8))) id;
        union {
                struct blkif_x86_64_request_rw rw;
                struct blkif_x86_64_request_discard discard;
        } u;
-};
+} __attribute__((__packed__));
+
 struct blkif_x86_64_response {
        uint64_t       __attribute__((__aligned__(8))) id;
        uint8_t         operation;       /* copied from request */
@@ -156,6 +164,7 @@ struct xen_vbd {
        /* Cached size parameter. */
        sector_t                size;
        bool                    flush_support;
+       bool                    discard_secure;
 };
 
 struct backend_info;
@@ -237,22 +246,23 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst,
 {
        int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
        dst->operation = src->operation;
-       dst->nr_segments = src->nr_segments;
-       dst->handle = src->handle;
-       dst->id = src->id;
        switch (src->operation) {
        case BLKIF_OP_READ:
        case BLKIF_OP_WRITE:
        case BLKIF_OP_WRITE_BARRIER:
        case BLKIF_OP_FLUSH_DISKCACHE:
+               dst->u.rw.nr_segments = src->u.rw.nr_segments;
+               dst->u.rw.handle = src->u.rw.handle;
+               dst->u.rw.id = src->u.rw.id;
                dst->u.rw.sector_number = src->u.rw.sector_number;
                barrier();
-               if (n > dst->nr_segments)
-                       n = dst->nr_segments;
+               if (n > dst->u.rw.nr_segments)
+                       n = dst->u.rw.nr_segments;
                for (i = 0; i < n; i++)
                        dst->u.rw.seg[i] = src->u.rw.seg[i];
                break;
        case BLKIF_OP_DISCARD:
+               dst->u.discard.flag = src->u.discard.flag;
                dst->u.discard.sector_number = src->u.discard.sector_number;
                dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
                break;
@@ -266,22 +276,23 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst,
 {
        int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
        dst->operation = src->operation;
-       dst->nr_segments = src->nr_segments;
-       dst->handle = src->handle;
-       dst->id = src->id;
        switch (src->operation) {
        case BLKIF_OP_READ:
        case BLKIF_OP_WRITE:
        case BLKIF_OP_WRITE_BARRIER:
        case BLKIF_OP_FLUSH_DISKCACHE:
+               dst->u.rw.nr_segments = src->u.rw.nr_segments;
+               dst->u.rw.handle = src->u.rw.handle;
+               dst->u.rw.id = src->u.rw.id;
                dst->u.rw.sector_number = src->u.rw.sector_number;
                barrier();
-               if (n > dst->nr_segments)
-                       n = dst->nr_segments;
+               if (n > dst->u.rw.nr_segments)
+                       n = dst->u.rw.nr_segments;
                for (i = 0; i < n; i++)
                        dst->u.rw.seg[i] = src->u.rw.seg[i];
                break;
        case BLKIF_OP_DISCARD:
+               dst->u.discard.flag = src->u.discard.flag;
                dst->u.discard.sector_number = src->u.discard.sector_number;
                dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
                break;
index 37c794d312644d30430446d32e3ed844565cc362..24a2fb57e5d012d57c5d3e1fc1929f27ac3998ee 100644 (file)
@@ -338,6 +338,9 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
        if (q && q->flush_flags)
                vbd->flush_support = true;
 
+       if (q && blk_queue_secdiscard(q))
+               vbd->discard_secure = true;
+
        DPRINTK("Successful creation of handle=%04x (dom=%u)\n",
                handle, blkif->domid);
        return 0;
@@ -420,6 +423,15 @@ int xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be)
                                state = 1;
                                blkif->blk_backend_type = BLKIF_BACKEND_PHY;
                        }
+                       /* Optional. */
+                       err = xenbus_printf(xbt, dev->nodename,
+                               "discard-secure", "%d",
+                               blkif->vbd.discard_secure);
+                       if (err) {
+                               xenbus_dev_fatal(dev, err,
+                                       "writting discard-secure");
+                               goto kfree;
+                       }
                }
        } else {
                err = PTR_ERR(type);
index 9fd3ee203b1e7b5e450c3e32737e61a64f9cc6b1..2f22874c0a374df53ef5f264b42901ac3fc15979 100644 (file)
@@ -98,7 +98,8 @@ struct blkfront_info
        unsigned long shadow_free;
        unsigned int feature_flush;
        unsigned int flush_op;
-       unsigned int feature_discard;
+       unsigned int feature_discard:1;
+       unsigned int feature_secdiscard:1;
        unsigned int discard_granularity;
        unsigned int discard_alignment;
        int is_ready;
@@ -135,15 +136,15 @@ static int get_id_from_freelist(struct blkfront_info *info)
 {
        unsigned long free = info->shadow_free;
        BUG_ON(free >= BLK_RING_SIZE);
-       info->shadow_free = info->shadow[free].req.id;
-       info->shadow[free].req.id = 0x0fffffee; /* debug */
+       info->shadow_free = info->shadow[free].req.u.rw.id;
+       info->shadow[free].req.u.rw.id = 0x0fffffee; /* debug */
        return free;
 }
 
 static void add_id_to_freelist(struct blkfront_info *info,
                               unsigned long id)
 {
-       info->shadow[id].req.id  = info->shadow_free;
+       info->shadow[id].req.u.rw.id  = info->shadow_free;
        info->shadow[id].request = NULL;
        info->shadow_free = id;
 }
@@ -156,7 +157,7 @@ static int xlbd_reserve_minors(unsigned int minor, unsigned int nr)
        if (end > nr_minors) {
                unsigned long *bitmap, *old;
 
-               bitmap = kzalloc(BITS_TO_LONGS(end) * sizeof(*bitmap),
+               bitmap = kcalloc(BITS_TO_LONGS(end), sizeof(*bitmap),
                                 GFP_KERNEL);
                if (bitmap == NULL)
                        return -ENOMEM;
@@ -287,9 +288,9 @@ static int blkif_queue_request(struct request *req)
        id = get_id_from_freelist(info);
        info->shadow[id].request = req;
 
-       ring_req->id = id;
+       ring_req->u.rw.id = id;
        ring_req->u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req);
-       ring_req->handle = info->handle;
+       ring_req->u.rw.handle = info->handle;
 
        ring_req->operation = rq_data_dir(req) ?
                BLKIF_OP_WRITE : BLKIF_OP_READ;
@@ -305,16 +306,21 @@ static int blkif_queue_request(struct request *req)
                ring_req->operation = info->flush_op;
        }
 
-       if (unlikely(req->cmd_flags & REQ_DISCARD)) {
+       if (unlikely(req->cmd_flags & (REQ_DISCARD | REQ_SECURE))) {
                /* id, sector_number and handle are set above. */
                ring_req->operation = BLKIF_OP_DISCARD;
-               ring_req->nr_segments = 0;
                ring_req->u.discard.nr_sectors = blk_rq_sectors(req);
+               if ((req->cmd_flags & REQ_SECURE) && info->feature_secdiscard)
+                       ring_req->u.discard.flag = BLKIF_DISCARD_SECURE;
+               else
+                       ring_req->u.discard.flag = 0;
        } else {
-               ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg);
-               BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST);
+               ring_req->u.rw.nr_segments = blk_rq_map_sg(req->q, req,
+                                                          info->sg);
+               BUG_ON(ring_req->u.rw.nr_segments >
+                      BLKIF_MAX_SEGMENTS_PER_REQUEST);
 
-               for_each_sg(info->sg, sg, ring_req->nr_segments, i) {
+               for_each_sg(info->sg, sg, ring_req->u.rw.nr_segments, i) {
                        buffer_mfn = pfn_to_mfn(page_to_pfn(sg_page(sg)));
                        fsect = sg->offset >> 9;
                        lsect = fsect + (sg->length >> 9) - 1;
@@ -424,6 +430,8 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
                blk_queue_max_discard_sectors(rq, get_capacity(gd));
                rq->limits.discard_granularity = info->discard_granularity;
                rq->limits.discard_alignment = info->discard_alignment;
+               if (info->feature_secdiscard)
+                       queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, rq);
        }
 
        /* Hard sector size and max sectors impersonate the equiv. hardware. */
@@ -705,7 +713,9 @@ static void blkif_free(struct blkfront_info *info, int suspend)
 static void blkif_completion(struct blk_shadow *s)
 {
        int i;
-       for (i = 0; i < s->req.nr_segments; i++)
+       /* Do not let BLKIF_OP_DISCARD as nr_segment is in the same place
+        * flag. */
+       for (i = 0; i < s->req.u.rw.nr_segments; i++)
                gnttab_end_foreign_access(s->req.u.rw.seg[i].gref, 0, 0UL);
 }
 
@@ -736,7 +746,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
                id   = bret->id;
                req  = info->shadow[id].request;
 
-               blkif_completion(&info->shadow[id]);
+               if (bret->operation != BLKIF_OP_DISCARD)
+                       blkif_completion(&info->shadow[id]);
 
                add_id_to_freelist(info, id);
 
@@ -749,7 +760,9 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
                                           info->gd->disk_name);
                                error = -EOPNOTSUPP;
                                info->feature_discard = 0;
+                               info->feature_secdiscard = 0;
                                queue_flag_clear(QUEUE_FLAG_DISCARD, rq);
+                               queue_flag_clear(QUEUE_FLAG_SECDISCARD, rq);
                        }
                        __blk_end_request_all(req, error);
                        break;
@@ -763,7 +776,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
                                error = -EOPNOTSUPP;
                        }
                        if (unlikely(bret->status == BLKIF_RSP_ERROR &&
-                                    info->shadow[id].req.nr_segments == 0)) {
+                                    info->shadow[id].req.u.rw.nr_segments == 0)) {
                                printk(KERN_WARNING "blkfront: %s: empty write %s op failed\n",
                                       info->flush_op == BLKIF_OP_WRITE_BARRIER ?
                                       "barrier" :  "flush disk cache",
@@ -984,8 +997,8 @@ static int blkfront_probe(struct xenbus_device *dev,
        INIT_WORK(&info->work, blkif_restart_queue);
 
        for (i = 0; i < BLK_RING_SIZE; i++)
-               info->shadow[i].req.id = i+1;
-       info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+               info->shadow[i].req.u.rw.id = i+1;
+       info->shadow[BLK_RING_SIZE-1].req.u.rw.id = 0x0fffffff;
 
        /* Front end dir is a number, which is used as the id. */
        info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0);
@@ -1019,9 +1032,9 @@ static int blkif_recover(struct blkfront_info *info)
        /* Stage 2: Set up free list. */
        memset(&info->shadow, 0, sizeof(info->shadow));
        for (i = 0; i < BLK_RING_SIZE; i++)
-               info->shadow[i].req.id = i+1;
+               info->shadow[i].req.u.rw.id = i+1;
        info->shadow_free = info->ring.req_prod_pvt;
-       info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+       info->shadow[BLK_RING_SIZE-1].req.u.rw.id = 0x0fffffff;
 
        /* Stage 3: Find pending requests and requeue them. */
        for (i = 0; i < BLK_RING_SIZE; i++) {
@@ -1034,17 +1047,19 @@ static int blkif_recover(struct blkfront_info *info)
                *req = copy[i].req;
 
                /* We get a new request id, and must reset the shadow state. */
-               req->id = get_id_from_freelist(info);
-               memcpy(&info->shadow[req->id], &copy[i], sizeof(copy[i]));
+               req->u.rw.id = get_id_from_freelist(info);
+               memcpy(&info->shadow[req->u.rw.id], &copy[i], sizeof(copy[i]));
 
+               if (req->operation != BLKIF_OP_DISCARD) {
                /* Rewrite any grant references invalidated by susp/resume. */
-               for (j = 0; j < req->nr_segments; j++)
-                       gnttab_grant_foreign_access_ref(
-                               req->u.rw.seg[j].gref,
-                               info->xbdev->otherend_id,
-                               pfn_to_mfn(info->shadow[req->id].frame[j]),
-                               rq_data_dir(info->shadow[req->id].request));
-               info->shadow[req->id].req = *req;
+                       for (j = 0; j < req->u.rw.nr_segments; j++)
+                               gnttab_grant_foreign_access_ref(
+                                       req->u.rw.seg[j].gref,
+                                       info->xbdev->otherend_id,
+                                       pfn_to_mfn(info->shadow[req->u.rw.id].frame[j]),
+                                       rq_data_dir(info->shadow[req->u.rw.id].request));
+               }
+               info->shadow[req->u.rw.id].req = *req;
 
                info->ring.req_prod_pvt++;
        }
@@ -1135,11 +1150,13 @@ static void blkfront_setup_discard(struct blkfront_info *info)
        char *type;
        unsigned int discard_granularity;
        unsigned int discard_alignment;
+       unsigned int discard_secure;
 
        type = xenbus_read(XBT_NIL, info->xbdev->otherend, "type", NULL);
        if (IS_ERR(type))
                return;
 
+       info->feature_secdiscard = 0;
        if (strncmp(type, "phy", 3) == 0) {
                err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
                        "discard-granularity", "%u", &discard_granularity,
@@ -1150,6 +1167,12 @@ static void blkfront_setup_discard(struct blkfront_info *info)
                        info->discard_granularity = discard_granularity;
                        info->discard_alignment = discard_alignment;
                }
+               err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                           "discard-secure", "%d", &discard_secure,
+                           NULL);
+               if (!err)
+                       info->feature_secdiscard = discard_secure;
+
        } else if (strncmp(type, "file", 4) == 0)
                info->feature_discard = 1;
 
index 55ac349695c48c147c5377030fe41254e9fd8ec8..f00f596c102997c8b32c48d4e41007eeae9a99a4 100644 (file)
 
 #define VERSION "0.6"
 
-static int ignore_dga;
-static int ignore_csr;
-static int ignore_sniffer;
-static int disable_scofix;
-static int force_scofix;
+static bool ignore_dga;
+static bool ignore_csr;
+static bool ignore_sniffer;
+static bool disable_scofix;
+static bool force_scofix;
 
-static int reset = 1;
+static bool reset = 1;
 
 static struct usb_driver btusb_driver;
 
index 9c5b2dc38e29455884618b4dfb5c8256d5fa5496..a767d4de45a4177d7fbc213f6f5edbcb42ae21c2 100644 (file)
@@ -49,8 +49,8 @@
 
 #define VERSION "0.3"
 
-static int txcrc = 1;
-static int hciextn = 1;
+static bool txcrc = 1;
+static bool hciextn = 1;
 
 #define BCSP_TXWINSIZE 4
 
index 48ad2a7ab080ba9a58c425da7cc959dba0e1e3de..07114489994f5f383f4aef45c38cca72b38b52f9 100644 (file)
@@ -48,7 +48,7 @@
 
 #define VERSION "2.2"
 
-static int reset = 0;
+static bool reset = 0;
 
 static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
 
index 2118211aff99835e457f266a10caeed72de7c110..55eaf474d32c3afa18aab0433552edc4dc193f6f 100644 (file)
 #include <asm/uaccess.h>
 
 /* used to tell the module to turn on full debugging messages */
-static int debug;
+static bool debug;
 /* used to keep tray locked at all times */
 static int keeplocked;
 /* default compatibility mode */
-static int autoclose=1;
-static int autoeject;
-static int lockdoor = 1;
+static bool autoclose=1;
+static bool autoeject;
+static bool lockdoor = 1;
 /* will we ever get to use this... sigh. */
-static int check_media_type;
+static bool check_media_type;
 /* automatically restart mrw format */
-static int mrw_format_restart = 1;
+static bool mrw_format_restart = 1;
 module_param(debug, bool, 0);
 module_param(autoclose, bool, 0);
 module_param(autoeject, bool, 0);
@@ -2746,12 +2746,11 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,
 {
        void __user *argp = (void __user *)arg;
        int ret;
-       struct gendisk *disk = bdev->bd_disk;
 
        /*
         * Try the generic SCSI command ioctl's first.
         */
-       ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp);
+       ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
        if (ret != -ENOTTY)
                return ret;
 
index 780498d765811db559d8bae1108357704490bf40..444f8b6ab41104003d94e7d510c3f89af02ecfce 100644 (file)
@@ -33,7 +33,7 @@
 #define ULI_X86_64_ENU_SCR_REG         0x54
 
 static struct resource *aperture_resource;
-static int __initdata agp_try_unsupported = 1;
+static bool __initdata agp_try_unsupported = 1;
 static int agp_bridges_found;
 
 static void amd64_tlbflush(struct agp_memory *temp)
index 29aacd81de78184d9b3d85d203465ad82476d0b3..08704ae539566fa8c337b9dbaa34c31654ff0a8c 100644 (file)
@@ -17,7 +17,7 @@
 #define PCI_DEVICE_ID_SI_662   0x0662
 #define PCI_DEVICE_ID_SI_671   0x0671
 
-static int __devinitdata agp_sis_force_delay = 0;
+static bool __devinitdata agp_sis_force_delay = 0;
 static int __devinitdata agp_sis_agp_spec = -1;
 
 static int sis_fetch_size(void)
index fd699ccecf5b83efb694734ef5a137c8d20a2217..723725bbb96b774036f9fee05562b207d1cecfc0 100644 (file)
@@ -47,7 +47,7 @@ static void register_buffer(u8 *buf, size_t size)
        sg_init_one(&sg, buf, size);
 
        /* There should always be room for one buffer. */
-       if (virtqueue_add_buf(vq, &sg, 0, 1, buf) < 0)
+       if (virtqueue_add_buf(vq, &sg, 0, 1, buf, GFP_KERNEL) < 0)
                BUG();
 
        virtqueue_kick(vq);
index 6e40072fbf675e3c69b105cc8ea1d05491bba485..40cc0cf2ded639f6b4e3f28cfb1b093660c19ae1 100644 (file)
@@ -69,19 +69,19 @@ MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
 MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
 MODULE_LICENSE("GPL");
 
-static int force;
+static bool force;
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Force loading without checking for supported models");
 
-static int ignore_dmi;
+static bool ignore_dmi;
 module_param(ignore_dmi, bool, 0);
 MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match");
 
-static int restricted;
+static bool restricted;
 module_param(restricted, bool, 0);
 MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set");
 
-static int power_status;
+static bool power_status;
 module_param(power_status, bool, 0600);
 MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
 
index 9397ab49b72e8b20f3984a55e31819fea26e20d7..50fcf9c04569a18007816dc322382103a604c542 100644 (file)
@@ -1227,7 +1227,7 @@ static int smi_num; /* Used to sequence the SMIs */
 #define DEFAULT_REGSPACING     1
 #define DEFAULT_REGSIZE                1
 
-static int           si_trydefaults = 1;
+static bool          si_trydefaults = 1;
 static char          *si_type[SI_MAX_PARMS];
 #define MAX_SI_TYPE_STR 30
 static char          si_type_str[MAX_SI_TYPE_STR];
index 97c3edb95ae747a3ff2832f48e6daf098fad83bf..f43485607063af7490ae37013de97675fbf156c5 100644 (file)
@@ -829,7 +829,7 @@ static struct console lpcons = {
 
 static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
 static char *parport[LP_NO];
-static int reset;
+static bool reset;
 
 module_param_array(parport, charp, NULL, 0);
 module_param(reset, bool, 0);
index a12f52400dbc5ed6ef65885ff7dc80052ed49ad6..bf586ae1ee83cabad66a2029e0c540b74bee0370 100644 (file)
@@ -51,7 +51,7 @@ static int write_block(unsigned long p, const char __user *buf, int count);
 #define KFLASH_ID      0x89A6          //Intel flash
 #define KFLASH_ID4     0xB0D4          //Intel flash 4Meg
 
-static int flashdebug;         //if set - we will display progress msgs
+static bool flashdebug;                //if set - we will display progress msgs
 
 static int gbWriteEnable;
 static int gbWriteBase64Enable;
index 15781396af25a7ae301d04a92024e74b3e94f373..07f6a5abe3722a1143c0dd71ef6e8527caa155bd 100644 (file)
@@ -439,7 +439,7 @@ static int mgslpc_device_count = 0;
  * .text section address and breakpoint on module load.
  * This is useful for use with gdb and add-symbol-file command.
  */
-static int break_on_load=0;
+static bool break_on_load=0;
 
 /*
  * Driver major number, defaults to zero to get auto
index 7c7f42a1f880cc81af6dafd89b73810c7eca34aa..9fec3232b7361b102ff5e05e55f2444eeab6ffb8 100644 (file)
@@ -83,8 +83,7 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper,
        struct timeval timestamp;
 
        if (reason != KMSG_DUMP_OOPS &&
-           reason != KMSG_DUMP_PANIC &&
-           reason != KMSG_DUMP_KEXEC)
+           reason != KMSG_DUMP_PANIC)
                return;
 
        /* Only dump oopses if dump_oops is set */
@@ -126,8 +125,8 @@ static int __init ramoops_probe(struct platform_device *pdev)
                goto fail3;
        }
 
-       rounddown_pow_of_two(pdata->mem_size);
-       rounddown_pow_of_two(pdata->record_size);
+       pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
+       pdata->record_size = rounddown_pow_of_two(pdata->record_size);
 
        /* Check for the minimum memory size */
        if (pdata->mem_size < MIN_MEM_SIZE &&
@@ -148,14 +147,6 @@ static int __init ramoops_probe(struct platform_device *pdev)
        cxt->phys_addr = pdata->mem_address;
        cxt->record_size = pdata->record_size;
        cxt->dump_oops = pdata->dump_oops;
-       /*
-        * Update the module parameter variables as well so they are visible
-        * through /sys/module/ramoops/parameters/
-        */
-       mem_size = pdata->mem_size;
-       mem_address = pdata->mem_address;
-       record_size = pdata->record_size;
-       dump_oops = pdata->dump_oops;
 
        if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) {
                pr_err("request mem region failed\n");
@@ -176,6 +167,15 @@ static int __init ramoops_probe(struct platform_device *pdev)
                goto fail1;
        }
 
+       /*
+        * Update the module parameter variables as well so they are visible
+        * through /sys/module/ramoops/parameters/
+        */
+       mem_size = pdata->mem_size;
+       mem_address = pdata->mem_address;
+       record_size = pdata->record_size;
+       dump_oops = pdata->dump_oops;
+
        return 0;
 
 fail1:
index 85da8740586b3dbe381373d6f7e52d6b348329ac..54ca8b23cde3f1aa5550d2806087300227531070 100644 (file)
@@ -387,7 +387,7 @@ static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
 static struct fasync_struct *fasync;
 
 #if 0
-static int debug;
+static bool debug;
 module_param(debug, bool, 0644);
 #define DEBUG_ENT(fmt, arg...) do { \
        if (debug) \
@@ -965,6 +965,7 @@ EXPORT_SYMBOL(get_random_bytes);
  */
 static void init_std_data(struct entropy_store *r)
 {
+       int i;
        ktime_t now;
        unsigned long flags;
 
@@ -974,6 +975,11 @@ static void init_std_data(struct entropy_store *r)
 
        now = ktime_get_real();
        mix_pool_bytes(r, &now, sizeof(now));
+       for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof flags) {
+               if (!arch_get_random_long(&flags))
+                       break;
+               mix_pool_bytes(r, &flags, sizeof(flags));
+       }
        mix_pool_bytes(r, utsname(), sizeof(*(utsname())));
 }
 
index 6a8771f47a55c799866468fe80946a479a0440f8..32362cf35b8d1a42c4b1f3e4f67881687ecad0cc 100644 (file)
@@ -846,6 +846,15 @@ int tpm_do_selftest(struct tpm_chip *chip)
 
        do {
                rc = __tpm_pcr_read(chip, 0, digest);
+               if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
+                       dev_info(chip->dev,
+                                "TPM is disabled/deactivated (0x%X)\n", rc);
+                       /* TPM is disabled and/or deactivated; driver can
+                        * proceed and TPM does handle commands for
+                        * suspend/resume correctly
+                        */
+                       return 0;
+               }
                if (rc != TPM_WARN_DOING_SELFTEST)
                        return rc;
                msleep(delay_msec);
index 8c1df302fbb6ce17cd9580cca1aaeca84f785745..01054713828128ea59fa1c06b2adf035b8b3f281 100644 (file)
@@ -39,6 +39,9 @@ enum tpm_addr {
 };
 
 #define TPM_WARN_DOING_SELFTEST 0x802
+#define TPM_ERR_DEACTIVATED     0x6
+#define TPM_ERR_DISABLED        0x7
+
 #define TPM_HEADER_SIZE                10
 extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
                                char *);
index 10cc44ceb5d1259dc1c91a90168702f5a048ad9b..a1748621111be511a8694a4d91ab74094f45c631 100644 (file)
@@ -255,7 +255,7 @@ out:
        return size;
 }
 
-static int itpm;
+static bool itpm;
 module_param(itpm, bool, 0444);
 MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)");
 
@@ -500,7 +500,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int interrupts = 1;
+static bool interrupts = 1;
 module_param(interrupts, bool, 0444);
 MODULE_PARM_DESC(interrupts, "Enable interrupts");
 
@@ -828,7 +828,7 @@ static struct platform_driver tis_drv = {
 
 static struct platform_device *pdev;
 
-static int force;
+static bool force;
 module_param(force, bool, 0444);
 MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
 static int __init init_tis(void)
index 8e3c46d67cb3d9f1f636ca0e38fb175e02a18cdb..b58b5618706588936ebcf7a028bde7dba8f616c1 100644 (file)
@@ -392,7 +392,7 @@ static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
 
        sg_init_one(sg, buf->buf, buf->size);
 
-       ret = virtqueue_add_buf(vq, sg, 0, 1, buf);
+       ret = virtqueue_add_buf(vq, sg, 0, 1, buf, GFP_ATOMIC);
        virtqueue_kick(vq);
        return ret;
 }
@@ -457,7 +457,7 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
        vq = portdev->c_ovq;
 
        sg_init_one(sg, &cpkt, sizeof(cpkt));
-       if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt) >= 0) {
+       if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt, GFP_ATOMIC) >= 0) {
                virtqueue_kick(vq);
                while (!virtqueue_get_buf(vq, &len))
                        cpu_relax();
@@ -506,7 +506,7 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
        reclaim_consumed_buffers(port);
 
        sg_init_one(sg, in_buf, in_count);
-       ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf);
+       ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf, GFP_ATOMIC);
 
        /* Tell Host to go! */
        virtqueue_kick(out_vq);
@@ -1271,6 +1271,20 @@ static void remove_port(struct kref *kref)
        kfree(port);
 }
 
+static void remove_port_data(struct port *port)
+{
+       struct port_buffer *buf;
+
+       /* Remove unused data this port might have received. */
+       discard_port_data(port);
+
+       reclaim_consumed_buffers(port);
+
+       /* Remove buffers we queued up for the Host to send us data in. */
+       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
+               free_buf(buf);
+}
+
 /*
  * Port got unplugged.  Remove port from portdev's list and drop the
  * kref reference.  If no userspace has this port opened, it will
@@ -1278,8 +1292,6 @@ static void remove_port(struct kref *kref)
  */
 static void unplug_port(struct port *port)
 {
-       struct port_buffer *buf;
-
        spin_lock_irq(&port->portdev->ports_lock);
        list_del(&port->list);
        spin_unlock_irq(&port->portdev->ports_lock);
@@ -1300,14 +1312,7 @@ static void unplug_port(struct port *port)
                hvc_remove(port->cons.hvc);
        }
 
-       /* Remove unused data this port might have received. */
-       discard_port_data(port);
-
-       reclaim_consumed_buffers(port);
-
-       /* Remove buffers we queued up for the Host to send us data in. */
-       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
-               free_buf(buf);
+       remove_port_data(port);
 
        /*
         * We should just assume the device itself has gone off --
@@ -1659,6 +1664,28 @@ static const struct file_operations portdev_fops = {
        .owner = THIS_MODULE,
 };
 
+static void remove_vqs(struct ports_device *portdev)
+{
+       portdev->vdev->config->del_vqs(portdev->vdev);
+       kfree(portdev->in_vqs);
+       kfree(portdev->out_vqs);
+}
+
+static void remove_controlq_data(struct ports_device *portdev)
+{
+       struct port_buffer *buf;
+       unsigned int len;
+
+       if (!use_multiport(portdev))
+               return;
+
+       while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
+               free_buf(buf);
+
+       while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
+               free_buf(buf);
+}
+
 /*
  * Once we're further in boot, we get probed like any other virtio
  * device.
@@ -1764,9 +1791,7 @@ free_vqs:
        /* The host might want to notify mgmt sw about device add failure */
        __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
                           VIRTIO_CONSOLE_DEVICE_READY, 0);
-       vdev->config->del_vqs(vdev);
-       kfree(portdev->in_vqs);
-       kfree(portdev->out_vqs);
+       remove_vqs(portdev);
 free_chrdev:
        unregister_chrdev(portdev->chr_major, "virtio-portsdev");
 free:
@@ -1804,21 +1829,8 @@ static void virtcons_remove(struct virtio_device *vdev)
         * have to just stop using the port, as the vqs are going
         * away.
         */
-       if (use_multiport(portdev)) {
-               struct port_buffer *buf;
-               unsigned int len;
-
-               while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
-                       free_buf(buf);
-
-               while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
-                       free_buf(buf);
-       }
-
-       vdev->config->del_vqs(vdev);
-       kfree(portdev->in_vqs);
-       kfree(portdev->out_vqs);
-
+       remove_controlq_data(portdev);
+       remove_vqs(portdev);
        kfree(portdev);
 }
 
@@ -1832,6 +1844,68 @@ static unsigned int features[] = {
        VIRTIO_CONSOLE_F_MULTIPORT,
 };
 
+#ifdef CONFIG_PM
+static int virtcons_freeze(struct virtio_device *vdev)
+{
+       struct ports_device *portdev;
+       struct port *port;
+
+       portdev = vdev->priv;
+
+       vdev->config->reset(vdev);
+
+       virtqueue_disable_cb(portdev->c_ivq);
+       cancel_work_sync(&portdev->control_work);
+       /*
+        * Once more: if control_work_handler() was running, it would
+        * enable the cb as the last step.
+        */
+       virtqueue_disable_cb(portdev->c_ivq);
+       remove_controlq_data(portdev);
+
+       list_for_each_entry(port, &portdev->ports, list) {
+               virtqueue_disable_cb(port->in_vq);
+               virtqueue_disable_cb(port->out_vq);
+               /*
+                * We'll ask the host later if the new invocation has
+                * the port opened or closed.
+                */
+               port->host_connected = false;
+               remove_port_data(port);
+       }
+       remove_vqs(portdev);
+
+       return 0;
+}
+
+static int virtcons_restore(struct virtio_device *vdev)
+{
+       struct ports_device *portdev;
+       struct port *port;
+       int ret;
+
+       portdev = vdev->priv;
+
+       ret = init_vqs(portdev);
+       if (ret)
+               return ret;
+
+       if (use_multiport(portdev))
+               fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+
+       list_for_each_entry(port, &portdev->ports, list) {
+               port->in_vq = portdev->in_vqs[port->id];
+               port->out_vq = portdev->out_vqs[port->id];
+
+               fill_queue(port->in_vq, &port->inbuf_lock);
+
+               /* Get port open/close status on the host */
+               send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+       }
+       return 0;
+}
+#endif
+
 static struct virtio_driver virtio_console = {
        .feature_table = features,
        .feature_table_size = ARRAY_SIZE(features),
@@ -1841,6 +1915,10 @@ static struct virtio_driver virtio_console = {
        .probe =        virtcons_probe,
        .remove =       virtcons_remove,
        .config_changed = config_intr,
+#ifdef CONFIG_PM
+       .freeze =       virtcons_freeze,
+       .restore =      virtcons_restore,
+#endif
 };
 
 static int __init init(void)
index 5a99bb3f255ae7c34fedc540949ab0163a15d5a5..f1a274994bb1fbdc1c8e0e54b26aebe58b161c2b 100644 (file)
@@ -124,7 +124,7 @@ config MV_XOR
 
 config MX3_IPU
        bool "MX3x Image Processing Unit support"
-       depends on SOC_IMX31 || SOC_IMX35
+       depends on ARCH_MXC
        select DMA_ENGINE
        default y
        help
@@ -187,6 +187,13 @@ config TIMB_DMA
        help
          Enable support for the Timberdale FPGA DMA engine.
 
+config SIRF_DMA
+       tristate "CSR SiRFprimaII DMA support"
+       depends on ARCH_PRIMA2
+       select DMA_ENGINE
+       help
+         Enable support for the CSR SiRFprimaII DMA engine.
+
 config ARCH_HAS_ASYNC_TX_FIND_CHANNEL
        bool
 
@@ -201,26 +208,26 @@ config PL330_DMA
          platform_data for a dma-pl330 device.
 
 config PCH_DMA
-       tristate "Intel EG20T PCH / OKI Semi IOH(ML7213/ML7223) DMA support"
+       tristate "Intel EG20T PCH / LAPIS Semicon IOH(ML7213/ML7223/ML7831) DMA"
        depends on PCI && X86
        select DMA_ENGINE
        help
          Enable support for Intel EG20T PCH DMA engine.
 
-         This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
-         Output Hub), ML7213 and ML7223.
-         ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
-         for MP(Media Phone) use.
-         ML7213/ML7223 is companion chip for Intel Atom E6xx series.
-         ML7213/ML7223 is completely compatible for Intel EG20T PCH.
+         This driver also can be used for LAPIS Semiconductor IOH(Input/
+         Output Hub), ML7213, ML7223 and ML7831.
+         ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is
+         for MP(Media Phone) use and ML7831 IOH is for general purpose use.
+         ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
+         ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
 
 config IMX_SDMA
        tristate "i.MX SDMA support"
-       depends on ARCH_MX25 || SOC_IMX31 || SOC_IMX35 || ARCH_MX5
+       depends on ARCH_MXC
        select DMA_ENGINE
        help
          Support the i.MX SDMA engine. This engine is integrated into
-         Freescale i.MX25/31/35/51 chips.
+         Freescale i.MX25/31/35/51/53 chips.
 
 config IMX_DMA
        tristate "i.MX DMA support"
index 30cf3b1f0c5ca4ff633d9e50474feef0a49fc565..009a222e8283cba3929fd8763ae9abe9b4d6d694 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_IMX_SDMA) += imx-sdma.o
 obj-$(CONFIG_IMX_DMA) += imx-dma.o
 obj-$(CONFIG_MXS_DMA) += mxs-dma.o
 obj-$(CONFIG_TIMB_DMA) += timb_dma.o
+obj-$(CONFIG_SIRF_DMA) += sirf-dma.o
 obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
 obj-$(CONFIG_PL330_DMA) += pl330.o
 obj-$(CONFIG_PCH_DMA) += pch_dma.o
index 0698695e8bf9508e0c0dac5cdad44f7f8f508c07..8a281584458b582bbb872137323ff82cdaac2eb1 100644 (file)
@@ -854,8 +854,10 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan,
        int ret;
 
        /* Check if we already have a channel */
-       if (plchan->phychan)
-               return 0;
+       if (plchan->phychan) {
+               ch = plchan->phychan;
+               goto got_channel;
+       }
 
        ch = pl08x_get_phy_channel(pl08x, plchan);
        if (!ch) {
@@ -880,21 +882,22 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan,
                        return -EBUSY;
                }
                ch->signal = ret;
-
-               /* Assign the flow control signal to this channel */
-               if (txd->direction == DMA_TO_DEVICE)
-                       txd->ccfg |= ch->signal << PL080_CONFIG_DST_SEL_SHIFT;
-               else if (txd->direction == DMA_FROM_DEVICE)
-                       txd->ccfg |= ch->signal << PL080_CONFIG_SRC_SEL_SHIFT;
        }
 
+       plchan->phychan = ch;
        dev_dbg(&pl08x->adev->dev, "allocated physical channel %d and signal %d for xfer on %s\n",
                 ch->id,
                 ch->signal,
                 plchan->name);
 
+got_channel:
+       /* Assign the flow control signal to this channel */
+       if (txd->direction == DMA_MEM_TO_DEV)
+               txd->ccfg |= ch->signal << PL080_CONFIG_DST_SEL_SHIFT;
+       else if (txd->direction == DMA_DEV_TO_MEM)
+               txd->ccfg |= ch->signal << PL080_CONFIG_SRC_SEL_SHIFT;
+
        plchan->phychan_hold++;
-       plchan->phychan = ch;
 
        return 0;
 }
@@ -1102,10 +1105,10 @@ static int dma_set_runtime_config(struct dma_chan *chan,
 
        /* Transfer direction */
        plchan->runtime_direction = config->direction;
-       if (config->direction == DMA_TO_DEVICE) {
+       if (config->direction == DMA_MEM_TO_DEV) {
                addr_width = config->dst_addr_width;
                maxburst = config->dst_maxburst;
-       } else if (config->direction == DMA_FROM_DEVICE) {
+       } else if (config->direction == DMA_DEV_TO_MEM) {
                addr_width = config->src_addr_width;
                maxburst = config->src_maxburst;
        } else {
@@ -1136,7 +1139,7 @@ static int dma_set_runtime_config(struct dma_chan *chan,
        cctl |= burst << PL080_CONTROL_SB_SIZE_SHIFT;
        cctl |= burst << PL080_CONTROL_DB_SIZE_SHIFT;
 
-       if (plchan->runtime_direction == DMA_FROM_DEVICE) {
+       if (plchan->runtime_direction == DMA_DEV_TO_MEM) {
                plchan->src_addr = config->src_addr;
                plchan->src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR |
                        pl08x_select_bus(plchan->cd->periph_buses,
@@ -1152,7 +1155,7 @@ static int dma_set_runtime_config(struct dma_chan *chan,
                "configured channel %s (%s) for %s, data width %d, "
                "maxburst %d words, LE, CCTL=0x%08x\n",
                dma_chan_name(chan), plchan->name,
-               (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
+               (config->direction == DMA_DEV_TO_MEM) ? "RX" : "TX",
                addr_width,
                maxburst,
                cctl);
@@ -1322,7 +1325,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
 
 static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
                struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned int sg_len, enum dma_transfer_direction direction,
                unsigned long flags)
 {
        struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
@@ -1354,10 +1357,10 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
         */
        txd->direction = direction;
 
-       if (direction == DMA_TO_DEVICE) {
+       if (direction == DMA_MEM_TO_DEV) {
                txd->cctl = plchan->dst_cctl;
                slave_addr = plchan->dst_addr;
-       } else if (direction == DMA_FROM_DEVICE) {
+       } else if (direction == DMA_DEV_TO_MEM) {
                txd->cctl = plchan->src_cctl;
                slave_addr = plchan->src_addr;
        } else {
@@ -1368,10 +1371,10 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
        }
 
        if (plchan->cd->device_fc)
-               tmp = (direction == DMA_TO_DEVICE) ? PL080_FLOW_MEM2PER_PER :
+               tmp = (direction == DMA_MEM_TO_DEV) ? PL080_FLOW_MEM2PER_PER :
                        PL080_FLOW_PER2MEM_PER;
        else
-               tmp = (direction == DMA_TO_DEVICE) ? PL080_FLOW_MEM2PER :
+               tmp = (direction == DMA_MEM_TO_DEV) ? PL080_FLOW_MEM2PER :
                        PL080_FLOW_PER2MEM;
 
        txd->ccfg |= tmp << PL080_CONFIG_FLOW_CONTROL_SHIFT;
@@ -1387,7 +1390,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
                list_add_tail(&dsg->node, &txd->dsg_list);
 
                dsg->len = sg_dma_len(sg);
-               if (direction == DMA_TO_DEVICE) {
+               if (direction == DMA_MEM_TO_DEV) {
                        dsg->src_addr = sg_phys(sg);
                        dsg->dst_addr = slave_addr;
                } else {
index fcfa0a8b5c59956516060cd9ff5535f6524a819f..97f87b29b9f3db5ea0068e076e145a0a81d5ad08 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include "at_hdmac_regs.h"
 
@@ -660,7 +662,7 @@ err_desc_get:
  */
 static struct dma_async_tx_descriptor *
 atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned int sg_len, enum dma_transfer_direction direction,
                unsigned long flags)
 {
        struct at_dma_chan      *atchan = to_at_dma_chan(chan);
@@ -678,7 +680,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 
        dev_vdbg(chan2dev(chan), "prep_slave_sg (%d): %s f0x%lx\n",
                        sg_len,
-                       direction == DMA_TO_DEVICE ? "TO DEVICE" : "FROM DEVICE",
+                       direction == DMA_MEM_TO_DEV ? "TO DEVICE" : "FROM DEVICE",
                        flags);
 
        if (unlikely(!atslave || !sg_len)) {
@@ -692,7 +694,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        ctrlb = ATC_IEN;
 
        switch (direction) {
-       case DMA_TO_DEVICE:
+       case DMA_MEM_TO_DEV:
                ctrla |=  ATC_DST_WIDTH(reg_width);
                ctrlb |=  ATC_DST_ADDR_MODE_FIXED
                        | ATC_SRC_ADDR_MODE_INCR
@@ -725,7 +727,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                        total_len += len;
                }
                break;
-       case DMA_FROM_DEVICE:
+       case DMA_DEV_TO_MEM:
                ctrla |=  ATC_SRC_WIDTH(reg_width);
                ctrlb |=  ATC_DST_ADDR_MODE_INCR
                        | ATC_SRC_ADDR_MODE_FIXED
@@ -787,7 +789,7 @@ err_desc_get:
  */
 static int
 atc_dma_cyclic_check_values(unsigned int reg_width, dma_addr_t buf_addr,
-               size_t period_len, enum dma_data_direction direction)
+               size_t period_len, enum dma_transfer_direction direction)
 {
        if (period_len > (ATC_BTSIZE_MAX << reg_width))
                goto err_out;
@@ -795,7 +797,7 @@ atc_dma_cyclic_check_values(unsigned int reg_width, dma_addr_t buf_addr,
                goto err_out;
        if (unlikely(buf_addr & ((1 << reg_width) - 1)))
                goto err_out;
-       if (unlikely(!(direction & (DMA_TO_DEVICE | DMA_FROM_DEVICE))))
+       if (unlikely(!(direction & (DMA_DEV_TO_MEM | DMA_MEM_TO_DEV))))
                goto err_out;
 
        return 0;
@@ -810,7 +812,7 @@ err_out:
 static int
 atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc,
                unsigned int period_index, dma_addr_t buf_addr,
-               size_t period_len, enum dma_data_direction direction)
+               size_t period_len, enum dma_transfer_direction direction)
 {
        u32             ctrla;
        unsigned int    reg_width = atslave->reg_width;
@@ -822,7 +824,7 @@ atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc,
                | period_len >> reg_width;
 
        switch (direction) {
-       case DMA_TO_DEVICE:
+       case DMA_MEM_TO_DEV:
                desc->lli.saddr = buf_addr + (period_len * period_index);
                desc->lli.daddr = atslave->tx_reg;
                desc->lli.ctrla = ctrla;
@@ -833,7 +835,7 @@ atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc,
                                | ATC_DIF(AT_DMA_PER_IF);
                break;
 
-       case DMA_FROM_DEVICE:
+       case DMA_DEV_TO_MEM:
                desc->lli.saddr = atslave->rx_reg;
                desc->lli.daddr = buf_addr + (period_len * period_index);
                desc->lli.ctrla = ctrla;
@@ -861,7 +863,7 @@ atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc,
  */
 static struct dma_async_tx_descriptor *
 atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
-               size_t period_len, enum dma_data_direction direction)
+               size_t period_len, enum dma_transfer_direction direction)
 {
        struct at_dma_chan      *atchan = to_at_dma_chan(chan);
        struct at_dma_slave     *atslave = chan->private;
@@ -872,7 +874,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
        unsigned int            i;
 
        dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@0x%08x - %d (%d/%d)\n",
-                       direction == DMA_TO_DEVICE ? "TO DEVICE" : "FROM DEVICE",
+                       direction == DMA_MEM_TO_DEV ? "TO DEVICE" : "FROM DEVICE",
                        buf_addr,
                        periods, buf_len, period_len);
 
@@ -1175,6 +1177,56 @@ static void atc_free_chan_resources(struct dma_chan *chan)
 
 /*--  Module Management  -----------------------------------------------*/
 
+/* cap_mask is a multi-u32 bitfield, fill it with proper C code. */
+static struct at_dma_platform_data at91sam9rl_config = {
+       .nr_channels = 2,
+};
+static struct at_dma_platform_data at91sam9g45_config = {
+       .nr_channels = 8,
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_dma_dt_ids[] = {
+       {
+               .compatible = "atmel,at91sam9rl-dma",
+               .data = &at91sam9rl_config,
+       }, {
+               .compatible = "atmel,at91sam9g45-dma",
+               .data = &at91sam9g45_config,
+       }, {
+               /* sentinel */
+       }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_dma_dt_ids);
+#endif
+
+static const struct platform_device_id atdma_devtypes[] = {
+       {
+               .name = "at91sam9rl_dma",
+               .driver_data = (unsigned long) &at91sam9rl_config,
+       }, {
+               .name = "at91sam9g45_dma",
+               .driver_data = (unsigned long) &at91sam9g45_config,
+       }, {
+               /* sentinel */
+       }
+};
+
+static inline struct at_dma_platform_data * __init at_dma_get_driver_data(
+                                               struct platform_device *pdev)
+{
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(atmel_dma_dt_ids, pdev->dev.of_node);
+               if (match == NULL)
+                       return NULL;
+               return match->data;
+       }
+       return (struct at_dma_platform_data *)
+                       platform_get_device_id(pdev)->driver_data;
+}
+
 /**
  * at_dma_off - disable DMA controller
  * @atdma: the Atmel HDAMC device
@@ -1193,18 +1245,23 @@ static void at_dma_off(struct at_dma *atdma)
 
 static int __init at_dma_probe(struct platform_device *pdev)
 {
-       struct at_dma_platform_data *pdata;
        struct resource         *io;
        struct at_dma           *atdma;
        size_t                  size;
        int                     irq;
        int                     err;
        int                     i;
+       struct at_dma_platform_data *plat_dat;
 
-       /* get DMA Controller parameters from platform */
-       pdata = pdev->dev.platform_data;
-       if (!pdata || pdata->nr_channels > AT_DMA_MAX_NR_CHANNELS)
-               return -EINVAL;
+       /* setup platform data for each SoC */
+       dma_cap_set(DMA_MEMCPY, at91sam9rl_config.cap_mask);
+       dma_cap_set(DMA_MEMCPY, at91sam9g45_config.cap_mask);
+       dma_cap_set(DMA_SLAVE, at91sam9g45_config.cap_mask);
+
+       /* get DMA parameters from controller type */
+       plat_dat = at_dma_get_driver_data(pdev);
+       if (!plat_dat)
+               return -ENODEV;
 
        io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!io)
@@ -1215,14 +1272,14 @@ static int __init at_dma_probe(struct platform_device *pdev)
                return irq;
 
        size = sizeof(struct at_dma);
-       size += pdata->nr_channels * sizeof(struct at_dma_chan);
+       size += plat_dat->nr_channels * sizeof(struct at_dma_chan);
        atdma = kzalloc(size, GFP_KERNEL);
        if (!atdma)
                return -ENOMEM;
 
-       /* discover transaction capabilites from the platform data */
-       atdma->dma_common.cap_mask = pdata->cap_mask;
-       atdma->all_chan_mask = (1 << pdata->nr_channels) - 1;
+       /* discover transaction capabilities */
+       atdma->dma_common.cap_mask = plat_dat->cap_mask;
+       atdma->all_chan_mask = (1 << plat_dat->nr_channels) - 1;
 
        size = resource_size(io);
        if (!request_mem_region(io->start, size, pdev->dev.driver->name)) {
@@ -1268,7 +1325,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
 
        /* initialize channels related values */
        INIT_LIST_HEAD(&atdma->dma_common.channels);
-       for (i = 0; i < pdata->nr_channels; i++) {
+       for (i = 0; i < plat_dat->nr_channels; i++) {
                struct at_dma_chan      *atchan = &atdma->chan[i];
 
                atchan->chan_common.device = &atdma->dma_common;
@@ -1313,7 +1370,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
        dev_info(&pdev->dev, "Atmel AHB DMA Controller ( %s%s), %d channels\n",
          dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask) ? "cpy " : "",
          dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)  ? "slave " : "",
-         pdata->nr_channels);
+         plat_dat->nr_channels);
 
        dma_async_device_register(&atdma->dma_common);
 
@@ -1495,9 +1552,11 @@ static const struct dev_pm_ops at_dma_dev_pm_ops = {
 static struct platform_driver at_dma_driver = {
        .remove         = __exit_p(at_dma_remove),
        .shutdown       = at_dma_shutdown,
+       .id_table       = atdma_devtypes,
        .driver = {
                .name   = "at_hdmac",
                .pm     = &at_dma_dev_pm_ops,
+               .of_match_table = of_match_ptr(atmel_dma_dt_ids),
        },
 };
 
index aa4c9aebab7cedec68a42aececeb218aaea0208b..dcaedfc181cf489d97bc0bd01444f7d875211fe8 100644 (file)
@@ -251,6 +251,7 @@ static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan)
 /**
  * struct at_dma - internal representation of an Atmel HDMA Controller
  * @chan_common: common dmaengine dma_device object members
+ * @atdma_devtype: identifier of DMA controller compatibility
  * @ch_regs: memory mapped register base
  * @clk: dma controller clock
  * @save_imr: interrupt mask register that is saved on suspend/resume cycle
index 4234f416ef115055cb425822a2c411a73dd41590..d65a718c0f9b1ae5819aef9af4c1c58200627a22 100644 (file)
@@ -39,7 +39,7 @@ struct coh901318_desc {
        struct scatterlist *sg;
        unsigned int sg_len;
        struct coh901318_lli *lli;
-       enum dma_data_direction dir;
+       enum dma_transfer_direction dir;
        unsigned long flags;
        u32 head_config;
        u32 head_ctrl;
@@ -1034,7 +1034,7 @@ coh901318_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 
 static struct dma_async_tx_descriptor *
 coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
-                       unsigned int sg_len, enum dma_data_direction direction,
+                       unsigned int sg_len, enum dma_transfer_direction direction,
                        unsigned long flags)
 {
        struct coh901318_chan *cohc = to_coh901318_chan(chan);
@@ -1077,7 +1077,7 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        ctrl_last |= cohc->runtime_ctrl;
        ctrl |= cohc->runtime_ctrl;
 
-       if (direction == DMA_TO_DEVICE) {
+       if (direction == DMA_MEM_TO_DEV) {
                u32 tx_flags = COH901318_CX_CTRL_PRDD_SOURCE |
                        COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE;
 
@@ -1085,7 +1085,7 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                ctrl_chained |= tx_flags;
                ctrl_last |= tx_flags;
                ctrl |= tx_flags;
-       } else if (direction == DMA_FROM_DEVICE) {
+       } else if (direction == DMA_DEV_TO_MEM) {
                u32 rx_flags = COH901318_CX_CTRL_PRDD_DEST |
                        COH901318_CX_CTRL_DST_ADDR_INC_ENABLE;
 
@@ -1274,11 +1274,11 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
        int i = 0;
 
        /* We only support mem to per or per to mem transfers */
-       if (config->direction == DMA_FROM_DEVICE) {
+       if (config->direction == DMA_DEV_TO_MEM) {
                addr = config->src_addr;
                addr_width = config->src_addr_width;
                maxburst = config->src_maxburst;
-       } else if (config->direction == DMA_TO_DEVICE) {
+       } else if (config->direction == DMA_MEM_TO_DEV) {
                addr = config->dst_addr;
                addr_width = config->dst_addr_width;
                maxburst = config->dst_maxburst;
index 9f7e0e6a7eea12e8487cef8fd1395c38cfbdc7a0..6c0e2d4c66827c7a179a55c8bc52375b932dfaa1 100644 (file)
@@ -7,11 +7,10 @@
  * Author: Per Friden <per.friden@stericsson.com>
  */
 
-#include <linux/dma-mapping.h>
 #include <linux/spinlock.h>
-#include <linux/dmapool.h>
 #include <linux/memory.h>
 #include <linux/gfp.h>
+#include <linux/dmapool.h>
 #include <mach/coh901318.h>
 
 #include "coh901318_lli.h"
@@ -177,18 +176,18 @@ coh901318_lli_fill_single(struct coh901318_pool *pool,
                          struct coh901318_lli *lli,
                          dma_addr_t buf, unsigned int size,
                          dma_addr_t dev_addr, u32 ctrl_chained, u32 ctrl_eom,
-                         enum dma_data_direction dir)
+                         enum dma_transfer_direction dir)
 {
        int s = size;
        dma_addr_t src;
        dma_addr_t dst;
 
 
-       if (dir == DMA_TO_DEVICE) {
+       if (dir == DMA_MEM_TO_DEV) {
                src = buf;
                dst = dev_addr;
 
-       } else if (dir == DMA_FROM_DEVICE) {
+       } else if (dir == DMA_DEV_TO_MEM) {
 
                src = dev_addr;
                dst = buf;
@@ -215,9 +214,9 @@ coh901318_lli_fill_single(struct coh901318_pool *pool,
 
                lli = coh901318_lli_next(lli);
 
-               if (dir == DMA_TO_DEVICE)
+               if (dir == DMA_MEM_TO_DEV)
                        src += block_size;
-               else if (dir == DMA_FROM_DEVICE)
+               else if (dir == DMA_DEV_TO_MEM)
                        dst += block_size;
        }
 
@@ -234,7 +233,7 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool,
                      struct scatterlist *sgl, unsigned int nents,
                      dma_addr_t dev_addr, u32 ctrl_chained, u32 ctrl,
                      u32 ctrl_last,
-                     enum dma_data_direction dir, u32 ctrl_irq_mask)
+                     enum dma_transfer_direction dir, u32 ctrl_irq_mask)
 {
        int i;
        struct scatterlist *sg;
@@ -249,9 +248,9 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool,
 
        spin_lock(&pool->lock);
 
-       if (dir == DMA_TO_DEVICE)
+       if (dir == DMA_MEM_TO_DEV)
                dst = dev_addr;
-       else if (dir == DMA_FROM_DEVICE)
+       else if (dir == DMA_DEV_TO_MEM)
                src = dev_addr;
        else
                goto err;
@@ -269,7 +268,7 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool,
                        ctrl_sg = ctrl ? ctrl : ctrl_last;
 
 
-               if (dir == DMA_TO_DEVICE)
+               if (dir == DMA_MEM_TO_DEV)
                        /* increment source address */
                        src = sg_phys(sg);
                else
@@ -293,7 +292,7 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool,
                        lli->src_addr = src;
                        lli->dst_addr = dst;
 
-                       if (dir == DMA_FROM_DEVICE)
+                       if (dir == DMA_DEV_TO_MEM)
                                dst += elem_size;
                        else
                                src += elem_size;
index 7a5c80990e9ef795def59abeb4e8b310e1245759..abff3714fdda73ed508d588c3b1b3fc923d08e89 100644 (file)
@@ -97,7 +97,7 @@ coh901318_lli_fill_single(struct coh901318_pool *pool,
                          struct coh901318_lli *lli,
                          dma_addr_t buf, unsigned int size,
                          dma_addr_t dev_addr, u32 ctrl_chained, u32 ctrl_last,
-                         enum dma_data_direction dir);
+                         enum dma_transfer_direction dir);
 
 /**
  * coh901318_lli_fill_single() - Prepares the lli:s for dma scatter list transfer
@@ -119,6 +119,6 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool,
                      struct scatterlist *sg, unsigned int nents,
                      dma_addr_t dev_addr, u32 ctrl_chained,
                      u32 ctrl, u32 ctrl_last,
-                     enum dma_data_direction dir, u32 ctrl_irq_mask);
+                     enum dma_transfer_direction dir, u32 ctrl_irq_mask);
 
 #endif /* COH901318_LLI_H */
index b48967b499da0bad30529501492def4695dc1f25..a6c6051ec85811041277c64d675810f14d9da851 100644 (file)
@@ -693,12 +693,12 @@ int dma_async_device_register(struct dma_device *device)
                !device->device_prep_dma_interrupt);
        BUG_ON(dma_has_cap(DMA_SG, device->cap_mask) &&
                !device->device_prep_dma_sg);
-       BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
-               !device->device_prep_slave_sg);
        BUG_ON(dma_has_cap(DMA_CYCLIC, device->cap_mask) &&
                !device->device_prep_dma_cyclic);
        BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
                !device->device_control);
+       BUG_ON(dma_has_cap(DMA_INTERLEAVE, device->cap_mask) &&
+               !device->device_prep_interleaved_dma);
 
        BUG_ON(!device->device_alloc_chan_resources);
        BUG_ON(!device->device_free_chan_resources);
index 9bfd6d3607180930692140b43f31db630c25bee6..9b592b02b5f49a3023cdc883322af7c451448a0a 100644 (file)
@@ -166,6 +166,38 @@ dwc_assign_cookie(struct dw_dma_chan *dwc, struct dw_desc *desc)
        return cookie;
 }
 
+static void dwc_initialize(struct dw_dma_chan *dwc)
+{
+       struct dw_dma *dw = to_dw_dma(dwc->chan.device);
+       struct dw_dma_slave *dws = dwc->chan.private;
+       u32 cfghi = DWC_CFGH_FIFO_MODE;
+       u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
+
+       if (dwc->initialized == true)
+               return;
+
+       if (dws) {
+               /*
+                * We need controller-specific data to set up slave
+                * transfers.
+                */
+               BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev);
+
+               cfghi = dws->cfg_hi;
+               cfglo |= dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK;
+       }
+
+       channel_writel(dwc, CFG_LO, cfglo);
+       channel_writel(dwc, CFG_HI, cfghi);
+
+       /* Enable interrupts */
+       channel_set_bit(dw, MASK.XFER, dwc->mask);
+       channel_set_bit(dw, MASK.BLOCK, dwc->mask);
+       channel_set_bit(dw, MASK.ERROR, dwc->mask);
+
+       dwc->initialized = true;
+}
+
 /*----------------------------------------------------------------------*/
 
 /* Called with dwc->lock held and bh disabled */
@@ -189,6 +221,8 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
                return;
        }
 
+       dwc_initialize(dwc);
+
        channel_writel(dwc, LLP, first->txd.phys);
        channel_writel(dwc, CTL_LO,
                        DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
@@ -696,7 +730,7 @@ err_desc_get:
 
 static struct dma_async_tx_descriptor *
 dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned int sg_len, enum dma_transfer_direction direction,
                unsigned long flags)
 {
        struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
@@ -720,7 +754,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        prev = first = NULL;
 
        switch (direction) {
-       case DMA_TO_DEVICE:
+       case DMA_MEM_TO_DEV:
                ctllo = (DWC_DEFAULT_CTLLO(chan->private)
                                | DWC_CTLL_DST_WIDTH(reg_width)
                                | DWC_CTLL_DST_FIX
@@ -777,7 +811,7 @@ slave_sg_todev_fill_desc:
                                goto slave_sg_todev_fill_desc;
                }
                break;
-       case DMA_FROM_DEVICE:
+       case DMA_DEV_TO_MEM:
                ctllo = (DWC_DEFAULT_CTLLO(chan->private)
                                | DWC_CTLL_SRC_WIDTH(reg_width)
                                | DWC_CTLL_DST_INC
@@ -959,10 +993,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
        struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
        struct dw_dma           *dw = to_dw_dma(chan->device);
        struct dw_desc          *desc;
-       struct dw_dma_slave     *dws;
        int                     i;
-       u32                     cfghi;
-       u32                     cfglo;
        unsigned long           flags;
 
        dev_vdbg(chan2dev(chan), "alloc_chan_resources\n");
@@ -975,26 +1006,6 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
 
        dwc->completed = chan->cookie = 1;
 
-       cfghi = DWC_CFGH_FIFO_MODE;
-       cfglo = 0;
-
-       dws = chan->private;
-       if (dws) {
-               /*
-                * We need controller-specific data to set up slave
-                * transfers.
-                */
-               BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev);
-
-               cfghi = dws->cfg_hi;
-               cfglo = dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK;
-       }
-
-       cfglo |= DWC_CFGL_CH_PRIOR(dwc->priority);
-
-       channel_writel(dwc, CFG_LO, cfglo);
-       channel_writel(dwc, CFG_HI, cfghi);
-
        /*
         * NOTE: some controllers may have additional features that we
         * need to initialize here, like "scatter-gather" (which
@@ -1026,11 +1037,6 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
                i = ++dwc->descs_allocated;
        }
 
-       /* Enable interrupts */
-       channel_set_bit(dw, MASK.XFER, dwc->mask);
-       channel_set_bit(dw, MASK.BLOCK, dwc->mask);
-       channel_set_bit(dw, MASK.ERROR, dwc->mask);
-
        spin_unlock_irqrestore(&dwc->lock, flags);
 
        dev_dbg(chan2dev(chan),
@@ -1058,6 +1064,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
        spin_lock_irqsave(&dwc->lock, flags);
        list_splice_init(&dwc->free_list, &list);
        dwc->descs_allocated = 0;
+       dwc->initialized = false;
 
        /* Disable interrupts */
        channel_clear_bit(dw, MASK.XFER, dwc->mask);
@@ -1165,7 +1172,7 @@ EXPORT_SYMBOL(dw_dma_cyclic_stop);
  */
 struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
                dma_addr_t buf_addr, size_t buf_len, size_t period_len,
-               enum dma_data_direction direction)
+               enum dma_transfer_direction direction)
 {
        struct dw_dma_chan              *dwc = to_dw_dma_chan(chan);
        struct dw_cyclic_desc           *cdesc;
@@ -1206,7 +1213,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
                goto out_err;
        if (unlikely(buf_addr & ((1 << reg_width) - 1)))
                goto out_err;
-       if (unlikely(!(direction & (DMA_TO_DEVICE | DMA_FROM_DEVICE))))
+       if (unlikely(!(direction & (DMA_MEM_TO_DEV | DMA_DEV_TO_MEM))))
                goto out_err;
 
        retval = ERR_PTR(-ENOMEM);
@@ -1228,7 +1235,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
                        goto out_err_desc_get;
 
                switch (direction) {
-               case DMA_TO_DEVICE:
+               case DMA_MEM_TO_DEV:
                        desc->lli.dar = dws->tx_reg;
                        desc->lli.sar = buf_addr + (period_len * i);
                        desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private)
@@ -1239,7 +1246,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
                                        | DWC_CTLL_FC(dws->fc)
                                        | DWC_CTLL_INT_EN);
                        break;
-               case DMA_FROM_DEVICE:
+               case DMA_DEV_TO_MEM:
                        desc->lli.dar = buf_addr + (period_len * i);
                        desc->lli.sar = dws->rx_reg;
                        desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private)
@@ -1335,6 +1342,8 @@ EXPORT_SYMBOL(dw_dma_cyclic_free);
 
 static void dw_dma_off(struct dw_dma *dw)
 {
+       int i;
+
        dma_writel(dw, CFG, 0);
 
        channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
@@ -1345,6 +1354,9 @@ static void dw_dma_off(struct dw_dma *dw)
 
        while (dma_readl(dw, CFG) & DW_CFG_DMA_EN)
                cpu_relax();
+
+       for (i = 0; i < dw->dma.chancnt; i++)
+               dw->chan[i].initialized = false;
 }
 
 static int __init dw_probe(struct platform_device *pdev)
@@ -1533,6 +1545,7 @@ static int dw_suspend_noirq(struct device *dev)
 
        dw_dma_off(platform_get_drvdata(pdev));
        clk_disable(dw->clk);
+
        return 0;
 }
 
index c3419518d701dbe3a0671cbc906a88c7ee3823a3..5eef6946a36713bd7413ecd29c1751291c4cc41c 100644 (file)
@@ -140,6 +140,7 @@ struct dw_dma_chan {
        u8                      mask;
        u8                      priority;
        bool                    paused;
+       bool                    initialized;
 
        spinlock_t              lock;
 
index b47e2b803fafdaedaf7c8a765858790ce869f2db..59e7a965772bfdff900aa1d82063d6f2510dd8c4 100644 (file)
@@ -246,6 +246,9 @@ static void ep93xx_dma_set_active(struct ep93xx_dma_chan *edmac,
 static struct ep93xx_dma_desc *
 ep93xx_dma_get_active(struct ep93xx_dma_chan *edmac)
 {
+       if (list_empty(&edmac->active))
+               return NULL;
+
        return list_first_entry(&edmac->active, struct ep93xx_dma_desc, node);
 }
 
@@ -263,16 +266,22 @@ ep93xx_dma_get_active(struct ep93xx_dma_chan *edmac)
  */
 static bool ep93xx_dma_advance_active(struct ep93xx_dma_chan *edmac)
 {
+       struct ep93xx_dma_desc *desc;
+
        list_rotate_left(&edmac->active);
 
        if (test_bit(EP93XX_DMA_IS_CYCLIC, &edmac->flags))
                return true;
 
+       desc = ep93xx_dma_get_active(edmac);
+       if (!desc)
+               return false;
+
        /*
         * If txd.cookie is set it means that we are back in the first
         * descriptor in the chain and hence done with it.
         */
-       return !ep93xx_dma_get_active(edmac)->txd.cookie;
+       return !desc->txd.cookie;
 }
 
 /*
@@ -327,10 +336,16 @@ static void m2p_hw_shutdown(struct ep93xx_dma_chan *edmac)
 
 static void m2p_fill_desc(struct ep93xx_dma_chan *edmac)
 {
-       struct ep93xx_dma_desc *desc = ep93xx_dma_get_active(edmac);
+       struct ep93xx_dma_desc *desc;
        u32 bus_addr;
 
-       if (ep93xx_dma_chan_direction(&edmac->chan) == DMA_TO_DEVICE)
+       desc = ep93xx_dma_get_active(edmac);
+       if (!desc) {
+               dev_warn(chan2dev(edmac), "M2P: empty descriptor list\n");
+               return;
+       }
+
+       if (ep93xx_dma_chan_direction(&edmac->chan) == DMA_MEM_TO_DEV)
                bus_addr = desc->src_addr;
        else
                bus_addr = desc->dst_addr;
@@ -443,7 +458,7 @@ static int m2m_hw_setup(struct ep93xx_dma_chan *edmac)
                control = (5 << M2M_CONTROL_PWSC_SHIFT);
                control |= M2M_CONTROL_NO_HDSK;
 
-               if (data->direction == DMA_TO_DEVICE) {
+               if (data->direction == DMA_MEM_TO_DEV) {
                        control |= M2M_CONTROL_DAH;
                        control |= M2M_CONTROL_TM_TX;
                        control |= M2M_CONTROL_RSS_SSPTX;
@@ -459,11 +474,7 @@ static int m2m_hw_setup(struct ep93xx_dma_chan *edmac)
                 * This IDE part is totally untested. Values below are taken
                 * from the EP93xx Users's Guide and might not be correct.
                 */
-               control |= M2M_CONTROL_NO_HDSK;
-               control |= M2M_CONTROL_RSS_IDE;
-               control |= M2M_CONTROL_PW_16;
-
-               if (data->direction == DMA_TO_DEVICE) {
+               if (data->direction == DMA_MEM_TO_DEV) {
                        /* Worst case from the UG */
                        control = (3 << M2M_CONTROL_PWSC_SHIFT);
                        control |= M2M_CONTROL_DAH;
@@ -473,6 +484,10 @@ static int m2m_hw_setup(struct ep93xx_dma_chan *edmac)
                        control |= M2M_CONTROL_SAH;
                        control |= M2M_CONTROL_TM_RX;
                }
+
+               control |= M2M_CONTROL_NO_HDSK;
+               control |= M2M_CONTROL_RSS_IDE;
+               control |= M2M_CONTROL_PW_16;
                break;
 
        default:
@@ -491,7 +506,13 @@ static void m2m_hw_shutdown(struct ep93xx_dma_chan *edmac)
 
 static void m2m_fill_desc(struct ep93xx_dma_chan *edmac)
 {
-       struct ep93xx_dma_desc *desc = ep93xx_dma_get_active(edmac);
+       struct ep93xx_dma_desc *desc;
+
+       desc = ep93xx_dma_get_active(edmac);
+       if (!desc) {
+               dev_warn(chan2dev(edmac), "M2M: empty descriptor list\n");
+               return;
+       }
 
        if (edmac->buffer == 0) {
                writel(desc->src_addr, edmac->regs + M2M_SAR_BASE0);
@@ -669,24 +690,30 @@ static void ep93xx_dma_tasklet(unsigned long data)
 {
        struct ep93xx_dma_chan *edmac = (struct ep93xx_dma_chan *)data;
        struct ep93xx_dma_desc *desc, *d;
-       dma_async_tx_callback callback;
-       void *callback_param;
+       dma_async_tx_callback callback = NULL;
+       void *callback_param = NULL;
        LIST_HEAD(list);
 
        spin_lock_irq(&edmac->lock);
+       /*
+        * If dma_terminate_all() was called before we get to run, the active
+        * list has become empty. If that happens we aren't supposed to do
+        * anything more than call ep93xx_dma_advance_work().
+        */
        desc = ep93xx_dma_get_active(edmac);
-       if (desc->complete) {
-               edmac->last_completed = desc->txd.cookie;
-               list_splice_init(&edmac->active, &list);
+       if (desc) {
+               if (desc->complete) {
+                       edmac->last_completed = desc->txd.cookie;
+                       list_splice_init(&edmac->active, &list);
+               }
+               callback = desc->txd.callback;
+               callback_param = desc->txd.callback_param;
        }
        spin_unlock_irq(&edmac->lock);
 
        /* Pick up the next descriptor from the queue */
        ep93xx_dma_advance_work(edmac);
 
-       callback = desc->txd.callback;
-       callback_param = desc->txd.callback_param;
-
        /* Now we can release all the chained descriptors */
        list_for_each_entry_safe(desc, d, &list, node) {
                /*
@@ -706,13 +733,22 @@ static void ep93xx_dma_tasklet(unsigned long data)
 static irqreturn_t ep93xx_dma_interrupt(int irq, void *dev_id)
 {
        struct ep93xx_dma_chan *edmac = dev_id;
+       struct ep93xx_dma_desc *desc;
        irqreturn_t ret = IRQ_HANDLED;
 
        spin_lock(&edmac->lock);
 
+       desc = ep93xx_dma_get_active(edmac);
+       if (!desc) {
+               dev_warn(chan2dev(edmac),
+                        "got interrupt while active list is empty\n");
+               spin_unlock(&edmac->lock);
+               return IRQ_NONE;
+       }
+
        switch (edmac->edma->hw_interrupt(edmac)) {
        case INTERRUPT_DONE:
-               ep93xx_dma_get_active(edmac)->complete = true;
+               desc->complete = true;
                tasklet_schedule(&edmac->tasklet);
                break;
 
@@ -803,8 +839,8 @@ static int ep93xx_dma_alloc_chan_resources(struct dma_chan *chan)
                        switch (data->port) {
                        case EP93XX_DMA_SSP:
                        case EP93XX_DMA_IDE:
-                               if (data->direction != DMA_TO_DEVICE &&
-                                   data->direction != DMA_FROM_DEVICE)
+                               if (data->direction != DMA_MEM_TO_DEV &&
+                                   data->direction != DMA_DEV_TO_MEM)
                                        return -EINVAL;
                                break;
                        default:
@@ -952,7 +988,7 @@ fail:
  */
 static struct dma_async_tx_descriptor *
 ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
-                        unsigned int sg_len, enum dma_data_direction dir,
+                        unsigned int sg_len, enum dma_transfer_direction dir,
                         unsigned long flags)
 {
        struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
@@ -988,7 +1024,7 @@ ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                        goto fail;
                }
 
-               if (dir == DMA_TO_DEVICE) {
+               if (dir == DMA_MEM_TO_DEV) {
                        desc->src_addr = sg_dma_address(sg);
                        desc->dst_addr = edmac->runtime_addr;
                } else {
@@ -1032,7 +1068,7 @@ fail:
 static struct dma_async_tx_descriptor *
 ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
                           size_t buf_len, size_t period_len,
-                          enum dma_data_direction dir)
+                          enum dma_transfer_direction dir)
 {
        struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
        struct ep93xx_dma_desc *desc, *first;
@@ -1065,7 +1101,7 @@ ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
                        goto fail;
                }
 
-               if (dir == DMA_TO_DEVICE) {
+               if (dir == DMA_MEM_TO_DEV) {
                        desc->src_addr = dma_addr + offset;
                        desc->dst_addr = edmac->runtime_addr;
                } else {
@@ -1133,12 +1169,12 @@ static int ep93xx_dma_slave_config(struct ep93xx_dma_chan *edmac,
                return -EINVAL;
 
        switch (config->direction) {
-       case DMA_FROM_DEVICE:
+       case DMA_DEV_TO_MEM:
                width = config->src_addr_width;
                addr = config->src_addr;
                break;
 
-       case DMA_TO_DEVICE:
+       case DMA_MEM_TO_DEV:
                width = config->dst_addr_width;
                addr = config->dst_addr;
                break;
index 8a781540590cdf1e76e79c74d137a647c02642f6..b98070c33ca9d3b8aa42d1fb5085da9772957733 100644 (file)
@@ -772,7 +772,7 @@ fail:
  */
 static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
        struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
-       enum dma_data_direction direction, unsigned long flags)
+       enum dma_transfer_direction direction, unsigned long flags)
 {
        /*
         * This operation is not supported on the Freescale DMA controller
@@ -819,7 +819,7 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
                        return -ENXIO;
 
                /* we set the controller burst size depending on direction */
-               if (config->direction == DMA_TO_DEVICE)
+               if (config->direction == DMA_MEM_TO_DEV)
                        size = config->dst_addr_width * config->dst_maxburst;
                else
                        size = config->src_addr_width * config->src_maxburst;
index 4be55f9bb6c19c6b6165a6de82eea9b2d977c18d..e4383ee2c9acd015b72675557ad03a06357f4eda 100644 (file)
@@ -107,7 +107,7 @@ static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                imx_dma_disable(imxdmac->imxdma_channel);
                return 0;
        case DMA_SLAVE_CONFIG:
-               if (dmaengine_cfg->direction == DMA_FROM_DEVICE) {
+               if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
                        imxdmac->per_address = dmaengine_cfg->src_addr;
                        imxdmac->watermark_level = dmaengine_cfg->src_maxburst;
                        imxdmac->word_size = dmaengine_cfg->src_addr_width;
@@ -224,7 +224,7 @@ static void imxdma_free_chan_resources(struct dma_chan *chan)
 
 static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
                struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned int sg_len, enum dma_transfer_direction direction,
                unsigned long flags)
 {
        struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
@@ -241,7 +241,7 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
                dma_length += sg->length;
        }
 
-       if (direction == DMA_FROM_DEVICE)
+       if (direction == DMA_DEV_TO_MEM)
                dmamode = DMA_MODE_READ;
        else
                dmamode = DMA_MODE_WRITE;
@@ -271,7 +271,7 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
 
 static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
                struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
-               size_t period_len, enum dma_data_direction direction)
+               size_t period_len, enum dma_transfer_direction direction)
 {
        struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
        struct imxdma_engine *imxdma = imxdmac->imxdma;
@@ -317,7 +317,7 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
        imxdmac->sg_list[periods].page_link =
                ((unsigned long)imxdmac->sg_list | 0x01) & ~0x02;
 
-       if (direction == DMA_FROM_DEVICE)
+       if (direction == DMA_DEV_TO_MEM)
                dmamode = DMA_MODE_READ;
        else
                dmamode = DMA_MODE_WRITE;
index f993955a640c376342498d3336668348ecd78884..a8af379680c16776e19ae3018a9991243a3a8255 100644 (file)
@@ -247,7 +247,7 @@ struct sdma_engine;
 struct sdma_channel {
        struct sdma_engine              *sdma;
        unsigned int                    channel;
-       enum dma_data_direction         direction;
+       enum dma_transfer_direction             direction;
        enum sdma_peripheral_type       peripheral_type;
        unsigned int                    event_id0;
        unsigned int                    event_id1;
@@ -268,6 +268,8 @@ struct sdma_channel {
        struct dma_async_tx_descriptor  desc;
        dma_cookie_t                    last_completed;
        enum dma_status                 status;
+       unsigned int                    chn_count;
+       unsigned int                    chn_real_count;
 };
 
 #define IMX_DMA_SG_LOOP                (1 << 0)
@@ -503,6 +505,7 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
        struct sdma_buffer_descriptor *bd;
        int i, error = 0;
 
+       sdmac->chn_real_count = 0;
        /*
         * non loop mode. Iterate over all descriptors, collect
         * errors and call callback function
@@ -512,6 +515,7 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
 
                 if (bd->mode.status & (BD_DONE | BD_RROR))
                        error = -EIO;
+                sdmac->chn_real_count += bd->mode.count;
        }
 
        if (error)
@@ -519,9 +523,9 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
        else
                sdmac->status = DMA_SUCCESS;
 
+       sdmac->last_completed = sdmac->desc.cookie;
        if (sdmac->desc.callback)
                sdmac->desc.callback(sdmac->desc.callback_param);
-       sdmac->last_completed = sdmac->desc.cookie;
 }
 
 static void mxc_sdma_handle_channel(struct sdma_channel *sdmac)
@@ -650,7 +654,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
        struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
        int ret;
 
-       if (sdmac->direction == DMA_FROM_DEVICE) {
+       if (sdmac->direction == DMA_DEV_TO_MEM) {
                load_address = sdmac->pc_from_device;
        } else {
                load_address = sdmac->pc_to_device;
@@ -832,17 +836,18 @@ static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
 
 static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
 {
+       unsigned long flags;
        struct sdma_channel *sdmac = to_sdma_chan(tx->chan);
        struct sdma_engine *sdma = sdmac->sdma;
        dma_cookie_t cookie;
 
-       spin_lock_irq(&sdmac->lock);
+       spin_lock_irqsave(&sdmac->lock, flags);
 
        cookie = sdma_assign_cookie(sdmac);
 
        sdma_enable_channel(sdma, sdmac->channel);
 
-       spin_unlock_irq(&sdmac->lock);
+       spin_unlock_irqrestore(&sdmac->lock, flags);
 
        return cookie;
 }
@@ -911,7 +916,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
 
 static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
                struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned int sg_len, enum dma_transfer_direction direction,
                unsigned long flags)
 {
        struct sdma_channel *sdmac = to_sdma_chan(chan);
@@ -941,6 +946,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
                goto err_out;
        }
 
+       sdmac->chn_count = 0;
        for_each_sg(sgl, sg, sg_len, i) {
                struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
                int param;
@@ -957,6 +963,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
                }
 
                bd->mode.count = count;
+               sdmac->chn_count += count;
 
                if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) {
                        ret =  -EINVAL;
@@ -1008,7 +1015,7 @@ err_out:
 
 static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
                struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
-               size_t period_len, enum dma_data_direction direction)
+               size_t period_len, enum dma_transfer_direction direction)
 {
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        struct sdma_engine *sdma = sdmac->sdma;
@@ -1093,7 +1100,7 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                sdma_disable_channel(sdmac);
                return 0;
        case DMA_SLAVE_CONFIG:
-               if (dmaengine_cfg->direction == DMA_FROM_DEVICE) {
+               if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
                        sdmac->per_address = dmaengine_cfg->src_addr;
                        sdmac->watermark_level = dmaengine_cfg->src_maxburst;
                        sdmac->word_size = dmaengine_cfg->src_addr_width;
@@ -1102,6 +1109,7 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                        sdmac->watermark_level = dmaengine_cfg->dst_maxburst;
                        sdmac->word_size = dmaengine_cfg->dst_addr_width;
                }
+               sdmac->direction = dmaengine_cfg->direction;
                return sdma_config_channel(sdmac);
        default:
                return -ENOSYS;
@@ -1119,7 +1127,8 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
 
        last_used = chan->cookie;
 
-       dma_set_tx_state(txstate, sdmac->last_completed, last_used, 0);
+       dma_set_tx_state(txstate, sdmac->last_completed, last_used,
+                       sdmac->chn_count - sdmac->chn_real_count);
 
        return sdmac->status;
 }
index 19a0c64d45d3643a99e7b8972c8c3f3a16fc6e5f..74f70aadf9e47313cb23e3bee95781c8f24a2e02 100644 (file)
@@ -280,7 +280,8 @@ static void midc_dostart(struct intel_mid_dma_chan *midc,
  * callbacks but must be called with the lock held.
  */
 static void midc_descriptor_complete(struct intel_mid_dma_chan *midc,
-              struct intel_mid_dma_desc *desc)
+               struct intel_mid_dma_desc *desc)
+               __releases(&midc->lock) __acquires(&midc->lock)
 {
        struct dma_async_tx_descriptor  *txd = &desc->txd;
        dma_async_tx_callback callback_txd = NULL;
@@ -311,6 +312,7 @@ static void midc_descriptor_complete(struct intel_mid_dma_chan *midc,
                        pci_pool_free(desc->lli_pool, desc->lli,
                                                desc->lli_phys);
                        pci_pool_destroy(desc->lli_pool);
+                       desc->lli = NULL;
                }
                list_move(&desc->desc_node, &midc->free_list);
                midc->busy = false;
@@ -395,10 +397,10 @@ static int midc_lli_fill_sg(struct intel_mid_dma_chan *midc,
                                                        midc->dma->block_size);
                /*Populate SAR and DAR values*/
                sg_phy_addr = sg_phys(sg);
-               if (desc->dirn ==  DMA_TO_DEVICE) {
+               if (desc->dirn ==  DMA_MEM_TO_DEV) {
                        lli_bloc_desc->sar  = sg_phy_addr;
                        lli_bloc_desc->dar  = mids->dma_slave.dst_addr;
-               } else if (desc->dirn ==  DMA_FROM_DEVICE) {
+               } else if (desc->dirn ==  DMA_DEV_TO_MEM) {
                        lli_bloc_desc->sar  = mids->dma_slave.src_addr;
                        lli_bloc_desc->dar  = sg_phy_addr;
                }
@@ -490,7 +492,9 @@ static enum dma_status intel_mid_dma_tx_status(struct dma_chan *chan,
 
        ret = dma_async_is_complete(cookie, last_complete, last_used);
        if (ret != DMA_SUCCESS) {
+               spin_lock_bh(&midc->lock);
                midc_scan_descriptors(to_middma_device(chan->device), midc);
+               spin_unlock_bh(&midc->lock);
 
                last_complete = midc->completed;
                last_used = chan->cookie;
@@ -566,6 +570,7 @@ static int intel_mid_dma_device_control(struct dma_chan *chan,
                        pci_pool_free(desc->lli_pool, desc->lli,
                                                desc->lli_phys);
                        pci_pool_destroy(desc->lli_pool);
+                       desc->lli = NULL;
                }
                list_move(&desc->desc_node, &midc->free_list);
        }
@@ -632,13 +637,13 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
                if (midc->dma->pimr_mask) {
                        cfg_hi.cfgx.protctl = 0x0; /*default value*/
                        cfg_hi.cfgx.fifo_mode = 1;
-                       if (mids->dma_slave.direction == DMA_TO_DEVICE) {
+                       if (mids->dma_slave.direction == DMA_MEM_TO_DEV) {
                                cfg_hi.cfgx.src_per = 0;
                                if (mids->device_instance == 0)
                                        cfg_hi.cfgx.dst_per = 3;
                                if (mids->device_instance == 1)
                                        cfg_hi.cfgx.dst_per = 1;
-                       } else if (mids->dma_slave.direction == DMA_FROM_DEVICE) {
+                       } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) {
                                if (mids->device_instance == 0)
                                        cfg_hi.cfgx.src_per = 2;
                                if (mids->device_instance == 1)
@@ -682,11 +687,11 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
                ctl_lo.ctlx.sinc = 0;
                ctl_lo.ctlx.dinc = 0;
        } else {
-               if (mids->dma_slave.direction == DMA_TO_DEVICE) {
+               if (mids->dma_slave.direction == DMA_MEM_TO_DEV) {
                        ctl_lo.ctlx.sinc = 0;
                        ctl_lo.ctlx.dinc = 2;
                        ctl_lo.ctlx.tt_fc = 1;
-               } else if (mids->dma_slave.direction == DMA_FROM_DEVICE) {
+               } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) {
                        ctl_lo.ctlx.sinc = 2;
                        ctl_lo.ctlx.dinc = 0;
                        ctl_lo.ctlx.tt_fc = 2;
@@ -732,7 +737,7 @@ err_desc_get:
  */
 static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
                        struct dma_chan *chan, struct scatterlist *sgl,
-                       unsigned int sg_len, enum dma_data_direction direction,
+                       unsigned int sg_len, enum dma_transfer_direction direction,
                        unsigned long flags)
 {
        struct intel_mid_dma_chan *midc = NULL;
@@ -868,7 +873,7 @@ static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
        pm_runtime_get_sync(&mid->pdev->dev);
 
        if (mid->state == SUSPENDED) {
-               if (dma_resume(mid->pdev)) {
+               if (dma_resume(&mid->pdev->dev)) {
                        pr_err("ERR_MDMA: resume failed");
                        return -EFAULT;
                }
@@ -1099,7 +1104,8 @@ static int mid_setup_dma(struct pci_dev *pdev)
                                        LNW_PERIPHRAL_MASK_SIZE);
                if (dma->mask_reg == NULL) {
                        pr_err("ERR_MDMA:Can't map periphral intr space !!\n");
-                       return -ENOMEM;
+                       err = -ENOMEM;
+                       goto err_ioremap;
                }
        } else
                dma->mask_reg = NULL;
@@ -1196,6 +1202,9 @@ static int mid_setup_dma(struct pci_dev *pdev)
 err_engine:
        free_irq(pdev->irq, dma);
 err_irq:
+       if (dma->mask_reg)
+               iounmap(dma->mask_reg);
+err_ioremap:
        pci_pool_destroy(dma->dma_pool);
 err_dma_pool:
        pr_err("ERR_MDMA:setup_dma failed: %d\n", err);
@@ -1337,8 +1346,9 @@ static void __devexit intel_mid_dma_remove(struct pci_dev *pdev)
 *
 * This function is called by OS when a power event occurs
 */
-int dma_suspend(struct pci_dev *pci, pm_message_t state)
+static int dma_suspend(struct device *dev)
 {
+       struct pci_dev *pci = to_pci_dev(dev);
        int i;
        struct middma_device *device = pci_get_drvdata(pci);
        pr_debug("MDMA: dma_suspend called\n");
@@ -1362,8 +1372,9 @@ int dma_suspend(struct pci_dev *pci, pm_message_t state)
 *
 * This function is called by OS when a power event occurs
 */
-int dma_resume(struct pci_dev *pci)
+int dma_resume(struct device *dev)
 {
+       struct pci_dev *pci = to_pci_dev(dev);
        int ret;
        struct middma_device *device = pci_get_drvdata(pci);
 
@@ -1429,6 +1440,8 @@ static const struct dev_pm_ops intel_mid_dma_pm = {
        .runtime_suspend = dma_runtime_suspend,
        .runtime_resume = dma_runtime_resume,
        .runtime_idle = dma_runtime_idle,
+       .suspend = dma_suspend,
+       .resume = dma_resume,
 };
 
 static struct pci_driver intel_mid_dma_pci_driver = {
@@ -1437,8 +1450,6 @@ static struct pci_driver intel_mid_dma_pci_driver = {
        .probe          =       intel_mid_dma_probe,
        .remove         =       __devexit_p(intel_mid_dma_remove),
 #ifdef CONFIG_PM
-       .suspend = dma_suspend,
-       .resume = dma_resume,
        .driver = {
                .pm = &intel_mid_dma_pm,
        },
index aea5ee88ce035a1d432eb836ef6b4b938f163ab4..c83d35b97bd8e38a91330854c3d8b10acbe4cedf 100644 (file)
@@ -262,7 +262,7 @@ struct intel_mid_dma_desc {
        unsigned int                    lli_length;
        unsigned int                    current_lli;
        dma_addr_t                      next;
-       enum dma_data_direction         dirn;
+       enum dma_transfer_direction             dirn;
        enum dma_status                 status;
        enum dma_slave_buswidth         width; /*width of DMA txn*/
        enum intel_mid_dma_mode         cfg_mode; /*mode configuration*/
@@ -296,6 +296,6 @@ static inline struct intel_mid_dma_slave *to_intel_mid_dma_slave
 }
 
 
-int dma_resume(struct pci_dev *pci);
+int dma_resume(struct device *dev);
 
 #endif /*__INTEL_MID_DMAC_REGS_H__*/
index e03f811a83dd980e5aad9e2b25b0acdc291769f5..04be90b645b839e929512032a234089cfe2d082c 100644 (file)
@@ -1735,8 +1735,6 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan)
        spin_unlock_bh(&iop_chan->lock);
 }
 
-MODULE_ALIAS("platform:iop-adma");
-
 static struct platform_driver iop_adma_driver = {
        .probe          = iop_adma_probe,
        .remove         = __devexit_p(iop_adma_remove),
@@ -1746,19 +1744,9 @@ static struct platform_driver iop_adma_driver = {
        },
 };
 
-static int __init iop_adma_init (void)
-{
-       return platform_driver_register(&iop_adma_driver);
-}
-
-static void __exit iop_adma_exit (void)
-{
-       platform_driver_unregister(&iop_adma_driver);
-       return;
-}
-module_exit(iop_adma_exit);
-module_init(iop_adma_init);
+module_platform_driver(iop_adma_driver);
 
 MODULE_AUTHOR("Intel Corporation");
 MODULE_DESCRIPTION("IOP ADMA Engine Driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:iop-adma");
index 0e5ef33f90a17ad75bebaa889a7ae7a46d75248c..6212b16e8cf21ea32ae05732ae1f3b1147b134b8 100644 (file)
@@ -312,7 +312,7 @@ static void ipu_ch_param_set_size(union chan_param_mem *params,
        case IPU_PIX_FMT_RGB565:
                params->ip.bpp  = 2;
                params->ip.pfs  = 4;
-               params->ip.npb  = 7;
+               params->ip.npb  = 15;
                params->ip.sat  = 2;            /* SAT = 32-bit access */
                params->ip.ofs0 = 0;            /* Red bit offset */
                params->ip.ofs1 = 5;            /* Green bit offset */
@@ -422,12 +422,6 @@ static void ipu_ch_param_set_size(union chan_param_mem *params,
        params->pp.nsb = 1;
 }
 
-static void ipu_ch_param_set_burst_size(union chan_param_mem *params,
-                                       uint16_t burst_pixels)
-{
-       params->pp.npb = burst_pixels - 1;
-}
-
 static void ipu_ch_param_set_buffer(union chan_param_mem *params,
                                    dma_addr_t buf0, dma_addr_t buf1)
 {
@@ -690,23 +684,6 @@ static int ipu_init_channel_buffer(struct idmac_channel *ichan,
        ipu_ch_param_set_size(&params, pixel_fmt, width, height, stride_bytes);
        ipu_ch_param_set_buffer(&params, phyaddr_0, phyaddr_1);
        ipu_ch_param_set_rotation(&params, rot_mode);
-       /* Some channels (rotation) have restriction on burst length */
-       switch (channel) {
-       case IDMAC_IC_7:        /* Hangs with burst 8, 16, other values
-                                  invalid - Table 44-30 */
-/*
-               ipu_ch_param_set_burst_size(&params, 8);
- */
-               break;
-       case IDMAC_SDC_0:
-       case IDMAC_SDC_1:
-               /* In original code only IPU_PIX_FMT_RGB565 was setting burst */
-               ipu_ch_param_set_burst_size(&params, 16);
-               break;
-       case IDMAC_IC_0:
-       default:
-               break;
-       }
 
        spin_lock_irqsave(&ipu->lock, flags);
 
@@ -1364,7 +1341,7 @@ static void ipu_gc_tasklet(unsigned long arg)
 /* Allocate and initialise a transfer descriptor. */
 static struct dma_async_tx_descriptor *idmac_prep_slave_sg(struct dma_chan *chan,
                struct scatterlist *sgl, unsigned int sg_len,
-               enum dma_data_direction direction, unsigned long tx_flags)
+               enum dma_transfer_direction direction, unsigned long tx_flags)
 {
        struct idmac_channel *ichan = to_idmac_chan(chan);
        struct idmac_tx_desc *desc = NULL;
@@ -1376,7 +1353,7 @@ static struct dma_async_tx_descriptor *idmac_prep_slave_sg(struct dma_chan *chan
            chan->chan_id != IDMAC_IC_7)
                return NULL;
 
-       if (direction != DMA_FROM_DEVICE && direction != DMA_TO_DEVICE) {
+       if (direction != DMA_DEV_TO_MEM && direction != DMA_MEM_TO_DEV) {
                dev_err(chan->device->dev, "Invalid DMA direction %d!\n", direction);
                return NULL;
        }
index 8ba4edc6185e904ea65b98537a1c09a2b38549bb..4d6d4cf669496ff0afc65d5dee450452b143a2c6 100644 (file)
@@ -835,17 +835,7 @@ static struct platform_driver mpc_dma_driver = {
        },
 };
 
-static int __init mpc_dma_init(void)
-{
-       return platform_driver_register(&mpc_dma_driver);
-}
-module_init(mpc_dma_init);
-
-static void __exit mpc_dma_exit(void)
-{
-       platform_driver_unregister(&mpc_dma_driver);
-}
-module_exit(mpc_dma_exit);
+module_platform_driver(mpc_dma_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Piotr Ziecik <kosmo@semihalf.com>");
index fc903c0ed234eae754d06911b94f73f463a3b7eb..b06cd4ca626fb4fd93d5ab3b7fedddbfd6ea6c25 100644 (file)
@@ -44,7 +44,6 @@
 #define HW_APBHX_CTRL0                         0x000
 #define BM_APBH_CTRL0_APB_BURST8_EN            (1 << 29)
 #define BM_APBH_CTRL0_APB_BURST_EN             (1 << 28)
-#define BP_APBH_CTRL0_CLKGATE_CHANNEL          8
 #define BP_APBH_CTRL0_RESET_CHANNEL            16
 #define HW_APBHX_CTRL1                         0x010
 #define HW_APBHX_CTRL2                         0x020
@@ -111,6 +110,7 @@ struct mxs_dma_chan {
        int                             chan_irq;
        struct mxs_dma_ccw              *ccw;
        dma_addr_t                      ccw_phys;
+       int                             desc_count;
        dma_cookie_t                    last_completed;
        enum dma_status                 status;
        unsigned int                    flags;
@@ -130,23 +130,6 @@ struct mxs_dma_engine {
        struct mxs_dma_chan             mxs_chans[MXS_DMA_CHANNELS];
 };
 
-static inline void mxs_dma_clkgate(struct mxs_dma_chan *mxs_chan, int enable)
-{
-       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
-       int chan_id = mxs_chan->chan.chan_id;
-       int set_clr = enable ? MXS_CLR_ADDR : MXS_SET_ADDR;
-
-       /* enable apbh channel clock */
-       if (dma_is_apbh()) {
-               if (apbh_is_old())
-                       writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL),
-                               mxs_dma->base + HW_APBHX_CTRL0 + set_clr);
-               else
-                       writel(1 << chan_id,
-                               mxs_dma->base + HW_APBHX_CTRL0 + set_clr);
-       }
-}
-
 static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan)
 {
        struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
@@ -165,9 +148,6 @@ static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan)
        struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
        int chan_id = mxs_chan->chan.chan_id;
 
-       /* clkgate needs to be enabled before writing other registers */
-       mxs_dma_clkgate(mxs_chan, 1);
-
        /* set cmd_addr up */
        writel(mxs_chan->ccw_phys,
                mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id));
@@ -178,9 +158,6 @@ static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan)
 
 static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan)
 {
-       /* disable apbh channel clock */
-       mxs_dma_clkgate(mxs_chan, 0);
-
        mxs_chan->status = DMA_SUCCESS;
 }
 
@@ -268,7 +245,7 @@ static irqreturn_t mxs_dma_int_handler(int irq, void *dev_id)
        /*
         * When both completion and error of termination bits set at the
         * same time, we do not take it as an error.  IOW, it only becomes
-        * an error we need to handler here in case of ether it's (1) an bus
+        * an error we need to handle here in case of either it's (1) a bus
         * error or (2) a termination error with no completion.
         */
        stat2 = ((stat2 >> MXS_DMA_CHANNELS) & stat2) | /* (1) */
@@ -338,10 +315,7 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
        if (ret)
                goto err_clk;
 
-       /* clkgate needs to be enabled for reset to finish */
-       mxs_dma_clkgate(mxs_chan, 1);
        mxs_dma_reset_chan(mxs_chan);
-       mxs_dma_clkgate(mxs_chan, 0);
 
        dma_async_tx_descriptor_init(&mxs_chan->desc, chan);
        mxs_chan->desc.tx_submit = mxs_dma_tx_submit;
@@ -377,7 +351,7 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
 
 static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
                struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned int sg_len, enum dma_transfer_direction direction,
                unsigned long append)
 {
        struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
@@ -386,7 +360,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
        struct scatterlist *sg;
        int i, j;
        u32 *pio;
-       static int idx;
+       int idx = append ? mxs_chan->desc_count : 0;
 
        if (mxs_chan->status == DMA_IN_PROGRESS && !append)
                return NULL;
@@ -417,7 +391,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
                idx = 0;
        }
 
-       if (direction == DMA_NONE) {
+       if (direction == DMA_TRANS_NONE) {
                ccw = &mxs_chan->ccw[idx++];
                pio = (u32 *) sgl;
 
@@ -450,7 +424,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
                        ccw->bits |= CCW_CHAIN;
                        ccw->bits |= CCW_HALT_ON_TERM;
                        ccw->bits |= CCW_TERM_FLUSH;
-                       ccw->bits |= BF_CCW(direction == DMA_FROM_DEVICE ?
+                       ccw->bits |= BF_CCW(direction == DMA_DEV_TO_MEM ?
                                        MXS_DMA_CMD_WRITE : MXS_DMA_CMD_READ,
                                        COMMAND);
 
@@ -462,6 +436,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
                        }
                }
        }
+       mxs_chan->desc_count = idx;
 
        return &mxs_chan->desc;
 
@@ -472,7 +447,7 @@ err_out:
 
 static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic(
                struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
-               size_t period_len, enum dma_data_direction direction)
+               size_t period_len, enum dma_transfer_direction direction)
 {
        struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
        struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
@@ -515,7 +490,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic(
                ccw->bits |= CCW_IRQ;
                ccw->bits |= CCW_HALT_ON_TERM;
                ccw->bits |= CCW_TERM_FLUSH;
-               ccw->bits |= BF_CCW(direction == DMA_FROM_DEVICE ?
+               ccw->bits |= BF_CCW(direction == DMA_DEV_TO_MEM ?
                                MXS_DMA_CMD_WRITE : MXS_DMA_CMD_READ, COMMAND);
 
                dma_addr += period_len;
@@ -523,6 +498,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic(
 
                i++;
        }
+       mxs_chan->desc_count = i;
 
        return &mxs_chan->desc;
 
@@ -539,8 +515,8 @@ static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 
        switch (cmd) {
        case DMA_TERMINATE_ALL:
-               mxs_dma_disable_chan(mxs_chan);
                mxs_dma_reset_chan(mxs_chan);
+               mxs_dma_disable_chan(mxs_chan);
                break;
        case DMA_PAUSE:
                mxs_dma_pause_chan(mxs_chan);
@@ -580,7 +556,7 @@ static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma)
 
        ret = clk_prepare_enable(mxs_dma->clk);
        if (ret)
-               goto err_out;
+               return ret;
 
        ret = mxs_reset_block(mxs_dma->base);
        if (ret)
@@ -604,11 +580,8 @@ static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma)
        writel(MXS_DMA_CHANNELS_MASK << MXS_DMA_CHANNELS,
                mxs_dma->base + HW_APBHX_CTRL1 + MXS_SET_ADDR);
 
-       clk_disable_unprepare(mxs_dma->clk);
-
-       return 0;
-
 err_out:
+       clk_disable_unprepare(mxs_dma->clk);
        return ret;
 }
 
index a6d0e3dbed0748f1d666f5972b4109dfb043a3e2..823f58179f9d46a8a169dbbaf7551b1d91ec5f28 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Topcliff PCH DMA controller driver
  * Copyright (c) 2010 Intel Corporation
- * Copyright (C) 2011 OKI SEMICONDUCTOR CO., LTD.
+ * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
  *
  * 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
@@ -99,7 +99,7 @@ struct pch_dma_desc {
 struct pch_dma_chan {
        struct dma_chan         chan;
        void __iomem *membase;
-       enum dma_data_direction dir;
+       enum dma_transfer_direction dir;
        struct tasklet_struct   tasklet;
        unsigned long           err_status;
 
@@ -224,7 +224,7 @@ static void pdc_set_dir(struct dma_chan *chan)
                mask_ctl = DMA_MASK_CTL0_MODE & ~(DMA_CTL0_MODE_MASK_BITS <<
                                       (DMA_CTL0_BITS_PER_CH * chan->chan_id));
                val &= mask_mode;
-               if (pd_chan->dir == DMA_TO_DEVICE)
+               if (pd_chan->dir == DMA_MEM_TO_DEV)
                        val |= 0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id +
                                       DMA_CTL0_DIR_SHIFT_BITS);
                else
@@ -242,7 +242,7 @@ static void pdc_set_dir(struct dma_chan *chan)
                mask_ctl = DMA_MASK_CTL2_MODE & ~(DMA_CTL0_MODE_MASK_BITS <<
                                                 (DMA_CTL0_BITS_PER_CH * ch));
                val &= mask_mode;
-               if (pd_chan->dir == DMA_TO_DEVICE)
+               if (pd_chan->dir == DMA_MEM_TO_DEV)
                        val |= 0x1 << (DMA_CTL0_BITS_PER_CH * ch +
                                       DMA_CTL0_DIR_SHIFT_BITS);
                else
@@ -607,7 +607,7 @@ static void pd_issue_pending(struct dma_chan *chan)
 
 static struct dma_async_tx_descriptor *pd_prep_slave_sg(struct dma_chan *chan,
                        struct scatterlist *sgl, unsigned int sg_len,
-                       enum dma_data_direction direction, unsigned long flags)
+                       enum dma_transfer_direction direction, unsigned long flags)
 {
        struct pch_dma_chan *pd_chan = to_pd_chan(chan);
        struct pch_dma_slave *pd_slave = chan->private;
@@ -623,9 +623,9 @@ static struct dma_async_tx_descriptor *pd_prep_slave_sg(struct dma_chan *chan,
                return NULL;
        }
 
-       if (direction == DMA_FROM_DEVICE)
+       if (direction == DMA_DEV_TO_MEM)
                reg = pd_slave->rx_reg;
-       else if (direction == DMA_TO_DEVICE)
+       else if (direction == DMA_MEM_TO_DEV)
                reg = pd_slave->tx_reg;
        else
                return NULL;
@@ -1018,6 +1018,8 @@ static void __devexit pch_dma_remove(struct pci_dev *pdev)
 #define PCI_DEVICE_ID_ML7223_DMA2_4CH  0x800E
 #define PCI_DEVICE_ID_ML7223_DMA3_4CH  0x8017
 #define PCI_DEVICE_ID_ML7223_DMA4_4CH  0x803B
+#define PCI_DEVICE_ID_ML7831_DMA1_8CH  0x8810
+#define PCI_DEVICE_ID_ML7831_DMA2_4CH  0x8815
 
 DEFINE_PCI_DEVICE_TABLE(pch_dma_id_table) = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_8CH), 8 },
@@ -1030,6 +1032,8 @@ DEFINE_PCI_DEVICE_TABLE(pch_dma_id_table) = {
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA2_4CH), 4}, /* Video SPI */
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA3_4CH), 4}, /* Security */
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA4_4CH), 4}, /* FPGA */
+       { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_DMA1_8CH), 8}, /* UART */
+       { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_DMA2_4CH), 4}, /* SPI */
        { 0, },
 };
 
@@ -1057,7 +1061,7 @@ static void __exit pch_dma_exit(void)
 module_init(pch_dma_init);
 module_exit(pch_dma_exit);
 
-MODULE_DESCRIPTION("Intel EG20T PCH / OKI SEMICONDUCTOR ML7213 IOH "
+MODULE_DESCRIPTION("Intel EG20T PCH / LAPIS Semicon ML7213/ML7223/ML7831 IOH "
                   "DMA controller driver");
 MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>");
 MODULE_LICENSE("GPL v2");
index 09adcfcd953e6841e840fb9caa663212c20c03f7..b8ec03ee8e22e495e633ff95bf9faf0d02756dac 100644 (file)
@@ -350,14 +350,14 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
        case DMA_SLAVE_CONFIG:
                slave_config = (struct dma_slave_config *)arg;
 
-               if (slave_config->direction == DMA_TO_DEVICE) {
+               if (slave_config->direction == DMA_MEM_TO_DEV) {
                        if (slave_config->dst_addr)
                                pch->fifo_addr = slave_config->dst_addr;
                        if (slave_config->dst_addr_width)
                                pch->burst_sz = __ffs(slave_config->dst_addr_width);
                        if (slave_config->dst_maxburst)
                                pch->burst_len = slave_config->dst_maxburst;
-               } else if (slave_config->direction == DMA_FROM_DEVICE) {
+               } else if (slave_config->direction == DMA_DEV_TO_MEM) {
                        if (slave_config->src_addr)
                                pch->fifo_addr = slave_config->src_addr;
                        if (slave_config->src_addr_width)
@@ -621,7 +621,7 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)
 
 static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
                struct dma_chan *chan, dma_addr_t dma_addr, size_t len,
-               size_t period_len, enum dma_data_direction direction)
+               size_t period_len, enum dma_transfer_direction direction)
 {
        struct dma_pl330_desc *desc;
        struct dma_pl330_chan *pch = to_pchan(chan);
@@ -636,14 +636,14 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
        }
 
        switch (direction) {
-       case DMA_TO_DEVICE:
+       case DMA_MEM_TO_DEV:
                desc->rqcfg.src_inc = 1;
                desc->rqcfg.dst_inc = 0;
                desc->req.rqtype = MEMTODEV;
                src = dma_addr;
                dst = pch->fifo_addr;
                break;
-       case DMA_FROM_DEVICE:
+       case DMA_DEV_TO_MEM:
                desc->rqcfg.src_inc = 0;
                desc->rqcfg.dst_inc = 1;
                desc->req.rqtype = DEVTOMEM;
@@ -710,7 +710,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
 
 static struct dma_async_tx_descriptor *
 pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned int sg_len, enum dma_transfer_direction direction,
                unsigned long flg)
 {
        struct dma_pl330_desc *first, *desc = NULL;
@@ -759,7 +759,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                else
                        list_add_tail(&desc->node, &first->node);
 
-               if (direction == DMA_TO_DEVICE) {
+               if (direction == DMA_MEM_TO_DEV) {
                        desc->rqcfg.src_inc = 1;
                        desc->rqcfg.dst_inc = 0;
                        desc->req.rqtype = MEMTODEV;
@@ -834,17 +834,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 
        amba_set_drvdata(adev, pdmac);
 
-#ifdef CONFIG_PM_RUNTIME
-       /* to use the runtime PM helper functions */
-       pm_runtime_enable(&adev->dev);
-
-       /* enable the power domain */
-       if (pm_runtime_get_sync(&adev->dev)) {
-               dev_err(&adev->dev, "failed to get runtime pm\n");
-               ret = -ENODEV;
-               goto probe_err1;
-       }
-#else
+#ifndef CONFIG_PM_RUNTIME
        /* enable dma clk */
        clk_enable(pdmac->clk);
 #endif
@@ -977,10 +967,7 @@ static int __devexit pl330_remove(struct amba_device *adev)
        res = &adev->res;
        release_mem_region(res->start, resource_size(res));
 
-#ifdef CONFIG_PM_RUNTIME
-       pm_runtime_put(&adev->dev);
-       pm_runtime_disable(&adev->dev);
-#else
+#ifndef CONFIG_PM_RUNTIME
        clk_disable(pdmac->clk);
 #endif
 
index 81809c2b46abef271cb2ac90408914990d0376a7..54043cd831c8e5b01875e08da6e8870343406134 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/interrupt.h>
 #include <linux/dmaengine.h>
 #include <linux/delay.h>
-#include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/sh_dma.h>
@@ -57,6 +56,15 @@ static LIST_HEAD(sh_dmae_devices);
 static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SH_DMA_SLAVE_NUMBER)];
 
 static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all);
+static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan);
+
+static void chclr_write(struct sh_dmae_chan *sh_dc, u32 data)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
+
+       __raw_writel(data, shdev->chan_reg +
+                    shdev->pdata->channel[sh_dc->id].chclr_offset);
+}
 
 static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg)
 {
@@ -129,6 +137,15 @@ static int sh_dmae_rst(struct sh_dmae_device *shdev)
 
        dmaor = dmaor_read(shdev) & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME);
 
+       if (shdev->pdata->chclr_present) {
+               int i;
+               for (i = 0; i < shdev->pdata->channel_num; i++) {
+                       struct sh_dmae_chan *sh_chan = shdev->chan[i];
+                       if (sh_chan)
+                               chclr_write(sh_chan, 0);
+               }
+       }
+
        dmaor_write(shdev, dmaor | shdev->pdata->dmaor_init);
 
        dmaor = dmaor_read(shdev);
@@ -139,6 +156,10 @@ static int sh_dmae_rst(struct sh_dmae_device *shdev)
                dev_warn(shdev->common.dev, "Can't initialize DMAOR.\n");
                return -EIO;
        }
+       if (shdev->pdata->dmaor_init & ~dmaor)
+               dev_warn(shdev->common.dev,
+                        "DMAOR=0x%x hasn't latched the initial value 0x%x.\n",
+                        dmaor, shdev->pdata->dmaor_init);
        return 0;
 }
 
@@ -259,8 +280,6 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
        return 0;
 }
 
-static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan);
-
 static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx)
 {
        struct sh_desc *desc = tx_to_sh_desc(tx), *chunk, *last = desc, *c;
@@ -340,6 +359,8 @@ static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx)
                                sh_chan_xfer_ld_queue(sh_chan);
                        sh_chan->pm_state = DMAE_PM_ESTABLISHED;
                }
+       } else {
+               sh_chan->pm_state = DMAE_PM_PENDING;
        }
 
        spin_unlock_irq(&sh_chan->desc_lock);
@@ -479,19 +500,19 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
  * @sh_chan:   DMA channel
  * @flags:     DMA transfer flags
  * @dest:      destination DMA address, incremented when direction equals
- *             DMA_FROM_DEVICE or DMA_BIDIRECTIONAL
+ *             DMA_DEV_TO_MEM
  * @src:       source DMA address, incremented when direction equals
- *             DMA_TO_DEVICE or DMA_BIDIRECTIONAL
+ *             DMA_MEM_TO_DEV
  * @len:       DMA transfer length
  * @first:     if NULL, set to the current descriptor and cookie set to -EBUSY
  * @direction: needed for slave DMA to decide which address to keep constant,
- *             equals DMA_BIDIRECTIONAL for MEMCPY
+ *             equals DMA_MEM_TO_MEM for MEMCPY
  * Returns 0 or an error
  * Locks: called with desc_lock held
  */
 static struct sh_desc *sh_dmae_add_desc(struct sh_dmae_chan *sh_chan,
        unsigned long flags, dma_addr_t *dest, dma_addr_t *src, size_t *len,
-       struct sh_desc **first, enum dma_data_direction direction)
+       struct sh_desc **first, enum dma_transfer_direction direction)
 {
        struct sh_desc *new;
        size_t copy_size;
@@ -531,9 +552,9 @@ static struct sh_desc *sh_dmae_add_desc(struct sh_dmae_chan *sh_chan,
        new->direction = direction;
 
        *len -= copy_size;
-       if (direction == DMA_BIDIRECTIONAL || direction == DMA_TO_DEVICE)
+       if (direction == DMA_MEM_TO_MEM || direction == DMA_MEM_TO_DEV)
                *src += copy_size;
-       if (direction == DMA_BIDIRECTIONAL || direction == DMA_FROM_DEVICE)
+       if (direction == DMA_MEM_TO_MEM || direction == DMA_DEV_TO_MEM)
                *dest += copy_size;
 
        return new;
@@ -546,12 +567,12 @@ static struct sh_desc *sh_dmae_add_desc(struct sh_dmae_chan *sh_chan,
  * converted to scatter-gather to guarantee consistent locking and a correct
  * list manipulation. For slave DMA direction carries the usual meaning, and,
  * logically, the SG list is RAM and the addr variable contains slave address,
- * e.g., the FIFO I/O register. For MEMCPY direction equals DMA_BIDIRECTIONAL
+ * e.g., the FIFO I/O register. For MEMCPY direction equals DMA_MEM_TO_MEM
  * and the SG list contains only one element and points at the source buffer.
  */
 static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_chan,
        struct scatterlist *sgl, unsigned int sg_len, dma_addr_t *addr,
-       enum dma_data_direction direction, unsigned long flags)
+       enum dma_transfer_direction direction, unsigned long flags)
 {
        struct scatterlist *sg;
        struct sh_desc *first = NULL, *new = NULL /* compiler... */;
@@ -592,7 +613,7 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_c
                        dev_dbg(sh_chan->dev, "Add SG #%d@%p[%d], dma %llx\n",
                                i, sg, len, (unsigned long long)sg_addr);
 
-                       if (direction == DMA_FROM_DEVICE)
+                       if (direction == DMA_DEV_TO_MEM)
                                new = sh_dmae_add_desc(sh_chan, flags,
                                                &sg_addr, addr, &len, &first,
                                                direction);
@@ -646,13 +667,13 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy(
        sg_dma_address(&sg) = dma_src;
        sg_dma_len(&sg) = len;
 
-       return sh_dmae_prep_sg(sh_chan, &sg, 1, &dma_dest, DMA_BIDIRECTIONAL,
+       return sh_dmae_prep_sg(sh_chan, &sg, 1, &dma_dest, DMA_MEM_TO_MEM,
                               flags);
 }
 
 static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg(
        struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len,
-       enum dma_data_direction direction, unsigned long flags)
+       enum dma_transfer_direction direction, unsigned long flags)
 {
        struct sh_dmae_slave *param;
        struct sh_dmae_chan *sh_chan;
@@ -996,7 +1017,7 @@ static void dmae_do_tasklet(unsigned long data)
        spin_lock_irq(&sh_chan->desc_lock);
        list_for_each_entry(desc, &sh_chan->ld_queue, node) {
                if (desc->mark == DESC_SUBMITTED &&
-                   ((desc->direction == DMA_FROM_DEVICE &&
+                   ((desc->direction == DMA_DEV_TO_MEM &&
                      (desc->hw.dar + desc->hw.tcr) == dar_buf) ||
                     (desc->hw.sar + desc->hw.tcr) == sar_buf)) {
                        dev_dbg(sh_chan->dev, "done #%d@%p dst %u\n",
@@ -1225,6 +1246,8 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, shdev);
 
+       shdev->common.dev = &pdev->dev;
+
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);
 
@@ -1254,7 +1277,6 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
        shdev->common.device_prep_slave_sg = sh_dmae_prep_slave_sg;
        shdev->common.device_control = sh_dmae_control;
 
-       shdev->common.dev = &pdev->dev;
        /* Default transfer size of 32 bytes requires 32-byte alignment */
        shdev->common.copy_align = LOG2_DEFAULT_XFER_SIZE;
 
@@ -1435,22 +1457,17 @@ static int sh_dmae_runtime_resume(struct device *dev)
 #ifdef CONFIG_PM
 static int sh_dmae_suspend(struct device *dev)
 {
-       struct sh_dmae_device *shdev = dev_get_drvdata(dev);
-       int i;
-
-       for (i = 0; i < shdev->pdata->channel_num; i++) {
-               struct sh_dmae_chan *sh_chan = shdev->chan[i];
-               if (sh_chan->descs_allocated)
-                       sh_chan->pm_error = pm_runtime_put_sync(dev);
-       }
-
        return 0;
 }
 
 static int sh_dmae_resume(struct device *dev)
 {
        struct sh_dmae_device *shdev = dev_get_drvdata(dev);
-       int i;
+       int i, ret;
+
+       ret = sh_dmae_rst(shdev);
+       if (ret < 0)
+               dev_err(dev, "Failed to reset!\n");
 
        for (i = 0; i < shdev->pdata->channel_num; i++) {
                struct sh_dmae_chan *sh_chan = shdev->chan[i];
@@ -1459,9 +1476,6 @@ static int sh_dmae_resume(struct device *dev)
                if (!sh_chan->descs_allocated)
                        continue;
 
-               if (!sh_chan->pm_error)
-                       pm_runtime_get_sync(dev);
-
                if (param) {
                        const struct sh_dmae_slave_config *cfg = param->config;
                        dmae_set_dmars(sh_chan, cfg->mid_rid);
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
new file mode 100644 (file)
index 0000000..2333810
--- /dev/null
@@ -0,0 +1,707 @@
+/*
+ * DMA controller driver for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/sirfsoc_dma.h>
+
+#define SIRFSOC_DMA_DESCRIPTORS                 16
+#define SIRFSOC_DMA_CHANNELS                    16
+
+#define SIRFSOC_DMA_CH_ADDR                     0x00
+#define SIRFSOC_DMA_CH_XLEN                     0x04
+#define SIRFSOC_DMA_CH_YLEN                     0x08
+#define SIRFSOC_DMA_CH_CTRL                     0x0C
+
+#define SIRFSOC_DMA_WIDTH_0                     0x100
+#define SIRFSOC_DMA_CH_VALID                    0x140
+#define SIRFSOC_DMA_CH_INT                      0x144
+#define SIRFSOC_DMA_INT_EN                      0x148
+#define SIRFSOC_DMA_CH_LOOP_CTRL                0x150
+
+#define SIRFSOC_DMA_MODE_CTRL_BIT               4
+#define SIRFSOC_DMA_DIR_CTRL_BIT                5
+
+/* xlen and dma_width register is in 4 bytes boundary */
+#define SIRFSOC_DMA_WORD_LEN                   4
+
+struct sirfsoc_dma_desc {
+       struct dma_async_tx_descriptor  desc;
+       struct list_head                node;
+
+       /* SiRFprimaII 2D-DMA parameters */
+
+       int             xlen;           /* DMA xlen */
+       int             ylen;           /* DMA ylen */
+       int             width;          /* DMA width */
+       int             dir;
+       bool            cyclic;         /* is loop DMA? */
+       u32             addr;           /* DMA buffer address */
+};
+
+struct sirfsoc_dma_chan {
+       struct dma_chan                 chan;
+       struct list_head                free;
+       struct list_head                prepared;
+       struct list_head                queued;
+       struct list_head                active;
+       struct list_head                completed;
+       dma_cookie_t                    completed_cookie;
+       unsigned long                   happened_cyclic;
+       unsigned long                   completed_cyclic;
+
+       /* Lock for this structure */
+       spinlock_t                      lock;
+
+       int                             mode;
+};
+
+struct sirfsoc_dma {
+       struct dma_device               dma;
+       struct tasklet_struct           tasklet;
+       struct sirfsoc_dma_chan         channels[SIRFSOC_DMA_CHANNELS];
+       void __iomem                    *base;
+       int                             irq;
+};
+
+#define DRV_NAME       "sirfsoc_dma"
+
+/* Convert struct dma_chan to struct sirfsoc_dma_chan */
+static inline
+struct sirfsoc_dma_chan *dma_chan_to_sirfsoc_dma_chan(struct dma_chan *c)
+{
+       return container_of(c, struct sirfsoc_dma_chan, chan);
+}
+
+/* Convert struct dma_chan to struct sirfsoc_dma */
+static inline struct sirfsoc_dma *dma_chan_to_sirfsoc_dma(struct dma_chan *c)
+{
+       struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(c);
+       return container_of(schan, struct sirfsoc_dma, channels[c->chan_id]);
+}
+
+/* Execute all queued DMA descriptors */
+static void sirfsoc_dma_execute(struct sirfsoc_dma_chan *schan)
+{
+       struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan);
+       int cid = schan->chan.chan_id;
+       struct sirfsoc_dma_desc *sdesc = NULL;
+
+       /*
+        * lock has been held by functions calling this, so we don't hold
+        * lock again
+        */
+
+       sdesc = list_first_entry(&schan->queued, struct sirfsoc_dma_desc,
+               node);
+       /* Move the first queued descriptor to active list */
+       list_move_tail(&schan->queued, &schan->active);
+
+       /* Start the DMA transfer */
+       writel_relaxed(sdesc->width, sdma->base + SIRFSOC_DMA_WIDTH_0 +
+               cid * 4);
+       writel_relaxed(cid | (schan->mode << SIRFSOC_DMA_MODE_CTRL_BIT) |
+               (sdesc->dir << SIRFSOC_DMA_DIR_CTRL_BIT),
+               sdma->base + cid * 0x10 + SIRFSOC_DMA_CH_CTRL);
+       writel_relaxed(sdesc->xlen, sdma->base + cid * 0x10 +
+               SIRFSOC_DMA_CH_XLEN);
+       writel_relaxed(sdesc->ylen, sdma->base + cid * 0x10 +
+               SIRFSOC_DMA_CH_YLEN);
+       writel_relaxed(readl_relaxed(sdma->base + SIRFSOC_DMA_INT_EN) |
+               (1 << cid), sdma->base + SIRFSOC_DMA_INT_EN);
+
+       /*
+        * writel has an implict memory write barrier to make sure data is
+        * flushed into memory before starting DMA
+        */
+       writel(sdesc->addr >> 2, sdma->base + cid * 0x10 + SIRFSOC_DMA_CH_ADDR);
+
+       if (sdesc->cyclic) {
+               writel((1 << cid) | 1 << (cid + 16) |
+                       readl_relaxed(sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL),
+                       sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL);
+               schan->happened_cyclic = schan->completed_cyclic = 0;
+       }
+}
+
+/* Interrupt handler */
+static irqreturn_t sirfsoc_dma_irq(int irq, void *data)
+{
+       struct sirfsoc_dma *sdma = data;
+       struct sirfsoc_dma_chan *schan;
+       struct sirfsoc_dma_desc *sdesc = NULL;
+       u32 is;
+       int ch;
+
+       is = readl(sdma->base + SIRFSOC_DMA_CH_INT);
+       while ((ch = fls(is) - 1) >= 0) {
+               is &= ~(1 << ch);
+               writel_relaxed(1 << ch, sdma->base + SIRFSOC_DMA_CH_INT);
+               schan = &sdma->channels[ch];
+
+               spin_lock(&schan->lock);
+
+               sdesc = list_first_entry(&schan->active, struct sirfsoc_dma_desc,
+                       node);
+               if (!sdesc->cyclic) {
+                       /* Execute queued descriptors */
+                       list_splice_tail_init(&schan->active, &schan->completed);
+                       if (!list_empty(&schan->queued))
+                               sirfsoc_dma_execute(schan);
+               } else
+                       schan->happened_cyclic++;
+
+               spin_unlock(&schan->lock);
+       }
+
+       /* Schedule tasklet */
+       tasklet_schedule(&sdma->tasklet);
+
+       return IRQ_HANDLED;
+}
+
+/* process completed descriptors */
+static void sirfsoc_dma_process_completed(struct sirfsoc_dma *sdma)
+{
+       dma_cookie_t last_cookie = 0;
+       struct sirfsoc_dma_chan *schan;
+       struct sirfsoc_dma_desc *sdesc;
+       struct dma_async_tx_descriptor *desc;
+       unsigned long flags;
+       unsigned long happened_cyclic;
+       LIST_HEAD(list);
+       int i;
+
+       for (i = 0; i < sdma->dma.chancnt; i++) {
+               schan = &sdma->channels[i];
+
+               /* Get all completed descriptors */
+               spin_lock_irqsave(&schan->lock, flags);
+               if (!list_empty(&schan->completed)) {
+                       list_splice_tail_init(&schan->completed, &list);
+                       spin_unlock_irqrestore(&schan->lock, flags);
+
+                       /* Execute callbacks and run dependencies */
+                       list_for_each_entry(sdesc, &list, node) {
+                               desc = &sdesc->desc;
+
+                               if (desc->callback)
+                                       desc->callback(desc->callback_param);
+
+                               last_cookie = desc->cookie;
+                               dma_run_dependencies(desc);
+                       }
+
+                       /* Free descriptors */
+                       spin_lock_irqsave(&schan->lock, flags);
+                       list_splice_tail_init(&list, &schan->free);
+                       schan->completed_cookie = last_cookie;
+                       spin_unlock_irqrestore(&schan->lock, flags);
+               } else {
+                       /* for cyclic channel, desc is always in active list */
+                       sdesc = list_first_entry(&schan->active, struct sirfsoc_dma_desc,
+                               node);
+
+                       if (!sdesc || (sdesc && !sdesc->cyclic)) {
+                               /* without active cyclic DMA */
+                               spin_unlock_irqrestore(&schan->lock, flags);
+                               continue;
+                       }
+
+                       /* cyclic DMA */
+                       happened_cyclic = schan->happened_cyclic;
+                       spin_unlock_irqrestore(&schan->lock, flags);
+
+                       desc = &sdesc->desc;
+                       while (happened_cyclic != schan->completed_cyclic) {
+                               if (desc->callback)
+                                       desc->callback(desc->callback_param);
+                               schan->completed_cyclic++;
+                       }
+               }
+       }
+}
+
+/* DMA Tasklet */
+static void sirfsoc_dma_tasklet(unsigned long data)
+{
+       struct sirfsoc_dma *sdma = (void *)data;
+
+       sirfsoc_dma_process_completed(sdma);
+}
+
+/* Submit descriptor to hardware */
+static dma_cookie_t sirfsoc_dma_tx_submit(struct dma_async_tx_descriptor *txd)
+{
+       struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(txd->chan);
+       struct sirfsoc_dma_desc *sdesc;
+       unsigned long flags;
+       dma_cookie_t cookie;
+
+       sdesc = container_of(txd, struct sirfsoc_dma_desc, desc);
+
+       spin_lock_irqsave(&schan->lock, flags);
+
+       /* Move descriptor to queue */
+       list_move_tail(&sdesc->node, &schan->queued);
+
+       /* Update cookie */
+       cookie = schan->chan.cookie + 1;
+       if (cookie <= 0)
+               cookie = 1;
+
+       schan->chan.cookie = cookie;
+       sdesc->desc.cookie = cookie;
+
+       spin_unlock_irqrestore(&schan->lock, flags);
+
+       return cookie;
+}
+
+static int sirfsoc_dma_slave_config(struct sirfsoc_dma_chan *schan,
+       struct dma_slave_config *config)
+{
+       unsigned long flags;
+
+       if ((config->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
+               (config->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES))
+               return -EINVAL;
+
+       spin_lock_irqsave(&schan->lock, flags);
+       schan->mode = (config->src_maxburst == 4 ? 1 : 0);
+       spin_unlock_irqrestore(&schan->lock, flags);
+
+       return 0;
+}
+
+static int sirfsoc_dma_terminate_all(struct sirfsoc_dma_chan *schan)
+{
+       struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan);
+       int cid = schan->chan.chan_id;
+       unsigned long flags;
+
+       writel_relaxed(readl_relaxed(sdma->base + SIRFSOC_DMA_INT_EN) &
+               ~(1 << cid), sdma->base + SIRFSOC_DMA_INT_EN);
+       writel_relaxed(1 << cid, sdma->base + SIRFSOC_DMA_CH_VALID);
+
+       writel_relaxed(readl_relaxed(sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL)
+               & ~((1 << cid) | 1 << (cid + 16)),
+                       sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL);
+
+       spin_lock_irqsave(&schan->lock, flags);
+       list_splice_tail_init(&schan->active, &schan->free);
+       list_splice_tail_init(&schan->queued, &schan->free);
+       spin_unlock_irqrestore(&schan->lock, flags);
+
+       return 0;
+}
+
+static int sirfsoc_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+       unsigned long arg)
+{
+       struct dma_slave_config *config;
+       struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
+
+       switch (cmd) {
+       case DMA_TERMINATE_ALL:
+               return sirfsoc_dma_terminate_all(schan);
+       case DMA_SLAVE_CONFIG:
+               config = (struct dma_slave_config *)arg;
+               return sirfsoc_dma_slave_config(schan, config);
+
+       default:
+               break;
+       }
+
+       return -ENOSYS;
+}
+
+/* Alloc channel resources */
+static int sirfsoc_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+       struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan);
+       struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
+       struct sirfsoc_dma_desc *sdesc;
+       unsigned long flags;
+       LIST_HEAD(descs);
+       int i;
+
+       /* Alloc descriptors for this channel */
+       for (i = 0; i < SIRFSOC_DMA_DESCRIPTORS; i++) {
+               sdesc = kzalloc(sizeof(*sdesc), GFP_KERNEL);
+               if (!sdesc) {
+                       dev_notice(sdma->dma.dev, "Memory allocation error. "
+                               "Allocated only %u descriptors\n", i);
+                       break;
+               }
+
+               dma_async_tx_descriptor_init(&sdesc->desc, chan);
+               sdesc->desc.flags = DMA_CTRL_ACK;
+               sdesc->desc.tx_submit = sirfsoc_dma_tx_submit;
+
+               list_add_tail(&sdesc->node, &descs);
+       }
+
+       /* Return error only if no descriptors were allocated */
+       if (i == 0)
+               return -ENOMEM;
+
+       spin_lock_irqsave(&schan->lock, flags);
+
+       list_splice_tail_init(&descs, &schan->free);
+       spin_unlock_irqrestore(&schan->lock, flags);
+
+       return i;
+}
+
+/* Free channel resources */
+static void sirfsoc_dma_free_chan_resources(struct dma_chan *chan)
+{
+       struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
+       struct sirfsoc_dma_desc *sdesc, *tmp;
+       unsigned long flags;
+       LIST_HEAD(descs);
+
+       spin_lock_irqsave(&schan->lock, flags);
+
+       /* Channel must be idle */
+       BUG_ON(!list_empty(&schan->prepared));
+       BUG_ON(!list_empty(&schan->queued));
+       BUG_ON(!list_empty(&schan->active));
+       BUG_ON(!list_empty(&schan->completed));
+
+       /* Move data */
+       list_splice_tail_init(&schan->free, &descs);
+
+       spin_unlock_irqrestore(&schan->lock, flags);
+
+       /* Free descriptors */
+       list_for_each_entry_safe(sdesc, tmp, &descs, node)
+               kfree(sdesc);
+}
+
+/* Send pending descriptor to hardware */
+static void sirfsoc_dma_issue_pending(struct dma_chan *chan)
+{
+       struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&schan->lock, flags);
+
+       if (list_empty(&schan->active) && !list_empty(&schan->queued))
+               sirfsoc_dma_execute(schan);
+
+       spin_unlock_irqrestore(&schan->lock, flags);
+}
+
+/* Check request completion status */
+static enum dma_status
+sirfsoc_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
+       struct dma_tx_state *txstate)
+{
+       struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
+       unsigned long flags;
+       dma_cookie_t last_used;
+       dma_cookie_t last_complete;
+
+       spin_lock_irqsave(&schan->lock, flags);
+       last_used = schan->chan.cookie;
+       last_complete = schan->completed_cookie;
+       spin_unlock_irqrestore(&schan->lock, flags);
+
+       dma_set_tx_state(txstate, last_complete, last_used, 0);
+       return dma_async_is_complete(cookie, last_complete, last_used);
+}
+
+static struct dma_async_tx_descriptor *sirfsoc_dma_prep_interleaved(
+       struct dma_chan *chan, struct dma_interleaved_template *xt,
+       unsigned long flags)
+{
+       struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan);
+       struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
+       struct sirfsoc_dma_desc *sdesc = NULL;
+       unsigned long iflags;
+       int ret;
+
+       if ((xt->dir != DMA_MEM_TO_DEV) || (xt->dir != DMA_DEV_TO_MEM)) {
+               ret = -EINVAL;
+               goto err_dir;
+       }
+
+       /* Get free descriptor */
+       spin_lock_irqsave(&schan->lock, iflags);
+       if (!list_empty(&schan->free)) {
+               sdesc = list_first_entry(&schan->free, struct sirfsoc_dma_desc,
+                       node);
+               list_del(&sdesc->node);
+       }
+       spin_unlock_irqrestore(&schan->lock, iflags);
+
+       if (!sdesc) {
+               /* try to free completed descriptors */
+               sirfsoc_dma_process_completed(sdma);
+               ret = 0;
+               goto no_desc;
+       }
+
+       /* Place descriptor in prepared list */
+       spin_lock_irqsave(&schan->lock, iflags);
+
+       /*
+        * Number of chunks in a frame can only be 1 for prima2
+        * and ylen (number of frame - 1) must be at least 0
+        */
+       if ((xt->frame_size == 1) && (xt->numf > 0)) {
+               sdesc->cyclic = 0;
+               sdesc->xlen = xt->sgl[0].size / SIRFSOC_DMA_WORD_LEN;
+               sdesc->width = (xt->sgl[0].size + xt->sgl[0].icg) /
+                               SIRFSOC_DMA_WORD_LEN;
+               sdesc->ylen = xt->numf - 1;
+               if (xt->dir == DMA_MEM_TO_DEV) {
+                       sdesc->addr = xt->src_start;
+                       sdesc->dir = 1;
+               } else {
+                       sdesc->addr = xt->dst_start;
+                       sdesc->dir = 0;
+               }
+
+               list_add_tail(&sdesc->node, &schan->prepared);
+       } else {
+               pr_err("sirfsoc DMA Invalid xfer\n");
+               ret = -EINVAL;
+               goto err_xfer;
+       }
+       spin_unlock_irqrestore(&schan->lock, iflags);
+
+       return &sdesc->desc;
+err_xfer:
+       spin_unlock_irqrestore(&schan->lock, iflags);
+no_desc:
+err_dir:
+       return ERR_PTR(ret);
+}
+
+static struct dma_async_tx_descriptor *
+sirfsoc_dma_prep_cyclic(struct dma_chan *chan, dma_addr_t addr,
+       size_t buf_len, size_t period_len,
+       enum dma_transfer_direction direction)
+{
+       struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
+       struct sirfsoc_dma_desc *sdesc = NULL;
+       unsigned long iflags;
+
+       /*
+        * we only support cycle transfer with 2 period
+        * If the X-length is set to 0, it would be the loop mode.
+        * The DMA address keeps increasing until reaching the end of a loop
+        * area whose size is defined by (DMA_WIDTH x (Y_LENGTH + 1)). Then
+        * the DMA address goes back to the beginning of this area.
+        * In loop mode, the DMA data region is divided into two parts, BUFA
+        * and BUFB. DMA controller generates interrupts twice in each loop:
+        * when the DMA address reaches the end of BUFA or the end of the
+        * BUFB
+        */
+       if (buf_len !=  2 * period_len)
+               return ERR_PTR(-EINVAL);
+
+       /* Get free descriptor */
+       spin_lock_irqsave(&schan->lock, iflags);
+       if (!list_empty(&schan->free)) {
+               sdesc = list_first_entry(&schan->free, struct sirfsoc_dma_desc,
+                       node);
+               list_del(&sdesc->node);
+       }
+       spin_unlock_irqrestore(&schan->lock, iflags);
+
+       if (!sdesc)
+               return 0;
+
+       /* Place descriptor in prepared list */
+       spin_lock_irqsave(&schan->lock, iflags);
+       sdesc->addr = addr;
+       sdesc->cyclic = 1;
+       sdesc->xlen = 0;
+       sdesc->ylen = buf_len / SIRFSOC_DMA_WORD_LEN - 1;
+       sdesc->width = 1;
+       list_add_tail(&sdesc->node, &schan->prepared);
+       spin_unlock_irqrestore(&schan->lock, iflags);
+
+       return &sdesc->desc;
+}
+
+/*
+ * The DMA controller consists of 16 independent DMA channels.
+ * Each channel is allocated to a different function
+ */
+bool sirfsoc_dma_filter_id(struct dma_chan *chan, void *chan_id)
+{
+       unsigned int ch_nr = (unsigned int) chan_id;
+
+       if (ch_nr == chan->chan_id +
+               chan->device->dev_id * SIRFSOC_DMA_CHANNELS)
+               return true;
+
+       return false;
+}
+EXPORT_SYMBOL(sirfsoc_dma_filter_id);
+
+static int __devinit sirfsoc_dma_probe(struct platform_device *op)
+{
+       struct device_node *dn = op->dev.of_node;
+       struct device *dev = &op->dev;
+       struct dma_device *dma;
+       struct sirfsoc_dma *sdma;
+       struct sirfsoc_dma_chan *schan;
+       struct resource res;
+       ulong regs_start, regs_size;
+       u32 id;
+       int ret, i;
+
+       sdma = devm_kzalloc(dev, sizeof(*sdma), GFP_KERNEL);
+       if (!sdma) {
+               dev_err(dev, "Memory exhausted!\n");
+               return -ENOMEM;
+       }
+
+       if (of_property_read_u32(dn, "cell-index", &id)) {
+               dev_err(dev, "Fail to get DMAC index\n");
+               ret = -ENODEV;
+               goto free_mem;
+       }
+
+       sdma->irq = irq_of_parse_and_map(dn, 0);
+       if (sdma->irq == NO_IRQ) {
+               dev_err(dev, "Error mapping IRQ!\n");
+               ret = -EINVAL;
+               goto free_mem;
+       }
+
+       ret = of_address_to_resource(dn, 0, &res);
+       if (ret) {
+               dev_err(dev, "Error parsing memory region!\n");
+               goto free_mem;
+       }
+
+       regs_start = res.start;
+       regs_size = resource_size(&res);
+
+       sdma->base = devm_ioremap(dev, regs_start, regs_size);
+       if (!sdma->base) {
+               dev_err(dev, "Error mapping memory region!\n");
+               ret = -ENOMEM;
+               goto irq_dispose;
+       }
+
+       ret = devm_request_irq(dev, sdma->irq, &sirfsoc_dma_irq, 0, DRV_NAME,
+               sdma);
+       if (ret) {
+               dev_err(dev, "Error requesting IRQ!\n");
+               ret = -EINVAL;
+               goto unmap_mem;
+       }
+
+       dma = &sdma->dma;
+       dma->dev = dev;
+       dma->chancnt = SIRFSOC_DMA_CHANNELS;
+
+       dma->device_alloc_chan_resources = sirfsoc_dma_alloc_chan_resources;
+       dma->device_free_chan_resources = sirfsoc_dma_free_chan_resources;
+       dma->device_issue_pending = sirfsoc_dma_issue_pending;
+       dma->device_control = sirfsoc_dma_control;
+       dma->device_tx_status = sirfsoc_dma_tx_status;
+       dma->device_prep_interleaved_dma = sirfsoc_dma_prep_interleaved;
+       dma->device_prep_dma_cyclic = sirfsoc_dma_prep_cyclic;
+
+       INIT_LIST_HEAD(&dma->channels);
+       dma_cap_set(DMA_SLAVE, dma->cap_mask);
+       dma_cap_set(DMA_CYCLIC, dma->cap_mask);
+       dma_cap_set(DMA_INTERLEAVE, dma->cap_mask);
+       dma_cap_set(DMA_PRIVATE, dma->cap_mask);
+
+       for (i = 0; i < dma->chancnt; i++) {
+               schan = &sdma->channels[i];
+
+               schan->chan.device = dma;
+               schan->chan.cookie = 1;
+               schan->completed_cookie = schan->chan.cookie;
+
+               INIT_LIST_HEAD(&schan->free);
+               INIT_LIST_HEAD(&schan->prepared);
+               INIT_LIST_HEAD(&schan->queued);
+               INIT_LIST_HEAD(&schan->active);
+               INIT_LIST_HEAD(&schan->completed);
+
+               spin_lock_init(&schan->lock);
+               list_add_tail(&schan->chan.device_node, &dma->channels);
+       }
+
+       tasklet_init(&sdma->tasklet, sirfsoc_dma_tasklet, (unsigned long)sdma);
+
+       /* Register DMA engine */
+       dev_set_drvdata(dev, sdma);
+       ret = dma_async_device_register(dma);
+       if (ret)
+               goto free_irq;
+
+       dev_info(dev, "initialized SIRFSOC DMAC driver\n");
+
+       return 0;
+
+free_irq:
+       devm_free_irq(dev, sdma->irq, sdma);
+irq_dispose:
+       irq_dispose_mapping(sdma->irq);
+unmap_mem:
+       iounmap(sdma->base);
+free_mem:
+       devm_kfree(dev, sdma);
+       return ret;
+}
+
+static int __devexit sirfsoc_dma_remove(struct platform_device *op)
+{
+       struct device *dev = &op->dev;
+       struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
+
+       dma_async_device_unregister(&sdma->dma);
+       devm_free_irq(dev, sdma->irq, sdma);
+       irq_dispose_mapping(sdma->irq);
+       iounmap(sdma->base);
+       devm_kfree(dev, sdma);
+       return 0;
+}
+
+static struct of_device_id sirfsoc_dma_match[] = {
+       { .compatible = "sirf,prima2-dmac", },
+       {},
+};
+
+static struct platform_driver sirfsoc_dma_driver = {
+       .probe          = sirfsoc_dma_probe,
+       .remove         = __devexit_p(sirfsoc_dma_remove),
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = sirfsoc_dma_match,
+       },
+};
+
+module_platform_driver(sirfsoc_dma_driver);
+
+MODULE_AUTHOR("Rongjun Ying <rongjun.ying@csr.com>, "
+       "Barry Song <baohua.song@csr.com>");
+MODULE_DESCRIPTION("SIRFSOC DMA control driver");
+MODULE_LICENSE("GPL v2");
index 13259cad0ceb61df6a593af758ebf1aec4ec877b..cc5ecbc067a3d8a8d88c97190b0248fb0851593b 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
 #include <linux/err.h>
 #include <linux/amba/bus.h>
 
@@ -32,6 +34,9 @@
 /* Maximum iterations taken before giving up suspending a channel */
 #define D40_SUSPEND_MAX_IT 500
 
+/* Milliseconds */
+#define DMA40_AUTOSUSPEND_DELAY        100
+
 /* Hardware requirement on LCLA alignment */
 #define LCLA_ALIGNMENT 0x40000
 
@@ -62,6 +67,55 @@ enum d40_command {
        D40_DMA_SUSPENDED       = 3
 };
 
+/*
+ * These are the registers that has to be saved and later restored
+ * when the DMA hw is powered off.
+ * TODO: Add save/restore of D40_DREG_GCC on dma40 v3 or later, if that works.
+ */
+static u32 d40_backup_regs[] = {
+       D40_DREG_LCPA,
+       D40_DREG_LCLA,
+       D40_DREG_PRMSE,
+       D40_DREG_PRMSO,
+       D40_DREG_PRMOE,
+       D40_DREG_PRMOO,
+};
+
+#define BACKUP_REGS_SZ ARRAY_SIZE(d40_backup_regs)
+
+/* TODO: Check if all these registers have to be saved/restored on dma40 v3 */
+static u32 d40_backup_regs_v3[] = {
+       D40_DREG_PSEG1,
+       D40_DREG_PSEG2,
+       D40_DREG_PSEG3,
+       D40_DREG_PSEG4,
+       D40_DREG_PCEG1,
+       D40_DREG_PCEG2,
+       D40_DREG_PCEG3,
+       D40_DREG_PCEG4,
+       D40_DREG_RSEG1,
+       D40_DREG_RSEG2,
+       D40_DREG_RSEG3,
+       D40_DREG_RSEG4,
+       D40_DREG_RCEG1,
+       D40_DREG_RCEG2,
+       D40_DREG_RCEG3,
+       D40_DREG_RCEG4,
+};
+
+#define BACKUP_REGS_SZ_V3 ARRAY_SIZE(d40_backup_regs_v3)
+
+static u32 d40_backup_regs_chan[] = {
+       D40_CHAN_REG_SSCFG,
+       D40_CHAN_REG_SSELT,
+       D40_CHAN_REG_SSPTR,
+       D40_CHAN_REG_SSLNK,
+       D40_CHAN_REG_SDCFG,
+       D40_CHAN_REG_SDELT,
+       D40_CHAN_REG_SDPTR,
+       D40_CHAN_REG_SDLNK,
+};
+
 /**
  * struct d40_lli_pool - Structure for keeping LLIs in memory
  *
@@ -96,7 +150,7 @@ struct d40_lli_pool {
  * during a transfer.
  * @node: List entry.
  * @is_in_client_list: true if the client owns this descriptor.
- * the previous one.
+ * @cyclic: true if this is a cyclic job
  *
  * This descriptor is used for both logical and physical transfers.
  */
@@ -143,6 +197,7 @@ struct d40_lcla_pool {
  * channels.
  *
  * @lock: A lock protection this entity.
+ * @reserved: True if used by secure world or otherwise.
  * @num: The physical channel number of this entity.
  * @allocated_src: Bit mapped to show which src event line's are mapped to
  * this physical channel. Can also be free or physically allocated.
@@ -152,6 +207,7 @@ struct d40_lcla_pool {
  */
 struct d40_phy_res {
        spinlock_t lock;
+       bool       reserved;
        int        num;
        u32        allocated_src;
        u32        allocated_dst;
@@ -185,7 +241,6 @@ struct d40_base;
  * @src_def_cfg: Default cfg register setting for src.
  * @dst_def_cfg: Default cfg register setting for dst.
  * @log_def: Default logical channel settings.
- * @lcla: Space for one dst src pair for logical channel transfers.
  * @lcpa: Pointer to dst and src lcpa settings.
  * @runtime_addr: runtime configured address.
  * @runtime_direction: runtime configured direction.
@@ -217,7 +272,7 @@ struct d40_chan {
        struct d40_log_lli_full         *lcpa;
        /* Runtime reconfiguration */
        dma_addr_t                      runtime_addr;
-       enum dma_data_direction         runtime_direction;
+       enum dma_transfer_direction     runtime_direction;
 };
 
 /**
@@ -241,6 +296,7 @@ struct d40_chan {
  * @dma_both: dma_device channels that can do both memcpy and slave transfers.
  * @dma_slave: dma_device channels that can do only do slave transfers.
  * @dma_memcpy: dma_device channels that can do only do memcpy transfers.
+ * @phy_chans: Room for all possible physical channels in system.
  * @log_chans: Room for all possible logical channels in system.
  * @lookup_log_chans: Used to map interrupt number to logical channel. Points
  * to log_chans entries.
@@ -248,12 +304,20 @@ struct d40_chan {
  * to phy_chans entries.
  * @plat_data: Pointer to provided platform_data which is the driver
  * configuration.
+ * @lcpa_regulator: Pointer to hold the regulator for the esram bank for lcla.
  * @phy_res: Vector containing all physical channels.
  * @lcla_pool: lcla pool settings and data.
  * @lcpa_base: The virtual mapped address of LCPA.
  * @phy_lcpa: The physical address of the LCPA.
  * @lcpa_size: The size of the LCPA area.
  * @desc_slab: cache for descriptors.
+ * @reg_val_backup: Here the values of some hardware registers are stored
+ * before the DMA is powered off. They are restored when the power is back on.
+ * @reg_val_backup_v3: Backup of registers that only exits on dma40 v3 and
+ * later.
+ * @reg_val_backup_chan: Backup data for standard channel parameter registers.
+ * @gcc_pwr_off_mask: Mask to maintain the channels that can be turned off.
+ * @initialized: true if the dma has been initialized
  */
 struct d40_base {
        spinlock_t                       interrupt_lock;
@@ -275,6 +339,7 @@ struct d40_base {
        struct d40_chan                 **lookup_log_chans;
        struct d40_chan                 **lookup_phy_chans;
        struct stedma40_platform_data    *plat_data;
+       struct regulator                 *lcpa_regulator;
        /* Physical half channels */
        struct d40_phy_res               *phy_res;
        struct d40_lcla_pool              lcla_pool;
@@ -282,6 +347,11 @@ struct d40_base {
        dma_addr_t                        phy_lcpa;
        resource_size_t                   lcpa_size;
        struct kmem_cache                *desc_slab;
+       u32                               reg_val_backup[BACKUP_REGS_SZ];
+       u32                               reg_val_backup_v3[BACKUP_REGS_SZ_V3];
+       u32                              *reg_val_backup_chan;
+       u16                               gcc_pwr_off_mask;
+       bool                              initialized;
 };
 
 /**
@@ -479,13 +549,14 @@ static struct d40_desc *d40_desc_get(struct d40_chan *d40c)
                struct d40_desc *d;
                struct d40_desc *_d;
 
-               list_for_each_entry_safe(d, _d, &d40c->client, node)
+               list_for_each_entry_safe(d, _d, &d40c->client, node) {
                        if (async_tx_test_ack(&d->txd)) {
                                d40_desc_remove(d);
                                desc = d;
                                memset(desc, 0, sizeof(*desc));
                                break;
                        }
+               }
        }
 
        if (!desc)
@@ -536,6 +607,7 @@ static void d40_log_lli_to_lcxa(struct d40_chan *chan, struct d40_desc *desc)
        bool cyclic = desc->cyclic;
        int curr_lcla = -EINVAL;
        int first_lcla = 0;
+       bool use_esram_lcla = chan->base->plat_data->use_esram_lcla;
        bool linkback;
 
        /*
@@ -608,11 +680,16 @@ static void d40_log_lli_to_lcxa(struct d40_chan *chan, struct d40_desc *desc)
                                       &lli->src[lli_current],
                                       next_lcla, flags);
 
-               dma_sync_single_range_for_device(chan->base->dev,
-                                       pool->dma_addr, lcla_offset,
-                                       2 * sizeof(struct d40_log_lli),
-                                       DMA_TO_DEVICE);
-
+               /*
+                * Cache maintenance is not needed if lcla is
+                * mapped in esram
+                */
+               if (!use_esram_lcla) {
+                       dma_sync_single_range_for_device(chan->base->dev,
+                                               pool->dma_addr, lcla_offset,
+                                               2 * sizeof(struct d40_log_lli),
+                                               DMA_TO_DEVICE);
+               }
                curr_lcla = next_lcla;
 
                if (curr_lcla == -EINVAL || curr_lcla == first_lcla) {
@@ -740,7 +817,61 @@ static int d40_sg_2_dmalen(struct scatterlist *sgl, int sg_len,
        return len;
 }
 
-/* Support functions for logical channels */
+
+#ifdef CONFIG_PM
+static void dma40_backup(void __iomem *baseaddr, u32 *backup,
+                        u32 *regaddr, int num, bool save)
+{
+       int i;
+
+       for (i = 0; i < num; i++) {
+               void __iomem *addr = baseaddr + regaddr[i];
+
+               if (save)
+                       backup[i] = readl_relaxed(addr);
+               else
+                       writel_relaxed(backup[i], addr);
+       }
+}
+
+static void d40_save_restore_registers(struct d40_base *base, bool save)
+{
+       int i;
+
+       /* Save/Restore channel specific registers */
+       for (i = 0; i < base->num_phy_chans; i++) {
+               void __iomem *addr;
+               int idx;
+
+               if (base->phy_res[i].reserved)
+                       continue;
+
+               addr = base->virtbase + D40_DREG_PCBASE + i * D40_DREG_PCDELTA;
+               idx = i * ARRAY_SIZE(d40_backup_regs_chan);
+
+               dma40_backup(addr, &base->reg_val_backup_chan[idx],
+                            d40_backup_regs_chan,
+                            ARRAY_SIZE(d40_backup_regs_chan),
+                            save);
+       }
+
+       /* Save/Restore global registers */
+       dma40_backup(base->virtbase, base->reg_val_backup,
+                    d40_backup_regs, ARRAY_SIZE(d40_backup_regs),
+                    save);
+
+       /* Save/Restore registers only existing on dma40 v3 and later */
+       if (base->rev >= 3)
+               dma40_backup(base->virtbase, base->reg_val_backup_v3,
+                            d40_backup_regs_v3,
+                            ARRAY_SIZE(d40_backup_regs_v3),
+                            save);
+}
+#else
+static void d40_save_restore_registers(struct d40_base *base, bool save)
+{
+}
+#endif
 
 static int d40_channel_execute_command(struct d40_chan *d40c,
                                       enum d40_command command)
@@ -973,6 +1104,10 @@ static void d40_config_write(struct d40_chan *d40c)
                /* Set LIDX for lcla */
                writel(lidx, chanbase + D40_CHAN_REG_SSELT);
                writel(lidx, chanbase + D40_CHAN_REG_SDELT);
+
+               /* Clear LNK which will be used by d40_chan_has_events() */
+               writel(0, chanbase + D40_CHAN_REG_SSLNK);
+               writel(0, chanbase + D40_CHAN_REG_SDLNK);
        }
 }
 
@@ -1013,6 +1148,7 @@ static int d40_pause(struct d40_chan *d40c)
        if (!d40c->busy)
                return 0;
 
+       pm_runtime_get_sync(d40c->base->dev);
        spin_lock_irqsave(&d40c->lock, flags);
 
        res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
@@ -1025,7 +1161,8 @@ static int d40_pause(struct d40_chan *d40c)
                                                                  D40_DMA_RUN);
                }
        }
-
+       pm_runtime_mark_last_busy(d40c->base->dev);
+       pm_runtime_put_autosuspend(d40c->base->dev);
        spin_unlock_irqrestore(&d40c->lock, flags);
        return res;
 }
@@ -1039,7 +1176,7 @@ static int d40_resume(struct d40_chan *d40c)
                return 0;
 
        spin_lock_irqsave(&d40c->lock, flags);
-
+       pm_runtime_get_sync(d40c->base->dev);
        if (d40c->base->rev == 0)
                if (chan_is_logical(d40c)) {
                        res = d40_channel_execute_command(d40c,
@@ -1057,6 +1194,8 @@ static int d40_resume(struct d40_chan *d40c)
        }
 
 no_suspend:
+       pm_runtime_mark_last_busy(d40c->base->dev);
+       pm_runtime_put_autosuspend(d40c->base->dev);
        spin_unlock_irqrestore(&d40c->lock, flags);
        return res;
 }
@@ -1129,7 +1268,10 @@ static struct d40_desc *d40_queue_start(struct d40_chan *d40c)
        d40d = d40_first_queued(d40c);
 
        if (d40d != NULL) {
-               d40c->busy = true;
+               if (!d40c->busy)
+                       d40c->busy = true;
+
+               pm_runtime_get_sync(d40c->base->dev);
 
                /* Remove from queue */
                d40_desc_remove(d40d);
@@ -1190,6 +1332,8 @@ static void dma_tc_handle(struct d40_chan *d40c)
 
                if (d40_queue_start(d40c) == NULL)
                        d40c->busy = false;
+               pm_runtime_mark_last_busy(d40c->base->dev);
+               pm_runtime_put_autosuspend(d40c->base->dev);
        }
 
        d40c->pending_tx++;
@@ -1405,11 +1549,16 @@ static int d40_validate_conf(struct d40_chan *d40c,
        return res;
 }
 
-static bool d40_alloc_mask_set(struct d40_phy_res *phy, bool is_src,
-                              int log_event_line, bool is_log)
+static bool d40_alloc_mask_set(struct d40_phy_res *phy,
+                              bool is_src, int log_event_line, bool is_log,
+                              bool *first_user)
 {
        unsigned long flags;
        spin_lock_irqsave(&phy->lock, flags);
+
+       *first_user = ((phy->allocated_src | phy->allocated_dst)
+                       == D40_ALLOC_FREE);
+
        if (!is_log) {
                /* Physical interrupts are masked per physical full channel */
                if (phy->allocated_src == D40_ALLOC_FREE &&
@@ -1490,7 +1639,7 @@ out:
        return is_free;
 }
 
-static int d40_allocate_channel(struct d40_chan *d40c)
+static int d40_allocate_channel(struct d40_chan *d40c, bool *first_phy_user)
 {
        int dev_type;
        int event_group;
@@ -1526,7 +1675,8 @@ static int d40_allocate_channel(struct d40_chan *d40c)
                        for (i = 0; i < d40c->base->num_phy_chans; i++) {
 
                                if (d40_alloc_mask_set(&phys[i], is_src,
-                                                      0, is_log))
+                                                      0, is_log,
+                                                      first_phy_user))
                                        goto found_phy;
                        }
                } else
@@ -1536,7 +1686,8 @@ static int d40_allocate_channel(struct d40_chan *d40c)
                                        if (d40_alloc_mask_set(&phys[i],
                                                               is_src,
                                                               0,
-                                                              is_log))
+                                                              is_log,
+                                                              first_phy_user))
                                                goto found_phy;
                                }
                        }
@@ -1552,6 +1703,25 @@ found_phy:
        /* Find logical channel */
        for (j = 0; j < d40c->base->num_phy_chans; j += 8) {
                int phy_num = j + event_group * 2;
+
+               if (d40c->dma_cfg.use_fixed_channel) {
+                       i = d40c->dma_cfg.phy_channel;
+
+                       if ((i != phy_num) && (i != phy_num + 1)) {
+                               dev_err(chan2dev(d40c),
+                                       "invalid fixed phy channel %d\n", i);
+                               return -EINVAL;
+                       }
+
+                       if (d40_alloc_mask_set(&phys[i], is_src, event_line,
+                                              is_log, first_phy_user))
+                               goto found_log;
+
+                       dev_err(chan2dev(d40c),
+                               "could not allocate fixed phy channel %d\n", i);
+                       return -EINVAL;
+               }
+
                /*
                 * Spread logical channels across all available physical rather
                 * than pack every logical channel at the first available phy
@@ -1560,13 +1730,15 @@ found_phy:
                if (is_src) {
                        for (i = phy_num; i < phy_num + 2; i++) {
                                if (d40_alloc_mask_set(&phys[i], is_src,
-                                                      event_line, is_log))
+                                                      event_line, is_log,
+                                                      first_phy_user))
                                        goto found_log;
                        }
                } else {
                        for (i = phy_num + 1; i >= phy_num; i--) {
                                if (d40_alloc_mask_set(&phys[i], is_src,
-                                                      event_line, is_log))
+                                                      event_line, is_log,
+                                                      first_phy_user))
                                        goto found_log;
                        }
                }
@@ -1643,10 +1815,11 @@ static int d40_free_dma(struct d40_chan *d40c)
                return -EINVAL;
        }
 
+       pm_runtime_get_sync(d40c->base->dev);
        res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
        if (res) {
                chan_err(d40c, "suspend failed\n");
-               return res;
+               goto out;
        }
 
        if (chan_is_logical(d40c)) {
@@ -1664,13 +1837,11 @@ static int d40_free_dma(struct d40_chan *d40c)
                        if (d40_chan_has_events(d40c)) {
                                res = d40_channel_execute_command(d40c,
                                                                  D40_DMA_RUN);
-                               if (res) {
+                               if (res)
                                        chan_err(d40c,
                                                "Executing RUN command\n");
-                                       return res;
-                               }
                        }
-                       return 0;
+                       goto out;
                }
        } else {
                (void) d40_alloc_mask_free(phy, is_src, 0);
@@ -1680,13 +1851,23 @@ static int d40_free_dma(struct d40_chan *d40c)
        res = d40_channel_execute_command(d40c, D40_DMA_STOP);
        if (res) {
                chan_err(d40c, "Failed to stop channel\n");
-               return res;
+               goto out;
        }
+
+       if (d40c->busy) {
+               pm_runtime_mark_last_busy(d40c->base->dev);
+               pm_runtime_put_autosuspend(d40c->base->dev);
+       }
+
+       d40c->busy = false;
        d40c->phy_chan = NULL;
        d40c->configured = false;
        d40c->base->lookup_phy_chans[phy->num] = NULL;
+out:
 
-       return 0;
+       pm_runtime_mark_last_busy(d40c->base->dev);
+       pm_runtime_put_autosuspend(d40c->base->dev);
+       return res;
 }
 
 static bool d40_is_paused(struct d40_chan *d40c)
@@ -1855,7 +2036,7 @@ err:
 }
 
 static dma_addr_t
-d40_get_dev_addr(struct d40_chan *chan, enum dma_data_direction direction)
+d40_get_dev_addr(struct d40_chan *chan, enum dma_transfer_direction direction)
 {
        struct stedma40_platform_data *plat = chan->base->plat_data;
        struct stedma40_chan_cfg *cfg = &chan->dma_cfg;
@@ -1864,9 +2045,9 @@ d40_get_dev_addr(struct d40_chan *chan, enum dma_data_direction direction)
        if (chan->runtime_addr)
                return chan->runtime_addr;
 
-       if (direction == DMA_FROM_DEVICE)
+       if (direction == DMA_DEV_TO_MEM)
                addr = plat->dev_rx[cfg->src_dev_type];
-       else if (direction == DMA_TO_DEVICE)
+       else if (direction == DMA_MEM_TO_DEV)
                addr = plat->dev_tx[cfg->dst_dev_type];
 
        return addr;
@@ -1875,7 +2056,7 @@ d40_get_dev_addr(struct d40_chan *chan, enum dma_data_direction direction)
 static struct dma_async_tx_descriptor *
 d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src,
            struct scatterlist *sg_dst, unsigned int sg_len,
-           enum dma_data_direction direction, unsigned long dma_flags)
+           enum dma_transfer_direction direction, unsigned long dma_flags)
 {
        struct d40_chan *chan = container_of(dchan, struct d40_chan, chan);
        dma_addr_t src_dev_addr = 0;
@@ -1902,9 +2083,9 @@ d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src,
        if (direction != DMA_NONE) {
                dma_addr_t dev_addr = d40_get_dev_addr(chan, direction);
 
-               if (direction == DMA_FROM_DEVICE)
+               if (direction == DMA_DEV_TO_MEM)
                        src_dev_addr = dev_addr;
-               else if (direction == DMA_TO_DEVICE)
+               else if (direction == DMA_MEM_TO_DEV)
                        dst_dev_addr = dev_addr;
        }
 
@@ -2011,14 +2192,15 @@ static int d40_alloc_chan_resources(struct dma_chan *chan)
                        goto fail;
                }
        }
-       is_free_phy = (d40c->phy_chan == NULL);
 
-       err = d40_allocate_channel(d40c);
+       err = d40_allocate_channel(d40c, &is_free_phy);
        if (err) {
                chan_err(d40c, "Failed to allocate channel\n");
+               d40c->configured = false;
                goto fail;
        }
 
+       pm_runtime_get_sync(d40c->base->dev);
        /* Fill in basic CFG register values */
        d40_phy_cfg(&d40c->dma_cfg, &d40c->src_def_cfg,
                    &d40c->dst_def_cfg, chan_is_logical(d40c));
@@ -2038,6 +2220,12 @@ static int d40_alloc_chan_resources(struct dma_chan *chan)
                          D40_LCPA_CHAN_SIZE + D40_LCPA_CHAN_DST_DELTA;
        }
 
+       dev_dbg(chan2dev(d40c), "allocated %s channel (phy %d%s)\n",
+                chan_is_logical(d40c) ? "logical" : "physical",
+                d40c->phy_chan->num,
+                d40c->dma_cfg.use_fixed_channel ? ", fixed" : "");
+
+
        /*
         * Only write channel configuration to the DMA if the physical
         * resource is free. In case of multiple logical channels
@@ -2046,6 +2234,8 @@ static int d40_alloc_chan_resources(struct dma_chan *chan)
        if (is_free_phy)
                d40_config_write(d40c);
 fail:
+       pm_runtime_mark_last_busy(d40c->base->dev);
+       pm_runtime_put_autosuspend(d40c->base->dev);
        spin_unlock_irqrestore(&d40c->lock, flags);
        return err;
 }
@@ -2108,10 +2298,10 @@ d40_prep_memcpy_sg(struct dma_chan *chan,
 static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan,
                                                         struct scatterlist *sgl,
                                                         unsigned int sg_len,
-                                                        enum dma_data_direction direction,
+                                                        enum dma_transfer_direction direction,
                                                         unsigned long dma_flags)
 {
-       if (direction != DMA_FROM_DEVICE && direction != DMA_TO_DEVICE)
+       if (direction != DMA_DEV_TO_MEM && direction != DMA_MEM_TO_DEV)
                return NULL;
 
        return d40_prep_sg(chan, sgl, sgl, sg_len, direction, dma_flags);
@@ -2120,7 +2310,7 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan,
 static struct dma_async_tx_descriptor *
 dma40_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
                     size_t buf_len, size_t period_len,
-                    enum dma_data_direction direction)
+                    enum dma_transfer_direction direction)
 {
        unsigned int periods = buf_len / period_len;
        struct dma_async_tx_descriptor *txd;
@@ -2269,7 +2459,7 @@ static int d40_set_runtime_config(struct dma_chan *chan,
        dst_addr_width = config->dst_addr_width;
        dst_maxburst = config->dst_maxburst;
 
-       if (config->direction == DMA_FROM_DEVICE) {
+       if (config->direction == DMA_DEV_TO_MEM) {
                dma_addr_t dev_addr_rx =
                        d40c->base->plat_data->dev_rx[cfg->src_dev_type];
 
@@ -2292,7 +2482,7 @@ static int d40_set_runtime_config(struct dma_chan *chan,
                if (dst_maxburst == 0)
                        dst_maxburst = src_maxburst;
 
-       } else if (config->direction == DMA_TO_DEVICE) {
+       } else if (config->direction == DMA_MEM_TO_DEV) {
                dma_addr_t dev_addr_tx =
                        d40c->base->plat_data->dev_tx[cfg->dst_dev_type];
 
@@ -2357,7 +2547,7 @@ static int d40_set_runtime_config(struct dma_chan *chan,
                "configured channel %s for %s, data width %d/%d, "
                "maxburst %d/%d elements, LE, no flow control\n",
                dma_chan_name(chan),
-               (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
+               (config->direction == DMA_DEV_TO_MEM) ? "RX" : "TX",
                src_addr_width, dst_addr_width,
                src_maxburst, dst_maxburst);
 
@@ -2519,6 +2709,72 @@ failure1:
        return err;
 }
 
+/* Suspend resume functionality */
+#ifdef CONFIG_PM
+static int dma40_pm_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct d40_base *base = platform_get_drvdata(pdev);
+       int ret = 0;
+       if (!pm_runtime_suspended(dev))
+               return -EBUSY;
+
+       if (base->lcpa_regulator)
+               ret = regulator_disable(base->lcpa_regulator);
+       return ret;
+}
+
+static int dma40_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct d40_base *base = platform_get_drvdata(pdev);
+
+       d40_save_restore_registers(base, true);
+
+       /* Don't disable/enable clocks for v1 due to HW bugs */
+       if (base->rev != 1)
+               writel_relaxed(base->gcc_pwr_off_mask,
+                              base->virtbase + D40_DREG_GCC);
+
+       return 0;
+}
+
+static int dma40_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct d40_base *base = platform_get_drvdata(pdev);
+
+       if (base->initialized)
+               d40_save_restore_registers(base, false);
+
+       writel_relaxed(D40_DREG_GCC_ENABLE_ALL,
+                      base->virtbase + D40_DREG_GCC);
+       return 0;
+}
+
+static int dma40_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct d40_base *base = platform_get_drvdata(pdev);
+       int ret = 0;
+
+       if (base->lcpa_regulator)
+               ret = regulator_enable(base->lcpa_regulator);
+
+       return ret;
+}
+
+static const struct dev_pm_ops dma40_pm_ops = {
+       .suspend                = dma40_pm_suspend,
+       .runtime_suspend        = dma40_runtime_suspend,
+       .runtime_resume         = dma40_runtime_resume,
+       .resume                 = dma40_resume,
+};
+#define DMA40_PM_OPS   (&dma40_pm_ops)
+#else
+#define DMA40_PM_OPS   NULL
+#endif
+
 /* Initialization functions. */
 
 static int __init d40_phy_res_init(struct d40_base *base)
@@ -2527,6 +2783,7 @@ static int __init d40_phy_res_init(struct d40_base *base)
        int num_phy_chans_avail = 0;
        u32 val[2];
        int odd_even_bit = -2;
+       int gcc = D40_DREG_GCC_ENA;
 
        val[0] = readl(base->virtbase + D40_DREG_PRSME);
        val[1] = readl(base->virtbase + D40_DREG_PRSMO);
@@ -2538,9 +2795,17 @@ static int __init d40_phy_res_init(struct d40_base *base)
                        /* Mark security only channels as occupied */
                        base->phy_res[i].allocated_src = D40_ALLOC_PHY;
                        base->phy_res[i].allocated_dst = D40_ALLOC_PHY;
+                       base->phy_res[i].reserved = true;
+                       gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(i),
+                                                      D40_DREG_GCC_SRC);
+                       gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(i),
+                                                      D40_DREG_GCC_DST);
+
+
                } else {
                        base->phy_res[i].allocated_src = D40_ALLOC_FREE;
                        base->phy_res[i].allocated_dst = D40_ALLOC_FREE;
+                       base->phy_res[i].reserved = false;
                        num_phy_chans_avail++;
                }
                spin_lock_init(&base->phy_res[i].lock);
@@ -2552,6 +2817,11 @@ static int __init d40_phy_res_init(struct d40_base *base)
 
                base->phy_res[chan].allocated_src = D40_ALLOC_PHY;
                base->phy_res[chan].allocated_dst = D40_ALLOC_PHY;
+               base->phy_res[chan].reserved = true;
+               gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(chan),
+                                              D40_DREG_GCC_SRC);
+               gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(chan),
+                                              D40_DREG_GCC_DST);
                num_phy_chans_avail--;
        }
 
@@ -2572,6 +2842,15 @@ static int __init d40_phy_res_init(struct d40_base *base)
                val[0] = val[0] >> 2;
        }
 
+       /*
+        * To keep things simple, Enable all clocks initially.
+        * The clocks will get managed later post channel allocation.
+        * The clocks for the event lines on which reserved channels exists
+        * are not managed here.
+        */
+       writel(D40_DREG_GCC_ENABLE_ALL, base->virtbase + D40_DREG_GCC);
+       base->gcc_pwr_off_mask = gcc;
+
        return num_phy_chans_avail;
 }
 
@@ -2699,10 +2978,15 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
                        goto failure;
        }
 
-       base->lcla_pool.alloc_map = kzalloc(num_phy_chans *
-                                           sizeof(struct d40_desc *) *
-                                           D40_LCLA_LINK_PER_EVENT_GRP,
+       base->reg_val_backup_chan = kmalloc(base->num_phy_chans *
+                                           sizeof(d40_backup_regs_chan),
                                            GFP_KERNEL);
+       if (!base->reg_val_backup_chan)
+               goto failure;
+
+       base->lcla_pool.alloc_map =
+               kzalloc(num_phy_chans * sizeof(struct d40_desc *)
+                       * D40_LCLA_LINK_PER_EVENT_GRP, GFP_KERNEL);
        if (!base->lcla_pool.alloc_map)
                goto failure;
 
@@ -2741,9 +3025,9 @@ failure:
 static void __init d40_hw_init(struct d40_base *base)
 {
 
-       static const struct d40_reg_val dma_init_reg[] = {
+       static struct d40_reg_val dma_init_reg[] = {
                /* Clock every part of the DMA block from start */
-               { .reg = D40_DREG_GCC,    .val = 0x0000ff01},
+               { .reg = D40_DREG_GCC,    .val = D40_DREG_GCC_ENABLE_ALL},
 
                /* Interrupts on all logical channels */
                { .reg = D40_DREG_LCMIS0, .val = 0xFFFFFFFF},
@@ -2943,11 +3227,31 @@ static int __init d40_probe(struct platform_device *pdev)
                d40_err(&pdev->dev, "Failed to ioremap LCPA region\n");
                goto failure;
        }
+       /* If lcla has to be located in ESRAM we don't need to allocate */
+       if (base->plat_data->use_esram_lcla) {
+               res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                                       "lcla_esram");
+               if (!res) {
+                       ret = -ENOENT;
+                       d40_err(&pdev->dev,
+                               "No \"lcla_esram\" memory resource\n");
+                       goto failure;
+               }
+               base->lcla_pool.base = ioremap(res->start,
+                                               resource_size(res));
+               if (!base->lcla_pool.base) {
+                       ret = -ENOMEM;
+                       d40_err(&pdev->dev, "Failed to ioremap LCLA region\n");
+                       goto failure;
+               }
+               writel(res->start, base->virtbase + D40_DREG_LCLA);
 
-       ret = d40_lcla_allocate(base);
-       if (ret) {
-               d40_err(&pdev->dev, "Failed to allocate LCLA area\n");
-               goto failure;
+       } else {
+               ret = d40_lcla_allocate(base);
+               if (ret) {
+                       d40_err(&pdev->dev, "Failed to allocate LCLA area\n");
+                       goto failure;
+               }
        }
 
        spin_lock_init(&base->lcla_pool.lock);
@@ -2960,6 +3264,32 @@ static int __init d40_probe(struct platform_device *pdev)
                goto failure;
        }
 
+       pm_runtime_irq_safe(base->dev);
+       pm_runtime_set_autosuspend_delay(base->dev, DMA40_AUTOSUSPEND_DELAY);
+       pm_runtime_use_autosuspend(base->dev);
+       pm_runtime_enable(base->dev);
+       pm_runtime_resume(base->dev);
+
+       if (base->plat_data->use_esram_lcla) {
+
+               base->lcpa_regulator = regulator_get(base->dev, "lcla_esram");
+               if (IS_ERR(base->lcpa_regulator)) {
+                       d40_err(&pdev->dev, "Failed to get lcpa_regulator\n");
+                       base->lcpa_regulator = NULL;
+                       goto failure;
+               }
+
+               ret = regulator_enable(base->lcpa_regulator);
+               if (ret) {
+                       d40_err(&pdev->dev,
+                               "Failed to enable lcpa_regulator\n");
+                       regulator_put(base->lcpa_regulator);
+                       base->lcpa_regulator = NULL;
+                       goto failure;
+               }
+       }
+
+       base->initialized = true;
        err = d40_dmaengine_init(base, num_reserved_chans);
        if (err)
                goto failure;
@@ -2976,6 +3306,11 @@ failure:
                if (base->virtbase)
                        iounmap(base->virtbase);
 
+               if (base->lcla_pool.base && base->plat_data->use_esram_lcla) {
+                       iounmap(base->lcla_pool.base);
+                       base->lcla_pool.base = NULL;
+               }
+
                if (base->lcla_pool.dma_addr)
                        dma_unmap_single(base->dev, base->lcla_pool.dma_addr,
                                         SZ_1K * base->num_phy_chans,
@@ -2998,6 +3333,11 @@ failure:
                        clk_put(base->clk);
                }
 
+               if (base->lcpa_regulator) {
+                       regulator_disable(base->lcpa_regulator);
+                       regulator_put(base->lcpa_regulator);
+               }
+
                kfree(base->lcla_pool.alloc_map);
                kfree(base->lookup_log_chans);
                kfree(base->lookup_phy_chans);
@@ -3013,6 +3353,7 @@ static struct platform_driver d40_driver = {
        .driver = {
                .owner = THIS_MODULE,
                .name  = D40_NAME,
+               .pm = DMA40_PM_OPS,
        },
 };
 
index b44c455158de3461f31ee5a0b0594cb136b2ad6a..8d3d490968a3a8240b6f91e1631609a2425c3f4f 100644 (file)
@@ -16,6 +16,8 @@
 
 #define D40_TYPE_TO_GROUP(type) (type / 16)
 #define D40_TYPE_TO_EVENT(type) (type % 16)
+#define D40_GROUP_SIZE 8
+#define D40_PHYS_TO_GROUP(phys) ((phys & (D40_GROUP_SIZE - 1)) / 2)
 
 /* Most bits of the CFG register are the same in log as in phy mode */
 #define D40_SREG_CFG_MST_POS           15
 
 /* DMA Register Offsets */
 #define D40_DREG_GCC           0x000
+#define D40_DREG_GCC_ENA       0x1
+/* This assumes that there are only 4 event groups */
+#define D40_DREG_GCC_ENABLE_ALL        0xff01
+#define D40_DREG_GCC_EVTGRP_POS 8
+#define D40_DREG_GCC_SRC 0
+#define D40_DREG_GCC_DST 1
+#define D40_DREG_GCC_EVTGRP_ENA(x, y) \
+       (1 << (D40_DREG_GCC_EVTGRP_POS + 2 * x + y))
+
 #define D40_DREG_PRTYP         0x004
 #define D40_DREG_PRSME         0x008
 #define D40_DREG_PRSMO         0x00C
index a4a398f2ef61eb5a362ca20c37ebe9a479e2121a..a6f9c1684a0fc1dc4a9c7a2dbd2407fe6252b68d 100644 (file)
@@ -90,7 +90,7 @@ struct timb_dma_chan {
        struct list_head        queue;
        struct list_head        free_list;
        unsigned int            bytes_per_line;
-       enum dma_data_direction direction;
+       enum dma_transfer_direction     direction;
        unsigned int            descs; /* Descriptors to allocate */
        unsigned int            desc_elems; /* number of elems per descriptor */
 };
@@ -166,10 +166,10 @@ static void __td_unmap_desc(struct timb_dma_chan *td_chan, const u8 *dma_desc,
 
        if (single)
                dma_unmap_single(chan2dev(&td_chan->chan), addr, len,
-                       td_chan->direction);
+                       DMA_TO_DEVICE);
        else
                dma_unmap_page(chan2dev(&td_chan->chan), addr, len,
-                       td_chan->direction);
+                       DMA_TO_DEVICE);
 }
 
 static void __td_unmap_descs(struct timb_dma_desc *td_desc, bool single)
@@ -235,7 +235,7 @@ static void __td_start_dma(struct timb_dma_chan *td_chan)
                "td_chan: %p, chan: %d, membase: %p\n",
                td_chan, td_chan->chan.chan_id, td_chan->membase);
 
-       if (td_chan->direction == DMA_FROM_DEVICE) {
+       if (td_chan->direction == DMA_DEV_TO_MEM) {
 
                /* descriptor address */
                iowrite32(0, td_chan->membase + TIMBDMA_OFFS_RX_DHAR);
@@ -278,7 +278,7 @@ static void __td_finish(struct timb_dma_chan *td_chan)
                txd->cookie);
 
        /* make sure to stop the transfer */
-       if (td_chan->direction == DMA_FROM_DEVICE)
+       if (td_chan->direction == DMA_DEV_TO_MEM)
                iowrite32(0, td_chan->membase + TIMBDMA_OFFS_RX_ER);
 /* Currently no support for stopping DMA transfers
        else
@@ -558,7 +558,7 @@ static void td_issue_pending(struct dma_chan *chan)
 
 static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan,
        struct scatterlist *sgl, unsigned int sg_len,
-       enum dma_data_direction direction, unsigned long flags)
+       enum dma_transfer_direction direction, unsigned long flags)
 {
        struct timb_dma_chan *td_chan =
                container_of(chan, struct timb_dma_chan, chan);
@@ -606,7 +606,7 @@ static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan,
        }
 
        dma_sync_single_for_device(chan2dmadev(chan), td_desc->txd.phys,
-               td_desc->desc_list_len, DMA_TO_DEVICE);
+               td_desc->desc_list_len, DMA_MEM_TO_DEV);
 
        return &td_desc->txd;
 }
@@ -775,8 +775,8 @@ static int __devinit td_probe(struct platform_device *pdev)
                td_chan->descs = pchan->descriptors;
                td_chan->desc_elems = pchan->descriptor_elements;
                td_chan->bytes_per_line = pchan->bytes_per_line;
-               td_chan->direction = pchan->rx ? DMA_FROM_DEVICE :
-                       DMA_TO_DEVICE;
+               td_chan->direction = pchan->rx ? DMA_DEV_TO_MEM :
+                       DMA_MEM_TO_DEV;
 
                td_chan->membase = td->membase +
                        (i / 2) * TIMBDMA_INSTANCE_OFFSET +
@@ -841,17 +841,7 @@ static struct platform_driver td_driver = {
        .remove = __exit_p(td_remove),
 };
 
-static int __init td_init(void)
-{
-       return platform_driver_register(&td_driver);
-}
-module_init(td_init);
-
-static void __exit td_exit(void)
-{
-       platform_driver_unregister(&td_driver);
-}
-module_exit(td_exit);
+module_platform_driver(td_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Timberdale DMA controller driver");
index cbd83e362b5e0a78bcb25dec65f4fb29663710d9..6122c364cf11bb0050fb2b029c083b3c40233722 100644 (file)
@@ -845,7 +845,7 @@ txx9dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 
 static struct dma_async_tx_descriptor *
 txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned int sg_len, enum dma_transfer_direction direction,
                unsigned long flags)
 {
        struct txx9dmac_chan *dc = to_txx9dmac_chan(chan);
@@ -860,9 +860,9 @@ txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 
        BUG_ON(!ds || !ds->reg_width);
        if (ds->tx_reg)
-               BUG_ON(direction != DMA_TO_DEVICE);
+               BUG_ON(direction != DMA_MEM_TO_DEV);
        else
-               BUG_ON(direction != DMA_FROM_DEVICE);
+               BUG_ON(direction != DMA_DEV_TO_MEM);
        if (unlikely(!sg_len))
                return NULL;
 
@@ -882,7 +882,7 @@ txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                mem = sg_dma_address(sg);
 
                if (__is_dmac64(ddev)) {
-                       if (direction == DMA_TO_DEVICE) {
+                       if (direction == DMA_MEM_TO_DEV) {
                                desc->hwdesc.SAR = mem;
                                desc->hwdesc.DAR = ds->tx_reg;
                        } else {
@@ -891,7 +891,7 @@ txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                        }
                        desc->hwdesc.CNTR = sg_dma_len(sg);
                } else {
-                       if (direction == DMA_TO_DEVICE) {
+                       if (direction == DMA_MEM_TO_DEV) {
                                desc->hwdesc32.SAR = mem;
                                desc->hwdesc32.DAR = ds->tx_reg;
                        } else {
@@ -900,7 +900,7 @@ txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                        }
                        desc->hwdesc32.CNTR = sg_dma_len(sg);
                }
-               if (direction == DMA_TO_DEVICE) {
+               if (direction == DMA_MEM_TO_DEV) {
                        sai = ds->reg_width;
                        dai = 0;
                } else {
index b153674431f19c7f4674a03c000da279a62ee878..e294e1b3616cf7c54343e6260a931676422f6206 100644 (file)
@@ -131,7 +131,7 @@ struct r82600_error_info {
        u32 eapr;
 };
 
-static unsigned int disable_hardware_scrub;
+static bool disable_hardware_scrub;
 
 static struct edac_pci_ctl_info *r82600_pci;
 
index 68375bc3aef66cdf6c08662a7502aef42ef08f81..80e95aa3bf14ea96ade61193783f490d35f08329 100644 (file)
@@ -66,7 +66,7 @@
  *
  * Concurrent logins are useful together with cluster filesystems.
  */
-static int sbp2_param_exclusive_login = 1;
+static bool sbp2_param_exclusive_login = 1;
 module_param_named(exclusive_login, sbp2_param_exclusive_login, bool, 0644);
 MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
                 "(default = Y, use N for concurrent initiators)");
index 573532f7553e737c1c7cee6cc3443d67cb4f8139..d0c41188d4e536b4983857de9c834913f1355c13 100644 (file)
@@ -87,6 +87,7 @@ config GPIO_GENERIC_PLATFORM
 
 config GPIO_IT8761E
        tristate "IT8761E GPIO support"
+       depends on X86  # unconditional access to IO space.
        help
          Say yes here to support GPIO functionality of IT8761E super I/O chip.
 
@@ -138,6 +139,7 @@ config GPIO_MXS
 config GPIO_PL061
        bool "PrimeCell PL061 GPIO support"
        depends on ARM_AMBA
+       select GENERIC_IRQ_CHIP
        help
          Say yes here to support the PrimeCell PL061 GPIO device
 
index 62e641e79e8f059194c0bb5315e7d46e1fd105e2..fa10df604c017badef9d8052f69e78bf84f5a24c 100644 (file)
@@ -2,7 +2,7 @@
 
 ccflags-$(CONFIG_DEBUG_GPIO)   += -DDEBUG
 
-obj-$(CONFIG_GPIOLIB)          += gpiolib.o
+obj-$(CONFIG_GPIOLIB)          += gpiolib.o devres.o
 
 # Device drivers. Generally keep list sorted alphabetically
 obj-$(CONFIG_GPIO_GENERIC)     += gpio-generic.o
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
new file mode 100644 (file)
index 0000000..3dd2939
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * drivers/gpio/devres.c - managed gpio resources
+ *
+ * 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.
+ *
+ * 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
+ *
+ * This file is based on kernel/irq/devres.c
+ *
+ * Copyright (c) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/device.h>
+#include <linux/gfp.h>
+
+static void devm_gpio_release(struct device *dev, void *res)
+{
+       unsigned *gpio = res;
+
+       gpio_free(*gpio);
+}
+
+static int devm_gpio_match(struct device *dev, void *res, void *data)
+{
+       unsigned *this = res, *gpio = data;
+
+       return *this == *gpio;
+}
+
+/**
+ *      devm_gpio_request - request a gpio for a managed device
+ *      @dev: device to request the gpio for
+ *      @gpio: gpio to allocate
+ *      @label: the name of the requested gpio
+ *
+ *      Except for the extra @dev argument, this function takes the
+ *      same arguments and performs the same function as
+ *      gpio_request().  GPIOs requested with this function will be
+ *      automatically freed on driver detach.
+ *
+ *      If an GPIO allocated with this function needs to be freed
+ *      separately, devm_gpio_free() must be used.
+ */
+
+int devm_gpio_request(struct device *dev, unsigned gpio, const char *label)
+{
+       unsigned *dr;
+       int rc;
+
+       dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       rc = gpio_request(gpio, label);
+       if (rc) {
+               devres_free(dr);
+               return rc;
+       }
+
+       *dr = gpio;
+       devres_add(dev, dr);
+
+       return 0;
+}
+EXPORT_SYMBOL(devm_gpio_request);
+
+/**
+ *      devm_gpio_free - free an interrupt
+ *      @dev: device to free gpio for
+ *      @gpio: gpio to free
+ *
+ *      Except for the extra @dev argument, this function takes the
+ *      same arguments and performs the same function as gpio_free().
+ *      This function instead of gpio_free() should be used to manually
+ *      free GPIOs allocated with devm_gpio_request().
+ */
+void devm_gpio_free(struct device *dev, unsigned int gpio)
+{
+
+       WARN_ON(devres_destroy(dev, devm_gpio_release, devm_gpio_match,
+               &gpio));
+       gpio_free(gpio);
+}
+EXPORT_SYMBOL(devm_gpio_free);
index 461958fc2264e91321a5bb80f7ba9cbed0a1a5bc..03d6dd5dcb77c0092c5297acb34bd4da59a5f81a 100644 (file)
@@ -248,7 +248,7 @@ static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port)
 static int ioh_irq_type(struct irq_data *d, unsigned int type)
 {
        u32 im;
-       u32 *im_reg;
+       void __iomem *im_reg;
        u32 ien;
        u32 im_pos;
        int ch;
@@ -412,7 +412,7 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
        int i, j;
        struct ioh_gpio *chip;
        void __iomem *base;
-       void __iomem *chip_save;
+       void *chip_save;
        int irq_base;
 
        ret = pci_enable_device(pdev);
@@ -428,7 +428,7 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
        }
 
        base = pci_iomap(pdev, 1, 0);
-       if (base == 0) {
+       if (!base) {
                dev_err(&pdev->dev, "%s : pci_iomap failed", __func__);
                ret = -ENOMEM;
                goto err_iomap;
@@ -521,7 +521,7 @@ static void __devexit ioh_gpio_remove(struct pci_dev *pdev)
        int err;
        int i;
        struct ioh_gpio *chip = pci_get_drvdata(pdev);
-       void __iomem *chip_save;
+       void *chip_save;
 
        chip_save = chip;
 
index f0603297f829e787129f4bf0c34beb980a17f368..68fa55e86eb1fe736332da26c66b8d564c394893 100644 (file)
@@ -231,7 +231,7 @@ static void pch_gpio_setup(struct pch_gpio *chip)
 static int pch_irq_type(struct irq_data *d, unsigned int type)
 {
        u32 im;
-       u32 *im_reg;
+       u32 __iomem *im_reg;
        u32 ien;
        u32 im_pos;
        int ch;
@@ -376,7 +376,7 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev,
        }
 
        chip->base = pci_iomap(pdev, 1, 0);
-       if (chip->base == 0) {
+       if (!chip->base) {
                dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__);
                ret = -ENOMEM;
                goto err_iomap;
index 8f79c03049f38f63a842801991c019ffa77f3b2b..77c9cc70fa7753fb406b87dbbf201021b4b6eb18 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/module.h>
-#include <linux/list.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/irq.h>
@@ -23,6 +22,8 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/pl061.h>
 #include <linux/slab.h>
+#include <linux/pm.h>
+#include <asm/mach/irq.h>
 
 #define GPIODIR 0x400
 #define GPIOIS  0x404
 
 #define PL061_GPIO_NR  8
 
-struct pl061_gpio {
-       /* We use a list of pl061_gpio structs for each trigger IRQ in the main
-        * interrupts controller of the system. We need this to support systems
-        * in which more that one PL061s are connected to the same IRQ. The ISR
-        * interates through this list to find the source of the interrupt.
-        */
-       struct list_head        list;
+#ifdef CONFIG_PM
+struct pl061_context_save_regs {
+       u8 gpio_data;
+       u8 gpio_dir;
+       u8 gpio_is;
+       u8 gpio_ibe;
+       u8 gpio_iev;
+       u8 gpio_ie;
+};
+#endif
 
+struct pl061_gpio {
        /* Each of the two spinlocks protects a different set of hardware
         * regiters and data structurs. This decouples the code of the IRQ from
         * the GPIO code. This also makes the case of a GPIO routine call from
         * the IRQ code simpler.
         */
        spinlock_t              lock;           /* GPIO registers */
-       spinlock_t              irq_lock;       /* IRQ registers */
 
        void __iomem            *base;
-       unsigned                irq_base;
+       int                     irq_base;
+       struct irq_chip_generic *irq_gc;
        struct gpio_chip        gc;
+
+#ifdef CONFIG_PM
+       struct pl061_context_save_regs csave_regs;
+#endif
 };
 
 static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
@@ -118,46 +127,16 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
 {
        struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
 
-       if (chip->irq_base == NO_IRQ)
+       if (chip->irq_base <= 0)
                return -EINVAL;
 
        return chip->irq_base + offset;
 }
 
-/*
- * PL061 GPIO IRQ
- */
-static void pl061_irq_disable(struct irq_data *d)
-{
-       struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
-       int offset = d->irq - chip->irq_base;
-       unsigned long flags;
-       u8 gpioie;
-
-       spin_lock_irqsave(&chip->irq_lock, flags);
-       gpioie = readb(chip->base + GPIOIE);
-       gpioie &= ~(1 << offset);
-       writeb(gpioie, chip->base + GPIOIE);
-       spin_unlock_irqrestore(&chip->irq_lock, flags);
-}
-
-static void pl061_irq_enable(struct irq_data *d)
-{
-       struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
-       int offset = d->irq - chip->irq_base;
-       unsigned long flags;
-       u8 gpioie;
-
-       spin_lock_irqsave(&chip->irq_lock, flags);
-       gpioie = readb(chip->base + GPIOIE);
-       gpioie |= 1 << offset;
-       writeb(gpioie, chip->base + GPIOIE);
-       spin_unlock_irqrestore(&chip->irq_lock, flags);
-}
-
 static int pl061_irq_type(struct irq_data *d, unsigned trigger)
 {
-       struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct pl061_gpio *chip = gc->private;
        int offset = d->irq - chip->irq_base;
        unsigned long flags;
        u8 gpiois, gpioibe, gpioiev;
@@ -165,7 +144,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
        if (offset < 0 || offset >= PL061_GPIO_NR)
                return -EINVAL;
 
-       spin_lock_irqsave(&chip->irq_lock, flags);
+       raw_spin_lock_irqsave(&gc->lock, flags);
 
        gpioiev = readb(chip->base + GPIOIEV);
 
@@ -194,49 +173,54 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
 
        writeb(gpioiev, chip->base + GPIOIEV);
 
-       spin_unlock_irqrestore(&chip->irq_lock, flags);
+       raw_spin_unlock_irqrestore(&gc->lock, flags);
 
        return 0;
 }
 
-static struct irq_chip pl061_irqchip = {
-       .name           = "GPIO",
-       .irq_enable     = pl061_irq_enable,
-       .irq_disable    = pl061_irq_disable,
-       .irq_set_type   = pl061_irq_type,
-};
-
 static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
 {
-       struct list_head *chip_list = irq_get_handler_data(irq);
-       struct list_head *ptr;
-       struct pl061_gpio *chip;
-
-       desc->irq_data.chip->irq_ack(&desc->irq_data);
-       list_for_each(ptr, chip_list) {
-               unsigned long pending;
-               int offset;
+       unsigned long pending;
+       int offset;
+       struct pl061_gpio *chip = irq_desc_get_handler_data(desc);
+       struct irq_chip *irqchip = irq_desc_get_chip(desc);
 
-               chip = list_entry(ptr, struct pl061_gpio, list);
-               pending = readb(chip->base + GPIOMIS);
-               writeb(pending, chip->base + GPIOIC);
-
-               if (pending == 0)
-                       continue;
+       chained_irq_enter(irqchip, desc);
 
+       pending = readb(chip->base + GPIOMIS);
+       writeb(pending, chip->base + GPIOIC);
+       if (pending) {
                for_each_set_bit(offset, &pending, PL061_GPIO_NR)
                        generic_handle_irq(pl061_to_irq(&chip->gc, offset));
        }
-       desc->irq_data.chip->irq_unmask(&desc->irq_data);
+
+       chained_irq_exit(irqchip, desc);
+}
+
+static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base)
+{
+       struct irq_chip_type *ct;
+
+       chip->irq_gc = irq_alloc_generic_chip("gpio-pl061", 1, irq_base,
+                                             chip->base, handle_simple_irq);
+       chip->irq_gc->private = chip;
+
+       ct = chip->irq_gc->chip_types;
+       ct->chip.irq_mask = irq_gc_mask_clr_bit;
+       ct->chip.irq_unmask = irq_gc_mask_set_bit;
+       ct->chip.irq_set_type = pl061_irq_type;
+       ct->chip.irq_set_wake = irq_gc_set_wake;
+       ct->regs.mask = GPIOIE;
+
+       irq_setup_generic_chip(chip->irq_gc, IRQ_MSK(PL061_GPIO_NR),
+                              IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
 }
 
 static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
 {
        struct pl061_platform_data *pdata;
        struct pl061_gpio *chip;
-       struct list_head *chip_list;
        int ret, irq, i;
-       static DECLARE_BITMAP(init_irq, NR_IRQS);
 
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        if (chip == NULL)
@@ -248,7 +232,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
                chip->irq_base = pdata->irq_base;
        } else if (dev->dev.of_node) {
                chip->gc.base = -1;
-               chip->irq_base = NO_IRQ;
+               chip->irq_base = 0;
        } else {
                ret = -ENODEV;
                goto free_mem;
@@ -267,8 +251,6 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
        }
 
        spin_lock_init(&chip->lock);
-       spin_lock_init(&chip->irq_lock);
-       INIT_LIST_HEAD(&chip->list);
 
        chip->gc.direction_input = pl061_direction_input;
        chip->gc.direction_output = pl061_direction_output;
@@ -288,9 +270,11 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
         * irq_chip support
         */
 
-       if (chip->irq_base == NO_IRQ)
+       if (chip->irq_base <= 0)
                return 0;
 
+       pl061_init_gc(chip, chip->irq_base);
+
        writeb(0, chip->base + GPIOIE); /* disable irqs */
        irq = dev->irq[0];
        if (irq < 0) {
@@ -298,18 +282,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
                goto iounmap;
        }
        irq_set_chained_handler(irq, pl061_irq_handler);
-       if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */
-               chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL);
-               if (chip_list == NULL) {
-                       clear_bit(irq, init_irq);
-                       ret = -ENOMEM;
-                       goto iounmap;
-               }
-               INIT_LIST_HEAD(chip_list);
-               irq_set_handler_data(irq, chip_list);
-       } else
-               chip_list = irq_get_handler_data(irq);
-       list_add(&chip->list, chip_list);
+       irq_set_handler_data(irq, chip);
 
        for (i = 0; i < PL061_GPIO_NR; i++) {
                if (pdata) {
@@ -319,13 +292,10 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
                        else
                                pl061_direction_input(&chip->gc, i);
                }
-
-               irq_set_chip_and_handler(i + chip->irq_base, &pl061_irqchip,
-                                        handle_simple_irq);
-               set_irq_flags(i+chip->irq_base, IRQF_VALID);
-               irq_set_chip_data(i + chip->irq_base, chip);
        }
 
+       amba_set_drvdata(dev, chip);
+
        return 0;
 
 iounmap:
@@ -338,6 +308,53 @@ free_mem:
        return ret;
 }
 
+#ifdef CONFIG_PM
+static int pl061_suspend(struct device *dev)
+{
+       struct pl061_gpio *chip = dev_get_drvdata(dev);
+       int offset;
+
+       chip->csave_regs.gpio_data = 0;
+       chip->csave_regs.gpio_dir = readb(chip->base + GPIODIR);
+       chip->csave_regs.gpio_is = readb(chip->base + GPIOIS);
+       chip->csave_regs.gpio_ibe = readb(chip->base + GPIOIBE);
+       chip->csave_regs.gpio_iev = readb(chip->base + GPIOIEV);
+       chip->csave_regs.gpio_ie = readb(chip->base + GPIOIE);
+
+       for (offset = 0; offset < PL061_GPIO_NR; offset++) {
+               if (chip->csave_regs.gpio_dir & (1 << offset))
+                       chip->csave_regs.gpio_data |=
+                               pl061_get_value(&chip->gc, offset) << offset;
+       }
+
+       return 0;
+}
+
+static int pl061_resume(struct device *dev)
+{
+       struct pl061_gpio *chip = dev_get_drvdata(dev);
+       int offset;
+
+       for (offset = 0; offset < PL061_GPIO_NR; offset++) {
+               if (chip->csave_regs.gpio_dir & (1 << offset))
+                       pl061_direction_output(&chip->gc, offset,
+                                       chip->csave_regs.gpio_data &
+                                       (1 << offset));
+               else
+                       pl061_direction_input(&chip->gc, offset);
+       }
+
+       writeb(chip->csave_regs.gpio_is, chip->base + GPIOIS);
+       writeb(chip->csave_regs.gpio_ibe, chip->base + GPIOIBE);
+       writeb(chip->csave_regs.gpio_iev, chip->base + GPIOIEV);
+       writeb(chip->csave_regs.gpio_ie, chip->base + GPIOIE);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume);
+#endif
+
 static struct amba_id pl061_ids[] = {
        {
                .id     = 0x00041061,
@@ -351,6 +368,9 @@ MODULE_DEVICE_TABLE(amba, pl061_ids);
 static struct amba_driver pl061_gpio_driver = {
        .drv = {
                .name   = "pl061_gpio",
+#ifdef CONFIG_PM
+               .pm     = &pl061_dev_pm_ops,
+#endif
        },
        .id_table       = pl061_ids,
        .probe          = pl061_probe,
index b6c1f6d80649a93145daef13d6fcfd042fe20e47..7eecf69362ee9d2b96d02fabc0a04ce1bdc8c3c6 100644 (file)
@@ -47,12 +47,18 @@ static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int
        return 0;
 }
 
+static int sa1100_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       return offset < 11 ? (IRQ_GPIO0 + offset) : (IRQ_GPIO11 - 11 + offset);
+}
+
 static struct gpio_chip sa1100_gpio_chip = {
        .label                  = "gpio",
        .direction_input        = sa1100_direction_input,
        .direction_output       = sa1100_direction_output,
        .set                    = sa1100_gpio_set,
        .get                    = sa1100_gpio_get,
+       .to_irq                 = sa1100_to_irq,
        .base                   = 0,
        .ngpio                  = GPIO_MAX + 1,
 };
index 4c980b573328eaeb4432504284ffe249fdb66a45..87a68a896abf7a0a010aa6395db5b0a53ba9ba41 100644 (file)
@@ -65,7 +65,14 @@ static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
        u8 reg = stmpe->regs[which] - (offset / 8);
        u8 mask = 1 << (offset % 8);
 
-       stmpe_reg_write(stmpe, reg, mask);
+       /*
+        * Some variants have single register for gpio set/clear functionality.
+        * For them we need to write 0 to clear and 1 to set.
+        */
+       if (stmpe->regs[STMPE_IDX_GPSR_LSB] == stmpe->regs[STMPE_IDX_GPCR_LSB])
+               stmpe_set_bits(stmpe, reg, mask, val ? mask : 0);
+       else
+               stmpe_reg_write(stmpe, reg, mask);
 }
 
 static int stmpe_gpio_direction_output(struct gpio_chip *chip,
@@ -132,6 +139,10 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
        if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
                return -EINVAL;
 
+       /* STMPE801 doesn't have RE and FE registers */
+       if (stmpe_gpio->stmpe->partnum == STMPE801)
+               return 0;
+
        if (type == IRQ_TYPE_EDGE_RISING)
                stmpe_gpio->regs[REG_RE][regoffset] |= mask;
        else
@@ -165,6 +176,11 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
        int i, j;
 
        for (i = 0; i < CACHE_NR_REGS; i++) {
+               /* STMPE801 doesn't have RE and FE registers */
+               if ((stmpe->partnum == STMPE801) &&
+                               (i != REG_IE))
+                       continue;
+
                for (j = 0; j < num_banks; j++) {
                        u8 old = stmpe_gpio->oldregs[i][j];
                        u8 new = stmpe_gpio->regs[i][j];
@@ -241,8 +257,11 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
                }
 
                stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
-               stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB] + i,
-                               status[i]);
+
+               /* Edge detect register is not present on 801 */
+               if (stmpe->partnum != STMPE801)
+                       stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB]
+                                       + i, status[i]);
        }
 
        return IRQ_HANDLED;
index 61044c889f7fec11ef8f0f6b81c78fafd15c87a3..bdc2937915906fa7a7589b02e258daccb7b024f7 100644 (file)
@@ -361,14 +361,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                                    resource_size(res),
-                                    dev_name(&pdev->dev))) {
-               dev_err(&pdev->dev, "Couldn't request MEM resource\n");
-               return -ENODEV;
-       }
-
-       regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       regs = devm_request_and_ioremap(&pdev->dev, res);
        if (!regs) {
                dev_err(&pdev->dev, "Couldn't ioremap regs\n");
                return -ENODEV;
index b9c1c297669e64a167a9257021a82d54e1f854c5..91f45b965d1e812d542e81d2c81ab6e60ae52843 100644 (file)
@@ -52,7 +52,7 @@ static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset,
        struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
 
        /* Set the initial value */
-       tps65910_gpio_set(gc, 0, value);
+       tps65910_gpio_set(gc, offset, value);
 
        return tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
                                                GPIO_CFG_MASK);
index 6d0f10b7569cd4842def5fc1d5ca68a713bf842c..c100f3e9c9207cbf38359a5df9fdf3d8a1bd0b3d 100644 (file)
@@ -66,6 +66,7 @@ static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode)
 static int cdv_intel_crt_mode_valid(struct drm_connector *connector,
                                struct drm_display_mode *mode)
 {
+       struct drm_psb_private *dev_priv = connector->dev->dev_private;
        int max_clock = 0;
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return MODE_NO_DBLESCAN;
@@ -82,6 +83,11 @@ static int cdv_intel_crt_mode_valid(struct drm_connector *connector,
        if (mode->hdisplay > 1680 || mode->vdisplay > 1050)
                return MODE_PANEL;
 
+       /* We assume worst case scenario of 32 bpp here, since we don't know */
+       if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
+           dev_priv->vram_stolen_size)
+               return MODE_MEM;
+
        return MODE_OK;
 }
 
index 50d7cfb51662eba470c87704d6b37041f67f5a3c..de25560e629d19031848b0ec09c32ca19d7c2fe3 100644 (file)
@@ -241,6 +241,7 @@ static int cdv_hdmi_get_modes(struct drm_connector *connector)
 static int cdv_hdmi_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
+       struct drm_psb_private *dev_priv = connector->dev->dev_private;
 
        if (mode->clock > 165000)
                return MODE_CLOCK_HIGH;
@@ -255,14 +256,11 @@ static int cdv_hdmi_mode_valid(struct drm_connector *connector,
        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
                return MODE_NO_INTERLACE;
 
-       /*
-        * FIXME: for now we limit the size to 1680x1050 on CDV, otherwise it
-        * will go beyond the stolen memory size allocated to the framebuffer
-        */
-       if (mode->hdisplay > 1680)
-               return MODE_PANEL;
-       if (mode->vdisplay > 1050)
-               return MODE_PANEL;
+       /* We assume worst case scenario of 32 bpp here, since we don't know */
+       if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
+           dev_priv->vram_stolen_size)
+               return MODE_MEM;
+
        return MODE_OK;
 }
 
index 36878a60080d8a59749dd838a2a4c762dd1046df..025d30970cc00e080b2140a5b2fe56540c57ee95 100644 (file)
@@ -506,6 +506,7 @@ int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc,
 static int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
                                struct drm_display_mode *mode)
 {
+       struct drm_psb_private *dev_priv = connector->dev->dev_private;
        if (mode->clock > 165000)
                return MODE_CLOCK_HIGH;
        if (mode->clock < 20000)
@@ -514,6 +515,11 @@ static int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return MODE_NO_DBLESCAN;
 
+       /* We assume worst case scenario of 32 bpp here, since we don't know */
+       if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
+           dev_priv->vram_stolen_size)
+               return MODE_MEM;
+
        return MODE_OK;
 }
 
index 4882b29119e09f0c5e753eb90289702b9976cf1d..88b42971c0fd07356155110581ea5c7e681a8408 100644 (file)
@@ -1141,6 +1141,7 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
 static int psb_intel_sdvo_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
+       struct drm_psb_private *dev_priv = connector->dev->dev_private;
        struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector);
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
@@ -1160,6 +1161,11 @@ static int psb_intel_sdvo_mode_valid(struct drm_connector *connector,
                        return MODE_PANEL;
        }
 
+       /* We assume worst case scenario of 32 bpp here, since we don't know */
+       if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
+           dev_priv->vram_stolen_size)
+               return MODE_MEM;
+
        return MODE_OK;
 }
 
index 525744d593c1e981cc1039c79391f6aa38813b1d..7814a760c16439e8d6a0c74da474b4a978ce9793 100644 (file)
 
 #include <linux/vga_switcheroo.h>
 
-#define NOUVEAU_DSM_SUPPORTED 0x00
-#define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00
-
-#define NOUVEAU_DSM_ACTIVE 0x01
-#define NOUVEAU_DSM_ACTIVE_QUERY 0x00
-
 #define NOUVEAU_DSM_LED 0x02
 #define NOUVEAU_DSM_LED_STATE 0x00
 #define NOUVEAU_DSM_LED_OFF 0x10
@@ -35,6 +29,9 @@
 #define NOUVEAU_DSM_POWER_SPEED 0x01
 #define NOUVEAU_DSM_POWER_STAMINA 0x02
 
+#define NOUVEAU_DSM_OPTIMUS_FN 0x1A
+#define NOUVEAU_DSM_OPTIMUS_ARGS 0x03000001
+
 static struct nouveau_dsm_priv {
        bool dsm_detected;
        bool optimus_detected;
@@ -61,7 +58,8 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
        struct acpi_object_list input;
        union acpi_object params[4];
        union acpi_object *obj;
-       int err;
+       int i, err;
+       char args_buff[4];
 
        input.count = 4;
        input.pointer = params;
@@ -73,7 +71,11 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
        params[2].type = ACPI_TYPE_INTEGER;
        params[2].integer.value = func;
        params[3].type = ACPI_TYPE_BUFFER;
-       params[3].buffer.length = 0;
+       params[3].buffer.length = 4;
+       /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */
+       for (i = 0; i < 4; i++)
+               args_buff[i] = (arg >> i * 8) & 0xFF;
+       params[3].buffer.pointer = args_buff;
 
        err = acpi_evaluate_object(handle, "_DSM", &input, &output);
        if (err) {
@@ -148,6 +150,23 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
        return 0;
 }
 
+/* Returns 1 if a DSM function is usable and 0 otherwise */
+static int nouveau_test_dsm(acpi_handle test_handle,
+       int (*dsm_func)(acpi_handle, int, int, uint32_t *),
+       int sfnc)
+{
+       u32 result = 0;
+
+       /* Function 0 returns a Buffer containing available functions. The args
+        * parameter is ignored for function 0, so just put 0 in it */
+       if (dsm_func(test_handle, 0, 0, &result))
+               return 0;
+
+       /* ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. If
+        * the n-th bit is enabled, function n is supported */
+       return result & 1 && result & (1 << sfnc);
+}
+
 static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
 {
        mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
@@ -168,6 +187,10 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero
 
 static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
 {
+       /* perhaps the _DSM functions are mutually exclusive, but prepare for
+        * the future */
+       if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected)
+               return 0;
        if (id == VGA_SWITCHEROO_IGD)
                return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA);
        else
@@ -180,6 +203,11 @@ static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
        if (id == VGA_SWITCHEROO_IGD)
                return 0;
 
+       /* Optimus laptops have the card already disabled in
+        * nouveau_switcheroo_set_state */
+       if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected)
+               return 0;
+
        return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
 }
 
@@ -212,8 +240,7 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
 {
        acpi_handle dhandle, nvidia_handle;
        acpi_status status;
-       int ret, retval = 0;
-       uint32_t result;
+       int retval = 0;
 
        dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
        if (!dhandle)
@@ -224,13 +251,11 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
                return false;
        }
 
-       ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED,
-                         NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
-       if (ret == 0)
+       if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER))
                retval |= NOUVEAU_DSM_HAS_MUX;
 
-       ret = nouveau_optimus_dsm(dhandle, 0, 0, &result);
-       if (ret == 0)
+       if (nouveau_test_dsm(dhandle, nouveau_optimus_dsm,
+               NOUVEAU_DSM_OPTIMUS_FN))
                retval |= NOUVEAU_DSM_HAS_OPT;
 
        if (retval)
@@ -269,15 +294,22 @@ static bool nouveau_dsm_detect(void)
        }
 
        if (vga_count == 2 && has_dsm && guid_valid) {
-               acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
+               acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
+                       &buffer);
                printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
-                      acpi_method_name);
+                       acpi_method_name);
                nouveau_dsm_priv.dsm_detected = true;
                ret = true;
        }
 
-       if (has_optimus == 1)
+       if (has_optimus == 1) {
+               acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
+                       &buffer);
+               printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n",
+                       acpi_method_name);
                nouveau_dsm_priv.optimus_detected = true;
+               ret = true;
+       }
 
        return ret;
 }
@@ -293,6 +325,17 @@ void nouveau_register_dsm_handler(void)
        vga_switcheroo_register_handler(&nouveau_dsm_handler);
 }
 
+/* Must be called for Optimus models before the card can be turned off */
+void nouveau_switcheroo_optimus_dsm(void)
+{
+       u32 result = 0;
+       if (!nouveau_dsm_priv.optimus_detected)
+               return;
+
+       nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FN,
+               NOUVEAU_DSM_OPTIMUS_ARGS, &result);
+}
+
 void nouveau_unregister_dsm_handler(void)
 {
        vga_switcheroo_unregister_handler();
index 38134a9c75780a16ab4f646aa978f4d85719ecea..b827098289311bf94012f66b91d1d17c2159f333 100644 (file)
@@ -1055,12 +1055,14 @@ extern int  nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
 #if defined(CONFIG_ACPI)
 void nouveau_register_dsm_handler(void);
 void nouveau_unregister_dsm_handler(void);
+void nouveau_switcheroo_optimus_dsm(void);
 int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
 bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
 int nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
 #else
 static inline void nouveau_register_dsm_handler(void) {}
 static inline void nouveau_unregister_dsm_handler(void) {}
+static inline void nouveau_switcheroo_optimus_dsm(void) {}
 static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; }
 static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; }
 static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return -EINVAL; }
index f5e98910d17faf6b80bcd64f49d9c8909896b6a7..f80c5e0762ff90b4c29ec186ee1c5c4017f2fc7d 100644 (file)
@@ -525,6 +525,7 @@ static void nouveau_switcheroo_set_state(struct pci_dev *pdev,
                printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");
                dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
                drm_kms_helper_poll_disable(dev);
+               nouveau_switcheroo_optimus_dsm();
                nouveau_pci_suspend(pdev, pmm);
                dev->switch_power_state = DRM_SWITCH_POWER_OFF;
        }
index f7442e62c03f676c42afc518eba2be44400c43da..8e8cd85e5c0045926fb6f185744532eb2d588464 100644 (file)
@@ -1793,10 +1793,12 @@ int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
                        ret = -EINVAL;
                        break;
                case PACKET_TYPE2:
+                       idx += 1;
                        break;
                case PACKET_TYPE3:
                        pkt.opcode = CP_PACKET3_GET_OPCODE(ib->ptr[idx]);
                        ret = evergreen_vm_packet3_check(rdev, ib->ptr, &pkt);
+                       idx += pkt.count + 2;
                        break;
                default:
                        dev_err(rdev->dev, "Unknown packet type %d !\n", pkt.type);
@@ -1805,7 +1807,6 @@ int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
                }
                if (ret)
                        break;
-               idx += pkt.count + 2;
        } while (idx < ib->length_dw);
 
        return ret;
index 3ec81c3d5108ce24163b00da4f42dbf4df83d7f6..bfd36ab643a68a5dea2b43d24283d08a0a2eb703 100644 (file)
@@ -2186,7 +2186,6 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
 void r100_bm_disable(struct radeon_device *rdev)
 {
        u32 tmp;
-       u16 tmp16;
 
        /* disable bus mastering */
        tmp = RREG32(R_000030_BUS_CNTL);
@@ -2197,8 +2196,7 @@ void r100_bm_disable(struct radeon_device *rdev)
        WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040);
        tmp = RREG32(RADEON_BUS_CNTL);
        mdelay(1);
-       pci_read_config_word(rdev->pdev, 0x4, &tmp16);
-       pci_write_config_word(rdev->pdev, 0x4, tmp16 & 0xFFFB);
+       pci_clear_master(rdev->pdev);
        mdelay(1);
 }
 
index 31da622eef63c20e7dc66e821eff0cc5f43ec62d..8032f1fedb114005ae3b0e38c5c4073409cb2f93 100644 (file)
@@ -145,7 +145,7 @@ module_param_named(vramlimit, radeon_vram_limit, int, 0600);
 MODULE_PARM_DESC(agpmode, "AGP Mode (-1 == PCI)");
 module_param_named(agpmode, radeon_agpmode, int, 0444);
 
-MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32,64, etc)\n");
+MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32, 64, etc)");
 module_param_named(gartsize, radeon_gart_size, int, 0600);
 
 MODULE_PARM_DESC(benchmark, "Run benchmark");
index 803e0d3c177385ad31c4861c2647b28f721562d8..ec46eb45e34cd8b7534deb5f75353496424756f7 100644 (file)
@@ -322,16 +322,6 @@ void rs600_hpd_fini(struct radeon_device *rdev)
        }
 }
 
-void rs600_bm_disable(struct radeon_device *rdev)
-{
-       u16 tmp;
-
-       /* disable bus mastering */
-       pci_read_config_word(rdev->pdev, 0x4, &tmp);
-       pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB);
-       mdelay(1);
-}
-
 int rs600_asic_reset(struct radeon_device *rdev)
 {
        struct rv515_mc_save save;
@@ -355,7 +345,8 @@ int rs600_asic_reset(struct radeon_device *rdev)
        WREG32(RADEON_CP_RB_CNTL, tmp);
        pci_save_state(rdev->pdev);
        /* disable bus mastering */
-       rs600_bm_disable(rdev);
+       pci_clear_master(rdev->pdev);
+       mdelay(1);
        /* reset GA+VAP */
        WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) |
                                        S_0000F0_SOFT_RESET_GA(1));
index 37ead6995c872b64e1f2b4cef484365688364b71..0c46d8cdc6eadee9f7c712905c3f24239a0f6e52 100644 (file)
@@ -952,10 +952,9 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev)
 
        type = ttm_to_type(ttm->page_flags, ttm->caching_state);
        pool = ttm_dma_find_pool(dev, type);
-       if (!pool) {
-               WARN_ON(!pool);
+       if (!pool)
                return;
-       }
+
        is_cached = (ttm_dma_find_pool(pool->dev,
                     ttm_to_type(ttm->page_flags, tt_cached)) == pool);
 
index f779009104eb93f79b29c94d8eef84561d1e468a..b71b77ab0dc759d1524b8302a7843583c2ff861b 100644 (file)
@@ -90,7 +90,7 @@ static const char longname[] = "Prodikeys PC-MIDI Keyboard";
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 module_param_array(index, int, NULL, 0444);
 module_param_array(id, charp, NULL, 0444);
index cb351d3583875a8ea1ebbb78ae681cb888e5dee3..02260406b9e440ac406ac3ae7fc3cded1f05bb4e 100644 (file)
@@ -474,8 +474,8 @@ config SENSORS_IT87
        select HWMON_VID
        help
          If you say yes here you get support for ITE IT8705F, IT8712F,
-         IT8716F, IT8718F, IT8720F, IT8721F, IT8726F and IT8758E sensor
-         chips, and the SiS960 clone.
+         IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F and IT8758E
+         sensor chips, and the SiS960 clone.
 
          This driver can also be built as a module.  If so, the module
          will be called it87.
@@ -515,11 +515,11 @@ config SENSORS_LINEAGE
          will be called lineage-pem.
 
 config SENSORS_LM63
-       tristate "National Semiconductor LM63 and LM64"
+       tristate "National Semiconductor LM63 and compatibles"
        depends on I2C
        help
          If you say yes here you get support for the National
-         Semiconductor LM63 and LM64 remote diode digital temperature
+         Semiconductor LM63, LM64, and LM96163 remote diode digital temperature
          sensors with integrated fan control.  Such chips are found
          on the Tyan S4882 (Thunder K8QS Pro) motherboard, among
          others.
index 65a35cf5b3c5c57b58803e78ae3eda0b0e99f266..3b728e8f169b9fe850b55e4a74e3965f1fe983b3 100644 (file)
@@ -145,7 +145,7 @@ static const u8 abituguru_pwm_max[5] = { 0, 255, 255, 75, 75 };
 
 
 /* Insmod parameters */
-static int force;
+static bool force;
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Set to one to force detection.");
 static int bank1_types[ABIT_UGURU_MAX_BANK1_SENSORS] = { -1, -1, -1, -1, -1,
index d30855a75786ec7609b624b7492631cda41ab540..34a14a77e008c95b010060791c7f7b417eca0ed4 100644 (file)
@@ -603,11 +603,11 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
 
 
 /* Insmod parameters */
-static int force;
+static bool force;
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Set to one to force detection.");
 /* Default verbose is 1, since this driver is still in the testing phase */
-static int verbose = 1;
+static bool verbose = 1;
 module_param(verbose, bool, 0644);
 MODULE_PARM_DESC(verbose, "Enable/disable verbose error reporting");
 
index 522860ab6ce8758e29c81654b210c416d804c959..554f046bcf20a4949fc108fab40e11206486856d 100644 (file)
@@ -58,7 +58,7 @@ ACPI_MODULE_NAME(ACPI_POWER_METER_NAME);
 #define POWER_ALARM_NAME       "power1_alarm"
 
 static int cap_in_hardware;
-static int force_cap_on;
+static bool force_cap_on;
 
 static int can_cap_in_hardware(void)
 {
index 1ad0a885c5a5795034759dfc93c9c13015d211d5..0158cc35cb2e180984f90cd49dfdf364764c0831 100644 (file)
@@ -103,7 +103,7 @@ static int adm1021_remove(struct i2c_client *client);
 static struct adm1021_data *adm1021_update_device(struct device *dev);
 
 /* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
-static int read_only;
+static bool read_only;
 
 
 static const struct i2c_device_id adm1021_id[] = {
index e6291dafa4caab89a36feb2cdc1a50abde70364c..97e2cfb0bc9365827bac1d40667954d18e4d0fc1 100644 (file)
@@ -155,7 +155,8 @@ adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value)
 #define TEMP_OFFSET_FROM_REG(val)      TEMP_FROM_REG((val) < 0 ? \
                                                      (val) | 0x70 : (val))
 
-#define FAN_FROM_REG(reg, div)         ((reg) ? (11250 * 60) / ((reg) * (div)) : 0)
+#define FAN_FROM_REG(reg, div)         ((reg) ? \
+                                        (11250 * 60) / ((reg) * (div)) : 0)
 
 static int FAN_TO_REG(int reg, int div)
 {
@@ -174,8 +175,8 @@ static int FAN_TO_REG(int reg, int div)
        (((reg) & 0x1F) | (((val) << 5) & 0xe0))
 
 #define AUTO_TEMP_MIN_TO_REG(val, reg) \
-       ((((val)/500) & 0xf8)|((reg) & 0x7))
-#define AUTO_TEMP_RANGE_FROM_REG(reg)  (5000 * (1<< ((reg)&0x7)))
+       ((((val) / 500) & 0xf8) | ((reg) & 0x7))
+#define AUTO_TEMP_RANGE_FROM_REG(reg)  (5000 * (1 << ((reg) & 0x7)))
 #define AUTO_TEMP_MIN_FROM_REG(reg)    (1000 * ((((reg) >> 3) & 0x1f) << 2))
 
 #define AUTO_TEMP_MIN_FROM_REG_DEG(reg)        ((((reg) >> 3) & 0x1f) << 2)
@@ -202,7 +203,7 @@ static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm)
 
 /* FAN auto control */
 #define GET_FAN_AUTO_BITFIELD(data, idx)       \
-       (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx%2]
+       (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx % 2]
 
 /* The tables below contains the possible values for the auto fan
  * control bitfields. the index in the table is the register value.
@@ -230,7 +231,7 @@ static const auto_chan_table_t auto_channel_select_table_adm1030 = {
  */
 static int
 get_fan_auto_nearest(struct adm1031_data *data,
-                    int chan, u8 val, u8 reg, u8 * new_reg)
+                    int chan, u8 val, u8 reg, u8 *new_reg)
 {
        int i;
        int first_match = -1, exact_match = -1;
@@ -258,13 +259,13 @@ get_fan_auto_nearest(struct adm1031_data *data,
                }
        }
 
-       if (exact_match >= 0) {
+       if (exact_match >= 0)
                *new_reg = exact_match;
-       } else if (first_match >= 0) {
+       else if (first_match >= 0)
                *new_reg = first_match;
-       } else {
+       else
                return -EINVAL;
-       }
+
        return 0;
 }
 
@@ -283,23 +284,28 @@ set_fan_auto_channel(struct device *dev, struct device_attribute *attr,
        struct i2c_client *client = to_i2c_client(dev);
        struct adm1031_data *data = i2c_get_clientdata(client);
        int nr = to_sensor_dev_attr(attr)->index;
-       int val = simple_strtol(buf, NULL, 10);
+       long val;
        u8 reg;
        int ret;
        u8 old_fan_mode;
 
+       ret = kstrtol(buf, 10, &val);
+       if (ret)
+               return ret;
+
        old_fan_mode = data->conf1;
 
        mutex_lock(&data->update_lock);
 
-       if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, &reg))) {
+       ret = get_fan_auto_nearest(data, nr, val, data->conf1, &reg);
+       if (ret) {
                mutex_unlock(&data->update_lock);
                return ret;
        }
        data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
        if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^
            (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) {
-               if (data->conf1 & ADM1031_CONF1_AUTO_MODE){
+               if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
                        /* Switch to Auto Fan Mode
                         * Save PWM registers
                         * Set PWM registers to 33% Both */
@@ -350,7 +356,12 @@ set_auto_temp_min(struct device *dev, struct device_attribute *attr,
        struct i2c_client *client = to_i2c_client(dev);
        struct adm1031_data *data = i2c_get_clientdata(client);
        int nr = to_sensor_dev_attr(attr)->index;
-       int val = simple_strtol(buf, NULL, 10);
+       long val;
+       int ret;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret)
+               return ret;
 
        mutex_lock(&data->update_lock);
        data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]);
@@ -374,10 +385,16 @@ set_auto_temp_max(struct device *dev, struct device_attribute *attr,
        struct i2c_client *client = to_i2c_client(dev);
        struct adm1031_data *data = i2c_get_clientdata(client);
        int nr = to_sensor_dev_attr(attr)->index;
-       int val = simple_strtol(buf, NULL, 10);
+       long val;
+       int ret;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret)
+               return ret;
 
        mutex_lock(&data->update_lock);
-       data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], data->pwm[nr]);
+       data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr],
+                                                 data->pwm[nr]);
        adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
                            data->temp_max[nr]);
        mutex_unlock(&data->update_lock);
@@ -410,8 +427,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
        struct i2c_client *client = to_i2c_client(dev);
        struct adm1031_data *data = i2c_get_clientdata(client);
        int nr = to_sensor_dev_attr(attr)->index;
-       int val = simple_strtol(buf, NULL, 10);
-       int reg;
+       long val;
+       int ret, reg;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret)
+               return ret;
 
        mutex_lock(&data->update_lock);
        if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) &&
@@ -449,9 +470,13 @@ static int trust_fan_readings(struct adm1031_data *data, int chan)
 
        if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
                switch (data->conf1 & 0x60) {
-               case 0x00:      /* remote temp1 controls fan1 remote temp2 controls fan2 */
+               case 0x00:
+                       /*
+                        * remote temp1 controls fan1,
+                        * remote temp2 controls fan2
+                        */
                        res = data->temp[chan+1] >=
-                             AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]);
+                           AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]);
                        break;
                case 0x20:      /* remote temp1 controls both fans */
                        res =
@@ -515,7 +540,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
        struct i2c_client *client = to_i2c_client(dev);
        struct adm1031_data *data = i2c_get_clientdata(client);
        int nr = to_sensor_dev_attr(attr)->index;
-       int val = simple_strtol(buf, NULL, 10);
+       long val;
+       int ret;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret)
+               return ret;
 
        mutex_lock(&data->update_lock);
        if (val) {
@@ -534,10 +564,15 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
        struct i2c_client *client = to_i2c_client(dev);
        struct adm1031_data *data = i2c_get_clientdata(client);
        int nr = to_sensor_dev_attr(attr)->index;
-       int val = simple_strtol(buf, NULL, 10);
+       long val;
        u8 tmp;
        int old_div;
        int new_min;
+       int ret;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret)
+               return ret;
 
        tmp = val == 8 ? 0xc0 :
              val == 4 ? 0x80 :
@@ -631,9 +666,13 @@ static ssize_t set_temp_offset(struct device *dev,
        struct i2c_client *client = to_i2c_client(dev);
        struct adm1031_data *data = i2c_get_clientdata(client);
        int nr = to_sensor_dev_attr(attr)->index;
-       int val;
+       long val;
+       int ret;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret)
+               return ret;
 
-       val = simple_strtol(buf, NULL, 10);
        val = SENSORS_LIMIT(val, -15000, 15000);
        mutex_lock(&data->update_lock);
        data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val);
@@ -648,9 +687,13 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
        struct i2c_client *client = to_i2c_client(dev);
        struct adm1031_data *data = i2c_get_clientdata(client);
        int nr = to_sensor_dev_attr(attr)->index;
-       int val;
+       long val;
+       int ret;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret)
+               return ret;
 
-       val = simple_strtol(buf, NULL, 10);
        val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
        mutex_lock(&data->update_lock);
        data->temp_min[nr] = TEMP_TO_REG(val);
@@ -665,9 +708,13 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
        struct i2c_client *client = to_i2c_client(dev);
        struct adm1031_data *data = i2c_get_clientdata(client);
        int nr = to_sensor_dev_attr(attr)->index;
-       int val;
+       long val;
+       int ret;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret)
+               return ret;
 
-       val = simple_strtol(buf, NULL, 10);
        val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
        mutex_lock(&data->update_lock);
        data->temp_max[nr] = TEMP_TO_REG(val);
@@ -682,9 +729,13 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
        struct i2c_client *client = to_i2c_client(dev);
        struct adm1031_data *data = i2c_get_clientdata(client);
        int nr = to_sensor_dev_attr(attr)->index;
-       int val;
+       long val;
+       int ret;
+
+       ret = kstrtol(buf, 10, &val);
+       if (ret)
+               return ret;
 
-       val = simple_strtol(buf, NULL, 10);
        val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
        mutex_lock(&data->update_lock);
        data->temp_crit[nr] = TEMP_TO_REG(val);
@@ -711,7 +762,8 @@ temp_reg(2);
 temp_reg(3);
 
 /* Alarms */
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+                          char *buf)
 {
        struct adm1031_data *data = adm1031_update_device(dev);
        return sprintf(buf, "%d\n", data->alarm);
@@ -919,12 +971,13 @@ static int adm1031_probe(struct i2c_client *client,
        adm1031_init_client(client);
 
        /* Register sysfs hooks */
-       if ((err = sysfs_create_group(&client->dev.kobj, &adm1031_group)))
+       err = sysfs_create_group(&client->dev.kobj, &adm1031_group);
+       if (err)
                goto exit_free;
 
        if (data->chip_type == adm1031) {
-               if ((err = sysfs_create_group(&client->dev.kobj,
-                                               &adm1031_group_opt)))
+               err = sysfs_create_group(&client->dev.kobj, &adm1031_group_opt);
+               if (err)
                        goto exit_remove;
        }
 
@@ -970,14 +1023,13 @@ static void adm1031_init_client(struct i2c_client *client)
        }
        /* Initialize the ADM1031 chip (enables fan speed reading ) */
        read_val = adm1031_read_value(client, ADM1031_REG_CONF2);
-       if ((read_val | mask) != read_val) {
-           adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask);
-       }
+       if ((read_val | mask) != read_val)
+               adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask);
 
        read_val = adm1031_read_value(client, ADM1031_REG_CONF1);
        if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) {
-           adm1031_write_value(client, ADM1031_REG_CONF1, read_val |
-                               ADM1031_CONF1_MONITOR_ENABLE);
+               adm1031_write_value(client, ADM1031_REG_CONF1,
+                                   read_val | ADM1031_CONF1_MONITOR_ENABLE);
        }
 
        /* Read the chip's update rate */
@@ -1024,8 +1076,7 @@ static struct adm1031_data *adm1031_update_device(struct device *dev)
                                /* oldh is actually newer */
                                if (newh != oldh)
                                        dev_warn(&client->dev,
-                                                "Remote temperature may be "
-                                                "wrong.\n");
+                                         "Remote temperature may be wrong.\n");
 #endif
                        }
                        data->temp[chan] = newh;
@@ -1052,22 +1103,24 @@ static struct adm1031_data *adm1031_update_device(struct device *dev)
                data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2);
 
                data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0))
-                            | (adm1031_read_value(client, ADM1031_REG_STATUS(1))
-                               << 8);
-               if (data->chip_type == adm1030) {
+                   | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) << 8);
+               if (data->chip_type == adm1030)
                        data->alarm &= 0xc0ff;
-               }
 
-               for (chan=0; chan<(data->chip_type == adm1030 ? 1 : 2); chan++) {
+               for (chan = 0; chan < (data->chip_type == adm1030 ? 1 : 2);
+                    chan++) {
                        data->fan_div[chan] =
-                           adm1031_read_value(client, ADM1031_REG_FAN_DIV(chan));
+                           adm1031_read_value(client,
+                                              ADM1031_REG_FAN_DIV(chan));
                        data->fan_min[chan] =
-                           adm1031_read_value(client, ADM1031_REG_FAN_MIN(chan));
+                           adm1031_read_value(client,
+                                              ADM1031_REG_FAN_MIN(chan));
                        data->fan[chan] =
-                           adm1031_read_value(client, ADM1031_REG_FAN_SPEED(chan));
+                           adm1031_read_value(client,
+                                              ADM1031_REG_FAN_SPEED(chan));
                        data->pwm[chan] =
-                           0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >>
-                                  (4*chan));
+                         (adm1031_read_value(client,
+                                       ADM1031_REG_PWM) >> (4 * chan)) & 0x0f;
                }
                data->last_updated = jiffies;
                data->valid = 1;
index cfcc3b6fb6bf9fcc4cdafbd7351206769ee61144..ed60242d6a0ad89a77af8f7cc675b92b114ce4dc 100644 (file)
@@ -48,8 +48,8 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
        I2C_CLIENT_END };
 
 /* Module parameters */
-static int se_input = 1; /* Default is SE, 0 == diff */
-static int int_vref = 1; /* Default is internal ref ON */
+static bool se_input = 1; /* Default is SE, 0 == diff */
+static bool int_vref = 1; /* Default is internal ref ON */
 static int vref_mv = ADS7828_INT_VREF_MV; /* set if vref != 2.5V */
 module_param(se_input, bool, S_IRUGO);
 module_param(int_vref, bool, S_IRUGO);
index 1fdef885341c4438842c92a381726e864dd3868c..a6c6ec36615e686b296fd4b199107eae08f2ba34 100644 (file)
@@ -190,7 +190,8 @@ static ssize_t show_temp(struct device *dev,
        return tdata->valid ? sprintf(buf, "%d\n", tdata->temp) : -EAGAIN;
 }
 
-static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
+static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
+                                 struct device *dev)
 {
        /* The 100C is default for both mobile and non mobile CPUs */
 
@@ -284,7 +285,8 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
        return tjmax;
 }
 
-static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
+static int __cpuinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
+                              struct device *dev)
 {
        int err;
        u32 eax, edx;
@@ -323,7 +325,8 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
        return adjust_tjmax(c, id, dev);
 }
 
-static int create_name_attr(struct platform_data *pdata, struct device *dev)
+static int __devinit create_name_attr(struct platform_data *pdata,
+                                     struct device *dev)
 {
        sysfs_attr_init(&pdata->name_attr.attr);
        pdata->name_attr.attr.name = "name";
@@ -332,8 +335,8 @@ static int create_name_attr(struct platform_data *pdata, struct device *dev)
        return device_create_file(dev, &pdata->name_attr);
 }
 
-static int create_core_attrs(struct temp_data *tdata, struct device *dev,
-                               int attr_no)
+static int __cpuinit create_core_attrs(struct temp_data *tdata,
+                                      struct device *dev, int attr_no)
 {
        int err, i;
        static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
@@ -383,7 +386,7 @@ static int __cpuinit chk_ucode_version(unsigned int cpu)
        return 0;
 }
 
-static struct platform_device *coretemp_get_pdev(unsigned int cpu)
+static struct platform_device __cpuinit *coretemp_get_pdev(unsigned int cpu)
 {
        u16 phys_proc_id = TO_PHYS_ID(cpu);
        struct pdev_entry *p;
@@ -400,7 +403,8 @@ static struct platform_device *coretemp_get_pdev(unsigned int cpu)
        return NULL;
 }
 
-static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
+static struct temp_data __cpuinit *init_temp_data(unsigned int cpu,
+                                                 int pkg_flag)
 {
        struct temp_data *tdata;
 
@@ -418,7 +422,7 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
        return tdata;
 }
 
-static int create_core_data(struct platform_device *pdev,
+static int __cpuinit create_core_data(struct platform_device *pdev,
                                unsigned int cpu, int pkg_flag)
 {
        struct temp_data *tdata;
@@ -489,7 +493,7 @@ exit_free:
        return err;
 }
 
-static void coretemp_add_core(unsigned int cpu, int pkg_flag)
+static void __cpuinit coretemp_add_core(unsigned int cpu, int pkg_flag)
 {
        struct platform_device *pdev = coretemp_get_pdev(cpu);
        int err;
@@ -618,7 +622,7 @@ exit:
        return err;
 }
 
-static void coretemp_device_remove(unsigned int cpu)
+static void __cpuinit coretemp_device_remove(unsigned int cpu)
 {
        struct pdev_entry *p, *n;
        u16 phys_proc_id = TO_PHYS_ID(cpu);
@@ -634,7 +638,7 @@ static void coretemp_device_remove(unsigned int cpu)
        mutex_unlock(&pdev_list_mutex);
 }
 
-static bool is_any_core_online(struct platform_data *pdata)
+static bool __cpuinit is_any_core_online(struct platform_data *pdata)
 {
        int i;
 
index d9803958e49f1d56afa134c9d174abf422c2984b..ffb229af7861369a7ade43be99d1fd0ce98767b5 100644 (file)
@@ -45,7 +45,7 @@
 static struct platform_device *pdev;
 
 /* Module load parameters */
-static int force_start;
+static bool force_start;
 module_param(force_start, bool, 0);
 MODULE_PARM_DESC(force_start, "Force the chip to start monitoring inputs");
 
@@ -53,7 +53,7 @@ static unsigned short force_id;
 module_param(force_id, ushort, 0);
 MODULE_PARM_DESC(force_id, "Override the detected device ID");
 
-static int probe_all_addr;
+static bool probe_all_addr;
 module_param(probe_all_addr, bool, 0);
 MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC "
                 "addresses");
index 848a2b0bc83f103fdbfcf9e3cc90b6ce32bc0966..865063914d7606f7638576989547a80cbeab431c 100644 (file)
@@ -55,7 +55,7 @@ static const u8 REG_TEMP_MAX[4] = { 0x34, 0x30, 0x31, 0x32 };
  * it.  Default is to leave the device in the state it's already in (-1).
  * This parameter allows APD mode to be optionally forced on or off */
 static int apd = -1;
-module_param(apd, bool, 0);
+module_param(apd, bint, 0);
 MODULE_PARM_DESC(init, "Set to zero to disable anti-parallel diode mode");
 
 struct temperature {
index 38c0b87676de222e9bb142b44168e14d029bddd8..0054d6f9cec95e4645608c7fec6fde4f646344ac 100644 (file)
@@ -17,6 +17,7 @@
  *            IT8720F  Super I/O chip w/LPC interface
  *            IT8721F  Super I/O chip w/LPC interface
  *            IT8726F  Super I/O chip w/LPC interface
+ *            IT8728F  Super I/O chip w/LPC interface
  *            IT8758E  Super I/O chip w/LPC interface
  *            Sis950   A clone of the IT8705F
  *
@@ -58,7 +59,7 @@
 
 #define DRVNAME "it87"
 
-enum chips { it87, it8712, it8716, it8718, it8720, it8721 };
+enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728 };
 
 static unsigned short force_id;
 module_param(force_id, ushort, 0);
@@ -135,6 +136,7 @@ static inline void superio_exit(void)
 #define IT8720F_DEVID 0x8720
 #define IT8721F_DEVID 0x8721
 #define IT8726F_DEVID 0x8726
+#define IT8728F_DEVID 0x8728
 #define IT87_ACT_REG  0x30
 #define IT87_BASE_REG 0x60
 
@@ -146,10 +148,10 @@ static inline void superio_exit(void)
 #define IT87_SIO_BEEP_PIN_REG  0xf6    /* Beep pin mapping */
 
 /* Update battery voltage after every reading if true */
-static int update_vbat;
+static bool update_vbat;
 
 /* Not all BIOSes properly configure the PWM registers */
-static int fix_pwm_polarity;
+static bool fix_pwm_polarity;
 
 /* Many IT87 constants specified below */
 
@@ -274,11 +276,31 @@ struct it87_data {
        s8 auto_temp[3][5];     /* [nr][0] is point1_temp_hyst */
 };
 
+static inline int has_12mv_adc(const struct it87_data *data)
+{
+       /*
+        * IT8721F and later have a 12 mV ADC, also with internal scaling
+        * on selected inputs.
+        */
+       return data->type == it8721
+           || data->type == it8728;
+}
+
+static inline int has_newer_autopwm(const struct it87_data *data)
+{
+       /*
+        * IT8721F and later have separate registers for the temperature
+        * mapping and the manual duty cycle.
+        */
+       return data->type == it8721
+           || data->type == it8728;
+}
+
 static u8 in_to_reg(const struct it87_data *data, int nr, long val)
 {
        long lsb;
 
-       if (data->type == it8721) {
+       if (has_12mv_adc(data)) {
                if (data->in_scaled & (1 << nr))
                        lsb = 24;
                else
@@ -292,7 +314,7 @@ static u8 in_to_reg(const struct it87_data *data, int nr, long val)
 
 static int in_from_reg(const struct it87_data *data, int nr, int val)
 {
-       if (data->type == it8721) {
+       if (has_12mv_adc(data)) {
                if (data->in_scaled & (1 << nr))
                        return val * 24;
                else
@@ -329,7 +351,7 @@ static inline u16 FAN16_TO_REG(long rpm)
 
 static u8 pwm_to_reg(const struct it87_data *data, long val)
 {
-       if (data->type == it8721)
+       if (has_newer_autopwm(data))
                return val;
        else
                return val >> 1;
@@ -337,7 +359,7 @@ static u8 pwm_to_reg(const struct it87_data *data, long val)
 
 static int pwm_from_reg(const struct it87_data *data, u8 reg)
 {
-       if (data->type == it8721)
+       if (has_newer_autopwm(data))
                return reg;
        else
                return (reg & 0x7f) << 1;
@@ -374,7 +396,8 @@ static inline int has_16bit_fans(const struct it87_data *data)
            || data->type == it8716
            || data->type == it8718
            || data->type == it8720
-           || data->type == it8721;
+           || data->type == it8721
+           || data->type == it8728;
 }
 
 static inline int has_old_autopwm(const struct it87_data *data)
@@ -842,7 +865,7 @@ static ssize_t set_pwm_enable(struct device *dev,
                                 data->fan_main_ctrl);
        } else {
                if (val == 1)                           /* Manual mode */
-                       data->pwm_ctrl[nr] = data->type == it8721 ?
+                       data->pwm_ctrl[nr] = has_newer_autopwm(data) ?
                                             data->pwm_temp_map[nr] :
                                             data->pwm_duty[nr];
                else                                    /* Automatic mode */
@@ -870,7 +893,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        mutex_lock(&data->update_lock);
-       if (data->type == it8721) {
+       if (has_newer_autopwm(data)) {
                /* If we are in automatic mode, the PWM duty cycle register
                 * is read-only so we can't write the value */
                if (data->pwm_ctrl[nr] & 0x80) {
@@ -1311,8 +1334,8 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr,
        struct it87_data *data = dev_get_drvdata(dev);
        int nr = to_sensor_dev_attr(attr)->index;
 
-       return sprintf(buf, "%s\n", data->type == it8721 ? labels_it8721[nr]
-                                                        : labels[nr]);
+       return sprintf(buf, "%s\n", has_12mv_adc(data) ? labels_it8721[nr]
+                                                      : labels[nr]);
 }
 static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0);
 static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1);
@@ -1605,6 +1628,9 @@ static int __init it87_find(unsigned short *address,
        case IT8721F_DEVID:
                sio_data->type = it8721;
                break;
+       case IT8728F_DEVID:
+               sio_data->type = it8728;
+               break;
        case 0xffff:    /* No device at all */
                goto exit;
        default:
@@ -1646,8 +1672,11 @@ static int __init it87_find(unsigned short *address,
                superio_select(GPIO);
 
                reg = superio_inb(IT87_SIO_GPIO3_REG);
-               if (sio_data->type == it8721) {
-                       /* The IT8721F/IT8758E doesn't have VID pins at all */
+               if (sio_data->type == it8721 || sio_data->type == it8728) {
+                       /*
+                        * The IT8721F/IT8758E doesn't have VID pins at all,
+                        * not sure about the IT8728F.
+                        */
                        sio_data->skip_vid = 1;
                } else {
                        /* We need at least 4 VID pins */
@@ -1692,7 +1721,8 @@ static int __init it87_find(unsigned short *address,
                }
                if (reg & (1 << 0))
                        sio_data->internal |= (1 << 0);
-               if ((reg & (1 << 1)) || sio_data->type == it8721)
+               if ((reg & (1 << 1)) || sio_data->type == it8721 ||
+                   sio_data->type == it8728)
                        sio_data->internal |= (1 << 1);
 
                sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
@@ -1770,6 +1800,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
                "it8718",
                "it8720",
                "it8721",
+               "it8728",
        };
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1807,7 +1838,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
        enable_pwm_interface = it87_check_pwm(dev);
 
        /* Starting with IT8721F, we handle scaling of internal voltages */
-       if (data->type == it8721) {
+       if (has_12mv_adc(data)) {
                if (sio_data->internal & (1 << 0))
                        data->in_scaled |= (1 << 3);    /* in3 is AVCC */
                if (sio_data->internal & (1 << 1))
@@ -2093,7 +2124,7 @@ static void __devinit it87_init_device(struct platform_device *pdev)
 static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
 {
        data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr));
-       if (data->type == it8721) {
+       if (has_newer_autopwm(data)) {
                data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
                data->pwm_duty[nr] = it87_read_value(data,
                                                     IT87_REG_PWM_DUTY(nr));
index 508cb291f71bfc35681bfda50dbad88a1a8a8dc2..5e6457a6644d879ab94830edd6881e0826f6678c 100644 (file)
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
+#include <linux/types.h>
 
 /*
  * Addresses to scan
- * Address is fully defined internally and cannot be changed.
+ * Address is fully defined internally and cannot be changed except for
+ * LM64 which has one pin dedicated to address selection.
+ * LM63 and LM96163 have address 0x4c.
+ * LM64 can have address 0x18 or 0x4e.
  */
 
 static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
@@ -60,6 +64,7 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
  */
 
 #define LM63_REG_CONFIG1               0x03
+#define LM63_REG_CONVRATE              0x04
 #define LM63_REG_CONFIG2               0xBF
 #define LM63_REG_CONFIG_FAN            0x4A
 
@@ -70,6 +75,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
 
 #define LM63_REG_PWM_VALUE             0x4C
 #define LM63_REG_PWM_FREQ              0x4D
+#define LM63_REG_LUT_TEMP_HYST         0x4F
+#define LM63_REG_LUT_TEMP(nr)          (0x50 + 2 * (nr))
+#define LM63_REG_LUT_PWM(nr)           (0x51 + 2 * (nr))
 
 #define LM63_REG_LOCAL_TEMP            0x00
 #define LM63_REG_LOCAL_HIGH            0x05
@@ -91,6 +99,16 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
 #define LM63_REG_MAN_ID                        0xFE
 #define LM63_REG_CHIP_ID               0xFF
 
+#define LM96163_REG_TRUTHERM           0x30
+#define LM96163_REG_REMOTE_TEMP_U_MSB  0x31
+#define LM96163_REG_REMOTE_TEMP_U_LSB  0x32
+#define LM96163_REG_CONFIG_ENHANCED    0x45
+
+#define LM63_MAX_CONVRATE              9
+
+#define LM63_MAX_CONVRATE_HZ           32
+#define LM96163_MAX_CONVRATE_HZ                26
+
 /*
  * Conversions and various macros
  * For tachometer counts, the LM63 uses 16-bit values.
@@ -112,15 +130,24 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
                                 (val) >= 127000 ? 127 : \
                                 (val) < 0 ? ((val) - 500) / 1000 : \
                                 ((val) + 500) / 1000)
+#define TEMP8U_TO_REG(val)     ((val) <= 0 ? 0 : \
+                                (val) >= 255000 ? 255 : \
+                                ((val) + 500) / 1000)
 #define TEMP11_FROM_REG(reg)   ((reg) / 32 * 125)
 #define TEMP11_TO_REG(val)     ((val) <= -128000 ? 0x8000 : \
                                 (val) >= 127875 ? 0x7FE0 : \
                                 (val) < 0 ? ((val) - 62) / 125 * 32 : \
                                 ((val) + 62) / 125 * 32)
+#define TEMP11U_TO_REG(val)    ((val) <= 0 ? 0 : \
+                                (val) >= 255875 ? 0xFFE0 : \
+                                ((val) + 62) / 125 * 32)
 #define HYST_TO_REG(val)       ((val) <= 0 ? 0 : \
                                 (val) >= 127000 ? 127 : \
                                 ((val) + 500) / 1000)
 
+#define UPDATE_INTERVAL(max, rate) \
+                       ((1000 << (LM63_MAX_CONVRATE - (rate))) / (max))
+
 /*
  * Functions declaration
  */
@@ -134,7 +161,7 @@ static struct lm63_data *lm63_update_device(struct device *dev);
 static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info);
 static void lm63_init_client(struct i2c_client *client);
 
-enum chips { lm63, lm64 };
+enum chips { lm63, lm64, lm96163 };
 
 /*
  * Driver data (common to all clients)
@@ -143,6 +170,7 @@ enum chips { lm63, lm64 };
 static const struct i2c_device_id lm63_id[] = {
        { "lm63", lm63 },
        { "lm64", lm64 },
+       { "lm96163", lm96163 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, lm63_id);
@@ -167,26 +195,53 @@ struct lm63_data {
        struct device *hwmon_dev;
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
+       char lut_valid; /* zero until lut fields are valid */
        unsigned long last_updated; /* in jiffies */
-       int kind;
+       unsigned long lut_last_updated; /* in jiffies */
+       enum chips kind;
        int temp2_offset;
 
+       int update_interval;    /* in milliseconds */
+       int max_convrate_hz;
+       int lut_size;           /* 8 or 12 */
+
        /* registers values */
        u8 config, config_fan;
        u16 fan[2];     /* 0: input
                           1: low limit */
        u8 pwm1_freq;
-       u8 pwm1_value;
-       s8 temp8[3];    /* 0: local input
+       u8 pwm1[13];    /* 0: current output
+                          1-12: lookup table */
+       s8 temp8[15];   /* 0: local input
                           1: local high limit
-                          2: remote critical limit */
-       s16 temp11[3];  /* 0: remote input
+                          2: remote critical limit
+                          3-14: lookup table */
+       s16 temp11[4];  /* 0: remote input
                           1: remote low limit
-                          2: remote high limit */
+                          2: remote high limit
+                          3: remote offset */
+       u16 temp11u;    /* remote input (unsigned) */
        u8 temp2_crit_hyst;
+       u8 lut_temp_hyst;
        u8 alarms;
+       bool pwm_highres;
+       bool lut_temp_highres;
+       bool remote_unsigned; /* true if unsigned remote upper limits */
+       bool trutherm;
 };
 
+static inline int temp8_from_reg(struct lm63_data *data, int nr)
+{
+       if (data->remote_unsigned)
+               return TEMP8_FROM_REG((u8)data->temp8[nr]);
+       return TEMP8_FROM_REG(data->temp8[nr]);
+}
+
+static inline int lut_temp_from_reg(struct lm63_data *data, int nr)
+{
+       return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000);
+}
+
 /*
  * Sysfs callback functions and files
  */
@@ -204,7 +259,12 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
-       unsigned long val = simple_strtoul(buf, NULL, 10);
+       unsigned long val;
+       int err;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err)
+               return err;
 
        mutex_lock(&data->update_lock);
        data->fan[1] = FAN_TO_REG(val);
@@ -216,13 +276,22 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
        return count;
 }
 
-static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy,
+static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
                         char *buf)
 {
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct lm63_data *data = lm63_update_device(dev);
-       return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ?
-                      255 : (data->pwm1_value * 255 + data->pwm1_freq) /
-                      (2 * data->pwm1_freq));
+       int nr = attr->index;
+       int pwm;
+
+       if (data->pwm_highres)
+               pwm = data->pwm1[nr];
+       else
+               pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ?
+                      255 : (data->pwm1[nr] * 255 + data->pwm1_freq) /
+                      (2 * data->pwm1_freq);
+
+       return sprintf(buf, "%d\n", pwm);
 }
 
 static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
@@ -231,22 +300,26 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
        unsigned long val;
-       
+       int err;
+
        if (!(data->config_fan & 0x20)) /* register is read-only */
                return -EPERM;
 
-       val = simple_strtoul(buf, NULL, 10);
+       err = kstrtoul(buf, 10, &val);
+       if (err)
+               return err;
+
+       val = SENSORS_LIMIT(val, 0, 255);
        mutex_lock(&data->update_lock);
-       data->pwm1_value = val <= 0 ? 0 :
-                          val >= 255 ? 2 * data->pwm1_freq :
-                          (val * data->pwm1_freq * 2 + 127) / 255;
-       i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value);
+       data->pwm1[0] = data->pwm_highres ? val :
+                       (val * data->pwm1_freq * 2 + 127) / 255;
+       i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]);
        mutex_unlock(&data->update_lock);
        return count;
 }
 
-static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy,
-                               char *buf)
+static ssize_t show_pwm1_enable(struct device *dev,
+                               struct device_attribute *dummy, char *buf)
 {
        struct lm63_data *data = lm63_update_device(dev);
        return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
@@ -273,21 +346,47 @@ static ssize_t show_remote_temp8(struct device *dev,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct lm63_data *data = lm63_update_device(dev);
-       return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index])
+       return sprintf(buf, "%d\n", temp8_from_reg(data, attr->index)
+                      + data->temp2_offset);
+}
+
+static ssize_t show_lut_temp(struct device *dev,
+                             struct device_attribute *devattr,
+                             char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct lm63_data *data = lm63_update_device(dev);
+       return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index)
                       + data->temp2_offset);
 }
 
-static ssize_t set_local_temp8(struct device *dev,
-                              struct device_attribute *dummy,
-                              const char *buf, size_t count)
+static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
+                        const char *buf, size_t count)
 {
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
-       long val = simple_strtol(buf, NULL, 10);
+       int nr = attr->index;
+       int reg = nr == 2 ? LM63_REG_REMOTE_TCRIT : LM63_REG_LOCAL_HIGH;
+       long val;
+       int err;
+       int temp;
+
+       err = kstrtol(buf, 10, &val);
+       if (err)
+               return err;
 
        mutex_lock(&data->update_lock);
-       data->temp8[1] = TEMP8_TO_REG(val);
-       i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]);
+       if (nr == 2) {
+               if (data->remote_unsigned)
+                       temp = TEMP8U_TO_REG(val - data->temp2_offset);
+               else
+                       temp = TEMP8_TO_REG(val - data->temp2_offset);
+       } else {
+               temp = TEMP8_TO_REG(val);
+       }
+       data->temp8[nr] = temp;
+       i2c_smbus_write_byte_data(client, reg, temp);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -297,28 +396,56 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct lm63_data *data = lm63_update_device(dev);
-       return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index])
-                      + data->temp2_offset);
+       int nr = attr->index;
+       int temp;
+
+       if (!nr) {
+               /*
+                * Use unsigned temperature unless its value is zero.
+                * If it is zero, use signed temperature.
+                */
+               if (data->temp11u)
+                       temp = TEMP11_FROM_REG(data->temp11u);
+               else
+                       temp = TEMP11_FROM_REG(data->temp11[nr]);
+       } else {
+               if (data->remote_unsigned && nr == 2)
+                       temp = TEMP11_FROM_REG((u16)data->temp11[nr]);
+               else
+                       temp = TEMP11_FROM_REG(data->temp11[nr]);
+       }
+       return sprintf(buf, "%d\n", temp + data->temp2_offset);
 }
 
 static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
                          const char *buf, size_t count)
 {
-       static const u8 reg[4] = {
+       static const u8 reg[6] = {
                LM63_REG_REMOTE_LOW_MSB,
                LM63_REG_REMOTE_LOW_LSB,
                LM63_REG_REMOTE_HIGH_MSB,
                LM63_REG_REMOTE_HIGH_LSB,
+               LM63_REG_REMOTE_OFFSET_MSB,
+               LM63_REG_REMOTE_OFFSET_LSB,
        };
 
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
-       long val = simple_strtol(buf, NULL, 10);
+       long val;
+       int err;
        int nr = attr->index;
 
+       err = kstrtol(buf, 10, &val);
+       if (err)
+               return err;
+
        mutex_lock(&data->update_lock);
-       data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset);
+       if (data->remote_unsigned && nr == 2)
+               data->temp11[nr] = TEMP11U_TO_REG(val - data->temp2_offset);
+       else
+               data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset);
+
        i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
                                  data->temp11[nr] >> 8);
        i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
@@ -327,35 +454,143 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
        return count;
 }
 
-/* Hysteresis register holds a relative value, while we want to present
-   an absolute to user-space */
-static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
-                                   char *buf)
+/*
+ * Hysteresis register holds a relative value, while we want to present
+ * an absolute to user-space
+ */
+static ssize_t show_temp2_crit_hyst(struct device *dev,
+                                   struct device_attribute *dummy, char *buf)
 {
        struct lm63_data *data = lm63_update_device(dev);
-       return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2])
+       return sprintf(buf, "%d\n", temp8_from_reg(data, 2)
                       + data->temp2_offset
                       - TEMP8_FROM_REG(data->temp2_crit_hyst));
 }
 
-/* And now the other way around, user-space provides an absolute
-   hysteresis value and we have to store a relative one */
-static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
+static ssize_t show_lut_temp_hyst(struct device *dev,
+                                 struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct lm63_data *data = lm63_update_device(dev);
+
+       return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index)
+                      + data->temp2_offset
+                      - TEMP8_FROM_REG(data->lut_temp_hyst));
+}
+
+/*
+ * And now the other way around, user-space provides an absolute
+ * hysteresis value and we have to store a relative one
+ */
+static ssize_t set_temp2_crit_hyst(struct device *dev,
+                                  struct device_attribute *dummy,
                                   const char *buf, size_t count)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
-       long val = simple_strtol(buf, NULL, 10);
+       long val;
+       int err;
        long hyst;
 
+       err = kstrtol(buf, 10, &val);
+       if (err)
+               return err;
+
        mutex_lock(&data->update_lock);
-       hyst = TEMP8_FROM_REG(data->temp8[2]) + data->temp2_offset - val;
+       hyst = temp8_from_reg(data, 2) + data->temp2_offset - val;
        i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
                                  HYST_TO_REG(hyst));
        mutex_unlock(&data->update_lock);
        return count;
 }
 
+/*
+ * Set conversion rate.
+ * client->update_lock must be held when calling this function.
+ */
+static void lm63_set_convrate(struct i2c_client *client, struct lm63_data *data,
+                             unsigned int interval)
+{
+       int i;
+       unsigned int update_interval;
+
+       /* Shift calculations to avoid rounding errors */
+       interval <<= 6;
+
+       /* find the nearest update rate */
+       update_interval = (1 << (LM63_MAX_CONVRATE + 6)) * 1000
+         / data->max_convrate_hz;
+       for (i = 0; i < LM63_MAX_CONVRATE; i++, update_interval >>= 1)
+               if (interval >= update_interval * 3 / 4)
+                       break;
+
+       i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE, i);
+       data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, i);
+}
+
+static ssize_t show_update_interval(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct lm63_data *data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", data->update_interval);
+}
+
+static ssize_t set_update_interval(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm63_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+       int err;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err)
+               return err;
+
+       mutex_lock(&data->update_lock);
+       lm63_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000));
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_type(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm63_data *data = i2c_get_clientdata(client);
+
+       return sprintf(buf, data->trutherm ? "1\n" : "2\n");
+}
+
+static ssize_t set_type(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm63_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+       int ret;
+       u8 reg;
+
+       ret = kstrtoul(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+       if (val != 1 && val != 2)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       data->trutherm = val == 1;
+       reg = i2c_smbus_read_byte_data(client, LM96163_REG_TRUTHERM) & ~0x02;
+       i2c_smbus_write_byte_data(client, LM96163_REG_TRUTHERM,
+                                 reg | (data->trutherm ? 0x02 : 0x00));
+       data->valid = 0;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
 static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
                           char *buf)
 {
@@ -377,27 +612,87 @@ static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
 static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
        set_fan, 1);
 
-static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0);
 static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, show_pwm1, NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IRUGO,
+       show_lut_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO,
+       show_lut_temp_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO, show_pwm1, NULL, 2);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO,
+       show_lut_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO,
+       show_lut_temp_hyst, NULL, 4);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, show_pwm1, NULL, 3);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IRUGO,
+       show_lut_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO,
+       show_lut_temp_hyst, NULL, 5);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO, show_pwm1, NULL, 4);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IRUGO,
+       show_lut_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO,
+       show_lut_temp_hyst, NULL, 6);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm1, NULL, 5);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IRUGO,
+       show_lut_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO,
+       show_lut_temp_hyst, NULL, 7);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IRUGO, show_pwm1, NULL, 6);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IRUGO,
+       show_lut_temp, NULL, 8);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO,
+       show_lut_temp_hyst, NULL, 8);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IRUGO, show_pwm1, NULL, 7);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IRUGO,
+       show_lut_temp, NULL, 9);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO,
+       show_lut_temp_hyst, NULL, 9);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IRUGO, show_pwm1, NULL, 8);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IRUGO,
+       show_lut_temp, NULL, 10);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO,
+       show_lut_temp_hyst, NULL, 10);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IRUGO, show_pwm1, NULL, 9);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IRUGO,
+       show_lut_temp, NULL, 11);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp_hyst, S_IRUGO,
+       show_lut_temp_hyst, NULL, 11);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IRUGO, show_pwm1, NULL, 10);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IRUGO,
+       show_lut_temp, NULL, 12);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp_hyst, S_IRUGO,
+       show_lut_temp_hyst, NULL, 12);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IRUGO, show_pwm1, NULL, 11);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IRUGO,
+       show_lut_temp, NULL, 13);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp_hyst, S_IRUGO,
+       show_lut_temp_hyst, NULL, 13);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IRUGO, show_pwm1, NULL, 12);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IRUGO,
+       show_lut_temp, NULL, 14);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp_hyst, S_IRUGO,
+       show_lut_temp_hyst, NULL, 14);
 
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8,
-       set_local_temp8, 1);
+       set_temp8, 1);
 
 static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
        set_temp11, 1);
 static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
        set_temp11, 2);
-/*
- * On LM63, temp2_crit can be set only once, which should be job
- * of the bootloader.
- */
+static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
+       set_temp11, 3);
 static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8,
-       NULL, 2);
+       set_temp8, 2);
 static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
        set_temp2_crit_hyst);
 
+static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type);
+
 /* Individual alarm files */
 static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
@@ -408,14 +703,43 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
 /* Raw alarm file for compatibility */
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
+static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
+                  set_update_interval);
+
 static struct attribute *lm63_attributes[] = {
-       &dev_attr_pwm1.attr,
+       &sensor_dev_attr_pwm1.dev_attr.attr,
        &dev_attr_pwm1_enable.attr,
+       &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point2_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point3_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point4_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point5_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point6_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point7_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point8_temp_hyst.dev_attr.attr,
+
        &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_temp2_input.dev_attr.attr,
        &sensor_dev_attr_temp2_min.dev_attr.attr,
        &sensor_dev_attr_temp1_max.dev_attr.attr,
        &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_offset.dev_attr.attr,
        &sensor_dev_attr_temp2_crit.dev_attr.attr,
        &dev_attr_temp2_crit_hyst.attr,
 
@@ -425,10 +749,54 @@ static struct attribute *lm63_attributes[] = {
        &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
        &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
        &dev_attr_alarms.attr,
+       &dev_attr_update_interval.attr,
        NULL
 };
 
+static struct attribute *lm63_attributes_extra_lut[] = {
+       &sensor_dev_attr_pwm1_auto_point9_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point9_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point9_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point10_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point10_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point10_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point11_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point11_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point11_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point12_pwm.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point12_temp.dev_attr.attr,
+       &sensor_dev_attr_pwm1_auto_point12_temp_hyst.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group lm63_group_extra_lut = {
+       .attrs = lm63_attributes_extra_lut,
+};
+
+/*
+ * On LM63, temp2_crit can be set only once, which should be job
+ * of the bootloader.
+ * On LM64, temp2_crit can always be set.
+ * On LM96163, temp2_crit can be set if bit 1 of the configuration
+ * register is true.
+ */
+static umode_t lm63_attribute_mode(struct kobject *kobj,
+                                  struct attribute *attr, int index)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm63_data *data = i2c_get_clientdata(client);
+
+       if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr
+           && (data->kind == lm64 ||
+               (data->kind == lm96163 && (data->config & 0x02))))
+               return attr->mode | S_IWUSR;
+
+       return attr->mode;
+}
+
 static const struct attribute_group lm63_group = {
+       .is_visible = lm63_attribute_mode,
        .attrs = lm63_attributes,
 };
 
@@ -487,6 +855,8 @@ static int lm63_detect(struct i2c_client *new_client,
                strlcpy(info->type, "lm63", I2C_NAME_SIZE);
        else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e))
                strlcpy(info->type, "lm64", I2C_NAME_SIZE);
+       else if (chip_id == 0x49 && address == 0x4c)
+               strlcpy(info->type, "lm96163", I2C_NAME_SIZE);
        else
                return -ENODEV;
 
@@ -518,12 +888,24 @@ static int lm63_probe(struct i2c_client *new_client,
        lm63_init_client(new_client);
 
        /* Register sysfs hooks */
-       if ((err = sysfs_create_group(&new_client->dev.kobj,
-                                     &lm63_group)))
+       err = sysfs_create_group(&new_client->dev.kobj, &lm63_group);
+       if (err)
                goto exit_free;
        if (data->config & 0x04) { /* tachometer enabled */
-               if ((err = sysfs_create_group(&new_client->dev.kobj,
-                                             &lm63_group_fan1)))
+               err = sysfs_create_group(&new_client->dev.kobj,
+                                        &lm63_group_fan1);
+               if (err)
+                       goto exit_remove_files;
+       }
+       if (data->kind == lm96163) {
+               err = device_create_file(&new_client->dev,
+                                        &dev_attr_temp2_type);
+               if (err)
+                       goto exit_remove_files;
+
+               err = sysfs_create_group(&new_client->dev.kobj,
+                                        &lm63_group_extra_lut);
+               if (err)
                        goto exit_remove_files;
        }
 
@@ -538,17 +920,25 @@ static int lm63_probe(struct i2c_client *new_client,
 exit_remove_files:
        sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
        sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
+       if (data->kind == lm96163) {
+               device_remove_file(&new_client->dev, &dev_attr_temp2_type);
+               sysfs_remove_group(&new_client->dev.kobj,
+                                  &lm63_group_extra_lut);
+       }
 exit_free:
        kfree(data);
 exit:
        return err;
 }
 
-/* Idealy we shouldn't have to initialize anything, since the BIOS
-   should have taken care of everything */
+/*
+ * Ideally we shouldn't have to initialize anything, since the BIOS
+ * should have taken care of everything
+ */
 static void lm63_init_client(struct i2c_client *client)
 {
        struct lm63_data *data = i2c_get_clientdata(client);
+       u8 convrate;
 
        data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
        data->config_fan = i2c_smbus_read_byte_data(client,
@@ -561,16 +951,57 @@ static void lm63_init_client(struct i2c_client *client)
                i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
                                          data->config);
        }
+       /* Tachometer is always enabled on LM64 */
+       if (data->kind == lm64)
+               data->config |= 0x04;
 
        /* We may need pwm1_freq before ever updating the client data */
        data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ);
        if (data->pwm1_freq == 0)
                data->pwm1_freq = 1;
 
+       switch (data->kind) {
+       case lm63:
+       case lm64:
+               data->max_convrate_hz = LM63_MAX_CONVRATE_HZ;
+               data->lut_size = 8;
+               break;
+       case lm96163:
+               data->max_convrate_hz = LM96163_MAX_CONVRATE_HZ;
+               data->lut_size = 12;
+               data->trutherm
+                 = i2c_smbus_read_byte_data(client,
+                                            LM96163_REG_TRUTHERM) & 0x02;
+               break;
+       }
+       convrate = i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE);
+       if (unlikely(convrate > LM63_MAX_CONVRATE))
+               convrate = LM63_MAX_CONVRATE;
+       data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz,
+                                               convrate);
+
+       /*
+        * For LM96163, check if high resolution PWM
+        * and unsigned temperature format is enabled.
+        */
+       if (data->kind == lm96163) {
+               u8 config_enhanced
+                 = i2c_smbus_read_byte_data(client,
+                                            LM96163_REG_CONFIG_ENHANCED);
+               if (config_enhanced & 0x20)
+                       data->lut_temp_highres = true;
+               if ((config_enhanced & 0x10)
+                   && !(data->config_fan & 0x08) && data->pwm1_freq == 8)
+                       data->pwm_highres = true;
+               if (config_enhanced & 0x08)
+                       data->remote_unsigned = true;
+       }
+
        /* Show some debug info about the LM63 configuration */
-       dev_dbg(&client->dev, "Alert/tach pin configured for %s\n",
-               (data->config & 0x04) ? "tachometer input" :
-               "alert output");
+       if (data->kind == lm63)
+               dev_dbg(&client->dev, "Alert/tach pin configured for %s\n",
+                       (data->config & 0x04) ? "tachometer input" :
+                       "alert output");
        dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz\n",
                (data->config_fan & 0x08) ? "1.4" : "360",
                ((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq);
@@ -586,6 +1017,10 @@ static int lm63_remove(struct i2c_client *client)
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm63_group);
        sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
+       if (data->kind == lm96163) {
+               device_remove_file(&client->dev, &dev_attr_temp2_type);
+               sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut);
+       }
 
        kfree(data);
        return 0;
@@ -595,10 +1030,15 @@ static struct lm63_data *lm63_update_device(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
+       unsigned long next_update;
+       int i;
 
        mutex_lock(&data->update_lock);
 
-       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+       next_update = data->last_updated
+         + msecs_to_jiffies(data->update_interval) + 1;
+
+       if (time_after(jiffies, next_update) || !data->valid) {
                if (data->config & 0x04) { /* tachometer enabled  */
                        /* order matters for fan1_input */
                        data->fan[0] = i2c_smbus_read_byte_data(client,
@@ -615,8 +1055,8 @@ static struct lm63_data *lm63_update_device(struct device *dev)
                                  LM63_REG_PWM_FREQ);
                if (data->pwm1_freq == 0)
                        data->pwm1_freq = 1;
-               data->pwm1_value = i2c_smbus_read_byte_data(client,
-                                  LM63_REG_PWM_VALUE);
+               data->pwm1[0] = i2c_smbus_read_byte_data(client,
+                               LM63_REG_PWM_VALUE);
 
                data->temp8[0] = i2c_smbus_read_byte_data(client,
                                 LM63_REG_LOCAL_TEMP);
@@ -636,6 +1076,17 @@ static struct lm63_data *lm63_update_device(struct device *dev)
                                  LM63_REG_REMOTE_HIGH_MSB) << 8)
                                | i2c_smbus_read_byte_data(client,
                                  LM63_REG_REMOTE_HIGH_LSB);
+               data->temp11[3] = (i2c_smbus_read_byte_data(client,
+                                 LM63_REG_REMOTE_OFFSET_MSB) << 8)
+                               | i2c_smbus_read_byte_data(client,
+                                 LM63_REG_REMOTE_OFFSET_LSB);
+
+               if (data->kind == lm96163)
+                       data->temp11u = (i2c_smbus_read_byte_data(client,
+                                       LM96163_REG_REMOTE_TEMP_U_MSB) << 8)
+                                     | i2c_smbus_read_byte_data(client,
+                                       LM96163_REG_REMOTE_TEMP_U_LSB);
+
                data->temp8[2] = i2c_smbus_read_byte_data(client,
                                 LM63_REG_REMOTE_TCRIT);
                data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
@@ -648,6 +1099,21 @@ static struct lm63_data *lm63_update_device(struct device *dev)
                data->valid = 1;
        }
 
+       if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
+           !data->lut_valid) {
+               for (i = 0; i < data->lut_size; i++) {
+                       data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
+                                           LM63_REG_LUT_PWM(i));
+                       data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
+                                            LM63_REG_LUT_TEMP(i));
+               }
+               data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
+                                     LM63_REG_LUT_TEMP_HYST);
+
+               data->lut_last_updated = jiffies;
+               data->lut_valid = 1;
+       }
+
        mutex_unlock(&data->update_lock);
 
        return data;
index bdfd675488aeb5e64b9d4c144c5cfd185ad0ecb0..d2dd5f90496df1ca4393467e31f1ab78264f17d8 100644 (file)
@@ -917,7 +917,7 @@ static ssize_t set_update_interval(struct device *dev,
                return err;
 
        mutex_lock(&data->update_lock);
-       lm90_set_convrate(client, data, val);
+       lm90_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000));
        mutex_unlock(&data->update_lock);
 
        return count;
index 3b43df418613faf329abe451022126109aae15ae..8bd6c5c9e05bc6781891cf65cb0f7a05c5faa1ae 100644 (file)
@@ -151,12 +151,12 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 
 /* Insmod parameters */
 
-static int disable_block;
+static bool disable_block;
 module_param(disable_block, bool, 0);
 MODULE_PARM_DESC(disable_block,
        "Set to non-zero to disable SMBus block data transactions.");
 
-static int init;
+static bool init;
 module_param(init, bool, 0);
 MODULE_PARM_DESC(init, "Set to non-zero to force chip initialization.");
 
index 84ef3a898707ec4bd572c04f4be75836d036a8c3..482ca901db30b61632773176a4131be60a200575 100644 (file)
@@ -106,11 +106,14 @@ static ssize_t show_adc(struct device *dev,
        if (ret < 0)
                return ret;
 
-       return sprintf(buf, "%d\n", ret);
+       /* assume the reference voltage to be 2.048V, with an 8-bit sample,
+        * the LSB weight is 8mV
+        */
+       return sprintf(buf, "%d\n", ret * 8);
 }
 
 #define MAX1111_ADC_ATTR(_id)          \
-       SENSOR_DEVICE_ATTR(adc##_id##_in, S_IRUGO, show_adc, NULL, _id)
+       SENSOR_DEVICE_ATTR(in##_id##_input, S_IRUGO, show_adc, NULL, _id)
 
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 static MAX1111_ADC_ATTR(0);
@@ -120,10 +123,10 @@ static MAX1111_ADC_ATTR(3);
 
 static struct attribute *max1111_attributes[] = {
        &dev_attr_name.attr,
-       &sensor_dev_attr_adc0_in.dev_attr.attr,
-       &sensor_dev_attr_adc1_in.dev_attr.attr,
-       &sensor_dev_attr_adc2_in.dev_attr.attr,
-       &sensor_dev_attr_adc3_in.dev_attr.attr,
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
        NULL,
 };
 
index 6914195cfd350bd826872f6f6beab08e65b48274..88953f99e91437da56a3cad38f593141b3d2e98f 100644 (file)
@@ -59,7 +59,7 @@ static unsigned short max1668_addr_list[] = {
 #define DEV_ID_MAX1989         0xb
 
 /* read only mode module parameter */
-static int read_only;
+static bool read_only;
 module_param(read_only, bool, 0);
 MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
 
index bde50e34d01322144639695d0608ec14144ed84f..374118f2b9f94b73fc47bf0ec5d2f83e86bbc697 100644 (file)
@@ -71,7 +71,7 @@ module_param(force_i2c, byte, 0);
 MODULE_PARM_DESC(force_i2c,
                 "Initialize the i2c address of the sensors");
 
-static int init = 1;
+static bool init = 1;
 module_param(init, bool, 0);
 MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
 
index 65b685e2c7b739634fd62f6d17238a1003945604..17a8fa2d9ae947492cb1ea6daaec152e688cad2e 100644 (file)
@@ -67,11 +67,11 @@ module_param_array(force_subclients, short, NULL, 0);
 MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
                    "{bus, clientaddr, subclientaddr1, subclientaddr2}");
 
-static int reset;
+static bool reset;
 module_param(reset, bool, 0);
 MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
 
-static int init = 1;
+static bool init = 1;
 module_param(init, bool, 0);
 MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
 
index 6e5d0ae594b06e53ef7cd5acc1327bd4fd366041..35aa5149307a28f7330b5a27698750f2afdd984f 100644 (file)
@@ -58,11 +58,11 @@ module_param_array(force_subclients, short, NULL, 0);
 MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
                        "{bus, clientaddr, subclientaddr1, subclientaddr2}");
 
-static int reset;
+static bool reset;
 module_param(reset, bool, 0);
 MODULE_PARM_DESC(reset, "Set to one to force a hardware chip reset");
 
-static int init;
+static bool init;
 module_param(init, bool, 0);
 MODULE_PARM_DESC(init, "Set to one to force extra software initialization");
 
index 9ded133e43f04ff09fbd90c3ddeaa803b1eb65be..d3100eab6b2f281bd77e94f1e669003ccd892fa3 100644 (file)
@@ -56,7 +56,7 @@ module_param_array(force_subclients, short, NULL, 0);
 MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
                        "{bus, clientaddr, subclientaddr1, subclientaddr2}");
 
-static int init;
+static bool init;
 module_param(init, bool, 0);
 MODULE_PARM_DESC(init, "Set to one to force chip initialization");
 
index 3cc6fef22087b19d03770b94a81d303b26d5afab..45ec7e7c3c278d3c774aec9cf4a4897aad8a342b 100644 (file)
@@ -61,7 +61,7 @@ module_param_array(force_subclients, short, NULL, 0);
 MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
                       "{bus, clientaddr, subclientaddr1, subclientaddr2}");
 
-static int reset;
+static bool reset;
 module_param(reset, bool, 0);
 MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
 
index 3ee398d0e4c914109fdd08f5451a308d2299d063..aa58b25565bc3e1d21dd23f2baca73d3fe7b2e9c 100644 (file)
@@ -42,7 +42,7 @@ static const unsigned short normal_i2c[] = {
 };
 
 
-static int reset;
+static bool reset;
 module_param(reset, bool, 0);
 MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
 
index 0254e181893d9f2e9bd0d010d37f6544559ad3e5..063bd9508d8a1505dadba8699e806a1c93901356 100644 (file)
@@ -39,7 +39,7 @@ static const unsigned short normal_i2c[] = { 0x2e, 0x2f, I2C_CLIENT_END };
 
 /* Insmod parameters */
 
-static int reset;
+static bool reset;
 module_param(reset, bool, 0);
 MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
 
index a3afac4be73463190c0d687efe480caa27db8d90..3101dd59e3794c6d2d34c2ff4df65f1cece29a28 100644 (file)
@@ -299,11 +299,11 @@ config I2C_AT91
          unless your system can cope with those limitations.
 
 config I2C_AU1550
-       tristate "Au1550/Au1200 SMBus interface"
+       tristate "Au1550/Au1200/Au1300 SMBus interface"
        depends on MIPS_ALCHEMY
        help
          If you say yes to this option, support will be included for the
-         Au1550 and Au1200 SMBus interface.
+         Au1550/Au1200/Au1300 SMBus interface.
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-au1550.
@@ -682,19 +682,19 @@ config I2C_XILINX
          will be called xilinx_i2c.
 
 config I2C_EG20T
-       tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223)"
+       tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
        depends on PCI
        help
          This driver is for PCH(Platform controller Hub) I2C of EG20T which
          is an IOH(Input/Output Hub) for x86 embedded processor.
          This driver can access PCH I2C bus device.
 
-         This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
-         Output Hub), ML7213 and ML7223.
-         ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
-         for MP(Media Phone) use.
-         ML7213/ML7223 is companion chip for Intel Atom E6xx series.
-         ML7213/ML7223 is completely compatible for Intel EG20T PCH.
+         This driver also can be used for LAPIS Semiconductor IOH(Input/
+         Output Hub), ML7213, ML7223 and ML7831.
+         ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is
+         for MP(Media Phone) use and ML7831 IOH is for general purpose use.
+         ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
+         ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
 
 comment "External I2C/SMBus adapter drivers"
 
index b6807db7b36f98f03ff00d15f6677906c4ddc8aa..e66d248fc126b8ffe4f9d85e45f82a76c5ee9bf7 100644 (file)
 #define        ALI1535_SMBIO_EN        0x04    /* SMB I/O Space enable         */
 
 static struct pci_driver ali1535_driver;
-static unsigned short ali1535_smba;
+static unsigned long ali1535_smba;
+static unsigned short ali1535_offset;
 
 /* Detect whether a ALI1535 can be found, and initialize it, where necessary.
    Note the differences between kernels with the old PCI BIOS interface and
@@ -140,7 +141,7 @@ static unsigned short ali1535_smba;
    defined to make the transition easier. */
 static int __devinit ali1535_setup(struct pci_dev *dev)
 {
-       int retval = -ENODEV;
+       int retval;
        unsigned char temp;
 
        /* Check the following things:
@@ -149,15 +150,28 @@ static int __devinit ali1535_setup(struct pci_dev *dev)
                - We can use the addresses
        */
 
+       retval = pci_enable_device(dev);
+       if (retval) {
+               dev_err(&dev->dev, "ALI1535_smb can't enable device\n");
+               goto exit;
+       }
+
        /* Determine the address of the SMBus area */
-       pci_read_config_word(dev, SMBBA, &ali1535_smba);
-       ali1535_smba &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1));
-       if (ali1535_smba == 0) {
+       pci_read_config_word(dev, SMBBA, &ali1535_offset);
+       dev_dbg(&dev->dev, "ALI1535_smb is at offset 0x%04x\n", ali1535_offset);
+       ali1535_offset &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1));
+       if (ali1535_offset == 0) {
                dev_warn(&dev->dev,
                        "ALI1535_smb region uninitialized - upgrade BIOS?\n");
+               retval = -ENODEV;
                goto exit;
        }
 
+       if (pci_resource_flags(dev, 0) & IORESOURCE_IO)
+               ali1535_smba = pci_resource_start(dev, 0) + ali1535_offset;
+       else
+               ali1535_smba = ali1535_offset;
+
        retval = acpi_check_region(ali1535_smba, ALI1535_SMB_IOSIZE,
                                   ali1535_driver.name);
        if (retval)
@@ -165,8 +179,9 @@ static int __devinit ali1535_setup(struct pci_dev *dev)
 
        if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE,
                            ali1535_driver.name)) {
-               dev_err(&dev->dev, "ALI1535_smb region 0x%x already in use!\n",
+               dev_err(&dev->dev, "ALI1535_smb region 0x%lx already in use!\n",
                        ali1535_smba);
+               retval = -EBUSY;
                goto exit;
        }
 
@@ -174,6 +189,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev)
        pci_read_config_byte(dev, SMBCFG, &temp);
        if ((temp & ALI1535_SMBIO_EN) == 0) {
                dev_err(&dev->dev, "SMB device not enabled - upgrade BIOS?\n");
+               retval = -ENODEV;
                goto exit_free;
        }
 
@@ -181,6 +197,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev)
        pci_read_config_byte(dev, SMBHSTCFG, &temp);
        if ((temp & 1) == 0) {
                dev_err(&dev->dev, "SMBus controller not enabled - upgrade BIOS?\n");
+               retval = -ENODEV;
                goto exit_free;
        }
 
@@ -196,14 +213,13 @@ static int __devinit ali1535_setup(struct pci_dev *dev)
        */
        pci_read_config_byte(dev, SMBREV, &temp);
        dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp);
-       dev_dbg(&dev->dev, "ALI1535_smba = 0x%X\n", ali1535_smba);
+       dev_dbg(&dev->dev, "ALI1535_smba = 0x%lx\n", ali1535_smba);
 
-       retval = 0;
-exit:
-       return retval;
+       return 0;
 
 exit_free:
        release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
+exit:
        return retval;
 }
 
@@ -498,7 +514,7 @@ static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_
        ali1535_adapter.dev.parent = &dev->dev;
 
        snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name),
-               "SMBus ALI1535 adapter at %04x", ali1535_smba);
+               "SMBus ALI1535 adapter at %04x", ali1535_offset);
        return i2c_add_adapter(&ali1535_adapter);
 }
 
index a409cfcf06291fdf568c6c2aed21e666da7b23bb..47ae0091e027dbab7b11e83b7924e7a2fc016027 100644 (file)
@@ -417,7 +417,7 @@ static void __devexit ali1563_remove(struct pci_dev * dev)
        ali1563_shutdown(dev);
 }
 
-static const struct pci_device_id ali1563_id_table[] __devinitconst = {
+static DEFINE_PCI_DEVICE_TABLE(ali1563_id_table) = {
        { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) },
        {},
 };
index 83e8a60cdc86ba8cc87d4d0463d0d3cf859c35e7..087ea9caa74d3ac34b4ced643c0b8303aba6474e 100644 (file)
@@ -477,7 +477,7 @@ static struct i2c_adapter ali15x3_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static const struct pci_device_id ali15x3_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(ali15x3_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
        { 0, }
 };
index 03bcd07c4697721b35810bf0b379465baffd23f2..eb778bf15c18539f579a6d435d4d0410fe1e4bce 100644 (file)
@@ -308,7 +308,7 @@ static const char* chipname[] = {
        "nVidia nForce", "AMD8111",
 };
 
-static const struct pci_device_id amd756_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(amd756_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B),
          .driver_data = AMD756 },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413),
index 6b6a6b1d70252539f6be0c0da874281d624d817e..e5ac53b99b0473703b8408bdde663ddd207f2b70 100644 (file)
@@ -415,7 +415,7 @@ static const struct i2c_algorithm smbus_algorithm = {
 };
 
 
-static const struct pci_device_id amd8111_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(amd8111_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) },
        { 0, }
 };
index 305c07504f7ebe055f2bfd5468e75a8e0ba31790..1679deef9c890131a951ee5cb8d50217ecb9bcf5 100644 (file)
@@ -295,9 +295,6 @@ static int at91_i2c_resume(struct platform_device *pdev)
 #define at91_i2c_resume                NULL
 #endif
 
-/* work with "modprobe at91_i2c" from hotplugging or coldplugging */
-MODULE_ALIAS("platform:at91_i2c");
-
 static struct platform_driver at91_i2c_driver = {
        .probe          = at91_i2c_probe,
        .remove         = __devexit_p(at91_i2c_remove),
@@ -309,19 +306,9 @@ static struct platform_driver at91_i2c_driver = {
        },
 };
 
-static int __init at91_i2c_init(void)
-{
-       return platform_driver_register(&at91_i2c_driver);
-}
-
-static void __exit at91_i2c_exit(void)
-{
-       platform_driver_unregister(&at91_i2c_driver);
-}
-
-module_init(at91_i2c_init);
-module_exit(at91_i2c_exit);
+module_platform_driver(at91_i2c_driver);
 
 MODULE_AUTHOR("Rick Bronson");
 MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:at91_i2c");
index f314d7f433d321f4abd236cca1723443db778aa7..582d616db34615611c4783525cbfc46bccf37351 100644 (file)
@@ -426,20 +426,9 @@ static struct platform_driver au1xpsc_smbus_driver = {
        .remove         = __devexit_p(i2c_au1550_remove),
 };
 
-static int __init i2c_au1550_init(void)
-{
-       return platform_driver_register(&au1xpsc_smbus_driver);
-}
-
-static void __exit i2c_au1550_exit(void)
-{
-       platform_driver_unregister(&au1xpsc_smbus_driver);
-}
+module_platform_driver(au1xpsc_smbus_driver);
 
 MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC.");
 MODULE_DESCRIPTION("SMBus adapter Alchemy pb1550");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:au1xpsc_smbus");
-
-module_init (i2c_au1550_init);
-module_exit (i2c_au1550_exit);
index b1d9cd28d8da9d92906a6cd5dc6b20c50ac3b48e..c1e1096ba06936a08cb60950123d67fdf59b3e96 100644 (file)
@@ -724,18 +724,7 @@ static struct platform_driver cpm_i2c_driver = {
        },
 };
 
-static int __init cpm_i2c_init(void)
-{
-       return platform_driver_register(&cpm_i2c_driver);
-}
-
-static void __exit cpm_i2c_exit(void)
-{
-       platform_driver_unregister(&cpm_i2c_driver);
-}
-
-module_init(cpm_i2c_init);
-module_exit(cpm_i2c_exit);
+module_platform_driver(cpm_i2c_driver);
 
 MODULE_AUTHOR("Jochen Friedrich <jochen@scram.de>");
 MODULE_DESCRIPTION("I2C-Bus adapter routines for CPM boards");
index 9e89e7313d620437fcd892abb808a1181709f726..37f42113af31bc54da67d953938630c513955a4d 100644 (file)
@@ -349,7 +349,7 @@ static void __devexit i2c_dw_pci_remove(struct pci_dev *pdev)
 /* work with hotplug and coldplug */
 MODULE_ALIAS("i2c_designware-pci");
 
-DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
+static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
        /* Moorestown */
        { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
        { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
index 18936ac9d51cd14af2221546fd062c3494ea18ec..ca8877641040284e4eb7964c9abe63a7e2d4a11d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD.
+ * Copyright (C) 2011 LAPIS Semiconductor Co., 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
 /*
 Set the number of I2C instance max
 Intel EG20T PCH :              1ch
-OKI SEMICONDUCTOR ML7213 IOH : 2ch
+LAPIS Semiconductor ML7213 IOH :       2ch
+LAPIS Semiconductor ML7831 IOH :       1ch
 */
 #define PCH_I2C_MAX_DEV                        2
 
@@ -180,15 +181,17 @@ static int pch_clk = 50000;       /* specifies I2C clock speed in KHz */
 static wait_queue_head_t pch_event;
 static DEFINE_MUTEX(pch_mutex);
 
-/* Definition for ML7213 by OKI SEMICONDUCTOR */
+/* Definition for ML7213 by LAPIS Semiconductor */
 #define PCI_VENDOR_ID_ROHM             0x10DB
 #define PCI_DEVICE_ID_ML7213_I2C       0x802D
 #define PCI_DEVICE_ID_ML7223_I2C       0x8010
+#define PCI_DEVICE_ID_ML7831_I2C       0x8817
 
-static struct pci_device_id __devinitdata pch_pcidev_id[] = {
+static DEFINE_PCI_DEVICE_TABLE(pch_pcidev_id) = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C),   1, },
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
+       { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_I2C), 1, },
        {0,}
 };
 
@@ -243,7 +246,7 @@ static void pch_i2c_init(struct i2c_algo_pch_data *adap)
        if (pch_clk > PCH_MAX_CLK)
                pch_clk = 62500;
 
-       pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / pch_i2c_speed * 8;
+       pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / (pch_i2c_speed * 8);
        /* Set transfer speed in I2CBC */
        iowrite32(pch_i2cbc, p + PCH_I2CBC);
 
@@ -918,7 +921,9 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev,
                pch_adap->dev.parent = &pdev->dev;
 
                pch_i2c_init(&adap_info->pch_data[i]);
-               ret = i2c_add_adapter(pch_adap);
+
+               pch_adap->nr = i;
+               ret = i2c_add_numbered_adapter(pch_adap);
                if (ret) {
                        pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i);
                        goto err_add_adapter;
@@ -1058,8 +1063,8 @@ static void __exit pch_pci_exit(void)
 }
 module_exit(pch_pci_exit);
 
-MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH I2C Driver");
+MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semico ML7213/ML7223/ML7831 IOH I2C");
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Tomoya MORINAGA. <tomoya-linux@dsn.okisemi.com>");
+MODULE_AUTHOR("Tomoya MORINAGA. <tomoya-linux@dsn.lapis-semi.com>");
 module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR));
 module_param(pch_clk, int, (S_IRUSR | S_IWUSR));
index 63bb1cc2a042125fe87e2bf9243a4bc40ffc5ab8..19515df610219a32fea7b2c162744a4474ead8bd 100644 (file)
@@ -52,7 +52,7 @@ struct highlander_i2c_dev {
        size_t                  buf_len;
 };
 
-static int iic_force_poll, iic_force_normal;
+static bool iic_force_poll, iic_force_normal;
 static int iic_timeout = 1000, iic_read_delay;
 
 static inline void highlander_i2c_irq_enable(struct highlander_i2c_dev *dev)
@@ -468,18 +468,7 @@ static struct platform_driver highlander_i2c_driver = {
        .remove         = __devexit_p(highlander_i2c_remove),
 };
 
-static int __init highlander_i2c_init(void)
-{
-       return platform_driver_register(&highlander_i2c_driver);
-}
-
-static void __exit highlander_i2c_exit(void)
-{
-       platform_driver_unregister(&highlander_i2c_driver);
-}
-
-module_init(highlander_i2c_init);
-module_exit(highlander_i2c_exit);
+module_platform_driver(highlander_i2c_driver);
 
 MODULE_AUTHOR("Paul Mundt");
 MODULE_DESCRIPTION("Renesas Highlander FPGA I2C/SMBus adapter");
index 9ff1695d845862ec77a4cf8ab1e5db7486ddc459..c527de17db4f25d8c539cefd2f3d2661b4e12fbf 100644 (file)
@@ -105,7 +105,7 @@ static struct i2c_adapter hydra_adap = {
        .algo_data      = &hydra_bit_data,
 };
 
-static const struct pci_device_id hydra_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(hydra_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) },
        { 0, }
 };
index ab26840d0c7087073dbbba598953ebfca699b7b9..5d2e2816831f21dcd73912e8d33a9407f6df0b62 100644 (file)
@@ -609,7 +609,7 @@ static const struct i2c_algorithm smbus_algorithm = {
        .functionality  = i801_func,
 };
 
-static const struct pci_device_id i801_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) },
index 3c110fbc409bb2c2ecd0cc2d7c6f9048914256cf..806e225f3de7d0ce2dfb9ff99698f9b68ba6e858 100644 (file)
 MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
-static int iic_force_poll;
+static bool iic_force_poll;
 module_param(iic_force_poll, bool, 0);
 MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
 
-static int iic_force_fast;
+static bool iic_force_fast;
 module_param(iic_force_fast, bool, 0);
 MODULE_PARM_DESC(iic_force_fast, "Force fast mode (400 kHz)");
 
@@ -815,15 +815,4 @@ static struct platform_driver ibm_iic_driver = {
        .remove = __devexit_p(iic_remove),
 };
 
-static int __init iic_init(void)
-{
-       return platform_driver_register(&ibm_iic_driver);
-}
-
-static void __exit iic_exit(void)
-{
-       platform_driver_unregister(&ibm_iic_driver);
-}
-
-module_init(iic_init);
-module_exit(iic_exit);
+module_platform_driver(ibm_iic_driver);
index e828ac85cfa7298c68e1c5d6396ce13bc051aa14..365bad5b890b7ed6001ab48de51a17505056a789 100644 (file)
@@ -1093,7 +1093,7 @@ static void __devexit intel_mid_i2c_remove(struct pci_dev *dev)
        pci_release_region(dev, 0);
 }
 
-static struct pci_device_id intel_mid_i2c_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(intel_mid_i2c_ids) = {
        /* Moorestown */
        { PCI_VDEVICE(INTEL, 0x0802), 0 },
        { PCI_VDEVICE(INTEL, 0x0803), 1 },
index f09c9319a2babdecdb743a016995c0dd6554ad5a..93f147a96b6222253f367d4c6eb161922447a85a 100644 (file)
@@ -523,21 +523,7 @@ static struct platform_driver iop3xx_i2c_driver = {
        },
 };
 
-static int __init 
-i2c_iop3xx_init (void)
-{
-       return platform_driver_register(&iop3xx_i2c_driver);
-}
-
-static void __exit 
-i2c_iop3xx_exit (void)
-{
-       platform_driver_unregister(&iop3xx_i2c_driver);
-       return;
-}
-
-module_init (i2c_iop3xx_init);
-module_exit (i2c_iop3xx_exit);
+module_platform_driver(iop3xx_i2c_driver);
 
 MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>");
 MODULE_DESCRIPTION("IOP3xx iic algorithm and driver");
index 0682f8f277b013847b5545f597f68114920f408d..6561d275b8cf20fd9ed056c1963d66fd4c318899 100644 (file)
@@ -306,20 +306,9 @@ static struct platform_driver smbus_sch_driver = {
        .remove         = __devexit_p(smbus_sch_remove),
 };
 
-static int __init i2c_sch_init(void)
-{
-       return platform_driver_register(&smbus_sch_driver);
-}
-
-static void __exit i2c_sch_exit(void)
-{
-       platform_driver_unregister(&smbus_sch_driver);
-}
+module_platform_driver(smbus_sch_driver);
 
 MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>");
 MODULE_DESCRIPTION("Intel SCH SMBus driver");
 MODULE_LICENSE("GPL");
-
-module_init(i2c_sch_init);
-module_exit(i2c_sch_exit);
 MODULE_ALIAS("platform:isch_smbus");
index c01e9519f6c15ee5df4e8cb32ae44ae234f57482..5d263f9014d647a325373ce76fe26c4e7ba75177 100644 (file)
@@ -148,18 +148,7 @@ static struct platform_driver ixp2000_i2c_driver = {
        },
 };
 
-static int __init ixp2000_i2c_init(void)
-{
-       return platform_driver_register(&ixp2000_i2c_driver);
-}
-
-static void __exit ixp2000_i2c_exit(void)
-{
-       platform_driver_unregister(&ixp2000_i2c_driver);
-}
-
-module_init(ixp2000_i2c_init);
-module_exit(ixp2000_i2c_exit);
+module_platform_driver(ixp2000_i2c_driver);
 
 MODULE_AUTHOR ("Deepak Saxena <dsaxena@plexity.net>");
 MODULE_DESCRIPTION("IXP2000 GPIO-based I2C bus driver");
index 107397a606b48957638a9569c2672ba363a5c57d..a8ebb84e23f9b179c80c2eb20c8266461b0265da 100644 (file)
@@ -715,18 +715,7 @@ static struct platform_driver mpc_i2c_driver = {
        },
 };
 
-static int __init fsl_i2c_init(void)
-{
-       return platform_driver_register(&mpc_i2c_driver);
-}
-
-static void __exit fsl_i2c_exit(void)
-{
-       platform_driver_unregister(&mpc_i2c_driver);
-}
-
-module_init(fsl_i2c_init);
-module_exit(fsl_i2c_exit);
+module_platform_driver(mpc_i2c_driver);
 
 MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
 MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and "
index a9941c65f226758d2992bb123fd0b5b2ead759dd..4f44a33017b061db314e051f9df882d4dee6a9e0 100644 (file)
@@ -611,20 +611,7 @@ static struct platform_driver mv64xxx_i2c_driver = {
        },
 };
 
-static int __init
-mv64xxx_i2c_init(void)
-{
-       return platform_driver_register(&mv64xxx_i2c_driver);
-}
-
-static void __exit
-mv64xxx_i2c_exit(void)
-{
-       platform_driver_unregister(&mv64xxx_i2c_driver);
-}
-
-module_init(mv64xxx_i2c_init);
-module_exit(mv64xxx_i2c_exit);
+module_platform_driver(mv64xxx_i2c_driver);
 
 MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
 MODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver");
index ff1e127dfea8e9b100c9fa1f6e2ebfd54c6992a6..43a96a123920c8d75773735b3070e7b4872ddd62 100644 (file)
@@ -309,7 +309,7 @@ static struct i2c_algorithm smbus_algorithm = {
 };
 
 
-static const struct pci_device_id nforce2_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },
@@ -356,7 +356,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
        error = acpi_check_region(smbus->base, smbus->size,
                                  nforce2_driver.name);
        if (error)
-               return -1;
+               return error;
 
        if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {
                dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",
index 1b46a9d9f907336fb70526ca93881ce3b3934950..18068dee48f1aa11543413894485e4916bfc5811 100644 (file)
@@ -394,9 +394,6 @@ static struct of_device_id ocores_i2c_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ocores_i2c_match);
 
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:ocores-i2c");
-
 static struct platform_driver ocores_i2c_driver = {
        .probe   = ocores_i2c_probe,
        .remove  = __devexit_p(ocores_i2c_remove),
@@ -409,19 +406,9 @@ static struct platform_driver ocores_i2c_driver = {
        },
 };
 
-static int __init ocores_i2c_init(void)
-{
-       return platform_driver_register(&ocores_i2c_driver);
-}
-
-static void __exit ocores_i2c_exit(void)
-{
-       platform_driver_unregister(&ocores_i2c_driver);
-}
-
-module_init(ocores_i2c_init);
-module_exit(ocores_i2c_exit);
+module_platform_driver(ocores_i2c_driver);
 
 MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
 MODULE_DESCRIPTION("OpenCores I2C bus driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ocores-i2c");
index 56dbe54e88118a3fb7b112da16e11ccd5bdbc9fb..ee139a598814ea46da91fc494d6d2ded770ddef4 100644 (file)
@@ -629,24 +629,10 @@ static struct platform_driver octeon_i2c_driver = {
        },
 };
 
-static int __init octeon_i2c_init(void)
-{
-       int rv;
-
-       rv = platform_driver_register(&octeon_i2c_driver);
-       return rv;
-}
-
-static void __exit octeon_i2c_exit(void)
-{
-       platform_driver_unregister(&octeon_i2c_driver);
-}
+module_platform_driver(octeon_i2c_driver);
 
 MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>");
 MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 MODULE_ALIAS("platform:" DRV_NAME);
-
-module_init(octeon_i2c_init);
-module_exit(octeon_i2c_exit);
index fa23faa20f0e34435881e24abc6d5e4c9545a259..f713eac550470cdac3139952e4229b639c05f798 100644 (file)
@@ -37,6 +37,9 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_i2c.h>
+#include <linux/of_device.h>
 #include <linux/slab.h>
 #include <linux/i2c-omap.h>
 #include <linux/pm_runtime.h>
@@ -182,7 +185,9 @@ struct omap_i2c_dev {
        u32                     latency;        /* maximum mpu wkup latency */
        void                    (*set_mpu_wkup_lat)(struct device *dev,
                                                    long latency);
-       u32                     speed;          /* Speed of bus in Khz */
+       u32                     speed;          /* Speed of bus in kHz */
+       u32                     dtrev;          /* extra revision from DT */
+       u32                     flags;
        u16                     cmd_err;
        u8                      *buf;
        u8                      *regs;
@@ -235,7 +240,7 @@ static const u8 reg_map_ip_v2[] = {
        [OMAP_I2C_BUF_REG] = 0x94,
        [OMAP_I2C_CNT_REG] = 0x98,
        [OMAP_I2C_DATA_REG] = 0x9c,
-       [OMAP_I2C_SYSC_REG] = 0x20,
+       [OMAP_I2C_SYSC_REG] = 0x10,
        [OMAP_I2C_CON_REG] = 0xa4,
        [OMAP_I2C_OA_REG] = 0xa8,
        [OMAP_I2C_SA_REG] = 0xac,
@@ -266,11 +271,7 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
 
 static void omap_i2c_unidle(struct omap_i2c_dev *dev)
 {
-       struct omap_i2c_bus_platform_data *pdata;
-
-       pdata = dev->dev->platform_data;
-
-       if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
+       if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
                omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
                omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
                omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
@@ -291,13 +292,10 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev)
 
 static void omap_i2c_idle(struct omap_i2c_dev *dev)
 {
-       struct omap_i2c_bus_platform_data *pdata;
        u16 iv;
 
-       pdata = dev->dev->platform_data;
-
        dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
-       if (pdata->rev == OMAP_I2C_IP_VERSION_2)
+       if (dev->dtrev == OMAP_I2C_IP_VERSION_2)
                omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1);
        else
                omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
@@ -320,9 +318,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
        unsigned long timeout;
        unsigned long internal_clk = 0;
        struct clk *fclk;
-       struct omap_i2c_bus_platform_data *pdata;
-
-       pdata = dev->dev->platform_data;
 
        if (dev->rev >= OMAP_I2C_OMAP1_REV_2) {
                /* Disable I2C controller before soft reset */
@@ -373,7 +368,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
        }
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
 
-       if (pdata->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) {
+       if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) {
                /*
                 * The I2C functional clock is the armxor_ck, so there's
                 * no need to get "armxor_ck" separately.  Now, if OMAP2420
@@ -397,7 +392,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                        psc = fclk_rate / 12000000;
        }
 
-       if (!(pdata->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) {
+       if (!(dev->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) {
 
                /*
                 * HSI2C controller internal clk rate should be 19.2 Mhz for
@@ -406,7 +401,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                 * The filter is iclk (fclk for HS) period.
                 */
                if (dev->speed > 400 ||
-                              pdata->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK)
+                              dev->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK)
                        internal_clk = 19200;
                else if (dev->speed > 100)
                        internal_clk = 9600;
@@ -475,7 +470,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
 
        dev->errata = 0;
 
-       if (pdata->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
+       if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
                dev->errata |= I2C_OMAP_ERRATA_I207;
 
        /* Enable interrupts */
@@ -484,7 +479,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                        OMAP_I2C_IE_AL)  | ((dev->fifo_size) ?
                                (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
        omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
-       if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
+       if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
                dev->pscstate = psc;
                dev->scllstate = scll;
                dev->sclhstate = sclh;
@@ -804,9 +799,6 @@ omap_i2c_isr(int this_irq, void *dev_id)
        u16 bits;
        u16 stat, w;
        int err, count = 0;
-       struct omap_i2c_bus_platform_data *pdata;
-
-       pdata = dev->dev->platform_data;
 
        if (pm_runtime_suspended(dev->dev))
                return IRQ_NONE;
@@ -830,11 +822,9 @@ complete:
                                ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
                                OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
 
-               if (stat & OMAP_I2C_STAT_NACK) {
+               if (stat & OMAP_I2C_STAT_NACK)
                        err |= OMAP_I2C_STAT_NACK;
-                       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
-                                          OMAP_I2C_CON_STP);
-               }
+
                if (stat & OMAP_I2C_STAT_AL) {
                        dev_err(dev->dev, "Arbitration lost\n");
                        err |= OMAP_I2C_STAT_AL;
@@ -875,7 +865,7 @@ complete:
                                         * Data reg in 2430, omap3 and
                                         * omap4 is 8 bit wide
                                         */
-                                       if (pdata->flags &
+                                       if (dev->flags &
                                                 OMAP_I2C_FLAG_16BIT_DATA_REG) {
                                                if (dev->buf_len) {
                                                        *dev->buf++ = w >> 8;
@@ -918,7 +908,7 @@ complete:
                                         * Data reg in 2430, omap3 and
                                         * omap4 is 8 bit wide
                                         */
-                                       if (pdata->flags &
+                                       if (dev->flags &
                                                 OMAP_I2C_FLAG_16BIT_DATA_REG) {
                                                if (dev->buf_len) {
                                                        w |= *dev->buf++ << 8;
@@ -965,6 +955,32 @@ static const struct i2c_algorithm omap_i2c_algo = {
        .functionality  = omap_i2c_func,
 };
 
+#ifdef CONFIG_OF
+static struct omap_i2c_bus_platform_data omap3_pdata = {
+       .rev = OMAP_I2C_IP_VERSION_1,
+       .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
+                OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
+                OMAP_I2C_FLAG_BUS_SHIFT_2,
+};
+
+static struct omap_i2c_bus_platform_data omap4_pdata = {
+       .rev = OMAP_I2C_IP_VERSION_2,
+};
+
+static const struct of_device_id omap_i2c_of_match[] = {
+       {
+               .compatible = "ti,omap4-i2c",
+               .data = &omap4_pdata,
+       },
+       {
+               .compatible = "ti,omap3-i2c",
+               .data = &omap3_pdata,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, omap_i2c_of_match);
+#endif
+
 static int __devinit
 omap_i2c_probe(struct platform_device *pdev)
 {
@@ -972,9 +988,10 @@ omap_i2c_probe(struct platform_device *pdev)
        struct i2c_adapter      *adap;
        struct resource         *mem, *irq, *ioarea;
        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;
        int r;
-       u32 speed = 0;
 
        /* NOTE: driver uses the static register mapping */
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1001,15 +1018,24 @@ omap_i2c_probe(struct platform_device *pdev)
                goto err_release_region;
        }
 
-       if (pdata != NULL) {
-               speed = pdata->clkrate;
+       match = of_match_device(omap_i2c_of_match, &pdev->dev);
+       if (match) {
+               u32 freq = 100000; /* default to 100000 Hz */
+
+               pdata = match->data;
+               dev->dtrev = pdata->rev;
+               dev->flags = pdata->flags;
+
+               of_property_read_u32(node, "clock-frequency", &freq);
+               /* convert DT freq value in Hz into kHz for speed */
+               dev->speed = freq / 1000;
+       } else if (pdata != NULL) {
+               dev->speed = pdata->clkrate;
+               dev->flags = pdata->flags;
                dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
-       } else {
-               speed = 100;    /* Default speed */
-               dev->set_mpu_wkup_lat = NULL;
+               dev->dtrev = pdata->rev;
        }
 
-       dev->speed = speed;
        dev->dev = &pdev->dev;
        dev->irq = irq->start;
        dev->base = ioremap(mem->start, resource_size(mem));
@@ -1020,9 +1046,9 @@ omap_i2c_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, dev);
 
-       dev->reg_shift = (pdata->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
+       dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
 
-       if (pdata->rev == OMAP_I2C_IP_VERSION_2)
+       if (dev->dtrev == OMAP_I2C_IP_VERSION_2)
                dev->regs = (u8 *)reg_map_ip_v2;
        else
                dev->regs = (u8 *)reg_map_ip_v1;
@@ -1035,7 +1061,7 @@ omap_i2c_probe(struct platform_device *pdev)
        if (dev->rev <= OMAP_I2C_REV_ON_3430)
                dev->errata |= I2C_OMAP3_1P153;
 
-       if (!(pdata->flags & OMAP_I2C_FLAG_NO_FIFO)) {
+       if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) {
                u16 s;
 
                /* Set up the fifo size - Get total size */
@@ -1058,7 +1084,7 @@ omap_i2c_probe(struct platform_device *pdev)
                /* calculate wakeup latency constraint for MPU */
                if (dev->set_mpu_wkup_lat != NULL)
                        dev->latency = (1000000 * dev->fifo_size) /
-                                      (1000 * speed / 8);
+                                      (1000 * dev->speed / 8);
        }
 
        /* reset ASAP, clearing any IRQs */
@@ -1074,7 +1100,7 @@ omap_i2c_probe(struct platform_device *pdev)
        }
 
        dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id,
-                pdata->rev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
+                dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
 
        pm_runtime_put(dev->dev);
 
@@ -1085,6 +1111,7 @@ omap_i2c_probe(struct platform_device *pdev)
        strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
        adap->algo = &omap_i2c_algo;
        adap->dev.parent = &pdev->dev;
+       adap->dev.of_node = pdev->dev.of_node;
 
        /* i2c device drivers may be active on return from add_adapter() */
        adap->nr = pdev->id;
@@ -1094,6 +1121,8 @@ omap_i2c_probe(struct platform_device *pdev)
                goto err_free_irq;
        }
 
+       of_i2c_register_devices(adap);
+
        return 0;
 
 err_free_irq:
@@ -1166,6 +1195,7 @@ static struct platform_driver omap_i2c_driver = {
                .name   = "omap_i2c",
                .owner  = THIS_MODULE,
                .pm     = OMAP_I2C_PM_OPS,
+               .of_match_table = of_match_ptr(omap_i2c_of_match),
        },
 };
 
index 837b8c1aa02a494ef92899c46ccaf67cb709f9c1..eaaea73209c5ca5d81a0aec5b389d0520cba850d 100644 (file)
@@ -401,7 +401,7 @@ static void __devexit pasemi_smb_remove(struct pci_dev *dev)
        kfree(smbus);
 }
 
-static const struct pci_device_id pasemi_smb_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(pasemi_smb_ids) = {
        { PCI_DEVICE(0x1959, 0xa003) },
        { 0, }
 };
index ace67995d7de85d6bd93920e0595f73b49bd9763..2adbf1a8fdea0019d8ca3acae29790ca18722552 100644 (file)
@@ -286,20 +286,8 @@ static struct platform_driver i2c_pca_pf_driver = {
        },
 };
 
-static int __init i2c_pca_pf_init(void)
-{
-       return platform_driver_register(&i2c_pca_pf_driver);
-}
-
-static void __exit i2c_pca_pf_exit(void)
-{
-       platform_driver_unregister(&i2c_pca_pf_driver);
-}
+module_platform_driver(i2c_pca_pf_driver);
 
 MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
 MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver");
 MODULE_LICENSE("GPL");
-
-module_init(i2c_pca_pf_init);
-module_exit(i2c_pca_pf_exit);
-
index 6d14ac2e3c41b80982b1c5666cbca554d7c5facb..c14d48dd601a7d524ab97c8fff076867f21bae05 100644 (file)
@@ -472,7 +472,7 @@ static struct i2c_adapter piix4_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static const struct pci_device_id piix4_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
        { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) },
index 127051b06921093f423b055f8b58cf364cc318e3..07b7447ecbc9102c7721e27727ab7d25223f35d8 100644 (file)
@@ -627,9 +627,6 @@ static struct i2c_adapter pmcmsptwi_adapter = {
        .name           = DRV_NAME,
 };
 
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:" DRV_NAME);
-
 static struct platform_driver pmcmsptwi_driver = {
        .probe  = pmcmsptwi_probe,
        .remove = __devexit_p(pmcmsptwi_remove),
@@ -639,18 +636,8 @@ static struct platform_driver pmcmsptwi_driver = {
        },
 };
 
-static int __init pmcmsptwi_init(void)
-{
-       return platform_driver_register(&pmcmsptwi_driver);
-}
-
-static void __exit pmcmsptwi_exit(void)
-{
-       platform_driver_unregister(&pmcmsptwi_driver);
-}
+module_platform_driver(pmcmsptwi_driver);
 
 MODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver");
 MODULE_LICENSE("GPL");
-
-module_init(pmcmsptwi_init);
-module_exit(pmcmsptwi_exit);
+MODULE_ALIAS("platform:" DRV_NAME);
index b289ec99eeba087cd4be7e7da762a70a5de34889..7b397c6f607e46e4d52dd87f127d0208dde13839 100644 (file)
@@ -312,10 +312,6 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
        return rc;
 }
 
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:i2c-powermac");
-
 static struct platform_driver i2c_powermac_driver = {
        .probe = i2c_powermac_probe,
        .remove = __devexit_p(i2c_powermac_remove),
@@ -325,17 +321,6 @@ static struct platform_driver i2c_powermac_driver = {
        },
 };
 
-static int __init i2c_powermac_init(void)
-{
-       platform_driver_register(&i2c_powermac_driver);
-       return 0;
-}
+module_platform_driver(i2c_powermac_driver);
 
-
-static void __exit i2c_powermac_cleanup(void)
-{
-       platform_driver_unregister(&i2c_powermac_driver);
-}
-
-module_init(i2c_powermac_init);
-module_exit(i2c_powermac_cleanup);
+MODULE_ALIAS("platform:i2c-powermac");
index 632e088760a3fc006147f375bd97d15b453fe961..a05817980556542d77a9e4463060fb8e7fc6ab5d 100644 (file)
@@ -150,7 +150,7 @@ static void __devexit ce4100_i2c_remove(struct pci_dev *dev)
        kfree(sds);
 }
 
-static struct pci_device_id ce4100_i2c_devices[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(ce4100_i2c_devices) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)},
        { },
 };
index a67132b2e0922b893c3920621524a014aabaf4c9..c0c9dffbdb12faa38fded2cfdae970dc941c91c5 100644 (file)
@@ -560,18 +560,7 @@ static struct platform_driver sh7760_i2c_drv = {
        .remove         = __devexit_p(sh7760_i2c_remove),
 };
 
-static int __init sh7760_i2c_init(void)
-{
-       return platform_driver_register(&sh7760_i2c_drv);
-}
-
-static void __exit sh7760_i2c_exit(void)
-{
-       platform_driver_unregister(&sh7760_i2c_drv);
-}
-
-module_init(sh7760_i2c_init);
-module_exit(sh7760_i2c_exit);
+module_platform_driver(sh7760_i2c_drv);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SH7760 I2C bus driver");
index 2fc08fbf67a223d6e7bfb26a0cf0d50ff40f821d..4fc87e7c94c9472b1df8b44f25e10dd605593805 100644 (file)
@@ -156,12 +156,8 @@ static int simtec_i2c_remove(struct platform_device *dev)
        return 0;
 }
 
-
 /* device driver */
 
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:simtec-i2c");
-
 static struct platform_driver simtec_i2c_driver = {
        .driver         = {
                .name           = "simtec-i2c",
@@ -171,19 +167,9 @@ static struct platform_driver simtec_i2c_driver = {
        .remove         = simtec_i2c_remove,
 };
 
-static int __init i2c_adap_simtec_init(void)
-{
-       return platform_driver_register(&simtec_i2c_driver);
-}
-
-static void __exit i2c_adap_simtec_exit(void)
-{
-       platform_driver_unregister(&simtec_i2c_driver);
-}
-
-module_init(i2c_adap_simtec_init);
-module_exit(i2c_adap_simtec_exit);
+module_platform_driver(simtec_i2c_driver);
 
 MODULE_DESCRIPTION("Simtec Generic I2C Bus driver");
 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:simtec-i2c");
index 437586611d4a18819f110698d7618f7dde9471c3..87e5126d449ce4072eb263cb04b180e5c6d597f4 100644 (file)
@@ -147,7 +147,7 @@ static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev)
        u16 a;
        u8 val;
        int *i;
-       int retval = -ENODEV;
+       int retval;
 
        /* Look for imposters */
        for (i = blacklist; *i != 0; i++) {
@@ -223,7 +223,7 @@ static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev)
 
 error:
        release_region(sis5595_base + SMB_INDEX, 2);
-       return retval;
+       return -ENODEV;
 }
 
 static int sis5595_transaction(struct i2c_adapter *adap)
@@ -369,7 +369,7 @@ static struct i2c_adapter sis5595_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static const struct pci_device_id sis5595_ids[] __devinitconst = {
+static DEFINE_PCI_DEVICE_TABLE(sis5595_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, 
        { 0, }
 };
index e6f539e26f65fb97918e132164d45b80ce4a0113..15cf78f65ce0f087236835ed877d55b8b69a4082 100644 (file)
@@ -93,8 +93,8 @@
 static struct pci_driver sis630_driver;
 
 /* insmod parameters */
-static int high_clock;
-static int force;
+static bool high_clock;
+static bool force;
 module_param(high_clock, bool, 0);
 MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz).");
 module_param(force, bool, 0);
@@ -393,7 +393,7 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev)
 {
        unsigned char b;
        struct pci_dev *dummy = NULL;
-       int retval = -ENODEV, i;
+       int retval, i;
 
        /* check for supported SiS devices */
        for (i=0; supported[i] > 0 ; i++) {
@@ -418,18 +418,21 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev)
        */
        if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) {
                dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n");
+               retval = -ENODEV;
                goto exit;
        }
        /* if ACPI already enabled , do nothing */
        if (!(b & 0x80) &&
            pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) {
                dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n");
+               retval = -ENODEV;
                goto exit;
        }
 
        /* Determine the ACPI base address */
        if (pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) {
                dev_err(&sis630_dev->dev, "Error: Can't determine ACPI base address\n");
+               retval = -ENODEV;
                goto exit;
        }
 
@@ -445,6 +448,7 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev)
                            sis630_driver.name)) {
                dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already "
                        "in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA);
+               retval = -EBUSY;
                goto exit;
        }
 
@@ -468,7 +472,7 @@ static struct i2c_adapter sis630_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static const struct pci_device_id sis630_ids[] __devinitconst = {
+static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
        { 0, }
index 86837f0c4cb92efc4e1582dc2cfa2e89f68d936a..cc5d149413f7edb236ca48f57af155aaef5fefd9 100644 (file)
@@ -245,7 +245,7 @@ static struct i2c_adapter sis96x_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static const struct pci_device_id sis96x_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(sis96x_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) },
        { 0, }
 };
index 7799fe5bda885d3513a6e7b34f5686ae979d8456..713d31ade26b7ca8f77f2fa6be99757cb6af3299 100644 (file)
@@ -89,7 +89,7 @@ static struct i2c_adapter vt586b_adapter = {
 };
 
 
-static const struct pci_device_id vt586b_ids[] __devinitconst = {
+static DEFINE_PCI_DEVICE_TABLE(vt586b_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) },
        { 0, }
 };
index 0b012f1f8ac5791ba9a4aa7926f75fbe97c57567..333011c83d5279c22eecacb2dd84879b8b687d82 100644 (file)
@@ -91,7 +91,7 @@ static unsigned short SMBHSTCFG = 0xD2;
 
 /* If force is set to anything different from 0, we forcibly enable the
    VT596. DANGEROUS! */
-static int force;
+static bool force;
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!");
 
@@ -324,7 +324,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev,
                                 const struct pci_device_id *id)
 {
        unsigned char temp;
-       int error = -ENODEV;
+       int error;
 
        /* Determine the address of the SMBus areas */
        if (force_addr) {
@@ -390,6 +390,7 @@ found:
                        dev_err(&pdev->dev, "SMBUS: Error: Host SMBus "
                                "controller not enabled! - upgrade BIOS or "
                                "use force=1\n");
+                       error = -ENODEV;
                        goto release_region;
                }
        }
@@ -422,9 +423,11 @@ found:
                 "SMBus Via Pro adapter at %04x", vt596_smba);
 
        vt596_pdev = pci_dev_get(pdev);
-       if (i2c_add_adapter(&vt596_adapter)) {
+       error = i2c_add_adapter(&vt596_adapter);
+       if (error) {
                pci_dev_put(vt596_pdev);
                vt596_pdev = NULL;
+               goto release_region;
        }
 
        /* Always return failure here.  This is to allow other drivers to bind
@@ -438,7 +441,7 @@ release_region:
        return error;
 }
 
-static const struct pci_device_id vt596_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(vt596_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3),
          .driver_data = SMBBA1 },
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3),
index ac083a28ae08e97f815632836638a7637d8732c1..2bded7647ef25b1a98f2211d1723de10568e3e7f 100644 (file)
@@ -795,10 +795,6 @@ static int __devexit xiic_i2c_remove(struct platform_device* pdev)
        return 0;
 }
 
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:"DRIVER_NAME);
-
 static struct platform_driver xiic_i2c_driver = {
        .probe   = xiic_i2c_probe,
        .remove  = __devexit_p(xiic_i2c_remove),
@@ -808,19 +804,9 @@ static struct platform_driver xiic_i2c_driver = {
        },
 };
 
-static int __init xiic_i2c_init(void)
-{
-       return platform_driver_register(&xiic_i2c_driver);
-}
-
-static void __exit xiic_i2c_exit(void)
-{
-       platform_driver_unregister(&xiic_i2c_driver);
-}
-
-module_init(xiic_i2c_init);
-module_exit(xiic_i2c_exit);
+module_platform_driver(xiic_i2c_driver);
 
 MODULE_AUTHOR("info@mocean-labs.com");
 MODULE_DESCRIPTION("Xilinx I2C bus driver");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:"DRIVER_NAME);
index 91e349c884c5c9ec73fc42b6fecd4964afc7ff12..2eacb7784d565edfeac64533ef48937c068220da 100644 (file)
@@ -559,7 +559,7 @@ static struct platform_driver scx200_pci_driver = {
        .remove = __devexit_p(scx200_remove),
 };
 
-static const struct pci_device_id scx200_isa[] __initconst = {
+static DEFINE_PCI_DEVICE_TABLE(scx200_isa) = {
        { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
        { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
        { 0, }
index 57a45ce84b2d42f893cf45fb6e876bc1904bcfde..10e7f1e7658610b8e2b697cf6e355a999aa4f5b6 100644 (file)
@@ -251,15 +251,10 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
        if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
                return -EINVAL;
 
-       rdwr_pa = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL);
-       if (!rdwr_pa)
-               return -ENOMEM;
-
-       if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
-                          rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
-               kfree(rdwr_pa);
-               return -EFAULT;
-       }
+       rdwr_pa = memdup_user(rdwr_arg.msgs,
+                             rdwr_arg.nmsgs * sizeof(struct i2c_msg));
+       if (IS_ERR(rdwr_pa))
+               return PTR_ERR(rdwr_pa);
 
        data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
        if (data_ptrs == NULL) {
index 7b6ce624cd6e7e403b2cb7708b8581423298ef42..e5fa695eb0fa64673e1c26e82536b52a3a3388e8 100644 (file)
@@ -165,18 +165,7 @@ static struct platform_driver gpiomux_driver = {
        },
 };
 
-static int __init gpiomux_init(void)
-{
-       return platform_driver_register(&gpiomux_driver);
-}
-
-static void __exit gpiomux_exit(void)
-{
-       platform_driver_unregister(&gpiomux_driver);
-}
-
-module_init(gpiomux_init);
-module_exit(gpiomux_exit);
+module_platform_driver(gpiomux_driver);
 
 MODULE_DESCRIPTION("GPIO-based I2C multiplexer driver");
 MODULE_AUTHOR("Peter Korsgaard <peter.korsgaard@barco.com>");
index 25b9fe3a9f8ef02047f689645755b347223a94a5..d3be99fb4154fdc1f55198d46b3d1f6611c1dd12 100644 (file)
@@ -221,7 +221,7 @@ static int __init ali14xx_probe(void)
        return ide_legacy_device_add(&ali14xx_port_info, 0);
 }
 
-static int probe_ali14xx;
+static bool probe_ali14xx;
 
 module_param_named(probe, probe_ali14xx, bool, 0);
 MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
index a81bd7575792f996763186339b7e3e40c835ce18..14717304b3888fc5ce45eb2771629dc39368bd64 100644 (file)
 
 #define DRV_NAME "cmd640"
 
-static int cmd640_vlb;
+static bool cmd640_vlb;
 
 /*
  * CMD640 specific registers definition.
index 6929f7fce93a735114333709e8cd020f319c01d3..46af4743b3e68db2a7d099d2cec82ae3e95eb411 100644 (file)
@@ -130,7 +130,7 @@ static int __init dtc2278_probe(void)
        return ide_legacy_device_add(&dtc2278_port_info, 0);
 }
 
-static int probe_dtc2278;
+static bool probe_dtc2278;
 
 module_param_named(probe, probe_dtc2278, bool, 0);
 MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets");
index 3feaa26410be9b26eb30d4d52768324d3cff0294..51beb85250d4400a06e90eca0b4f539825cc7438 100644 (file)
@@ -50,7 +50,7 @@
                                               GAYLE_NUM_HWIFS-1)
 #define GAYLE_HAS_CONTROL_REG  (!ide_doubler)
 
-static int ide_doubler;
+static bool ide_doubler;
 module_param_named(doubler, ide_doubler, bool, 0);
 MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
 
index 808bcdcbf8e1bab0e6e45354d7d684c75e6917cd..986f2513eab435e06e2597977624fd9d8a2550ce 100644 (file)
@@ -317,7 +317,7 @@ static void __init ht6560b_init_dev(ide_drive_t *drive)
        ide_set_drivedata(drive, (void *)t);
 }
 
-static int probe_ht6560b;
+static bool probe_ht6560b;
 
 module_param_named(probe, probe_ht6560b, bool, 0);
 MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
index 979d342c338ae71b39b03edd7986a7ea37732f97..547d7cf2e0167e760da5a31add56eec953980699 100644 (file)
@@ -6,7 +6,7 @@
 
 #define DRV_NAME "ide-4drives"
 
-static int probe_4drives;
+static bool probe_4drives;
 
 module_param_named(probe, probe_4drives, bool, 0);
 MODULE_PARM_DESC(probe, "probe for generic IDE chipset with 4 drives/port");
index f22edc66b030b4a58c09caa3952353394686ecce..f1a6796b165c154bffd18d9c6f99e407aac24d96 100644 (file)
@@ -53,15 +53,15 @@ struct ide_acpi_hwif_link {
 #define DEBPRINT(fmt, args...) do {} while (0)
 #endif /* DEBUGGING */
 
-static int ide_noacpi;
+static bool ide_noacpi;
 module_param_named(noacpi, ide_noacpi, bool, 0);
 MODULE_PARM_DESC(noacpi, "disable IDE ACPI support");
 
-static int ide_acpigtf;
+static bool ide_acpigtf;
 module_param_named(acpigtf, ide_acpigtf, bool, 0);
 MODULE_PARM_DESC(acpigtf, "enable IDE ACPI _GTF support");
 
-static int ide_acpionboot;
+static bool ide_acpionboot;
 module_param_named(acpionboot, ide_acpionboot, bool, 0);
 MODULE_PARM_DESC(acpionboot, "call IDE ACPI methods on boot");
 
index d267b7affad63fab887a10585e647cec6eb98020..a22ca846701080d3721ef32fc72dc9b3038b02fd 100644 (file)
@@ -292,8 +292,7 @@ int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev,
         * and CDROM_SEND_PACKET (legacy) ioctls
         */
        if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
-               err = scsi_cmd_ioctl(bdev->bd_disk->queue, bdev->bd_disk,
-                               mode, cmd, argp);
+               err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
 
        if (err == -ENOTTY)
                err = generic_ide_ioctl(drive, bdev, cmd, arg);
index a743e68a8903cc62185d0fc861e888242e630cf7..7f56b738d7621f8a37377afc2f93e7236f387996 100644 (file)
@@ -28,7 +28,7 @@
 
 #define DRV_NAME "ide_pci_generic"
 
-static int ide_generic_all;            /* Set to claim all devices */
+static bool ide_generic_all;           /* Set to claim all devices */
 
 module_param_named(all_generic_ide, ide_generic_all, bool, 0444);
 MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers.");
index 3f0244fd8e623010433c5086c1656bf812a62fbb..8bbfe5557c7bbd178cea496ef8abe65ee9f5041e 100644 (file)
@@ -417,7 +417,7 @@ static int __init qd_probe(int base)
        return rc;
 }
 
-static int probe_qd65xx;
+static bool probe_qd65xx;
 
 module_param_named(probe, probe_qd65xx, bool, 0);
 MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
index 47adcd09cb26a3c6f867374ec31b9aa6dfb039e1..5cfb7812066961281a37710dca2f033c80b4d733 100644 (file)
@@ -160,7 +160,7 @@ static int __init umc8672_probe(void)
        return ide_legacy_device_add(&umc8672_port_info, 0);
 }
 
-static int probe_umc8672;
+static bool probe_umc8672;
 
 module_param_named(probe, probe_umc8672, bool, 0);
 MODULE_PARM_DESC(probe, "probe for UMC8672 chipset");
index 5d2f8e13cf0e670e83b48b6dc243402d781b9758..20bce51c2e82f18f96346a1e19aa24b5fada35fd 100644 (file)
@@ -197,7 +197,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .enter = &intel_idle },
 };
 
-static int get_driver_data(int cstate)
+static long get_driver_data(int cstate)
 {
        int driver_data;
        switch (cstate) {
@@ -232,6 +232,7 @@ static int get_driver_data(int cstate)
  * @drv: cpuidle driver
  * @index: index of cpuidle state
  *
+ * Must be called under local_irq_disable().
  */
 static int intel_idle(struct cpuidle_device *dev,
                struct cpuidle_driver *drv, int index)
@@ -247,8 +248,6 @@ static int intel_idle(struct cpuidle_device *dev,
 
        cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1;
 
-       local_irq_disable();
-
        /*
         * leave_mm() to avoid costly and often unnecessary wakeups
         * for flushing the user TLB's associated with the active mm.
@@ -348,7 +347,8 @@ static int intel_idle_probe(void)
        cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &mwait_substates);
 
        if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
-               !(ecx & CPUID5_ECX_INTERRUPT_BREAK))
+           !(ecx & CPUID5_ECX_INTERRUPT_BREAK) ||
+           !mwait_substates)
                        return -ENODEV;
 
        pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates);
@@ -394,7 +394,7 @@ static int intel_idle_probe(void)
        if (boot_cpu_has(X86_FEATURE_ARAT))     /* Always Reliable APIC Timer */
                lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
        else {
-               smp_call_function(__setup_broadcast_timer, (void *)true, 1);
+               on_each_cpu(__setup_broadcast_timer, (void *)true, 1);
                register_cpu_notifier(&setup_broadcast_notifier);
        }
 
@@ -471,71 +471,67 @@ static int intel_idle_cpuidle_driver_init(void)
        }
 
        if (auto_demotion_disable_flags)
-               smp_call_function(auto_demotion_disable, NULL, 1);
+               on_each_cpu(auto_demotion_disable, NULL, 1);
 
        return 0;
 }
 
 
 /*
- * intel_idle_cpuidle_devices_init()
+ * intel_idle_cpu_init()
  * allocate, initialize, register cpuidle_devices
+ * @cpu: cpu/core to initialize
  */
-static int intel_idle_cpuidle_devices_init(void)
+int intel_idle_cpu_init(int cpu)
 {
-       int i, cstate;
+       int cstate;
        struct cpuidle_device *dev;
 
-       intel_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device);
-       if (intel_idle_cpuidle_devices == NULL)
-               return -ENOMEM;
-
-       for_each_online_cpu(i) {
-               dev = per_cpu_ptr(intel_idle_cpuidle_devices, i);
+       dev = per_cpu_ptr(intel_idle_cpuidle_devices, cpu);
 
-               dev->state_count = 1;
+       dev->state_count = 1;
 
-               for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) {
-                       int num_substates;
+       for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) {
+               int num_substates;
 
-                       if (cstate > max_cstate) {
-                               printk(PREFIX "max_cstate %d reached\n",
-                                       max_cstate);
-                               break;
-                       }
+               if (cstate > max_cstate) {
+                       printk(PREFIX "max_cstate %d reached\n",
+                              max_cstate);
+                       break;
+               }
 
-                       /* does the state exist in CPUID.MWAIT? */
-                       num_substates = (mwait_substates >> ((cstate) * 4))
-                                               & MWAIT_SUBSTATE_MASK;
-                       if (num_substates == 0)
-                               continue;
-                       /* is the state not enabled? */
-                       if (cpuidle_state_table[cstate].enter == NULL) {
-                               continue;
-                       }
+               /* does the state exist in CPUID.MWAIT? */
+               num_substates = (mwait_substates >> ((cstate) * 4))
+                       & MWAIT_SUBSTATE_MASK;
+               if (num_substates == 0)
+                       continue;
+               /* is the state not enabled? */
+               if (cpuidle_state_table[cstate].enter == NULL)
+                       continue;
 
-                       dev->states_usage[dev->state_count].driver_data =
-                               (void *)get_driver_data(cstate);
+               dev->states_usage[dev->state_count].driver_data =
+                       (void *)get_driver_data(cstate);
 
                        dev->state_count += 1;
                }
+       dev->cpu = cpu;
 
-               dev->cpu = i;
-               if (cpuidle_register_device(dev)) {
-                       pr_debug(PREFIX "cpuidle_register_device %d failed!\n",
-                                i);
-                       intel_idle_cpuidle_devices_uninit();
-                       return -EIO;
-               }
+       if (cpuidle_register_device(dev)) {
+               pr_debug(PREFIX "cpuidle_register_device %d failed!\n", cpu);
+               intel_idle_cpuidle_devices_uninit();
+               return -EIO;
        }
 
+       if (auto_demotion_disable_flags)
+               smp_call_function_single(cpu, auto_demotion_disable, NULL, 1);
+
        return 0;
 }
 
 
 static int __init intel_idle_init(void)
 {
-       int retval;
+       int retval, i;
 
        /* Do not load intel_idle at all for now if idle= is passed */
        if (boot_option_idle_override != IDLE_NO_OVERRIDE)
@@ -553,10 +549,16 @@ static int __init intel_idle_init(void)
                return retval;
        }
 
-       retval = intel_idle_cpuidle_devices_init();
-       if (retval) {
-               cpuidle_unregister_driver(&intel_idle_driver);
-               return retval;
+       intel_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device);
+       if (intel_idle_cpuidle_devices == NULL)
+               return -ENOMEM;
+
+       for_each_online_cpu(i) {
+               retval = intel_idle_cpu_init(i);
+               if (retval) {
+                       cpuidle_unregister_driver(&intel_idle_driver);
+                       return retval;
+               }
        }
 
        return 0;
@@ -568,7 +570,7 @@ static void __exit intel_idle_exit(void)
        cpuidle_unregister_driver(&intel_idle_driver);
 
        if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) {
-               smp_call_function(__setup_broadcast_timer, (void *)false, 1);
+               on_each_cpu(__setup_broadcast_timer, (void *)false, 1);
                unregister_cpu_notifier(&setup_broadcast_notifier);
        }
 
index 0f9a84c1046ab38776abe891ef0ff98ea0c19c98..eb0add311dc8be40ff8876f8b1bcd7d3f2e0b161 100644 (file)
@@ -55,6 +55,7 @@ source "drivers/infiniband/hw/nes/Kconfig"
 source "drivers/infiniband/ulp/ipoib/Kconfig"
 
 source "drivers/infiniband/ulp/srp/Kconfig"
+source "drivers/infiniband/ulp/srpt/Kconfig"
 
 source "drivers/infiniband/ulp/iser/Kconfig"
 
index 9cc7a47d3e6737f22379384ac60366ea183d65dc..a3b2d8eac86ef0089a41dff9686c4dd752b0ca4a 100644 (file)
@@ -10,4 +10,5 @@ obj-$(CONFIG_MLX4_INFINIBAND)         += hw/mlx4/
 obj-$(CONFIG_INFINIBAND_NES)           += hw/nes/
 obj-$(CONFIG_INFINIBAND_IPOIB)         += ulp/ipoib/
 obj-$(CONFIG_INFINIBAND_SRP)           += ulp/srp/
+obj-$(CONFIG_INFINIBAND_SRPT)          += ulp/srpt/
 obj-$(CONFIG_INFINIBAND_ISER)          += ulp/iser/
index aaf6023a4835e79551226a6262678dc83b28d7bb..f08f6eaf3fa8822340c8d01693d4fbe5c3dfdd75 100644 (file)
@@ -379,8 +379,8 @@ extern spinlock_t shca_list_lock;
 
 extern int ehca_static_rate;
 extern int ehca_port_act_time;
-extern int ehca_use_hp_mr;
-extern int ehca_scaling_code;
+extern bool ehca_use_hp_mr;
+extern bool ehca_scaling_code;
 extern int ehca_lock_hcalls;
 extern int ehca_nr_ports;
 extern int ehca_max_cq;
index c240e9972cb0e52c2f2789f48e1e4c9ab6cbb29d..832e7a7d0aeeaaf1d4b213120532de26d6465065 100644 (file)
@@ -59,16 +59,16 @@ MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
 MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
 MODULE_VERSION(HCAD_VERSION);
 
-static int ehca_open_aqp1     = 0;
+static bool ehca_open_aqp1    = 0;
 static int ehca_hw_level      = 0;
-static int ehca_poll_all_eqs  = 1;
+static bool ehca_poll_all_eqs = 1;
 
 int ehca_debug_level   = 0;
 int ehca_nr_ports      = -1;
-int ehca_use_hp_mr     = 0;
+bool ehca_use_hp_mr    = 0;
 int ehca_port_act_time = 30;
 int ehca_static_rate   = -1;
-int ehca_scaling_code  = 0;
+bool ehca_scaling_code = 0;
 int ehca_lock_hcalls   = -1;
 int ehca_max_cq        = -1;
 int ehca_max_qp        = -1;
@@ -82,7 +82,7 @@ module_param_named(port_act_time, ehca_port_act_time, int,  S_IRUGO);
 module_param_named(poll_all_eqs,  ehca_poll_all_eqs,  bool, S_IRUGO);
 module_param_named(static_rate,   ehca_static_rate,   int,  S_IRUGO);
 module_param_named(scaling_code,  ehca_scaling_code,  bool, S_IRUGO);
-module_param_named(lock_hcalls,   ehca_lock_hcalls,   bool, S_IRUGO);
+module_param_named(lock_hcalls,   ehca_lock_hcalls,   bint, S_IRUGO);
 module_param_named(number_of_cqs, ehca_max_cq,        int,  S_IRUGO);
 module_param_named(number_of_qps, ehca_max_qp,        int,  S_IRUGO);
 
index 5965b3df8f2f6ee0c10dbbc9b7f8218823161ccc..7013da5e9eda8e9df0b8511568b4b2dd18ea177b 100644 (file)
@@ -96,7 +96,7 @@ unsigned int wqm_quanta = 0x10000;
 module_param(wqm_quanta, int, 0644);
 MODULE_PARM_DESC(wqm_quanta, "WQM quanta");
 
-static unsigned int limit_maxrdreqsz;
+static bool limit_maxrdreqsz;
 module_param(limit_maxrdreqsz, bool, 0644);
 MODULE_PARM_DESC(limit_maxrdreqsz, "Limit max read request size to 256 Bytes");
 
diff --git a/drivers/infiniband/ulp/srpt/Kconfig b/drivers/infiniband/ulp/srpt/Kconfig
new file mode 100644 (file)
index 0000000..31ee83d
--- /dev/null
@@ -0,0 +1,12 @@
+config INFINIBAND_SRPT
+       tristate "InfiniBand SCSI RDMA Protocol target support"
+       depends on INFINIBAND && TARGET_CORE
+       ---help---
+
+         Support for the SCSI RDMA Protocol (SRP) Target driver. The
+         SRP protocol is a protocol that allows an initiator to access
+         a block storage device on another host (target) over a network
+         that supports the RDMA protocol. Currently the RDMA protocol is
+         supported by InfiniBand and by iWarp network hardware. More
+         information about the SRP protocol can be found on the website
+         of the INCITS T10 technical committee (http://www.t10.org/).
diff --git a/drivers/infiniband/ulp/srpt/Makefile b/drivers/infiniband/ulp/srpt/Makefile
new file mode 100644 (file)
index 0000000..e3ee4bd
--- /dev/null
@@ -0,0 +1,2 @@
+ccflags-y                      := -Idrivers/target
+obj-$(CONFIG_INFINIBAND_SRPT)  += ib_srpt.o
diff --git a/drivers/infiniband/ulp/srpt/ib_dm_mad.h b/drivers/infiniband/ulp/srpt/ib_dm_mad.h
new file mode 100644 (file)
index 0000000..fb1de1f
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2006 - 2009 Mellanox Technology Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef IB_DM_MAD_H
+#define IB_DM_MAD_H
+
+#include <linux/types.h>
+
+#include <rdma/ib_mad.h>
+
+enum {
+       /*
+        * See also section 13.4.7 Status Field, table 115 MAD Common Status
+        * Field Bit Values and also section 16.3.1.1 Status Field in the
+        * InfiniBand Architecture Specification.
+        */
+       DM_MAD_STATUS_UNSUP_METHOD = 0x0008,
+       DM_MAD_STATUS_UNSUP_METHOD_ATTR = 0x000c,
+       DM_MAD_STATUS_INVALID_FIELD = 0x001c,
+       DM_MAD_STATUS_NO_IOC = 0x0100,
+
+       /*
+        * See also the Device Management chapter, section 16.3.3 Attributes,
+        * table 279 Device Management Attributes in the InfiniBand
+        * Architecture Specification.
+        */
+       DM_ATTR_CLASS_PORT_INFO = 0x01,
+       DM_ATTR_IOU_INFO = 0x10,
+       DM_ATTR_IOC_PROFILE = 0x11,
+       DM_ATTR_SVC_ENTRIES = 0x12
+};
+
+struct ib_dm_hdr {
+       u8 reserved[28];
+};
+
+/*
+ * Structure of management datagram sent by the SRP target implementation.
+ * Contains a management datagram header, reliable multi-packet transaction
+ * protocol (RMPP) header and ib_dm_hdr. Notes:
+ * - The SRP target implementation does not use RMPP or ib_dm_hdr when sending
+ *   management datagrams.
+ * - The header size must be exactly 64 bytes (IB_MGMT_DEVICE_HDR), since this
+ *   is the header size that is passed to ib_create_send_mad() in ib_srpt.c.
+ * - The maximum supported size for a management datagram when not using RMPP
+ *   is 256 bytes -- 64 bytes header and 192 (IB_MGMT_DEVICE_DATA) bytes data.
+ */
+struct ib_dm_mad {
+       struct ib_mad_hdr mad_hdr;
+       struct ib_rmpp_hdr rmpp_hdr;
+       struct ib_dm_hdr dm_hdr;
+       u8 data[IB_MGMT_DEVICE_DATA];
+};
+
+/*
+ * IOUnitInfo as defined in section 16.3.3.3 IOUnitInfo of the InfiniBand
+ * Architecture Specification.
+ */
+struct ib_dm_iou_info {
+       __be16 change_id;
+       u8 max_controllers;
+       u8 op_rom;
+       u8 controller_list[128];
+};
+
+/*
+ * IOControllerprofile as defined in section 16.3.3.4 IOControllerProfile of
+ * the InfiniBand Architecture Specification.
+ */
+struct ib_dm_ioc_profile {
+       __be64 guid;
+       __be32 vendor_id;
+       __be32 device_id;
+       __be16 device_version;
+       __be16 reserved1;
+       __be32 subsys_vendor_id;
+       __be32 subsys_device_id;
+       __be16 io_class;
+       __be16 io_subclass;
+       __be16 protocol;
+       __be16 protocol_version;
+       __be16 service_conn;
+       __be16 initiators_supported;
+       __be16 send_queue_depth;
+       u8 reserved2;
+       u8 rdma_read_depth;
+       __be32 send_size;
+       __be32 rdma_size;
+       u8 op_cap_mask;
+       u8 svc_cap_mask;
+       u8 num_svc_entries;
+       u8 reserved3[9];
+       u8 id_string[64];
+};
+
+struct ib_dm_svc_entry {
+       u8 name[40];
+       __be64 id;
+};
+
+/*
+ * See also section 16.3.3.5 ServiceEntries in the InfiniBand Architecture
+ * Specification. See also section B.7, table B.8 in the T10 SRP r16a document.
+ */
+struct ib_dm_svc_entries {
+       struct ib_dm_svc_entry service_entries[4];
+};
+
+#endif
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
new file mode 100644 (file)
index 0000000..cd5d05e
--- /dev/null
@@ -0,0 +1,4073 @@
+/*
+ * Copyright (c) 2006 - 2009 Mellanox Technology Inc.  All rights reserved.
+ * Copyright (C) 2008 - 2011 Bart Van Assche <bvanassche@acm.org>.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/kthread.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/atomic.h>
+#include <scsi/scsi_tcq.h>
+#include <target/configfs_macros.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_configfs.h>
+#include "ib_srpt.h"
+
+/* Name of this kernel module. */
+#define DRV_NAME               "ib_srpt"
+#define DRV_VERSION            "2.0.0"
+#define DRV_RELDATE            "2011-02-14"
+
+#define SRPT_ID_STRING "Linux SRP target"
+
+#undef pr_fmt
+#define pr_fmt(fmt) DRV_NAME " " fmt
+
+MODULE_AUTHOR("Vu Pham and Bart Van Assche");
+MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol target "
+                  "v" DRV_VERSION " (" DRV_RELDATE ")");
+MODULE_LICENSE("Dual BSD/GPL");
+
+/*
+ * Global Variables
+ */
+
+static u64 srpt_service_guid;
+static spinlock_t srpt_dev_lock;       /* Protects srpt_dev_list. */
+static struct list_head srpt_dev_list; /* List of srpt_device structures. */
+
+static unsigned srp_max_req_size = DEFAULT_MAX_REQ_SIZE;
+module_param(srp_max_req_size, int, 0444);
+MODULE_PARM_DESC(srp_max_req_size,
+                "Maximum size of SRP request messages in bytes.");
+
+static int srpt_srq_size = DEFAULT_SRPT_SRQ_SIZE;
+module_param(srpt_srq_size, int, 0444);
+MODULE_PARM_DESC(srpt_srq_size,
+                "Shared receive queue (SRQ) size.");
+
+static int srpt_get_u64_x(char *buffer, struct kernel_param *kp)
+{
+       return sprintf(buffer, "0x%016llx", *(u64 *)kp->arg);
+}
+module_param_call(srpt_service_guid, NULL, srpt_get_u64_x, &srpt_service_guid,
+                 0444);
+MODULE_PARM_DESC(srpt_service_guid,
+                "Using this value for ioc_guid, id_ext, and cm_listen_id"
+                " instead of using the node_guid of the first HCA.");
+
+static struct ib_client srpt_client;
+static struct target_fabric_configfs *srpt_target;
+static void srpt_release_channel(struct srpt_rdma_ch *ch);
+static int srpt_queue_status(struct se_cmd *cmd);
+
+/**
+ * opposite_dma_dir() - Swap DMA_TO_DEVICE and DMA_FROM_DEVICE.
+ */
+static inline
+enum dma_data_direction opposite_dma_dir(enum dma_data_direction dir)
+{
+       switch (dir) {
+       case DMA_TO_DEVICE:     return DMA_FROM_DEVICE;
+       case DMA_FROM_DEVICE:   return DMA_TO_DEVICE;
+       default:                return dir;
+       }
+}
+
+/**
+ * srpt_sdev_name() - Return the name associated with the HCA.
+ *
+ * Examples are ib0, ib1, ...
+ */
+static inline const char *srpt_sdev_name(struct srpt_device *sdev)
+{
+       return sdev->device->name;
+}
+
+static enum rdma_ch_state srpt_get_ch_state(struct srpt_rdma_ch *ch)
+{
+       unsigned long flags;
+       enum rdma_ch_state state;
+
+       spin_lock_irqsave(&ch->spinlock, flags);
+       state = ch->state;
+       spin_unlock_irqrestore(&ch->spinlock, flags);
+       return state;
+}
+
+static enum rdma_ch_state
+srpt_set_ch_state(struct srpt_rdma_ch *ch, enum rdma_ch_state new_state)
+{
+       unsigned long flags;
+       enum rdma_ch_state prev;
+
+       spin_lock_irqsave(&ch->spinlock, flags);
+       prev = ch->state;
+       ch->state = new_state;
+       spin_unlock_irqrestore(&ch->spinlock, flags);
+       return prev;
+}
+
+/**
+ * srpt_test_and_set_ch_state() - Test and set the channel state.
+ *
+ * Returns true if and only if the channel state has been set to the new state.
+ */
+static bool
+srpt_test_and_set_ch_state(struct srpt_rdma_ch *ch, enum rdma_ch_state old,
+                          enum rdma_ch_state new)
+{
+       unsigned long flags;
+       enum rdma_ch_state prev;
+
+       spin_lock_irqsave(&ch->spinlock, flags);
+       prev = ch->state;
+       if (prev == old)
+               ch->state = new;
+       spin_unlock_irqrestore(&ch->spinlock, flags);
+       return prev == old;
+}
+
+/**
+ * srpt_event_handler() - Asynchronous IB event callback function.
+ *
+ * Callback function called by the InfiniBand core when an asynchronous IB
+ * event occurs. This callback may occur in interrupt context. See also
+ * section 11.5.2, Set Asynchronous Event Handler in the InfiniBand
+ * Architecture Specification.
+ */
+static void srpt_event_handler(struct ib_event_handler *handler,
+                              struct ib_event *event)
+{
+       struct srpt_device *sdev;
+       struct srpt_port *sport;
+
+       sdev = ib_get_client_data(event->device, &srpt_client);
+       if (!sdev || sdev->device != event->device)
+               return;
+
+       pr_debug("ASYNC event= %d on device= %s\n", event->event,
+                srpt_sdev_name(sdev));
+
+       switch (event->event) {
+       case IB_EVENT_PORT_ERR:
+               if (event->element.port_num <= sdev->device->phys_port_cnt) {
+                       sport = &sdev->port[event->element.port_num - 1];
+                       sport->lid = 0;
+                       sport->sm_lid = 0;
+               }
+               break;
+       case IB_EVENT_PORT_ACTIVE:
+       case IB_EVENT_LID_CHANGE:
+       case IB_EVENT_PKEY_CHANGE:
+       case IB_EVENT_SM_CHANGE:
+       case IB_EVENT_CLIENT_REREGISTER:
+               /* Refresh port data asynchronously. */
+               if (event->element.port_num <= sdev->device->phys_port_cnt) {
+                       sport = &sdev->port[event->element.port_num - 1];
+                       if (!sport->lid && !sport->sm_lid)
+                               schedule_work(&sport->work);
+               }
+               break;
+       default:
+               printk(KERN_ERR "received unrecognized IB event %d\n",
+                      event->event);
+               break;
+       }
+}
+
+/**
+ * srpt_srq_event() - SRQ event callback function.
+ */
+static void srpt_srq_event(struct ib_event *event, void *ctx)
+{
+       printk(KERN_INFO "SRQ event %d\n", event->event);
+}
+
+/**
+ * srpt_qp_event() - QP event callback function.
+ */
+static void srpt_qp_event(struct ib_event *event, struct srpt_rdma_ch *ch)
+{
+       pr_debug("QP event %d on cm_id=%p sess_name=%s state=%d\n",
+                event->event, ch->cm_id, ch->sess_name, srpt_get_ch_state(ch));
+
+       switch (event->event) {
+       case IB_EVENT_COMM_EST:
+               ib_cm_notify(ch->cm_id, event->event);
+               break;
+       case IB_EVENT_QP_LAST_WQE_REACHED:
+               if (srpt_test_and_set_ch_state(ch, CH_DRAINING,
+                                              CH_RELEASING))
+                       srpt_release_channel(ch);
+               else
+                       pr_debug("%s: state %d - ignored LAST_WQE.\n",
+                                ch->sess_name, srpt_get_ch_state(ch));
+               break;
+       default:
+               printk(KERN_ERR "received unrecognized IB QP event %d\n",
+                      event->event);
+               break;
+       }
+}
+
+/**
+ * srpt_set_ioc() - Helper function for initializing an IOUnitInfo structure.
+ *
+ * @slot: one-based slot number.
+ * @value: four-bit value.
+ *
+ * Copies the lowest four bits of value in element slot of the array of four
+ * bit elements called c_list (controller list). The index slot is one-based.
+ */
+static void srpt_set_ioc(u8 *c_list, u32 slot, u8 value)
+{
+       u16 id;
+       u8 tmp;
+
+       id = (slot - 1) / 2;
+       if (slot & 0x1) {
+               tmp = c_list[id] & 0xf;
+               c_list[id] = (value << 4) | tmp;
+       } else {
+               tmp = c_list[id] & 0xf0;
+               c_list[id] = (value & 0xf) | tmp;
+       }
+}
+
+/**
+ * srpt_get_class_port_info() - Copy ClassPortInfo to a management datagram.
+ *
+ * See also section 16.3.3.1 ClassPortInfo in the InfiniBand Architecture
+ * Specification.
+ */
+static void srpt_get_class_port_info(struct ib_dm_mad *mad)
+{
+       struct ib_class_port_info *cif;
+
+       cif = (struct ib_class_port_info *)mad->data;
+       memset(cif, 0, sizeof *cif);
+       cif->base_version = 1;
+       cif->class_version = 1;
+       cif->resp_time_value = 20;
+
+       mad->mad_hdr.status = 0;
+}
+
+/**
+ * srpt_get_iou() - Write IOUnitInfo to a management datagram.
+ *
+ * See also section 16.3.3.3 IOUnitInfo in the InfiniBand Architecture
+ * Specification. See also section B.7, table B.6 in the SRP r16a document.
+ */
+static void srpt_get_iou(struct ib_dm_mad *mad)
+{
+       struct ib_dm_iou_info *ioui;
+       u8 slot;
+       int i;
+
+       ioui = (struct ib_dm_iou_info *)mad->data;
+       ioui->change_id = __constant_cpu_to_be16(1);
+       ioui->max_controllers = 16;
+
+       /* set present for slot 1 and empty for the rest */
+       srpt_set_ioc(ioui->controller_list, 1, 1);
+       for (i = 1, slot = 2; i < 16; i++, slot++)
+               srpt_set_ioc(ioui->controller_list, slot, 0);
+
+       mad->mad_hdr.status = 0;
+}
+
+/**
+ * srpt_get_ioc() - Write IOControllerprofile to a management datagram.
+ *
+ * See also section 16.3.3.4 IOControllerProfile in the InfiniBand
+ * Architecture Specification. See also section B.7, table B.7 in the SRP
+ * r16a document.
+ */
+static void srpt_get_ioc(struct srpt_port *sport, u32 slot,
+                        struct ib_dm_mad *mad)
+{
+       struct srpt_device *sdev = sport->sdev;
+       struct ib_dm_ioc_profile *iocp;
+
+       iocp = (struct ib_dm_ioc_profile *)mad->data;
+
+       if (!slot || slot > 16) {
+               mad->mad_hdr.status
+                       = __constant_cpu_to_be16(DM_MAD_STATUS_INVALID_FIELD);
+               return;
+       }
+
+       if (slot > 2) {
+               mad->mad_hdr.status
+                       = __constant_cpu_to_be16(DM_MAD_STATUS_NO_IOC);
+               return;
+       }
+
+       memset(iocp, 0, sizeof *iocp);
+       strcpy(iocp->id_string, SRPT_ID_STRING);
+       iocp->guid = cpu_to_be64(srpt_service_guid);
+       iocp->vendor_id = cpu_to_be32(sdev->dev_attr.vendor_id);
+       iocp->device_id = cpu_to_be32(sdev->dev_attr.vendor_part_id);
+       iocp->device_version = cpu_to_be16(sdev->dev_attr.hw_ver);
+       iocp->subsys_vendor_id = cpu_to_be32(sdev->dev_attr.vendor_id);
+       iocp->subsys_device_id = 0x0;
+       iocp->io_class = __constant_cpu_to_be16(SRP_REV16A_IB_IO_CLASS);
+       iocp->io_subclass = __constant_cpu_to_be16(SRP_IO_SUBCLASS);
+       iocp->protocol = __constant_cpu_to_be16(SRP_PROTOCOL);
+       iocp->protocol_version = __constant_cpu_to_be16(SRP_PROTOCOL_VERSION);
+       iocp->send_queue_depth = cpu_to_be16(sdev->srq_size);
+       iocp->rdma_read_depth = 4;
+       iocp->send_size = cpu_to_be32(srp_max_req_size);
+       iocp->rdma_size = cpu_to_be32(min(sport->port_attrib.srp_max_rdma_size,
+                                         1U << 24));
+       iocp->num_svc_entries = 1;
+       iocp->op_cap_mask = SRP_SEND_TO_IOC | SRP_SEND_FROM_IOC |
+               SRP_RDMA_READ_FROM_IOC | SRP_RDMA_WRITE_FROM_IOC;
+
+       mad->mad_hdr.status = 0;
+}
+
+/**
+ * srpt_get_svc_entries() - Write ServiceEntries to a management datagram.
+ *
+ * See also section 16.3.3.5 ServiceEntries in the InfiniBand Architecture
+ * Specification. See also section B.7, table B.8 in the SRP r16a document.
+ */
+static void srpt_get_svc_entries(u64 ioc_guid,
+                                u16 slot, u8 hi, u8 lo, struct ib_dm_mad *mad)
+{
+       struct ib_dm_svc_entries *svc_entries;
+
+       WARN_ON(!ioc_guid);
+
+       if (!slot || slot > 16) {
+               mad->mad_hdr.status
+                       = __constant_cpu_to_be16(DM_MAD_STATUS_INVALID_FIELD);
+               return;
+       }
+
+       if (slot > 2 || lo > hi || hi > 1) {
+               mad->mad_hdr.status
+                       = __constant_cpu_to_be16(DM_MAD_STATUS_NO_IOC);
+               return;
+       }
+
+       svc_entries = (struct ib_dm_svc_entries *)mad->data;
+       memset(svc_entries, 0, sizeof *svc_entries);
+       svc_entries->service_entries[0].id = cpu_to_be64(ioc_guid);
+       snprintf(svc_entries->service_entries[0].name,
+                sizeof(svc_entries->service_entries[0].name),
+                "%s%016llx",
+                SRP_SERVICE_NAME_PREFIX,
+                ioc_guid);
+
+       mad->mad_hdr.status = 0;
+}
+
+/**
+ * srpt_mgmt_method_get() - Process a received management datagram.
+ * @sp:      source port through which the MAD has been received.
+ * @rq_mad:  received MAD.
+ * @rsp_mad: response MAD.
+ */
+static void srpt_mgmt_method_get(struct srpt_port *sp, struct ib_mad *rq_mad,
+                                struct ib_dm_mad *rsp_mad)
+{
+       u16 attr_id;
+       u32 slot;
+       u8 hi, lo;
+
+       attr_id = be16_to_cpu(rq_mad->mad_hdr.attr_id);
+       switch (attr_id) {
+       case DM_ATTR_CLASS_PORT_INFO:
+               srpt_get_class_port_info(rsp_mad);
+               break;
+       case DM_ATTR_IOU_INFO:
+               srpt_get_iou(rsp_mad);
+               break;
+       case DM_ATTR_IOC_PROFILE:
+               slot = be32_to_cpu(rq_mad->mad_hdr.attr_mod);
+               srpt_get_ioc(sp, slot, rsp_mad);
+               break;
+       case DM_ATTR_SVC_ENTRIES:
+               slot = be32_to_cpu(rq_mad->mad_hdr.attr_mod);
+               hi = (u8) ((slot >> 8) & 0xff);
+               lo = (u8) (slot & 0xff);
+               slot = (u16) ((slot >> 16) & 0xffff);
+               srpt_get_svc_entries(srpt_service_guid,
+                                    slot, hi, lo, rsp_mad);
+               break;
+       default:
+               rsp_mad->mad_hdr.status =
+                   __constant_cpu_to_be16(DM_MAD_STATUS_UNSUP_METHOD_ATTR);
+               break;
+       }
+}
+
+/**
+ * srpt_mad_send_handler() - Post MAD-send callback function.
+ */
+static void srpt_mad_send_handler(struct ib_mad_agent *mad_agent,
+                                 struct ib_mad_send_wc *mad_wc)
+{
+       ib_destroy_ah(mad_wc->send_buf->ah);
+       ib_free_send_mad(mad_wc->send_buf);
+}
+
+/**
+ * srpt_mad_recv_handler() - MAD reception callback function.
+ */
+static void srpt_mad_recv_handler(struct ib_mad_agent *mad_agent,
+                                 struct ib_mad_recv_wc *mad_wc)
+{
+       struct srpt_port *sport = (struct srpt_port *)mad_agent->context;
+       struct ib_ah *ah;
+       struct ib_mad_send_buf *rsp;
+       struct ib_dm_mad *dm_mad;
+
+       if (!mad_wc || !mad_wc->recv_buf.mad)
+               return;
+
+       ah = ib_create_ah_from_wc(mad_agent->qp->pd, mad_wc->wc,
+                                 mad_wc->recv_buf.grh, mad_agent->port_num);
+       if (IS_ERR(ah))
+               goto err;
+
+       BUILD_BUG_ON(offsetof(struct ib_dm_mad, data) != IB_MGMT_DEVICE_HDR);
+
+       rsp = ib_create_send_mad(mad_agent, mad_wc->wc->src_qp,
+                                mad_wc->wc->pkey_index, 0,
+                                IB_MGMT_DEVICE_HDR, IB_MGMT_DEVICE_DATA,
+                                GFP_KERNEL);
+       if (IS_ERR(rsp))
+               goto err_rsp;
+
+       rsp->ah = ah;
+
+       dm_mad = rsp->mad;
+       memcpy(dm_mad, mad_wc->recv_buf.mad, sizeof *dm_mad);
+       dm_mad->mad_hdr.method = IB_MGMT_METHOD_GET_RESP;
+       dm_mad->mad_hdr.status = 0;
+
+       switch (mad_wc->recv_buf.mad->mad_hdr.method) {
+       case IB_MGMT_METHOD_GET:
+               srpt_mgmt_method_get(sport, mad_wc->recv_buf.mad, dm_mad);
+               break;
+       case IB_MGMT_METHOD_SET:
+               dm_mad->mad_hdr.status =
+                   __constant_cpu_to_be16(DM_MAD_STATUS_UNSUP_METHOD_ATTR);
+               break;
+       default:
+               dm_mad->mad_hdr.status =
+                   __constant_cpu_to_be16(DM_MAD_STATUS_UNSUP_METHOD);
+               break;
+       }
+
+       if (!ib_post_send_mad(rsp, NULL)) {
+               ib_free_recv_mad(mad_wc);
+               /* will destroy_ah & free_send_mad in send completion */
+               return;
+       }
+
+       ib_free_send_mad(rsp);
+
+err_rsp:
+       ib_destroy_ah(ah);
+err:
+       ib_free_recv_mad(mad_wc);
+}
+
+/**
+ * srpt_refresh_port() - Configure a HCA port.
+ *
+ * Enable InfiniBand management datagram processing, update the cached sm_lid,
+ * lid and gid values, and register a callback function for processing MADs
+ * on the specified port.
+ *
+ * Note: It is safe to call this function more than once for the same port.
+ */
+static int srpt_refresh_port(struct srpt_port *sport)
+{
+       struct ib_mad_reg_req reg_req;
+       struct ib_port_modify port_modify;
+       struct ib_port_attr port_attr;
+       int ret;
+
+       memset(&port_modify, 0, sizeof port_modify);
+       port_modify.set_port_cap_mask = IB_PORT_DEVICE_MGMT_SUP;
+       port_modify.clr_port_cap_mask = 0;
+
+       ret = ib_modify_port(sport->sdev->device, sport->port, 0, &port_modify);
+       if (ret)
+               goto err_mod_port;
+
+       ret = ib_query_port(sport->sdev->device, sport->port, &port_attr);
+       if (ret)
+               goto err_query_port;
+
+       sport->sm_lid = port_attr.sm_lid;
+       sport->lid = port_attr.lid;
+
+       ret = ib_query_gid(sport->sdev->device, sport->port, 0, &sport->gid);
+       if (ret)
+               goto err_query_port;
+
+       if (!sport->mad_agent) {
+               memset(&reg_req, 0, sizeof reg_req);
+               reg_req.mgmt_class = IB_MGMT_CLASS_DEVICE_MGMT;
+               reg_req.mgmt_class_version = IB_MGMT_BASE_VERSION;
+               set_bit(IB_MGMT_METHOD_GET, reg_req.method_mask);
+               set_bit(IB_MGMT_METHOD_SET, reg_req.method_mask);
+
+               sport->mad_agent = ib_register_mad_agent(sport->sdev->device,
+                                                        sport->port,
+                                                        IB_QPT_GSI,
+                                                        &reg_req, 0,
+                                                        srpt_mad_send_handler,
+                                                        srpt_mad_recv_handler,
+                                                        sport);
+               if (IS_ERR(sport->mad_agent)) {
+                       ret = PTR_ERR(sport->mad_agent);
+                       sport->mad_agent = NULL;
+                       goto err_query_port;
+               }
+       }
+
+       return 0;
+
+err_query_port:
+
+       port_modify.set_port_cap_mask = 0;
+       port_modify.clr_port_cap_mask = IB_PORT_DEVICE_MGMT_SUP;
+       ib_modify_port(sport->sdev->device, sport->port, 0, &port_modify);
+
+err_mod_port:
+
+       return ret;
+}
+
+/**
+ * srpt_unregister_mad_agent() - Unregister MAD callback functions.
+ *
+ * Note: It is safe to call this function more than once for the same device.
+ */
+static void srpt_unregister_mad_agent(struct srpt_device *sdev)
+{
+       struct ib_port_modify port_modify = {
+               .clr_port_cap_mask = IB_PORT_DEVICE_MGMT_SUP,
+       };
+       struct srpt_port *sport;
+       int i;
+
+       for (i = 1; i <= sdev->device->phys_port_cnt; i++) {
+               sport = &sdev->port[i - 1];
+               WARN_ON(sport->port != i);
+               if (ib_modify_port(sdev->device, i, 0, &port_modify) < 0)
+                       printk(KERN_ERR "disabling MAD processing failed.\n");
+               if (sport->mad_agent) {
+                       ib_unregister_mad_agent(sport->mad_agent);
+                       sport->mad_agent = NULL;
+               }
+       }
+}
+
+/**
+ * srpt_alloc_ioctx() - Allocate an SRPT I/O context structure.
+ */
+static struct srpt_ioctx *srpt_alloc_ioctx(struct srpt_device *sdev,
+                                          int ioctx_size, int dma_size,
+                                          enum dma_data_direction dir)
+{
+       struct srpt_ioctx *ioctx;
+
+       ioctx = kmalloc(ioctx_size, GFP_KERNEL);
+       if (!ioctx)
+               goto err;
+
+       ioctx->buf = kmalloc(dma_size, GFP_KERNEL);
+       if (!ioctx->buf)
+               goto err_free_ioctx;
+
+       ioctx->dma = ib_dma_map_single(sdev->device, ioctx->buf, dma_size, dir);
+       if (ib_dma_mapping_error(sdev->device, ioctx->dma))
+               goto err_free_buf;
+
+       return ioctx;
+
+err_free_buf:
+       kfree(ioctx->buf);
+err_free_ioctx:
+       kfree(ioctx);
+err:
+       return NULL;
+}
+
+/**
+ * srpt_free_ioctx() - Free an SRPT I/O context structure.
+ */
+static void srpt_free_ioctx(struct srpt_device *sdev, struct srpt_ioctx *ioctx,
+                           int dma_size, enum dma_data_direction dir)
+{
+       if (!ioctx)
+               return;
+
+       ib_dma_unmap_single(sdev->device, ioctx->dma, dma_size, dir);
+       kfree(ioctx->buf);
+       kfree(ioctx);
+}
+
+/**
+ * srpt_alloc_ioctx_ring() - Allocate a ring of SRPT I/O context structures.
+ * @sdev:       Device to allocate the I/O context ring for.
+ * @ring_size:  Number of elements in the I/O context ring.
+ * @ioctx_size: I/O context size.
+ * @dma_size:   DMA buffer size.
+ * @dir:        DMA data direction.
+ */
+static struct srpt_ioctx **srpt_alloc_ioctx_ring(struct srpt_device *sdev,
+                               int ring_size, int ioctx_size,
+                               int dma_size, enum dma_data_direction dir)
+{
+       struct srpt_ioctx **ring;
+       int i;
+
+       WARN_ON(ioctx_size != sizeof(struct srpt_recv_ioctx)
+               && ioctx_size != sizeof(struct srpt_send_ioctx));
+
+       ring = kmalloc(ring_size * sizeof(ring[0]), GFP_KERNEL);
+       if (!ring)
+               goto out;
+       for (i = 0; i < ring_size; ++i) {
+               ring[i] = srpt_alloc_ioctx(sdev, ioctx_size, dma_size, dir);
+               if (!ring[i])
+                       goto err;
+               ring[i]->index = i;
+       }
+       goto out;
+
+err:
+       while (--i >= 0)
+               srpt_free_ioctx(sdev, ring[i], dma_size, dir);
+       kfree(ring);
+out:
+       return ring;
+}
+
+/**
+ * srpt_free_ioctx_ring() - Free the ring of SRPT I/O context structures.
+ */
+static void srpt_free_ioctx_ring(struct srpt_ioctx **ioctx_ring,
+                                struct srpt_device *sdev, int ring_size,
+                                int dma_size, enum dma_data_direction dir)
+{
+       int i;
+
+       for (i = 0; i < ring_size; ++i)
+               srpt_free_ioctx(sdev, ioctx_ring[i], dma_size, dir);
+       kfree(ioctx_ring);
+}
+
+/**
+ * srpt_get_cmd_state() - Get the state of a SCSI command.
+ */
+static enum srpt_command_state srpt_get_cmd_state(struct srpt_send_ioctx *ioctx)
+{
+       enum srpt_command_state state;
+       unsigned long flags;
+
+       BUG_ON(!ioctx);
+
+       spin_lock_irqsave(&ioctx->spinlock, flags);
+       state = ioctx->state;
+       spin_unlock_irqrestore(&ioctx->spinlock, flags);
+       return state;
+}
+
+/**
+ * srpt_set_cmd_state() - Set the state of a SCSI command.
+ *
+ * Does not modify the state of aborted commands. Returns the previous command
+ * state.
+ */
+static enum srpt_command_state srpt_set_cmd_state(struct srpt_send_ioctx *ioctx,
+                                                 enum srpt_command_state new)
+{
+       enum srpt_command_state previous;
+       unsigned long flags;
+
+       BUG_ON(!ioctx);
+
+       spin_lock_irqsave(&ioctx->spinlock, flags);
+       previous = ioctx->state;
+       if (previous != SRPT_STATE_DONE)
+               ioctx->state = new;
+       spin_unlock_irqrestore(&ioctx->spinlock, flags);
+
+       return previous;
+}
+
+/**
+ * srpt_test_and_set_cmd_state() - Test and set the state of a command.
+ *
+ * Returns true if and only if the previous command state was equal to 'old'.
+ */
+static bool srpt_test_and_set_cmd_state(struct srpt_send_ioctx *ioctx,
+                                       enum srpt_command_state old,
+                                       enum srpt_command_state new)
+{
+       enum srpt_command_state previous;
+       unsigned long flags;
+
+       WARN_ON(!ioctx);
+       WARN_ON(old == SRPT_STATE_DONE);
+       WARN_ON(new == SRPT_STATE_NEW);
+
+       spin_lock_irqsave(&ioctx->spinlock, flags);
+       previous = ioctx->state;
+       if (previous == old)
+               ioctx->state = new;
+       spin_unlock_irqrestore(&ioctx->spinlock, flags);
+       return previous == old;
+}
+
+/**
+ * srpt_post_recv() - Post an IB receive request.
+ */
+static int srpt_post_recv(struct srpt_device *sdev,
+                         struct srpt_recv_ioctx *ioctx)
+{
+       struct ib_sge list;
+       struct ib_recv_wr wr, *bad_wr;
+
+       BUG_ON(!sdev);
+       wr.wr_id = encode_wr_id(SRPT_RECV, ioctx->ioctx.index);
+
+       list.addr = ioctx->ioctx.dma;
+       list.length = srp_max_req_size;
+       list.lkey = sdev->mr->lkey;
+
+       wr.next = NULL;
+       wr.sg_list = &list;
+       wr.num_sge = 1;
+
+       return ib_post_srq_recv(sdev->srq, &wr, &bad_wr);
+}
+
+/**
+ * srpt_post_send() - Post an IB send request.
+ *
+ * Returns zero upon success and a non-zero value upon failure.
+ */
+static int srpt_post_send(struct srpt_rdma_ch *ch,
+                         struct srpt_send_ioctx *ioctx, int len)
+{
+       struct ib_sge list;
+       struct ib_send_wr wr, *bad_wr;
+       struct srpt_device *sdev = ch->sport->sdev;
+       int ret;
+
+       atomic_inc(&ch->req_lim);
+
+       ret = -ENOMEM;
+       if (unlikely(atomic_dec_return(&ch->sq_wr_avail) < 0)) {
+               printk(KERN_WARNING "IB send queue full (needed 1)\n");
+               goto out;
+       }
+
+       ib_dma_sync_single_for_device(sdev->device, ioctx->ioctx.dma, len,
+                                     DMA_TO_DEVICE);
+
+       list.addr = ioctx->ioctx.dma;
+       list.length = len;
+       list.lkey = sdev->mr->lkey;
+
+       wr.next = NULL;
+       wr.wr_id = encode_wr_id(SRPT_SEND, ioctx->ioctx.index);
+       wr.sg_list = &list;
+       wr.num_sge = 1;
+       wr.opcode = IB_WR_SEND;
+       wr.send_flags = IB_SEND_SIGNALED;
+
+       ret = ib_post_send(ch->qp, &wr, &bad_wr);
+
+out:
+       if (ret < 0) {
+               atomic_inc(&ch->sq_wr_avail);
+               atomic_dec(&ch->req_lim);
+       }
+       return ret;
+}
+
+/**
+ * srpt_get_desc_tbl() - Parse the data descriptors of an SRP_CMD request.
+ * @ioctx: Pointer to the I/O context associated with the request.
+ * @srp_cmd: Pointer to the SRP_CMD request data.
+ * @dir: Pointer to the variable to which the transfer direction will be
+ *   written.
+ * @data_len: Pointer to the variable to which the total data length of all
+ *   descriptors in the SRP_CMD request will be written.
+ *
+ * This function initializes ioctx->nrbuf and ioctx->r_bufs.
+ *
+ * Returns -EINVAL when the SRP_CMD request contains inconsistent descriptors;
+ * -ENOMEM when memory allocation fails and zero upon success.
+ */
+static int srpt_get_desc_tbl(struct srpt_send_ioctx *ioctx,
+                            struct srp_cmd *srp_cmd,
+                            enum dma_data_direction *dir, u64 *data_len)
+{
+       struct srp_indirect_buf *idb;
+       struct srp_direct_buf *db;
+       unsigned add_cdb_offset;
+       int ret;
+
+       /*
+        * The pointer computations below will only be compiled correctly
+        * if srp_cmd::add_data is declared as s8*, u8*, s8[] or u8[], so check
+        * whether srp_cmd::add_data has been declared as a byte pointer.
+        */
+       BUILD_BUG_ON(!__same_type(srp_cmd->add_data[0], (s8)0)
+                    && !__same_type(srp_cmd->add_data[0], (u8)0));
+
+       BUG_ON(!dir);
+       BUG_ON(!data_len);
+
+       ret = 0;
+       *data_len = 0;
+
+       /*
+        * The lower four bits of the buffer format field contain the DATA-IN
+        * buffer descriptor format, and the highest four bits contain the
+        * DATA-OUT buffer descriptor format.
+        */
+       *dir = DMA_NONE;
+       if (srp_cmd->buf_fmt & 0xf)
+               /* DATA-IN: transfer data from target to initiator (read). */
+               *dir = DMA_FROM_DEVICE;
+       else if (srp_cmd->buf_fmt >> 4)
+               /* DATA-OUT: transfer data from initiator to target (write). */
+               *dir = DMA_TO_DEVICE;
+
+       /*
+        * According to the SRP spec, the lower two bits of the 'ADDITIONAL
+        * CDB LENGTH' field are reserved and the size in bytes of this field
+        * is four times the value specified in bits 3..7. Hence the "& ~3".
+        */
+       add_cdb_offset = srp_cmd->add_cdb_len & ~3;
+       if (((srp_cmd->buf_fmt & 0xf) == SRP_DATA_DESC_DIRECT) ||
+           ((srp_cmd->buf_fmt >> 4) == SRP_DATA_DESC_DIRECT)) {
+               ioctx->n_rbuf = 1;
+               ioctx->rbufs = &ioctx->single_rbuf;
+
+               db = (struct srp_direct_buf *)(srp_cmd->add_data
+                                              + add_cdb_offset);
+               memcpy(ioctx->rbufs, db, sizeof *db);
+               *data_len = be32_to_cpu(db->len);
+       } else if (((srp_cmd->buf_fmt & 0xf) == SRP_DATA_DESC_INDIRECT) ||
+                  ((srp_cmd->buf_fmt >> 4) == SRP_DATA_DESC_INDIRECT)) {
+               idb = (struct srp_indirect_buf *)(srp_cmd->add_data
+                                                 + add_cdb_offset);
+
+               ioctx->n_rbuf = be32_to_cpu(idb->table_desc.len) / sizeof *db;
+
+               if (ioctx->n_rbuf >
+                   (srp_cmd->data_out_desc_cnt + srp_cmd->data_in_desc_cnt)) {
+                       printk(KERN_ERR "received unsupported SRP_CMD request"
+                              " type (%u out + %u in != %u / %zu)\n",
+                              srp_cmd->data_out_desc_cnt,
+                              srp_cmd->data_in_desc_cnt,
+                              be32_to_cpu(idb->table_desc.len),
+                              sizeof(*db));
+                       ioctx->n_rbuf = 0;
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               if (ioctx->n_rbuf == 1)
+                       ioctx->rbufs = &ioctx->single_rbuf;
+               else {
+                       ioctx->rbufs =
+                               kmalloc(ioctx->n_rbuf * sizeof *db, GFP_ATOMIC);
+                       if (!ioctx->rbufs) {
+                               ioctx->n_rbuf = 0;
+                               ret = -ENOMEM;
+                               goto out;
+                       }
+               }
+
+               db = idb->desc_list;
+               memcpy(ioctx->rbufs, db, ioctx->n_rbuf * sizeof *db);
+               *data_len = be32_to_cpu(idb->len);
+       }
+out:
+       return ret;
+}
+
+/**
+ * srpt_init_ch_qp() - Initialize queue pair attributes.
+ *
+ * Initialized the attributes of queue pair 'qp' by allowing local write,
+ * remote read and remote write. Also transitions 'qp' to state IB_QPS_INIT.
+ */
+static int srpt_init_ch_qp(struct srpt_rdma_ch *ch, struct ib_qp *qp)
+{
+       struct ib_qp_attr *attr;
+       int ret;
+
+       attr = kzalloc(sizeof *attr, GFP_KERNEL);
+       if (!attr)
+               return -ENOMEM;
+
+       attr->qp_state = IB_QPS_INIT;
+       attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ |
+           IB_ACCESS_REMOTE_WRITE;
+       attr->port_num = ch->sport->port;
+       attr->pkey_index = 0;
+
+       ret = ib_modify_qp(qp, attr,
+                          IB_QP_STATE | IB_QP_ACCESS_FLAGS | IB_QP_PORT |
+                          IB_QP_PKEY_INDEX);
+
+       kfree(attr);
+       return ret;
+}
+
+/**
+ * srpt_ch_qp_rtr() - Change the state of a channel to 'ready to receive' (RTR).
+ * @ch: channel of the queue pair.
+ * @qp: queue pair to change the state of.
+ *
+ * Returns zero upon success and a negative value upon failure.
+ *
+ * Note: currently a struct ib_qp_attr takes 136 bytes on a 64-bit system.
+ * If this structure ever becomes larger, it might be necessary to allocate
+ * it dynamically instead of on the stack.
+ */
+static int srpt_ch_qp_rtr(struct srpt_rdma_ch *ch, struct ib_qp *qp)
+{
+       struct ib_qp_attr qp_attr;
+       int attr_mask;
+       int ret;
+
+       qp_attr.qp_state = IB_QPS_RTR;
+       ret = ib_cm_init_qp_attr(ch->cm_id, &qp_attr, &attr_mask);
+       if (ret)
+               goto out;
+
+       qp_attr.max_dest_rd_atomic = 4;
+
+       ret = ib_modify_qp(qp, &qp_attr, attr_mask);
+
+out:
+       return ret;
+}
+
+/**
+ * srpt_ch_qp_rts() - Change the state of a channel to 'ready to send' (RTS).
+ * @ch: channel of the queue pair.
+ * @qp: queue pair to change the state of.
+ *
+ * Returns zero upon success and a negative value upon failure.
+ *
+ * Note: currently a struct ib_qp_attr takes 136 bytes on a 64-bit system.
+ * If this structure ever becomes larger, it might be necessary to allocate
+ * it dynamically instead of on the stack.
+ */
+static int srpt_ch_qp_rts(struct srpt_rdma_ch *ch, struct ib_qp *qp)
+{
+       struct ib_qp_attr qp_attr;
+       int attr_mask;
+       int ret;
+
+       qp_attr.qp_state = IB_QPS_RTS;
+       ret = ib_cm_init_qp_attr(ch->cm_id, &qp_attr, &attr_mask);
+       if (ret)
+               goto out;
+
+       qp_attr.max_rd_atomic = 4;
+
+       ret = ib_modify_qp(qp, &qp_attr, attr_mask);
+
+out:
+       return ret;
+}
+
+/**
+ * srpt_ch_qp_err() - Set the channel queue pair state to 'error'.
+ */
+static int srpt_ch_qp_err(struct srpt_rdma_ch *ch)
+{
+       struct ib_qp_attr qp_attr;
+
+       qp_attr.qp_state = IB_QPS_ERR;
+       return ib_modify_qp(ch->qp, &qp_attr, IB_QP_STATE);
+}
+
+/**
+ * srpt_unmap_sg_to_ib_sge() - Unmap an IB SGE list.
+ */
+static void srpt_unmap_sg_to_ib_sge(struct srpt_rdma_ch *ch,
+                                   struct srpt_send_ioctx *ioctx)
+{
+       struct scatterlist *sg;
+       enum dma_data_direction dir;
+
+       BUG_ON(!ch);
+       BUG_ON(!ioctx);
+       BUG_ON(ioctx->n_rdma && !ioctx->rdma_ius);
+
+       while (ioctx->n_rdma)
+               kfree(ioctx->rdma_ius[--ioctx->n_rdma].sge);
+
+       kfree(ioctx->rdma_ius);
+       ioctx->rdma_ius = NULL;
+
+       if (ioctx->mapped_sg_count) {
+               sg = ioctx->sg;
+               WARN_ON(!sg);
+               dir = ioctx->cmd.data_direction;
+               BUG_ON(dir == DMA_NONE);
+               ib_dma_unmap_sg(ch->sport->sdev->device, sg, ioctx->sg_cnt,
+                               opposite_dma_dir(dir));
+               ioctx->mapped_sg_count = 0;
+       }
+}
+
+/**
+ * srpt_map_sg_to_ib_sge() - Map an SG list to an IB SGE list.
+ */
+static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
+                                struct srpt_send_ioctx *ioctx)
+{
+       struct se_cmd *cmd;
+       struct scatterlist *sg, *sg_orig;
+       int sg_cnt;
+       enum dma_data_direction dir;
+       struct rdma_iu *riu;
+       struct srp_direct_buf *db;
+       dma_addr_t dma_addr;
+       struct ib_sge *sge;
+       u64 raddr;
+       u32 rsize;
+       u32 tsize;
+       u32 dma_len;
+       int count, nrdma;
+       int i, j, k;
+
+       BUG_ON(!ch);
+       BUG_ON(!ioctx);
+       cmd = &ioctx->cmd;
+       dir = cmd->data_direction;
+       BUG_ON(dir == DMA_NONE);
+
+       transport_do_task_sg_chain(cmd);
+       ioctx->sg = sg = sg_orig = cmd->t_tasks_sg_chained;
+       ioctx->sg_cnt = sg_cnt = cmd->t_tasks_sg_chained_no;
+
+       count = ib_dma_map_sg(ch->sport->sdev->device, sg, sg_cnt,
+                             opposite_dma_dir(dir));
+       if (unlikely(!count))
+               return -EAGAIN;
+
+       ioctx->mapped_sg_count = count;
+
+       if (ioctx->rdma_ius && ioctx->n_rdma_ius)
+               nrdma = ioctx->n_rdma_ius;
+       else {
+               nrdma = (count + SRPT_DEF_SG_PER_WQE - 1) / SRPT_DEF_SG_PER_WQE
+                       + ioctx->n_rbuf;
+
+               ioctx->rdma_ius = kzalloc(nrdma * sizeof *riu, GFP_KERNEL);
+               if (!ioctx->rdma_ius)
+                       goto free_mem;
+
+               ioctx->n_rdma_ius = nrdma;
+       }
+
+       db = ioctx->rbufs;
+       tsize = cmd->data_length;
+       dma_len = sg_dma_len(&sg[0]);
+       riu = ioctx->rdma_ius;
+
+       /*
+        * For each remote desc - calculate the #ib_sge.
+        * If #ib_sge < SRPT_DEF_SG_PER_WQE per rdma operation then
+        *      each remote desc rdma_iu is required a rdma wr;
+        * else
+        *      we need to allocate extra rdma_iu to carry extra #ib_sge in
+        *      another rdma wr
+        */
+       for (i = 0, j = 0;
+            j < count && i < ioctx->n_rbuf && tsize > 0; ++i, ++riu, ++db) {
+               rsize = be32_to_cpu(db->len);
+               raddr = be64_to_cpu(db->va);
+               riu->raddr = raddr;
+               riu->rkey = be32_to_cpu(db->key);
+               riu->sge_cnt = 0;
+
+               /* calculate how many sge required for this remote_buf */
+               while (rsize > 0 && tsize > 0) {
+
+                       if (rsize >= dma_len) {
+                               tsize -= dma_len;
+                               rsize -= dma_len;
+                               raddr += dma_len;
+
+                               if (tsize > 0) {
+                                       ++j;
+                                       if (j < count) {
+                                               sg = sg_next(sg);
+                                               dma_len = sg_dma_len(sg);
+                                       }
+                               }
+                       } else {
+                               tsize -= rsize;
+                               dma_len -= rsize;
+                               rsize = 0;
+                       }
+
+                       ++riu->sge_cnt;
+
+                       if (rsize > 0 && riu->sge_cnt == SRPT_DEF_SG_PER_WQE) {
+                               ++ioctx->n_rdma;
+                               riu->sge =
+                                   kmalloc(riu->sge_cnt * sizeof *riu->sge,
+                                           GFP_KERNEL);
+                               if (!riu->sge)
+                                       goto free_mem;
+
+                               ++riu;
+                               riu->sge_cnt = 0;
+                               riu->raddr = raddr;
+                               riu->rkey = be32_to_cpu(db->key);
+                       }
+               }
+
+               ++ioctx->n_rdma;
+               riu->sge = kmalloc(riu->sge_cnt * sizeof *riu->sge,
+                                  GFP_KERNEL);
+               if (!riu->sge)
+                       goto free_mem;
+       }
+
+       db = ioctx->rbufs;
+       tsize = cmd->data_length;
+       riu = ioctx->rdma_ius;
+       sg = sg_orig;
+       dma_len = sg_dma_len(&sg[0]);
+       dma_addr = sg_dma_address(&sg[0]);
+
+       /* this second loop is really mapped sg_addres to rdma_iu->ib_sge */
+       for (i = 0, j = 0;
+            j < count && i < ioctx->n_rbuf && tsize > 0; ++i, ++riu, ++db) {
+               rsize = be32_to_cpu(db->len);
+               sge = riu->sge;
+               k = 0;
+
+               while (rsize > 0 && tsize > 0) {
+                       sge->addr = dma_addr;
+                       sge->lkey = ch->sport->sdev->mr->lkey;
+
+                       if (rsize >= dma_len) {
+                               sge->length =
+                                       (tsize < dma_len) ? tsize : dma_len;
+                               tsize -= dma_len;
+                               rsize -= dma_len;
+
+                               if (tsize > 0) {
+                                       ++j;
+                                       if (j < count) {
+                                               sg = sg_next(sg);
+                                               dma_len = sg_dma_len(sg);
+                                               dma_addr = sg_dma_address(sg);
+                                       }
+                               }
+                       } else {
+                               sge->length = (tsize < rsize) ? tsize : rsize;
+                               tsize -= rsize;
+                               dma_len -= rsize;
+                               dma_addr += rsize;
+                               rsize = 0;
+                       }
+
+                       ++k;
+                       if (k == riu->sge_cnt && rsize > 0 && tsize > 0) {
+                               ++riu;
+                               sge = riu->sge;
+                               k = 0;
+                       } else if (rsize > 0 && tsize > 0)
+                               ++sge;
+               }
+       }
+
+       return 0;
+
+free_mem:
+       srpt_unmap_sg_to_ib_sge(ch, ioctx);
+
+       return -ENOMEM;
+}
+
+/**
+ * srpt_get_send_ioctx() - Obtain an I/O context for sending to the initiator.
+ */
+static struct srpt_send_ioctx *srpt_get_send_ioctx(struct srpt_rdma_ch *ch)
+{
+       struct srpt_send_ioctx *ioctx;
+       unsigned long flags;
+
+       BUG_ON(!ch);
+
+       ioctx = NULL;
+       spin_lock_irqsave(&ch->spinlock, flags);
+       if (!list_empty(&ch->free_list)) {
+               ioctx = list_first_entry(&ch->free_list,
+                                        struct srpt_send_ioctx, free_list);
+               list_del(&ioctx->free_list);
+       }
+       spin_unlock_irqrestore(&ch->spinlock, flags);
+
+       if (!ioctx)
+               return ioctx;
+
+       BUG_ON(ioctx->ch != ch);
+       kref_init(&ioctx->kref);
+       spin_lock_init(&ioctx->spinlock);
+       ioctx->state = SRPT_STATE_NEW;
+       ioctx->n_rbuf = 0;
+       ioctx->rbufs = NULL;
+       ioctx->n_rdma = 0;
+       ioctx->n_rdma_ius = 0;
+       ioctx->rdma_ius = NULL;
+       ioctx->mapped_sg_count = 0;
+       init_completion(&ioctx->tx_done);
+       ioctx->queue_status_only = false;
+       /*
+        * transport_init_se_cmd() does not initialize all fields, so do it
+        * here.
+        */
+       memset(&ioctx->cmd, 0, sizeof(ioctx->cmd));
+       memset(&ioctx->sense_data, 0, sizeof(ioctx->sense_data));
+
+       return ioctx;
+}
+
+/**
+ * srpt_put_send_ioctx() - Free up resources.
+ */
+static void srpt_put_send_ioctx(struct srpt_send_ioctx *ioctx)
+{
+       struct srpt_rdma_ch *ch;
+       unsigned long flags;
+
+       BUG_ON(!ioctx);
+       ch = ioctx->ch;
+       BUG_ON(!ch);
+
+       WARN_ON(srpt_get_cmd_state(ioctx) != SRPT_STATE_DONE);
+
+       srpt_unmap_sg_to_ib_sge(ioctx->ch, ioctx);
+       transport_generic_free_cmd(&ioctx->cmd, 0);
+
+       if (ioctx->n_rbuf > 1) {
+               kfree(ioctx->rbufs);
+               ioctx->rbufs = NULL;
+               ioctx->n_rbuf = 0;
+       }
+
+       spin_lock_irqsave(&ch->spinlock, flags);
+       list_add(&ioctx->free_list, &ch->free_list);
+       spin_unlock_irqrestore(&ch->spinlock, flags);
+}
+
+static void srpt_put_send_ioctx_kref(struct kref *kref)
+{
+       srpt_put_send_ioctx(container_of(kref, struct srpt_send_ioctx, kref));
+}
+
+/**
+ * srpt_abort_cmd() - Abort a SCSI command.
+ * @ioctx:   I/O context associated with the SCSI command.
+ * @context: Preferred execution context.
+ */
+static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx)
+{
+       enum srpt_command_state state;
+       unsigned long flags;
+
+       BUG_ON(!ioctx);
+
+       /*
+        * If the command is in a state where the target core is waiting for
+        * the ib_srpt driver, change the state to the next state. Changing
+        * the state of the command from SRPT_STATE_NEED_DATA to
+        * SRPT_STATE_DATA_IN ensures that srpt_xmit_response() will call this
+        * function a second time.
+        */
+
+       spin_lock_irqsave(&ioctx->spinlock, flags);
+       state = ioctx->state;
+       switch (state) {
+       case SRPT_STATE_NEED_DATA:
+               ioctx->state = SRPT_STATE_DATA_IN;
+               break;
+       case SRPT_STATE_DATA_IN:
+       case SRPT_STATE_CMD_RSP_SENT:
+       case SRPT_STATE_MGMT_RSP_SENT:
+               ioctx->state = SRPT_STATE_DONE;
+               break;
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(&ioctx->spinlock, flags);
+
+       if (state == SRPT_STATE_DONE)
+               goto out;
+
+       pr_debug("Aborting cmd with state %d and tag %lld\n", state,
+                ioctx->tag);
+
+       switch (state) {
+       case SRPT_STATE_NEW:
+       case SRPT_STATE_DATA_IN:
+       case SRPT_STATE_MGMT:
+               /*
+                * Do nothing - defer abort processing until
+                * srpt_queue_response() is invoked.
+                */
+               WARN_ON(!transport_check_aborted_status(&ioctx->cmd, false));
+               break;
+       case SRPT_STATE_NEED_DATA:
+               /* DMA_TO_DEVICE (write) - RDMA read error. */
+               atomic_set(&ioctx->cmd.transport_lun_stop, 1);
+               transport_generic_handle_data(&ioctx->cmd);
+               break;
+       case SRPT_STATE_CMD_RSP_SENT:
+               /*
+                * SRP_RSP sending failed or the SRP_RSP send completion has
+                * not been received in time.
+                */
+               srpt_unmap_sg_to_ib_sge(ioctx->ch, ioctx);
+               atomic_set(&ioctx->cmd.transport_lun_stop, 1);
+               kref_put(&ioctx->kref, srpt_put_send_ioctx_kref);
+               break;
+       case SRPT_STATE_MGMT_RSP_SENT:
+               srpt_set_cmd_state(ioctx, SRPT_STATE_DONE);
+               kref_put(&ioctx->kref, srpt_put_send_ioctx_kref);
+               break;
+       default:
+               WARN_ON("ERROR: unexpected command state");
+               break;
+       }
+
+out:
+       return state;
+}
+
+/**
+ * srpt_handle_send_err_comp() - Process an IB_WC_SEND error completion.
+ */
+static void srpt_handle_send_err_comp(struct srpt_rdma_ch *ch, u64 wr_id)
+{
+       struct srpt_send_ioctx *ioctx;
+       enum srpt_command_state state;
+       struct se_cmd *cmd;
+       u32 index;
+
+       atomic_inc(&ch->sq_wr_avail);
+
+       index = idx_from_wr_id(wr_id);
+       ioctx = ch->ioctx_ring[index];
+       state = srpt_get_cmd_state(ioctx);
+       cmd = &ioctx->cmd;
+
+       WARN_ON(state != SRPT_STATE_CMD_RSP_SENT
+               && state != SRPT_STATE_MGMT_RSP_SENT
+               && state != SRPT_STATE_NEED_DATA
+               && state != SRPT_STATE_DONE);
+
+       /* If SRP_RSP sending failed, undo the ch->req_lim change. */
+       if (state == SRPT_STATE_CMD_RSP_SENT
+           || state == SRPT_STATE_MGMT_RSP_SENT)
+               atomic_dec(&ch->req_lim);
+
+       srpt_abort_cmd(ioctx);
+}
+
+/**
+ * srpt_handle_send_comp() - Process an IB send completion notification.
+ */
+static void srpt_handle_send_comp(struct srpt_rdma_ch *ch,
+                                 struct srpt_send_ioctx *ioctx)
+{
+       enum srpt_command_state state;
+
+       atomic_inc(&ch->sq_wr_avail);
+
+       state = srpt_set_cmd_state(ioctx, SRPT_STATE_DONE);
+
+       if (WARN_ON(state != SRPT_STATE_CMD_RSP_SENT
+                   && state != SRPT_STATE_MGMT_RSP_SENT
+                   && state != SRPT_STATE_DONE))
+               pr_debug("state = %d\n", state);
+
+       if (state != SRPT_STATE_DONE)
+               kref_put(&ioctx->kref, srpt_put_send_ioctx_kref);
+       else
+               printk(KERN_ERR "IB completion has been received too late for"
+                      " wr_id = %u.\n", ioctx->ioctx.index);
+}
+
+/**
+ * srpt_handle_rdma_comp() - Process an IB RDMA completion notification.
+ *
+ * Note: transport_generic_handle_data() is asynchronous so unmapping the
+ * data that has been transferred via IB RDMA must be postponed until the
+ * check_stop_free() callback.
+ */
+static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch,
+                                 struct srpt_send_ioctx *ioctx,
+                                 enum srpt_opcode opcode)
+{
+       WARN_ON(ioctx->n_rdma <= 0);
+       atomic_add(ioctx->n_rdma, &ch->sq_wr_avail);
+
+       if (opcode == SRPT_RDMA_READ_LAST) {
+               if (srpt_test_and_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA,
+                                               SRPT_STATE_DATA_IN))
+                       transport_generic_handle_data(&ioctx->cmd);
+               else
+                       printk(KERN_ERR "%s[%d]: wrong state = %d\n", __func__,
+                              __LINE__, srpt_get_cmd_state(ioctx));
+       } else if (opcode == SRPT_RDMA_ABORT) {
+               ioctx->rdma_aborted = true;
+       } else {
+               WARN(true, "unexpected opcode %d\n", opcode);
+       }
+}
+
+/**
+ * srpt_handle_rdma_err_comp() - Process an IB RDMA error completion.
+ */
+static void srpt_handle_rdma_err_comp(struct srpt_rdma_ch *ch,
+                                     struct srpt_send_ioctx *ioctx,
+                                     enum srpt_opcode opcode)
+{
+       struct se_cmd *cmd;
+       enum srpt_command_state state;
+
+       cmd = &ioctx->cmd;
+       state = srpt_get_cmd_state(ioctx);
+       switch (opcode) {
+       case SRPT_RDMA_READ_LAST:
+               if (ioctx->n_rdma <= 0) {
+                       printk(KERN_ERR "Received invalid RDMA read"
+                              " error completion with idx %d\n",
+                              ioctx->ioctx.index);
+                       break;
+               }
+               atomic_add(ioctx->n_rdma, &ch->sq_wr_avail);
+               if (state == SRPT_STATE_NEED_DATA)
+                       srpt_abort_cmd(ioctx);
+               else
+                       printk(KERN_ERR "%s[%d]: wrong state = %d\n",
+                              __func__, __LINE__, state);
+               break;
+       case SRPT_RDMA_WRITE_LAST:
+               atomic_set(&ioctx->cmd.transport_lun_stop, 1);
+               break;
+       default:
+               printk(KERN_ERR "%s[%d]: opcode = %u\n", __func__,
+                      __LINE__, opcode);
+               break;
+       }
+}
+
+/**
+ * srpt_build_cmd_rsp() - Build an SRP_RSP response.
+ * @ch: RDMA channel through which the request has been received.
+ * @ioctx: I/O context associated with the SRP_CMD request. The response will
+ *   be built in the buffer ioctx->buf points at and hence this function will
+ *   overwrite the request data.
+ * @tag: tag of the request for which this response is being generated.
+ * @status: value for the STATUS field of the SRP_RSP information unit.
+ *
+ * Returns the size in bytes of the SRP_RSP response.
+ *
+ * An SRP_RSP response contains a SCSI status or service response. See also
+ * section 6.9 in the SRP r16a document for the format of an SRP_RSP
+ * response. See also SPC-2 for more information about sense data.
+ */
+static int srpt_build_cmd_rsp(struct srpt_rdma_ch *ch,
+                             struct srpt_send_ioctx *ioctx, u64 tag,
+                             int status)
+{
+       struct srp_rsp *srp_rsp;
+       const u8 *sense_data;
+       int sense_data_len, max_sense_len;
+
+       /*
+        * The lowest bit of all SAM-3 status codes is zero (see also
+        * paragraph 5.3 in SAM-3).
+        */
+       WARN_ON(status & 1);
+
+       srp_rsp = ioctx->ioctx.buf;
+       BUG_ON(!srp_rsp);
+
+       sense_data = ioctx->sense_data;
+       sense_data_len = ioctx->cmd.scsi_sense_length;
+       WARN_ON(sense_data_len > sizeof(ioctx->sense_data));
+
+       memset(srp_rsp, 0, sizeof *srp_rsp);
+       srp_rsp->opcode = SRP_RSP;
+       srp_rsp->req_lim_delta =
+               __constant_cpu_to_be32(1 + atomic_xchg(&ch->req_lim_delta, 0));
+       srp_rsp->tag = tag;
+       srp_rsp->status = status;
+
+       if (sense_data_len) {
+               BUILD_BUG_ON(MIN_MAX_RSP_SIZE <= sizeof(*srp_rsp));
+               max_sense_len = ch->max_ti_iu_len - sizeof(*srp_rsp);
+               if (sense_data_len > max_sense_len) {
+                       printk(KERN_WARNING "truncated sense data from %d to %d"
+                              " bytes\n", sense_data_len, max_sense_len);
+                       sense_data_len = max_sense_len;
+               }
+
+               srp_rsp->flags |= SRP_RSP_FLAG_SNSVALID;
+               srp_rsp->sense_data_len = cpu_to_be32(sense_data_len);
+               memcpy(srp_rsp + 1, sense_data, sense_data_len);
+       }
+
+       return sizeof(*srp_rsp) + sense_data_len;
+}
+
+/**
+ * srpt_build_tskmgmt_rsp() - Build a task management response.
+ * @ch:       RDMA channel through which the request has been received.
+ * @ioctx:    I/O context in which the SRP_RSP response will be built.
+ * @rsp_code: RSP_CODE that will be stored in the response.
+ * @tag:      Tag of the request for which this response is being generated.
+ *
+ * Returns the size in bytes of the SRP_RSP response.
+ *
+ * An SRP_RSP response contains a SCSI status or service response. See also
+ * section 6.9 in the SRP r16a document for the format of an SRP_RSP
+ * response.
+ */
+static int srpt_build_tskmgmt_rsp(struct srpt_rdma_ch *ch,
+                                 struct srpt_send_ioctx *ioctx,
+                                 u8 rsp_code, u64 tag)
+{
+       struct srp_rsp *srp_rsp;
+       int resp_data_len;
+       int resp_len;
+
+       resp_data_len = (rsp_code == SRP_TSK_MGMT_SUCCESS) ? 0 : 4;
+       resp_len = sizeof(*srp_rsp) + resp_data_len;
+
+       srp_rsp = ioctx->ioctx.buf;
+       BUG_ON(!srp_rsp);
+       memset(srp_rsp, 0, sizeof *srp_rsp);
+
+       srp_rsp->opcode = SRP_RSP;
+       srp_rsp->req_lim_delta = __constant_cpu_to_be32(1
+                                   + atomic_xchg(&ch->req_lim_delta, 0));
+       srp_rsp->tag = tag;
+
+       if (rsp_code != SRP_TSK_MGMT_SUCCESS) {
+               srp_rsp->flags |= SRP_RSP_FLAG_RSPVALID;
+               srp_rsp->resp_data_len = cpu_to_be32(resp_data_len);
+               srp_rsp->data[3] = rsp_code;
+       }
+
+       return resp_len;
+}
+
+#define NO_SUCH_LUN ((uint64_t)-1LL)
+
+/*
+ * SCSI LUN addressing method. See also SAM-2 and the section about
+ * eight byte LUNs.
+ */
+enum scsi_lun_addr_method {
+       SCSI_LUN_ADDR_METHOD_PERIPHERAL   = 0,
+       SCSI_LUN_ADDR_METHOD_FLAT         = 1,
+       SCSI_LUN_ADDR_METHOD_LUN          = 2,
+       SCSI_LUN_ADDR_METHOD_EXTENDED_LUN = 3,
+};
+
+/*
+ * srpt_unpack_lun() - Convert from network LUN to linear LUN.
+ *
+ * Convert an 2-byte, 4-byte, 6-byte or 8-byte LUN structure in network byte
+ * order (big endian) to a linear LUN. Supports three LUN addressing methods:
+ * peripheral, flat and logical unit. See also SAM-2, section 4.9.4 (page 40).
+ */
+static uint64_t srpt_unpack_lun(const uint8_t *lun, int len)
+{
+       uint64_t res = NO_SUCH_LUN;
+       int addressing_method;
+
+       if (unlikely(len < 2)) {
+               printk(KERN_ERR "Illegal LUN length %d, expected 2 bytes or "
+                      "more", len);
+               goto out;
+       }
+
+       switch (len) {
+       case 8:
+               if ((*((__be64 *)lun) &
+                    __constant_cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0)
+                       goto out_err;
+               break;
+       case 4:
+               if (*((__be16 *)&lun[2]) != 0)
+                       goto out_err;
+               break;
+       case 6:
+               if (*((__be32 *)&lun[2]) != 0)
+                       goto out_err;
+               break;
+       case 2:
+               break;
+       default:
+               goto out_err;
+       }
+
+       addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */
+       switch (addressing_method) {
+       case SCSI_LUN_ADDR_METHOD_PERIPHERAL:
+       case SCSI_LUN_ADDR_METHOD_FLAT:
+       case SCSI_LUN_ADDR_METHOD_LUN:
+               res = *(lun + 1) | (((*lun) & 0x3f) << 8);
+               break;
+
+       case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN:
+       default:
+               printk(KERN_ERR "Unimplemented LUN addressing method %u",
+                      addressing_method);
+               break;
+       }
+
+out:
+       return res;
+
+out_err:
+       printk(KERN_ERR "Support for multi-level LUNs has not yet been"
+              " implemented");
+       goto out;
+}
+
+static int srpt_check_stop_free(struct se_cmd *cmd)
+{
+       struct srpt_send_ioctx *ioctx;
+
+       ioctx = container_of(cmd, struct srpt_send_ioctx, cmd);
+       return kref_put(&ioctx->kref, srpt_put_send_ioctx_kref);
+}
+
+/**
+ * srpt_handle_cmd() - Process SRP_CMD.
+ */
+static int srpt_handle_cmd(struct srpt_rdma_ch *ch,
+                          struct srpt_recv_ioctx *recv_ioctx,
+                          struct srpt_send_ioctx *send_ioctx)
+{
+       struct se_cmd *cmd;
+       struct srp_cmd *srp_cmd;
+       uint64_t unpacked_lun;
+       u64 data_len;
+       enum dma_data_direction dir;
+       int ret;
+
+       BUG_ON(!send_ioctx);
+
+       srp_cmd = recv_ioctx->ioctx.buf;
+       kref_get(&send_ioctx->kref);
+       cmd = &send_ioctx->cmd;
+       send_ioctx->tag = srp_cmd->tag;
+
+       switch (srp_cmd->task_attr) {
+       case SRP_CMD_SIMPLE_Q:
+               cmd->sam_task_attr = MSG_SIMPLE_TAG;
+               break;
+       case SRP_CMD_ORDERED_Q:
+       default:
+               cmd->sam_task_attr = MSG_ORDERED_TAG;
+               break;
+       case SRP_CMD_HEAD_OF_Q:
+               cmd->sam_task_attr = MSG_HEAD_TAG;
+               break;
+       case SRP_CMD_ACA:
+               cmd->sam_task_attr = MSG_ACA_TAG;
+               break;
+       }
+
+       ret = srpt_get_desc_tbl(send_ioctx, srp_cmd, &dir, &data_len);
+       if (ret) {
+               printk(KERN_ERR "0x%llx: parsing SRP descriptor table failed.\n",
+                      srp_cmd->tag);
+               cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+               cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+               goto send_sense;
+       }
+
+       cmd->data_length = data_len;
+       cmd->data_direction = dir;
+       unpacked_lun = srpt_unpack_lun((uint8_t *)&srp_cmd->lun,
+                                      sizeof(srp_cmd->lun));
+       if (transport_lookup_cmd_lun(cmd, unpacked_lun) < 0)
+               goto send_sense;
+       ret = transport_generic_allocate_tasks(cmd, srp_cmd->cdb);
+       if (cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
+               srpt_queue_status(cmd);
+       else if (cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION)
+               goto send_sense;
+       else
+               WARN_ON_ONCE(ret);
+
+       transport_handle_cdb_direct(cmd);
+       return 0;
+
+send_sense:
+       transport_send_check_condition_and_sense(cmd, cmd->scsi_sense_reason,
+                                                0);
+       return -1;
+}
+
+/**
+ * srpt_rx_mgmt_fn_tag() - Process a task management function by tag.
+ * @ch: RDMA channel of the task management request.
+ * @fn: Task management function to perform.
+ * @req_tag: Tag of the SRP task management request.
+ * @mgmt_ioctx: I/O context of the task management request.
+ *
+ * Returns zero if the target core will process the task management
+ * request asynchronously.
+ *
+ * Note: It is assumed that the initiator serializes tag-based task management
+ * requests.
+ */
+static int srpt_rx_mgmt_fn_tag(struct srpt_send_ioctx *ioctx, u64 tag)
+{
+       struct srpt_device *sdev;
+       struct srpt_rdma_ch *ch;
+       struct srpt_send_ioctx *target;
+       int ret, i;
+
+       ret = -EINVAL;
+       ch = ioctx->ch;
+       BUG_ON(!ch);
+       BUG_ON(!ch->sport);
+       sdev = ch->sport->sdev;
+       BUG_ON(!sdev);
+       spin_lock_irq(&sdev->spinlock);
+       for (i = 0; i < ch->rq_size; ++i) {
+               target = ch->ioctx_ring[i];
+               if (target->cmd.se_lun == ioctx->cmd.se_lun &&
+                   target->tag == tag &&
+                   srpt_get_cmd_state(target) != SRPT_STATE_DONE) {
+                       ret = 0;
+                       /* now let the target core abort &target->cmd; */
+                       break;
+               }
+       }
+       spin_unlock_irq(&sdev->spinlock);
+       return ret;
+}
+
+static int srp_tmr_to_tcm(int fn)
+{
+       switch (fn) {
+       case SRP_TSK_ABORT_TASK:
+               return TMR_ABORT_TASK;
+       case SRP_TSK_ABORT_TASK_SET:
+               return TMR_ABORT_TASK_SET;
+       case SRP_TSK_CLEAR_TASK_SET:
+               return TMR_CLEAR_TASK_SET;
+       case SRP_TSK_LUN_RESET:
+               return TMR_LUN_RESET;
+       case SRP_TSK_CLEAR_ACA:
+               return TMR_CLEAR_ACA;
+       default:
+               return -1;
+       }
+}
+
+/**
+ * srpt_handle_tsk_mgmt() - Process an SRP_TSK_MGMT information unit.
+ *
+ * Returns 0 if and only if the request will be processed by the target core.
+ *
+ * For more information about SRP_TSK_MGMT information units, see also section
+ * 6.7 in the SRP r16a document.
+ */
+static void srpt_handle_tsk_mgmt(struct srpt_rdma_ch *ch,
+                                struct srpt_recv_ioctx *recv_ioctx,
+                                struct srpt_send_ioctx *send_ioctx)
+{
+       struct srp_tsk_mgmt *srp_tsk;
+       struct se_cmd *cmd;
+       uint64_t unpacked_lun;
+       int tcm_tmr;
+       int res;
+
+       BUG_ON(!send_ioctx);
+
+       srp_tsk = recv_ioctx->ioctx.buf;
+       cmd = &send_ioctx->cmd;
+
+       pr_debug("recv tsk_mgmt fn %d for task_tag %lld and cmd tag %lld"
+                " cm_id %p sess %p\n", srp_tsk->tsk_mgmt_func,
+                srp_tsk->task_tag, srp_tsk->tag, ch->cm_id, ch->sess);
+
+       srpt_set_cmd_state(send_ioctx, SRPT_STATE_MGMT);
+       send_ioctx->tag = srp_tsk->tag;
+       tcm_tmr = srp_tmr_to_tcm(srp_tsk->tsk_mgmt_func);
+       if (tcm_tmr < 0) {
+               send_ioctx->cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+               send_ioctx->cmd.se_tmr_req->response =
+                       TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
+               goto process_tmr;
+       }
+       cmd->se_tmr_req = core_tmr_alloc_req(cmd, NULL, tcm_tmr, GFP_KERNEL);
+       if (!cmd->se_tmr_req) {
+               send_ioctx->cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+               send_ioctx->cmd.se_tmr_req->response = TMR_FUNCTION_REJECTED;
+               goto process_tmr;
+       }
+
+       unpacked_lun = srpt_unpack_lun((uint8_t *)&srp_tsk->lun,
+                                      sizeof(srp_tsk->lun));
+       res = transport_lookup_tmr_lun(&send_ioctx->cmd, unpacked_lun);
+       if (res) {
+               pr_debug("rejecting TMR for LUN %lld\n", unpacked_lun);
+               send_ioctx->cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+               send_ioctx->cmd.se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST;
+               goto process_tmr;
+       }
+
+       if (srp_tsk->tsk_mgmt_func == SRP_TSK_ABORT_TASK)
+               srpt_rx_mgmt_fn_tag(send_ioctx, srp_tsk->task_tag);
+
+process_tmr:
+       kref_get(&send_ioctx->kref);
+       if (!(send_ioctx->cmd.se_cmd_flags & SCF_SCSI_CDB_EXCEPTION))
+               transport_generic_handle_tmr(&send_ioctx->cmd);
+       else
+               transport_send_check_condition_and_sense(cmd,
+                                               cmd->scsi_sense_reason, 0);
+
+}
+
+/**
+ * srpt_handle_new_iu() - Process a newly received information unit.
+ * @ch:    RDMA channel through which the information unit has been received.
+ * @ioctx: SRPT I/O context associated with the information unit.
+ */
+static void srpt_handle_new_iu(struct srpt_rdma_ch *ch,
+                              struct srpt_recv_ioctx *recv_ioctx,
+                              struct srpt_send_ioctx *send_ioctx)
+{
+       struct srp_cmd *srp_cmd;
+       enum rdma_ch_state ch_state;
+
+       BUG_ON(!ch);
+       BUG_ON(!recv_ioctx);
+
+       ib_dma_sync_single_for_cpu(ch->sport->sdev->device,
+                                  recv_ioctx->ioctx.dma, srp_max_req_size,
+                                  DMA_FROM_DEVICE);
+
+       ch_state = srpt_get_ch_state(ch);
+       if (unlikely(ch_state == CH_CONNECTING)) {
+               list_add_tail(&recv_ioctx->wait_list, &ch->cmd_wait_list);
+               goto out;
+       }
+
+       if (unlikely(ch_state != CH_LIVE))
+               goto out;
+
+       srp_cmd = recv_ioctx->ioctx.buf;
+       if (srp_cmd->opcode == SRP_CMD || srp_cmd->opcode == SRP_TSK_MGMT) {
+               if (!send_ioctx)
+                       send_ioctx = srpt_get_send_ioctx(ch);
+               if (unlikely(!send_ioctx)) {
+                       list_add_tail(&recv_ioctx->wait_list,
+                                     &ch->cmd_wait_list);
+                       goto out;
+               }
+       }
+
+       transport_init_se_cmd(&send_ioctx->cmd, &srpt_target->tf_ops, ch->sess,
+                             0, DMA_NONE, MSG_SIMPLE_TAG,
+                             send_ioctx->sense_data);
+
+       switch (srp_cmd->opcode) {
+       case SRP_CMD:
+               srpt_handle_cmd(ch, recv_ioctx, send_ioctx);
+               break;
+       case SRP_TSK_MGMT:
+               srpt_handle_tsk_mgmt(ch, recv_ioctx, send_ioctx);
+               break;
+       case SRP_I_LOGOUT:
+               printk(KERN_ERR "Not yet implemented: SRP_I_LOGOUT\n");
+               break;
+       case SRP_CRED_RSP:
+               pr_debug("received SRP_CRED_RSP\n");
+               break;
+       case SRP_AER_RSP:
+               pr_debug("received SRP_AER_RSP\n");
+               break;
+       case SRP_RSP:
+               printk(KERN_ERR "Received SRP_RSP\n");
+               break;
+       default:
+               printk(KERN_ERR "received IU with unknown opcode 0x%x\n",
+                      srp_cmd->opcode);
+               break;
+       }
+
+       srpt_post_recv(ch->sport->sdev, recv_ioctx);
+out:
+       return;
+}
+
+static void srpt_process_rcv_completion(struct ib_cq *cq,
+                                       struct srpt_rdma_ch *ch,
+                                       struct ib_wc *wc)
+{
+       struct srpt_device *sdev = ch->sport->sdev;
+       struct srpt_recv_ioctx *ioctx;
+       u32 index;
+
+       index = idx_from_wr_id(wc->wr_id);
+       if (wc->status == IB_WC_SUCCESS) {
+               int req_lim;
+
+               req_lim = atomic_dec_return(&ch->req_lim);
+               if (unlikely(req_lim < 0))
+                       printk(KERN_ERR "req_lim = %d < 0\n", req_lim);
+               ioctx = sdev->ioctx_ring[index];
+               srpt_handle_new_iu(ch, ioctx, NULL);
+       } else {
+               printk(KERN_INFO "receiving failed for idx %u with status %d\n",
+                      index, wc->status);
+       }
+}
+
+/**
+ * srpt_process_send_completion() - Process an IB send completion.
+ *
+ * Note: Although this has not yet been observed during tests, at least in
+ * theory it is possible that the srpt_get_send_ioctx() call invoked by
+ * srpt_handle_new_iu() fails. This is possible because the req_lim_delta
+ * value in each response is set to one, and it is possible that this response
+ * makes the initiator send a new request before the send completion for that
+ * response has been processed. This could e.g. happen if the call to
+ * srpt_put_send_iotcx() is delayed because of a higher priority interrupt or
+ * if IB retransmission causes generation of the send completion to be
+ * delayed. Incoming information units for which srpt_get_send_ioctx() fails
+ * are queued on cmd_wait_list. The code below processes these delayed
+ * requests one at a time.
+ */
+static void srpt_process_send_completion(struct ib_cq *cq,
+                                        struct srpt_rdma_ch *ch,
+                                        struct ib_wc *wc)
+{
+       struct srpt_send_ioctx *send_ioctx;
+       uint32_t index;
+       enum srpt_opcode opcode;
+
+       index = idx_from_wr_id(wc->wr_id);
+       opcode = opcode_from_wr_id(wc->wr_id);
+       send_ioctx = ch->ioctx_ring[index];
+       if (wc->status == IB_WC_SUCCESS) {
+               if (opcode == SRPT_SEND)
+                       srpt_handle_send_comp(ch, send_ioctx);
+               else {
+                       WARN_ON(opcode != SRPT_RDMA_ABORT &&
+                               wc->opcode != IB_WC_RDMA_READ);
+                       srpt_handle_rdma_comp(ch, send_ioctx, opcode);
+               }
+       } else {
+               if (opcode == SRPT_SEND) {
+                       printk(KERN_INFO "sending response for idx %u failed"
+                              " with status %d\n", index, wc->status);
+                       srpt_handle_send_err_comp(ch, wc->wr_id);
+               } else if (opcode != SRPT_RDMA_MID) {
+                       printk(KERN_INFO "RDMA t %d for idx %u failed with"
+                               " status %d", opcode, index, wc->status);
+                       srpt_handle_rdma_err_comp(ch, send_ioctx, opcode);
+               }
+       }
+
+       while (unlikely(opcode == SRPT_SEND
+                       && !list_empty(&ch->cmd_wait_list)
+                       && srpt_get_ch_state(ch) == CH_LIVE
+                       && (send_ioctx = srpt_get_send_ioctx(ch)) != NULL)) {
+               struct srpt_recv_ioctx *recv_ioctx;
+
+               recv_ioctx = list_first_entry(&ch->cmd_wait_list,
+                                             struct srpt_recv_ioctx,
+                                             wait_list);
+               list_del(&recv_ioctx->wait_list);
+               srpt_handle_new_iu(ch, recv_ioctx, send_ioctx);
+       }
+}
+
+static void srpt_process_completion(struct ib_cq *cq, struct srpt_rdma_ch *ch)
+{
+       struct ib_wc *const wc = ch->wc;
+       int i, n;
+
+       WARN_ON(cq != ch->cq);
+
+       ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+       while ((n = ib_poll_cq(cq, ARRAY_SIZE(ch->wc), wc)) > 0) {
+               for (i = 0; i < n; i++) {
+                       if (opcode_from_wr_id(wc[i].wr_id) == SRPT_RECV)
+                               srpt_process_rcv_completion(cq, ch, &wc[i]);
+                       else
+                               srpt_process_send_completion(cq, ch, &wc[i]);
+               }
+       }
+}
+
+/**
+ * srpt_completion() - IB completion queue callback function.
+ *
+ * Notes:
+ * - It is guaranteed that a completion handler will never be invoked
+ *   concurrently on two different CPUs for the same completion queue. See also
+ *   Documentation/infiniband/core_locking.txt and the implementation of
+ *   handle_edge_irq() in kernel/irq/chip.c.
+ * - When threaded IRQs are enabled, completion handlers are invoked in thread
+ *   context instead of interrupt context.
+ */
+static void srpt_completion(struct ib_cq *cq, void *ctx)
+{
+       struct srpt_rdma_ch *ch = ctx;
+
+       wake_up_interruptible(&ch->wait_queue);
+}
+
+static int srpt_compl_thread(void *arg)
+{
+       struct srpt_rdma_ch *ch;
+
+       /* Hibernation / freezing of the SRPT kernel thread is not supported. */
+       current->flags |= PF_NOFREEZE;
+
+       ch = arg;
+       BUG_ON(!ch);
+       printk(KERN_INFO "Session %s: kernel thread %s (PID %d) started\n",
+              ch->sess_name, ch->thread->comm, current->pid);
+       while (!kthread_should_stop()) {
+               wait_event_interruptible(ch->wait_queue,
+                       (srpt_process_completion(ch->cq, ch),
+                        kthread_should_stop()));
+       }
+       printk(KERN_INFO "Session %s: kernel thread %s (PID %d) stopped\n",
+              ch->sess_name, ch->thread->comm, current->pid);
+       return 0;
+}
+
+/**
+ * srpt_create_ch_ib() - Create receive and send completion queues.
+ */
+static int srpt_create_ch_ib(struct srpt_rdma_ch *ch)
+{
+       struct ib_qp_init_attr *qp_init;
+       struct srpt_port *sport = ch->sport;
+       struct srpt_device *sdev = sport->sdev;
+       u32 srp_sq_size = sport->port_attrib.srp_sq_size;
+       int ret;
+
+       WARN_ON(ch->rq_size < 1);
+
+       ret = -ENOMEM;
+       qp_init = kzalloc(sizeof *qp_init, GFP_KERNEL);
+       if (!qp_init)
+               goto out;
+
+       ch->cq = ib_create_cq(sdev->device, srpt_completion, NULL, ch,
+                             ch->rq_size + srp_sq_size, 0);
+       if (IS_ERR(ch->cq)) {
+               ret = PTR_ERR(ch->cq);
+               printk(KERN_ERR "failed to create CQ cqe= %d ret= %d\n",
+                      ch->rq_size + srp_sq_size, ret);
+               goto out;
+       }
+
+       qp_init->qp_context = (void *)ch;
+       qp_init->event_handler
+               = (void(*)(struct ib_event *, void*))srpt_qp_event;
+       qp_init->send_cq = ch->cq;
+       qp_init->recv_cq = ch->cq;
+       qp_init->srq = sdev->srq;
+       qp_init->sq_sig_type = IB_SIGNAL_REQ_WR;
+       qp_init->qp_type = IB_QPT_RC;
+       qp_init->cap.max_send_wr = srp_sq_size;
+       qp_init->cap.max_send_sge = SRPT_DEF_SG_PER_WQE;
+
+       ch->qp = ib_create_qp(sdev->pd, qp_init);
+       if (IS_ERR(ch->qp)) {
+               ret = PTR_ERR(ch->qp);
+               printk(KERN_ERR "failed to create_qp ret= %d\n", ret);
+               goto err_destroy_cq;
+       }
+
+       atomic_set(&ch->sq_wr_avail, qp_init->cap.max_send_wr);
+
+       pr_debug("%s: max_cqe= %d max_sge= %d sq_size = %d cm_id= %p\n",
+                __func__, ch->cq->cqe, qp_init->cap.max_send_sge,
+                qp_init->cap.max_send_wr, ch->cm_id);
+
+       ret = srpt_init_ch_qp(ch, ch->qp);
+       if (ret)
+               goto err_destroy_qp;
+
+       init_waitqueue_head(&ch->wait_queue);
+
+       pr_debug("creating thread for session %s\n", ch->sess_name);
+
+       ch->thread = kthread_run(srpt_compl_thread, ch, "ib_srpt_compl");
+       if (IS_ERR(ch->thread)) {
+               printk(KERN_ERR "failed to create kernel thread %ld\n",
+                      PTR_ERR(ch->thread));
+               ch->thread = NULL;
+               goto err_destroy_qp;
+       }
+
+out:
+       kfree(qp_init);
+       return ret;
+
+err_destroy_qp:
+       ib_destroy_qp(ch->qp);
+err_destroy_cq:
+       ib_destroy_cq(ch->cq);
+       goto out;
+}
+
+static void srpt_destroy_ch_ib(struct srpt_rdma_ch *ch)
+{
+       if (ch->thread)
+               kthread_stop(ch->thread);
+
+       ib_destroy_qp(ch->qp);
+       ib_destroy_cq(ch->cq);
+}
+
+/**
+ * __srpt_close_ch() - Close an RDMA channel by setting the QP error state.
+ *
+ * Reset the QP and make sure all resources associated with the channel will
+ * be deallocated at an appropriate time.
+ *
+ * Note: The caller must hold ch->sport->sdev->spinlock.
+ */
+static void __srpt_close_ch(struct srpt_rdma_ch *ch)
+{
+       struct srpt_device *sdev;
+       enum rdma_ch_state prev_state;
+       unsigned long flags;
+
+       sdev = ch->sport->sdev;
+
+       spin_lock_irqsave(&ch->spinlock, flags);
+       prev_state = ch->state;
+       switch (prev_state) {
+       case CH_CONNECTING:
+       case CH_LIVE:
+               ch->state = CH_DISCONNECTING;
+               break;
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(&ch->spinlock, flags);
+
+       switch (prev_state) {
+       case CH_CONNECTING:
+               ib_send_cm_rej(ch->cm_id, IB_CM_REJ_NO_RESOURCES, NULL, 0,
+                              NULL, 0);
+               /* fall through */
+       case CH_LIVE:
+               if (ib_send_cm_dreq(ch->cm_id, NULL, 0) < 0)
+                       printk(KERN_ERR "sending CM DREQ failed.\n");
+               break;
+       case CH_DISCONNECTING:
+               break;
+       case CH_DRAINING:
+       case CH_RELEASING:
+               break;
+       }
+}
+
+/**
+ * srpt_close_ch() - Close an RDMA channel.
+ */
+static void srpt_close_ch(struct srpt_rdma_ch *ch)
+{
+       struct srpt_device *sdev;
+
+       sdev = ch->sport->sdev;
+       spin_lock_irq(&sdev->spinlock);
+       __srpt_close_ch(ch);
+       spin_unlock_irq(&sdev->spinlock);
+}
+
+/**
+ * srpt_drain_channel() - Drain a channel by resetting the IB queue pair.
+ * @cm_id: Pointer to the CM ID of the channel to be drained.
+ *
+ * Note: Must be called from inside srpt_cm_handler to avoid a race between
+ * accessing sdev->spinlock and the call to kfree(sdev) in srpt_remove_one()
+ * (the caller of srpt_cm_handler holds the cm_id spinlock; srpt_remove_one()
+ * waits until all target sessions for the associated IB device have been
+ * unregistered and target session registration involves a call to
+ * ib_destroy_cm_id(), which locks the cm_id spinlock and hence waits until
+ * this function has finished).
+ */
+static void srpt_drain_channel(struct ib_cm_id *cm_id)
+{
+       struct srpt_device *sdev;
+       struct srpt_rdma_ch *ch;
+       int ret;
+       bool do_reset = false;
+
+       WARN_ON_ONCE(irqs_disabled());
+
+       sdev = cm_id->context;
+       BUG_ON(!sdev);
+       spin_lock_irq(&sdev->spinlock);
+       list_for_each_entry(ch, &sdev->rch_list, list) {
+               if (ch->cm_id == cm_id) {
+                       do_reset = srpt_test_and_set_ch_state(ch,
+                                       CH_CONNECTING, CH_DRAINING) ||
+                                  srpt_test_and_set_ch_state(ch,
+                                       CH_LIVE, CH_DRAINING) ||
+                                  srpt_test_and_set_ch_state(ch,
+                                       CH_DISCONNECTING, CH_DRAINING);
+                       break;
+               }
+       }
+       spin_unlock_irq(&sdev->spinlock);
+
+       if (do_reset) {
+               ret = srpt_ch_qp_err(ch);
+               if (ret < 0)
+                       printk(KERN_ERR "Setting queue pair in error state"
+                              " failed: %d\n", ret);
+       }
+}
+
+/**
+ * srpt_find_channel() - Look up an RDMA channel.
+ * @cm_id: Pointer to the CM ID of the channel to be looked up.
+ *
+ * Return NULL if no matching RDMA channel has been found.
+ */
+static struct srpt_rdma_ch *srpt_find_channel(struct srpt_device *sdev,
+                                             struct ib_cm_id *cm_id)
+{
+       struct srpt_rdma_ch *ch;
+       bool found;
+
+       WARN_ON_ONCE(irqs_disabled());
+       BUG_ON(!sdev);
+
+       found = false;
+       spin_lock_irq(&sdev->spinlock);
+       list_for_each_entry(ch, &sdev->rch_list, list) {
+               if (ch->cm_id == cm_id) {
+                       found = true;
+                       break;
+               }
+       }
+       spin_unlock_irq(&sdev->spinlock);
+
+       return found ? ch : NULL;
+}
+
+/**
+ * srpt_release_channel() - Release channel resources.
+ *
+ * Schedules the actual release because:
+ * - Calling the ib_destroy_cm_id() call from inside an IB CM callback would
+ *   trigger a deadlock.
+ * - It is not safe to call TCM transport_* functions from interrupt context.
+ */
+static void srpt_release_channel(struct srpt_rdma_ch *ch)
+{
+       schedule_work(&ch->release_work);
+}
+
+static void srpt_release_channel_work(struct work_struct *w)
+{
+       struct srpt_rdma_ch *ch;
+       struct srpt_device *sdev;
+
+       ch = container_of(w, struct srpt_rdma_ch, release_work);
+       pr_debug("ch = %p; ch->sess = %p; release_done = %p\n", ch, ch->sess,
+                ch->release_done);
+
+       sdev = ch->sport->sdev;
+       BUG_ON(!sdev);
+
+       transport_deregister_session_configfs(ch->sess);
+       transport_deregister_session(ch->sess);
+       ch->sess = NULL;
+
+       srpt_destroy_ch_ib(ch);
+
+       srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_ring,
+                            ch->sport->sdev, ch->rq_size,
+                            ch->rsp_size, DMA_TO_DEVICE);
+
+       spin_lock_irq(&sdev->spinlock);
+       list_del(&ch->list);
+       spin_unlock_irq(&sdev->spinlock);
+
+       ib_destroy_cm_id(ch->cm_id);
+
+       if (ch->release_done)
+               complete(ch->release_done);
+
+       wake_up(&sdev->ch_releaseQ);
+
+       kfree(ch);
+}
+
+static struct srpt_node_acl *__srpt_lookup_acl(struct srpt_port *sport,
+                                              u8 i_port_id[16])
+{
+       struct srpt_node_acl *nacl;
+
+       list_for_each_entry(nacl, &sport->port_acl_list, list)
+               if (memcmp(nacl->i_port_id, i_port_id,
+                          sizeof(nacl->i_port_id)) == 0)
+                       return nacl;
+
+       return NULL;
+}
+
+static struct srpt_node_acl *srpt_lookup_acl(struct srpt_port *sport,
+                                            u8 i_port_id[16])
+{
+       struct srpt_node_acl *nacl;
+
+       spin_lock_irq(&sport->port_acl_lock);
+       nacl = __srpt_lookup_acl(sport, i_port_id);
+       spin_unlock_irq(&sport->port_acl_lock);
+
+       return nacl;
+}
+
+/**
+ * srpt_cm_req_recv() - Process the event IB_CM_REQ_RECEIVED.
+ *
+ * Ownership of the cm_id is transferred to the target session if this
+ * functions returns zero. Otherwise the caller remains the owner of cm_id.
+ */
+static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
+                           struct ib_cm_req_event_param *param,
+                           void *private_data)
+{
+       struct srpt_device *sdev = cm_id->context;
+       struct srpt_port *sport = &sdev->port[param->port - 1];
+       struct srp_login_req *req;
+       struct srp_login_rsp *rsp;
+       struct srp_login_rej *rej;
+       struct ib_cm_rep_param *rep_param;
+       struct srpt_rdma_ch *ch, *tmp_ch;
+       struct srpt_node_acl *nacl;
+       u32 it_iu_len;
+       int i;
+       int ret = 0;
+
+       WARN_ON_ONCE(irqs_disabled());
+
+       if (WARN_ON(!sdev || !private_data))
+               return -EINVAL;
+
+       req = (struct srp_login_req *)private_data;
+
+       it_iu_len = be32_to_cpu(req->req_it_iu_len);
+
+       printk(KERN_INFO "Received SRP_LOGIN_REQ with i_port_id 0x%llx:0x%llx,"
+              " t_port_id 0x%llx:0x%llx and it_iu_len %d on port %d"
+              " (guid=0x%llx:0x%llx)\n",
+              be64_to_cpu(*(__be64 *)&req->initiator_port_id[0]),
+              be64_to_cpu(*(__be64 *)&req->initiator_port_id[8]),
+              be64_to_cpu(*(__be64 *)&req->target_port_id[0]),
+              be64_to_cpu(*(__be64 *)&req->target_port_id[8]),
+              it_iu_len,
+              param->port,
+              be64_to_cpu(*(__be64 *)&sdev->port[param->port - 1].gid.raw[0]),
+              be64_to_cpu(*(__be64 *)&sdev->port[param->port - 1].gid.raw[8]));
+
+       rsp = kzalloc(sizeof *rsp, GFP_KERNEL);
+       rej = kzalloc(sizeof *rej, GFP_KERNEL);
+       rep_param = kzalloc(sizeof *rep_param, GFP_KERNEL);
+
+       if (!rsp || !rej || !rep_param) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (it_iu_len > srp_max_req_size || it_iu_len < 64) {
+               rej->reason = __constant_cpu_to_be32(
+                               SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE);
+               ret = -EINVAL;
+               printk(KERN_ERR "rejected SRP_LOGIN_REQ because its"
+                      " length (%d bytes) is out of range (%d .. %d)\n",
+                      it_iu_len, 64, srp_max_req_size);
+               goto reject;
+       }
+
+       if (!sport->enabled) {
+               rej->reason = __constant_cpu_to_be32(
+                            SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
+               ret = -EINVAL;
+               printk(KERN_ERR "rejected SRP_LOGIN_REQ because the target port"
+                      " has not yet been enabled\n");
+               goto reject;
+       }
+
+       if ((req->req_flags & SRP_MTCH_ACTION) == SRP_MULTICHAN_SINGLE) {
+               rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_NO_CHAN;
+
+               spin_lock_irq(&sdev->spinlock);
+
+               list_for_each_entry_safe(ch, tmp_ch, &sdev->rch_list, list) {
+                       if (!memcmp(ch->i_port_id, req->initiator_port_id, 16)
+                           && !memcmp(ch->t_port_id, req->target_port_id, 16)
+                           && param->port == ch->sport->port
+                           && param->listen_id == ch->sport->sdev->cm_id
+                           && ch->cm_id) {
+                               enum rdma_ch_state ch_state;
+
+                               ch_state = srpt_get_ch_state(ch);
+                               if (ch_state != CH_CONNECTING
+                                   && ch_state != CH_LIVE)
+                                       continue;
+
+                               /* found an existing channel */
+                               pr_debug("Found existing channel %s"
+                                        " cm_id= %p state= %d\n",
+                                        ch->sess_name, ch->cm_id, ch_state);
+
+                               __srpt_close_ch(ch);
+
+                               rsp->rsp_flags =
+                                       SRP_LOGIN_RSP_MULTICHAN_TERMINATED;
+                       }
+               }
+
+               spin_unlock_irq(&sdev->spinlock);
+
+       } else
+               rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_MAINTAINED;
+
+       if (*(__be64 *)req->target_port_id != cpu_to_be64(srpt_service_guid)
+           || *(__be64 *)(req->target_port_id + 8) !=
+              cpu_to_be64(srpt_service_guid)) {
+               rej->reason = __constant_cpu_to_be32(
+                               SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL);
+               ret = -ENOMEM;
+               printk(KERN_ERR "rejected SRP_LOGIN_REQ because it"
+                      " has an invalid target port identifier.\n");
+               goto reject;
+       }
+
+       ch = kzalloc(sizeof *ch, GFP_KERNEL);
+       if (!ch) {
+               rej->reason = __constant_cpu_to_be32(
+                                       SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
+               printk(KERN_ERR "rejected SRP_LOGIN_REQ because no memory.\n");
+               ret = -ENOMEM;
+               goto reject;
+       }
+
+       INIT_WORK(&ch->release_work, srpt_release_channel_work);
+       memcpy(ch->i_port_id, req->initiator_port_id, 16);
+       memcpy(ch->t_port_id, req->target_port_id, 16);
+       ch->sport = &sdev->port[param->port - 1];
+       ch->cm_id = cm_id;
+       /*
+        * Avoid QUEUE_FULL conditions by limiting the number of buffers used
+        * for the SRP protocol to the command queue size.
+        */
+       ch->rq_size = SRPT_RQ_SIZE;
+       spin_lock_init(&ch->spinlock);
+       ch->state = CH_CONNECTING;
+       INIT_LIST_HEAD(&ch->cmd_wait_list);
+       ch->rsp_size = ch->sport->port_attrib.srp_max_rsp_size;
+
+       ch->ioctx_ring = (struct srpt_send_ioctx **)
+               srpt_alloc_ioctx_ring(ch->sport->sdev, ch->rq_size,
+                                     sizeof(*ch->ioctx_ring[0]),
+                                     ch->rsp_size, DMA_TO_DEVICE);
+       if (!ch->ioctx_ring)
+               goto free_ch;
+
+       INIT_LIST_HEAD(&ch->free_list);
+       for (i = 0; i < ch->rq_size; i++) {
+               ch->ioctx_ring[i]->ch = ch;
+               list_add_tail(&ch->ioctx_ring[i]->free_list, &ch->free_list);
+       }
+
+       ret = srpt_create_ch_ib(ch);
+       if (ret) {
+               rej->reason = __constant_cpu_to_be32(
+                               SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
+               printk(KERN_ERR "rejected SRP_LOGIN_REQ because creating"
+                      " a new RDMA channel failed.\n");
+               goto free_ring;
+       }
+
+       ret = srpt_ch_qp_rtr(ch, ch->qp);
+       if (ret) {
+               rej->reason = __constant_cpu_to_be32(
+                               SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
+               printk(KERN_ERR "rejected SRP_LOGIN_REQ because enabling"
+                      " RTR failed (error code = %d)\n", ret);
+               goto destroy_ib;
+       }
+       /*
+        * Use the initator port identifier as the session name.
+        */
+       snprintf(ch->sess_name, sizeof(ch->sess_name), "0x%016llx%016llx",
+                       be64_to_cpu(*(__be64 *)ch->i_port_id),
+                       be64_to_cpu(*(__be64 *)(ch->i_port_id + 8)));
+
+       pr_debug("registering session %s\n", ch->sess_name);
+
+       nacl = srpt_lookup_acl(sport, ch->i_port_id);
+       if (!nacl) {
+               printk(KERN_INFO "Rejected login because no ACL has been"
+                      " configured yet for initiator %s.\n", ch->sess_name);
+               rej->reason = __constant_cpu_to_be32(
+                               SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED);
+               goto destroy_ib;
+       }
+
+       ch->sess = transport_init_session();
+       if (!ch->sess) {
+               rej->reason = __constant_cpu_to_be32(
+                               SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
+               pr_debug("Failed to create session\n");
+               goto deregister_session;
+       }
+       ch->sess->se_node_acl = &nacl->nacl;
+       transport_register_session(&sport->port_tpg_1, &nacl->nacl, ch->sess, ch);
+
+       pr_debug("Establish connection sess=%p name=%s cm_id=%p\n", ch->sess,
+                ch->sess_name, ch->cm_id);
+
+       /* create srp_login_response */
+       rsp->opcode = SRP_LOGIN_RSP;
+       rsp->tag = req->tag;
+       rsp->max_it_iu_len = req->req_it_iu_len;
+       rsp->max_ti_iu_len = req->req_it_iu_len;
+       ch->max_ti_iu_len = it_iu_len;
+       rsp->buf_fmt = __constant_cpu_to_be16(SRP_BUF_FORMAT_DIRECT
+                                             | SRP_BUF_FORMAT_INDIRECT);
+       rsp->req_lim_delta = cpu_to_be32(ch->rq_size);
+       atomic_set(&ch->req_lim, ch->rq_size);
+       atomic_set(&ch->req_lim_delta, 0);
+
+       /* create cm reply */
+       rep_param->qp_num = ch->qp->qp_num;
+       rep_param->private_data = (void *)rsp;
+       rep_param->private_data_len = sizeof *rsp;
+       rep_param->rnr_retry_count = 7;
+       rep_param->flow_control = 1;
+       rep_param->failover_accepted = 0;
+       rep_param->srq = 1;
+       rep_param->responder_resources = 4;
+       rep_param->initiator_depth = 4;
+
+       ret = ib_send_cm_rep(cm_id, rep_param);
+       if (ret) {
+               printk(KERN_ERR "sending SRP_LOGIN_REQ response failed"
+                      " (error code = %d)\n", ret);
+               goto release_channel;
+       }
+
+       spin_lock_irq(&sdev->spinlock);
+       list_add_tail(&ch->list, &sdev->rch_list);
+       spin_unlock_irq(&sdev->spinlock);
+
+       goto out;
+
+release_channel:
+       srpt_set_ch_state(ch, CH_RELEASING);
+       transport_deregister_session_configfs(ch->sess);
+
+deregister_session:
+       transport_deregister_session(ch->sess);
+       ch->sess = NULL;
+
+destroy_ib:
+       srpt_destroy_ch_ib(ch);
+
+free_ring:
+       srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_ring,
+                            ch->sport->sdev, ch->rq_size,
+                            ch->rsp_size, DMA_TO_DEVICE);
+free_ch:
+       kfree(ch);
+
+reject:
+       rej->opcode = SRP_LOGIN_REJ;
+       rej->tag = req->tag;
+       rej->buf_fmt = __constant_cpu_to_be16(SRP_BUF_FORMAT_DIRECT
+                                             | SRP_BUF_FORMAT_INDIRECT);
+
+       ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED, NULL, 0,
+                            (void *)rej, sizeof *rej);
+
+out:
+       kfree(rep_param);
+       kfree(rsp);
+       kfree(rej);
+
+       return ret;
+}
+
+static void srpt_cm_rej_recv(struct ib_cm_id *cm_id)
+{
+       printk(KERN_INFO "Received IB REJ for cm_id %p.\n", cm_id);
+       srpt_drain_channel(cm_id);
+}
+
+/**
+ * srpt_cm_rtu_recv() - Process an IB_CM_RTU_RECEIVED or USER_ESTABLISHED event.
+ *
+ * An IB_CM_RTU_RECEIVED message indicates that the connection is established
+ * and that the recipient may begin transmitting (RTU = ready to use).
+ */
+static void srpt_cm_rtu_recv(struct ib_cm_id *cm_id)
+{
+       struct srpt_rdma_ch *ch;
+       int ret;
+
+       ch = srpt_find_channel(cm_id->context, cm_id);
+       BUG_ON(!ch);
+
+       if (srpt_test_and_set_ch_state(ch, CH_CONNECTING, CH_LIVE)) {
+               struct srpt_recv_ioctx *ioctx, *ioctx_tmp;
+
+               ret = srpt_ch_qp_rts(ch, ch->qp);
+
+               list_for_each_entry_safe(ioctx, ioctx_tmp, &ch->cmd_wait_list,
+                                        wait_list) {
+                       list_del(&ioctx->wait_list);
+                       srpt_handle_new_iu(ch, ioctx, NULL);
+               }
+               if (ret)
+                       srpt_close_ch(ch);
+       }
+}
+
+static void srpt_cm_timewait_exit(struct ib_cm_id *cm_id)
+{
+       printk(KERN_INFO "Received IB TimeWait exit for cm_id %p.\n", cm_id);
+       srpt_drain_channel(cm_id);
+}
+
+static void srpt_cm_rep_error(struct ib_cm_id *cm_id)
+{
+       printk(KERN_INFO "Received IB REP error for cm_id %p.\n", cm_id);
+       srpt_drain_channel(cm_id);
+}
+
+/**
+ * srpt_cm_dreq_recv() - Process reception of a DREQ message.
+ */
+static void srpt_cm_dreq_recv(struct ib_cm_id *cm_id)
+{
+       struct srpt_rdma_ch *ch;
+       unsigned long flags;
+       bool send_drep = false;
+
+       ch = srpt_find_channel(cm_id->context, cm_id);
+       BUG_ON(!ch);
+
+       pr_debug("cm_id= %p ch->state= %d\n", cm_id, srpt_get_ch_state(ch));
+
+       spin_lock_irqsave(&ch->spinlock, flags);
+       switch (ch->state) {
+       case CH_CONNECTING:
+       case CH_LIVE:
+               send_drep = true;
+               ch->state = CH_DISCONNECTING;
+               break;
+       case CH_DISCONNECTING:
+       case CH_DRAINING:
+       case CH_RELEASING:
+               WARN(true, "unexpected channel state %d\n", ch->state);
+               break;
+       }
+       spin_unlock_irqrestore(&ch->spinlock, flags);
+
+       if (send_drep) {
+               if (ib_send_cm_drep(ch->cm_id, NULL, 0) < 0)
+                       printk(KERN_ERR "Sending IB DREP failed.\n");
+               printk(KERN_INFO "Received DREQ and sent DREP for session %s.\n",
+                      ch->sess_name);
+       }
+}
+
+/**
+ * srpt_cm_drep_recv() - Process reception of a DREP message.
+ */
+static void srpt_cm_drep_recv(struct ib_cm_id *cm_id)
+{
+       printk(KERN_INFO "Received InfiniBand DREP message for cm_id %p.\n",
+              cm_id);
+       srpt_drain_channel(cm_id);
+}
+
+/**
+ * srpt_cm_handler() - IB connection manager callback function.
+ *
+ * A non-zero return value will cause the caller destroy the CM ID.
+ *
+ * Note: srpt_cm_handler() must only return a non-zero value when transferring
+ * ownership of the cm_id to a channel by srpt_cm_req_recv() failed. Returning
+ * a non-zero value in any other case will trigger a race with the
+ * ib_destroy_cm_id() call in srpt_release_channel().
+ */
+static int srpt_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
+{
+       int ret;
+
+       ret = 0;
+       switch (event->event) {
+       case IB_CM_REQ_RECEIVED:
+               ret = srpt_cm_req_recv(cm_id, &event->param.req_rcvd,
+                                      event->private_data);
+               break;
+       case IB_CM_REJ_RECEIVED:
+               srpt_cm_rej_recv(cm_id);
+               break;
+       case IB_CM_RTU_RECEIVED:
+       case IB_CM_USER_ESTABLISHED:
+               srpt_cm_rtu_recv(cm_id);
+               break;
+       case IB_CM_DREQ_RECEIVED:
+               srpt_cm_dreq_recv(cm_id);
+               break;
+       case IB_CM_DREP_RECEIVED:
+               srpt_cm_drep_recv(cm_id);
+               break;
+       case IB_CM_TIMEWAIT_EXIT:
+               srpt_cm_timewait_exit(cm_id);
+               break;
+       case IB_CM_REP_ERROR:
+               srpt_cm_rep_error(cm_id);
+               break;
+       case IB_CM_DREQ_ERROR:
+               printk(KERN_INFO "Received IB DREQ ERROR event.\n");
+               break;
+       case IB_CM_MRA_RECEIVED:
+               printk(KERN_INFO "Received IB MRA event\n");
+               break;
+       default:
+               printk(KERN_ERR "received unrecognized IB CM event %d\n",
+                      event->event);
+               break;
+       }
+
+       return ret;
+}
+
+/**
+ * srpt_perform_rdmas() - Perform IB RDMA.
+ *
+ * Returns zero upon success or a negative number upon failure.
+ */
+static int srpt_perform_rdmas(struct srpt_rdma_ch *ch,
+                             struct srpt_send_ioctx *ioctx)
+{
+       struct ib_send_wr wr;
+       struct ib_send_wr *bad_wr;
+       struct rdma_iu *riu;
+       int i;
+       int ret;
+       int sq_wr_avail;
+       enum dma_data_direction dir;
+       const int n_rdma = ioctx->n_rdma;
+
+       dir = ioctx->cmd.data_direction;
+       if (dir == DMA_TO_DEVICE) {
+               /* write */
+               ret = -ENOMEM;
+               sq_wr_avail = atomic_sub_return(n_rdma, &ch->sq_wr_avail);
+               if (sq_wr_avail < 0) {
+                       printk(KERN_WARNING "IB send queue full (needed %d)\n",
+                              n_rdma);
+                       goto out;
+               }
+       }
+
+       ioctx->rdma_aborted = false;
+       ret = 0;
+       riu = ioctx->rdma_ius;
+       memset(&wr, 0, sizeof wr);
+
+       for (i = 0; i < n_rdma; ++i, ++riu) {
+               if (dir == DMA_FROM_DEVICE) {
+                       wr.opcode = IB_WR_RDMA_WRITE;
+                       wr.wr_id = encode_wr_id(i == n_rdma - 1 ?
+                                               SRPT_RDMA_WRITE_LAST :
+                                               SRPT_RDMA_MID,
+                                               ioctx->ioctx.index);
+               } else {
+                       wr.opcode = IB_WR_RDMA_READ;
+                       wr.wr_id = encode_wr_id(i == n_rdma - 1 ?
+                                               SRPT_RDMA_READ_LAST :
+                                               SRPT_RDMA_MID,
+                                               ioctx->ioctx.index);
+               }
+               wr.next = NULL;
+               wr.wr.rdma.remote_addr = riu->raddr;
+               wr.wr.rdma.rkey = riu->rkey;
+               wr.num_sge = riu->sge_cnt;
+               wr.sg_list = riu->sge;
+
+               /* only get completion event for the last rdma write */
+               if (i == (n_rdma - 1) && dir == DMA_TO_DEVICE)
+                       wr.send_flags = IB_SEND_SIGNALED;
+
+               ret = ib_post_send(ch->qp, &wr, &bad_wr);
+               if (ret)
+                       break;
+       }
+
+       if (ret)
+               printk(KERN_ERR "%s[%d]: ib_post_send() returned %d for %d/%d",
+                                __func__, __LINE__, ret, i, n_rdma);
+       if (ret && i > 0) {
+               wr.num_sge = 0;
+               wr.wr_id = encode_wr_id(SRPT_RDMA_ABORT, ioctx->ioctx.index);
+               wr.send_flags = IB_SEND_SIGNALED;
+               while (ch->state == CH_LIVE &&
+                       ib_post_send(ch->qp, &wr, &bad_wr) != 0) {
+                       printk(KERN_INFO "Trying to abort failed RDMA transfer [%d]",
+                               ioctx->ioctx.index);
+                       msleep(1000);
+               }
+               while (ch->state != CH_RELEASING && !ioctx->rdma_aborted) {
+                       printk(KERN_INFO "Waiting until RDMA abort finished [%d]",
+                               ioctx->ioctx.index);
+                       msleep(1000);
+               }
+       }
+out:
+       if (unlikely(dir == DMA_TO_DEVICE && ret < 0))
+               atomic_add(n_rdma, &ch->sq_wr_avail);
+       return ret;
+}
+
+/**
+ * srpt_xfer_data() - Start data transfer from initiator to target.
+ */
+static int srpt_xfer_data(struct srpt_rdma_ch *ch,
+                         struct srpt_send_ioctx *ioctx)
+{
+       int ret;
+
+       ret = srpt_map_sg_to_ib_sge(ch, ioctx);
+       if (ret) {
+               printk(KERN_ERR "%s[%d] ret=%d\n", __func__, __LINE__, ret);
+               goto out;
+       }
+
+       ret = srpt_perform_rdmas(ch, ioctx);
+       if (ret) {
+               if (ret == -EAGAIN || ret == -ENOMEM)
+                       printk(KERN_INFO "%s[%d] queue full -- ret=%d\n",
+                                  __func__, __LINE__, ret);
+               else
+                       printk(KERN_ERR "%s[%d] fatal error -- ret=%d\n",
+                              __func__, __LINE__, ret);
+               goto out_unmap;
+       }
+
+out:
+       return ret;
+out_unmap:
+       srpt_unmap_sg_to_ib_sge(ch, ioctx);
+       goto out;
+}
+
+static int srpt_write_pending_status(struct se_cmd *se_cmd)
+{
+       struct srpt_send_ioctx *ioctx;
+
+       ioctx = container_of(se_cmd, struct srpt_send_ioctx, cmd);
+       return srpt_get_cmd_state(ioctx) == SRPT_STATE_NEED_DATA;
+}
+
+/*
+ * srpt_write_pending() - Start data transfer from initiator to target (write).
+ */
+static int srpt_write_pending(struct se_cmd *se_cmd)
+{
+       struct srpt_rdma_ch *ch;
+       struct srpt_send_ioctx *ioctx;
+       enum srpt_command_state new_state;
+       enum rdma_ch_state ch_state;
+       int ret;
+
+       ioctx = container_of(se_cmd, struct srpt_send_ioctx, cmd);
+
+       new_state = srpt_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA);
+       WARN_ON(new_state == SRPT_STATE_DONE);
+
+       ch = ioctx->ch;
+       BUG_ON(!ch);
+
+       ch_state = srpt_get_ch_state(ch);
+       switch (ch_state) {
+       case CH_CONNECTING:
+               WARN(true, "unexpected channel state %d\n", ch_state);
+               ret = -EINVAL;
+               goto out;
+       case CH_LIVE:
+               break;
+       case CH_DISCONNECTING:
+       case CH_DRAINING:
+       case CH_RELEASING:
+               pr_debug("cmd with tag %lld: channel disconnecting\n",
+                        ioctx->tag);
+               srpt_set_cmd_state(ioctx, SRPT_STATE_DATA_IN);
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = srpt_xfer_data(ch, ioctx);
+
+out:
+       return ret;
+}
+
+static u8 tcm_to_srp_tsk_mgmt_status(const int tcm_mgmt_status)
+{
+       switch (tcm_mgmt_status) {
+       case TMR_FUNCTION_COMPLETE:
+               return SRP_TSK_MGMT_SUCCESS;
+       case TMR_FUNCTION_REJECTED:
+               return SRP_TSK_MGMT_FUNC_NOT_SUPP;
+       }
+       return SRP_TSK_MGMT_FAILED;
+}
+
+/**
+ * srpt_queue_response() - Transmits the response to a SCSI command.
+ *
+ * Callback function called by the TCM core. Must not block since it can be
+ * invoked on the context of the IB completion handler.
+ */
+static int srpt_queue_response(struct se_cmd *cmd)
+{
+       struct srpt_rdma_ch *ch;
+       struct srpt_send_ioctx *ioctx;
+       enum srpt_command_state state;
+       unsigned long flags;
+       int ret;
+       enum dma_data_direction dir;
+       int resp_len;
+       u8 srp_tm_status;
+
+       ret = 0;
+
+       ioctx = container_of(cmd, struct srpt_send_ioctx, cmd);
+       ch = ioctx->ch;
+       BUG_ON(!ch);
+
+       spin_lock_irqsave(&ioctx->spinlock, flags);
+       state = ioctx->state;
+       switch (state) {
+       case SRPT_STATE_NEW:
+       case SRPT_STATE_DATA_IN:
+               ioctx->state = SRPT_STATE_CMD_RSP_SENT;
+               break;
+       case SRPT_STATE_MGMT:
+               ioctx->state = SRPT_STATE_MGMT_RSP_SENT;
+               break;
+       default:
+               WARN(true, "ch %p; cmd %d: unexpected command state %d\n",
+                       ch, ioctx->ioctx.index, ioctx->state);
+               break;
+       }
+       spin_unlock_irqrestore(&ioctx->spinlock, flags);
+
+       if (unlikely(transport_check_aborted_status(&ioctx->cmd, false)
+                    || WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) {
+               atomic_inc(&ch->req_lim_delta);
+               srpt_abort_cmd(ioctx);
+               goto out;
+       }
+
+       dir = ioctx->cmd.data_direction;
+
+       /* For read commands, transfer the data to the initiator. */
+       if (dir == DMA_FROM_DEVICE && ioctx->cmd.data_length &&
+           !ioctx->queue_status_only) {
+               ret = srpt_xfer_data(ch, ioctx);
+               if (ret) {
+                       printk(KERN_ERR "xfer_data failed for tag %llu\n",
+                              ioctx->tag);
+                       goto out;
+               }
+       }
+
+       if (state != SRPT_STATE_MGMT)
+               resp_len = srpt_build_cmd_rsp(ch, ioctx, ioctx->tag,
+                                             cmd->scsi_status);
+       else {
+               srp_tm_status
+                       = tcm_to_srp_tsk_mgmt_status(cmd->se_tmr_req->response);
+               resp_len = srpt_build_tskmgmt_rsp(ch, ioctx, srp_tm_status,
+                                                ioctx->tag);
+       }
+       ret = srpt_post_send(ch, ioctx, resp_len);
+       if (ret) {
+               printk(KERN_ERR "sending cmd response failed for tag %llu\n",
+                      ioctx->tag);
+               srpt_unmap_sg_to_ib_sge(ch, ioctx);
+               srpt_set_cmd_state(ioctx, SRPT_STATE_DONE);
+               kref_put(&ioctx->kref, srpt_put_send_ioctx_kref);
+       }
+
+out:
+       return ret;
+}
+
+static int srpt_queue_status(struct se_cmd *cmd)
+{
+       struct srpt_send_ioctx *ioctx;
+
+       ioctx = container_of(cmd, struct srpt_send_ioctx, cmd);
+       BUG_ON(ioctx->sense_data != cmd->sense_buffer);
+       if (cmd->se_cmd_flags &
+           (SCF_TRANSPORT_TASK_SENSE | SCF_EMULATED_TASK_SENSE))
+               WARN_ON(cmd->scsi_status != SAM_STAT_CHECK_CONDITION);
+       ioctx->queue_status_only = true;
+       return srpt_queue_response(cmd);
+}
+
+static void srpt_refresh_port_work(struct work_struct *work)
+{
+       struct srpt_port *sport = container_of(work, struct srpt_port, work);
+
+       srpt_refresh_port(sport);
+}
+
+static int srpt_ch_list_empty(struct srpt_device *sdev)
+{
+       int res;
+
+       spin_lock_irq(&sdev->spinlock);
+       res = list_empty(&sdev->rch_list);
+       spin_unlock_irq(&sdev->spinlock);
+
+       return res;
+}
+
+/**
+ * srpt_release_sdev() - Free the channel resources associated with a target.
+ */
+static int srpt_release_sdev(struct srpt_device *sdev)
+{
+       struct srpt_rdma_ch *ch, *tmp_ch;
+       int res;
+
+       WARN_ON_ONCE(irqs_disabled());
+
+       BUG_ON(!sdev);
+
+       spin_lock_irq(&sdev->spinlock);
+       list_for_each_entry_safe(ch, tmp_ch, &sdev->rch_list, list)
+               __srpt_close_ch(ch);
+       spin_unlock_irq(&sdev->spinlock);
+
+       res = wait_event_interruptible(sdev->ch_releaseQ,
+                                      srpt_ch_list_empty(sdev));
+       if (res)
+               printk(KERN_ERR "%s: interrupted.\n", __func__);
+
+       return 0;
+}
+
+static struct srpt_port *__srpt_lookup_port(const char *name)
+{
+       struct ib_device *dev;
+       struct srpt_device *sdev;
+       struct srpt_port *sport;
+       int i;
+
+       list_for_each_entry(sdev, &srpt_dev_list, list) {
+               dev = sdev->device;
+               if (!dev)
+                       continue;
+
+               for (i = 0; i < dev->phys_port_cnt; i++) {
+                       sport = &sdev->port[i];
+
+                       if (!strcmp(sport->port_guid, name))
+                               return sport;
+               }
+       }
+
+       return NULL;
+}
+
+static struct srpt_port *srpt_lookup_port(const char *name)
+{
+       struct srpt_port *sport;
+
+       spin_lock(&srpt_dev_lock);
+       sport = __srpt_lookup_port(name);
+       spin_unlock(&srpt_dev_lock);
+
+       return sport;
+}
+
+/**
+ * srpt_add_one() - Infiniband device addition callback function.
+ */
+static void srpt_add_one(struct ib_device *device)
+{
+       struct srpt_device *sdev;
+       struct srpt_port *sport;
+       struct ib_srq_init_attr srq_attr;
+       int i;
+
+       pr_debug("device = %p, device->dma_ops = %p\n", device,
+                device->dma_ops);
+
+       sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
+       if (!sdev)
+               goto err;
+
+       sdev->device = device;
+       INIT_LIST_HEAD(&sdev->rch_list);
+       init_waitqueue_head(&sdev->ch_releaseQ);
+       spin_lock_init(&sdev->spinlock);
+
+       if (ib_query_device(device, &sdev->dev_attr))
+               goto free_dev;
+
+       sdev->pd = ib_alloc_pd(device);
+       if (IS_ERR(sdev->pd))
+               goto free_dev;
+
+       sdev->mr = ib_get_dma_mr(sdev->pd, IB_ACCESS_LOCAL_WRITE);
+       if (IS_ERR(sdev->mr))
+               goto err_pd;
+
+       sdev->srq_size = min(srpt_srq_size, sdev->dev_attr.max_srq_wr);
+
+       srq_attr.event_handler = srpt_srq_event;
+       srq_attr.srq_context = (void *)sdev;
+       srq_attr.attr.max_wr = sdev->srq_size;
+       srq_attr.attr.max_sge = 1;
+       srq_attr.attr.srq_limit = 0;
+
+       sdev->srq = ib_create_srq(sdev->pd, &srq_attr);
+       if (IS_ERR(sdev->srq))
+               goto err_mr;
+
+       pr_debug("%s: create SRQ #wr= %d max_allow=%d dev= %s\n",
+                __func__, sdev->srq_size, sdev->dev_attr.max_srq_wr,
+                device->name);
+
+       if (!srpt_service_guid)
+               srpt_service_guid = be64_to_cpu(device->node_guid);
+
+       sdev->cm_id = ib_create_cm_id(device, srpt_cm_handler, sdev);
+       if (IS_ERR(sdev->cm_id))
+               goto err_srq;
+
+       /* print out target login information */
+       pr_debug("Target login info: id_ext=%016llx,ioc_guid=%016llx,"
+                "pkey=ffff,service_id=%016llx\n", srpt_service_guid,
+                srpt_service_guid, srpt_service_guid);
+
+       /*
+        * We do not have a consistent service_id (ie. also id_ext of target_id)
+        * to identify this target. We currently use the guid of the first HCA
+        * in the system as service_id; therefore, the target_id will change
+        * if this HCA is gone bad and replaced by different HCA
+        */
+       if (ib_cm_listen(sdev->cm_id, cpu_to_be64(srpt_service_guid), 0, NULL))
+               goto err_cm;
+
+       INIT_IB_EVENT_HANDLER(&sdev->event_handler, sdev->device,
+                             srpt_event_handler);
+       if (ib_register_event_handler(&sdev->event_handler))
+               goto err_cm;
+
+       sdev->ioctx_ring = (struct srpt_recv_ioctx **)
+               srpt_alloc_ioctx_ring(sdev, sdev->srq_size,
+                                     sizeof(*sdev->ioctx_ring[0]),
+                                     srp_max_req_size, DMA_FROM_DEVICE);
+       if (!sdev->ioctx_ring)
+               goto err_event;
+
+       for (i = 0; i < sdev->srq_size; ++i)
+               srpt_post_recv(sdev, sdev->ioctx_ring[i]);
+
+       WARN_ON(sdev->device->phys_port_cnt
+               > sizeof(sdev->port)/sizeof(sdev->port[0]));
+
+       for (i = 1; i <= sdev->device->phys_port_cnt; i++) {
+               sport = &sdev->port[i - 1];
+               sport->sdev = sdev;
+               sport->port = i;
+               sport->port_attrib.srp_max_rdma_size = DEFAULT_MAX_RDMA_SIZE;
+               sport->port_attrib.srp_max_rsp_size = DEFAULT_MAX_RSP_SIZE;
+               sport->port_attrib.srp_sq_size = DEF_SRPT_SQ_SIZE;
+               INIT_WORK(&sport->work, srpt_refresh_port_work);
+               INIT_LIST_HEAD(&sport->port_acl_list);
+               spin_lock_init(&sport->port_acl_lock);
+
+               if (srpt_refresh_port(sport)) {
+                       printk(KERN_ERR "MAD registration failed for %s-%d.\n",
+                              srpt_sdev_name(sdev), i);
+                       goto err_ring;
+               }
+               snprintf(sport->port_guid, sizeof(sport->port_guid),
+                       "0x%016llx%016llx",
+                       be64_to_cpu(sport->gid.global.subnet_prefix),
+                       be64_to_cpu(sport->gid.global.interface_id));
+       }
+
+       spin_lock(&srpt_dev_lock);
+       list_add_tail(&sdev->list, &srpt_dev_list);
+       spin_unlock(&srpt_dev_lock);
+
+out:
+       ib_set_client_data(device, &srpt_client, sdev);
+       pr_debug("added %s.\n", device->name);
+       return;
+
+err_ring:
+       srpt_free_ioctx_ring((struct srpt_ioctx **)sdev->ioctx_ring, sdev,
+                            sdev->srq_size, srp_max_req_size,
+                            DMA_FROM_DEVICE);
+err_event:
+       ib_unregister_event_handler(&sdev->event_handler);
+err_cm:
+       ib_destroy_cm_id(sdev->cm_id);
+err_srq:
+       ib_destroy_srq(sdev->srq);
+err_mr:
+       ib_dereg_mr(sdev->mr);
+err_pd:
+       ib_dealloc_pd(sdev->pd);
+free_dev:
+       kfree(sdev);
+err:
+       sdev = NULL;
+       printk(KERN_INFO "%s(%s) failed.\n", __func__, device->name);
+       goto out;
+}
+
+/**
+ * srpt_remove_one() - InfiniBand device removal callback function.
+ */
+static void srpt_remove_one(struct ib_device *device)
+{
+       struct srpt_device *sdev;
+       int i;
+
+       sdev = ib_get_client_data(device, &srpt_client);
+       if (!sdev) {
+               printk(KERN_INFO "%s(%s): nothing to do.\n", __func__,
+                      device->name);
+               return;
+       }
+
+       srpt_unregister_mad_agent(sdev);
+
+       ib_unregister_event_handler(&sdev->event_handler);
+
+       /* Cancel any work queued by the just unregistered IB event handler. */
+       for (i = 0; i < sdev->device->phys_port_cnt; i++)
+               cancel_work_sync(&sdev->port[i].work);
+
+       ib_destroy_cm_id(sdev->cm_id);
+
+       /*
+        * Unregistering a target must happen after destroying sdev->cm_id
+        * such that no new SRP_LOGIN_REQ information units can arrive while
+        * destroying the target.
+        */
+       spin_lock(&srpt_dev_lock);
+       list_del(&sdev->list);
+       spin_unlock(&srpt_dev_lock);
+       srpt_release_sdev(sdev);
+
+       ib_destroy_srq(sdev->srq);
+       ib_dereg_mr(sdev->mr);
+       ib_dealloc_pd(sdev->pd);
+
+       srpt_free_ioctx_ring((struct srpt_ioctx **)sdev->ioctx_ring, sdev,
+                            sdev->srq_size, srp_max_req_size, DMA_FROM_DEVICE);
+       sdev->ioctx_ring = NULL;
+       kfree(sdev);
+}
+
+static struct ib_client srpt_client = {
+       .name = DRV_NAME,
+       .add = srpt_add_one,
+       .remove = srpt_remove_one
+};
+
+static int srpt_check_true(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static int srpt_check_false(struct se_portal_group *se_tpg)
+{
+       return 0;
+}
+
+static char *srpt_get_fabric_name(void)
+{
+       return "srpt";
+}
+
+static u8 srpt_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+       return SCSI_TRANSPORTID_PROTOCOLID_SRP;
+}
+
+static char *srpt_get_fabric_wwn(struct se_portal_group *tpg)
+{
+       struct srpt_port *sport = container_of(tpg, struct srpt_port, port_tpg_1);
+
+       return sport->port_guid;
+}
+
+static u16 srpt_get_tag(struct se_portal_group *tpg)
+{
+       return 1;
+}
+
+static u32 srpt_get_default_depth(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static u32 srpt_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 srpt_node_acl *nacl;
+       struct spc_rdma_transport_id *tr_id;
+
+       nacl = container_of(se_nacl, struct srpt_node_acl, nacl);
+       tr_id = (void *)buf;
+       tr_id->protocol_identifier = SCSI_TRANSPORTID_PROTOCOLID_SRP;
+       memcpy(tr_id->i_port_id, nacl->i_port_id, sizeof(tr_id->i_port_id));
+       return sizeof(*tr_id);
+}
+
+static u32 srpt_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)
+{
+       *format_code = 0;
+       return sizeof(struct spc_rdma_transport_id);
+}
+
+static char *srpt_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
+                                           const char *buf, u32 *out_tid_len,
+                                           char **port_nexus_ptr)
+{
+       struct spc_rdma_transport_id *tr_id;
+
+       *port_nexus_ptr = NULL;
+       *out_tid_len = sizeof(struct spc_rdma_transport_id);
+       tr_id = (void *)buf;
+       return (char *)tr_id->i_port_id;
+}
+
+static struct se_node_acl *srpt_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+       struct srpt_node_acl *nacl;
+
+       nacl = kzalloc(sizeof(struct srpt_node_acl), GFP_KERNEL);
+       if (!nacl) {
+               printk(KERN_ERR "Unable to alocate struct srpt_node_acl\n");
+               return NULL;
+       }
+
+       return &nacl->nacl;
+}
+
+static void srpt_release_fabric_acl(struct se_portal_group *se_tpg,
+                                   struct se_node_acl *se_nacl)
+{
+       struct srpt_node_acl *nacl;
+
+       nacl = container_of(se_nacl, struct srpt_node_acl, nacl);
+       kfree(nacl);
+}
+
+static u32 srpt_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static void srpt_release_cmd(struct se_cmd *se_cmd)
+{
+}
+
+/**
+ * srpt_shutdown_session() - Whether or not a session may be shut down.
+ */
+static int srpt_shutdown_session(struct se_session *se_sess)
+{
+       return true;
+}
+
+/**
+ * srpt_close_session() - Forcibly close a session.
+ *
+ * Callback function invoked by the TCM core to clean up sessions associated
+ * with a node ACL when the user invokes
+ * rmdir /sys/kernel/config/target/$driver/$port/$tpg/acls/$i_port_id
+ */
+static void srpt_close_session(struct se_session *se_sess)
+{
+       DECLARE_COMPLETION_ONSTACK(release_done);
+       struct srpt_rdma_ch *ch;
+       struct srpt_device *sdev;
+       int res;
+
+       ch = se_sess->fabric_sess_ptr;
+       WARN_ON(ch->sess != se_sess);
+
+       pr_debug("ch %p state %d\n", ch, srpt_get_ch_state(ch));
+
+       sdev = ch->sport->sdev;
+       spin_lock_irq(&sdev->spinlock);
+       BUG_ON(ch->release_done);
+       ch->release_done = &release_done;
+       __srpt_close_ch(ch);
+       spin_unlock_irq(&sdev->spinlock);
+
+       res = wait_for_completion_timeout(&release_done, 60 * HZ);
+       WARN_ON(res <= 0);
+}
+
+/**
+ * To do: Find out whether stop_session() has a meaning for transports
+ * other than iSCSI.
+ */
+static void srpt_stop_session(struct se_session *se_sess, int sess_sleep,
+                             int conn_sleep)
+{
+}
+
+static void srpt_reset_nexus(struct se_session *sess)
+{
+       printk(KERN_ERR "This is the SRP protocol, not iSCSI\n");
+}
+
+static int srpt_sess_logged_in(struct se_session *se_sess)
+{
+       return true;
+}
+
+/**
+ * srpt_sess_get_index() - Return the value of scsiAttIntrPortIndex (SCSI-MIB).
+ *
+ * A quote from RFC 4455 (SCSI-MIB) about this MIB object:
+ * This object represents an arbitrary integer used to uniquely identify a
+ * particular attached remote initiator port to a particular SCSI target port
+ * within a particular SCSI target device within a particular SCSI instance.
+ */
+static u32 srpt_sess_get_index(struct se_session *se_sess)
+{
+       return 0;
+}
+
+static void srpt_set_default_node_attrs(struct se_node_acl *nacl)
+{
+}
+
+static u32 srpt_get_task_tag(struct se_cmd *se_cmd)
+{
+       struct srpt_send_ioctx *ioctx;
+
+       ioctx = container_of(se_cmd, struct srpt_send_ioctx, cmd);
+       return ioctx->tag;
+}
+
+/* Note: only used from inside debug printk's by the TCM core. */
+static int srpt_get_tcm_cmd_state(struct se_cmd *se_cmd)
+{
+       struct srpt_send_ioctx *ioctx;
+
+       ioctx = container_of(se_cmd, struct srpt_send_ioctx, cmd);
+       return srpt_get_cmd_state(ioctx);
+}
+
+static u16 srpt_set_fabric_sense_len(struct se_cmd *cmd, u32 sense_length)
+{
+       return 0;
+}
+
+static u16 srpt_get_fabric_sense_len(void)
+{
+       return 0;
+}
+
+static int srpt_is_state_remove(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+/**
+ * srpt_parse_i_port_id() - Parse an initiator port ID.
+ * @name: ASCII representation of a 128-bit initiator port ID.
+ * @i_port_id: Binary 128-bit port ID.
+ */
+static int srpt_parse_i_port_id(u8 i_port_id[16], const char *name)
+{
+       const char *p;
+       unsigned len, count, leading_zero_bytes;
+       int ret, rc;
+
+       p = name;
+       if (strnicmp(p, "0x", 2) == 0)
+               p += 2;
+       ret = -EINVAL;
+       len = strlen(p);
+       if (len % 2)
+               goto out;
+       count = min(len / 2, 16U);
+       leading_zero_bytes = 16 - count;
+       memset(i_port_id, 0, leading_zero_bytes);
+       rc = hex2bin(i_port_id + leading_zero_bytes, p, count);
+       if (rc < 0)
+               pr_debug("hex2bin failed for srpt_parse_i_port_id: %d\n", rc);
+       ret = 0;
+out:
+       return ret;
+}
+
+/*
+ * configfs callback function invoked for
+ * mkdir /sys/kernel/config/target/$driver/$port/$tpg/acls/$i_port_id
+ */
+static struct se_node_acl *srpt_make_nodeacl(struct se_portal_group *tpg,
+                                            struct config_group *group,
+                                            const char *name)
+{
+       struct srpt_port *sport = container_of(tpg, struct srpt_port, port_tpg_1);
+       struct se_node_acl *se_nacl, *se_nacl_new;
+       struct srpt_node_acl *nacl;
+       int ret = 0;
+       u32 nexus_depth = 1;
+       u8 i_port_id[16];
+
+       if (srpt_parse_i_port_id(i_port_id, name) < 0) {
+               printk(KERN_ERR "invalid initiator port ID %s\n", name);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       se_nacl_new = srpt_alloc_fabric_acl(tpg);
+       if (!se_nacl_new) {
+               ret = -ENOMEM;
+               goto err;
+       }
+       /*
+        * nacl_new may be released by core_tpg_add_initiator_node_acl()
+        * when converting a node ACL from demo mode to explict
+        */
+       se_nacl = core_tpg_add_initiator_node_acl(tpg, se_nacl_new, name,
+                                                 nexus_depth);
+       if (IS_ERR(se_nacl)) {
+               ret = PTR_ERR(se_nacl);
+               goto err;
+       }
+       /* Locate our struct srpt_node_acl and set sdev and i_port_id. */
+       nacl = container_of(se_nacl, struct srpt_node_acl, nacl);
+       memcpy(&nacl->i_port_id[0], &i_port_id[0], 16);
+       nacl->sport = sport;
+
+       spin_lock_irq(&sport->port_acl_lock);
+       list_add_tail(&nacl->list, &sport->port_acl_list);
+       spin_unlock_irq(&sport->port_acl_lock);
+
+       return se_nacl;
+err:
+       return ERR_PTR(ret);
+}
+
+/*
+ * configfs callback function invoked for
+ * rmdir /sys/kernel/config/target/$driver/$port/$tpg/acls/$i_port_id
+ */
+static void srpt_drop_nodeacl(struct se_node_acl *se_nacl)
+{
+       struct srpt_node_acl *nacl;
+       struct srpt_device *sdev;
+       struct srpt_port *sport;
+
+       nacl = container_of(se_nacl, struct srpt_node_acl, nacl);
+       sport = nacl->sport;
+       sdev = sport->sdev;
+       spin_lock_irq(&sport->port_acl_lock);
+       list_del(&nacl->list);
+       spin_unlock_irq(&sport->port_acl_lock);
+       core_tpg_del_initiator_node_acl(&sport->port_tpg_1, se_nacl, 1);
+       srpt_release_fabric_acl(NULL, se_nacl);
+}
+
+static ssize_t srpt_tpg_attrib_show_srp_max_rdma_size(
+       struct se_portal_group *se_tpg,
+       char *page)
+{
+       struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
+
+       return sprintf(page, "%u\n", sport->port_attrib.srp_max_rdma_size);
+}
+
+static ssize_t srpt_tpg_attrib_store_srp_max_rdma_size(
+       struct se_portal_group *se_tpg,
+       const char *page,
+       size_t count)
+{
+       struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
+       unsigned long val;
+       int ret;
+
+       ret = strict_strtoul(page, 0, &val);
+       if (ret < 0) {
+               pr_err("strict_strtoul() failed with ret: %d\n", ret);
+               return -EINVAL;
+       }
+       if (val > MAX_SRPT_RDMA_SIZE) {
+               pr_err("val: %lu exceeds MAX_SRPT_RDMA_SIZE: %d\n", val,
+                       MAX_SRPT_RDMA_SIZE);
+               return -EINVAL;
+       }
+       if (val < DEFAULT_MAX_RDMA_SIZE) {
+               pr_err("val: %lu smaller than DEFAULT_MAX_RDMA_SIZE: %d\n",
+                       val, DEFAULT_MAX_RDMA_SIZE);
+               return -EINVAL;
+       }
+       sport->port_attrib.srp_max_rdma_size = val;
+
+       return count;
+}
+
+TF_TPG_ATTRIB_ATTR(srpt, srp_max_rdma_size, S_IRUGO | S_IWUSR);
+
+static ssize_t srpt_tpg_attrib_show_srp_max_rsp_size(
+       struct se_portal_group *se_tpg,
+       char *page)
+{
+       struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
+
+       return sprintf(page, "%u\n", sport->port_attrib.srp_max_rsp_size);
+}
+
+static ssize_t srpt_tpg_attrib_store_srp_max_rsp_size(
+       struct se_portal_group *se_tpg,
+       const char *page,
+       size_t count)
+{
+       struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
+       unsigned long val;
+       int ret;
+
+       ret = strict_strtoul(page, 0, &val);
+       if (ret < 0) {
+               pr_err("strict_strtoul() failed with ret: %d\n", ret);
+               return -EINVAL;
+       }
+       if (val > MAX_SRPT_RSP_SIZE) {
+               pr_err("val: %lu exceeds MAX_SRPT_RSP_SIZE: %d\n", val,
+                       MAX_SRPT_RSP_SIZE);
+               return -EINVAL;
+       }
+       if (val < MIN_MAX_RSP_SIZE) {
+               pr_err("val: %lu smaller than MIN_MAX_RSP_SIZE: %d\n", val,
+                       MIN_MAX_RSP_SIZE);
+               return -EINVAL;
+       }
+       sport->port_attrib.srp_max_rsp_size = val;
+
+       return count;
+}
+
+TF_TPG_ATTRIB_ATTR(srpt, srp_max_rsp_size, S_IRUGO | S_IWUSR);
+
+static ssize_t srpt_tpg_attrib_show_srp_sq_size(
+       struct se_portal_group *se_tpg,
+       char *page)
+{
+       struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
+
+       return sprintf(page, "%u\n", sport->port_attrib.srp_sq_size);
+}
+
+static ssize_t srpt_tpg_attrib_store_srp_sq_size(
+       struct se_portal_group *se_tpg,
+       const char *page,
+       size_t count)
+{
+       struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
+       unsigned long val;
+       int ret;
+
+       ret = strict_strtoul(page, 0, &val);
+       if (ret < 0) {
+               pr_err("strict_strtoul() failed with ret: %d\n", ret);
+               return -EINVAL;
+       }
+       if (val > MAX_SRPT_SRQ_SIZE) {
+               pr_err("val: %lu exceeds MAX_SRPT_SRQ_SIZE: %d\n", val,
+                       MAX_SRPT_SRQ_SIZE);
+               return -EINVAL;
+       }
+       if (val < MIN_SRPT_SRQ_SIZE) {
+               pr_err("val: %lu smaller than MIN_SRPT_SRQ_SIZE: %d\n", val,
+                       MIN_SRPT_SRQ_SIZE);
+               return -EINVAL;
+       }
+       sport->port_attrib.srp_sq_size = val;
+
+       return count;
+}
+
+TF_TPG_ATTRIB_ATTR(srpt, srp_sq_size, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *srpt_tpg_attrib_attrs[] = {
+       &srpt_tpg_attrib_srp_max_rdma_size.attr,
+       &srpt_tpg_attrib_srp_max_rsp_size.attr,
+       &srpt_tpg_attrib_srp_sq_size.attr,
+       NULL,
+};
+
+static ssize_t srpt_tpg_show_enable(
+       struct se_portal_group *se_tpg,
+       char *page)
+{
+       struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
+
+       return snprintf(page, PAGE_SIZE, "%d\n", (sport->enabled) ? 1: 0);
+}
+
+static ssize_t srpt_tpg_store_enable(
+       struct se_portal_group *se_tpg,
+       const char *page,
+       size_t count)
+{
+       struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
+       unsigned long tmp;
+        int ret;
+
+       ret = strict_strtoul(page, 0, &tmp);
+       if (ret < 0) {
+               printk(KERN_ERR "Unable to extract srpt_tpg_store_enable\n");
+               return -EINVAL;
+       }
+
+       if ((tmp != 0) && (tmp != 1)) {
+               printk(KERN_ERR "Illegal value for srpt_tpg_store_enable: %lu\n", tmp);
+               return -EINVAL;
+       }
+       if (tmp == 1)
+               sport->enabled = true;
+       else
+               sport->enabled = false;
+
+       return count;
+}
+
+TF_TPG_BASE_ATTR(srpt, enable, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *srpt_tpg_attrs[] = {
+       &srpt_tpg_enable.attr,
+       NULL,
+};
+
+/**
+ * configfs callback invoked for
+ * mkdir /sys/kernel/config/target/$driver/$port/$tpg
+ */
+static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn,
+                                            struct config_group *group,
+                                            const char *name)
+{
+       struct srpt_port *sport = container_of(wwn, struct srpt_port, port_wwn);
+       int res;
+
+       /* Initialize sport->port_wwn and sport->port_tpg_1 */
+       res = core_tpg_register(&srpt_target->tf_ops, &sport->port_wwn,
+                       &sport->port_tpg_1, sport, TRANSPORT_TPG_TYPE_NORMAL);
+       if (res)
+               return ERR_PTR(res);
+
+       return &sport->port_tpg_1;
+}
+
+/**
+ * configfs callback invoked for
+ * rmdir /sys/kernel/config/target/$driver/$port/$tpg
+ */
+static void srpt_drop_tpg(struct se_portal_group *tpg)
+{
+       struct srpt_port *sport = container_of(tpg,
+                               struct srpt_port, port_tpg_1);
+
+       sport->enabled = false;
+       core_tpg_deregister(&sport->port_tpg_1);
+}
+
+/**
+ * configfs callback invoked for
+ * mkdir /sys/kernel/config/target/$driver/$port
+ */
+static struct se_wwn *srpt_make_tport(struct target_fabric_configfs *tf,
+                                     struct config_group *group,
+                                     const char *name)
+{
+       struct srpt_port *sport;
+       int ret;
+
+       sport = srpt_lookup_port(name);
+       pr_debug("make_tport(%s)\n", name);
+       ret = -EINVAL;
+       if (!sport)
+               goto err;
+
+       return &sport->port_wwn;
+
+err:
+       return ERR_PTR(ret);
+}
+
+/**
+ * configfs callback invoked for
+ * rmdir /sys/kernel/config/target/$driver/$port
+ */
+static void srpt_drop_tport(struct se_wwn *wwn)
+{
+       struct srpt_port *sport = container_of(wwn, struct srpt_port, port_wwn);
+
+       pr_debug("drop_tport(%s\n", config_item_name(&sport->port_wwn.wwn_group.cg_item));
+}
+
+static ssize_t srpt_wwn_show_attr_version(struct target_fabric_configfs *tf,
+                                             char *buf)
+{
+       return scnprintf(buf, PAGE_SIZE, "%s\n", DRV_VERSION);
+}
+
+TF_WWN_ATTR_RO(srpt, version);
+
+static struct configfs_attribute *srpt_wwn_attrs[] = {
+       &srpt_wwn_version.attr,
+       NULL,
+};
+
+static struct target_core_fabric_ops srpt_template = {
+       .get_fabric_name                = srpt_get_fabric_name,
+       .get_fabric_proto_ident         = srpt_get_fabric_proto_ident,
+       .tpg_get_wwn                    = srpt_get_fabric_wwn,
+       .tpg_get_tag                    = srpt_get_tag,
+       .tpg_get_default_depth          = srpt_get_default_depth,
+       .tpg_get_pr_transport_id        = srpt_get_pr_transport_id,
+       .tpg_get_pr_transport_id_len    = srpt_get_pr_transport_id_len,
+       .tpg_parse_pr_out_transport_id  = srpt_parse_pr_out_transport_id,
+       .tpg_check_demo_mode            = srpt_check_false,
+       .tpg_check_demo_mode_cache      = srpt_check_true,
+       .tpg_check_demo_mode_write_protect = srpt_check_true,
+       .tpg_check_prod_mode_write_protect = srpt_check_false,
+       .tpg_alloc_fabric_acl           = srpt_alloc_fabric_acl,
+       .tpg_release_fabric_acl         = srpt_release_fabric_acl,
+       .tpg_get_inst_index             = srpt_tpg_get_inst_index,
+       .release_cmd                    = srpt_release_cmd,
+       .check_stop_free                = srpt_check_stop_free,
+       .shutdown_session               = srpt_shutdown_session,
+       .close_session                  = srpt_close_session,
+       .stop_session                   = srpt_stop_session,
+       .fall_back_to_erl0              = srpt_reset_nexus,
+       .sess_logged_in                 = srpt_sess_logged_in,
+       .sess_get_index                 = srpt_sess_get_index,
+       .sess_get_initiator_sid         = NULL,
+       .write_pending                  = srpt_write_pending,
+       .write_pending_status           = srpt_write_pending_status,
+       .set_default_node_attributes    = srpt_set_default_node_attrs,
+       .get_task_tag                   = srpt_get_task_tag,
+       .get_cmd_state                  = srpt_get_tcm_cmd_state,
+       .queue_data_in                  = srpt_queue_response,
+       .queue_status                   = srpt_queue_status,
+       .queue_tm_rsp                   = srpt_queue_response,
+       .get_fabric_sense_len           = srpt_get_fabric_sense_len,
+       .set_fabric_sense_len           = srpt_set_fabric_sense_len,
+       .is_state_remove                = srpt_is_state_remove,
+       /*
+        * Setup function pointers for generic logic in
+        * target_core_fabric_configfs.c
+        */
+       .fabric_make_wwn                = srpt_make_tport,
+       .fabric_drop_wwn                = srpt_drop_tport,
+       .fabric_make_tpg                = srpt_make_tpg,
+       .fabric_drop_tpg                = srpt_drop_tpg,
+       .fabric_post_link               = NULL,
+       .fabric_pre_unlink              = NULL,
+       .fabric_make_np                 = NULL,
+       .fabric_drop_np                 = NULL,
+       .fabric_make_nodeacl            = srpt_make_nodeacl,
+       .fabric_drop_nodeacl            = srpt_drop_nodeacl,
+};
+
+/**
+ * srpt_init_module() - Kernel module initialization.
+ *
+ * Note: Since ib_register_client() registers callback functions, and since at
+ * least one of these callback functions (srpt_add_one()) calls target core
+ * functions, this driver must be registered with the target core before
+ * ib_register_client() is called.
+ */
+static int __init srpt_init_module(void)
+{
+       int ret;
+
+       ret = -EINVAL;
+       if (srp_max_req_size < MIN_MAX_REQ_SIZE) {
+               printk(KERN_ERR "invalid value %d for kernel module parameter"
+                      " srp_max_req_size -- must be at least %d.\n",
+                      srp_max_req_size, MIN_MAX_REQ_SIZE);
+               goto out;
+       }
+
+       if (srpt_srq_size < MIN_SRPT_SRQ_SIZE
+           || srpt_srq_size > MAX_SRPT_SRQ_SIZE) {
+               printk(KERN_ERR "invalid value %d for kernel module parameter"
+                      " srpt_srq_size -- must be in the range [%d..%d].\n",
+                      srpt_srq_size, MIN_SRPT_SRQ_SIZE, MAX_SRPT_SRQ_SIZE);
+               goto out;
+       }
+
+       spin_lock_init(&srpt_dev_lock);
+       INIT_LIST_HEAD(&srpt_dev_list);
+
+       ret = -ENODEV;
+       srpt_target = target_fabric_configfs_init(THIS_MODULE, "srpt");
+       if (!srpt_target) {
+               printk(KERN_ERR "couldn't register\n");
+               goto out;
+       }
+
+       srpt_target->tf_ops = srpt_template;
+
+       /* Enable SG chaining */
+       srpt_target->tf_ops.task_sg_chaining = true;
+
+       /*
+        * Set up default attribute lists.
+        */
+       srpt_target->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = srpt_wwn_attrs;
+       srpt_target->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = srpt_tpg_attrs;
+       srpt_target->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = srpt_tpg_attrib_attrs;
+       srpt_target->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
+       srpt_target->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
+       srpt_target->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+       srpt_target->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+       srpt_target->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+       srpt_target->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+
+       ret = target_fabric_configfs_register(srpt_target);
+       if (ret < 0) {
+               printk(KERN_ERR "couldn't register\n");
+               goto out_free_target;
+       }
+
+       ret = ib_register_client(&srpt_client);
+       if (ret) {
+               printk(KERN_ERR "couldn't register IB client\n");
+               goto out_unregister_target;
+       }
+
+       return 0;
+
+out_unregister_target:
+       target_fabric_configfs_deregister(srpt_target);
+       srpt_target = NULL;
+out_free_target:
+       if (srpt_target)
+               target_fabric_configfs_free(srpt_target);
+out:
+       return ret;
+}
+
+static void __exit srpt_cleanup_module(void)
+{
+       ib_unregister_client(&srpt_client);
+       target_fabric_configfs_deregister(srpt_target);
+       srpt_target = NULL;
+}
+
+module_init(srpt_init_module);
+module_exit(srpt_cleanup_module);
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h
new file mode 100644 (file)
index 0000000..b4b4bbc
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2006 - 2009 Mellanox Technology Inc.  All rights reserved.
+ * Copyright (C) 2009 - 2010 Bart Van Assche <bvanassche@acm.org>.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef IB_SRPT_H
+#define IB_SRPT_H
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_sa.h>
+#include <rdma/ib_cm.h>
+
+#include <scsi/srp.h>
+
+#include "ib_dm_mad.h"
+
+/*
+ * The prefix the ServiceName field must start with in the device management
+ * ServiceEntries attribute pair. See also the SRP specification.
+ */
+#define SRP_SERVICE_NAME_PREFIX                "SRP.T10:"
+
+enum {
+       /*
+        * SRP IOControllerProfile attributes for SRP target ports that have
+        * not been defined in <scsi/srp.h>. Source: section B.7, table B.7
+        * in the SRP specification.
+        */
+       SRP_PROTOCOL = 0x0108,
+       SRP_PROTOCOL_VERSION = 0x0001,
+       SRP_IO_SUBCLASS = 0x609e,
+       SRP_SEND_TO_IOC = 0x01,
+       SRP_SEND_FROM_IOC = 0x02,
+       SRP_RDMA_READ_FROM_IOC = 0x08,
+       SRP_RDMA_WRITE_FROM_IOC = 0x20,
+
+       /*
+        * srp_login_cmd.req_flags bitmasks. See also table 9 in the SRP
+        * specification.
+        */
+       SRP_MTCH_ACTION = 0x03, /* MULTI-CHANNEL ACTION */
+       SRP_LOSOLNT = 0x10, /* logout solicited notification */
+       SRP_CRSOLNT = 0x20, /* credit request solicited notification */
+       SRP_AESOLNT = 0x40, /* asynchronous event solicited notification */
+
+       /*
+        * srp_cmd.sol_nt / srp_tsk_mgmt.sol_not bitmasks. See also tables
+        * 18 and 20 in the SRP specification.
+        */
+       SRP_SCSOLNT = 0x02, /* SCSOLNT = successful solicited notification */
+       SRP_UCSOLNT = 0x04, /* UCSOLNT = unsuccessful solicited notification */
+
+       /*
+        * srp_rsp.sol_not / srp_t_logout.sol_not bitmasks. See also tables
+        * 16 and 22 in the SRP specification.
+        */
+       SRP_SOLNT = 0x01, /* SOLNT = solicited notification */
+
+       /* See also table 24 in the SRP specification. */
+       SRP_TSK_MGMT_SUCCESS = 0x00,
+       SRP_TSK_MGMT_FUNC_NOT_SUPP = 0x04,
+       SRP_TSK_MGMT_FAILED = 0x05,
+
+       /* See also table 21 in the SRP specification. */
+       SRP_CMD_SIMPLE_Q = 0x0,
+       SRP_CMD_HEAD_OF_Q = 0x1,
+       SRP_CMD_ORDERED_Q = 0x2,
+       SRP_CMD_ACA = 0x4,
+
+       SRP_LOGIN_RSP_MULTICHAN_NO_CHAN = 0x0,
+       SRP_LOGIN_RSP_MULTICHAN_TERMINATED = 0x1,
+       SRP_LOGIN_RSP_MULTICHAN_MAINTAINED = 0x2,
+
+       SRPT_DEF_SG_TABLESIZE = 128,
+       SRPT_DEF_SG_PER_WQE = 16,
+
+       MIN_SRPT_SQ_SIZE = 16,
+       DEF_SRPT_SQ_SIZE = 4096,
+       SRPT_RQ_SIZE = 128,
+       MIN_SRPT_SRQ_SIZE = 4,
+       DEFAULT_SRPT_SRQ_SIZE = 4095,
+       MAX_SRPT_SRQ_SIZE = 65535,
+       MAX_SRPT_RDMA_SIZE = 1U << 24,
+       MAX_SRPT_RSP_SIZE = 1024,
+
+       MIN_MAX_REQ_SIZE = 996,
+       DEFAULT_MAX_REQ_SIZE
+               = sizeof(struct srp_cmd)/*48*/
+               + sizeof(struct srp_indirect_buf)/*20*/
+               + 128 * sizeof(struct srp_direct_buf)/*16*/,
+
+       MIN_MAX_RSP_SIZE = sizeof(struct srp_rsp)/*36*/ + 4,
+       DEFAULT_MAX_RSP_SIZE = 256, /* leaves 220 bytes for sense data */
+
+       DEFAULT_MAX_RDMA_SIZE = 65536,
+};
+
+enum srpt_opcode {
+       SRPT_RECV,
+       SRPT_SEND,
+       SRPT_RDMA_MID,
+       SRPT_RDMA_ABORT,
+       SRPT_RDMA_READ_LAST,
+       SRPT_RDMA_WRITE_LAST,
+};
+
+static inline u64 encode_wr_id(u8 opcode, u32 idx)
+{
+       return ((u64)opcode << 32) | idx;
+}
+static inline enum srpt_opcode opcode_from_wr_id(u64 wr_id)
+{
+       return wr_id >> 32;
+}
+static inline u32 idx_from_wr_id(u64 wr_id)
+{
+       return (u32)wr_id;
+}
+
+struct rdma_iu {
+       u64             raddr;
+       u32             rkey;
+       struct ib_sge   *sge;
+       u32             sge_cnt;
+       int             mem_id;
+};
+
+/**
+ * enum srpt_command_state - SCSI command state managed by SRPT.
+ * @SRPT_STATE_NEW:           New command arrived and is being processed.
+ * @SRPT_STATE_NEED_DATA:     Processing a write or bidir command and waiting
+ *                            for data arrival.
+ * @SRPT_STATE_DATA_IN:       Data for the write or bidir command arrived and is
+ *                            being processed.
+ * @SRPT_STATE_CMD_RSP_SENT:  SRP_RSP for SRP_CMD has been sent.
+ * @SRPT_STATE_MGMT:          Processing a SCSI task management command.
+ * @SRPT_STATE_MGMT_RSP_SENT: SRP_RSP for SRP_TSK_MGMT has been sent.
+ * @SRPT_STATE_DONE:          Command processing finished successfully, command
+ *                            processing has been aborted or command processing
+ *                            failed.
+ */
+enum srpt_command_state {
+       SRPT_STATE_NEW           = 0,
+       SRPT_STATE_NEED_DATA     = 1,
+       SRPT_STATE_DATA_IN       = 2,
+       SRPT_STATE_CMD_RSP_SENT  = 3,
+       SRPT_STATE_MGMT          = 4,
+       SRPT_STATE_MGMT_RSP_SENT = 5,
+       SRPT_STATE_DONE          = 6,
+};
+
+/**
+ * struct srpt_ioctx - Shared SRPT I/O context information.
+ * @buf:   Pointer to the buffer.
+ * @dma:   DMA address of the buffer.
+ * @index: Index of the I/O context in its ioctx_ring array.
+ */
+struct srpt_ioctx {
+       void                    *buf;
+       dma_addr_t              dma;
+       uint32_t                index;
+};
+
+/**
+ * struct srpt_recv_ioctx - SRPT receive I/O context.
+ * @ioctx:     See above.
+ * @wait_list: Node for insertion in srpt_rdma_ch.cmd_wait_list.
+ */
+struct srpt_recv_ioctx {
+       struct srpt_ioctx       ioctx;
+       struct list_head        wait_list;
+};
+
+/**
+ * struct srpt_send_ioctx - SRPT send I/O context.
+ * @ioctx:       See above.
+ * @ch:          Channel pointer.
+ * @free_list:   Node in srpt_rdma_ch.free_list.
+ * @n_rbuf:      Number of data buffers in the received SRP command.
+ * @rbufs:       Pointer to SRP data buffer array.
+ * @single_rbuf: SRP data buffer if the command has only a single buffer.
+ * @sg:          Pointer to sg-list associated with this I/O context.
+ * @sg_cnt:      SG-list size.
+ * @mapped_sg_count: ib_dma_map_sg() return value.
+ * @n_rdma_ius:  Number of elements in the rdma_ius array.
+ * @rdma_ius:    Array with information about the RDMA mapping.
+ * @tag:         Tag of the received SRP information unit.
+ * @spinlock:    Protects 'state'.
+ * @state:       I/O context state.
+ * @rdma_aborted: If initiating a multipart RDMA transfer failed, whether
+ *              the already initiated transfers have finished.
+ * @cmd:         Target core command data structure.
+ * @sense_data:  SCSI sense data.
+ */
+struct srpt_send_ioctx {
+       struct srpt_ioctx       ioctx;
+       struct srpt_rdma_ch     *ch;
+       struct kref              kref;
+       struct rdma_iu          *rdma_ius;
+       struct srp_direct_buf   *rbufs;
+       struct srp_direct_buf   single_rbuf;
+       struct scatterlist      *sg;
+       struct list_head        free_list;
+       spinlock_t              spinlock;
+       enum srpt_command_state state;
+       bool                    rdma_aborted;
+       struct se_cmd           cmd;
+       struct completion       tx_done;
+       u64                     tag;
+       int                     sg_cnt;
+       int                     mapped_sg_count;
+       u16                     n_rdma_ius;
+       u8                      n_rdma;
+       u8                      n_rbuf;
+       bool                    queue_status_only;
+       u8                      sense_data[SCSI_SENSE_BUFFERSIZE];
+};
+
+/**
+ * enum rdma_ch_state - SRP channel state.
+ * @CH_CONNECTING:      QP is in RTR state; waiting for RTU.
+ * @CH_LIVE:            QP is in RTS state.
+ * @CH_DISCONNECTING:    DREQ has been received; waiting for DREP
+ *                       or DREQ has been send and waiting for DREP
+ *                       or .
+ * @CH_DRAINING:        QP is in ERR state; waiting for last WQE event.
+ * @CH_RELEASING:       Last WQE event has been received; releasing resources.
+ */
+enum rdma_ch_state {
+       CH_CONNECTING,
+       CH_LIVE,
+       CH_DISCONNECTING,
+       CH_DRAINING,
+       CH_RELEASING
+};
+
+/**
+ * struct srpt_rdma_ch - RDMA channel.
+ * @wait_queue:    Allows the kernel thread to wait for more work.
+ * @thread:        Kernel thread that processes the IB queues associated with
+ *                 the channel.
+ * @cm_id:         IB CM ID associated with the channel.
+ * @qp:            IB queue pair used for communicating over this channel.
+ * @cq:            IB completion queue for this channel.
+ * @rq_size:       IB receive queue size.
+ * @rsp_size      IB response message size in bytes.
+ * @sq_wr_avail:   number of work requests available in the send queue.
+ * @sport:         pointer to the information of the HCA port used by this
+ *                 channel.
+ * @i_port_id:     128-bit initiator port identifier copied from SRP_LOGIN_REQ.
+ * @t_port_id:     128-bit target port identifier copied from SRP_LOGIN_REQ.
+ * @max_ti_iu_len: maximum target-to-initiator information unit length.
+ * @req_lim:       request limit: maximum number of requests that may be sent
+ *                 by the initiator without having received a response.
+ * @req_lim_delta: Number of credits not yet sent back to the initiator.
+ * @spinlock:      Protects free_list and state.
+ * @free_list:     Head of list with free send I/O contexts.
+ * @state:         channel state. See also enum rdma_ch_state.
+ * @ioctx_ring:    Send ring.
+ * @wc:            IB work completion array for srpt_process_completion().
+ * @list:          Node for insertion in the srpt_device.rch_list list.
+ * @cmd_wait_list: List of SCSI commands that arrived before the RTU event. This
+ *                 list contains struct srpt_ioctx elements and is protected
+ *                 against concurrent modification by the cm_id spinlock.
+ * @sess:          Session information associated with this SRP channel.
+ * @sess_name:     Session name.
+ * @release_work:  Allows scheduling of srpt_release_channel().
+ * @release_done:  Enables waiting for srpt_release_channel() completion.
+ */
+struct srpt_rdma_ch {
+       wait_queue_head_t       wait_queue;
+       struct task_struct      *thread;
+       struct ib_cm_id         *cm_id;
+       struct ib_qp            *qp;
+       struct ib_cq            *cq;
+       int                     rq_size;
+       u32                     rsp_size;
+       atomic_t                sq_wr_avail;
+       struct srpt_port        *sport;
+       u8                      i_port_id[16];
+       u8                      t_port_id[16];
+       int                     max_ti_iu_len;
+       atomic_t                req_lim;
+       atomic_t                req_lim_delta;
+       spinlock_t              spinlock;
+       struct list_head        free_list;
+       enum rdma_ch_state      state;
+       struct srpt_send_ioctx  **ioctx_ring;
+       struct ib_wc            wc[16];
+       struct list_head        list;
+       struct list_head        cmd_wait_list;
+       struct se_session       *sess;
+       u8                      sess_name[36];
+       struct work_struct      release_work;
+       struct completion       *release_done;
+};
+
+/**
+ * struct srpt_port_attib - Attributes for SRPT port
+ * @srp_max_rdma_size: Maximum size of SRP RDMA transfers for new connections.
+ * @srp_max_rsp_size: Maximum size of SRP response messages in bytes.
+ * @srp_sq_size: Shared receive queue (SRQ) size.
+ */
+struct srpt_port_attrib {
+       u32                     srp_max_rdma_size;
+       u32                     srp_max_rsp_size;
+       u32                     srp_sq_size;
+};
+
+/**
+ * struct srpt_port - Information associated by SRPT with a single IB port.
+ * @sdev:      backpointer to the HCA information.
+ * @mad_agent: per-port management datagram processing information.
+ * @enabled:   Whether or not this target port is enabled.
+ * @port_guid: ASCII representation of Port GUID
+ * @port:      one-based port number.
+ * @sm_lid:    cached value of the port's sm_lid.
+ * @lid:       cached value of the port's lid.
+ * @gid:       cached value of the port's gid.
+ * @port_acl_lock spinlock for port_acl_list:
+ * @work:      work structure for refreshing the aforementioned cached values.
+ * @port_tpg_1 Target portal group = 1 data.
+ * @port_wwn:  Target core WWN data.
+ * @port_acl_list: Head of the list with all node ACLs for this port.
+ */
+struct srpt_port {
+       struct srpt_device      *sdev;
+       struct ib_mad_agent     *mad_agent;
+       bool                    enabled;
+       u8                      port_guid[64];
+       u8                      port;
+       u16                     sm_lid;
+       u16                     lid;
+       union ib_gid            gid;
+       spinlock_t              port_acl_lock;
+       struct work_struct      work;
+       struct se_portal_group  port_tpg_1;
+       struct se_wwn           port_wwn;
+       struct list_head        port_acl_list;
+       struct srpt_port_attrib port_attrib;
+};
+
+/**
+ * struct srpt_device - Information associated by SRPT with a single HCA.
+ * @device:        Backpointer to the struct ib_device managed by the IB core.
+ * @pd:            IB protection domain.
+ * @mr:            L_Key (local key) with write access to all local memory.
+ * @srq:           Per-HCA SRQ (shared receive queue).
+ * @cm_id:         Connection identifier.
+ * @dev_attr:      Attributes of the InfiniBand device as obtained during the
+ *                 ib_client.add() callback.
+ * @srq_size:      SRQ size.
+ * @ioctx_ring:    Per-HCA SRQ.
+ * @rch_list:      Per-device channel list -- see also srpt_rdma_ch.list.
+ * @ch_releaseQ:   Enables waiting for removal from rch_list.
+ * @spinlock:      Protects rch_list and tpg.
+ * @port:          Information about the ports owned by this HCA.
+ * @event_handler: Per-HCA asynchronous IB event handler.
+ * @list:          Node in srpt_dev_list.
+ */
+struct srpt_device {
+       struct ib_device        *device;
+       struct ib_pd            *pd;
+       struct ib_mr            *mr;
+       struct ib_srq           *srq;
+       struct ib_cm_id         *cm_id;
+       struct ib_device_attr   dev_attr;
+       int                     srq_size;
+       struct srpt_recv_ioctx  **ioctx_ring;
+       struct list_head        rch_list;
+       wait_queue_head_t       ch_releaseQ;
+       spinlock_t              spinlock;
+       struct srpt_port        port[2];
+       struct ib_event_handler event_handler;
+       struct list_head        list;
+};
+
+/**
+ * struct srpt_node_acl - Per-initiator ACL data (managed via configfs).
+ * @i_port_id: 128-bit SRP initiator port ID.
+ * @sport:     port information.
+ * @nacl:      Target core node ACL information.
+ * @list:      Element of the per-HCA ACL list.
+ */
+struct srpt_node_acl {
+       u8                      i_port_id[16];
+       struct srpt_port        *sport;
+       struct se_node_acl      nacl;
+       struct list_head        list;
+};
+
+/*
+ * SRP-releated SCSI persistent reservation definitions.
+ *
+ * See also SPC4r28, section 7.6.1 (Protocol specific parameters introduction).
+ * See also SPC4r28, section 7.6.4.5 (TransportID for initiator ports using
+ * SCSI over an RDMA interface).
+ */
+
+enum {
+       SCSI_TRANSPORTID_PROTOCOLID_SRP = 4,
+};
+
+struct spc_rdma_transport_id {
+       uint8_t protocol_identifier;
+       uint8_t reserved[7];
+       uint8_t i_port_id[16];
+};
+
+#endif                         /* IB_SRPT_H */
index 32bbd4c77b7c5da7f6ef4e4b18871f0df2ebc3bd..fd7a0d5bc94d94d21fc3e21f5f23c52c1b512929 100644 (file)
 #define XTYPE_XBOX360W    2
 #define XTYPE_UNKNOWN     3
 
-static int dpad_to_buttons;
+static bool dpad_to_buttons;
 module_param(dpad_to_buttons, bool, S_IRUGO);
 MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
 
-static int triggers_to_buttons;
+static bool triggers_to_buttons;
 module_param(triggers_to_buttons, bool, S_IRUGO);
 MODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads");
 
-static int sticks_to_null;
+static bool sticks_to_null;
 module_param(sticks_to_null, bool, S_IRUGO);
 MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads");
 
index 6df5f6aa7908a9dbf649226cfb1bbc8dee6685cf..79172af164f25a5ccd913f32225dcd5e60c22760 100644 (file)
@@ -259,6 +259,19 @@ static struct platform_driver amikbd_driver = {
                .owner  = THIS_MODULE,
        },
 };
-module_platform_driver(amikbd_driver);
+
+static int __init amikbd_init(void)
+{
+       return platform_driver_probe(&amikbd_driver, amikbd_probe);
+}
+
+module_init(amikbd_init);
+
+static void __exit amikbd_exit(void)
+{
+       platform_driver_unregister(&amikbd_driver);
+}
+
+module_exit(amikbd_exit);
 
 MODULE_ALIAS("platform:amiga-keyboard");
index 469825247552588e46615d04d5e4221006ab9186..9d82b3aeff5e5535b5f85d4a084a410523359564 100644 (file)
@@ -328,7 +328,18 @@ static struct platform_driver davinci_ks_driver = {
        },
        .remove = __devexit_p(davinci_ks_remove),
 };
-module_platform_driver(davinci_ks_driver);
+
+static int __init davinci_ks_init(void)
+{
+       return platform_driver_probe(&davinci_ks_driver, davinci_ks_probe);
+}
+module_init(davinci_ks_init);
+
+static void __exit davinci_ks_exit(void)
+{
+       platform_driver_unregister(&davinci_ks_driver);
+}
+module_exit(davinci_ks_exit);
 
 MODULE_AUTHOR("Miguel Aguilar");
 MODULE_DESCRIPTION("Texas Instruments DaVinci Key Scan Driver");
index 5a71e55c9c54e2c6f532ef70e0cc114b49eeeb67..e35566aa102fa2b4dde8c1f193d705b13fbbd1f3 100644 (file)
@@ -390,7 +390,18 @@ static struct platform_driver ske_keypad_driver = {
        .probe = ske_keypad_probe,
        .remove = __devexit_p(ske_keypad_remove),
 };
-module_platform_driver(ske_keypad_driver);
+
+static int __init ske_keypad_init(void)
+{
+       return platform_driver_probe(&ske_keypad_driver, ske_keypad_probe);
+}
+module_init(ske_keypad_init);
+
+static void __exit ske_keypad_exit(void)
+{
+       platform_driver_unregister(&ske_keypad_driver);
+}
+module_exit(ske_keypad_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Naveen Kumar <naveen.gaddipati@stericsson.com> / Sundar Iyer <sundar.iyer@stericsson.com>");
index 79d9016336355a4885681ca68a2a0249b3b5894e..350fd0c385d2449115ea332fdf8f27601c46485c 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/slab.h>
 
 /**
index 19a68828cd865d0812ae57e2305dea1432bee912..38e4b507b94cc629ef330cf173b1b41d3765e904 100644 (file)
@@ -107,14 +107,25 @@ static int __exit twl4030_pwrbutton_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver twl4030_pwrbutton_driver = {
-       .probe          = twl4030_pwrbutton_probe,
        .remove         = __exit_p(twl4030_pwrbutton_remove),
        .driver         = {
                .name   = "twl4030_pwrbutton",
                .owner  = THIS_MODULE,
        },
 };
-module_platform_driver(twl4030_pwrbutton_driver);
+
+static int __init twl4030_pwrbutton_init(void)
+{
+       return platform_driver_probe(&twl4030_pwrbutton_driver,
+                       twl4030_pwrbutton_probe);
+}
+module_init(twl4030_pwrbutton_init);
+
+static void __exit twl4030_pwrbutton_exit(void)
+{
+       platform_driver_unregister(&twl4030_pwrbutton_driver);
+}
+module_exit(twl4030_pwrbutton_exit);
 
 MODULE_ALIAS("platform:twl4030_pwrbutton");
 MODULE_DESCRIPTION("Triton2 Power Button");
index 52b41934898379a1d40dcea6bd283a8f50ca8d9a..e2bdfd4bea70bbf1add272fc8c2152c2790c37b1 100644 (file)
@@ -48,7 +48,7 @@ MODULE_DESCRIPTION("Wistron laptop button driver");
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION("0.3");
 
-static int force; /* = 0; */
+static bool force; /* = 0; */
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Load even if computer is not in database");
 
index 39be7b82c046ac9b9129678631077aa5cf5e37e8..ff5f61a0fd3ad1eb071e600e5e37fb15fb4ca61a 100644 (file)
@@ -140,13 +140,25 @@ static int __exit amimouse_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver amimouse_driver = {
-       .probe = amimouse_probe,
        .remove = __exit_p(amimouse_remove),
        .driver   = {
                .name   = "amiga-mouse",
                .owner  = THIS_MODULE,
        },
 };
-module_platform_driver(amimouse_driver);
+
+static int __init amimouse_init(void)
+{
+       return platform_driver_probe(&amimouse_driver, amimouse_probe);
+}
+
+module_init(amimouse_init);
+
+static void __exit amimouse_exit(void)
+{
+       platform_driver_unregister(&amimouse_driver);
+}
+
+module_exit(amimouse_exit);
 
 MODULE_ALIAS("platform:amiga-mouse");
index cf87f8b18e34479c14bbfe49d1ca95495ecf4a5d..927e479c26494506df371e9cc4757d7b032ea3f4 100644 (file)
@@ -433,6 +433,9 @@ static void setup_events_to_report(struct input_dev *input_dev,
        __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
        __set_bit(BTN_LEFT, input_dev->keybit);
 
+       if (cfg->caps & HAS_INTEGRATED_BUTTON)
+               __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
+
        input_set_events_per_packet(input_dev, 60);
 }
 
index de7e8bc17b1f053906bfea7811bd791ed38dcd96..e6c9931f02c73176483105b494feab56b19ddacd 100644 (file)
@@ -60,7 +60,7 @@ static unsigned int psmouse_rate = 100;
 module_param_named(rate, psmouse_rate, uint, 0644);
 MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
 
-static unsigned int psmouse_smartscroll = 1;
+static bool psmouse_smartscroll = 1;
 module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
 MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
 
index 4b755cb5b38cfc183a02c894e623352e486750b2..1c58aafa523fd8ed699bd274378f1e8b2c21dd21 100644 (file)
 #define NO_DATA_SLEEP_MSECS    (MSEC_PER_SEC / 4)
 
 /* Control touchpad's No Deceleration option */
-static int no_decel = 1;
+static bool no_decel = 1;
 module_param(no_decel, bool, 0644);
 MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)");
 
 /* Control touchpad's Reduced Reporting option */
-static int reduce_report;
+static bool reduce_report;
 module_param(reduce_report, bool, 0644);
 MODULE_PARM_DESC(reduce_report, "Reduced Reporting. Default = 0 (off)");
 
 /* Control touchpad's No Filter option */
-static int no_filter;
+static bool no_filter;
 module_param(no_filter, bool, 0644);
 MODULE_PARM_DESC(no_filter, "No Filter. Default = 0 (off)");
 
index 421a7442e4641f92e73aa231cefe1de805a87fd2..95280f9207e14cf4d552aaa7cf8b7b3704fc123f 100644 (file)
@@ -358,7 +358,19 @@ static struct platform_driver psif_driver = {
        .suspend        = psif_suspend,
        .resume         = psif_resume,
 };
-module_platform_driver(psif_driver);
+
+static int __init psif_init(void)
+{
+       return platform_driver_probe(&psif_driver, psif_probe);
+}
+
+static void __exit psif_exit(void)
+{
+       platform_driver_unregister(&psif_driver);
+}
+
+module_init(psif_init);
+module_exit(psif_exit);
 
 MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
 MODULE_DESCRIPTION("Atmel AVR32 PSIF PS/2 driver");
index 979c443bf1efa78fc150cd190073e111d907b842..be3316073ae7db4f8a21c80f0207893ea3dd433d 100644 (file)
@@ -105,7 +105,7 @@ EXPORT_SYMBOL(__hp_sdc_enqueue_transaction);
 EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
 EXPORT_SYMBOL(hp_sdc_dequeue_transaction);
 
-static unsigned int hp_sdc_disabled;
+static bool hp_sdc_disabled;
 module_param_named(no_hpsdc, hp_sdc_disabled, bool, 0);
 MODULE_PARM_DESC(no_hpsdc, "Do not enable HP SDC driver.");
 
index 4d4cd142bbbb126455e739b083750c547af4bfaa..8250299fd64ff37d78d97910a702f00710157532 100644 (file)
@@ -220,11 +220,11 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
                        goto out;
                }
                written++;
-       };
+       }
 
 out:
        mutex_unlock(&serio_raw_mutex);
-       return written;
+       return written ?: retval;
 }
 
 static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
@@ -237,9 +237,9 @@ static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
 
        mask = serio_raw->dead ? POLLHUP | POLLERR : POLLOUT | POLLWRNORM;
        if (serio_raw->head != serio_raw->tail)
-               return POLLIN | POLLRDNORM;
+               mask |= POLLIN | POLLRDNORM;
 
-       return 0;
+       return mask;
 }
 
 static const struct file_operations serio_raw_fops = {
index d016cb26d12523f6eb24214aa10a7e1f70a286ee..8034cbb20f74c8d8bcd426aa27b998e8bd8fcf20 100644 (file)
@@ -429,7 +429,18 @@ static struct platform_driver atmel_wm97xx_driver = {
        .suspend        = atmel_wm97xx_suspend,
        .resume         = atmel_wm97xx_resume,
 };
-module_platform_driver(atmel_wm97xx_driver);
+
+static int __init atmel_wm97xx_init(void)
+{
+       return platform_driver_probe(&atmel_wm97xx_driver, atmel_wm97xx_probe);
+}
+module_init(atmel_wm97xx_init);
+
+static void __exit atmel_wm97xx_exit(void)
+{
+       platform_driver_unregister(&atmel_wm97xx_driver);
+}
+module_exit(atmel_wm97xx_exit);
 
 MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
 MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32");
index 7f8f538a9806d067f7aef37943d8050d041f50ac..1df19bb8534ab4b0ae9aa0a6678ea3d2a03ea912 100644 (file)
 #include <linux/input/eeti_ts.h>
 #include <linux/slab.h>
 
-static int flip_x;
+static bool flip_x;
 module_param(flip_x, bool, 0644);
 MODULE_PARM_DESC(flip_x, "flip x coordinate");
 
-static int flip_y;
+static bool flip_y;
 module_param(flip_y, bool, 0644);
 MODULE_PARM_DESC(flip_y, "flip y coordinate");
 
index 81e33862394443261d3958ae60d17bb2ec98fbc9..d13143b68b3e0b32f7a9e1623c113f14a74de13f 100644 (file)
@@ -40,10 +40,10 @@ MODULE_LICENSE("GPL");
 #define X_AXIS_MAX             2040
 #define Y_AXIS_MAX             2040
 
-static int invert_x;
+static bool invert_x;
 module_param(invert_x, bool, 0644);
 MODULE_PARM_DESC(invert_x, "If set, X axis is inverted");
-static int invert_y;
+static bool invert_y;
 module_param(invert_y, bool, 0644);
 MODULE_PARM_DESC(invert_y, "If set, Y axis is inverted");
 
index 68f86f7dabbce712f80ebe3c6322f008bf934ea2..ede02743eac1997b426a7970f96429a486ea4059 100644 (file)
@@ -240,7 +240,18 @@ static struct platform_driver mc13783_ts_driver = {
                .name   = MC13783_TS_NAME,
        },
 };
-module_platform_driver(mc13783_ts_driver);
+
+static int __init mc13783_ts_init(void)
+{
+       return platform_driver_probe(&mc13783_ts_driver, &mc13783_ts_probe);
+}
+module_init(mc13783_ts_init);
+
+static void __exit mc13783_ts_exit(void)
+{
+       platform_driver_unregister(&mc13783_ts_driver);
+}
+module_exit(mc13783_ts_exit);
 
 MODULE_DESCRIPTION("MC13783 input touchscreen driver");
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
index d2b57536feeabd776e105df75433e9296444a398..46e83ad53f4399b01046ea7b3150a2ab22239813 100644 (file)
@@ -30,7 +30,7 @@
 
 #define UCB1400_TS_POLL_PERIOD 10 /* ms */
 
-static int adcsync;
+static bool adcsync;
 static int ts_delay = 55; /* us */
 static int ts_delay_pressure;  /* us */
 
index 06cef3ccc63a7d180864c7e99e4f5ad16a8b7cbc..3a5ebf452e810bde7b032650f3e942b3fd6d085e 100644 (file)
 #define DRIVER_AUTHOR          "Daniel Ritz <daniel.ritz@gmx.ch>"
 #define DRIVER_DESC            "USB Touchscreen Driver"
 
-static int swap_xy;
+static bool swap_xy;
 module_param(swap_xy, bool, 0644);
 MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
 
-static int hwcalib_xy;
+static bool hwcalib_xy;
 module_param(hwcalib_xy, bool, 0644);
 MODULE_PARM_DESC(hwcalib_xy, "If set hw-calibrated X/Y are used if available");
 
index 9c8d7aa053c5ae4d2631aa22590f1967e00562e8..a0ed668d4d2ac428d77c19c5a4f0d69fc0148bc9 100644 (file)
@@ -40,7 +40,7 @@ MODULE_DESCRIPTION("CAPI4Linux: DMA support for active AVM cards");
 MODULE_AUTHOR("Carsten Paeth");
 MODULE_LICENSE("GPL");
 
-static int suppress_pollack = 0;
+static bool suppress_pollack = 0;
 module_param(suppress_pollack, bool, 0);
 
 /* ------------------------------------------------------------- */
index d3530f6e8115350668b148377d61a85256883a0a..9743b24ef9d6f7a1cc4f41bd9c4e3ff60b036671 100644 (file)
@@ -40,7 +40,7 @@ static char *revision = "$Revision: 1.1.2.2 $";
 
 /* ------------------------------------------------------------- */
 
-static int suppress_pollack;
+static bool suppress_pollack;
 
 static struct pci_device_id c4_pci_tbl[] = {
        { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, 0, 0, (unsigned long)4 },
index 9c6650ea848ece07f2a369cbc0e7a17b26fc035b..2302fbe70ac62badd292a5e455a24042687f2b09 100644 (file)
@@ -6,7 +6,7 @@ if ISDN_I4L
 
 config ISDN_PPP
        bool "Support synchronous PPP"
-       depends on INET
+       depends on INET && NETDEVICES
        select SLHC
        help
          Over digital connections such as ISDN, there is no need to
index ca710ab278ec49788a50a483375c7de08b340a1b..023de789f2505b82f9782805c825609ce1328e91 100644 (file)
@@ -30,7 +30,7 @@ static const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCo
 static unsigned int io[] = {0,0,0,0};
 static unsigned char irq[] = {0,0,0,0};
 static unsigned long ram[] = {0,0,0,0};
-static int do_reset = 0;
+static bool do_reset = 0;
 
 module_param_array(io, int, NULL, 0);
 module_param_array(irq, int, NULL, 0);
index 897a77dfa9d7dd923ec7567c26c729e1901e1757..c957c344233f4ed283df710222492f1ee38d9bf0 100644 (file)
@@ -396,6 +396,13 @@ config LEDS_TCA6507
          LED driver chips accessed via the I2C bus.
          Driver support brightness control and hardware-assisted blinking.
 
+config LEDS_MAX8997
+       tristate "LED support for MAX8997 PMIC"
+       depends on LEDS_CLASS && MFD_MAX8997
+       help
+         This option enables support for on-chip LED drivers on
+         MAXIM MAX8997 PMIC.
+
 config LEDS_TRIGGERS
        bool "LED Trigger support"
        depends on LEDS_CLASS
index 5c9dc4b000d5d2ab9996de7909623d030e2352fa..b8a9723477f0819b2fb07e2c19a61847888945e6 100644 (file)
@@ -44,6 +44,7 @@ obj-$(CONFIG_LEDS_NS2)                        += leds-ns2.o
 obj-$(CONFIG_LEDS_NETXBIG)             += leds-netxbig.o
 obj-$(CONFIG_LEDS_ASIC3)               += leds-asic3.o
 obj-$(CONFIG_LEDS_RENESAS_TPU)         += leds-renesas-tpu.o
+obj-$(CONFIG_LEDS_MAX8997)             += leds-max8997.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
index a498135a4e80c78e8ba4fe63ba485476f3a11f46..1ed1677c916f260285d0acefa255ef7adf337802 100644 (file)
@@ -18,7 +18,7 @@ MODULE_AUTHOR("Márton Németh <nm127@freemail.hu>");
 MODULE_DESCRIPTION("Clevo mail LED driver");
 MODULE_LICENSE("GPL");
 
-static unsigned int __initdata nodetect;
+static bool __initdata nodetect;
 module_param_named(nodetect, nodetect, bool, 0);
 MODULE_PARM_DESC(nodetect, "Skip DMI hardware detection");
 
diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c
new file mode 100644 (file)
index 0000000..f4c0e37
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * leds-max8997.c - LED class driver for MAX8997 LEDs.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * Donggeun Kim <dg77.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/leds.h>
+#include <linux/mfd/max8997.h>
+#include <linux/mfd/max8997-private.h>
+#include <linux/platform_device.h>
+
+#define MAX8997_LED_FLASH_SHIFT                        3
+#define MAX8997_LED_FLASH_CUR_MASK             0xf8
+#define MAX8997_LED_MOVIE_SHIFT                        4
+#define MAX8997_LED_MOVIE_CUR_MASK             0xf0
+
+#define MAX8997_LED_FLASH_MAX_BRIGHTNESS       0x1f
+#define MAX8997_LED_MOVIE_MAX_BRIGHTNESS       0xf
+#define MAX8997_LED_NONE_MAX_BRIGHTNESS                0
+
+#define MAX8997_LED0_FLASH_MASK                        0x1
+#define MAX8997_LED0_FLASH_PIN_MASK            0x5
+#define MAX8997_LED0_MOVIE_MASK                        0x8
+#define MAX8997_LED0_MOVIE_PIN_MASK            0x28
+
+#define MAX8997_LED1_FLASH_MASK                        0x2
+#define MAX8997_LED1_FLASH_PIN_MASK            0x6
+#define MAX8997_LED1_MOVIE_MASK                        0x10
+#define MAX8997_LED1_MOVIE_PIN_MASK            0x30
+
+#define MAX8997_LED_BOOST_ENABLE_MASK          (1 << 6)
+
+struct max8997_led {
+       struct max8997_dev *iodev;
+       struct led_classdev cdev;
+       bool enabled;
+       int id;
+       enum max8997_led_mode led_mode;
+       struct mutex mutex;
+};
+
+static void max8997_led_clear_mode(struct max8997_led *led,
+                       enum max8997_led_mode mode)
+{
+       struct i2c_client *client = led->iodev->i2c;
+       u8 val = 0, mask = 0;
+       int ret;
+
+       switch (mode) {
+       case MAX8997_FLASH_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK;
+               break;
+       case MAX8997_MOVIE_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK;
+               break;
+       case MAX8997_FLASH_PIN_CONTROL_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK;
+               break;
+       case MAX8997_MOVIE_PIN_CONTROL_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK;
+               break;
+       default:
+               break;
+       }
+
+       if (mask) {
+               ret = max8997_update_reg(client,
+                               MAX8997_REG_LEN_CNTL, val, mask);
+               if (ret)
+                       dev_err(led->iodev->dev,
+                               "failed to update register(%d)\n", ret);
+       }
+}
+
+static void max8997_led_set_mode(struct max8997_led *led,
+                       enum max8997_led_mode mode)
+{
+       int ret;
+       struct i2c_client *client = led->iodev->i2c;
+       u8 mask = 0;
+
+       /* First, clear the previous mode */
+       max8997_led_clear_mode(led, led->led_mode);
+
+       switch (mode) {
+       case MAX8997_FLASH_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK;
+               led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;
+               break;
+       case MAX8997_MOVIE_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK;
+               led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;
+               break;
+       case MAX8997_FLASH_PIN_CONTROL_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK;
+               led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;
+               break;
+       case MAX8997_MOVIE_PIN_CONTROL_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK;
+               led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;
+               break;
+       default:
+               led->cdev.max_brightness = MAX8997_LED_NONE_MAX_BRIGHTNESS;
+               break;
+       }
+
+       if (mask) {
+               ret = max8997_update_reg(client,
+                               MAX8997_REG_LEN_CNTL, mask, mask);
+               if (ret)
+                       dev_err(led->iodev->dev,
+                               "failed to update register(%d)\n", ret);
+       }
+
+       led->led_mode = mode;
+}
+
+static void max8997_led_enable(struct max8997_led *led, bool enable)
+{
+       int ret;
+       struct i2c_client *client = led->iodev->i2c;
+       u8 val = 0, mask = MAX8997_LED_BOOST_ENABLE_MASK;
+
+       if (led->enabled == enable)
+               return;
+
+       val = enable ? MAX8997_LED_BOOST_ENABLE_MASK : 0;
+
+       ret = max8997_update_reg(client, MAX8997_REG_BOOST_CNTL, val, mask);
+       if (ret)
+               dev_err(led->iodev->dev,
+                       "failed to update register(%d)\n", ret);
+
+       led->enabled = enable;
+}
+
+static void max8997_led_set_current(struct max8997_led *led,
+                               enum led_brightness value)
+{
+       int ret;
+       struct i2c_client *client = led->iodev->i2c;
+       u8 val = 0, mask = 0, reg = 0;
+
+       switch (led->led_mode) {
+       case MAX8997_FLASH_MODE:
+       case MAX8997_FLASH_PIN_CONTROL_MODE:
+               val = value << MAX8997_LED_FLASH_SHIFT;
+               mask = MAX8997_LED_FLASH_CUR_MASK;
+               reg = led->id ? MAX8997_REG_FLASH2_CUR : MAX8997_REG_FLASH1_CUR;
+               break;
+       case MAX8997_MOVIE_MODE:
+       case MAX8997_MOVIE_PIN_CONTROL_MODE:
+               val = value << MAX8997_LED_MOVIE_SHIFT;
+               mask = MAX8997_LED_MOVIE_CUR_MASK;
+               reg = MAX8997_REG_MOVIE_CUR;
+               break;
+       default:
+               break;
+       }
+
+       if (mask) {
+               ret = max8997_update_reg(client, reg, val, mask);
+               if (ret)
+                       dev_err(led->iodev->dev,
+                               "failed to update register(%d)\n", ret);
+       }
+}
+
+static void max8997_led_brightness_set(struct led_classdev *led_cdev,
+                               enum led_brightness value)
+{
+       struct max8997_led *led =
+                       container_of(led_cdev, struct max8997_led, cdev);
+
+       if (value) {
+               max8997_led_set_current(led, value);
+               max8997_led_enable(led, true);
+       } else {
+               max8997_led_set_current(led, value);
+               max8997_led_enable(led, false);
+       }
+}
+
+static ssize_t max8997_led_show_mode(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct max8997_led *led =
+                       container_of(led_cdev, struct max8997_led, cdev);
+       ssize_t ret = 0;
+
+       mutex_lock(&led->mutex);
+
+       switch (led->led_mode) {
+       case MAX8997_FLASH_MODE:
+               ret += sprintf(buf, "FLASH\n");
+               break;
+       case MAX8997_MOVIE_MODE:
+               ret += sprintf(buf, "MOVIE\n");
+               break;
+       case MAX8997_FLASH_PIN_CONTROL_MODE:
+               ret += sprintf(buf, "FLASH_PIN_CONTROL\n");
+               break;
+       case MAX8997_MOVIE_PIN_CONTROL_MODE:
+               ret += sprintf(buf, "MOVIE_PIN_CONTROL\n");
+               break;
+       default:
+               ret += sprintf(buf, "NONE\n");
+               break;
+       }
+
+       mutex_unlock(&led->mutex);
+
+       return ret;
+}
+
+static ssize_t max8997_led_store_mode(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct max8997_led *led =
+                       container_of(led_cdev, struct max8997_led, cdev);
+       enum max8997_led_mode mode;
+
+       mutex_lock(&led->mutex);
+
+       if (!strncmp(buf, "FLASH_PIN_CONTROL", 17))
+               mode = MAX8997_FLASH_PIN_CONTROL_MODE;
+       else if (!strncmp(buf, "MOVIE_PIN_CONTROL", 17))
+               mode = MAX8997_MOVIE_PIN_CONTROL_MODE;
+       else if (!strncmp(buf, "FLASH", 5))
+               mode = MAX8997_FLASH_MODE;
+       else if (!strncmp(buf, "MOVIE", 5))
+               mode = MAX8997_MOVIE_MODE;
+       else
+               mode = MAX8997_NONE;
+
+       max8997_led_set_mode(led, mode);
+
+       mutex_unlock(&led->mutex);
+
+       return size;
+}
+
+static DEVICE_ATTR(mode, 0644, max8997_led_show_mode, max8997_led_store_mode);
+
+static int __devinit max8997_led_probe(struct platform_device *pdev)
+{
+       struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
+       struct max8997_led *led;
+       char name[20];
+       int ret = 0;
+
+       if (pdata == NULL) {
+               dev_err(&pdev->dev, "no platform data\n");
+               return -ENODEV;
+       }
+
+       led = kzalloc(sizeof(*led), GFP_KERNEL);
+       if (led == NULL) {
+               ret = -ENOMEM;
+               goto err_mem;
+       }
+
+       led->id = pdev->id;
+       snprintf(name, sizeof(name), "max8997-led%d", pdev->id);
+
+       led->cdev.name = name;
+       led->cdev.brightness_set = max8997_led_brightness_set;
+       led->cdev.flags |= LED_CORE_SUSPENDRESUME;
+       led->cdev.brightness = 0;
+       led->iodev = iodev;
+
+       /* initialize mode and brightness according to platform_data */
+       if (pdata->led_pdata) {
+               u8 mode = 0, brightness = 0;
+
+               mode = pdata->led_pdata->mode[led->id];
+               brightness = pdata->led_pdata->brightness[led->id];
+
+               max8997_led_set_mode(led, pdata->led_pdata->mode[led->id]);
+
+               if (brightness > led->cdev.max_brightness)
+                       brightness = led->cdev.max_brightness;
+               max8997_led_set_current(led, brightness);
+               led->cdev.brightness = brightness;
+       } else {
+               max8997_led_set_mode(led, MAX8997_NONE);
+               max8997_led_set_current(led, 0);
+       }
+
+       mutex_init(&led->mutex);
+
+       platform_set_drvdata(pdev, led);
+
+       ret = led_classdev_register(&pdev->dev, &led->cdev);
+       if (ret < 0)
+               goto err_led;
+
+       ret = device_create_file(led->cdev.dev, &dev_attr_mode);
+       if (ret != 0) {
+               dev_err(&pdev->dev,
+                       "failed to create file: %d\n", ret);
+               goto err_file;
+       }
+
+       return 0;
+
+err_file:
+       led_classdev_unregister(&led->cdev);
+err_led:
+       kfree(led);
+err_mem:
+       return ret;
+}
+
+static int __devexit max8997_led_remove(struct platform_device *pdev)
+{
+       struct max8997_led *led = platform_get_drvdata(pdev);
+
+       device_remove_file(led->cdev.dev, &dev_attr_mode);
+       led_classdev_unregister(&led->cdev);
+       kfree(led);
+
+       return 0;
+}
+
+static struct platform_driver max8997_led_driver = {
+       .driver = {
+               .name  = "max8997-led",
+               .owner = THIS_MODULE,
+       },
+       .probe  = max8997_led_probe,
+       .remove = __devexit_p(max8997_led_remove),
+};
+
+static int __init max8997_led_init(void)
+{
+       return platform_driver_register(&max8997_led_driver);
+}
+module_init(max8997_led_init);
+
+static void __exit max8997_led_exit(void)
+{
+       platform_driver_unregister(&max8997_led_driver);
+}
+module_exit(max8997_led_exit);
+
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_DESCRIPTION("MAX8997 LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:max8997-led");
index 614ebebaaa28cdcf7d7c765b1c0c959fd7ac4782..57371e1485ab4e14aaba55ca3ae10e81b52caff6 100644 (file)
@@ -79,7 +79,7 @@ static int __init ss4200_led_dmi_callback(const struct dmi_system_id *id)
        return 1;
 }
 
-static unsigned int __initdata nodetect;
+static bool __initdata nodetect;
 module_param_named(nodetect, nodetect, bool, 0);
 MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection");
 
index 8ac947c7e7c77e11cb08d8482221fb8e48087685..c4197503900ed3a1457e27d3a1c05207952036be 100644 (file)
@@ -18,7 +18,7 @@ Mastery: PREFIX=M
 Beer:
        @for f in Preparation Guest Drivers Launcher Host Switcher Mastery; do echo "{==- $$f -==}"; make -s $$f; done; echo "{==-==}"
 Preparation Preparation! Guest Drivers Launcher Host Switcher Mastery:
-       @sh ../../Documentation/virtual/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'`
+       @sh ../../tools/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'`
 Puppy:
        @clear
        @printf "      __  \n (___()'\`;\n /,    /\`\n \\\\\\\"--\\\\\\   \n"
index 595d7319701680d9360e9f252d9f0273e7de8726..9e8388efd88e2cffeb4c11fc8c432d2a5a7eb371 100644 (file)
@@ -241,7 +241,7 @@ static void lg_notify(struct virtqueue *vq)
 }
 
 /* An extern declaration inside a C file is bad form.  Don't do it. */
-extern void lguest_setup_irq(unsigned int irq);
+extern int lguest_setup_irq(unsigned int irq);
 
 /*
  * This routine finds the Nth virtqueue described in the configuration of
@@ -292,17 +292,21 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
 
        /*
         * OK, tell virtio_ring.c to set up a virtqueue now we know its size
-        * and we've got a pointer to its pages.
+        * and we've got a pointer to its pages.  Note that we set weak_barriers
+        * to 'true': the host just a(nother) SMP CPU, so we only need inter-cpu
+        * barriers.
         */
-       vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN,
-                                vdev, lvq->pages, lg_notify, callback, name);
+       vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN, vdev,
+                                true, lvq->pages, lg_notify, callback, name);
        if (!vq) {
                err = -ENOMEM;
                goto unmap;
        }
 
        /* Make sure the interrupt is allocated. */
-       lguest_setup_irq(lvq->config.irq);
+       err = lguest_setup_irq(lvq->config.irq);
+       if (err)
+               goto destroy_vring;
 
        /*
         * Tell the interrupt for this virtqueue to go to the virtio_ring
@@ -315,7 +319,7 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
        err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED,
                          dev_name(&vdev->dev), vq);
        if (err)
-               goto destroy_vring;
+               goto free_desc;
 
        /*
         * Last of all we hook up our 'struct lguest_vq_info" to the
@@ -324,6 +328,8 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
        vq->priv = lvq;
        return vq;
 
+free_desc:
+       irq_free_desc(lvq->config.irq);
 destroy_vring:
        vring_del_virtqueue(vq);
 unmap:
index ede46581351a04d9a635aee91bec38d69c67c76f..c4fb424dfddbac93d4a191f99dd93627136f5aa6 100644 (file)
@@ -81,8 +81,8 @@ static void fixup_gdt_table(struct lg_cpu *cpu, unsigned start, unsigned end)
                 * sometimes careless and leaves this as 0, even though it's
                 * running at privilege level 1.  If so, we fix it here.
                 */
-               if ((cpu->arch.gdt[i].b & 0x00006000) == 0)
-                       cpu->arch.gdt[i].b |= (GUEST_PL << 13);
+               if (cpu->arch.gdt[i].dpl == 0)
+                       cpu->arch.gdt[i].dpl |= GUEST_PL;
 
                /*
                 * Each descriptor has an "accessed" bit.  If we don't set it
@@ -90,7 +90,7 @@ static void fixup_gdt_table(struct lg_cpu *cpu, unsigned start, unsigned end)
                 * that entry into a segment register.  But the GDT isn't
                 * writable by the Guest, so bad things can happen.
                 */
-               cpu->arch.gdt[i].b |= 0x00000100;
+               cpu->arch.gdt[i].type |= 0x1;
        }
 }
 
@@ -114,13 +114,19 @@ void setup_default_gdt_entries(struct lguest_ro_state *state)
 
        /*
         * The TSS segment refers to the TSS entry for this particular CPU.
-        * Forgive the magic flags: the 0x8900 means the entry is Present, it's
-        * privilege level 0 Available 386 TSS system segment, and the 0x67
-        * means Saturn is eclipsed by Mercury in the twelfth house.
         */
-       gdt[GDT_ENTRY_TSS].a = 0x00000067 | (tss << 16);
-       gdt[GDT_ENTRY_TSS].b = 0x00008900 | (tss & 0xFF000000)
-               | ((tss >> 16) & 0x000000FF);
+       gdt[GDT_ENTRY_TSS].a = 0;
+       gdt[GDT_ENTRY_TSS].b = 0;
+
+       gdt[GDT_ENTRY_TSS].limit0 = 0x67;
+       gdt[GDT_ENTRY_TSS].base0  = tss & 0xFFFF;
+       gdt[GDT_ENTRY_TSS].base1  = (tss >> 16) & 0xFF;
+       gdt[GDT_ENTRY_TSS].base2  = tss >> 24;
+       gdt[GDT_ENTRY_TSS].type   = 0x9; /* 32-bit TSS (available) */
+       gdt[GDT_ENTRY_TSS].p      = 0x1; /* Entry is present */
+       gdt[GDT_ENTRY_TSS].dpl    = 0x0; /* Privilege level 0 */
+       gdt[GDT_ENTRY_TSS].s      = 0x0; /* system segment */
+
 }
 
 /*
@@ -135,8 +141,8 @@ void setup_guest_gdt(struct lg_cpu *cpu)
         */
        cpu->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
        cpu->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
-       cpu->arch.gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13);
-       cpu->arch.gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
+       cpu->arch.gdt[GDT_ENTRY_KERNEL_CS].dpl |= GUEST_PL;
+       cpu->arch.gdt[GDT_ENTRY_KERNEL_DS].dpl |= GUEST_PL;
 }
 
 /*H:650
index 399beb1638d1aa9acf009c1c05aeb9cf1bc79af2..5c6a2d876562dd73f4a6f71fa958353182012dc5 100644 (file)
@@ -31,7 +31,7 @@
 /* There is only one motion sensor per machine */
 struct ams ams_info;
 
-static unsigned int verbose;
+static bool verbose;
 module_param(verbose, bool, 0644);
 MODULE_PARM_DESC(verbose, "Show free falls and shocks in kernel output");
 
index 8a712392cd3829a32dd471f50a557aaa8e774cc3..b27e530a87a4dc6f17046de52c22011efbf7da36 100644 (file)
 
 #include "ams.h"
 
-static unsigned int joystick;
+static bool joystick;
 module_param(joystick, bool, S_IRUGO);
 MODULE_PARM_DESC(joystick, "Enable the input class device on module load");
 
-static unsigned int invert;
+static bool invert;
 module_param(invert, bool, S_IWUSR | S_IRUGO);
 MODULE_PARM_DESC(invert, "Invert input data on X and Y axis");
 
index 02367308ff2e781da67bc4ceb03f0e9463463894..c60d025044ee5ba2009b43717fb2273cf3c80c19 100644 (file)
@@ -52,7 +52,7 @@ static const char *sensor_location[3];
 
 static int limit_adjust;
 static int fan_speed = -1;
-static int verbose;
+static bool verbose;
 
 MODULE_AUTHOR("Colin Leroy <colin@colino.net>");
 MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and "
index f84c08029b2154f6362220a5149a337622a23564..9fb18c147825aef18fb859ad9bc4faafa7d5e6c9 100644 (file)
@@ -368,8 +368,17 @@ static int flakey_status(struct dm_target *ti, status_type_t type,
 static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg)
 {
        struct flakey_c *fc = ti->private;
+       struct dm_dev *dev = fc->dev;
+       int r = 0;
 
-       return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg);
+       /*
+        * Only pass ioctls through if the device sizes match exactly.
+        */
+       if (fc->start ||
+           ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
+               r = scsi_verify_blk_ioctl(NULL, cmd);
+
+       return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg);
 }
 
 static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
index 3921e3bb43c15a107c90e4769fa682b1041d9a7a..9728839f844a8b71a34c04b7317a9dc1fe1497ba 100644 (file)
@@ -116,7 +116,17 @@ static int linear_ioctl(struct dm_target *ti, unsigned int cmd,
                        unsigned long arg)
 {
        struct linear_c *lc = (struct linear_c *) ti->private;
-       return __blkdev_driver_ioctl(lc->dev->bdev, lc->dev->mode, cmd, arg);
+       struct dm_dev *dev = lc->dev;
+       int r = 0;
+
+       /*
+        * Only pass ioctls through if the device sizes match exactly.
+        */
+       if (lc->start ||
+           ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
+               r = scsi_verify_blk_ioctl(NULL, cmd);
+
+       return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg);
 }
 
 static int linear_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
index 5e0090ef4182e71de26afec04d23edb19b3f4e39..801d92d237cfc316ee81c08ab4c261f7113f2690 100644 (file)
@@ -1520,6 +1520,12 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
 
        spin_unlock_irqrestore(&m->lock, flags);
 
+       /*
+        * Only pass ioctls through if the device sizes match exactly.
+        */
+       if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
+               r = scsi_verify_blk_ioctl(NULL, cmd);
+
        return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
 }
 
index 8e91321301424afda07c456a8b6ae53aec524d04..63cc54289afff481c1d4ce8a9cc2e6749de8b5de 100644 (file)
@@ -699,7 +699,7 @@ static int validate_hardware_logical_block_alignment(struct dm_table *table,
        while (i < dm_table_get_num_targets(table)) {
                ti = dm_table_get_target(table, i++);
 
-               blk_set_default_limits(&ti_limits);
+               blk_set_stacking_limits(&ti_limits);
 
                /* combine all target devices' limits */
                if (ti->type->iterate_devices)
@@ -1221,10 +1221,10 @@ int dm_calculate_queue_limits(struct dm_table *table,
        struct queue_limits ti_limits;
        unsigned i = 0;
 
-       blk_set_default_limits(limits);
+       blk_set_stacking_limits(limits);
 
        while (i < dm_table_get_num_targets(table)) {
-               blk_set_default_limits(&ti_limits);
+               blk_set_stacking_limits(&ti_limits);
 
                ti = dm_table_get_target(table, i++);
 
index da52acb60f520088fbb169de53769d5f81abc887..9417ae2fa0bbc68b061d6b50ba23f5127dae5b2c 100644 (file)
@@ -4666,6 +4666,7 @@ static int md_alloc(dev_t dev, char *name)
        mddev->queue->queuedata = mddev;
 
        blk_queue_make_request(mddev->queue, md_make_request);
+       blk_set_stacking_limits(&mddev->queue->limits);
 
        disk = alloc_disk(1 << shift);
        if (!disk) {
index 996302ae210e7b1fe9686a6425662d49f83c4dc3..4a6d5cef3964c910dc8982198c6b7ea921096394 100644 (file)
@@ -26,7 +26,7 @@ config MEDIA_TUNER
        select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
-       select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && EXPERIMENTAL
        select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE
@@ -116,6 +116,13 @@ config MEDIA_TUNER_MT2060
        help
          A driver for the silicon IF tuner MT2060 from Microtune.
 
+config MEDIA_TUNER_MT2063
+       tristate "Microtune MT2063 silicon IF tuner"
+       depends on VIDEO_MEDIA && I2C
+       default m if MEDIA_TUNER_CUSTOMISE
+       help
+         A driver for the silicon IF tuner MT2063 from Microtune.
+
 config MEDIA_TUNER_MT2266
        tristate "Microtune MT2266 silicon tuner"
        depends on VIDEO_MEDIA && I2C
index 196c12a55f9aa7e3d1fefa80d54d6a605c5425ee..8295854ab94bc7923bd85483b7e1b3a6d4ec9256 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o
 obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o
 obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o
 obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o
+obj-$(CONFIG_MEDIA_TUNER_MT2063) += mt2063.o
 obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o
 obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o
 obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o
index 9883617b78620a4e813bcfe3b7451a5430b60e44..cb2c98fbad1ba066d839ace44fe8a6fb5c500024 100644 (file)
@@ -151,7 +151,7 @@ static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw)
 {
        u8 val;
 
-       if (bw == BANDWIDTH_8_MHZ)
+       if (bw == 8000000)
                val = priv->bb_filter_8mhz_cfg;
        else
                val = priv->bb_filter_7mhz_cfg;
@@ -257,39 +257,28 @@ static void max2165_debug_status(struct max2165_priv *priv)
        dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc);
 }
 
-static int max2165_set_params(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params)
+static int max2165_set_params(struct dvb_frontend *fe)
 {
        struct max2165_priv *priv = fe->tuner_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret;
 
-       dprintk("%s() frequency=%d (Hz)\n", __func__, params->frequency);
-       if (fe->ops.info.type == FE_ATSC) {
-                       return -EINVAL;
-       } else if (fe->ops.info.type == FE_OFDM) {
-               dprintk("%s() OFDM\n", __func__);
-               switch (params->u.ofdm.bandwidth) {
-               case BANDWIDTH_6_MHZ:
-                       return -EINVAL;
-               case BANDWIDTH_7_MHZ:
-               case BANDWIDTH_8_MHZ:
-                       priv->frequency = params->frequency;
-                       priv->bandwidth = params->u.ofdm.bandwidth;
-                       break;
-               default:
-                       printk(KERN_ERR "MAX2165 bandwidth not set!\n");
-                       return -EINVAL;
-               }
-       } else {
-               printk(KERN_ERR "MAX2165 modulation type not supported!\n");
+       switch (c->bandwidth_hz) {
+       case 7000000:
+       case 8000000:
+               priv->frequency = c->frequency;
+               break;
+       default:
+               printk(KERN_INFO "MAX2165: bandwidth %d Hz not supported.\n",
+                      c->bandwidth_hz);
                return -EINVAL;
        }
 
-       dprintk("%s() frequency=%d\n", __func__, priv->frequency);
+       dprintk("%s() frequency=%d\n", __func__, c->frequency);
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
-       max2165_set_bandwidth(priv, priv->bandwidth);
+       max2165_set_bandwidth(priv, c->bandwidth_hz);
        ret = max2165_set_rf(priv, priv->frequency);
        mdelay(50);
        max2165_debug_status(priv);
@@ -370,7 +359,7 @@ static int max2165_init(struct dvb_frontend *fe)
 
        max2165_read_rom_table(priv);
 
-       max2165_set_bandwidth(priv, BANDWIDTH_8_MHZ);
+       max2165_set_bandwidth(priv, 8000000);
 
        if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
index fe5c4b8d83eeddaa203806da48726822e93eeb49..5ddce7e326f743043d8cdaa87c5c1f3ca8c079d4 100644 (file)
@@ -214,22 +214,22 @@ exit:
        return err;
 }
 
-static int mc44s803_set_params(struct dvb_frontend *fe,
-                              struct dvb_frontend_parameters *params)
+static int mc44s803_set_params(struct dvb_frontend *fe)
 {
        struct mc44s803_priv *priv = fe->tuner_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        u32 r1, r2, n1, n2, lo1, lo2, freq, val;
        int err;
 
-       priv->frequency = params->frequency;
+       priv->frequency = c->frequency;
 
        r1 = MC44S803_OSC / 1000000;
        r2 = MC44S803_OSC /  100000;
 
-       n1 = (params->frequency + MC44S803_IF1 + 500000) / 1000000;
+       n1 = (c->frequency + MC44S803_IF1 + 500000) / 1000000;
        freq = MC44S803_OSC / r1 * n1;
        lo1 = ((60 * n1) + (r1 / 2)) / r1;
-       freq = freq - params->frequency;
+       freq = freq - c->frequency;
 
        n2 = (freq - MC44S803_IF2 + 50000) / 100000;
        lo2 = ((60 * n2) + (r2 / 2)) / r2;
index 2d0e7689c6a224eae8757c5c054972f1ab03d2a6..13381de58a843a4b8f4997705bdfc62c40ae34f5 100644 (file)
@@ -153,8 +153,9 @@ static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2)
 #define IF2  36150       // IF2 frequency = 36.150 MHz
 #define FREF 16000       // Quartz oscillator 16 MHz
 
-static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int mt2060_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct mt2060_priv *priv;
        int ret=0;
        int i=0;
@@ -176,8 +177,7 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
 
        mt2060_writeregs(priv,b,2);
 
-       freq = params->frequency / 1000; // Hz -> kHz
-       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+       freq = c->frequency / 1000; /* Hz -> kHz */
 
        f_lo1 = freq + if1 * 1000;
        f_lo1 = (f_lo1 / 250) * 250;
@@ -293,10 +293,9 @@ static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency)
        return 0;
 }
 
-static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+static int mt2060_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
-       struct mt2060_priv *priv = fe->tuner_priv;
-       *bandwidth = priv->bandwidth;
+       *frequency = IF2 * 1000;
        return 0;
 }
 
@@ -356,7 +355,7 @@ static const struct dvb_tuner_ops mt2060_tuner_ops = {
 
        .set_params    = mt2060_set_params,
        .get_frequency = mt2060_get_frequency,
-       .get_bandwidth = mt2060_get_bandwidth
+       .get_if_frequency = mt2060_get_if_frequency,
 };
 
 /* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */
index 5eaccdefd0b056222664dc0d0ca68555b0269654..2b60de6c707dfd884812376358089fde51600233 100644 (file)
@@ -97,7 +97,6 @@ struct mt2060_priv {
        struct i2c_adapter   *i2c;
 
        u32 frequency;
-       u32 bandwidth;
        u16 if1_freq;
        u8  fmfreq;
 };
diff --git a/drivers/media/common/tuners/mt2063.c b/drivers/media/common/tuners/mt2063.c
new file mode 100644 (file)
index 0000000..c89af3c
--- /dev/null
@@ -0,0 +1,2307 @@
+/*
+ * Driver for mt2063 Micronas tuner
+ *
+ * Copyright (c) 2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This driver came from a driver originally written by:
+ *             Henry Wang <Henry.wang@AzureWave.com>
+ * Made publicly available by Terratec, at:
+ *     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()
+ *
+ * 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 under 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+
+#include "mt2063.h"
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Set Verbosity level");
+
+#define dprintk(level, fmt, arg...) do {                               \
+if (debug >= level)                                                    \
+       printk(KERN_DEBUG "mt2063 %s: " fmt, __func__, ## arg); \
+} while (0)
+
+
+/* positive error codes used internally */
+
+/*  Info: Unavoidable LO-related spur may be present in the output  */
+#define MT2063_SPUR_PRESENT_ERR             (0x00800000)
+
+/*  Info: Mask of bits used for # of LO-related spurs that were avoided during tuning  */
+#define MT2063_SPUR_CNT_MASK                (0x001f0000)
+#define MT2063_SPUR_SHIFT                   (16)
+
+/*  Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */
+#define MT2063_UPC_RANGE                    (0x04000000)
+
+/*  Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */
+#define MT2063_DNC_RANGE                    (0x08000000)
+
+/*
+ *  Constant defining the version of the following structure
+ *  and therefore the API for this code.
+ *
+ *  When compiling the tuner driver, the preprocessor will
+ *  check against this version number to make sure that
+ *  it matches the version that the tuner driver knows about.
+ */
+
+/* DECT Frequency Avoidance */
+#define MT2063_DECT_AVOID_US_FREQS      0x00000001
+
+#define MT2063_DECT_AVOID_EURO_FREQS    0x00000002
+
+#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0)
+
+#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0)
+
+enum MT2063_DECT_Avoid_Type {
+       MT2063_NO_DECT_AVOIDANCE = 0,                           /* Do not create DECT exclusion zones.     */
+       MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS,      /* Avoid US DECT frequencies.              */
+       MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS,  /* Avoid European DECT frequencies.        */
+       MT2063_AVOID_BOTH                                       /* Avoid both regions. Not typically used. */
+};
+
+#define MT2063_MAX_ZONES 48
+
+struct MT2063_ExclZone_t {
+       u32 min_;
+       u32 max_;
+       struct MT2063_ExclZone_t *next_;
+};
+
+/*
+ *  Structure of data needed for Spur Avoidance
+ */
+struct MT2063_AvoidSpursData_t {
+       u32 f_ref;
+       u32 f_in;
+       u32 f_LO1;
+       u32 f_if1_Center;
+       u32 f_if1_Request;
+       u32 f_if1_bw;
+       u32 f_LO2;
+       u32 f_out;
+       u32 f_out_bw;
+       u32 f_LO1_Step;
+       u32 f_LO2_Step;
+       u32 f_LO1_FracN_Avoid;
+       u32 f_LO2_FracN_Avoid;
+       u32 f_zif_bw;
+       u32 f_min_LO_Separation;
+       u32 maxH1;
+       u32 maxH2;
+       enum MT2063_DECT_Avoid_Type avoidDECT;
+       u32 bSpurPresent;
+       u32 bSpurAvoided;
+       u32 nSpursFound;
+       u32 nZones;
+       struct MT2063_ExclZone_t *freeZones;
+       struct MT2063_ExclZone_t *usedZones;
+       struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES];
+};
+
+/*
+ * Parameter for function MT2063_SetPowerMask that specifies the power down
+ * of various sections of the MT2063.
+ */
+enum MT2063_Mask_Bits {
+       MT2063_REG_SD = 0x0040,         /* Shutdown regulator                 */
+       MT2063_SRO_SD = 0x0020,         /* Shutdown SRO                       */
+       MT2063_AFC_SD = 0x0010,         /* Shutdown AFC A/D                   */
+       MT2063_PD_SD = 0x0002,          /* Enable power detector shutdown     */
+       MT2063_PDADC_SD = 0x0001,       /* Enable power detector A/D shutdown */
+       MT2063_VCO_SD = 0x8000,         /* Enable VCO shutdown                */
+       MT2063_LTX_SD = 0x4000,         /* Enable LTX shutdown                */
+       MT2063_LT1_SD = 0x2000,         /* Enable LT1 shutdown                */
+       MT2063_LNA_SD = 0x1000,         /* Enable LNA shutdown                */
+       MT2063_UPC_SD = 0x0800,         /* Enable upconverter shutdown        */
+       MT2063_DNC_SD = 0x0400,         /* Enable downconverter shutdown      */
+       MT2063_VGA_SD = 0x0200,         /* Enable VGA shutdown                */
+       MT2063_AMP_SD = 0x0100,         /* Enable AMP shutdown                */
+       MT2063_ALL_SD = 0xFF73,         /* All shutdown bits for this tuner   */
+       MT2063_NONE_SD = 0x0000         /* No shutdown bits                   */
+};
+
+/*
+ *  Possible values for MT2063_DNC_OUTPUT
+ */
+enum MT2063_DNC_Output_Enable {
+       MT2063_DNC_NONE = 0,
+       MT2063_DNC_1,
+       MT2063_DNC_2,
+       MT2063_DNC_BOTH
+};
+
+/*
+ *  Two-wire serial bus subaddresses of the tuner registers.
+ *  Also known as the tuner's register addresses.
+ */
+enum MT2063_Register_Offsets {
+       MT2063_REG_PART_REV = 0,        /*  0x00: Part/Rev Code         */
+       MT2063_REG_LO1CQ_1,             /*  0x01: LO1C Queued Byte 1    */
+       MT2063_REG_LO1CQ_2,             /*  0x02: LO1C Queued Byte 2    */
+       MT2063_REG_LO2CQ_1,             /*  0x03: LO2C Queued Byte 1    */
+       MT2063_REG_LO2CQ_2,             /*  0x04: LO2C Queued Byte 2    */
+       MT2063_REG_LO2CQ_3,             /*  0x05: LO2C Queued Byte 3    */
+       MT2063_REG_RSVD_06,             /*  0x06: Reserved              */
+       MT2063_REG_LO_STATUS,           /*  0x07: LO Status             */
+       MT2063_REG_FIFFC,               /*  0x08: FIFF Center           */
+       MT2063_REG_CLEARTUNE,           /*  0x09: ClearTune Filter      */
+       MT2063_REG_ADC_OUT,             /*  0x0A: ADC_OUT               */
+       MT2063_REG_LO1C_1,              /*  0x0B: LO1C Byte 1           */
+       MT2063_REG_LO1C_2,              /*  0x0C: LO1C Byte 2           */
+       MT2063_REG_LO2C_1,              /*  0x0D: LO2C Byte 1           */
+       MT2063_REG_LO2C_2,              /*  0x0E: LO2C Byte 2           */
+       MT2063_REG_LO2C_3,              /*  0x0F: LO2C Byte 3           */
+       MT2063_REG_RSVD_10,             /*  0x10: Reserved              */
+       MT2063_REG_PWR_1,               /*  0x11: PWR Byte 1            */
+       MT2063_REG_PWR_2,               /*  0x12: PWR Byte 2            */
+       MT2063_REG_TEMP_STATUS,         /*  0x13: Temp Status           */
+       MT2063_REG_XO_STATUS,           /*  0x14: Crystal Status        */
+       MT2063_REG_RF_STATUS,           /*  0x15: RF Attn Status        */
+       MT2063_REG_FIF_STATUS,          /*  0x16: FIF Attn Status       */
+       MT2063_REG_LNA_OV,              /*  0x17: LNA Attn Override     */
+       MT2063_REG_RF_OV,               /*  0x18: RF Attn Override      */
+       MT2063_REG_FIF_OV,              /*  0x19: FIF Attn Override     */
+       MT2063_REG_LNA_TGT,             /*  0x1A: Reserved              */
+       MT2063_REG_PD1_TGT,             /*  0x1B: Pwr Det 1 Target      */
+       MT2063_REG_PD2_TGT,             /*  0x1C: Pwr Det 2 Target      */
+       MT2063_REG_RSVD_1D,             /*  0x1D: Reserved              */
+       MT2063_REG_RSVD_1E,             /*  0x1E: Reserved              */
+       MT2063_REG_RSVD_1F,             /*  0x1F: Reserved              */
+       MT2063_REG_RSVD_20,             /*  0x20: Reserved              */
+       MT2063_REG_BYP_CTRL,            /*  0x21: Bypass Control        */
+       MT2063_REG_RSVD_22,             /*  0x22: Reserved              */
+       MT2063_REG_RSVD_23,             /*  0x23: Reserved              */
+       MT2063_REG_RSVD_24,             /*  0x24: Reserved              */
+       MT2063_REG_RSVD_25,             /*  0x25: Reserved              */
+       MT2063_REG_RSVD_26,             /*  0x26: Reserved              */
+       MT2063_REG_RSVD_27,             /*  0x27: Reserved              */
+       MT2063_REG_FIFF_CTRL,           /*  0x28: FIFF Control          */
+       MT2063_REG_FIFF_OFFSET,         /*  0x29: FIFF Offset           */
+       MT2063_REG_CTUNE_CTRL,          /*  0x2A: Reserved              */
+       MT2063_REG_CTUNE_OV,            /*  0x2B: Reserved              */
+       MT2063_REG_CTRL_2C,             /*  0x2C: Reserved              */
+       MT2063_REG_FIFF_CTRL2,          /*  0x2D: Fiff Control          */
+       MT2063_REG_RSVD_2E,             /*  0x2E: Reserved              */
+       MT2063_REG_DNC_GAIN,            /*  0x2F: DNC Control           */
+       MT2063_REG_VGA_GAIN,            /*  0x30: VGA Gain Ctrl         */
+       MT2063_REG_RSVD_31,             /*  0x31: Reserved              */
+       MT2063_REG_TEMP_SEL,            /*  0x32: Temperature Selection */
+       MT2063_REG_RSVD_33,             /*  0x33: Reserved              */
+       MT2063_REG_RSVD_34,             /*  0x34: Reserved              */
+       MT2063_REG_RSVD_35,             /*  0x35: Reserved              */
+       MT2063_REG_RSVD_36,             /*  0x36: Reserved              */
+       MT2063_REG_RSVD_37,             /*  0x37: Reserved              */
+       MT2063_REG_RSVD_38,             /*  0x38: Reserved              */
+       MT2063_REG_RSVD_39,             /*  0x39: Reserved              */
+       MT2063_REG_RSVD_3A,             /*  0x3A: Reserved              */
+       MT2063_REG_RSVD_3B,             /*  0x3B: Reserved              */
+       MT2063_REG_RSVD_3C,             /*  0x3C: Reserved              */
+       MT2063_REG_END_REGS
+};
+
+struct mt2063_state {
+       struct i2c_adapter *i2c;
+
+       bool init;
+
+       const struct mt2063_config *config;
+       struct dvb_tuner_ops ops;
+       struct dvb_frontend *frontend;
+       struct tuner_state status;
+
+       u32 frequency;
+       u32 srate;
+       u32 bandwidth;
+       u32 reference;
+
+       u32 tuner_id;
+       struct MT2063_AvoidSpursData_t AS_Data;
+       u32 f_IF1_actual;
+       u32 rcvr_mode;
+       u32 ctfilt_sw;
+       u32 CTFiltMax[31];
+       u32 num_regs;
+       u8 reg[MT2063_REG_END_REGS];
+};
+
+/*
+ * mt2063_write - Write data into the I2C bus
+ */
+static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len)
+{
+       struct dvb_frontend *fe = state->frontend;
+       int ret;
+       u8 buf[60];
+       struct i2c_msg msg = {
+               .addr = state->config->tuner_address,
+               .flags = 0,
+               .buf = buf,
+               .len = len + 1
+       };
+
+       dprintk(2, "\n");
+
+       msg.buf[0] = reg;
+       memcpy(msg.buf + 1, data, len);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       ret = i2c_transfer(state->i2c, &msg, 1);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       if (ret < 0)
+               printk(KERN_ERR "%s error ret=%d\n", __func__, ret);
+
+       return ret;
+}
+
+/*
+ * mt2063_write - Write register data into the I2C bus, caching the value
+ */
+static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val)
+{
+       u32 status;
+
+       dprintk(2, "\n");
+
+       if (reg >= MT2063_REG_END_REGS)
+               return -ERANGE;
+
+       status = mt2063_write(state, reg, &val, 1);
+       if (status < 0)
+               return status;
+
+       state->reg[reg] = val;
+
+       return 0;
+}
+
+/*
+ * mt2063_read - Read data from the I2C bus
+ */
+static u32 mt2063_read(struct mt2063_state *state,
+                          u8 subAddress, u8 *pData, u32 cnt)
+{
+       u32 status = 0; /* Status to be returned        */
+       struct dvb_frontend *fe = state->frontend;
+       u32 i = 0;
+
+       dprintk(2, "addr 0x%02x, cnt %d\n", subAddress, cnt);
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+
+       for (i = 0; i < cnt; i++) {
+               u8 b0[] = { subAddress + i };
+               struct i2c_msg msg[] = {
+                       {
+                               .addr = state->config->tuner_address,
+                               .flags = 0,
+                               .buf = b0,
+                               .len = 1
+                       }, {
+                               .addr = state->config->tuner_address,
+                               .flags = I2C_M_RD,
+                               .buf = pData + i,
+                               .len = 1
+                       }
+               };
+
+               status = i2c_transfer(state->i2c, msg, 2);
+               dprintk(2, "addr 0x%02x, ret = %d, val = 0x%02x\n",
+                          subAddress + i, status, *(pData + i));
+               if (status < 0)
+                       break;
+       }
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       if (status < 0)
+               printk(KERN_ERR "Can't read from address 0x%02x,\n",
+                      subAddress + i);
+
+       return status;
+}
+
+/*
+ * FIXME: Is this really needed?
+ */
+static int MT2063_Sleep(struct dvb_frontend *fe)
+{
+       /*
+        *  ToDo:  Add code here to implement a OS blocking
+        */
+       msleep(10);
+
+       return 0;
+}
+
+/*
+ * Microtune spur avoidance
+ */
+
+/*  Implement ceiling, floor functions.  */
+#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0))
+#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d))
+
+struct MT2063_FIFZone_t {
+       s32 min_;
+       s32 max_;
+};
+
+static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t
+                                           *pAS_Info,
+                                           struct MT2063_ExclZone_t *pPrevNode)
+{
+       struct MT2063_ExclZone_t *pNode;
+
+       dprintk(2, "\n");
+
+       /*  Check for a node in the free list  */
+       if (pAS_Info->freeZones != NULL) {
+               /*  Use one from the free list  */
+               pNode = pAS_Info->freeZones;
+               pAS_Info->freeZones = pNode->next_;
+       } else {
+               /*  Grab a node from the array  */
+               pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones];
+       }
+
+       if (pPrevNode != NULL) {
+               pNode->next_ = pPrevNode->next_;
+               pPrevNode->next_ = pNode;
+       } else {                /*  insert at the beginning of the list  */
+
+               pNode->next_ = pAS_Info->usedZones;
+               pAS_Info->usedZones = pNode;
+       }
+
+       pAS_Info->nZones++;
+       return pNode;
+}
+
+static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t
+                                           *pAS_Info,
+                                           struct MT2063_ExclZone_t *pPrevNode,
+                                           struct MT2063_ExclZone_t
+                                           *pNodeToRemove)
+{
+       struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_;
+
+       dprintk(2, "\n");
+
+       /*  Make previous node point to the subsequent node  */
+       if (pPrevNode != NULL)
+               pPrevNode->next_ = pNext;
+
+       /*  Add pNodeToRemove to the beginning of the freeZones  */
+       pNodeToRemove->next_ = pAS_Info->freeZones;
+       pAS_Info->freeZones = pNodeToRemove;
+
+       /*  Decrement node count  */
+       pAS_Info->nZones--;
+
+       return pNext;
+}
+
+/*
+ * MT_AddExclZone()
+ *
+ * Add (and merge) an exclusion zone into the list.
+ * If the range (f_min, f_max) is totally outside the
+ * 1st IF BW, ignore the entry.
+ * If the range (f_min, f_max) is negative, ignore the entry.
+ */
+static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info,
+                              u32 f_min, u32 f_max)
+{
+       struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
+       struct MT2063_ExclZone_t *pPrev = NULL;
+       struct MT2063_ExclZone_t *pNext = NULL;
+
+       dprintk(2, "\n");
+
+       /*  Check to see if this overlaps the 1st IF filter  */
+       if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2)))
+           && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2)))
+           && (f_min < f_max)) {
+               /*
+                *                1        2         3      4       5        6
+                *
+                *   New entry:  |---|    |--|      |--|    |-|    |---|    |--|
+                *                or       or        or     or      or
+                *   Existing:  |--|      |--|      |--|    |---|  |-|      |--|
+                */
+
+               /*  Check for our place in the list  */
+               while ((pNode != NULL) && (pNode->max_ < f_min)) {
+                       pPrev = pNode;
+                       pNode = pNode->next_;
+               }
+
+               if ((pNode != NULL) && (pNode->min_ < f_max)) {
+                       /*  Combine me with pNode  */
+                       if (f_min < pNode->min_)
+                               pNode->min_ = f_min;
+                       if (f_max > pNode->max_)
+                               pNode->max_ = f_max;
+               } else {
+                       pNode = InsertNode(pAS_Info, pPrev);
+                       pNode->min_ = f_min;
+                       pNode->max_ = f_max;
+               }
+
+               /*  Look for merging possibilities  */
+               pNext = pNode->next_;
+               while ((pNext != NULL) && (pNext->min_ < pNode->max_)) {
+                       if (pNext->max_ > pNode->max_)
+                               pNode->max_ = pNext->max_;
+                       /*  Remove pNext, return ptr to pNext->next  */
+                       pNext = RemoveNode(pAS_Info, pNode, pNext);
+               }
+       }
+}
+
+/*
+ *  Reset all exclusion zones.
+ *  Add zones to protect the PLL FracN regions near zero
+ */
+static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info)
+{
+       u32 center;
+
+       dprintk(2, "\n");
+
+       pAS_Info->nZones = 0;   /*  this clears the used list  */
+       pAS_Info->usedZones = NULL;     /*  reset ptr                  */
+       pAS_Info->freeZones = NULL;     /*  reset ptr                  */
+
+       center =
+           pAS_Info->f_ref *
+           ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 +
+             pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in;
+       while (center <
+              pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
+              pAS_Info->f_LO1_FracN_Avoid) {
+               /*  Exclude LO1 FracN  */
+               MT2063_AddExclZone(pAS_Info,
+                                  center - pAS_Info->f_LO1_FracN_Avoid,
+                                  center - 1);
+               MT2063_AddExclZone(pAS_Info, center + 1,
+                                  center + pAS_Info->f_LO1_FracN_Avoid);
+               center += pAS_Info->f_ref;
+       }
+
+       center =
+           pAS_Info->f_ref *
+           ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 -
+             pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out;
+       while (center <
+              pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 +
+              pAS_Info->f_LO2_FracN_Avoid) {
+               /*  Exclude LO2 FracN  */
+               MT2063_AddExclZone(pAS_Info,
+                                  center - pAS_Info->f_LO2_FracN_Avoid,
+                                  center - 1);
+               MT2063_AddExclZone(pAS_Info, center + 1,
+                                  center + pAS_Info->f_LO2_FracN_Avoid);
+               center += pAS_Info->f_ref;
+       }
+
+       if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
+               /*  Exclude LO1 values that conflict with DECT channels */
+               MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */
+               MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */
+               MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */
+               MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */
+               MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */
+       }
+
+       if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) {
+               MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */
+               MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */
+               MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */
+               MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16  */
+               MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */
+               MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */
+               MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */
+               MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */
+               MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52  */
+               MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */
+       }
+}
+
+/*
+ * MT_ChooseFirstIF - Choose the best available 1st IF
+ *                    If f_Desired is not excluded, choose that first.
+ *                    Otherwise, return the value closest to f_Center that is
+ *                    not excluded
+ */
+static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info)
+{
+       /*
+        * Update "f_Desired" to be the nearest "combinational-multiple" of
+        * "f_LO1_Step".
+        * The resulting number, F_LO1 must be a multiple of f_LO1_Step.
+        * And F_LO1 is the arithmetic sum of f_in + f_Center.
+        * Neither f_in, nor f_Center must be a multiple of f_LO1_Step.
+        * However, the sum must be.
+        */
+       const u32 f_Desired =
+           pAS_Info->f_LO1_Step *
+           ((pAS_Info->f_if1_Request + pAS_Info->f_in +
+             pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) -
+           pAS_Info->f_in;
+       const u32 f_Step =
+           (pAS_Info->f_LO1_Step >
+            pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info->
+           f_LO2_Step;
+       u32 f_Center;
+       s32 i;
+       s32 j = 0;
+       u32 bDesiredExcluded = 0;
+       u32 bZeroExcluded = 0;
+       s32 tmpMin, tmpMax;
+       s32 bestDiff;
+       struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones;
+       struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES];
+
+       dprintk(2, "\n");
+
+       if (pAS_Info->nZones == 0)
+               return f_Desired;
+
+       /*
+        *  f_Center needs to be an integer multiple of f_Step away
+        *  from f_Desired
+        */
+       if (pAS_Info->f_if1_Center > f_Desired)
+               f_Center =
+                   f_Desired +
+                   f_Step *
+                   ((pAS_Info->f_if1_Center - f_Desired +
+                     f_Step / 2) / f_Step);
+       else
+               f_Center =
+                   f_Desired -
+                   f_Step *
+                   ((f_Desired - pAS_Info->f_if1_Center +
+                     f_Step / 2) / f_Step);
+
+       /*
+        * Take MT_ExclZones, center around f_Center and change the
+        * resolution to f_Step
+        */
+       while (pNode != NULL) {
+               /*  floor function  */
+               tmpMin =
+                   floor((s32) (pNode->min_ - f_Center), (s32) f_Step);
+
+               /*  ceil function  */
+               tmpMax =
+                   ceil((s32) (pNode->max_ - f_Center), (s32) f_Step);
+
+               if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired))
+                       bDesiredExcluded = 1;
+
+               if ((tmpMin < 0) && (tmpMax > 0))
+                       bZeroExcluded = 1;
+
+               /*  See if this zone overlaps the previous  */
+               if ((j > 0) && (tmpMin < zones[j - 1].max_))
+                       zones[j - 1].max_ = tmpMax;
+               else {
+                       /*  Add new zone  */
+                       zones[j].min_ = tmpMin;
+                       zones[j].max_ = tmpMax;
+                       j++;
+               }
+               pNode = pNode->next_;
+       }
+
+       /*
+        *  If the desired is okay, return with it
+        */
+       if (bDesiredExcluded == 0)
+               return f_Desired;
+
+       /*
+        *  If the desired is excluded and the center is okay, return with it
+        */
+       if (bZeroExcluded == 0)
+               return f_Center;
+
+       /*  Find the value closest to 0 (f_Center)  */
+       bestDiff = zones[0].min_;
+       for (i = 0; i < j; i++) {
+               if (abs(zones[i].min_) < abs(bestDiff))
+                       bestDiff = zones[i].min_;
+               if (abs(zones[i].max_) < abs(bestDiff))
+                       bestDiff = zones[i].max_;
+       }
+
+       if (bestDiff < 0)
+               return f_Center - ((u32) (-bestDiff) * f_Step);
+
+       return f_Center + (bestDiff * f_Step);
+}
+
+/**
+ * gcd() - Uses Euclid's algorithm
+ *
+ * @u, @v:     Unsigned values whose GCD is desired.
+ *
+ * Returns THE greatest common divisor of u and v, if either value is 0,
+ * the other value is returned as the result.
+ */
+static u32 MT2063_gcd(u32 u, u32 v)
+{
+       u32 r;
+
+       while (v != 0) {
+               r = u % v;
+               u = v;
+               v = r;
+       }
+
+       return u;
+}
+
+/**
+ * IsSpurInBand() - Checks to see if a spur will be present within the IF's
+ *                  bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW)
+ *
+ *                    ma   mb                                     mc   md
+ *                  <--+-+-+-------------------+-------------------+-+-+-->
+ *                     |   ^                   0                   ^   |
+ *                     ^   b=-fIFOut+fIFBW/2      -b=+fIFOut-fIFBW/2   ^
+ *                     a=-fIFOut-fIFBW/2              -a=+fIFOut+fIFBW/2
+ *
+ *                  Note that some equations are doubled to prevent round-off
+ *                  problems when calculating fIFBW/2
+ *
+ * @pAS_Info:  Avoid Spurs information block
+ * @fm:                If spur, amount f_IF1 has to move negative
+ * @fp:                If spur, amount f_IF1 has to move positive
+ *
+ *  Returns 1 if an LO spur would be present, otherwise 0.
+ */
+static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info,
+                       u32 *fm, u32 * fp)
+{
+       /*
+        **  Calculate LO frequency settings.
+        */
+       u32 n, n0;
+       const u32 f_LO1 = pAS_Info->f_LO1;
+       const u32 f_LO2 = pAS_Info->f_LO2;
+       const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2;
+       const u32 c = d - pAS_Info->f_out_bw;
+       const u32 f = pAS_Info->f_zif_bw / 2;
+       const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1;
+       s32 f_nsLO1, f_nsLO2;
+       s32 f_Spur;
+       u32 ma, mb, mc, md, me, mf;
+       u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs;
+
+       dprintk(2, "\n");
+
+       *fm = 0;
+
+       /*
+        ** For each edge (d, c & f), calculate a scale, based on the gcd
+        ** of f_LO1, f_LO2 and the edge value.  Use the larger of this
+        ** gcd-based scale factor or f_Scale.
+        */
+       lo_gcd = MT2063_gcd(f_LO1, f_LO2);
+       gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale);
+       hgds = gd_Scale / 2;
+       gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale);
+       hgcs = gc_Scale / 2;
+       gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale);
+       hgfs = gf_Scale / 2;
+
+       n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2);
+
+       /*  Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic  */
+       for (n = n0; n <= pAS_Info->maxH1; ++n) {
+               md = (n * ((f_LO1 + hgds) / gd_Scale) -
+                     ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
+
+               /*  If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present  */
+               if (md >= pAS_Info->maxH1)
+                       break;
+
+               ma = (n * ((f_LO1 + hgds) / gd_Scale) +
+                     ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale);
+
+               /*  If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic  */
+               if (md == ma)
+                       continue;
+
+               mc = (n * ((f_LO1 + hgcs) / gc_Scale) -
+                     ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
+               if (mc != md) {
+                       f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale));
+                       f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale));
+                       f_Spur =
+                           (gc_Scale * (f_nsLO1 - f_nsLO2)) +
+                           n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale);
+
+                       *fp = ((f_Spur - (s32) c) / (mc - n)) + 1;
+                       *fm = (((s32) d - f_Spur) / (mc - n)) + 1;
+                       return 1;
+               }
+
+               /*  Location of Zero-IF-spur to be checked  */
+               me = (n * ((f_LO1 + hgfs) / gf_Scale) +
+                     ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
+               mf = (n * ((f_LO1 + hgfs) / gf_Scale) -
+                     ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale);
+               if (me != mf) {
+                       f_nsLO1 = n * (f_LO1 / gf_Scale);
+                       f_nsLO2 = me * (f_LO2 / gf_Scale);
+                       f_Spur =
+                           (gf_Scale * (f_nsLO1 - f_nsLO2)) +
+                           n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale);
+
+                       *fp = ((f_Spur + (s32) f) / (me - n)) + 1;
+                       *fm = (((s32) f - f_Spur) / (me - n)) + 1;
+                       return 1;
+               }
+
+               mb = (n * ((f_LO1 + hgcs) / gc_Scale) +
+                     ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale);
+               if (ma != mb) {
+                       f_nsLO1 = n * (f_LO1 / gc_Scale);
+                       f_nsLO2 = ma * (f_LO2 / gc_Scale);
+                       f_Spur =
+                           (gc_Scale * (f_nsLO1 - f_nsLO2)) +
+                           n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale);
+
+                       *fp = (((s32) d + f_Spur) / (ma - n)) + 1;
+                       *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1;
+                       return 1;
+               }
+       }
+
+       /*  No spurs found  */
+       return 0;
+}
+
+/*
+ * MT_AvoidSpurs() - Main entry point to avoid spurs.
+ *                   Checks for existing spurs in present LO1, LO2 freqs
+ *                   and if present, chooses spur-free LO1, LO2 combination
+ *                   that tunes the same input/output frequencies.
+ */
+static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info)
+{
+       u32 status = 0;
+       u32 fm, fp;             /*  restricted range on LO's        */
+       pAS_Info->bSpurAvoided = 0;
+       pAS_Info->nSpursFound = 0;
+
+       dprintk(2, "\n");
+
+       if (pAS_Info->maxH1 == 0)
+               return 0;
+
+       /*
+        * Avoid LO Generated Spurs
+        *
+        * Make sure that have no LO-related spurs within the IF output
+        * bandwidth.
+        *
+        * If there is an LO spur in this band, start at the current IF1 frequency
+        * and work out until we find a spur-free frequency or run up against the
+        * 1st IF SAW band edge.  Use temporary copies of fLO1 and fLO2 so that they
+        * will be unchanged if a spur-free setting is not found.
+        */
+       pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
+       if (pAS_Info->bSpurPresent) {
+               u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in;   /*  current attempt at a 1st IF  */
+               u32 zfLO1 = pAS_Info->f_LO1;    /*  current attempt at an LO1 freq  */
+               u32 zfLO2 = pAS_Info->f_LO2;    /*  current attempt at an LO2 freq  */
+               u32 delta_IF1;
+               u32 new_IF1;
+
+               /*
+                **  Spur was found, attempt to find a spur-free 1st IF
+                */
+               do {
+                       pAS_Info->nSpursFound++;
+
+                       /*  Raise f_IF1_upper, if needed  */
+                       MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp);
+
+                       /*  Choose next IF1 that is closest to f_IF1_CENTER              */
+                       new_IF1 = MT2063_ChooseFirstIF(pAS_Info);
+
+                       if (new_IF1 > zfIF1) {
+                               pAS_Info->f_LO1 += (new_IF1 - zfIF1);
+                               pAS_Info->f_LO2 += (new_IF1 - zfIF1);
+                       } else {
+                               pAS_Info->f_LO1 -= (zfIF1 - new_IF1);
+                               pAS_Info->f_LO2 -= (zfIF1 - new_IF1);
+                       }
+                       zfIF1 = new_IF1;
+
+                       if (zfIF1 > pAS_Info->f_if1_Center)
+                               delta_IF1 = zfIF1 - pAS_Info->f_if1_Center;
+                       else
+                               delta_IF1 = pAS_Info->f_if1_Center - zfIF1;
+
+                       pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp);
+               /*
+                *  Continue while the new 1st IF is still within the 1st IF bandwidth
+                *  and there is a spur in the band (again)
+                */
+               } while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent);
+
+               /*
+                * Use the LO-spur free values found.  If the search went all
+                * the way to the 1st IF band edge and always found spurs, just
+                * leave the original choice.  It's as "good" as any other.
+                */
+               if (pAS_Info->bSpurPresent == 1) {
+                       status |= MT2063_SPUR_PRESENT_ERR;
+                       pAS_Info->f_LO1 = zfLO1;
+                       pAS_Info->f_LO2 = zfLO2;
+               } else
+                       pAS_Info->bSpurAvoided = 1;
+       }
+
+       status |=
+           ((pAS_Info->
+             nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK);
+
+       return status;
+}
+
+/*
+ * Constants used by the tuning algorithm
+ */
+#define MT2063_REF_FREQ          (16000000UL)  /* Reference oscillator Frequency (in Hz) */
+#define MT2063_IF1_BW            (22000000UL)  /* The IF1 filter bandwidth (in Hz) */
+#define MT2063_TUNE_STEP_SIZE       (50000UL)  /* Tune in steps of 50 kHz */
+#define MT2063_SPUR_STEP_HZ        (250000UL)  /* Step size (in Hz) to move IF1 when avoiding spurs */
+#define MT2063_ZIF_BW             (2000000UL)  /* Zero-IF spur-free bandwidth (in Hz) */
+#define MT2063_MAX_HARMONICS_1         (15UL)  /* Highest intra-tuner LO Spur Harmonic to be avoided */
+#define MT2063_MAX_HARMONICS_2          (5UL)  /* Highest inter-tuner LO Spur Harmonic to be avoided */
+#define MT2063_MIN_LO_SEP         (1000000UL)  /* Minimum inter-tuner LO frequency separation */
+#define MT2063_LO1_FRACN_AVOID          (0UL)  /* LO1 FracN numerator avoid region (in Hz) */
+#define MT2063_LO2_FRACN_AVOID     (199999UL)  /* LO2 FracN numerator avoid region (in Hz) */
+#define MT2063_MIN_FIN_FREQ      (44000000UL)  /* Minimum input frequency (in Hz) */
+#define MT2063_MAX_FIN_FREQ    (1100000000UL)  /* Maximum input frequency (in Hz) */
+#define MT2063_MIN_FOUT_FREQ     (36000000UL)  /* Minimum output frequency (in Hz) */
+#define MT2063_MAX_FOUT_FREQ     (57000000UL)  /* Maximum output frequency (in Hz) */
+#define MT2063_MIN_DNC_FREQ    (1293000000UL)  /* Minimum LO2 frequency (in Hz) */
+#define MT2063_MAX_DNC_FREQ    (1614000000UL)  /* Maximum LO2 frequency (in Hz) */
+#define MT2063_MIN_UPC_FREQ    (1396000000UL)  /* Minimum LO1 frequency (in Hz) */
+#define MT2063_MAX_UPC_FREQ    (2750000000UL)  /* Maximum LO1 frequency (in Hz) */
+
+/*
+ *  Define the supported Part/Rev codes for the MT2063
+ */
+#define MT2063_B0       (0x9B)
+#define MT2063_B1       (0x9C)
+#define MT2063_B2       (0x9D)
+#define MT2063_B3       (0x9E)
+
+/**
+ * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked
+ *
+ * @state:     struct mt2063_state pointer
+ *
+ * This function returns 0, if no lock, 1 if locked and a value < 1 if error
+ */
+static unsigned int mt2063_lockStatus(struct mt2063_state *state)
+{
+       const u32 nMaxWait = 100;       /*  wait a maximum of 100 msec   */
+       const u32 nPollRate = 2;        /*  poll status bits every 2 ms */
+       const u32 nMaxLoops = nMaxWait / nPollRate;
+       const u8 LO1LK = 0x80;
+       u8 LO2LK = 0x08;
+       u32 status;
+       u32 nDelays = 0;
+
+       dprintk(2, "\n");
+
+       /*  LO2 Lock bit was in a different place for B0 version  */
+       if (state->tuner_id == MT2063_B0)
+               LO2LK = 0x40;
+
+       do {
+               status = mt2063_read(state, MT2063_REG_LO_STATUS,
+                                    &state->reg[MT2063_REG_LO_STATUS], 1);
+
+               if (status < 0)
+                       return status;
+
+               if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) ==
+                   (LO1LK | LO2LK)) {
+                       return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO;
+               }
+               msleep(nPollRate);      /*  Wait between retries  */
+       } while (++nDelays < nMaxLoops);
+
+       /*
+        * Got no lock or partial lock
+        */
+       return 0;
+}
+
+/*
+ *  Constants for setting receiver modes.
+ *  (6 modes defined at this time, enumerated by mt2063_delivery_sys)
+ *  (DNC1GC & DNC2GC are the values, which are used, when the specific
+ *   DNC Output is selected, the other is always off)
+ *
+ *                enum mt2063_delivery_sys
+ * -------------+----------------------------------------------
+ * Mode 0 :     | MT2063_CABLE_QAM
+ * Mode 1 :     | MT2063_CABLE_ANALOG
+ * Mode 2 :     | MT2063_OFFAIR_COFDM
+ * Mode 3 :     | MT2063_OFFAIR_COFDM_SAWLESS
+ * Mode 4 :     | MT2063_OFFAIR_ANALOG
+ * Mode 5 :     | MT2063_OFFAIR_8VSB
+ * --------------+----------------------------------------------
+ *
+ *                |<----------   Mode  -------------->|
+ *    Reg Field   |  0  |  1  |  2  |  3  |  4  |  5  |
+ *    ------------+-----+-----+-----+-----+-----+-----+
+ *    RFAGCen     | OFF | OFF | OFF | OFF | OFF | OFF
+ *    LNARin      |   0 |   0 |   3 |   3 |  3  |  3
+ *    FIFFQen     |   1 |   1 |   1 |   1 |  1  |  1
+ *    FIFFq       |   0 |   0 |   0 |   0 |  0  |  0
+ *    DNC1gc      |   0 |   0 |   0 |   0 |  0  |  0
+ *    DNC2gc      |   0 |   0 |   0 |   0 |  0  |  0
+ *    GCU Auto    |   1 |   1 |   1 |   1 |  1  |  1
+ *    LNA max Atn |  31 |  31 |  31 |  31 | 31  | 31
+ *    LNA Target  |  44 |  43 |  43 |  43 | 43  | 43
+ *    ign  RF Ovl |   0 |   0 |   0 |   0 |  0  |  0
+ *    RF  max Atn |  31 |  31 |  31 |  31 | 31  | 31
+ *    PD1 Target  |  36 |  36 |  38 |  38 | 36  | 38
+ *    ign FIF Ovl |   0 |   0 |   0 |   0 |  0  |  0
+ *    FIF max Atn |   5 |   5 |   5 |   5 |  5  |  5
+ *    PD2 Target  |  40 |  33 |  42 |  42 | 33  | 42
+ */
+
+enum mt2063_delivery_sys {
+       MT2063_CABLE_QAM = 0,
+       MT2063_CABLE_ANALOG,
+       MT2063_OFFAIR_COFDM,
+       MT2063_OFFAIR_COFDM_SAWLESS,
+       MT2063_OFFAIR_ANALOG,
+       MT2063_OFFAIR_8VSB,
+       MT2063_NUM_RCVR_MODES
+};
+
+static const char *mt2063_mode_name[] = {
+       [MT2063_CABLE_QAM]              = "digital cable",
+       [MT2063_CABLE_ANALOG]           = "analog cable",
+       [MT2063_OFFAIR_COFDM]           = "digital offair",
+       [MT2063_OFFAIR_COFDM_SAWLESS]   = "digital offair without SAW",
+       [MT2063_OFFAIR_ANALOG]          = "analog offair",
+       [MT2063_OFFAIR_8VSB]            = "analog offair 8vsb",
+};
+
+static const u8 RFAGCEN[]      = {  0,  0,  0,  0,  0,  0 };
+static const u8 LNARIN[]       = {  0,  0,  3,  3,  3,  3 };
+static const u8 FIFFQEN[]      = {  1,  1,  1,  1,  1,  1 };
+static const u8 FIFFQ[]                = {  0,  0,  0,  0,  0,  0 };
+static const u8 DNC1GC[]       = {  0,  0,  0,  0,  0,  0 };
+static const u8 DNC2GC[]       = {  0,  0,  0,  0,  0,  0 };
+static const u8 ACLNAMAX[]     = { 31, 31, 31, 31, 31, 31 };
+static const u8 LNATGT[]       = { 44, 43, 43, 43, 43, 43 };
+static const u8 RFOVDIS[]      = {  0,  0,  0,  0,  0,  0 };
+static const u8 ACRFMAX[]      = { 31, 31, 31, 31, 31, 31 };
+static const u8 PD1TGT[]       = { 36, 36, 38, 38, 36, 38 };
+static const u8 FIFOVDIS[]     = {  0,  0,  0,  0,  0,  0 };
+static const u8 ACFIFMAX[]     = { 29, 29, 29, 29, 29, 29 };
+static const u8 PD2TGT[]       = { 40, 33, 38, 42, 30, 38 };
+
+/*
+ * mt2063_set_dnc_output_enable()
+ */
+static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state,
+                                       enum MT2063_DNC_Output_Enable *pValue)
+{
+       dprintk(2, "\n");
+
+       if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */
+               if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03)   /* if DNC2 is off */
+                       *pValue = MT2063_DNC_NONE;
+               else
+                       *pValue = MT2063_DNC_2;
+       } else {        /* DNC1 is on */
+               if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03)   /* if DNC2 is off */
+                       *pValue = MT2063_DNC_1;
+               else
+                       *pValue = MT2063_DNC_BOTH;
+       }
+       return 0;
+}
+
+/*
+ * mt2063_set_dnc_output_enable()
+ */
+static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state,
+                                       enum MT2063_DNC_Output_Enable nValue)
+{
+       u32 status = 0; /* Status to be returned        */
+       u8 val = 0;
+
+       dprintk(2, "\n");
+
+       /* selects, which DNC output is used */
+       switch (nValue) {
+       case MT2063_DNC_NONE:
+               val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03;  /* Set DNC1GC=3 */
+               if (state->reg[MT2063_REG_DNC_GAIN] !=
+                   val)
+                       status |=
+                           mt2063_setreg(state,
+                                         MT2063_REG_DNC_GAIN,
+                                         val);
+
+               val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03;  /* Set DNC2GC=3 */
+               if (state->reg[MT2063_REG_VGA_GAIN] !=
+                   val)
+                       status |=
+                           mt2063_setreg(state,
+                                         MT2063_REG_VGA_GAIN,
+                                         val);
+
+               val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
+               if (state->reg[MT2063_REG_RSVD_20] !=
+                   val)
+                       status |=
+                           mt2063_setreg(state,
+                                         MT2063_REG_RSVD_20,
+                                         val);
+
+               break;
+       case MT2063_DNC_1:
+               val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03);     /* Set DNC1GC=x */
+               if (state->reg[MT2063_REG_DNC_GAIN] !=
+                   val)
+                       status |=
+                           mt2063_setreg(state,
+                                         MT2063_REG_DNC_GAIN,
+                                         val);
+
+               val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03;  /* Set DNC2GC=3 */
+               if (state->reg[MT2063_REG_VGA_GAIN] !=
+                   val)
+                       status |=
+                           mt2063_setreg(state,
+                                         MT2063_REG_VGA_GAIN,
+                                         val);
+
+               val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */
+               if (state->reg[MT2063_REG_RSVD_20] !=
+                   val)
+                       status |=
+                           mt2063_setreg(state,
+                                         MT2063_REG_RSVD_20,
+                                         val);
+
+               break;
+       case MT2063_DNC_2:
+               val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03;  /* Set DNC1GC=3 */
+               if (state->reg[MT2063_REG_DNC_GAIN] !=
+                   val)
+                       status |=
+                           mt2063_setreg(state,
+                                         MT2063_REG_DNC_GAIN,
+                                         val);
+
+               val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03);     /* Set DNC2GC=x */
+               if (state->reg[MT2063_REG_VGA_GAIN] !=
+                   val)
+                       status |=
+                           mt2063_setreg(state,
+                                         MT2063_REG_VGA_GAIN,
+                                         val);
+
+               val = (state->reg[MT2063_REG_RSVD_20] | 0x40);  /* Set PD2MUX=1 */
+               if (state->reg[MT2063_REG_RSVD_20] !=
+                   val)
+                       status |=
+                           mt2063_setreg(state,
+                                         MT2063_REG_RSVD_20,
+                                         val);
+
+               break;
+       case MT2063_DNC_BOTH:
+               val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03);     /* Set DNC1GC=x */
+               if (state->reg[MT2063_REG_DNC_GAIN] !=
+                   val)
+                       status |=
+                           mt2063_setreg(state,
+                                         MT2063_REG_DNC_GAIN,
+                                         val);
+
+               val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03);     /* Set DNC2GC=x */
+               if (state->reg[MT2063_REG_VGA_GAIN] !=
+                   val)
+                       status |=
+                           mt2063_setreg(state,
+                                         MT2063_REG_VGA_GAIN,
+                                         val);
+
+               val = (state->reg[MT2063_REG_RSVD_20] | 0x40);  /* Set PD2MUX=1 */
+               if (state->reg[MT2063_REG_RSVD_20] !=
+                   val)
+                       status |=
+                           mt2063_setreg(state,
+                                         MT2063_REG_RSVD_20,
+                                         val);
+
+               break;
+       default:
+               break;
+       }
+
+       return status;
+}
+
+/*
+ * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with
+ *                           the selected enum mt2063_delivery_sys type.
+ *
+ *  (DNC1GC & DNC2GC are the values, which are used, when the specific
+ *   DNC Output is selected, the other is always off)
+ *
+ * @state:     ptr to mt2063_state structure
+ * @Mode:      desired reciever delivery system
+ *
+ * Note: Register cache must be valid for it to work
+ */
+
+static u32 MT2063_SetReceiverMode(struct mt2063_state *state,
+                                 enum mt2063_delivery_sys Mode)
+{
+       u32 status = 0; /* Status to be returned        */
+       u8 val;
+       u32 longval;
+
+       dprintk(2, "\n");
+
+       if (Mode >= MT2063_NUM_RCVR_MODES)
+               status = -ERANGE;
+
+       /* RFAGCen */
+       if (status >= 0) {
+               val =
+                   (state->
+                    reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode]
+                                                                  ? 0x40 :
+                                                                  0x00);
+               if (state->reg[MT2063_REG_PD1_TGT] != val)
+                       status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
+       }
+
+       /* LNARin */
+       if (status >= 0) {
+               u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) |
+                        (LNARIN[Mode] & 0x03);
+               if (state->reg[MT2063_REG_CTRL_2C] != val)
+                       status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val);
+       }
+
+       /* FIFFQEN and FIFFQ */
+       if (status >= 0) {
+               val =
+                   (state->
+                    reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) |
+                   (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
+               if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
+                       status |=
+                           mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val);
+                       /* trigger FIFF calibration, needed after changing FIFFQ */
+                       val =
+                           (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
+                       status |=
+                           mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
+                       val =
+                           (state->
+                            reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01);
+                       status |=
+                           mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
+               }
+       }
+
+       /* DNC1GC & DNC2GC */
+       status |= mt2063_get_dnc_output_enable(state, &longval);
+       status |= mt2063_set_dnc_output_enable(state, longval);
+
+       /* acLNAmax */
+       if (status >= 0) {
+               u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) |
+                        (ACLNAMAX[Mode] & 0x1F);
+               if (state->reg[MT2063_REG_LNA_OV] != val)
+                       status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val);
+       }
+
+       /* LNATGT */
+       if (status >= 0) {
+               u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) |
+                        (LNATGT[Mode] & 0x3F);
+               if (state->reg[MT2063_REG_LNA_TGT] != val)
+                       status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
+       }
+
+       /* ACRF */
+       if (status >= 0) {
+               u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) |
+                        (ACRFMAX[Mode] & 0x1F);
+               if (state->reg[MT2063_REG_RF_OV] != val)
+                       status |= mt2063_setreg(state, MT2063_REG_RF_OV, val);
+       }
+
+       /* PD1TGT */
+       if (status >= 0) {
+               u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) |
+                        (PD1TGT[Mode] & 0x3F);
+               if (state->reg[MT2063_REG_PD1_TGT] != val)
+                       status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
+       }
+
+       /* FIFATN */
+       if (status >= 0) {
+               u8 val = ACFIFMAX[Mode];
+               if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5)
+                       val = 5;
+               val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) |
+                     (val & 0x1F);
+               if (state->reg[MT2063_REG_FIF_OV] != val)
+                       status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val);
+       }
+
+       /* PD2TGT */
+       if (status >= 0) {
+               u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) |
+                   (PD2TGT[Mode] & 0x3F);
+               if (state->reg[MT2063_REG_PD2_TGT] != val)
+                       status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val);
+       }
+
+       /* Ignore ATN Overload */
+       if (status >= 0) {
+               val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) |
+                     (RFOVDIS[Mode] ? 0x80 : 0x00);
+               if (state->reg[MT2063_REG_LNA_TGT] != val)
+                       status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
+       }
+
+       /* Ignore FIF Overload */
+       if (status >= 0) {
+               val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) |
+                     (FIFOVDIS[Mode] ? 0x80 : 0x00);
+               if (state->reg[MT2063_REG_PD1_TGT] != val)
+                       status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
+       }
+
+       if (status >= 0) {
+               state->rcvr_mode = Mode;
+               dprintk(1, "mt2063 mode changed to %s\n",
+                       mt2063_mode_name[state->rcvr_mode]);
+       }
+
+       return status;
+}
+
+/*
+ * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various
+ *                               sections of the MT2063
+ *
+ * @Bits:              Mask bits to be cleared.
+ *
+ * See definition of MT2063_Mask_Bits type for description
+ * of each of the power bits.
+ */
+static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state,
+                                    enum MT2063_Mask_Bits Bits)
+{
+       u32 status = 0;
+
+       dprintk(2, "\n");
+       Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD);   /* Only valid bits for this tuner */
+       if ((Bits & 0xFF00) != 0) {
+               state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8);
+               status |=
+                   mt2063_write(state,
+                                   MT2063_REG_PWR_2,
+                                   &state->reg[MT2063_REG_PWR_2], 1);
+       }
+       if ((Bits & 0xFF) != 0) {
+               state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF);
+               status |=
+                   mt2063_write(state,
+                                   MT2063_REG_PWR_1,
+                                   &state->reg[MT2063_REG_PWR_1], 1);
+       }
+
+       return status;
+}
+
+/*
+ * MT2063_SoftwareShutdown() - Enables or disables software shutdown function.
+ *                            When Shutdown is 1, any section whose power
+ *                            mask is set will be shutdown.
+ */
+static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown)
+{
+       u32 status;
+
+       dprintk(2, "\n");
+       if (Shutdown == 1)
+               state->reg[MT2063_REG_PWR_1] |= 0x04;
+       else
+               state->reg[MT2063_REG_PWR_1] &= ~0x04;
+
+       status = mt2063_write(state,
+                           MT2063_REG_PWR_1,
+                           &state->reg[MT2063_REG_PWR_1], 1);
+
+       if (Shutdown != 1) {
+               state->reg[MT2063_REG_BYP_CTRL] =
+                   (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40;
+               status |=
+                   mt2063_write(state,
+                                   MT2063_REG_BYP_CTRL,
+                                   &state->reg[MT2063_REG_BYP_CTRL],
+                                   1);
+               state->reg[MT2063_REG_BYP_CTRL] =
+                   (state->reg[MT2063_REG_BYP_CTRL] & 0x9F);
+               status |=
+                   mt2063_write(state,
+                                   MT2063_REG_BYP_CTRL,
+                                   &state->reg[MT2063_REG_BYP_CTRL],
+                                   1);
+       }
+
+       return status;
+}
+
+static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref)
+{
+       return f_ref * (f_LO / f_ref)
+           + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step);
+}
+
+/**
+ * fLO_FractionalTerm() - Calculates the portion contributed by FracN / denom.
+ *                        This function preserves maximum precision without
+ *                        risk of overflow.  It accurately calculates
+ *                        f_ref * num / denom to within 1 HZ with fixed math.
+ *
+ * @num :      Fractional portion of the multiplier
+ * @denom:     denominator portion of the ratio
+ * @f_Ref:     SRO frequency.
+ *
+ * This calculation handles f_ref as two separate 14-bit fields.
+ * Therefore, a maximum value of 2^28-1 may safely be used for f_ref.
+ * This is the genesis of the magic number "14" and the magic mask value of
+ * 0x03FFF.
+ *
+ * This routine successfully handles denom values up to and including 2^18.
+ *  Returns:        f_ref * num / denom
+ */
+static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom)
+{
+       u32 t1 = (f_ref >> 14) * num;
+       u32 term1 = t1 / denom;
+       u32 loss = t1 % denom;
+       u32 term2 =
+           (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom;
+       return (term1 << 14) + term2;
+}
+
+/*
+ * CalcLO1Mult()- Calculates Integer divider value and the numerator
+ *                value for a FracN PLL.
+ *
+ *                This function assumes that the f_LO and f_Ref are
+ *                evenly divisible by f_LO_Step.
+ *
+ * @Div:       OUTPUT: Whole number portion of the multiplier
+ * @FracN:     OUTPUT: Fractional portion of the multiplier
+ * @f_LO:      desired LO frequency.
+ * @f_LO_Step: Minimum step size for the LO (in Hz).
+ * @f_Ref:     SRO frequency.
+ * @f_Avoid:   Range of PLL frequencies to avoid near integer multiples
+ *             of f_Ref (in Hz).
+ *
+ * Returns:        Recalculated LO frequency.
+ */
+static u32 MT2063_CalcLO1Mult(u32 *Div,
+                             u32 *FracN,
+                             u32 f_LO,
+                             u32 f_LO_Step, u32 f_Ref)
+{
+       /*  Calculate the whole number portion of the divider */
+       *Div = f_LO / f_Ref;
+
+       /*  Calculate the numerator value (round to nearest f_LO_Step) */
+       *FracN =
+           (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
+            (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
+
+       return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64);
+}
+
+/**
+ * CalcLO2Mult() - Calculates Integer divider value and the numerator
+ *                 value for a FracN PLL.
+ *
+ *                  This function assumes that the f_LO and f_Ref are
+ *                  evenly divisible by f_LO_Step.
+ *
+ * @Div:       OUTPUT: Whole number portion of the multiplier
+ * @FracN:     OUTPUT: Fractional portion of the multiplier
+ * @f_LO:      desired LO frequency.
+ * @f_LO_Step: Minimum step size for the LO (in Hz).
+ * @f_Ref:     SRO frequency.
+ * @f_Avoid:   Range of PLL frequencies to avoid near
+ *             integer multiples of f_Ref (in Hz).
+ *
+ * Returns: Recalculated LO frequency.
+ */
+static u32 MT2063_CalcLO2Mult(u32 *Div,
+                             u32 *FracN,
+                             u32 f_LO,
+                             u32 f_LO_Step, u32 f_Ref)
+{
+       /*  Calculate the whole number portion of the divider */
+       *Div = f_LO / f_Ref;
+
+       /*  Calculate the numerator value (round to nearest f_LO_Step) */
+       *FracN =
+           (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) +
+            (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step);
+
+       return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN,
+                                                           8191);
+}
+
+/*
+ * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be
+ *                        used for a given input frequency.
+ *
+ * @state:     ptr to tuner data structure
+ * @f_in:      RF input center frequency (in Hz).
+ *
+ * Returns: ClearTune filter number (0-31)
+ */
+static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in)
+{
+       u32 RFBand;
+       u32 idx;                /*  index loop                      */
+
+       /*
+        **  Find RF Band setting
+        */
+       RFBand = 31;            /*  def when f_in > all    */
+       for (idx = 0; idx < 31; ++idx) {
+               if (state->CTFiltMax[idx] >= f_in) {
+                       RFBand = idx;
+                       break;
+               }
+       }
+       return RFBand;
+}
+
+/*
+ * MT2063_Tune() - Change the tuner's tuned frequency to RFin.
+ */
+static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in)
+{                              /* RF input center frequency   */
+
+       u32 status = 0;
+       u32 LO1;                /*  1st LO register value           */
+       u32 Num1;               /*  Numerator for LO1 reg. value    */
+       u32 f_IF1;              /*  1st IF requested                */
+       u32 LO2;                /*  2nd LO register value           */
+       u32 Num2;               /*  Numerator for LO2 reg. value    */
+       u32 ofLO1, ofLO2;       /*  last time's LO frequencies      */
+       u8 fiffc = 0x80;        /*  FIFF center freq from tuner     */
+       u32 fiffof;             /*  Offset from FIFF center freq    */
+       const u8 LO1LK = 0x80;  /*  Mask for LO1 Lock bit           */
+       u8 LO2LK = 0x08;        /*  Mask for LO2 Lock bit           */
+       u8 val;
+       u32 RFBand;
+
+       dprintk(2, "\n");
+       /*  Check the input and output frequency ranges                   */
+       if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ))
+               return -EINVAL;
+
+       if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ)
+           || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ))
+               return -EINVAL;
+
+       /*
+        * Save original LO1 and LO2 register values
+        */
+       ofLO1 = state->AS_Data.f_LO1;
+       ofLO2 = state->AS_Data.f_LO2; 
+
+       /*
+        * Find and set RF Band setting
+        */
+       if (state->ctfilt_sw == 1) {
+               val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08);
+               if (state->reg[MT2063_REG_CTUNE_CTRL] != val) {
+                       status |=
+                           mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val);
+               }
+               val = state->reg[MT2063_REG_CTUNE_OV];
+               RFBand = FindClearTuneFilter(state, f_in);
+               state->reg[MT2063_REG_CTUNE_OV] =
+                   (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F)
+                             | RFBand);
+               if (state->reg[MT2063_REG_CTUNE_OV] != val) {
+                       status |=
+                           mt2063_setreg(state, MT2063_REG_CTUNE_OV, val);
+               }
+       }
+
+       /*
+        * Read the FIFF Center Frequency from the tuner
+        */
+       if (status >= 0) {
+               status |=
+                   mt2063_read(state,
+                                  MT2063_REG_FIFFC,
+                                  &state->reg[MT2063_REG_FIFFC], 1);
+               fiffc = state->reg[MT2063_REG_FIFFC];
+       }
+       /*
+        * Assign in the requested values
+        */
+       state->AS_Data.f_in = f_in;
+       /*  Request a 1st IF such that LO1 is on a step size */
+       state->AS_Data.f_if1_Request =
+           MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in,
+                            state->AS_Data.f_LO1_Step,
+                            state->AS_Data.f_ref) - f_in;
+
+       /*
+        * Calculate frequency settings.  f_IF1_FREQ + f_in is the
+        * desired LO1 frequency
+        */
+       MT2063_ResetExclZones(&state->AS_Data);
+
+       f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data);
+
+       state->AS_Data.f_LO1 =
+           MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step,
+                            state->AS_Data.f_ref);
+
+       state->AS_Data.f_LO2 =
+           MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
+                            state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
+
+       /*
+        * Check for any LO spurs in the output bandwidth and adjust
+        * the LO settings to avoid them if needed
+        */
+       status |= MT2063_AvoidSpurs(&state->AS_Data);
+       /*
+        * MT_AvoidSpurs spurs may have changed the LO1 & LO2 values.
+        * Recalculate the LO frequencies and the values to be placed
+        * in the tuning registers.
+        */
+       state->AS_Data.f_LO1 =
+           MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1,
+                              state->AS_Data.f_LO1_Step, state->AS_Data.f_ref);
+       state->AS_Data.f_LO2 =
+           MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in,
+                            state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
+       state->AS_Data.f_LO2 =
+           MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2,
+                              state->AS_Data.f_LO2_Step, state->AS_Data.f_ref);
+
+       /*
+        *  Check the upconverter and downconverter frequency ranges
+        */
+       if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ)
+           || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ))
+               status |= MT2063_UPC_RANGE;
+       if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ)
+           || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ))
+               status |= MT2063_DNC_RANGE;
+       /*  LO2 Lock bit was in a different place for B0 version  */
+       if (state->tuner_id == MT2063_B0)
+               LO2LK = 0x40;
+
+       /*
+        *  If we have the same LO frequencies and we're already locked,
+        *  then skip re-programming the LO registers.
+        */
+       if ((ofLO1 != state->AS_Data.f_LO1)
+           || (ofLO2 != state->AS_Data.f_LO2)
+           || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) !=
+               (LO1LK | LO2LK))) {
+               /*
+                * Calculate the FIFFOF register value
+                *
+                *           IF1_Actual
+                * FIFFOF = ------------ - 8 * FIFFC - 4992
+                *            f_ref/64
+                */
+               fiffof =
+                   (state->AS_Data.f_LO1 -
+                    f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc -
+                   4992;
+               if (fiffof > 0xFF)
+                       fiffof = 0xFF;
+
+               /*
+                * Place all of the calculated values into the local tuner
+                * register fields.
+                */
+               if (status >= 0) {
+                       state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF);     /* DIV1q */
+                       state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F);    /* NUM1q */
+                       state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1)      /* DIV2q */
+                                                                  |(Num2 >> 12));      /* NUM2q (hi) */
+                       state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4);   /* NUM2q (mid) */
+                       state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */
+
+                       /*
+                        * Now write out the computed register values
+                        * IMPORTANT: There is a required order for writing
+                        *            (0x05 must follow all the others).
+                        */
+                       status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5);  /* 0x01 - 0x05 */
+                       if (state->tuner_id == MT2063_B0) {
+                               /* Re-write the one-shot bits to trigger the tune operation */
+                               status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1);  /* 0x05 */
+                       }
+                       /* Write out the FIFF offset only if it's changing */
+                       if (state->reg[MT2063_REG_FIFF_OFFSET] !=
+                           (u8) fiffof) {
+                               state->reg[MT2063_REG_FIFF_OFFSET] =
+                                   (u8) fiffof;
+                               status |=
+                                   mt2063_write(state,
+                                                   MT2063_REG_FIFF_OFFSET,
+                                                   &state->
+                                                   reg[MT2063_REG_FIFF_OFFSET],
+                                                   1);
+                       }
+               }
+
+               /*
+                * Check for LO's locking
+                */
+
+               if (status < 0)
+                       return status;
+
+               status = mt2063_lockStatus(state);
+               if (status < 0)
+                       return status;
+               if (!status)
+                       return -EINVAL;         /* Couldn't lock */
+
+               /*
+                * If we locked OK, assign calculated data to mt2063_state structure
+                */
+               state->f_IF1_actual = state->AS_Data.f_LO1 - f_in;
+       }
+
+       return status;
+}
+
+static const u8 MT2063B0_defaults[] = {
+       /* Reg,  Value */
+       0x19, 0x05,
+       0x1B, 0x1D,
+       0x1C, 0x1F,
+       0x1D, 0x0F,
+       0x1E, 0x3F,
+       0x1F, 0x0F,
+       0x20, 0x3F,
+       0x22, 0x21,
+       0x23, 0x3F,
+       0x24, 0x20,
+       0x25, 0x3F,
+       0x27, 0xEE,
+       0x2C, 0x27,     /*  bit at 0x20 is cleared below  */
+       0x30, 0x03,
+       0x2C, 0x07,     /*  bit at 0x20 is cleared here   */
+       0x2D, 0x87,
+       0x2E, 0xAA,
+       0x28, 0xE1,     /*  Set the FIFCrst bit here      */
+       0x28, 0xE0,     /*  Clear the FIFCrst bit here    */
+       0x00
+};
+
+/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
+static const u8 MT2063B1_defaults[] = {
+       /* Reg,  Value */
+       0x05, 0xF0,
+       0x11, 0x10,     /* New Enable AFCsd */
+       0x19, 0x05,
+       0x1A, 0x6C,
+       0x1B, 0x24,
+       0x1C, 0x28,
+       0x1D, 0x8F,
+       0x1E, 0x14,
+       0x1F, 0x8F,
+       0x20, 0x57,
+       0x22, 0x21,     /* New - ver 1.03 */
+       0x23, 0x3C,     /* New - ver 1.10 */
+       0x24, 0x20,     /* New - ver 1.03 */
+       0x2C, 0x24,     /*  bit at 0x20 is cleared below  */
+       0x2D, 0x87,     /*  FIFFQ=0  */
+       0x2F, 0xF3,
+       0x30, 0x0C,     /* New - ver 1.11 */
+       0x31, 0x1B,     /* New - ver 1.11 */
+       0x2C, 0x04,     /*  bit at 0x20 is cleared here  */
+       0x28, 0xE1,     /*  Set the FIFCrst bit here      */
+       0x28, 0xE0,     /*  Clear the FIFCrst bit here    */
+       0x00
+};
+
+/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */
+static const u8 MT2063B3_defaults[] = {
+       /* Reg,  Value */
+       0x05, 0xF0,
+       0x19, 0x3D,
+       0x2C, 0x24,     /*  bit at 0x20 is cleared below  */
+       0x2C, 0x04,     /*  bit at 0x20 is cleared here  */
+       0x28, 0xE1,     /*  Set the FIFCrst bit here      */
+       0x28, 0xE0,     /*  Clear the FIFCrst bit here    */
+       0x00
+};
+
+static int mt2063_init(struct dvb_frontend *fe)
+{
+       u32 status;
+       struct mt2063_state *state = fe->tuner_priv;
+       u8 all_resets = 0xF0;   /* reset/load bits */
+       const u8 *def = NULL;
+       char *step;
+       u32 FCRUN;
+       s32 maxReads;
+       u32 fcu_osc;
+       u32 i;
+
+       dprintk(2, "\n");
+
+       state->rcvr_mode = MT2063_CABLE_QAM;
+
+       /*  Read the Part/Rev code from the tuner */
+       status = mt2063_read(state, MT2063_REG_PART_REV,
+                            &state->reg[MT2063_REG_PART_REV], 1);
+       if (status < 0) {
+               printk(KERN_ERR "Can't read mt2063 part ID\n");
+               return status;
+       }
+
+       /* Check the part/rev code */
+       switch (state->reg[MT2063_REG_PART_REV]) {
+       case MT2063_B0:
+               step = "B0";
+               break;
+       case MT2063_B1:
+               step = "B1";
+               break;
+       case MT2063_B2:
+               step = "B2";
+               break;
+       case MT2063_B3:
+               step = "B3";
+               break;
+       default:
+               printk(KERN_ERR "mt2063: Unknown mt2063 device ID (0x%02x)\n",
+                      state->reg[MT2063_REG_PART_REV]);
+               return -ENODEV; /*  Wrong tuner Part/Rev code */
+       }
+
+       /*  Check the 2nd byte of the Part/Rev code from the tuner */
+       status = mt2063_read(state, MT2063_REG_RSVD_3B,
+                            &state->reg[MT2063_REG_RSVD_3B], 1);
+
+       /* b7 != 0 ==> NOT MT2063 */
+       if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) {
+               printk(KERN_ERR "mt2063: Unknown part ID (0x%02x%02x)\n",
+                      state->reg[MT2063_REG_PART_REV],
+                      state->reg[MT2063_REG_RSVD_3B]);
+               return -ENODEV; /*  Wrong tuner Part/Rev code */
+       }
+
+       printk(KERN_INFO "mt2063: detected a mt2063 %s\n", step);
+
+       /*  Reset the tuner  */
+       status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1);
+       if (status < 0)
+               return status;
+
+       /* change all of the default values that vary from the HW reset values */
+       /*  def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */
+       switch (state->reg[MT2063_REG_PART_REV]) {
+       case MT2063_B3:
+               def = MT2063B3_defaults;
+               break;
+
+       case MT2063_B1:
+               def = MT2063B1_defaults;
+               break;
+
+       case MT2063_B0:
+               def = MT2063B0_defaults;
+               break;
+
+       default:
+               return -ENODEV;
+               break;
+       }
+
+       while (status >= 0 && *def) {
+               u8 reg = *def++;
+               u8 val = *def++;
+               status = mt2063_write(state, reg, &val, 1);
+       }
+       if (status < 0)
+               return status;
+
+       /*  Wait for FIFF location to complete.  */
+       FCRUN = 1;
+       maxReads = 10;
+       while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) {
+               msleep(2);
+               status = mt2063_read(state,
+                                        MT2063_REG_XO_STATUS,
+                                        &state->
+                                        reg[MT2063_REG_XO_STATUS], 1);
+               FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6;
+       }
+
+       if (FCRUN != 0 || status < 0)
+               return -ENODEV;
+
+       status = mt2063_read(state,
+                          MT2063_REG_FIFFC,
+                          &state->reg[MT2063_REG_FIFFC], 1);
+       if (status < 0)
+               return status;
+
+       /* Read back all the registers from the tuner */
+       status = mt2063_read(state,
+                               MT2063_REG_PART_REV,
+                               state->reg, MT2063_REG_END_REGS);
+       if (status < 0)
+               return status;
+
+       /*  Initialize the tuner state.  */
+       state->tuner_id = state->reg[MT2063_REG_PART_REV];
+       state->AS_Data.f_ref = MT2063_REF_FREQ;
+       state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) *
+                                     ((u32) state->reg[MT2063_REG_FIFFC] + 640);
+       state->AS_Data.f_if1_bw = MT2063_IF1_BW;
+       state->AS_Data.f_out = 43750000UL;
+       state->AS_Data.f_out_bw = 6750000UL;
+       state->AS_Data.f_zif_bw = MT2063_ZIF_BW;
+       state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64;
+       state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE;
+       state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1;
+       state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2;
+       state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP;
+       state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center;
+       state->AS_Data.f_LO1 = 2181000000UL;
+       state->AS_Data.f_LO2 = 1486249786UL;
+       state->f_IF1_actual = state->AS_Data.f_if1_Center;
+       state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual;
+       state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID;
+       state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID;
+       state->num_regs = MT2063_REG_END_REGS;
+       state->AS_Data.avoidDECT = MT2063_AVOID_BOTH;
+       state->ctfilt_sw = 0;
+
+       state->CTFiltMax[0] = 69230000;
+       state->CTFiltMax[1] = 105770000;
+       state->CTFiltMax[2] = 140350000;
+       state->CTFiltMax[3] = 177110000;
+       state->CTFiltMax[4] = 212860000;
+       state->CTFiltMax[5] = 241130000;
+       state->CTFiltMax[6] = 274370000;
+       state->CTFiltMax[7] = 309820000;
+       state->CTFiltMax[8] = 342450000;
+       state->CTFiltMax[9] = 378870000;
+       state->CTFiltMax[10] = 416210000;
+       state->CTFiltMax[11] = 456500000;
+       state->CTFiltMax[12] = 495790000;
+       state->CTFiltMax[13] = 534530000;
+       state->CTFiltMax[14] = 572610000;
+       state->CTFiltMax[15] = 598970000;
+       state->CTFiltMax[16] = 635910000;
+       state->CTFiltMax[17] = 672130000;
+       state->CTFiltMax[18] = 714840000;
+       state->CTFiltMax[19] = 739660000;
+       state->CTFiltMax[20] = 770410000;
+       state->CTFiltMax[21] = 814660000;
+       state->CTFiltMax[22] = 846950000;
+       state->CTFiltMax[23] = 867820000;
+       state->CTFiltMax[24] = 915980000;
+       state->CTFiltMax[25] = 947450000;
+       state->CTFiltMax[26] = 983110000;
+       state->CTFiltMax[27] = 1021630000;
+       state->CTFiltMax[28] = 1061870000;
+       state->CTFiltMax[29] = 1098330000;
+       state->CTFiltMax[30] = 1138990000;
+
+       /*
+        **   Fetch the FCU osc value and use it and the fRef value to
+        **   scale all of the Band Max values
+        */
+
+       state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A;
+       status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
+                             &state->reg[MT2063_REG_CTUNE_CTRL], 1);
+       if (status < 0)
+               return status;
+
+       /*  Read the ClearTune filter calibration value  */
+       status = mt2063_read(state, MT2063_REG_FIFFC,
+                            &state->reg[MT2063_REG_FIFFC], 1);
+       if (status < 0)
+               return status;
+
+       fcu_osc = state->reg[MT2063_REG_FIFFC];
+
+       state->reg[MT2063_REG_CTUNE_CTRL] = 0x00;
+       status = mt2063_write(state, MT2063_REG_CTUNE_CTRL,
+                             &state->reg[MT2063_REG_CTUNE_CTRL], 1);
+       if (status < 0)
+               return status;
+
+       /*  Adjust each of the values in the ClearTune filter cross-over table  */
+       for (i = 0; i < 31; i++)
+               state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640);
+
+       status = MT2063_SoftwareShutdown(state, 1);
+       if (status < 0)
+               return status;
+       status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
+       if (status < 0)
+               return status;
+
+       state->init = true;
+
+       return 0;
+}
+
+static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status)
+{
+       struct mt2063_state *state = fe->tuner_priv;
+       int status;
+
+       dprintk(2, "\n");
+
+       if (!state->init)
+               return -ENODEV;
+
+       *tuner_status = 0;
+       status = mt2063_lockStatus(state);
+       if (status < 0)
+               return status;
+       if (status)
+               *tuner_status = TUNER_STATUS_LOCKED;
+
+       dprintk(1, "Tuner status: %d", *tuner_status);
+
+       return 0;
+}
+
+static int mt2063_release(struct dvb_frontend *fe)
+{
+       struct mt2063_state *state = fe->tuner_priv;
+
+       dprintk(2, "\n");
+
+       fe->tuner_priv = NULL;
+       kfree(state);
+
+       return 0;
+}
+
+static int mt2063_set_analog_params(struct dvb_frontend *fe,
+                                   struct analog_parameters *params)
+{
+       struct mt2063_state *state = fe->tuner_priv;
+       s32 pict_car;
+       s32 pict2chanb_vsb;
+       s32 ch_bw;
+       s32 if_mid;
+       s32 rcvr_mode;
+       int status;
+
+       dprintk(2, "\n");
+
+       if (!state->init) {
+               status = mt2063_init(fe);
+               if (status < 0)
+                       return status;
+       }
+
+       switch (params->mode) {
+       case V4L2_TUNER_RADIO:
+               pict_car = 38900000;
+               ch_bw = 8000000;
+               pict2chanb_vsb = -(ch_bw / 2);
+               rcvr_mode = MT2063_OFFAIR_ANALOG;
+               break;
+       case V4L2_TUNER_ANALOG_TV:
+               rcvr_mode = MT2063_CABLE_ANALOG;
+               if (params->std & ~V4L2_STD_MN) {
+                       pict_car = 38900000;
+                       ch_bw = 6000000;
+                       pict2chanb_vsb = -1250000;
+               } else if (params->std & V4L2_STD_PAL_G) {
+                       pict_car = 38900000;
+                       ch_bw = 7000000;
+                       pict2chanb_vsb = -1250000;
+               } else {                /* PAL/SECAM standards */
+                       pict_car = 38900000;
+                       ch_bw = 8000000;
+                       pict2chanb_vsb = -1250000;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+       if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
+
+       state->AS_Data.f_LO2_Step = 125000;     /* FIXME: probably 5000 for FM */
+       state->AS_Data.f_out = if_mid;
+       state->AS_Data.f_out_bw = ch_bw + 750000;
+       status = MT2063_SetReceiverMode(state, rcvr_mode);
+       if (status < 0)
+               return status;
+
+       dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n",
+               params->frequency, ch_bw, pict2chanb_vsb);
+
+       status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2))));
+       if (status < 0)
+               return status;
+
+       state->frequency = params->frequency;
+       return 0;
+}
+
+/*
+ * As defined on EN 300 429, the DVB-C roll-off factor is 0.15.
+ * So, the amount of the needed bandwith is given by:
+ *     Bw = Symbol_rate * (1 + 0.15)
+ * As such, the maximum symbol rate supported by 6 MHz is given by:
+ *     max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
+ */
+#define MAX_SYMBOL_RATE_6MHz   5217391
+
+static int mt2063_set_params(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct mt2063_state *state = fe->tuner_priv;
+       int status;
+       s32 pict_car;
+       s32 pict2chanb_vsb;
+       s32 ch_bw;
+       s32 if_mid;
+       s32 rcvr_mode;
+
+       if (!state->init) {
+               status = mt2063_init(fe);
+               if (status < 0)
+                       return status;
+       }
+
+       dprintk(2, "\n");
+
+       if (c->bandwidth_hz == 0)
+               return -EINVAL;
+       if (c->bandwidth_hz <= 6000000)
+               ch_bw = 6000000;
+       else if (c->bandwidth_hz <= 7000000)
+               ch_bw = 7000000;
+       else
+               ch_bw = 8000000;
+
+       switch (c->delivery_system) {
+       case SYS_DVBT:
+               rcvr_mode = MT2063_OFFAIR_COFDM;
+               pict_car = 36125000;
+               pict2chanb_vsb = -(ch_bw / 2);
+               break;
+       case SYS_DVBC_ANNEX_A:
+       case SYS_DVBC_ANNEX_C:
+               rcvr_mode = MT2063_CABLE_QAM;
+               pict_car = 36125000;
+               pict2chanb_vsb = -(ch_bw / 2);
+               break;
+       default:
+               return -EINVAL;
+       }
+       if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2));
+
+       state->AS_Data.f_LO2_Step = 125000;     /* FIXME: probably 5000 for FM */
+       state->AS_Data.f_out = if_mid;
+       state->AS_Data.f_out_bw = ch_bw + 750000;
+       status = MT2063_SetReceiverMode(state, rcvr_mode);
+       if (status < 0)
+               return status;
+
+       dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n",
+               c->frequency, ch_bw, pict2chanb_vsb);
+
+       status = MT2063_Tune(state, (c->frequency + (pict2chanb_vsb + (ch_bw / 2))));
+
+       if (status < 0)
+               return status;
+
+       state->frequency = c->frequency;
+       return 0;
+}
+
+static int mt2063_get_if_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+       struct mt2063_state *state = fe->tuner_priv;
+
+       dprintk(2, "\n");
+
+       if (!state->init)
+               return -ENODEV;
+
+       *freq = state->AS_Data.f_out;
+
+       dprintk(1, "IF frequency: %d\n", *freq);
+
+       return 0;
+}
+
+static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+       struct mt2063_state *state = fe->tuner_priv;
+
+       dprintk(2, "\n");
+
+       if (!state->init)
+               return -ENODEV;
+
+       *bw = state->AS_Data.f_out_bw - 750000;
+
+       dprintk(1, "bandwidth: %d\n", *bw);
+
+       return 0;
+}
+
+static struct dvb_tuner_ops mt2063_ops = {
+       .info = {
+                .name = "MT2063 Silicon Tuner",
+                .frequency_min = 45000000,
+                .frequency_max = 850000000,
+                .frequency_step = 0,
+                },
+
+       .init = mt2063_init,
+       .sleep = MT2063_Sleep,
+       .get_status = mt2063_get_status,
+       .set_analog_params = mt2063_set_analog_params,
+       .set_params    = mt2063_set_params,
+       .get_if_frequency = mt2063_get_if_frequency,
+       .get_bandwidth = mt2063_get_bandwidth,
+       .release = mt2063_release,
+};
+
+struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
+                                  struct mt2063_config *config,
+                                  struct i2c_adapter *i2c)
+{
+       struct mt2063_state *state = NULL;
+
+       dprintk(2, "\n");
+
+       state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       state->config = config;
+       state->i2c = i2c;
+       state->frontend = fe;
+       state->reference = config->refclock / 1000;     /* kHz */
+       fe->tuner_priv = state;
+       fe->ops.tuner_ops = mt2063_ops;
+
+       printk(KERN_INFO "%s: Attaching MT2063\n", __func__);
+       return fe;
+
+error:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(mt2063_attach);
+
+/*
+ * Ancillary routines visible outside mt2063
+ * FIXME: Remove them in favor of using standard tuner callbacks
+ */
+unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe)
+{
+       struct mt2063_state *state = fe->tuner_priv;
+       int err = 0;
+
+       dprintk(2, "\n");
+
+       err = MT2063_SoftwareShutdown(state, 1);
+       if (err < 0)
+               printk(KERN_ERR "%s: Couldn't shutdown\n", __func__);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown);
+
+unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe)
+{
+       struct mt2063_state *state = fe->tuner_priv;
+       int err = 0;
+
+       dprintk(2, "\n");
+
+       err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD);
+       if (err < 0)
+               printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits);
+
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_DESCRIPTION("MT2063 Silicon tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/mt2063.h b/drivers/media/common/tuners/mt2063.h
new file mode 100644 (file)
index 0000000..62d0e8e
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __MT2063_H__
+#define __MT2063_H__
+
+#include "dvb_frontend.h"
+
+struct mt2063_config {
+       u8 tuner_address;
+       u32 refclock;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_MT2063) || (defined(CONFIG_MEDIA_TUNER_MT2063_MODULE) && defined(MODULE))
+struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
+                                  struct mt2063_config *config,
+                                  struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
+                                  struct mt2063_config *config,
+                                  struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+int mt2063_setTune(struct dvb_frontend *fe, u32 f_in,
+                                  u32 bw_in,
+                                  enum MTTune_atv_standard tv_type);
+
+/* FIXME: Should use the standard DVB attachment interfaces */
+unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe);
+unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe);
+
+#endif /* CONFIG_DVB_MT2063 */
+
+#endif /* __MT2063_H__ */
index a4f830bb25d1346a8961f15fd477d64023424604..f83b0c1ea6c86ad08e1f2252cde018077189d0db 100644 (file)
@@ -92,9 +92,9 @@ static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len)
        return 0;
 }
 
-static int mt2131_set_params(struct dvb_frontend *fe,
-                            struct dvb_frontend_parameters *params)
+static int mt2131_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct mt2131_priv *priv;
        int ret=0, i;
        u32 freq;
@@ -105,12 +105,8 @@ static int mt2131_set_params(struct dvb_frontend *fe,
        u8 lockval = 0;
 
        priv = fe->tuner_priv;
-       if (fe->ops.info.type == FE_OFDM)
-               priv->bandwidth = params->u.ofdm.bandwidth;
-       else
-               priv->bandwidth = 0;
 
-       freq = params->frequency / 1000;  // Hz -> kHz
+       freq = c->frequency / 1000;  /* Hz -> kHz */
        dprintk(1, "%s() freq=%d\n", __func__, freq);
 
        f_lo1 = freq + MT2131_IF1 * 1000;
@@ -193,14 +189,6 @@ static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency)
        return 0;
 }
 
-static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
-       struct mt2131_priv *priv = fe->tuner_priv;
-       dprintk(1, "%s()\n", __func__);
-       *bandwidth = priv->bandwidth;
-       return 0;
-}
-
 static int mt2131_get_status(struct dvb_frontend *fe, u32 *status)
 {
        struct mt2131_priv *priv = fe->tuner_priv;
@@ -263,7 +251,6 @@ static const struct dvb_tuner_ops mt2131_tuner_ops = {
 
        .set_params    = mt2131_set_params,
        .get_frequency = mt2131_get_frequency,
-       .get_bandwidth = mt2131_get_bandwidth,
        .get_status    = mt2131_get_status
 };
 
@@ -281,7 +268,6 @@ struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe,
                return NULL;
 
        priv->cfg = cfg;
-       priv->bandwidth = 6000000; /* 6MHz */
        priv->i2c = i2c;
 
        if (mt2131_readreg(priv, 0, &id) != 0) {
index 4e05a67e88c1419580fe410450c07bf00c66f8e4..62aeedf5c5503198a606bbff9fe443c780ac288d 100644 (file)
@@ -38,7 +38,6 @@ struct mt2131_priv {
        struct i2c_adapter   *i2c;
 
        u32 frequency;
-       u32 bandwidth;
 };
 
 #endif /* __MT2131_PRIV_H__ */
index 25a8ea342c466d60a767d7d4b4ea622003125add..bca4d75e42d468a6e6662a222b792b38385601e5 100644 (file)
@@ -122,8 +122,9 @@ static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
 
 #define FREF 30000       // Quartz oscillator 30 MHz
 
-static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int mt2266_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct mt2266_priv *priv;
        int ret=0;
        u32 freq;
@@ -135,32 +136,32 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
 
        priv = fe->tuner_priv;
 
-       freq = params->frequency / 1000; // Hz -> kHz
+       freq = priv->frequency / 1000; /* Hz -> kHz */
        if (freq < 470000 && freq > 230000)
                return -EINVAL; /* Gap between VHF and UHF bands */
-       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
-       priv->frequency = freq * 1000;
 
+       priv->frequency = c->frequency;
        tune = 2 * freq * (8192/16) / (FREF/16);
        band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
        if (band == MT2266_VHF)
                tune *= 2;
 
-       switch (params->u.ofdm.bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       switch (c->bandwidth_hz) {
+       case 6000000:
                mt2266_writeregs(priv, mt2266_init_6mhz,
                                 sizeof(mt2266_init_6mhz));
                break;
-       case BANDWIDTH_7_MHZ:
-               mt2266_writeregs(priv, mt2266_init_7mhz,
-                                sizeof(mt2266_init_7mhz));
-               break;
-       case BANDWIDTH_8_MHZ:
-       default:
+       case 8000000:
                mt2266_writeregs(priv, mt2266_init_8mhz,
                                 sizeof(mt2266_init_8mhz));
                break;
+       case 7000000:
+       default:
+               mt2266_writeregs(priv, mt2266_init_7mhz,
+                                sizeof(mt2266_init_7mhz));
+               break;
        }
+       priv->bandwidth = c->bandwidth_hz;
 
        if (band == MT2266_VHF && priv->band == MT2266_UHF) {
                dprintk("Switch from UHF to VHF");
index 54be9e6faaaf394c8be9020a39119af149058d28..6133315fb0e34ed5b48ba5e26c2bc48e249d8722 100644 (file)
@@ -3979,54 +3979,47 @@ static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type,
        return 0;
 }
 
-static int mxl5005s_set_params(struct dvb_frontend *fe,
-                              struct dvb_frontend_parameters *params)
+static int mxl5005s_set_params(struct dvb_frontend *fe)
 {
        struct mxl5005s_state *state = fe->tuner_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 delsys = c->delivery_system;
+       u32 bw = c->bandwidth_hz;
        u32 req_mode, req_bw = 0;
        int ret;
 
        dprintk(1, "%s()\n", __func__);
 
-       if (fe->ops.info.type == FE_ATSC) {
-               switch (params->u.vsb.modulation) {
-               case VSB_8:
-                       req_mode = MXL_ATSC; break;
-               default:
-               case QAM_64:
-               case QAM_256:
-               case QAM_AUTO:
-                       req_mode = MXL_QAM; break;
-               }
-       } else
+       switch (delsys) {
+       case SYS_ATSC:
+               req_mode = MXL_ATSC;
+               req_bw  = MXL5005S_BANDWIDTH_6MHZ;
+               break;
+       case SYS_DVBC_ANNEX_B:
+               req_mode = MXL_QAM;
+               req_bw  = MXL5005S_BANDWIDTH_6MHZ;
+               break;
+       default:        /* Assume DVB-T */
                req_mode = MXL_DVBT;
-
-       /* Change tuner for new modulation type if reqd */
-       if (req_mode != state->current_mode) {
-               switch (req_mode) {
-               case MXL_ATSC:
-               case MXL_QAM:
-                       req_bw  = MXL5005S_BANDWIDTH_6MHZ;
+               switch (bw) {
+               case 6000000:
+                       req_bw = MXL5005S_BANDWIDTH_6MHZ;
+                       break;
+               case 7000000:
+                       req_bw = MXL5005S_BANDWIDTH_7MHZ;
+                       break;
+               case 8000000:
+               case 0:
+                       req_bw = MXL5005S_BANDWIDTH_8MHZ;
                        break;
-               case MXL_DVBT:
                default:
-                       /* Assume DVB-T */
-                       switch (params->u.ofdm.bandwidth) {
-                       case BANDWIDTH_6_MHZ:
-                               req_bw  = MXL5005S_BANDWIDTH_6MHZ;
-                               break;
-                       case BANDWIDTH_7_MHZ:
-                               req_bw  = MXL5005S_BANDWIDTH_7MHZ;
-                               break;
-                       case BANDWIDTH_AUTO:
-                       case BANDWIDTH_8_MHZ:
-                               req_bw  = MXL5005S_BANDWIDTH_8MHZ;
-                               break;
-                       default:
-                               return -EINVAL;
-                       }
+                       return -EINVAL;
                }
+       }
 
+       /* Change tuner for new modulation type if reqd */
+       if (req_mode != state->current_mode ||
+           req_bw != state->Chan_Bandwidth) {
                state->current_mode = req_mode;
                ret = mxl5005s_reconfigure(fe, req_mode, req_bw);
 
@@ -4034,8 +4027,8 @@ static int mxl5005s_set_params(struct dvb_frontend *fe,
                ret = 0;
 
        if (ret == 0) {
-               dprintk(1, "%s() freq=%d\n", __func__, params->frequency);
-               ret = mxl5005s_SetRfFreqHz(fe, params->frequency);
+               dprintk(1, "%s() freq=%d\n", __func__, c->frequency);
+               ret = mxl5005s_SetRfFreqHz(fe, c->frequency);
        }
 
        return ret;
index 5d02221e99dd973ad674e56567bab4b369fae7ac..69e453ef0a1a8631ae3067fb9eb2780fa7768040 100644 (file)
@@ -165,6 +165,8 @@ struct mxl5007t_state {
        struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)];
        struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)];
 
+       enum mxl5007t_if_freq if_freq;
+
        u32 frequency;
        u32 bandwidth;
 };
@@ -286,6 +288,8 @@ static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state,
        /* set inverted IF or normal IF */
        set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00);
 
+       state->if_freq = if_freq;
+
        return;
 }
 
@@ -612,47 +616,43 @@ fail:
 
 /* ------------------------------------------------------------------------- */
 
-static int mxl5007t_set_params(struct dvb_frontend *fe,
-                              struct dvb_frontend_parameters *params)
+static int mxl5007t_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 delsys = c->delivery_system;
        struct mxl5007t_state *state = fe->tuner_priv;
        enum mxl5007t_bw_mhz bw;
        enum mxl5007t_mode mode;
        int ret;
-       u32 freq = params->frequency;
+       u32 freq = c->frequency;
 
-       if (fe->ops.info.type == FE_ATSC) {
-               switch (params->u.vsb.modulation) {
-               case VSB_8:
-               case VSB_16:
-                       mode = MxL_MODE_ATSC;
-                       break;
-               case QAM_64:
-               case QAM_256:
-                       mode = MxL_MODE_CABLE;
-                       break;
-               default:
-                       mxl_err("modulation not set!");
-                       return -EINVAL;
-               }
+       switch (delsys) {
+       case SYS_ATSC:
+               mode = MxL_MODE_ATSC;
+               bw = MxL_BW_6MHz;
+               break;
+       case SYS_DVBC_ANNEX_B:
+               mode = MxL_MODE_CABLE;
                bw = MxL_BW_6MHz;
-       } else if (fe->ops.info.type == FE_OFDM) {
-               switch (params->u.ofdm.bandwidth) {
-               case BANDWIDTH_6_MHZ:
+               break;
+       case SYS_DVBT:
+       case SYS_DVBT2:
+               mode = MxL_MODE_DVBT;
+               switch (c->bandwidth_hz) {
+               case 6000000:
                        bw = MxL_BW_6MHz;
                        break;
-               case BANDWIDTH_7_MHZ:
+               case 7000000:
                        bw = MxL_BW_7MHz;
                        break;
-               case BANDWIDTH_8_MHZ:
+               case 8000000:
                        bw = MxL_BW_8MHz;
                        break;
                default:
-                       mxl_err("bandwidth not set!");
                        return -EINVAL;
                }
-               mode = MxL_MODE_DVBT;
-       } else {
+               break;
+       default:
                mxl_err("modulation type not supported!");
                return -EINVAL;
        }
@@ -671,8 +671,7 @@ static int mxl5007t_set_params(struct dvb_frontend *fe,
                goto fail;
 
        state->frequency = freq;
-       state->bandwidth = (fe->ops.info.type == FE_OFDM) ?
-               params->u.ofdm.bandwidth : 0;
+       state->bandwidth = c->bandwidth_hz;
 fail:
        mutex_unlock(&state->lock);
 
@@ -738,6 +737,50 @@ static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
        return 0;
 }
 
+static int mxl5007t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct mxl5007t_state *state = fe->tuner_priv;
+
+       *frequency = 0;
+
+       switch (state->if_freq) {
+       case MxL_IF_4_MHZ:
+               *frequency = 4000000;
+               break;
+       case MxL_IF_4_5_MHZ:
+               *frequency = 4500000;
+               break;
+       case MxL_IF_4_57_MHZ:
+               *frequency = 4570000;
+               break;
+       case MxL_IF_5_MHZ:
+               *frequency = 5000000;
+               break;
+       case MxL_IF_5_38_MHZ:
+               *frequency = 5380000;
+               break;
+       case MxL_IF_6_MHZ:
+               *frequency = 6000000;
+               break;
+       case MxL_IF_6_28_MHZ:
+               *frequency = 6280000;
+               break;
+       case MxL_IF_9_1915_MHZ:
+               *frequency = 9191500;
+               break;
+       case MxL_IF_35_25_MHZ:
+               *frequency = 35250000;
+               break;
+       case MxL_IF_36_15_MHZ:
+               *frequency = 36150000;
+               break;
+       case MxL_IF_44_MHZ:
+               *frequency = 44000000;
+               break;
+       }
+       return 0;
+}
+
 static int mxl5007t_release(struct dvb_frontend *fe)
 {
        struct mxl5007t_state *state = fe->tuner_priv;
@@ -767,6 +810,7 @@ static struct dvb_tuner_ops mxl5007t_tuner_ops = {
        .get_frequency     = mxl5007t_get_frequency,
        .get_bandwidth     = mxl5007t_get_bandwidth,
        .release           = mxl5007t_release,
+       .get_if_frequency  = mxl5007t_get_if_frequency,
 };
 
 static int mxl5007t_get_chip_id(struct mxl5007t_state *state)
index 9f5dba244cb86e7e361e992bbd45fedd41b1a1f9..2d79b1f5d5ebcebe9a00321ee278239ca64d0a7f 100644 (file)
@@ -82,9 +82,9 @@ static void qt1010_dump_regs(struct qt1010_priv *priv)
        printk(KERN_CONT "\n");
 }
 
-static int qt1010_set_params(struct dvb_frontend *fe,
-                            struct dvb_frontend_parameters *params)
+static int qt1010_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct qt1010_priv *priv;
        int err;
        u32 freq, div, mod1, mod2;
@@ -144,13 +144,11 @@ static int qt1010_set_params(struct dvb_frontend *fe,
 #define FREQ2  4000000 /* 4 MHz Quartz oscillator in the stick? */
 
        priv = fe->tuner_priv;
-       freq = params->frequency;
+       freq = c->frequency;
        div = (freq + QT1010_OFFSET) / QT1010_STEP;
        freq = (div * QT1010_STEP) - QT1010_OFFSET;
        mod1 = (freq + QT1010_OFFSET) % FREQ1;
        mod2 = (freq + QT1010_OFFSET) % FREQ2;
-       priv->bandwidth =
-               (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
        priv->frequency = freq;
 
        if (fe->ops.i2c_gate_ctrl)
@@ -320,7 +318,7 @@ static u8 qt1010_init_meas2(struct qt1010_priv *priv,
 static int qt1010_init(struct dvb_frontend *fe)
 {
        struct qt1010_priv *priv = fe->tuner_priv;
-       struct dvb_frontend_parameters params;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int err = 0;
        u8 i, tmpval, *valptr = NULL;
 
@@ -397,9 +395,9 @@ static int qt1010_init(struct dvb_frontend *fe)
                if ((err = qt1010_init_meas2(priv, i, &tmpval)))
                        return err;
 
-       params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */
+       c->frequency = 545000000; /* Sigmatek DVB-110 545000000 */
                                      /* MSI Megasky 580 GL861 533000000 */
-       return qt1010_set_params(fe, &params);
+       return qt1010_set_params(fe);
 }
 
 static int qt1010_release(struct dvb_frontend *fe)
@@ -416,10 +414,9 @@ static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency)
        return 0;
 }
 
-static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+static int qt1010_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
-       struct qt1010_priv *priv = fe->tuner_priv;
-       *bandwidth = priv->bandwidth;
+       *frequency = 36125000;
        return 0;
 }
 
@@ -437,7 +434,7 @@ static const struct dvb_tuner_ops qt1010_tuner_ops = {
 
        .set_params    = qt1010_set_params,
        .get_frequency = qt1010_get_frequency,
-       .get_bandwidth = qt1010_get_bandwidth
+       .get_if_frequency = qt1010_get_if_frequency,
 };
 
 struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe,
index 090cf475f099ea567f5ea7899f684952b62f7795..2c42d3f016366d5f7cb8b11baebee9d1342a3ea3 100644 (file)
@@ -99,7 +99,6 @@ struct qt1010_priv {
        u8 reg25_init_val;
 
        u32 frequency;
-       u32 bandwidth;
 };
 
 #endif
index e29cc2bc113a91604f03b009a7f2877dd4a7d0e2..602c2e392b178c255a2d6fa476b8b2fa439f45d0 100644 (file)
@@ -25,6 +25,8 @@
 struct tda18212_priv {
        struct tda18212_config *cfg;
        struct i2c_adapter *i2c;
+
+       u32 if_frequency;
 };
 
 #define dbg(fmt, arg...)                                       \
@@ -128,20 +130,31 @@ static void tda18212_dump_regs(struct tda18212_priv *priv)
 }
 #endif
 
-static int tda18212_set_params(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int tda18212_set_params(struct dvb_frontend *fe)
 {
        struct tda18212_priv *priv = fe->tuner_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret, i;
        u32 if_khz;
        u8 buf[9];
+       #define DVBT_6   0
+       #define DVBT_7   1
+       #define DVBT_8   2
+       #define DVBT2_6  3
+       #define DVBT2_7  4
+       #define DVBT2_8  5
+       #define DVBC_6   6
+       #define DVBC_8   7
        static const u8 bw_params[][3] = {
-               /*  0f    13    23 */
-               { 0xb3, 0x20, 0x03 }, /* DVB-T 6 MHz */
-               { 0xb3, 0x31, 0x01 }, /* DVB-T 7 MHz */
-               { 0xb3, 0x22, 0x01 }, /* DVB-T 8 MHz */
-               { 0x92, 0x53, 0x03 }, /* DVB-C */
+                    /* reg:   0f    13    23 */
+               [DVBT_6]  = { 0xb3, 0x20, 0x03 },
+               [DVBT_7]  = { 0xb3, 0x31, 0x01 },
+               [DVBT_8]  = { 0xb3, 0x22, 0x01 },
+               [DVBT2_6] = { 0xbc, 0x20, 0x03 },
+               [DVBT2_7] = { 0xbc, 0x72, 0x03 },
+               [DVBT2_8] = { 0xbc, 0x22, 0x01 },
+               [DVBC_6]  = { 0x92, 0x50, 0x03 },
+               [DVBC_8]  = { 0x92, 0x53, 0x03 },
        };
 
        dbg("delsys=%d RF=%d BW=%d\n",
@@ -155,24 +168,44 @@ static int tda18212_set_params(struct dvb_frontend *fe,
                switch (c->bandwidth_hz) {
                case 6000000:
                        if_khz = priv->cfg->if_dvbt_6;
-                       i = 0;
+                       i = DVBT_6;
                        break;
                case 7000000:
                        if_khz = priv->cfg->if_dvbt_7;
-                       i = 1;
+                       i = DVBT_7;
                        break;
                case 8000000:
                        if_khz = priv->cfg->if_dvbt_8;
-                       i = 2;
+                       i = DVBT_8;
                        break;
                default:
                        ret = -EINVAL;
                        goto error;
                }
                break;
-       case SYS_DVBC_ANNEX_AC:
+       case SYS_DVBT2:
+               switch (c->bandwidth_hz) {
+               case 6000000:
+                       if_khz = priv->cfg->if_dvbt2_6;
+                       i = DVBT2_6;
+                       break;
+               case 7000000:
+                       if_khz = priv->cfg->if_dvbt2_7;
+                       i = DVBT2_7;
+                       break;
+               case 8000000:
+                       if_khz = priv->cfg->if_dvbt2_8;
+                       i = DVBT2_8;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto error;
+               }
+               break;
+       case SYS_DVBC_ANNEX_A:
+       case SYS_DVBC_ANNEX_C:
                if_khz = priv->cfg->if_dvbc;
-               i = 3;
+               i = DVBC_8;
                break;
        default:
                ret = -EINVAL;
@@ -194,7 +227,7 @@ static int tda18212_set_params(struct dvb_frontend *fe,
        buf[0] = 0x02;
        buf[1] = bw_params[i][1];
        buf[2] = 0x03; /* default value */
-       buf[3] = if_khz / 50;
+       buf[3] = DIV_ROUND_CLOSEST(if_khz, 50);
        buf[4] = ((c->frequency / 1000) >> 16) & 0xff;
        buf[5] = ((c->frequency / 1000) >>  8) & 0xff;
        buf[6] = ((c->frequency / 1000) >>  0) & 0xff;
@@ -204,6 +237,9 @@ static int tda18212_set_params(struct dvb_frontend *fe,
        if (ret)
                goto error;
 
+       /* actual IF rounded as it is on register */
+       priv->if_frequency = buf[3] * 50 * 1000;
+
 exit:
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
@@ -215,6 +251,15 @@ error:
        goto exit;
 }
 
+static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct tda18212_priv *priv = fe->tuner_priv;
+
+       *frequency = priv->if_frequency;
+
+       return 0;
+}
+
 static int tda18212_release(struct dvb_frontend *fe)
 {
        kfree(fe->tuner_priv);
@@ -234,6 +279,7 @@ static const struct dvb_tuner_ops tda18212_tuner_ops = {
        .release       = tda18212_release,
 
        .set_params    = tda18212_set_params,
+       .get_if_frequency = tda18212_get_if_frequency,
 };
 
 struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
index 83b497f59e1b2e16b2a214bb4b6b06ec882778da..9bd5da4aabb7b032e13e6dc2ad7633d8d21b6971 100644 (file)
@@ -29,6 +29,10 @@ struct tda18212_config {
        u16 if_dvbt_6;
        u16 if_dvbt_7;
        u16 if_dvbt_8;
+       u16 if_dvbt2_5;
+       u16 if_dvbt2_6;
+       u16 if_dvbt2_7;
+       u16 if_dvbt2_8;
        u16 if_dvbc;
 };
 
index 4fc29730a12ccf2305739c34efa625deef0a1f95..dfb3a831df4540541757f5b6cc0ce7f23f989cd3 100644 (file)
@@ -109,10 +109,11 @@ static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
        return tda18218_rd_regs(priv, reg, val, 1);
 }
 
-static int tda18218_set_params(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params)
+static int tda18218_set_params(struct dvb_frontend *fe)
 {
        struct tda18218_priv *priv = fe->tuner_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 bw = c->bandwidth_hz;
        int ret;
        u8 buf[3], i, BP_Filter, LP_Fc;
        u32 LO_Frac;
@@ -138,22 +139,19 @@ static int tda18218_set_params(struct dvb_frontend *fe,
                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
 
        /* low-pass filter cut-off frequency */
-       switch (params->u.ofdm.bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       if (bw <= 6000000) {
                LP_Fc = 0;
-               LO_Frac = params->frequency + 3000000;
-               break;
-       case BANDWIDTH_7_MHZ:
+               priv->if_frequency = 3000000;
+       } else if (bw <= 7000000) {
                LP_Fc = 1;
-               LO_Frac = params->frequency + 3500000;
-               break;
-       case BANDWIDTH_8_MHZ:
-       default:
+               priv->if_frequency = 3500000;
+       } else {
                LP_Fc = 2;
-               LO_Frac = params->frequency + 4000000;
-               break;
+               priv->if_frequency = 4000000;
        }
 
+       LO_Frac = c->frequency + priv->if_frequency;
+
        /* band-pass filter */
        if (LO_Frac < 188000000)
                BP_Filter = 3;
@@ -206,6 +204,14 @@ error:
        return ret;
 }
 
+static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct tda18218_priv *priv = fe->tuner_priv;
+       *frequency = priv->if_frequency;
+       dbg("%s: if=%d", __func__, *frequency);
+       return 0;
+}
+
 static int tda18218_sleep(struct dvb_frontend *fe)
 {
        struct tda18218_priv *priv = fe->tuner_priv;
@@ -268,6 +274,8 @@ static const struct dvb_tuner_ops tda18218_tuner_ops = {
        .sleep         = tda18218_sleep,
 
        .set_params    = tda18218_set_params,
+
+       .get_if_frequency = tda18218_get_if_frequency,
 };
 
 struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
index 904e5365c78c75402b73a9cbeaecff67810856fd..dc52b72e14071015255cb026354d44e4cf248fc6 100644 (file)
@@ -100,6 +100,8 @@ struct tda18218_priv {
        struct tda18218_config *cfg;
        struct i2c_adapter *i2c;
 
+       u32 if_frequency;
+
        u8 regs[TDA18218_NUM_REGS];
 };
 
index 63cc4004e211e9654044b612400460bb93832bf9..2e67f44599045e175ba6f0881bbb56bb6c11c578 100644 (file)
@@ -928,59 +928,49 @@ fail:
 
 /* ------------------------------------------------------------------ */
 
-static int tda18271_set_params(struct dvb_frontend *fe,
-                              struct dvb_frontend_parameters *params)
+static int tda18271_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 delsys = c->delivery_system;
+       u32 bw = c->bandwidth_hz;
+       u32 freq = c->frequency;
        struct tda18271_priv *priv = fe->tuner_priv;
        struct tda18271_std_map *std_map = &priv->std;
        struct tda18271_std_map_item *map;
        int ret;
-       u32 bw, freq = params->frequency;
 
        priv->mode = TDA18271_DIGITAL;
 
-       if (fe->ops.info.type == FE_ATSC) {
-               switch (params->u.vsb.modulation) {
-               case VSB_8:
-               case VSB_16:
-                       map = &std_map->atsc_6;
-                       break;
-               case QAM_64:
-               case QAM_256:
-                       map = &std_map->qam_6;
-                       break;
-               default:
-                       tda_warn("modulation not set!\n");
-                       return -EINVAL;
-               }
-#if 0
-               /* userspace request is already center adjusted */
-               freq += 1750000; /* Adjust to center (+1.75MHZ) */
-#endif
+       switch (delsys) {
+       case SYS_ATSC:
+               map = &std_map->atsc_6;
                bw = 6000000;
-       } else if (fe->ops.info.type == FE_OFDM) {
-               switch (params->u.ofdm.bandwidth) {
-               case BANDWIDTH_6_MHZ:
-                       bw = 6000000;
+               break;
+       case SYS_ISDBT:
+       case SYS_DVBT:
+       case SYS_DVBT2:
+               if (bw <= 6000000) {
                        map = &std_map->dvbt_6;
-                       break;
-               case BANDWIDTH_7_MHZ:
-                       bw = 7000000;
+               } else if (bw <= 7000000) {
                        map = &std_map->dvbt_7;
-                       break;
-               case BANDWIDTH_8_MHZ:
-                       bw = 8000000;
+               } else {
                        map = &std_map->dvbt_8;
-                       break;
-               default:
-                       tda_warn("bandwidth not set!\n");
-                       return -EINVAL;
                }
-       } else if (fe->ops.info.type == FE_QAM) {
-               /* DVB-C */
-               map = &std_map->qam_8;
-               bw = 8000000;
-       } else {
+               break;
+       case SYS_DVBC_ANNEX_B:
+               bw = 6000000;
+               /* falltrough */
+       case SYS_DVBC_ANNEX_A:
+       case SYS_DVBC_ANNEX_C:
+               if (bw <= 6000000) {
+                       map = &std_map->qam_6;
+               } else if (bw <= 7000000) {
+                       map = &std_map->qam_7;
+               } else {
+                       map = &std_map->qam_8;
+               }
+               break;
+       default:
                tda_warn("modulation type not supported!\n");
                return -EINVAL;
        }
@@ -994,9 +984,9 @@ static int tda18271_set_params(struct dvb_frontend *fe,
        if (tda_fail(ret))
                goto fail;
 
+       priv->if_freq   = map->if_freq;
        priv->frequency = freq;
-       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
-               params->u.ofdm.bandwidth : 0;
+       priv->bandwidth = bw;
 fail:
        return ret;
 }
@@ -1050,6 +1040,7 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe,
        if (tda_fail(ret))
                goto fail;
 
+       priv->if_freq   = map->if_freq;
        priv->frequency = freq;
        priv->bandwidth = 0;
 fail:
@@ -1086,6 +1077,13 @@ static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
        return 0;
 }
 
+static int tda18271_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct tda18271_priv *priv = fe->tuner_priv;
+       *frequency = (u32)priv->if_freq * 1000;
+       return 0;
+}
+
 /* ------------------------------------------------------------------ */
 
 #define tda18271_update_std(std_cfg, name) do {                                \
@@ -1245,6 +1243,7 @@ static const struct dvb_tuner_ops tda18271_tuner_ops = {
        .set_config        = tda18271_set_config,
        .get_frequency     = tda18271_get_frequency,
        .get_bandwidth     = tda18271_get_bandwidth,
+       .get_if_frequency  = tda18271_get_if_frequency,
 };
 
 struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
index 3d5b6ab7e3322630814036cf65654f545cc7e095..fb881c667c9401aa355681816a5a7045d271183e 100644 (file)
@@ -1213,6 +1213,8 @@ static struct tda18271_std_map tda18271c1_std_map = {
                      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
        .qam_6    = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
                      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+       .qam_7    = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6,
+                     .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
        .qam_8    = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7,
                      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */
 };
@@ -1244,6 +1246,8 @@ static struct tda18271_std_map tda18271c2_std_map = {
                      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
        .qam_6    = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
                      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+       .qam_7    = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6,
+                     .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
        .qam_8    = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7,
                      .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */
 };
index 94340f47562bbe36c01a5035a0633ff1c2149c72..454c152ccaa023d66423591108ca16616c058660 100644 (file)
@@ -122,6 +122,8 @@ struct tda18271_priv {
 
        struct mutex lock;
 
+       u16 if_freq;
+
        u32 frequency;
        u32 bandwidth;
 };
index 50cfa8cebb9309043e63059c350d7091e877e24c..640bae4e6a5a85c6db5274e9654b1d02f61c419b 100644 (file)
@@ -53,6 +53,7 @@ struct tda18271_std_map {
        struct tda18271_std_map_item dvbt_7;
        struct tda18271_std_map_item dvbt_8;
        struct tda18271_std_map_item qam_6;
+       struct tda18271_std_map_item qam_7;
        struct tda18271_std_map_item qam_8;
 };
 
index e0d5b43772b81e997ab6cd15199ae137c7bcb599..a0d17626747096b081d81add3ed5e072d964fd60 100644 (file)
@@ -152,9 +152,9 @@ static int tuner_transfer(struct dvb_frontend *fe,
        return rc;
 }
 
-static int tda827xo_set_params(struct dvb_frontend *fe,
-                              struct dvb_frontend_parameters *params)
+static int tda827xo_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct tda827x_priv *priv = fe->tuner_priv;
        u8 buf[14];
        int rc;
@@ -165,18 +165,16 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
        u32 N;
 
        dprintk("%s:\n", __func__);
-       switch (params->u.ofdm.bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       if (c->bandwidth_hz == 0) {
+               if_freq = 5000000;
+       } else if (c->bandwidth_hz <= 6000000) {
                if_freq = 4000000;
-               break;
-       case BANDWIDTH_7_MHZ:
+       } else if (c->bandwidth_hz <= 7000000) {
                if_freq = 4500000;
-               break;
-       default:                   /* 8 MHz or Auto */
+       } else {        /* 8 MHz */
                if_freq = 5000000;
-               break;
        }
-       tuner_freq = params->frequency;
+       tuner_freq = c->frequency;
 
        i = 0;
        while (tda827x_table[i].lomax < tuner_freq) {
@@ -220,8 +218,8 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
        if (rc < 0)
                goto err;
 
-       priv->frequency = params->frequency;
-       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+       priv->frequency = c->frequency;
+       priv->bandwidth = c->bandwidth_hz;
 
        return 0;
 
@@ -513,9 +511,9 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
        }
 }
 
-static int tda827xa_set_params(struct dvb_frontend *fe,
-                              struct dvb_frontend_parameters *params)
+static int tda827xa_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct tda827x_priv *priv = fe->tuner_priv;
        struct tda827xa_data *frequency_map = tda827xa_dvbt;
        u8 buf[11];
@@ -531,22 +529,25 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
        tda827xa_lna_gain(fe, 1, NULL);
        msleep(20);
 
-       switch (params->u.ofdm.bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       if (c->bandwidth_hz == 0) {
+               if_freq = 5000000;
+       } else if (c->bandwidth_hz <= 6000000) {
                if_freq = 4000000;
-               break;
-       case BANDWIDTH_7_MHZ:
+       } else if (c->bandwidth_hz <= 7000000) {
                if_freq = 4500000;
-               break;
-       default:                   /* 8 MHz or Auto */
+       } else {        /* 8 MHz */
                if_freq = 5000000;
-               break;
        }
-       tuner_freq = params->frequency;
+       tuner_freq = c->frequency;
 
-       if (fe->ops.info.type == FE_QAM) {
+       switch (c->delivery_system) {
+       case SYS_DVBC_ANNEX_A:
+       case SYS_DVBC_ANNEX_C:
                dprintk("%s select tda827xa_dvbc\n", __func__);
                frequency_map = tda827xa_dvbc;
+               break;
+       default:
+               break;
        }
 
        i = 0;
@@ -645,9 +646,8 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
        if (rc < 0)
                goto err;
 
-       priv->frequency = params->frequency;
-       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
-
+       priv->frequency = c->frequency;
+       priv->bandwidth = c->bandwidth_hz;
 
        return 0;
 
index f8ee29e6059c982e8e8ddce5cd0cbe28d78b58ed..39e7e583c8c0efb89335e6ab0c863ce77bd36db8 100644 (file)
@@ -751,6 +751,17 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
        if (4 != rc)
                tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
 
+       /* Write AUX byte */
+       switch (priv->type) {
+       case TUNER_PHILIPS_FM1216ME_MK3:
+               buffer[2] = 0x98;
+               buffer[3] = 0x20; /* set TOP AGC */
+               rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
+               if (4 != rc)
+                       tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
+               break;
+       }
+
        return 0;
 }
 
@@ -780,24 +791,26 @@ static int simple_set_params(struct dvb_frontend *fe,
 }
 
 static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
-                          const struct dvb_frontend_parameters *params)
+                          const u32 delsys,
+                          const u32 frequency,
+                          const u32 bandwidth)
 {
        struct tuner_simple_priv *priv = fe->tuner_priv;
 
        switch (priv->type) {
        case TUNER_PHILIPS_FMD1216ME_MK3:
        case TUNER_PHILIPS_FMD1216MEX_MK3:
-               if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
-                   params->frequency >= 158870000)
+               if (bandwidth == 8000000 &&
+                   frequency >= 158870000)
                        buf[3] |= 0x08;
                break;
        case TUNER_PHILIPS_TD1316:
                /* determine band */
-               buf[3] |= (params->frequency < 161000000) ? 1 :
-                         (params->frequency < 444000000) ? 2 : 4;
+               buf[3] |= (frequency < 161000000) ? 1 :
+                         (frequency < 444000000) ? 2 : 4;
 
                /* setup PLL filter */
-               if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+               if (bandwidth == 8000000)
                        buf[3] |= 1 << 3;
                break;
        case TUNER_PHILIPS_TUV1236D:
@@ -808,12 +821,11 @@ static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
                if (dtv_input[priv->nr])
                        new_rf = dtv_input[priv->nr];
                else
-                       switch (params->u.vsb.modulation) {
-                       case QAM_64:
-                       case QAM_256:
+                       switch (delsys) {
+                       case SYS_DVBC_ANNEX_B:
                                new_rf = 1;
                                break;
-                       case VSB_8:
+                       case SYS_ATSC:
                        default:
                                new_rf = 0;
                                break;
@@ -827,7 +839,9 @@ static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
 }
 
 static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
-                               const struct dvb_frontend_parameters *params)
+                               const u32 delsys,
+                               const u32 freq,
+                               const u32 bw)
 {
        /* This function returns the tuned frequency on success, 0 on error */
        struct tuner_simple_priv *priv = fe->tuner_priv;
@@ -836,7 +850,7 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
        u8 config, cb;
        u32 div;
        int ret;
-       unsigned frequency = params->frequency / 62500;
+       u32 frequency = freq / 62500;
 
        if (!tun->stepsize) {
                /* tuner-core was loaded before the digital tuner was
@@ -860,7 +874,7 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
        buf[2] = config;
        buf[3] = cb;
 
-       simple_set_dvb(fe, buf, params);
+       simple_set_dvb(fe, buf, delsys, freq, bw);
 
        tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
                  tun->name, div, buf[0], buf[1], buf[2], buf[3]);
@@ -870,32 +884,37 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
 }
 
 static int simple_dvb_calc_regs(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *params,
                                u8 *buf, int buf_len)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 delsys = c->delivery_system;
+       u32 bw = c->bandwidth_hz;
        struct tuner_simple_priv *priv = fe->tuner_priv;
        u32 frequency;
 
        if (buf_len < 5)
                return -EINVAL;
 
-       frequency = simple_dvb_configure(fe, buf+1, params);
+       frequency = simple_dvb_configure(fe, buf+1, delsys, c->frequency, bw);
        if (frequency == 0)
                return -EINVAL;
 
        buf[0] = priv->i2c_props.addr;
 
        priv->frequency = frequency;
-       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
-               params->u.ofdm.bandwidth : 0;
+       priv->bandwidth = c->bandwidth_hz;
 
        return 5;
 }
 
-static int simple_dvb_set_params(struct dvb_frontend *fe,
-                                struct dvb_frontend_parameters *params)
+static int simple_dvb_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 delsys = c->delivery_system;
+       u32 bw = c->bandwidth_hz;
+       u32 freq = c->frequency;
        struct tuner_simple_priv *priv = fe->tuner_priv;
+       u32 frequency;
        u32 prev_freq, prev_bw;
        int ret;
        u8 buf[5];
@@ -906,9 +925,14 @@ static int simple_dvb_set_params(struct dvb_frontend *fe,
        prev_freq = priv->frequency;
        prev_bw   = priv->bandwidth;
 
-       ret = simple_dvb_calc_regs(fe, params, buf, 5);
-       if (ret != 5)
-               goto fail;
+       frequency = simple_dvb_configure(fe, buf+1, delsys, freq, bw);
+       if (frequency == 0)
+               return -EINVAL;
+
+       buf[0] = priv->i2c_props.addr;
+
+       priv->frequency = frequency;
+       priv->bandwidth = bw;
 
        /* put analog demod in standby when tuning digital */
        if (fe->ops.analog_ops.standby)
index 3acbaa04e1b3b3c6a4711211b5bf9acfe1e1dbe8..b5ee3ebfcfca03e2f9fd5973cd5d72b52d1c5f53 100644 (file)
 #include <linux/dvb/frontend.h>
 #include "dvb_frontend.h"
 
+/* Registers (Write-only) */
+#define XREG_INIT         0x00
+#define XREG_RF_FREQ      0x02
+#define XREG_POWER_DOWN   0x08
+
+/* Registers (Read-only) */
+#define XREG_FREQ_ERROR   0x01
+#define XREG_LOCK         0x02
+#define XREG_VERSION      0x04
+#define XREG_PRODUCT_ID   0x08
+#define XREG_HSYNC_FREQ   0x10
+#define XREG_FRAME_LINES  0x20
+#define XREG_SNR          0x40
+
+#define XREG_ADC_ENV      0x0100
 
 static int debug;
 module_param(debug, int, 0644);
@@ -311,7 +326,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
                   n_array, fname, name,
                   priv->firm_version >> 8, priv->firm_version & 0xff);
 
-       priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
+       priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
        if (priv->firm == NULL) {
                tuner_err("Not enough memory to load firmware file.\n");
                rc = -ENOMEM;
@@ -885,16 +900,16 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
        mutex_lock(&priv->lock);
 
        /* Sync Lock Indicator */
-       rc = xc2028_get_reg(priv, 0x0002, &frq_lock);
+       rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
        if (rc < 0)
                goto ret;
 
        /* Frequency is locked */
        if (frq_lock == 1)
-               signal = 32768;
+               signal = 1 << 11;
 
        /* Get SNR of the video signal */
-       rc = xc2028_get_reg(priv, 0x0040, &signal);
+       rc = xc2028_get_reg(priv, XREG_SNR, &signal);
        if (rc < 0)
                goto ret;
 
@@ -962,14 +977,24 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
                 * For DTV 7/8, the firmware uses BW = 8000, so it needs a
                 * further adjustment to get the frequency center on VHF
                 */
+
+               /*
+                * The firmware DTV78 used to work fine in UHF band (8 MHz
+                * bandwidth) but not at all in VHF band (7 MHz bandwidth).
+                * The real problem was connected to the formula used to
+                * calculate the center frequency offset in VHF band.
+                * In fact, removing the 500KHz adjustment fixed the problem.
+                * This is coherent to what was implemented for the DTV7
+                * firmware.
+                * In the end, now the center frequency is the same for all 3
+                * firmwares (DTV7, DTV8, DTV78) and doesn't depend on channel
+                * bandwidth.
+                */
+
                if (priv->cur_fw.type & DTV6)
                        offset = 1750000;
-               else if (priv->cur_fw.type & DTV7)
-                       offset = 2250000;
-               else    /* DTV8 or DTV78 */
+               else    /* DTV7 or DTV8 or DTV78 */
                        offset = 2750000;
-               if ((priv->cur_fw.type & DTV78) && freq < 470000000)
-                       offset -= 500000;
 
                /*
                 * xc3028 additional "magic"
@@ -979,17 +1004,13 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
                 * newer firmwares
                 */
 
-#if 1
                /*
                 * The proper adjustment would be to do it at s-code table.
                 * However, this didn't work, as reported by
                 * Robert Lowery <rglowery@exemail.com.au>
                 */
 
-               if (priv->cur_fw.type & DTV7)
-                       offset += 500000;
-
-#else
+#if 0
                /*
                 * Still need tests for XC3028L (firmware 3.2 or upper)
                 * So, for now, let's just comment the per-firmware
@@ -1013,9 +1034,9 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
 
        /* CMD= Set frequency */
        if (priv->firm_version < 0x0202)
-               rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00});
+               rc = send_seq(priv, {0x00, XREG_RF_FREQ, 0x00, 0x00});
        else
-               rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00});
+               rc = send_seq(priv, {0x80, XREG_RF_FREQ, 0x00, 0x00});
        if (rc < 0)
                goto ret;
 
@@ -1084,68 +1105,28 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
                                V4L2_TUNER_ANALOG_TV, type, p->std, 0);
 }
 
-static int xc2028_set_params(struct dvb_frontend *fe,
-                            struct dvb_frontend_parameters *p)
+static int xc2028_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 delsys = c->delivery_system;
+       u32 bw = c->bandwidth_hz;
        struct xc2028_data *priv = fe->tuner_priv;
        unsigned int       type=0;
-       fe_bandwidth_t     bw = BANDWIDTH_8_MHZ;
        u16                demod = 0;
 
        tuner_dbg("%s called\n", __func__);
 
-       switch(fe->ops.info.type) {
-       case FE_OFDM:
-               bw = p->u.ofdm.bandwidth;
+       switch (delsys) {
+       case SYS_DVBT:
+       case SYS_DVBT2:
                /*
                 * The only countries with 6MHz seem to be Taiwan/Uruguay.
                 * Both seem to require QAM firmware for OFDM decoding
                 * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com>
                 */
-               if (bw == BANDWIDTH_6_MHZ)
+               if (bw <= 6000000)
                        type |= QAM;
-               break;
-       case FE_ATSC:
-               bw = BANDWIDTH_6_MHZ;
-               /* The only ATSC firmware (at least on v2.7) is D2633 */
-               type |= ATSC | D2633;
-               break;
-       /* DVB-S and pure QAM (FE_QAM) are not supported */
-       default:
-               return -EINVAL;
-       }
-
-       switch (bw) {
-       case BANDWIDTH_8_MHZ:
-               if (p->frequency < 470000000)
-                       priv->ctrl.vhfbw7 = 0;
-               else
-                       priv->ctrl.uhfbw8 = 1;
-               type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8;
-               type |= F8MHZ;
-               break;
-       case BANDWIDTH_7_MHZ:
-               if (p->frequency < 470000000)
-                       priv->ctrl.vhfbw7 = 1;
-               else
-                       priv->ctrl.uhfbw8 = 0;
-               type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7;
-               type |= F8MHZ;
-               break;
-       case BANDWIDTH_6_MHZ:
-               type |= DTV6;
-               priv->ctrl.vhfbw7 = 0;
-               priv->ctrl.uhfbw8 = 0;
-               break;
-       default:
-               tuner_err("error: bandwidth not supported.\n");
-       };
 
-       /*
-         Selects between D2633 or D2620 firmware.
-         It doesn't make sense for ATSC, since it should be D2633 on all cases
-        */
-       if (fe->ops.info.type != FE_ATSC) {
                switch (priv->ctrl.type) {
                case XC2028_D2633:
                        type |= D2633;
@@ -1161,6 +1142,34 @@ static int xc2028_set_params(struct dvb_frontend *fe,
                        else
                                type |= D2620;
                }
+               break;
+       case SYS_ATSC:
+               /* The only ATSC firmware (at least on v2.7) is D2633 */
+               type |= ATSC | D2633;
+               break;
+       /* DVB-S and pure QAM (FE_QAM) are not supported */
+       default:
+               return -EINVAL;
+       }
+
+       if (bw <= 6000000) {
+               type |= DTV6;
+               priv->ctrl.vhfbw7 = 0;
+               priv->ctrl.uhfbw8 = 0;
+       } else if (bw <= 7000000) {
+               if (c->frequency < 470000000)
+                       priv->ctrl.vhfbw7 = 1;
+               else
+                       priv->ctrl.uhfbw8 = 0;
+               type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7;
+               type |= F8MHZ;
+       } else {
+               if (c->frequency < 470000000)
+                       priv->ctrl.vhfbw7 = 0;
+               else
+                       priv->ctrl.uhfbw8 = 1;
+               type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8;
+               type |= F8MHZ;
        }
 
        /* All S-code tables need a 200kHz shift */
@@ -1185,7 +1194,7 @@ static int xc2028_set_params(struct dvb_frontend *fe,
                 */
        }
 
-       return generic_set_freq(fe, p->frequency,
+       return generic_set_freq(fe, c->frequency,
                                V4L2_TUNER_DIGITAL_TV, type, 0, demod);
 }
 
@@ -1207,9 +1216,9 @@ static int xc2028_sleep(struct dvb_frontend *fe)
        mutex_lock(&priv->lock);
 
        if (priv->firm_version < 0x0202)
-               rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
+               rc = send_seq(priv, {0x00, XREG_POWER_DOWN, 0x00, 0x00});
        else
-               rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
+               rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00});
 
        priv->cur_fw.type = 0;  /* need firmware reload */
 
index 634f4d9b6c6380678bf879e50293e9254a813e13..68397110b7d932fec46c3cdd4ecc0b9d2e99ddf4 100644 (file)
@@ -154,6 +154,8 @@ struct xc4000_priv {
 #define XREG_SNR          0x06
 #define XREG_VERSION      0x07
 #define XREG_PRODUCT_ID   0x08
+#define XREG_SIGNAL_LEVEL 0x0A
+#define XREG_NOISE_LEVEL  0x0B
 
 /*
    Basic firmware description. This will remain with
@@ -486,6 +488,16 @@ static int xc_get_quality(struct xc4000_priv *priv, u16 *quality)
        return xc4000_readreg(priv, XREG_QUALITY, quality);
 }
 
+static int xc_get_signal_level(struct xc4000_priv *priv, u16 *signal)
+{
+       return xc4000_readreg(priv, XREG_SIGNAL_LEVEL, signal);
+}
+
+static int xc_get_noise_level(struct xc4000_priv *priv, u16 *noise)
+{
+       return xc4000_readreg(priv, XREG_NOISE_LEVEL, noise);
+}
+
 static u16 xc_wait_for_lock(struct xc4000_priv *priv)
 {
        u16     lock_state = 0;
@@ -758,7 +770,7 @@ static int xc4000_fwupload(struct dvb_frontend *fe)
                n_array, fname, name,
                priv->firm_version >> 8, priv->firm_version & 0xff);
 
-       priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
+       priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
        if (priv->firm == NULL) {
                printk(KERN_ERR "Not enough memory to load firmware file.\n");
                rc = -ENOMEM;
@@ -1089,6 +1101,8 @@ static void xc_debug_dump(struct xc4000_priv *priv)
        u32     hsync_freq_hz = 0;
        u16     frame_lines;
        u16     quality;
+       u16     signal = 0;
+       u16     noise = 0;
        u8      hw_majorversion = 0, hw_minorversion = 0;
        u8      fw_majorversion = 0, fw_minorversion = 0;
 
@@ -1119,85 +1133,70 @@ static void xc_debug_dump(struct xc4000_priv *priv)
 
        xc_get_quality(priv, &quality);
        dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
+
+       xc_get_signal_level(priv, &signal);
+       dprintk(1, "*** Signal level = -%ddB (%d)\n", signal >> 8, signal);
+
+       xc_get_noise_level(priv, &noise);
+       dprintk(1, "*** Noise level = %ddB (%d)\n", noise >> 8, noise);
 }
 
-static int xc4000_set_params(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params)
+static int xc4000_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 delsys = c->delivery_system;
+       u32 bw = c->bandwidth_hz;
        struct xc4000_priv *priv = fe->tuner_priv;
        unsigned int type;
        int     ret = -EREMOTEIO;
 
-       dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
+       dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency);
 
        mutex_lock(&priv->lock);
 
-       if (fe->ops.info.type == FE_ATSC) {
-               dprintk(1, "%s() ATSC\n", __func__);
-               switch (params->u.vsb.modulation) {
-               case VSB_8:
-               case VSB_16:
-                       dprintk(1, "%s() VSB modulation\n", __func__);
-                       priv->rf_mode = XC_RF_MODE_AIR;
-                       priv->freq_hz = params->frequency - 1750000;
-                       priv->bandwidth = BANDWIDTH_6_MHZ;
-                       priv->video_standard = XC4000_DTV6;
-                       type = DTV6;
-                       break;
-               case QAM_64:
-               case QAM_256:
-               case QAM_AUTO:
-                       dprintk(1, "%s() QAM modulation\n", __func__);
-                       priv->rf_mode = XC_RF_MODE_CABLE;
-                       priv->freq_hz = params->frequency - 1750000;
-                       priv->bandwidth = BANDWIDTH_6_MHZ;
-                       priv->video_standard = XC4000_DTV6;
-                       type = DTV6;
-                       break;
-               default:
-                       ret = -EINVAL;
-                       goto fail;
-               }
-       } else if (fe->ops.info.type == FE_OFDM) {
+       switch (delsys) {
+       case SYS_ATSC:
+               dprintk(1, "%s() VSB modulation\n", __func__);
+               priv->rf_mode = XC_RF_MODE_AIR;
+               priv->freq_hz = c->frequency - 1750000;
+               priv->video_standard = XC4000_DTV6;
+               type = DTV6;
+               break;
+       case SYS_DVBC_ANNEX_B:
+               dprintk(1, "%s() QAM modulation\n", __func__);
+               priv->rf_mode = XC_RF_MODE_CABLE;
+               priv->freq_hz = c->frequency - 1750000;
+               priv->video_standard = XC4000_DTV6;
+               type = DTV6;
+               break;
+       case SYS_DVBT:
+       case SYS_DVBT2:
                dprintk(1, "%s() OFDM\n", __func__);
-               switch (params->u.ofdm.bandwidth) {
-               case BANDWIDTH_6_MHZ:
-                       priv->bandwidth = BANDWIDTH_6_MHZ;
+               if (bw == 0) {
+                       if (c->frequency < 400000000) {
+                               priv->freq_hz = c->frequency - 2250000;
+                       } else {
+                               priv->freq_hz = c->frequency - 2750000;
+                       }
+                       priv->video_standard = XC4000_DTV7_8;
+                       type = DTV78;
+               } else if (bw <= 6000000) {
                        priv->video_standard = XC4000_DTV6;
-                       priv->freq_hz = params->frequency - 1750000;
+                       priv->freq_hz = c->frequency - 1750000;
                        type = DTV6;
-                       break;
-               case BANDWIDTH_7_MHZ:
-                       priv->bandwidth = BANDWIDTH_7_MHZ;
+               } else if (bw <= 7000000) {
                        priv->video_standard = XC4000_DTV7;
-                       priv->freq_hz = params->frequency - 2250000;
+                       priv->freq_hz = c->frequency - 2250000;
                        type = DTV7;
-                       break;
-               case BANDWIDTH_8_MHZ:
-                       priv->bandwidth = BANDWIDTH_8_MHZ;
+               } else {
                        priv->video_standard = XC4000_DTV8;
-                       priv->freq_hz = params->frequency - 2750000;
+                       priv->freq_hz = c->frequency - 2750000;
                        type = DTV8;
-                       break;
-               case BANDWIDTH_AUTO:
-                       if (params->frequency < 400000000) {
-                               priv->bandwidth = BANDWIDTH_7_MHZ;
-                               priv->freq_hz = params->frequency - 2250000;
-                       } else {
-                               priv->bandwidth = BANDWIDTH_8_MHZ;
-                               priv->freq_hz = params->frequency - 2750000;
-                       }
-                       priv->video_standard = XC4000_DTV7_8;
-                       type = DTV78;
-                       break;
-               default:
-                       printk(KERN_ERR "xc4000 bandwidth not set!\n");
-                       ret = -EINVAL;
-                       goto fail;
                }
                priv->rf_mode = XC_RF_MODE_AIR;
-       } else {
-               printk(KERN_ERR "xc4000 modulation type not supported!\n");
+               break;
+       default:
+               printk(KERN_ERR "xc4000 delivery system not supported!\n");
                ret = -EINVAL;
                goto fail;
        }
@@ -1209,6 +1208,8 @@ static int xc4000_set_params(struct dvb_frontend *fe,
        if (check_firmware(fe, type, 0, priv->if_khz) != 0)
                goto fail;
 
+       priv->bandwidth = c->bandwidth_hz;
+
        ret = xc_set_signal_source(priv, priv->rf_mode);
        if (ret != 0) {
                printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n",
@@ -1451,6 +1452,71 @@ fail:
        return ret;
 }
 
+static int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       u16 value = 0;
+       int rc;
+
+       mutex_lock(&priv->lock);
+       rc = xc4000_readreg(priv, XREG_SIGNAL_LEVEL, &value);
+       mutex_unlock(&priv->lock);
+
+       if (rc < 0)
+               goto ret;
+
+       /* Informations from real testing of DVB-T and radio part,
+          coeficient for one dB is 0xff.
+        */
+       tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value);
+
+       /* all known digital modes */
+       if ((priv->video_standard == XC4000_DTV6) ||
+           (priv->video_standard == XC4000_DTV7) ||
+           (priv->video_standard == XC4000_DTV7_8) ||
+           (priv->video_standard == XC4000_DTV8))
+               goto digital;
+
+       /* Analog mode has NOISE LEVEL important, signal
+          depends only on gain of antenna and amplifiers,
+          but it doesn't tell anything about real quality
+          of reception.
+        */
+       mutex_lock(&priv->lock);
+       rc = xc4000_readreg(priv, XREG_NOISE_LEVEL, &value);
+       mutex_unlock(&priv->lock);
+
+       tuner_dbg("Noise level: %ddB (%05d)\n", value >> 8, value);
+
+       /* highest noise level: 32dB */
+       if (value >= 0x2000) {
+               value = 0;
+       } else {
+               value = ~value << 3;
+       }
+
+       goto ret;
+
+       /* Digital mode has SIGNAL LEVEL important and real
+          noise level is stored in demodulator registers.
+        */
+digital:
+       /* best signal: -50dB */
+       if (value <= 0x3200) {
+               value = 0xffff;
+       /* minimum: -114dB - should be 0x7200 but real zero is 0x713A */
+       } else if (value >= 0x713A) {
+               value = 0;
+       } else {
+               value = ~(value - 0x3200) << 2;
+       }
+
+ret:
+       *strength = value;
+
+       return rc;
+}
+
 static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq)
 {
        struct xc4000_priv *priv = fe->tuner_priv;
@@ -1578,6 +1644,7 @@ static const struct dvb_tuner_ops xc4000_tuner_ops = {
        .set_params        = xc4000_set_params,
        .set_analog_params = xc4000_set_analog_params,
        .get_frequency     = xc4000_get_frequency,
+       .get_rf_strength   = xc4000_get_signal,
        .get_bandwidth     = xc4000_get_bandwidth,
        .get_status        = xc4000_get_status
 };
@@ -1605,7 +1672,7 @@ struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
                break;
        case 1:
                /* new tuner instance */
-               priv->bandwidth = BANDWIDTH_6_MHZ;
+               priv->bandwidth = 6000000;
                /* set default configuration */
                priv->if_khz = 4560;
                priv->default_pm = 0;
index aa1b2e844d3206b8c2bcc96ddaab3f583f7e2739..296df05b8cda8fbe66ab430d0988f647807e5ac0 100644 (file)
@@ -628,20 +628,13 @@ static void xc_debug_dump(struct xc5000_priv *priv)
        dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
 }
 
-/*
- * As defined on EN 300 429, the DVB-C roll-off factor is 0.15.
- * So, the amount of the needed bandwith is given by:
- *     Bw = Symbol_rate * (1 + 0.15)
- * As such, the maximum symbol rate supported by 6 MHz is given by:
- *     max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
- */
-#define MAX_SYMBOL_RATE_6MHz   5217391
-
-static int xc5000_set_params(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params)
+static int xc5000_set_params(struct dvb_frontend *fe)
 {
+       int ret, b;
        struct xc5000_priv *priv = fe->tuner_priv;
-       int ret;
+       u32 bw = fe->dtv_property_cache.bandwidth_hz;
+       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) {
@@ -650,88 +643,69 @@ static int xc5000_set_params(struct dvb_frontend *fe,
                }
        }
 
-       dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
-
-       if (fe->ops.info.type == FE_ATSC) {
-               dprintk(1, "%s() ATSC\n", __func__);
-               switch (params->u.vsb.modulation) {
-               case VSB_8:
-               case VSB_16:
-                       dprintk(1, "%s() VSB modulation\n", __func__);
-                       priv->rf_mode = XC_RF_MODE_AIR;
-                       priv->freq_hz = params->frequency - 1750000;
-                       priv->bandwidth = BANDWIDTH_6_MHZ;
-                       priv->video_standard = DTV6;
-                       break;
-               case QAM_64:
-               case QAM_256:
-               case QAM_AUTO:
-                       dprintk(1, "%s() QAM modulation\n", __func__);
-                       priv->rf_mode = XC_RF_MODE_CABLE;
-                       priv->freq_hz = params->frequency - 1750000;
-                       priv->bandwidth = BANDWIDTH_6_MHZ;
-                       priv->video_standard = DTV6;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       } else if (fe->ops.info.type == FE_OFDM) {
+       dprintk(1, "%s() frequency=%d (Hz)\n", __func__, freq);
+
+       switch (delsys) {
+       case SYS_ATSC:
+               dprintk(1, "%s() VSB modulation\n", __func__);
+               priv->rf_mode = XC_RF_MODE_AIR;
+               priv->freq_hz = freq - 1750000;
+               priv->video_standard = DTV6;
+               break;
+       case SYS_DVBC_ANNEX_B:
+               dprintk(1, "%s() QAM modulation\n", __func__);
+               priv->rf_mode = XC_RF_MODE_CABLE;
+               priv->freq_hz = freq - 1750000;
+               priv->video_standard = DTV6;
+               break;
+       case SYS_DVBT:
+       case SYS_DVBT2:
                dprintk(1, "%s() OFDM\n", __func__);
-               switch (params->u.ofdm.bandwidth) {
-               case BANDWIDTH_6_MHZ:
-                       priv->bandwidth = BANDWIDTH_6_MHZ;
+               switch (bw) {
+               case 6000000:
                        priv->video_standard = DTV6;
-                       priv->freq_hz = params->frequency - 1750000;
+                       priv->freq_hz = freq - 1750000;
                        break;
-               case BANDWIDTH_7_MHZ:
-                       printk(KERN_ERR "xc5000 bandwidth 7MHz not supported\n");
-                       return -EINVAL;
-               case BANDWIDTH_8_MHZ:
-                       priv->bandwidth = BANDWIDTH_8_MHZ;
+               case 7000000:
+                       priv->video_standard = DTV7;
+                       priv->freq_hz = freq - 2250000;
+                       break;
+               case 8000000:
                        priv->video_standard = DTV8;
-                       priv->freq_hz = params->frequency - 2750000;
+                       priv->freq_hz = freq - 2750000;
                        break;
                default:
                        printk(KERN_ERR "xc5000 bandwidth not set!\n");
                        return -EINVAL;
                }
                priv->rf_mode = XC_RF_MODE_AIR;
-       } else if (fe->ops.info.type == FE_QAM) {
-               switch (params->u.qam.modulation) {
-               case QAM_256:
-               case QAM_AUTO:
-               case QAM_16:
-               case QAM_32:
-               case QAM_64:
-               case QAM_128:
-                       dprintk(1, "%s() QAM modulation\n", __func__);
-                       priv->rf_mode = XC_RF_MODE_CABLE;
-                       /*
-                        * Using a 8MHz bandwidth sometimes fail
-                        * with 6MHz-spaced channels, due to inter-carrier
-                        * interference. So, use DTV6 firmware
-                        */
-                       if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz) {
-                               priv->bandwidth = BANDWIDTH_6_MHZ;
-                               priv->video_standard = DTV6;
-                               priv->freq_hz = params->frequency - 1750000;
-                       } else {
-                               priv->bandwidth = BANDWIDTH_8_MHZ;
-                               priv->video_standard = DTV7_8;
-                               priv->freq_hz = params->frequency - 2750000;
-                       }
-                       break;
-               default:
-                       dprintk(1, "%s() Unsupported QAM type\n", __func__);
-                       return -EINVAL;
+       case SYS_DVBC_ANNEX_A:
+       case SYS_DVBC_ANNEX_C:
+               dprintk(1, "%s() QAM modulation\n", __func__);
+               priv->rf_mode = XC_RF_MODE_CABLE;
+               if (bw <= 6000000) {
+                       priv->video_standard = DTV6;
+                       priv->freq_hz = freq - 1750000;
+                       b = 6;
+               } else if (bw <= 7000000) {
+                       priv->video_standard = DTV7;
+                       priv->freq_hz = freq - 2250000;
+                       b = 7;
+               } else {
+                       priv->video_standard = DTV7_8;
+                       priv->freq_hz = freq - 2750000;
+                       b = 8;
                }
-       } else {
-               printk(KERN_ERR "xc5000 modulation type not supported!\n");
+               dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__,
+                       b, bw);
+               break;
+       default:
+               printk(KERN_ERR "xc5000: delivery system is not supported!\n");
                return -EINVAL;
        }
 
-       dprintk(1, "%s() frequency=%d (compensated)\n",
-               __func__, priv->freq_hz);
+       dprintk(1, "%s() frequency=%d (compensated to %d)\n",
+               __func__, freq, priv->freq_hz);
 
        ret = xc_SetSignalSource(priv, priv->rf_mode);
        if (ret != XC_RESULT_SUCCESS) {
@@ -763,6 +737,8 @@ static int xc5000_set_params(struct dvb_frontend *fe,
        if (debug)
                xc_debug_dump(priv);
 
+       priv->bandwidth = bw;
+
        return 0;
 }
 
@@ -968,6 +944,14 @@ static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
        return 0;
 }
 
+static int xc5000_get_if_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       dprintk(1, "%s()\n", __func__);
+       *freq = priv->if_khz * 1000;
+       return 0;
+}
+
 static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
@@ -1108,6 +1092,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
        .set_params        = xc5000_set_params,
        .set_analog_params = xc5000_set_analog_params,
        .get_frequency     = xc5000_get_frequency,
+       .get_if_frequency  = xc5000_get_if_frequency,
        .get_bandwidth     = xc5000_get_bandwidth,
        .get_status        = xc5000_get_status
 };
@@ -1135,7 +1120,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
                break;
        case 1:
                /* new tuner instance */
-               priv->bandwidth = BANDWIDTH_6_MHZ;
+               priv->bandwidth = 6000000;
                fe->tuner_priv = priv;
                break;
        default:
index 2df1b0214dcdce8bbb139990c18b74c8f9cc5a7b..b1e8c99f469b403005cdb9ff7680050c1ea6278b 100644 (file)
@@ -86,7 +86,8 @@ static int flexcop_dvb_init(struct flexcop_device *fc)
        fc->demux.stop_feed = flexcop_dvb_stop_feed;
        fc->demux.write_to_decoder = NULL;
 
-       if ((ret = dvb_dmx_init(&fc->demux)) < 0) {
+       ret = dvb_dmx_init(&fc->demux);
+       if (ret < 0) {
                err("dvb_dmx failed: error %d", ret);
                goto err_dmx;
        }
@@ -96,32 +97,42 @@ static int flexcop_dvb_init(struct flexcop_device *fc)
        fc->dmxdev.filternum = fc->demux.feednum;
        fc->dmxdev.demux = &fc->demux.dmx;
        fc->dmxdev.capabilities = 0;
-       if ((ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter)) < 0) {
+       ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter);
+       if (ret < 0) {
                err("dvb_dmxdev_init failed: error %d", ret);
                goto err_dmx_dev;
        }
 
-       if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
+       ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend);
+       if (ret < 0) {
                err("adding hw_frontend to dmx failed: error %d", ret);
                goto err_dmx_add_hw_frontend;
        }
 
        fc->mem_frontend.source = DMX_MEMORY_FE;
-       if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend)) < 0) {
+       ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend);
+       if (ret < 0) {
                err("adding mem_frontend to dmx failed: error %d", ret);
                goto err_dmx_add_mem_frontend;
        }
 
-       if ((ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) {
+       ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend);
+       if (ret < 0) {
                err("connect frontend failed: error %d", ret);
                goto err_connect_frontend;
        }
 
-       dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
+       ret = dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
+       if (ret < 0) {
+               err("dvb_net_init failed: error %d", ret);
+               goto err_net;
+       }
 
        fc->init_state |= FC_STATE_DVB_INIT;
        return 0;
 
+err_net:
+       fc->demux.dmx.disconnect_frontend(&fc->demux.dmx);
 err_connect_frontend:
        fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend);
 err_dmx_add_mem_frontend:
@@ -254,7 +265,8 @@ int flexcop_device_initialize(struct flexcop_device *fc)
        flexcop_hw_filter_init(fc);
        flexcop_smc_ctrl(fc, 0);
 
-       if ((ret = flexcop_dvb_init(fc)))
+       ret = flexcop_dvb_init(fc);
+       if (ret)
                goto error;
 
        /* i2c has to be done before doing EEProm stuff -
@@ -272,7 +284,8 @@ int flexcop_device_initialize(struct flexcop_device *fc)
        } else
                warn("reading of MAC address failed.\n");
 
-       if ((ret = flexcop_frontend_init(fc)))
+       ret = flexcop_frontend_init(fc);
+       if (ret)
                goto error;
 
        flexcop_device_name(fc,"initialization of","complete");
index caa4e18ed1c188d4d20575f184f2bf67572358ff..430b3eb118152c1c3606e4cf355f3a925777f672 100644 (file)
@@ -386,7 +386,7 @@ static int dst_set_freq(struct dst_state *state, u32 freq)
        return 0;
 }
 
-static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth)
+static int dst_set_bandwidth(struct dst_state *state, u32 bandwidth)
 {
        state->bandwidth = bandwidth;
 
@@ -394,7 +394,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth)
                return -EOPNOTSUPP;
 
        switch (bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       case 6000000:
                if (state->dst_hw_cap & DST_TYPE_HAS_CA)
                        state->tx_tuna[7] = 0x06;
                else {
@@ -402,7 +402,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth)
                        state->tx_tuna[7] = 0x00;
                }
                break;
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                if (state->dst_hw_cap & DST_TYPE_HAS_CA)
                        state->tx_tuna[7] = 0x07;
                else {
@@ -410,7 +410,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth)
                        state->tx_tuna[7] = 0x00;
                }
                break;
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
                if (state->dst_hw_cap & DST_TYPE_HAS_CA)
                        state->tx_tuna[7] = 0x08;
                else {
@@ -1561,7 +1561,7 @@ static int dst_init(struct dvb_frontend *fe)
        state->tone = SEC_TONE_OFF;
        state->diseq_flags = 0;
        state->k22 = 0x02;
-       state->bandwidth = BANDWIDTH_7_MHZ;
+       state->bandwidth = 7000000;
        state->cur_jiff = jiffies;
        if (state->dst_type == DST_TYPE_IS_SAT)
                memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
@@ -1609,8 +1609,9 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
        return retval;
 }
 
-static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int dst_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        int retval = -EINVAL;
        struct dst_state *state = fe->demodulator_priv;
 
@@ -1623,17 +1624,17 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet
                if (state->dst_type == DST_TYPE_IS_SAT) {
                        if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
                                dst_set_inversion(state, p->inversion);
-                       dst_set_fec(state, p->u.qpsk.fec_inner);
-                       dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+                       dst_set_fec(state, p->fec_inner);
+                       dst_set_symbolrate(state, p->symbol_rate);
                        dst_set_polarization(state);
-                       dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
+                       dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate);
 
                } else if (state->dst_type == DST_TYPE_IS_TERR)
-                       dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+                       dst_set_bandwidth(state, p->bandwidth_hz);
                else if (state->dst_type == DST_TYPE_IS_CABLE) {
-                       dst_set_fec(state, p->u.qam.fec_inner);
-                       dst_set_symbolrate(state, p->u.qam.symbol_rate);
-                       dst_set_modulation(state, p->u.qam.modulation);
+                       dst_set_fec(state, p->fec_inner);
+                       dst_set_symbolrate(state, p->symbol_rate);
+                       dst_set_modulation(state, p->modulation);
                }
                retval = dst_write_tuna(fe);
        }
@@ -1642,31 +1643,32 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet
 }
 
 static int dst_tune_frontend(struct dvb_frontend* fe,
-                           struct dvb_frontend_parameters* p,
+                           bool re_tune,
                            unsigned int mode_flags,
                            unsigned int *delay,
                            fe_status_t *status)
 {
        struct dst_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 
-       if (p != NULL) {
+       if (re_tune) {
                dst_set_freq(state, p->frequency);
                dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
 
                if (state->dst_type == DST_TYPE_IS_SAT) {
                        if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
                                dst_set_inversion(state, p->inversion);
-                       dst_set_fec(state, p->u.qpsk.fec_inner);
-                       dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+                       dst_set_fec(state, p->fec_inner);
+                       dst_set_symbolrate(state, p->symbol_rate);
                        dst_set_polarization(state);
-                       dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
+                       dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate);
 
                } else if (state->dst_type == DST_TYPE_IS_TERR)
-                       dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+                       dst_set_bandwidth(state, p->bandwidth_hz);
                else if (state->dst_type == DST_TYPE_IS_CABLE) {
-                       dst_set_fec(state, p->u.qam.fec_inner);
-                       dst_set_symbolrate(state, p->u.qam.symbol_rate);
-                       dst_set_modulation(state, p->u.qam.modulation);
+                       dst_set_fec(state, p->fec_inner);
+                       dst_set_symbolrate(state, p->symbol_rate);
+                       dst_set_modulation(state, p->modulation);
                }
                dst_write_tuna(fe);
        }
@@ -1683,22 +1685,23 @@ static int dst_get_tuning_algo(struct dvb_frontend *fe)
        return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW;
 }
 
-static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int dst_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct dst_state *state = fe->demodulator_priv;
 
        p->frequency = state->decode_freq;
        if (state->dst_type == DST_TYPE_IS_SAT) {
                if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
                        p->inversion = state->inversion;
-               p->u.qpsk.symbol_rate = state->symbol_rate;
-               p->u.qpsk.fec_inner = dst_get_fec(state);
+               p->symbol_rate = state->symbol_rate;
+               p->fec_inner = dst_get_fec(state);
        } else if (state->dst_type == DST_TYPE_IS_TERR) {
-               p->u.ofdm.bandwidth = state->bandwidth;
+               p->bandwidth_hz = state->bandwidth;
        } else if (state->dst_type == DST_TYPE_IS_CABLE) {
-               p->u.qam.symbol_rate = state->symbol_rate;
-               p->u.qam.fec_inner = dst_get_fec(state);
-               p->u.qam.modulation = dst_get_modulation(state);
+               p->symbol_rate = state->symbol_rate;
+               p->fec_inner = dst_get_fec(state);
+               p->modulation = dst_get_modulation(state);
        }
 
        return 0;
@@ -1756,10 +1759,9 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad
 EXPORT_SYMBOL(dst_attach);
 
 static struct dvb_frontend_ops dst_dvbt_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name = "DST DVB-T",
-               .type = FE_OFDM,
                .frequency_min = 137000000,
                .frequency_max = 858000000,
                .frequency_stepsize = 166667,
@@ -1786,10 +1788,9 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
 };
 
 static struct dvb_frontend_ops dst_dvbs_ops = {
-
+       .delsys = { SYS_DVBS },
        .info = {
                .name = "DST DVB-S",
-               .type = FE_QPSK,
                .frequency_min = 950000,
                .frequency_max = 2150000,
                .frequency_stepsize = 1000,     /* kHz for QPSK frontends */
@@ -1816,10 +1817,9 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
 };
 
 static struct dvb_frontend_ops dst_dvbc_ops = {
-
+       .delsys = { SYS_DVBC_ANNEX_A },
        .info = {
                .name = "DST DVB-C",
-               .type = FE_QAM,
                .frequency_stepsize = 62500,
                .frequency_min = 51000000,
                .frequency_max = 858000000,
@@ -1846,9 +1846,9 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
 };
 
 static struct dvb_frontend_ops dst_atsc_ops = {
+       .delsys = { SYS_ATSC },
        .info = {
                .name = "DST ATSC",
-               .type = FE_ATSC,
                .frequency_stepsize = 62500,
                .frequency_min = 510000000,
                .frequency_max = 858000000,
index d88cf2add82b6b20010b6b1c92c7f8d6d139b784..d70d98f1a5716775c2b9163a80fccfb56051ef6c 100644 (file)
@@ -124,7 +124,7 @@ struct dst_state {
        u16 decode_snr;
        unsigned long cur_jiff;
        u8 k22;
-       fe_bandwidth_t bandwidth;
+       u32 bandwidth;
        u32 dst_hw_cap;
        u8 dst_fw_version;
        fe_sec_mini_cmd_t minicmd;
index 521d691049824523f7229335bf0eb267f976376f..81fab9adc1cad18de7d3f24420893fdc894f1994 100644 (file)
@@ -19,6 +19,8 @@
  *
  */
 
+#define pr_fmt(fmt) "dvb_bt8xx: " fmt
+
 #include <linux/bitops.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -148,8 +150,9 @@ static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
+static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend *fe, u8* pllbuf, int buf_len)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        u32 div;
        unsigned char bs = 0;
        unsigned char cp = 0;
@@ -157,18 +160,18 @@ static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_f
        if (buf_len < 5)
                return -EINVAL;
 
-       div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+       div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
-       if (params->frequency < 542000000)
+       if (c->frequency < 542000000)
                cp = 0xb4;
-       else if (params->frequency < 771000000)
+       else if (c->frequency < 771000000)
                cp = 0xbc;
        else
                cp = 0xf4;
 
-       if (params->frequency == 0)
+       if (c->frequency == 0)
                bs = 0x03;
-       else if (params->frequency < 443250000)
+       else if (c->frequency < 443250000)
                bs = 0x02;
        else
                bs = 0x08;
@@ -191,13 +194,12 @@ static struct zl10353_config thomson_dtt7579_zl10353_config = {
        .demod_address = 0x0f,
 };
 
-static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int cx24108_tuner_set_params(struct dvb_frontend *fe)
 {
-       u32 freq = params->frequency;
-
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 freq = c->frequency;
        int i, a, n, pump;
        u32 band, pll;
-
        u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000,
                1576000,1718000,1856000,2036000,2150000};
        u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000,
@@ -205,7 +207,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend
                0x00120000,0x00140000};
 
        #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
-       printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq);
+       dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq);
 
        /* This is really the bit driving the tuner chip cx24108 */
 
@@ -216,7 +218,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend
 
        /* decide which VCO to use for the input frequency */
        for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++);
-       printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq);
+       dprintk("cx24108 debug: select vco #%d (f=%d)\n", i, freq);
        band=bandsel[i];
        /* the gain values must be set by SetSymbolrate */
        /* compute the pll divider needed, from Conexant data sheet,
@@ -232,7 +234,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend
            ((a&0x1f)<<11);
        /* everything is shifted left 11 bits to left-align the bits in the
           32bit word. Output to the tuner goes MSB-aligned, after all */
-       printk("cx24108 debug: pump=%d, n=%d, a=%d\n",pump,n,a);
+       dprintk("cx24108 debug: pump=%d, n=%d, a=%d\n", pump, n, a);
        cx24110_pll_write(fe,band);
        /* set vga and vca to their widest-band settings, as a precaution.
           SetSymbolrate might not be called to set this up */
@@ -267,31 +269,32 @@ static struct cx24110_config pctvsat_config = {
        .demod_address = 0x55,
 };
 
-static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
        u8 cfg, cpump, band_select;
        u8 data[4];
        u32 div;
        struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
 
-       div = (36000000 + params->frequency + 83333) / 166666;
+       div = (36000000 + c->frequency + 83333) / 166666;
        cfg = 0x88;
 
-       if (params->frequency < 175000000)
+       if (c->frequency < 175000000)
                cpump = 2;
-       else if (params->frequency < 390000000)
+       else if (c->frequency < 390000000)
                cpump = 1;
-       else if (params->frequency < 470000000)
+       else if (c->frequency < 470000000)
                cpump = 2;
-       else if (params->frequency < 750000000)
+       else if (c->frequency < 750000000)
                cpump = 2;
        else
                cpump = 3;
 
-       if (params->frequency < 175000000)
+       if (c->frequency < 175000000)
                band_select = 0x0e;
-       else if (params->frequency < 470000000)
+       else if (c->frequency < 470000000)
                band_select = 0x05;
        else
                band_select = 0x03;
@@ -342,50 +345,51 @@ static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
+static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        u32 div;
        unsigned char bs = 0;
        unsigned char cp = 0;
 
        if (buf_len < 5) return -EINVAL;
 
-       div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+       div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
-       if (params->frequency < 150000000)
+       if (c->frequency < 150000000)
                cp = 0xB4;
-       else if (params->frequency < 173000000)
+       else if (c->frequency < 173000000)
                cp = 0xBC;
-       else if (params->frequency < 250000000)
+       else if (c->frequency < 250000000)
                cp = 0xB4;
-       else if (params->frequency < 400000000)
+       else if (c->frequency < 400000000)
                cp = 0xBC;
-       else if (params->frequency < 420000000)
+       else if (c->frequency < 420000000)
                cp = 0xF4;
-       else if (params->frequency < 470000000)
+       else if (c->frequency < 470000000)
                cp = 0xFC;
-       else if (params->frequency < 600000000)
+       else if (c->frequency < 600000000)
                cp = 0xBC;
-       else if (params->frequency < 730000000)
+       else if (c->frequency < 730000000)
                cp = 0xF4;
        else
                cp = 0xFC;
 
-       if (params->frequency < 150000000)
+       if (c->frequency < 150000000)
                bs = 0x01;
-       else if (params->frequency < 173000000)
+       else if (c->frequency < 173000000)
                bs = 0x01;
-       else if (params->frequency < 250000000)
+       else if (c->frequency < 250000000)
                bs = 0x02;
-       else if (params->frequency < 400000000)
+       else if (c->frequency < 400000000)
                bs = 0x02;
-       else if (params->frequency < 420000000)
+       else if (c->frequency < 420000000)
                bs = 0x02;
-       else if (params->frequency < 470000000)
+       else if (c->frequency < 470000000)
                bs = 0x02;
-       else if (params->frequency < 600000000)
+       else if (c->frequency < 600000000)
                bs = 0x08;
-       else if (params->frequency < 730000000)
+       else if (c->frequency < 730000000)
                bs = 0x08;
        else
                bs = 0x08;
@@ -461,25 +465,26 @@ static struct or51211_config or51211_config = {
        .sleep = or51211_sleep,
 };
 
-static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
        u8 buf[4];
        u32 div;
        struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) };
 
-       div = (params->frequency + 36166667) / 166667;
+       div = (c->frequency + 36166667) / 166667;
 
        buf[0] = (div >> 8) & 0x7F;
        buf[1] = div & 0xFF;
        buf[2] = 0x85;
-       if ((params->frequency >= 47000000) && (params->frequency < 153000000))
+       if ((c->frequency >= 47000000) && (c->frequency < 153000000))
                buf[3] = 0x01;
-       else if ((params->frequency >= 153000000) && (params->frequency < 430000000))
+       else if ((c->frequency >= 153000000) && (c->frequency < 430000000))
                buf[3] = 0x02;
-       else if ((params->frequency >= 430000000) && (params->frequency < 824000000))
+       else if ((c->frequency >= 430000000) && (c->frequency < 824000000))
                buf[3] = 0x0C;
-       else if ((params->frequency >= 824000000) && (params->frequency < 863000000))
+       else if ((c->frequency >= 824000000) && (c->frequency < 863000000))
                buf[3] = 0x8C;
        else
                return -EINVAL;
@@ -513,31 +518,31 @@ static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
+static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend *fe,  u8 *pllbuf, int buf_len)
 {
        u32 div;
-       struct dvb_ofdm_parameters *op = &params->u.ofdm;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
        if (buf_len < 5)
                return -EINVAL;
 
-       div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+       div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
 
        pllbuf[0] = 0x61;
        pllbuf[1] = (div >> 8) & 0x7F;
        pllbuf[2] = div & 0xFF;
        pllbuf[3] = 0x85;
 
-       dprintk("frequency %u, div %u\n", params->frequency, div);
+       dprintk("frequency %u, div %u\n", c->frequency, div);
 
-       if (params->frequency < 470000000)
+       if (c->frequency < 470000000)
                pllbuf[4] = 0x02;
-       else if (params->frequency > 823000000)
+       else if (c->frequency > 823000000)
                pllbuf[4] = 0x88;
        else
                pllbuf[4] = 0x08;
 
-       if (op->bandwidth == 8)
+       if (c->bandwidth_hz == 8000000)
                pllbuf[4] |= 0x04;
 
        return 5;
@@ -663,7 +668,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                /*      DST is not a frontend driver !!!                */
                state = kmalloc(sizeof (struct dst_state), GFP_KERNEL);
                if (!state) {
-                       printk("dvb_bt8xx: No memory\n");
+                       pr_err("No memory\n");
                        break;
                }
                /*      Setup the Card                                  */
@@ -673,7 +678,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                state->dst_ca = NULL;
                /*      DST is not a frontend, attaching the ASIC       */
                if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
-                       printk("%s: Could not find a Twinhan DST.\n", __func__);
+                       pr_err("%s: Could not find a Twinhan DST\n", __func__);
                        break;
                }
                /*      Attach other DST peripherals if any             */
@@ -702,14 +707,14 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
        }
 
        if (card->fe == NULL)
-               printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
+               pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
                       card->bt->dev->vendor,
                       card->bt->dev->device,
                       card->bt->dev->subsystem_vendor,
                       card->bt->dev->subsystem_device);
        else
                if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
-                       printk("dvb-bt8xx: Frontend registration failed!\n");
+                       pr_err("Frontend registration failed!\n");
                        dvb_frontend_detach(card->fe);
                        card->fe = NULL;
                }
@@ -723,7 +728,7 @@ static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
                                      THIS_MODULE, &card->bt->dev->dev,
                                      adapter_nr);
        if (result < 0) {
-               printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
+               pr_err("dvb_register_adapter failed (errno = %d)\n", result);
                return result;
        }
        card->dvb_adapter.priv = card;
@@ -741,66 +746,69 @@ static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
        card->demux.stop_feed = dvb_bt8xx_stop_feed;
        card->demux.write_to_decoder = NULL;
 
-       if ((result = dvb_dmx_init(&card->demux)) < 0) {
-               printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
-
-               dvb_unregister_adapter(&card->dvb_adapter);
-               return result;
+       result = dvb_dmx_init(&card->demux);
+       if (result < 0) {
+               pr_err("dvb_dmx_init failed (errno = %d)\n", result);
+               goto err_unregister_adaptor;
        }
 
        card->dmxdev.filternum = 256;
        card->dmxdev.demux = &card->demux.dmx;
        card->dmxdev.capabilities = 0;
 
-       if ((result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter)) < 0) {
-               printk("dvb_bt8xx: dvb_dmxdev_init failed (errno = %d)\n", result);
-
-               dvb_dmx_release(&card->demux);
-               dvb_unregister_adapter(&card->dvb_adapter);
-               return result;
+       result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter);
+       if (result < 0) {
+               pr_err("dvb_dmxdev_init failed (errno = %d)\n", result);
+               goto err_dmx_release;
        }
 
        card->fe_hw.source = DMX_FRONTEND_0;
 
-       if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw)) < 0) {
-               printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
-
-               dvb_dmxdev_release(&card->dmxdev);
-               dvb_dmx_release(&card->demux);
-               dvb_unregister_adapter(&card->dvb_adapter);
-               return result;
+       result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw);
+       if (result < 0) {
+               pr_err("dvb_dmx_init failed (errno = %d)\n", result);
+               goto err_dmxdev_release;
        }
 
        card->fe_mem.source = DMX_MEMORY_FE;
 
-       if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem)) < 0) {
-               printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
-
-               card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
-               dvb_dmxdev_release(&card->dmxdev);
-               dvb_dmx_release(&card->demux);
-               dvb_unregister_adapter(&card->dvb_adapter);
-               return result;
+       result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem);
+       if (result < 0) {
+               pr_err("dvb_dmx_init failed (errno = %d)\n", result);
+               goto err_remove_hw_frontend;
        }
 
-       if ((result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw)) < 0) {
-               printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
-
-               card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
-               card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
-               dvb_dmxdev_release(&card->dmxdev);
-               dvb_dmx_release(&card->demux);
-               dvb_unregister_adapter(&card->dvb_adapter);
-               return result;
+       result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw);
+       if (result < 0) {
+               pr_err("dvb_dmx_init failed (errno = %d)\n", result);
+               goto err_remove_mem_frontend;
        }
 
-       dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx);
+       result = dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx);
+       if (result < 0) {
+               pr_err("dvb_net_init failed (errno = %d)\n", result);
+               goto err_disconnect_frontend;
+       }
 
        tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card);
 
        frontend_init(card, type);
 
        return 0;
+
+err_disconnect_frontend:
+       card->demux.dmx.disconnect_frontend(&card->demux.dmx);
+err_remove_mem_frontend:
+       card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
+err_remove_hw_frontend:
+       card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
+err_dmxdev_release:
+       dvb_dmxdev_release(&card->dmxdev);
+err_dmx_release:
+       dvb_dmx_release(&card->demux);
+err_unregister_adaptor:
+       dvb_unregister_adapter(&card->dvb_adapter);
+       return result;
 }
 
 static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
@@ -881,8 +889,7 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
                break;
 
        default:
-               printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n",
-                               sub->core->type);
+               pr_err("Unknown bttv card type: %d\n", sub->core->type);
                kfree(card);
                return -ENODEV;
        }
@@ -890,16 +897,14 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
        dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name);
 
        if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) {
-               printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr);
+               pr_err("no pci device for card %d\n", card->bttv_nr);
                kfree(card);
                return -ENODEV;
        }
 
        if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) {
-               printk("dvb_bt8xx: unable to determine DMA core of card %d,\n",
-                      card->bttv_nr);
-               printk("dvb_bt8xx: if you have the ALSA bt87x audio driver "
-                      "installed, try removing it.\n");
+               pr_err("unable to determine DMA core of card %d,\n", card->bttv_nr);
+               pr_err("if you have the ALSA bt87x audio driver installed, try removing it.\n");
 
                kfree(card);
                return -ENODEV;
index d1e91bc80e78ac1e819663ac827d2c4302e38f3d..ce4f85849e7b1cc6114b05e1664dd2be71dc6e54 100644 (file)
@@ -580,7 +580,7 @@ static int demod_attach_drxk(struct ddb_input *input)
        memset(&config, 0, sizeof(config));
        config.adr = 0x29 + (input->nr & 1);
 
-       fe = input->fe = dvb_attach(drxk_attach, &config, i2c, &input->fe2);
+       fe = input->fe = dvb_attach(drxk_attach, &config, i2c);
        if (!input->fe) {
                printk(KERN_ERR "No DRXK found!\n");
                return -ENODEV;
index 55e6533f15e9f5ed8d5a95991256a14208fc7dcb..a609b3a9b14695bfff2a3e53a387c241e4b38107 100644 (file)
@@ -1115,11 +1115,14 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
        if (ret < 0)
                goto err_remove_mem_frontend;
 
-       ret = frontend_init(dev);
+       ret = dvb_net_init(dvb_adapter, &dev->dvbnet, dmx);
        if (ret < 0)
                goto err_disconnect_frontend;
 
-       dvb_net_init(dvb_adapter, &dev->dvbnet, dmx);
+       ret = frontend_init(dev);
+       if (ret < 0)
+               goto err_dvb_net;
+
        dm1105_ir_init(dev);
 
        INIT_WORK(&dev->work, dm1105_dmx_buffer);
index 7ea517b7e18626fd5723c255cb0aee2a102970a8..9be65a3b931fc91bd71c8155d8ccdd1da94e63e3 100644 (file)
@@ -1306,6 +1306,10 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
        /* fragment the packets & store in the buffer */
        while (fragpos < count) {
                fraglen = ca->slot_info[slot].link_buf_size - 2;
+               if (fraglen < 0)
+                       break;
+               if (fraglen > HOST_LINK_BUF_SIZE - 2)
+                       fraglen = HOST_LINK_BUF_SIZE - 2;
                if ((count - fragpos) < fraglen)
                        fraglen = count - fragpos;
 
index 2c0acdb4d81144b00b1381742505d18f208addb2..fbbe545a74cb5357c3c1cdf445511c80f32dd724 100644 (file)
@@ -25,6 +25,9 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  */
 
+/* Enables DVBv3 compatibility bits at the headers */
+#define __DVB_CORE__
+
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -105,7 +108,6 @@ struct dvb_frontend_private {
 
        /* thread/frontend values */
        struct dvb_device *dvbdev;
-       struct dvb_frontend_parameters parameters_in;
        struct dvb_frontend_parameters parameters_out;
        struct dvb_fe_events events;
        struct semaphore sem;
@@ -139,6 +141,62 @@ struct dvb_frontend_private {
 };
 
 static void dvb_frontend_wakeup(struct dvb_frontend *fe);
+static int dtv_get_frontend(struct dvb_frontend *fe,
+                           struct dvb_frontend_parameters *p_out);
+
+static bool has_get_frontend(struct dvb_frontend *fe)
+{
+       return fe->ops.get_frontend;
+}
+
+/*
+ * Due to DVBv3 API calls, a delivery system should be mapped into one of
+ * the 4 DVBv3 delivery systems (FE_QPSK, FE_QAM, FE_OFDM or FE_ATSC),
+ * otherwise, a DVBv3 call will fail.
+ */
+enum dvbv3_emulation_type {
+       DVBV3_UNKNOWN,
+       DVBV3_QPSK,
+       DVBV3_QAM,
+       DVBV3_OFDM,
+       DVBV3_ATSC,
+};
+
+static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system)
+{
+       switch (delivery_system) {
+       case SYS_DVBC_ANNEX_A:
+       case SYS_DVBC_ANNEX_C:
+               return DVBV3_QAM;
+       case SYS_DVBS:
+       case SYS_DVBS2:
+       case SYS_TURBO:
+       case SYS_ISDBS:
+       case SYS_DSS:
+               return DVBV3_QPSK;
+       case SYS_DVBT:
+       case SYS_DVBT2:
+       case SYS_ISDBT:
+       case SYS_DMBTH:
+               return DVBV3_OFDM;
+       case SYS_ATSC:
+       case SYS_DVBC_ANNEX_B:
+               return DVBV3_ATSC;
+       case SYS_UNDEFINED:
+       case SYS_ISDBC:
+       case SYS_DVBH:
+       case SYS_DAB:
+       case SYS_ATSCMH:
+       default:
+               /*
+                * Doesn't know how to emulate those types and/or
+                * there's no frontend driver from this type yet
+                * with some emulation code, so, we're not sure yet how
+                * to handle them, or they're not compatible with a DVBv3 call.
+                */
+               return DVBV3_UNKNOWN;
+       }
+}
 
 static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
 {
@@ -149,8 +207,8 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
 
        dprintk ("%s\n", __func__);
 
-       if ((status & FE_HAS_LOCK) && fe->ops.get_frontend)
-               fe->ops.get_frontend(fe, &fepriv->parameters_out);
+       if ((status & FE_HAS_LOCK) && has_get_frontend(fe))
+               dtv_get_frontend(fe, &fepriv->parameters_out);
 
        mutex_lock(&events->mtx);
 
@@ -277,12 +335,13 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
        int ready = 0;
        int fe_set_err = 0;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       int original_inversion = fepriv->parameters_in.inversion;
-       u32 original_frequency = fepriv->parameters_in.frequency;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
+       int original_inversion = c->inversion;
+       u32 original_frequency = c->frequency;
 
        /* are we using autoinversion? */
        autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
-                        (fepriv->parameters_in.inversion == INVERSION_AUTO));
+                        (c->inversion == INVERSION_AUTO));
 
        /* setup parameters correctly */
        while(!ready) {
@@ -348,19 +407,20 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
                fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
 
        /* set the frontend itself */
-       fepriv->parameters_in.frequency += fepriv->lnb_drift;
+       c->frequency += fepriv->lnb_drift;
        if (autoinversion)
-               fepriv->parameters_in.inversion = fepriv->inversion;
+               c->inversion = fepriv->inversion;
+       tmp = *c;
        if (fe->ops.set_frontend)
-               fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters_in);
-       fepriv->parameters_out = fepriv->parameters_in;
+               fe_set_err = fe->ops.set_frontend(fe);
+       *c = tmp;
        if (fe_set_err < 0) {
                fepriv->state = FESTATE_ERROR;
                return fe_set_err;
        }
 
-       fepriv->parameters_in.frequency = original_frequency;
-       fepriv->parameters_in.inversion = original_inversion;
+       c->frequency = original_frequency;
+       c->inversion = original_inversion;
 
        fepriv->auto_sub_step++;
        return 0;
@@ -371,6 +431,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
        fe_status_t s = 0;
        int retval = 0;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
 
        /* if we've got no parameters, just keep idling */
        if (fepriv->state & FESTATE_IDLE) {
@@ -382,10 +443,10 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
        /* in SCAN mode, we just set the frontend when asked and leave it alone */
        if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
                if (fepriv->state & FESTATE_RETUNE) {
+                       tmp = *c;
                        if (fe->ops.set_frontend)
-                               retval = fe->ops.set_frontend(fe,
-                                                       &fepriv->parameters_in);
-                       fepriv->parameters_out = fepriv->parameters_in;
+                               retval = fe->ops.set_frontend(fe);
+                       *c = tmp;
                        if (retval < 0)
                                fepriv->state = FESTATE_ERROR;
                        else
@@ -415,8 +476,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
 
                /* if we're tuned, then we have determined the correct inversion */
                if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
-                   (fepriv->parameters_in.inversion == INVERSION_AUTO)) {
-                       fepriv->parameters_in.inversion = fepriv->inversion;
+                   (c->inversion == INVERSION_AUTO)) {
+                       c->inversion = fepriv->inversion;
                }
                return;
        }
@@ -507,7 +568,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
                return 1;
 
        if (fepriv->dvbdev->writers == 1)
-               if (time_after(jiffies, fepriv->release_jiffies +
+               if (time_after_eq(jiffies, fepriv->release_jiffies +
                                  dvb_shutdown_timeout * HZ))
                        return 1;
 
@@ -540,7 +601,7 @@ static int dvb_frontend_thread(void *data)
        fe_status_t s;
        enum dvbfe_algo algo;
 
-       struct dvb_frontend_parameters *params;
+       bool re_tune = false;
 
        dprintk("%s\n", __func__);
 
@@ -589,18 +650,15 @@ restart:
                        switch (algo) {
                        case DVBFE_ALGO_HW:
                                dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
-                               params = NULL; /* have we been asked to RETUNE ? */
 
                                if (fepriv->state & FESTATE_RETUNE) {
                                        dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
-                                       params = &fepriv->parameters_in;
+                                       re_tune = true;
                                        fepriv->state = FESTATE_TUNED;
                                }
 
                                if (fe->ops.tune)
-                                       fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
-                               if (params)
-                                       fepriv->parameters_out = *params;
+                                       fe->ops.tune(fe, re_tune, fepriv->tune_mode_flags, &fepriv->delay, &s);
 
                                if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
                                        dprintk("%s: state changed, adding current state\n", __func__);
@@ -624,7 +682,7 @@ restart:
                                 */
                                if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
                                        if (fe->ops.search) {
-                                               fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters_in);
+                                               fepriv->algo_status = fe->ops.search(fe);
                                                /* We did do a search as was requested, the flags are
                                                 * now unset as well and has the flags wrt to search.
                                                 */
@@ -633,14 +691,10 @@ restart:
                                        }
                                }
                                /* Track the carrier if the search was successful */
-                               if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {
-                                       if (fe->ops.track)
-                                               fe->ops.track(fe, &fepriv->parameters_in);
-                               } else {
+                               if (fepriv->algo_status != DVBFE_ALGO_SEARCH_SUCCESS) {
                                        fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
                                        fepriv->delay = HZ / 2;
                                }
-                               fepriv->parameters_out = fepriv->parameters_in;
                                fe->ops.read_status(fe, &s);
                                if (s != fepriv->status) {
                                        dvb_frontend_add_event(fe, s); /* update event list */
@@ -807,52 +861,40 @@ static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
                       fe->dvb->num,fe->id);
 }
 
-static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *parms)
+static int dvb_frontend_check_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        u32 freq_min;
        u32 freq_max;
 
        /* range check: frequency */
        dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max);
-       if ((freq_min && parms->frequency < freq_min) ||
-           (freq_max && parms->frequency > freq_max)) {
+       if ((freq_min && c->frequency < freq_min) ||
+           (freq_max && c->frequency > freq_max)) {
                printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
-                      fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max);
+                      fe->dvb->num, fe->id, c->frequency, freq_min, freq_max);
                return -EINVAL;
        }
 
        /* range check: symbol rate */
-       if (fe->ops.info.type == FE_QPSK) {
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+       case SYS_DVBS2:
+       case SYS_TURBO:
+       case SYS_DVBC_ANNEX_A:
+       case SYS_DVBC_ANNEX_C:
                if ((fe->ops.info.symbol_rate_min &&
-                    parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
+                    c->symbol_rate < fe->ops.info.symbol_rate_min) ||
                    (fe->ops.info.symbol_rate_max &&
-                    parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {
+                    c->symbol_rate > fe->ops.info.symbol_rate_max)) {
                        printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
-                              fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate,
-                              fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
+                              fe->dvb->num, fe->id, c->symbol_rate,
+                              fe->ops.info.symbol_rate_min,
+                              fe->ops.info.symbol_rate_max);
                        return -EINVAL;
                }
-
-       } else if (fe->ops.info.type == FE_QAM) {
-               if ((fe->ops.info.symbol_rate_min &&
-                    parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||
-                   (fe->ops.info.symbol_rate_max &&
-                    parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {
-                       printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
-                              fe->dvb->num, fe->id, parms->u.qam.symbol_rate,
-                              fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
-                       return -EINVAL;
-               }
-       }
-
-       /* check for supported modulation */
-       if (fe->ops.info.type == FE_QAM &&
-           (parms->u.qam.modulation > QAM_AUTO ||
-            !((1 << (parms->u.qam.modulation + 10)) & fe->ops.info.caps))) {
-               printk(KERN_WARNING "DVB: adapter %i frontend %i modulation %u not supported\n",
-                      fe->dvb->num, fe->id, parms->u.qam.modulation);
-                       return -EINVAL;
+       default:
+               break;
        }
 
        return 0;
@@ -862,32 +904,59 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
 {
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int i;
+       u32 delsys;
 
+       delsys = c->delivery_system;
        memset(c, 0, sizeof(struct dtv_frontend_properties));
+       c->delivery_system = delsys;
 
        c->state = DTV_CLEAR;
-       c->delivery_system = SYS_UNDEFINED;
-       c->inversion = INVERSION_AUTO;
-       c->fec_inner = FEC_AUTO;
+
+       dprintk("%s() Clearing cache for delivery system %d\n", __func__,
+               c->delivery_system);
+
        c->transmission_mode = TRANSMISSION_MODE_AUTO;
-       c->bandwidth_hz = BANDWIDTH_AUTO;
+       c->bandwidth_hz = 0;    /* AUTO */
        c->guard_interval = GUARD_INTERVAL_AUTO;
        c->hierarchy = HIERARCHY_AUTO;
-       c->symbol_rate = QAM_AUTO;
+       c->symbol_rate = 0;
        c->code_rate_HP = FEC_AUTO;
        c->code_rate_LP = FEC_AUTO;
-
-       c->isdbt_partial_reception = -1;
-       c->isdbt_sb_mode = -1;
-       c->isdbt_sb_subchannel = -1;
-       c->isdbt_sb_segment_idx = -1;
-       c->isdbt_sb_segment_count = -1;
-       c->isdbt_layer_enabled = 0x7;
+       c->fec_inner = FEC_AUTO;
+       c->rolloff = ROLLOFF_AUTO;
+       c->voltage = SEC_VOLTAGE_OFF;
+       c->sectone = SEC_TONE_OFF;
+       c->pilot = PILOT_AUTO;
+
+       c->isdbt_partial_reception = 0;
+       c->isdbt_sb_mode = 0;
+       c->isdbt_sb_subchannel = 0;
+       c->isdbt_sb_segment_idx = 0;
+       c->isdbt_sb_segment_count = 0;
+       c->isdbt_layer_enabled = 0;
        for (i = 0; i < 3; i++) {
                c->layer[i].fec = FEC_AUTO;
                c->layer[i].modulation = QAM_AUTO;
-               c->layer[i].interleaving = -1;
-               c->layer[i].segment_count = -1;
+               c->layer[i].interleaving = 0;
+               c->layer[i].segment_count = 0;
+       }
+
+       c->isdbs_ts_id = 0;
+       c->dvbt2_plp_id = 0;
+
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+       case SYS_DVBS2:
+       case SYS_TURBO:
+               c->modulation = QPSK;   /* implied for DVB-S in legacy API */
+               c->rolloff = ROLLOFF_35;/* implied for DVB-S */
+               break;
+       case SYS_ATSC:
+               c->modulation = VSB_8;
+               break;
+       default:
+               c->modulation = QAM_AUTO;
+               break;
        }
 
        return 0;
@@ -943,25 +1012,6 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
        _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0),
        _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0),
 
-       _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 0, 0),
-       _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 0, 0),
-       _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 0, 0),
-       _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 0, 0),
-       _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 0, 0),
-       _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 0, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 0, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 0, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 0, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 0, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 0, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 0, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 0, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 0, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 0, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 0, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 0, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0),
-
        _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
        _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0),
 
@@ -973,6 +1023,8 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
        _DTV_CMD(DTV_GUARD_INTERVAL, 0, 0),
        _DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0),
        _DTV_CMD(DTV_HIERARCHY, 0, 0),
+
+       _DTV_CMD(DTV_ENUM_DELSYS, 0, 0),
 };
 
 static void dtv_property_dump(struct dtv_property *tvp)
@@ -1006,70 +1058,54 @@ static void dtv_property_dump(struct dtv_property *tvp)
                dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);
 }
 
-static int is_legacy_delivery_system(fe_delivery_system_t s)
-{
-       if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) ||
-          (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) ||
-          (s == SYS_ATSC))
-               return 1;
-
-       return 0;
-}
-
-/* Initialize the cache with some default values derived from the
- * legacy frontend_info structure.
- */
-static void dtv_property_cache_init(struct dvb_frontend *fe,
-                                   struct dtv_frontend_properties *c)
-{
-       switch (fe->ops.info.type) {
-       case FE_QPSK:
-               c->modulation = QPSK;   /* implied for DVB-S in legacy API */
-               c->rolloff = ROLLOFF_35;/* implied for DVB-S */
-               c->delivery_system = SYS_DVBS;
-               break;
-       case FE_QAM:
-               c->delivery_system = SYS_DVBC_ANNEX_AC;
-               break;
-       case FE_OFDM:
-               c->delivery_system = SYS_DVBT;
-               break;
-       case FE_ATSC:
-               break;
-       }
-}
-
 /* Synchronise the legacy tuning parameters into the cache, so that demodulator
  * drivers can use a single set_frontend tuning function, regardless of whether
  * it's being used for the legacy or new API, reducing code and complexity.
  */
-static void dtv_property_cache_sync(struct dvb_frontend *fe,
-                                   struct dtv_frontend_properties *c,
-                                   const struct dvb_frontend_parameters *p)
+static int dtv_property_cache_sync(struct dvb_frontend *fe,
+                                  struct dtv_frontend_properties *c,
+                                  const struct dvb_frontend_parameters *p)
 {
        c->frequency = p->frequency;
        c->inversion = p->inversion;
 
-       switch (fe->ops.info.type) {
-       case FE_QPSK:
+       switch (dvbv3_type(c->delivery_system)) {
+       case DVBV3_QPSK:
+               dprintk("%s() Preparing QPSK req\n", __func__);
                c->symbol_rate = p->u.qpsk.symbol_rate;
                c->fec_inner = p->u.qpsk.fec_inner;
                break;
-       case FE_QAM:
+       case DVBV3_QAM:
+               dprintk("%s() Preparing QAM req\n", __func__);
                c->symbol_rate = p->u.qam.symbol_rate;
                c->fec_inner = p->u.qam.fec_inner;
                c->modulation = p->u.qam.modulation;
                break;
-       case FE_OFDM:
-               if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
-                       c->bandwidth_hz = 6000000;
-               else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
-                       c->bandwidth_hz = 7000000;
-               else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+       case DVBV3_OFDM:
+               dprintk("%s() Preparing OFDM req\n", __func__);
+               switch (p->u.ofdm.bandwidth) {
+               case BANDWIDTH_10_MHZ:
+                       c->bandwidth_hz = 10000000;
+                       break;
+               case BANDWIDTH_8_MHZ:
                        c->bandwidth_hz = 8000000;
-               else
-                       /* Including BANDWIDTH_AUTO */
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       c->bandwidth_hz = 7000000;
+                       break;
+               case BANDWIDTH_6_MHZ:
+                       c->bandwidth_hz = 6000000;
+                       break;
+               case BANDWIDTH_5_MHZ:
+                       c->bandwidth_hz = 5000000;
+                       break;
+               case BANDWIDTH_1_712_MHZ:
+                       c->bandwidth_hz = 1712000;
+                       break;
+               case BANDWIDTH_AUTO:
                        c->bandwidth_hz = 0;
+               }
+
                c->code_rate_HP = p->u.ofdm.code_rate_HP;
                c->code_rate_LP = p->u.ofdm.code_rate_LP;
                c->modulation = p->u.ofdm.constellation;
@@ -1077,50 +1113,78 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe,
                c->guard_interval = p->u.ofdm.guard_interval;
                c->hierarchy = p->u.ofdm.hierarchy_information;
                break;
-       case FE_ATSC:
+       case DVBV3_ATSC:
+               dprintk("%s() Preparing ATSC req\n", __func__);
                c->modulation = p->u.vsb.modulation;
                if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
                        c->delivery_system = SYS_ATSC;
                else
                        c->delivery_system = SYS_DVBC_ANNEX_B;
                break;
+       case DVBV3_UNKNOWN:
+               printk(KERN_ERR
+                      "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
+                      __func__, c->delivery_system);
+               return -EINVAL;
        }
+
+       return 0;
 }
 
 /* Ensure the cached values are set correctly in the frontend
  * legacy tuning structures, for the advanced tuning API.
  */
-static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
+                                           struct dvb_frontend_parameters *p)
 {
        const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dvb_frontend_parameters *p = &fepriv->parameters_in;
 
        p->frequency = c->frequency;
        p->inversion = c->inversion;
 
-       switch (fe->ops.info.type) {
-       case FE_QPSK:
+       switch (dvbv3_type(c->delivery_system)) {
+       case DVBV3_UNKNOWN:
+               printk(KERN_ERR
+                      "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
+                      __func__, c->delivery_system);
+               return -EINVAL;
+       case DVBV3_QPSK:
                dprintk("%s() Preparing QPSK req\n", __func__);
                p->u.qpsk.symbol_rate = c->symbol_rate;
                p->u.qpsk.fec_inner = c->fec_inner;
                break;
-       case FE_QAM:
+       case DVBV3_QAM:
                dprintk("%s() Preparing QAM req\n", __func__);
                p->u.qam.symbol_rate = c->symbol_rate;
                p->u.qam.fec_inner = c->fec_inner;
                p->u.qam.modulation = c->modulation;
                break;
-       case FE_OFDM:
+       case DVBV3_OFDM:
                dprintk("%s() Preparing OFDM req\n", __func__);
-               if (c->bandwidth_hz == 6000000)
-                       p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
-               else if (c->bandwidth_hz == 7000000)
-                       p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
-               else if (c->bandwidth_hz == 8000000)
+
+               switch (c->bandwidth_hz) {
+               case 10000000:
+                       p->u.ofdm.bandwidth = BANDWIDTH_10_MHZ;
+                       break;
+               case 8000000:
                        p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
-               else
+                       break;
+               case 7000000:
+                       p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+                       break;
+               case 6000000:
+                       p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+                       break;
+               case 5000000:
+                       p->u.ofdm.bandwidth = BANDWIDTH_5_MHZ;
+                       break;
+               case 1712000:
+                       p->u.ofdm.bandwidth = BANDWIDTH_1_712_MHZ;
+                       break;
+               case 0:
+               default:
                        p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
+               }
                p->u.ofdm.code_rate_HP = c->code_rate_HP;
                p->u.ofdm.code_rate_LP = c->code_rate_LP;
                p->u.ofdm.constellation = c->modulation;
@@ -1128,78 +1192,40 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
                p->u.ofdm.guard_interval = c->guard_interval;
                p->u.ofdm.hierarchy_information = c->hierarchy;
                break;
-       case FE_ATSC:
+       case DVBV3_ATSC:
                dprintk("%s() Preparing VSB req\n", __func__);
                p->u.vsb.modulation = c->modulation;
                break;
        }
+       return 0;
 }
 
-/* Ensure the cached values are set correctly in the frontend
- * legacy tuning structures, for the legacy tuning API.
+/**
+ * dtv_get_frontend - calls a callback for retrieving DTV parameters
+ * @fe:                struct dvb_frontend pointer
+ * @c:         struct dtv_frontend_properties pointer (DVBv5 cache)
+ * @p_out      struct dvb_frontend_parameters pointer (DVBv3 FE struct)
+ *
+ * This routine calls either the DVBv3 or DVBv5 get_frontend call.
+ * If c is not null, it will update the DVBv5 cache struct pointed by it.
+ * If p_out is not null, it will update the DVBv3 params pointed by it.
  */
-static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+static int dtv_get_frontend(struct dvb_frontend *fe,
+                           struct dvb_frontend_parameters *p_out)
 {
-       const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dvb_frontend_parameters *p = &fepriv->parameters_in;
-
-       p->frequency = c->frequency;
-       p->inversion = c->inversion;
-
-       if (c->delivery_system == SYS_DSS ||
-           c->delivery_system == SYS_DVBS ||
-           c->delivery_system == SYS_DVBS2 ||
-           c->delivery_system == SYS_ISDBS ||
-           c->delivery_system == SYS_TURBO) {
-               p->u.qpsk.symbol_rate = c->symbol_rate;
-               p->u.qpsk.fec_inner = c->fec_inner;
-       }
+       int r;
 
-       /* Fake out a generic DVB-T request so we pass validation in the ioctl */
-       if ((c->delivery_system == SYS_ISDBT) ||
-           (c->delivery_system == SYS_DVBT2)) {
-               p->u.ofdm.constellation = QAM_AUTO;
-               p->u.ofdm.code_rate_HP = FEC_AUTO;
-               p->u.ofdm.code_rate_LP = FEC_AUTO;
-               p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
-               p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
-               p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;
-               if (c->bandwidth_hz == 8000000)
-                       p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
-               else if (c->bandwidth_hz == 7000000)
-                       p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
-               else if (c->bandwidth_hz == 6000000)
-                       p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
-               else
-                       p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
+       if (fe->ops.get_frontend) {
+               r = fe->ops.get_frontend(fe);
+               if (unlikely(r < 0))
+                       return r;
+               if (p_out)
+                       dtv_property_legacy_params_sync(fe, p_out);
+               return 0;
        }
-}
 
-static void dtv_property_cache_submit(struct dvb_frontend *fe)
-{
-       const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
-       /* For legacy delivery systems we don't need the delivery_system to
-        * be specified, but we populate the older structures from the cache
-        * so we can call set_frontend on older drivers.
-        */
-       if(is_legacy_delivery_system(c->delivery_system)) {
-
-               dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation);
-               dtv_property_legacy_params_sync(fe);
-
-       } else {
-               dprintk("%s() adv, modulation = %d\n", __func__, c->modulation);
-
-               /* For advanced delivery systems / modulation types ...
-                * we seed the lecacy dvb_frontend_parameters structure
-                * so that the sanity checking code later in the IOCTL processing
-                * can validate our basic frequency ranges, symbolrates, modulation
-                * etc.
-                */
-               dtv_property_adv_params_sync(fe);
-       }
+       /* As everything is in cache, get_frontend fops are always supported */
+       return 0;
 }
 
 static int dvb_frontend_ioctl_legacy(struct file *file,
@@ -1208,25 +1234,21 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                        unsigned int cmd, void *parg);
 
 static int dtv_property_process_get(struct dvb_frontend *fe,
+                                   const struct dtv_frontend_properties *c,
                                    struct dtv_property *tvp,
                                    struct file *file)
 {
-       const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dtv_frontend_properties cdetected;
-       int r;
-
-       /*
-        * If the driver implements a get_frontend function, then convert
-        * detected parameters to S2API properties.
-        */
-       if (fe->ops.get_frontend) {
-               cdetected = *c;
-               dtv_property_cache_sync(fe, &cdetected, &fepriv->parameters_out);
-               c = &cdetected;
-       }
+       int r, ncaps;
 
        switch(tvp->cmd) {
+       case DTV_ENUM_DELSYS:
+               ncaps = 0;
+               while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+                       tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps];
+                       ncaps++;
+               }
+               tvp->u.buffer.len = ncaps;
+               break;
        case DTV_FREQUENCY:
                tvp->u.data = c->frequency;
                break;
@@ -1356,14 +1378,168 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
        return 0;
 }
 
+static int dtv_set_frontend(struct dvb_frontend *fe);
+
+static bool is_dvbv3_delsys(u32 delsys)
+{
+       bool status;
+
+       status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
+                (delsys == SYS_DVBS) || (delsys == SYS_ATSC);
+
+       return status;
+}
+
+static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
+{
+       int ncaps, i;
+       u32 delsys = SYS_UNDEFINED;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       enum dvbv3_emulation_type type;
+
+       /*
+        * It was reported that some old DVBv5 applications were
+        * filling delivery_system with SYS_UNDEFINED. If this happens,
+        * assume that the application wants to use the first supported
+        * delivery system.
+        */
+       if (c->delivery_system == SYS_UNDEFINED)
+               c->delivery_system = fe->ops.delsys[0];
+
+       if (desired_system == SYS_UNDEFINED) {
+               /*
+                * A DVBv3 call doesn't know what's the desired system.
+                * Also, DVBv3 applications don't know that ops.info->type
+                * could be changed, and they simply dies when it doesn't
+                * match.
+                * So, don't change the current delivery system, as it
+                * may be trying to do the wrong thing, like setting an
+                * ISDB-T frontend as DVB-T. Instead, find the closest
+                * DVBv3 system that matches the delivery system.
+                */
+               if (is_dvbv3_delsys(c->delivery_system)) {
+                       dprintk("%s() Using delivery system to %d\n",
+                               __func__, c->delivery_system);
+                       return 0;
+               }
+               type = dvbv3_type(c->delivery_system);
+               switch (type) {
+               case DVBV3_QPSK:
+                       desired_system = SYS_DVBS;
+                       break;
+               case DVBV3_QAM:
+                       desired_system = SYS_DVBC_ANNEX_A;
+                       break;
+               case DVBV3_ATSC:
+                       desired_system = SYS_ATSC;
+                       break;
+               case DVBV3_OFDM:
+                       desired_system = SYS_DVBT;
+                       break;
+               default:
+                       dprintk("%s(): This frontend doesn't support DVBv3 calls\n",
+                               __func__);
+                       return -EINVAL;
+               }
+       } else {
+               /*
+                * This is a DVBv5 call. So, it likely knows the supported
+                * delivery systems.
+                */
+
+               /* Check if the desired delivery system is supported */
+               ncaps = 0;
+               while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+                       if (fe->ops.delsys[ncaps] == desired_system) {
+                               c->delivery_system = desired_system;
+                               dprintk("%s() Changing delivery system to %d\n",
+                                       __func__, desired_system);
+                               return 0;
+                       }
+                       ncaps++;
+               }
+               type = dvbv3_type(desired_system);
+
+               /*
+                * The delivery system is not supported. See if it can be
+                * emulated.
+                * The emulation only works if the desired system is one of the
+                * DVBv3 delivery systems
+                */
+               if (!is_dvbv3_delsys(desired_system)) {
+                       dprintk("%s() can't use a DVBv3 FE_SET_FRONTEND call on this frontend\n",
+                               __func__);
+                       return -EINVAL;
+               }
+
+               /*
+                * Get the last non-DVBv3 delivery system that has the same type
+                * of the desired system
+                */
+               ncaps = 0;
+               while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+                       if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) &&
+                           !is_dvbv3_delsys(fe->ops.delsys[ncaps]))
+                               delsys = fe->ops.delsys[ncaps];
+                       ncaps++;
+               }
+               /* There's nothing compatible with the desired delivery system */
+               if (delsys == SYS_UNDEFINED) {
+                       dprintk("%s() Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n",
+                               __func__);
+                       return -EINVAL;
+               }
+               c->delivery_system = delsys;
+       }
+
+       /*
+        * The DVBv3 or DVBv5 call is requesting a different system. So,
+        * emulation is needed.
+        *
+        * Emulate newer delivery systems like ISDBT, DVBT and DMBTH
+        * for older DVBv5 applications. The emulation will try to use
+        * the auto mode for most things, and will assume that the desired
+        * delivery system is the last one at the ops.delsys[] array
+        */
+       dprintk("%s() Using delivery system %d emulated as if it were a %d\n",
+               __func__, delsys, desired_system);
+
+       /*
+        * For now, handles ISDB-T calls. More code may be needed here for the
+        * other emulated stuff
+        */
+       if (type == DVBV3_OFDM) {
+               if (c->delivery_system == SYS_ISDBT) {
+                       dprintk("%s() Using defaults for SYS_ISDBT\n",
+                               __func__);
+                       if (!c->bandwidth_hz)
+                               c->bandwidth_hz = 6000000;
+
+                       c->isdbt_partial_reception = 0;
+                       c->isdbt_sb_mode = 0;
+                       c->isdbt_sb_subchannel = 0;
+                       c->isdbt_sb_segment_idx = 0;
+                       c->isdbt_sb_segment_count = 0;
+                       c->isdbt_layer_enabled = 0;
+                       for (i = 0; i < 3; i++) {
+                               c->layer[i].fec = FEC_AUTO;
+                               c->layer[i].modulation = QAM_AUTO;
+                               c->layer[i].interleaving = 0;
+                               c->layer[i].segment_count = 0;
+                       }
+               }
+       }
+       dprintk("change delivery system on cache to %d\n", c->delivery_system);
+
+       return 0;
+}
+
 static int dtv_property_process_set(struct dvb_frontend *fe,
                                    struct dtv_property *tvp,
                                    struct file *file)
 {
        int r = 0;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       dtv_property_dump(tvp);
 
        /* Allow the frontend to validate incoming properties */
        if (fe->ops.set_property) {
@@ -1374,11 +1550,11 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
 
        switch(tvp->cmd) {
        case DTV_CLEAR:
-               /* Reset a cache of data specific to the frontend here. This does
+               /*
+                * Reset a cache of data specific to the frontend here. This does
                 * not effect hardware.
                 */
                dvb_frontend_clear_cache(fe);
-               dprintk("%s() Flushing property cache\n", __func__);
                break;
        case DTV_TUNE:
                /* interpret the cache of data, build either a traditional frontend
@@ -1387,10 +1563,8 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
                 */
                c->state = tvp->cmd;
                dprintk("%s() Finalised property cache\n", __func__);
-               dtv_property_cache_submit(fe);
 
-               r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
-                       &fepriv->parameters_in);
+               r = dtv_set_frontend(fe);
                break;
        case DTV_FREQUENCY:
                c->frequency = tvp->u.data;
@@ -1417,7 +1591,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
                c->rolloff = tvp->u.data;
                break;
        case DTV_DELIVERY_SYSTEM:
-               c->delivery_system = tvp->u.data;
+               r = set_delivery_system(fe, tvp->u.data);
                break;
        case DTV_VOLTAGE:
                c->voltage = tvp->u.data;
@@ -1551,6 +1725,7 @@ static int dvb_frontend_ioctl_properties(struct file *file,
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dvb_frontend *fe = dvbdev->priv;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int err = 0;
 
@@ -1594,7 +1769,6 @@ static int dvb_frontend_ioctl_properties(struct file *file,
 
        } else
        if(cmd == FE_GET_PROPERTY) {
-
                tvps = (struct dtv_properties __user *)parg;
 
                dprintk("%s() properties.num = %d\n", __func__, tvps->num);
@@ -1616,8 +1790,18 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                        goto out;
                }
 
+               /*
+                * Fills the cache out struct with the cache contents, plus
+                * the data retrieved from get_frontend, if the frontend
+                * is not idle. Otherwise, returns the cached content
+                */
+               if (fepriv->state != FESTATE_IDLE) {
+                       err = dtv_get_frontend(fe, NULL);
+                       if (err < 0)
+                               goto out;
+               }
                for (i = 0; i < tvps->num; i++) {
-                       err = dtv_property_process_get(fe, tvp + i, file);
+                       err = dtv_property_process_get(fe, c, tvp + i, file);
                        if (err < 0)
                                goto out;
                        (tvp + i)->result = err;
@@ -1636,12 +1820,121 @@ out:
        return err;
 }
 
+static int dtv_set_frontend(struct dvb_frontend *fe)
+{
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_tune_settings fetunesettings;
+       u32 rolloff = 0;
+
+       if (dvb_frontend_check_parameters(fe) < 0)
+               return -EINVAL;
+
+       /*
+        * Be sure that the bandwidth will be filled for all
+        * non-satellite systems, as tuners need to know what
+        * low pass/Nyquist half filter should be applied, in
+        * order to avoid inter-channel noise.
+        *
+        * ISDB-T and DVB-T/T2 already sets bandwidth.
+        * ATSC and DVB-C don't set, so, the core should fill it.
+        *
+        * On DVB-C Annex A and C, the bandwidth is a function of
+        * the roll-off and symbol rate. Annex B defines different
+        * roll-off factors depending on the modulation. Fortunately,
+        * Annex B is only used with 6MHz, so there's no need to
+        * calculate it.
+        *
+        * While not officially supported, a side effect of handling it at
+        * the cache level is that a program could retrieve the bandwidth
+        * via DTV_BANDWIDTH_HZ, which may be useful for test programs.
+        */
+       switch (c->delivery_system) {
+       case SYS_ATSC:
+       case SYS_DVBC_ANNEX_B:
+               c->bandwidth_hz = 6000000;
+               break;
+       case SYS_DVBC_ANNEX_A:
+               rolloff = 115;
+               break;
+       case SYS_DVBC_ANNEX_C:
+               rolloff = 113;
+               break;
+       default:
+               break;
+       }
+       if (rolloff)
+               c->bandwidth_hz = (c->symbol_rate * rolloff) / 100;
+
+       /* force auto frequency inversion if requested */
+       if (dvb_force_auto_inversion)
+               c->inversion = INVERSION_AUTO;
+
+       /*
+        * without hierarchical coding code_rate_LP is irrelevant,
+        * so we tolerate the otherwise invalid FEC_NONE setting
+        */
+       if (c->hierarchy == HIERARCHY_NONE && c->code_rate_LP == FEC_NONE)
+               c->code_rate_LP = FEC_AUTO;
+
+       /* get frontend-specific tuning settings */
+       memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
+       if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
+               fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
+               fepriv->max_drift = fetunesettings.max_drift;
+               fepriv->step_size = fetunesettings.step_size;
+       } else {
+               /* default values */
+               switch (c->delivery_system) {
+               case SYS_DVBC_ANNEX_A:
+               case SYS_DVBC_ANNEX_C:
+                       fepriv->min_delay = HZ / 20;
+                       fepriv->step_size = c->symbol_rate / 16000;
+                       fepriv->max_drift = c->symbol_rate / 2000;
+                       break;
+               case SYS_DVBT:
+               case SYS_DVBT2:
+               case SYS_ISDBT:
+               case SYS_DMBTH:
+                       fepriv->min_delay = HZ / 20;
+                       fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
+                       fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+                       break;
+               default:
+                       /*
+                        * FIXME: This sounds wrong! if freqency_stepsize is
+                        * defined by the frontend, why not use it???
+                        */
+                       fepriv->min_delay = HZ / 20;
+                       fepriv->step_size = 0; /* no zigzag */
+                       fepriv->max_drift = 0;
+                       break;
+               }
+       }
+       if (dvb_override_tune_delay > 0)
+               fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;
+
+       fepriv->state = FESTATE_RETUNE;
+
+       /* Request the search algorithm to search */
+       fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+
+       dvb_frontend_clear_events(fe);
+       dvb_frontend_add_event(fe, 0);
+       dvb_frontend_wakeup(fe);
+       fepriv->status = 0;
+
+       return 0;
+}
+
+
 static int dvb_frontend_ioctl_legacy(struct file *file,
                        unsigned int cmd, void *parg)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dvb_frontend *fe = dvbdev->priv;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int cb_err, err = -EOPNOTSUPP;
 
        if (fe->dvb->fe_ioctl_override) {
@@ -1658,9 +1951,43 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
        switch (cmd) {
        case FE_GET_INFO: {
                struct dvb_frontend_info* info = parg;
+
                memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
                dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max);
 
+               /*
+                * Associate the 4 delivery systems supported by DVBv3
+                * API with their DVBv5 counterpart. For the other standards,
+                * use the closest type, assuming that it would hopefully
+                * work with a DVBv3 application.
+                * It should be noticed that, on multi-frontend devices with
+                * different types (terrestrial and cable, for example),
+                * a pure DVBv3 application won't be able to use all delivery
+                * systems. Yet, changing the DVBv5 cache to the other delivery
+                * system should be enough for making it work.
+                */
+               switch (dvbv3_type(c->delivery_system)) {
+               case DVBV3_QPSK:
+                       info->type = FE_QPSK;
+                       break;
+               case DVBV3_ATSC:
+                       info->type = FE_ATSC;
+                       break;
+               case DVBV3_QAM:
+                       info->type = FE_QAM;
+                       break;
+               case DVBV3_OFDM:
+                       info->type = FE_OFDM;
+                       break;
+               default:
+                       printk(KERN_ERR
+                              "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
+                              __func__, c->delivery_system);
+                       fe->ops.info.type = FE_OFDM;
+               }
+               dprintk("current delivery system on cache: %d, V3 type: %d\n",
+                       c->delivery_system, fe->ops.info.type);
+
                /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
                 * do it, it is done for it. */
                info->caps |= FE_CAN_INVERSION_AUTO;
@@ -1819,108 +2146,22 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
                        err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
                break;
 
-       case FE_SET_FRONTEND: {
-               struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-               struct dvb_frontend_tune_settings fetunesettings;
-
-               if (c->state == DTV_TUNE) {
-                       if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) {
-                               err = -EINVAL;
-                               break;
-                       }
-               } else {
-                       if (dvb_frontend_check_parameters(fe, parg) < 0) {
-                               err = -EINVAL;
-                               break;
-                       }
-
-                       memcpy (&fepriv->parameters_in, parg,
-                               sizeof (struct dvb_frontend_parameters));
-                       dtv_property_cache_init(fe, c);
-                       dtv_property_cache_sync(fe, c, &fepriv->parameters_in);
-               }
-
-               /*
-                * Initialize output parameters to match the values given by
-                * the user. FE_SET_FRONTEND triggers an initial frontend event
-                * with status = 0, which copies output parameters to userspace.
-                */
-               fepriv->parameters_out = fepriv->parameters_in;
-
-               memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
-               memcpy(&fetunesettings.parameters, parg,
-                      sizeof (struct dvb_frontend_parameters));
-
-               /* force auto frequency inversion if requested */
-               if (dvb_force_auto_inversion) {
-                       fepriv->parameters_in.inversion = INVERSION_AUTO;
-                       fetunesettings.parameters.inversion = INVERSION_AUTO;
-               }
-               if (fe->ops.info.type == FE_OFDM) {
-                       /* without hierarchical coding code_rate_LP is irrelevant,
-                        * so we tolerate the otherwise invalid FEC_NONE setting */
-                       if (fepriv->parameters_in.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
-                           fepriv->parameters_in.u.ofdm.code_rate_LP == FEC_NONE)
-                               fepriv->parameters_in.u.ofdm.code_rate_LP = FEC_AUTO;
-               }
-
-               /* get frontend-specific tuning settings */
-               if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
-                       fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
-                       fepriv->max_drift = fetunesettings.max_drift;
-                       fepriv->step_size = fetunesettings.step_size;
-               } else {
-                       /* default values */
-                       switch(fe->ops.info.type) {
-                       case FE_QPSK:
-                               fepriv->min_delay = HZ/20;
-                               fepriv->step_size = fepriv->parameters_in.u.qpsk.symbol_rate / 16000;
-                               fepriv->max_drift = fepriv->parameters_in.u.qpsk.symbol_rate / 2000;
-                               break;
-
-                       case FE_QAM:
-                               fepriv->min_delay = HZ/20;
-                               fepriv->step_size = 0; /* no zigzag */
-                               fepriv->max_drift = 0;
-                               break;
-
-                       case FE_OFDM:
-                               fepriv->min_delay = HZ/20;
-                               fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
-                               fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
-                               break;
-                       case FE_ATSC:
-                               fepriv->min_delay = HZ/20;
-                               fepriv->step_size = 0;
-                               fepriv->max_drift = 0;
-                               break;
-                       }
-               }
-               if (dvb_override_tune_delay > 0)
-                       fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;
-
-               fepriv->state = FESTATE_RETUNE;
-
-               /* Request the search algorithm to search */
-               fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+       case FE_SET_FRONTEND:
+               err = set_delivery_system(fe, SYS_UNDEFINED);
+               if (err)
+                       break;
 
-               dvb_frontend_clear_events(fe);
-               dvb_frontend_add_event(fe, 0);
-               dvb_frontend_wakeup(fe);
-               fepriv->status = 0;
-               err = 0;
+               err = dtv_property_cache_sync(fe, c, parg);
+               if (err)
+                       break;
+               err = dtv_set_frontend(fe);
                break;
-       }
-
        case FE_GET_EVENT:
                err = dvb_frontend_get_event (fe, parg, file->f_flags);
                break;
 
        case FE_GET_FRONTEND:
-               if (fe->ops.get_frontend) {
-                       err = fe->ops.get_frontend(fe, &fepriv->parameters_out);
-                       memcpy(parg, &fepriv->parameters_out, sizeof(struct dvb_frontend_parameters));
-               }
+               err = dtv_get_frontend(fe, parg);
                break;
 
        case FE_SET_FRONTEND_TUNE_MODE:
@@ -2061,12 +2302,15 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
 
        dprintk ("%s\n", __func__);
 
-       if ((file->f_flags & O_ACCMODE) != O_RDONLY)
+       if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
                fepriv->release_jiffies = jiffies;
+               mb();
+       }
 
        ret = dvb_generic_release (inode, file);
 
        if (dvbdev->users == -1) {
+               wake_up(&fepriv->wait_queue);
                if (fepriv->exit != DVB_FE_NO_EXIT) {
                        fops_put(file->f_op);
                        file->f_op = NULL;
@@ -2127,6 +2371,14 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
        dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
                             fe, DVB_DEVICE_FRONTEND);
 
+       /*
+        * Initialize the cache to the proper values according with the
+        * first supported delivery system (ops->delsys[0])
+        */
+
+        fe->dtv_property_cache.delivery_system = fe->ops.delsys[0];
+       dvb_frontend_clear_cache(fe);
+
        mutex_unlock(&frontend_mutex);
        return 0;
 }
index 67bbfa728016f72ef600bd683d84ef422930362e..d63a8215fe0315fa893902206a64f99303b9fb77 100644 (file)
 
 #include "dvbdev.h"
 
+/*
+ * Maximum number of Delivery systems per frontend. It
+ * should be smaller or equal to 32
+ */
+#define MAX_DELSYS     8
+
 struct dvb_frontend_tune_settings {
        int min_delay_ms;
        int step_size;
        int max_drift;
-       struct dvb_frontend_parameters parameters;
 };
 
 struct dvb_frontend;
@@ -198,11 +203,11 @@ struct dvb_tuner_ops {
        int (*sleep)(struct dvb_frontend *fe);
 
        /** This is for simple PLLs - set all parameters in one go. */
-       int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+       int (*set_params)(struct dvb_frontend *fe);
        int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
 
        /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
-       int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
+       int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
 
        /** This is to allow setting tuner-specific configs */
        int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
@@ -250,10 +255,14 @@ struct analog_demod_ops {
        int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
 };
 
+struct dtv_frontend_properties;
+
 struct dvb_frontend_ops {
 
        struct dvb_frontend_info info;
 
+       u8 delsys[MAX_DELSYS];
+
        void (*release)(struct dvb_frontend* fe);
        void (*release_sec)(struct dvb_frontend* fe);
 
@@ -264,7 +273,7 @@ struct dvb_frontend_ops {
 
        /* if this is set, it overrides the default swzigzag */
        int (*tune)(struct dvb_frontend* fe,
-                   struct dvb_frontend_parameters* params,
+                   bool re_tune,
                    unsigned int mode_flags,
                    unsigned int *delay,
                    fe_status_t *status);
@@ -272,10 +281,10 @@ struct dvb_frontend_ops {
        enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
 
        /* these two are only used for the swzigzag code */
-       int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+       int (*set_frontend)(struct dvb_frontend *fe);
        int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
 
-       int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+       int (*get_frontend)(struct dvb_frontend *fe);
 
        int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
        int (*read_ber)(struct dvb_frontend* fe, u32* ber);
@@ -297,8 +306,7 @@ struct dvb_frontend_ops {
        /* These callbacks are for devices that implement their own
         * tuning algorithms, rather than a simple swzigzag
         */
-       enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
-       int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+       enum dvbfe_search (*search)(struct dvb_frontend *fe);
 
        struct dvb_tuner_ops tuner_ops;
        struct analog_demod_ops analog_ops;
@@ -307,6 +315,7 @@ struct dvb_frontend_ops {
        int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
 };
 
+#ifdef __DVB_CORE__
 #define MAX_EVENT 8
 
 struct dvb_fe_events {
@@ -317,6 +326,7 @@ struct dvb_fe_events {
        wait_queue_head_t         wait_queue;
        struct mutex              mtx;
 };
+#endif
 
 struct dtv_frontend_properties {
 
@@ -374,6 +384,7 @@ struct dvb_frontend {
        void *analog_demod_priv;
        struct dtv_frontend_properties dtv_property_cache;
 #define DVB_FRONTEND_COMPONENT_TUNER 0
+#define DVB_FRONTEND_COMPONENT_DEMOD 1
        int (*callback)(void *adapter_priv, int component, int cmd, int arg);
        int id;
 };
index 93d9869e0f15f3ecd10588a9bd981ab7a6ba8dfc..8766ce8c354dd908e1fbb9a493942e8669fe4259 100644 (file)
@@ -1510,9 +1510,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
        for (i=0; i<DVB_NET_DEVICES_MAX; i++)
                dvbnet->state[i] = 0;
 
-       dvb_register_device (adap, &dvbnet->dvbdev, &dvbdev_net,
+       return dvb_register_device(adap, &dvbnet->dvbdev, &dvbdev_net,
                             dvbnet, DVB_DEVICE_NET);
-
-       return 0;
 }
 EXPORT_SYMBOL(dvb_net_init);
index 58257165761e1b016a58b30019a9388d395400b2..9f203c6767a672baf3405d6c6751a39e4e96fed8 100644 (file)
@@ -311,6 +311,7 @@ config DVB_USB_ANYSEE
        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.
@@ -340,7 +341,7 @@ config DVB_USB_AF9015
 
 config DVB_USB_CE6230
        tristate "Intel CE6230 DVB-T USB2.0 support"
-       depends on DVB_USB && EXPERIMENTAL
+       depends on DVB_USB
        select DVB_ZL10353
        select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
        help
@@ -354,7 +355,7 @@ config DVB_USB_FRIIO
 
 config DVB_USB_EC168
        tristate "E3C EC168 DVB-T USB2.0 support"
-       depends on DVB_USB && EXPERIMENTAL
+       depends on DVB_USB
        select DVB_EC100
        select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
        help
index 3263e9749d09dfd610e467da5a583f84c26dc2d1..740f3f496f12c171bfe19564eafaa69fdfa6f40d 100644 (file)
@@ -303,7 +303,7 @@ static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe,
                return -EINVAL;
        }
 
-       /* read constellation mode */
+       /* read modulation mode */
        ret =
            af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
                                      reg_tpsd_const_pos, reg_tpsd_const_len,
@@ -321,7 +321,7 @@ static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe,
                bits = 6;
                break;
        default:
-               err("invalid constellation mode");
+               err("invalid modulation mode");
                return -EINVAL;
        }
        *pre_bit_count = super_frame_count * 68 * 4 * x * bits;
@@ -533,13 +533,13 @@ static int af9005_fe_read_signal_strength(struct dvb_frontend *fe,
 
 static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr)
 {
-       /* the snr can be derived from the ber and the constellation
+       /* the snr can be derived from the ber and the modulation
           but I don't think this kind of complex calculations belong
           in the driver. I may be wrong.... */
        return -ENOSYS;
 }
 
-static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
+static int af9005_fe_program_cfoe(struct dvb_usb_device *d, u32 bw)
 {
        u8 temp0, temp1, temp2, temp3, buf[4];
        int ret;
@@ -551,7 +551,7 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
        u32 NS_coeff2_8k;
 
        switch (bw) {
-       case BANDWIDTH_6_MHZ:
+       case 6000000:
                NS_coeff1_2048Nu = 0x2ADB6DC;
                NS_coeff1_8191Nu = 0xAB7313;
                NS_coeff1_8192Nu = 0xAB6DB7;
@@ -560,7 +560,7 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
                NS_coeff2_8k = 0x55B6DC;
                break;
 
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                NS_coeff1_2048Nu = 0x3200001;
                NS_coeff1_8191Nu = 0xC80640;
                NS_coeff1_8192Nu = 0xC80000;
@@ -569,7 +569,7 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
                NS_coeff2_8k = 0x640000;
                break;
 
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
                NS_coeff1_2048Nu = 0x3924926;
                NS_coeff1_8191Nu = 0xE4996E;
                NS_coeff1_8192Nu = 0xE49249;
@@ -773,17 +773,17 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
 
 }
 
-static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw)
+static int af9005_fe_select_bw(struct dvb_usb_device *d, u32 bw)
 {
        u8 temp;
        switch (bw) {
-       case BANDWIDTH_6_MHZ:
+       case 6000000:
                temp = 0;
                break;
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                temp = 1;
                break;
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
                temp = 2;
                break;
        default:
@@ -930,10 +930,11 @@ static int af9005_fe_init(struct dvb_frontend *fe)
 
        /* init other parameters: program cfoe and select bandwidth */
        deb_info("program cfoe\n");
-       if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ)))
+       ret = af9005_fe_program_cfoe(state->d, 6000000);
+       if (ret)
                return ret;
-       /* set read-update bit for constellation */
-       deb_info("set read-update bit for constellation\n");
+       /* set read-update bit for modulation */
+       deb_info("set read-update bit for modulation\n");
        if ((ret =
             af9005_write_register_bits(state->d, xd_p_reg_feq_read_update,
                                        reg_feq_read_update_pos,
@@ -943,8 +944,8 @@ static int af9005_fe_init(struct dvb_frontend *fe)
        /* sample code has a set MPEG TS code here
           but sniffing reveals that it doesn't do it */
 
-       /* set read-update bit to 1 for DCA constellation */
-       deb_info("set read-update bit 1 for DCA constellation\n");
+       /* set read-update bit to 1 for DCA modulation */
+       deb_info("set read-update bit 1 for DCA modulation\n");
        if ((ret =
             af9005_write_register_bits(state->d, xd_p_reg_dca_read_update,
                                        reg_dca_read_update_pos,
@@ -1099,15 +1100,15 @@ static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
        return 0;
 }
 
-static int af9005_fe_set_frontend(struct dvb_frontend *fe,
-                                 struct dvb_frontend_parameters *fep)
+static int af9005_fe_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct af9005_fe_state *state = fe->demodulator_priv;
        int ret;
        u8 temp, temp0, temp1, temp2;
 
        deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency,
-                fep->u.ofdm.bandwidth);
+                fep->bandwidth_hz);
        if (fe->ops.tuner_ops.release == NULL) {
                err("Tuner not attached");
                return -ENODEV;
@@ -1167,10 +1168,10 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe,
 
        /* select bandwidth */
        deb_info("select bandwidth");
-       ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth);
+       ret = af9005_fe_select_bw(state->d, fep->bandwidth_hz);
        if (ret)
                return ret;
-       ret = af9005_fe_program_cfoe(state->d, fep->u.ofdm.bandwidth);
+       ret = af9005_fe_program_cfoe(state->d, fep->bandwidth_hz);
        if (ret)
                return ret;
 
@@ -1189,7 +1190,7 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe,
                return ret;
        /* set tuner */
        deb_info("set tuner\n");
-       ret = fe->ops.tuner_ops.set_params(fe, fep);
+       ret = fe->ops.tuner_ops.set_params(fe);
        if (ret)
                return ret;
 
@@ -1225,9 +1226,9 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe,
        return 0;
 }
 
-static int af9005_fe_get_frontend(struct dvb_frontend *fe,
-                                 struct dvb_frontend_parameters *fep)
+static int af9005_fe_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct af9005_fe_state *state = fe->demodulator_priv;
        int ret;
        u8 temp;
@@ -1239,19 +1240,19 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
                                      &temp);
        if (ret)
                return ret;
-       deb_info("===== fe_get_frontend ==============\n");
+       deb_info("===== fe_get_frontend_legacy = =============\n");
        deb_info("CONSTELLATION ");
        switch (temp) {
        case 0:
-               fep->u.ofdm.constellation = QPSK;
+               fep->modulation = QPSK;
                deb_info("QPSK\n");
                break;
        case 1:
-               fep->u.ofdm.constellation = QAM_16;
+               fep->modulation = QAM_16;
                deb_info("QAM_16\n");
                break;
        case 2:
-               fep->u.ofdm.constellation = QAM_64;
+               fep->modulation = QAM_64;
                deb_info("QAM_64\n");
                break;
        }
@@ -1266,19 +1267,19 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
        deb_info("HIERARCHY ");
        switch (temp) {
        case 0:
-               fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+               fep->hierarchy = HIERARCHY_NONE;
                deb_info("NONE\n");
                break;
        case 1:
-               fep->u.ofdm.hierarchy_information = HIERARCHY_1;
+               fep->hierarchy = HIERARCHY_1;
                deb_info("1\n");
                break;
        case 2:
-               fep->u.ofdm.hierarchy_information = HIERARCHY_2;
+               fep->hierarchy = HIERARCHY_2;
                deb_info("2\n");
                break;
        case 3:
-               fep->u.ofdm.hierarchy_information = HIERARCHY_4;
+               fep->hierarchy = HIERARCHY_4;
                deb_info("4\n");
                break;
        }
@@ -1302,23 +1303,23 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
        deb_info("CODERATE HP ");
        switch (temp) {
        case 0:
-               fep->u.ofdm.code_rate_HP = FEC_1_2;
+               fep->code_rate_HP = FEC_1_2;
                deb_info("FEC_1_2\n");
                break;
        case 1:
-               fep->u.ofdm.code_rate_HP = FEC_2_3;
+               fep->code_rate_HP = FEC_2_3;
                deb_info("FEC_2_3\n");
                break;
        case 2:
-               fep->u.ofdm.code_rate_HP = FEC_3_4;
+               fep->code_rate_HP = FEC_3_4;
                deb_info("FEC_3_4\n");
                break;
        case 3:
-               fep->u.ofdm.code_rate_HP = FEC_5_6;
+               fep->code_rate_HP = FEC_5_6;
                deb_info("FEC_5_6\n");
                break;
        case 4:
-               fep->u.ofdm.code_rate_HP = FEC_7_8;
+               fep->code_rate_HP = FEC_7_8;
                deb_info("FEC_7_8\n");
                break;
        }
@@ -1333,23 +1334,23 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
        deb_info("CODERATE LP ");
        switch (temp) {
        case 0:
-               fep->u.ofdm.code_rate_LP = FEC_1_2;
+               fep->code_rate_LP = FEC_1_2;
                deb_info("FEC_1_2\n");
                break;
        case 1:
-               fep->u.ofdm.code_rate_LP = FEC_2_3;
+               fep->code_rate_LP = FEC_2_3;
                deb_info("FEC_2_3\n");
                break;
        case 2:
-               fep->u.ofdm.code_rate_LP = FEC_3_4;
+               fep->code_rate_LP = FEC_3_4;
                deb_info("FEC_3_4\n");
                break;
        case 3:
-               fep->u.ofdm.code_rate_LP = FEC_5_6;
+               fep->code_rate_LP = FEC_5_6;
                deb_info("FEC_5_6\n");
                break;
        case 4:
-               fep->u.ofdm.code_rate_LP = FEC_7_8;
+               fep->code_rate_LP = FEC_7_8;
                deb_info("FEC_7_8\n");
                break;
        }
@@ -1363,19 +1364,19 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
        deb_info("GUARD INTERVAL ");
        switch (temp) {
        case 0:
-               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+               fep->guard_interval = GUARD_INTERVAL_1_32;
                deb_info("1_32\n");
                break;
        case 1:
-               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+               fep->guard_interval = GUARD_INTERVAL_1_16;
                deb_info("1_16\n");
                break;
        case 2:
-               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+               fep->guard_interval = GUARD_INTERVAL_1_8;
                deb_info("1_8\n");
                break;
        case 3:
-               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+               fep->guard_interval = GUARD_INTERVAL_1_4;
                deb_info("1_4\n");
                break;
        }
@@ -1390,11 +1391,11 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
        deb_info("TRANSMISSION MODE ");
        switch (temp) {
        case 0:
-               fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+               fep->transmission_mode = TRANSMISSION_MODE_2K;
                deb_info("2K\n");
                break;
        case 1:
-               fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+               fep->transmission_mode = TRANSMISSION_MODE_8K;
                deb_info("8K\n");
                break;
        }
@@ -1406,15 +1407,15 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe,
        deb_info("BANDWIDTH ");
        switch (temp) {
        case 0:
-               fep->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+               fep->bandwidth_hz = 6000000;
                deb_info("6\n");
                break;
        case 1:
-               fep->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+               fep->bandwidth_hz = 7000000;
                deb_info("7\n");
                break;
        case 2:
-               fep->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+               fep->bandwidth_hz = 8000000;
                deb_info("8\n");
                break;
        }
@@ -1454,9 +1455,9 @@ struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d)
 }
 
 static struct dvb_frontend_ops af9005_fe_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                 .name = "AF9005 USB DVB-T",
-                .type = FE_OFDM,
                 .frequency_min = 44250000,
                 .frequency_max = 867250000,
                 .frequency_stepsize = 250000,
index bd51a764351b8483878e04f070206c878c5fc575..af176b6ce738e78d4dc366ae0d56597f833f4e59 100644 (file)
@@ -30,7 +30,7 @@ MODULE_PARM_DESC(debug,
                 "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
                 DVB_USB_DEBUG_STATUS);
 /* enable obnoxious led */
-int dvb_usb_af9005_led = 1;
+bool dvb_usb_af9005_led = 1;
 module_param_named(led, dvb_usb_af9005_led, bool, 0644);
 MODULE_PARM_DESC(led, "enable led (default: 1).");
 
@@ -977,11 +977,20 @@ static int af9005_usb_probe(struct usb_interface *intf,
                                   THIS_MODULE, NULL, adapter_nr);
 }
 
+enum af9005_usb_table_entry {
+       AFATECH_AF9005,
+       TERRATEC_AF9005,
+       ANSONIC_AF9005,
+};
+
 static struct usb_device_id af9005_usb_table[] = {
-       {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)},
-       {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)},
-       {USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)},
-       {0},
+       [AFATECH_AF9005] = {USB_DEVICE(USB_VID_AFATECH,
+                               USB_PID_AFATECH_AF9005)},
+       [TERRATEC_AF9005] = {USB_DEVICE(USB_VID_TERRATEC,
+                               USB_PID_TERRATEC_CINERGY_T_USB_XE)},
+       [ANSONIC_AF9005] = {USB_DEVICE(USB_VID_ANSONIC,
+                               USB_PID_ANSONIC_DVBT_USB)},
+       { }
 };
 
 MODULE_DEVICE_TABLE(usb, af9005_usb_table);
@@ -1041,15 +1050,15 @@ static struct dvb_usb_device_properties af9005_properties = {
        .num_device_descs = 3,
        .devices = {
                    {.name = "Afatech DVB-T USB1.1 stick",
-                    .cold_ids = {&af9005_usb_table[0], NULL},
+                    .cold_ids = {&af9005_usb_table[AFATECH_AF9005], NULL},
                     .warm_ids = {NULL},
                     },
                    {.name = "TerraTec Cinergy T USB XE",
-                    .cold_ids = {&af9005_usb_table[1], NULL},
+                    .cold_ids = {&af9005_usb_table[TERRATEC_AF9005], NULL},
                     .warm_ids = {NULL},
                     },
                    {.name = "Ansonic DVB-T USB1.1 stick",
-                    .cold_ids = {&af9005_usb_table[2], NULL},
+                    .cold_ids = {&af9005_usb_table[ANSONIC_AF9005], NULL},
                     .warm_ids = {NULL},
                     },
                    {NULL},
index c71c77bd7f4bd5db129fae67f8c273d76e02f1cf..6a2bf3de845668c162cf679fdab5eaaf775005c0 100644 (file)
@@ -35,7 +35,7 @@ extern int dvb_usb_af9005_debug;
 #define deb_i2c(args...)  dprintk(dvb_usb_af9005_debug,0x10,args)
 #define deb_fw(args...)   dprintk(dvb_usb_af9005_debug,0x20,args)
 
-extern int dvb_usb_af9005_led;
+extern bool dvb_usb_af9005_led;
 
 /* firmware */
 #define FW_BULKOUT_SIZE 250
index 56cbd3636c318aa327e96bf8b1397131ac70d370..282a43d648df1817ec0d86ef4adf995706af52cf 100644 (file)
@@ -50,14 +50,14 @@ static int af9015_properties_count = ARRAY_SIZE(af9015_properties);
 
 static struct af9013_config af9015_af9013_config[] = {
        {
-               .demod_address = AF9015_I2C_DEMOD,
-               .output_mode = AF9013_OUTPUT_MODE_USB,
+               .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,
 
        }, {
-               .output_mode = AF9013_OUTPUT_MODE_SERIAL,
+               .ts_mode = AF9013_TS_SERIAL,
                .api_version = { 0, 1, 9, 0 },
                .gpio[0] = AF9013_GPIO_TUNER_ON,
                .gpio[1] = AF9013_GPIO_LO,
@@ -216,8 +216,8 @@ static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
 {
        struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val};
 
-       if (addr == af9015_af9013_config[0].demod_address ||
-           addr == af9015_af9013_config[1].demod_address)
+       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);
@@ -228,8 +228,8 @@ static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
 {
        struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val};
 
-       if (addr == af9015_af9013_config[0].demod_address ||
-           addr == af9015_af9013_config[1].demod_address)
+       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);
@@ -271,8 +271,8 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
                return -EAGAIN;
 
        while (i < num) {
-               if (msg[i].addr == af9015_af9013_config[0].demod_address ||
-                   msg[i].addr == af9015_af9013_config[1].demod_address) {
+               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];
@@ -288,8 +288,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
                                ret = -EOPNOTSUPP;
                                goto error;
                        }
-                       if (msg[i].addr ==
-                               af9015_af9013_config[0].demod_address)
+                       if (msg[i].addr == af9015_af9013_config[0].i2c_addr)
                                req.cmd = READ_MEMORY;
                        else
                                req.cmd = READ_I2C;
@@ -307,7 +306,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
                                goto error;
                        }
                        if (msg[i].addr ==
-                               af9015_af9013_config[0].demod_address) {
+                               af9015_af9013_config[0].i2c_addr) {
                                ret = -EINVAL;
                                goto error;
                        }
@@ -325,8 +324,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
                                ret = -EOPNOTSUPP;
                                goto error;
                        }
-                       if (msg[i].addr ==
-                               af9015_af9013_config[0].demod_address)
+                       if (msg[i].addr == af9015_af9013_config[0].i2c_addr)
                                req.cmd = WRITE_MEMORY;
                        else
                                req.cmd = WRITE_I2C;
@@ -508,7 +506,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d)
        msleep(100);
 
        ret = af9015_read_reg_i2c(d,
-               af9015_af9013_config[1].demod_address, 0x98be, &val);
+               af9015_af9013_config[1].i2c_addr, 0x98be, &val);
        if (ret)
                goto error;
        else
@@ -536,7 +534,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d)
                goto error;
 
        /* request boot firmware */
-       ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].demod_address,
+       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)
@@ -547,7 +545,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d)
 
                /* check firmware status */
                ret = af9015_read_reg_i2c(d,
-                       af9015_af9013_config[1].demod_address, 0x98be, &val);
+                       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)
@@ -840,7 +838,7 @@ static int af9015_read_config(struct usb_device *udev)
        if (ret)
                goto error;
 
-       deb_info("%s: IR mode:%d\n", __func__, val);
+       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;
@@ -854,7 +852,7 @@ static int af9015_read_config(struct usb_device *udev)
        if (ret)
                goto error;
        af9015_config.dual_mode = val;
-       deb_info("%s: TS mode:%d\n", __func__, af9015_config.dual_mode);
+       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 */
@@ -878,7 +876,7 @@ static int af9015_read_config(struct usb_device *udev)
                ret = af9015_rw_udev(udev, &req);
                if (ret)
                        goto error;
-               af9015_af9013_config[1].demod_address = val;
+               af9015_af9013_config[1].i2c_addr = val;
 
                /* enable 2nd adapter */
                for (i = 0; i < af9015_properties_count; i++)
@@ -900,34 +898,38 @@ static int af9015_read_config(struct usb_device *udev)
                        goto error;
                switch (val) {
                case 0:
-                       af9015_af9013_config[i].adc_clock = 28800;
+                       af9015_af9013_config[i].clock = 28800000;
                        break;
                case 1:
-                       af9015_af9013_config[i].adc_clock = 20480;
+                       af9015_af9013_config[i].clock = 20480000;
                        break;
                case 2:
-                       af9015_af9013_config[i].adc_clock = 28000;
+                       af9015_af9013_config[i].clock = 28000000;
                        break;
                case 3:
-                       af9015_af9013_config[i].adc_clock = 25000;
+                       af9015_af9013_config[i].clock = 25000000;
                        break;
                };
-               deb_info("%s: [%d] xtal:%d set adc_clock:%d\n", __func__, i,
-                       val, af9015_af9013_config[i].adc_clock);
+               deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i,
+                       val, af9015_af9013_config[i].clock);
 
-               /* tuner IF */
+               /* IF frequency */
                req.addr = AF9015_EEPROM_IF1H + offset;
                ret = af9015_rw_udev(udev, &req);
                if (ret)
                        goto error;
-               af9015_af9013_config[i].tuner_if = val << 8;
+
+               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].tuner_if += val;
-               deb_info("%s: [%d] IF1:%d\n", __func__, i,
-                       af9015_af9013_config[0].tuner_if);
+
+               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;
@@ -940,7 +942,7 @@ static int af9015_read_config(struct usb_device *udev)
                if (ret)
                        goto error;
                af9015_config.mt2060_if1[i] += val;
-               deb_info("%s: [%d] MT2060 IF1:%d\n", __func__, i,
+               deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i,
                        af9015_config.mt2060_if1[i]);
 
                /* tuner */
@@ -957,30 +959,30 @@ static int af9015_read_config(struct usb_device *udev)
                case AF9013_TUNER_TDA18271:
                case AF9013_TUNER_QT1010A:
                case AF9013_TUNER_TDA18218:
-                       af9015_af9013_config[i].rf_spec_inv = 1;
+                       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].rf_spec_inv = 0;
+                       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].rf_spec_inv = 1;
+                       af9015_af9013_config[i].spec_inv = 1;
                        break;
                default:
-                       warn("tuner id:%d not supported, please report!", val);
+                       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);
+               deb_info("%s: [%d] tuner id=%d\n", __func__, i, val);
        }
 
 error:
        if (ret)
-               err("eeprom read failed:%d", 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
@@ -998,7 +1000,7 @@ error:
                        af9015_properties[i].num_adapters = 1;
 
                /* set correct IF */
-               af9015_af9013_config[0].tuner_if = 4570;
+               af9015_af9013_config[0].if_frequency = 4570000;
        }
 
        return ret;
@@ -1093,9 +1095,79 @@ error:
        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;
+}
+
 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 */
@@ -1116,6 +1188,32 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
        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;
 }
 
@@ -1245,49 +1343,112 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
        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[] = {
-/*  0 */{USB_DEVICE(USB_VID_AFATECH,   USB_PID_AFATECH_AF9015_9015)},
-       {USB_DEVICE(USB_VID_AFATECH,   USB_PID_AFATECH_AF9015_9016)},
-       {USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_GOLD)},
-       {USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV71E)},
-       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_399U)},
-/*  5 */{USB_DEVICE(USB_VID_VISIONPLUS,
-               USB_PID_TINYTWIN)},
-       {USB_DEVICE(USB_VID_VISIONPLUS,
-               USB_PID_AZUREWAVE_AD_TU700)},
-       {USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)},
-       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_PC160_2T)},
-       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)},
-/* 10 */{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)},
-       {USB_DEVICE(USB_VID_MSI_2,     USB_PID_MSI_DIGIVOX_DUO)},
-       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)},
-       {USB_DEVICE(USB_VID_TELESTAR,  USB_PID_TELESTAR_STARSTICK_2)},
-       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
-/* 15 */{USB_DEVICE(USB_VID_MSI_2,     USB_PID_MSI_DIGI_VOX_MINI_III)},
-       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U)},
-       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_2)},
-       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_3)},
-       {USB_DEVICE(USB_VID_AFATECH,   USB_PID_TREKSTOR_DVBT)},
-/* 20 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
-       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)},
-       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_CONCEPTRONIC_CTVDIGRCU)},
-       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_MC810)},
-       {USB_DEVICE(USB_VID_KYE,       USB_PID_GENIUS_TVGO_DVB_T03)},
-/* 25 */{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_399U_2)},
-       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_PC160_T)},
-       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_SVEON_STV20)},
-       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_TINYTWIN_2)},
-       {USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV2000DS)},
-/* 30 */{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_UB383_T)},
-       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_4)},
-       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
-       {USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_T_STICK_RC)},
-       {USB_DEVICE(USB_VID_TERRATEC,
-               USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)},
-/* 35 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
-       {USB_DEVICE(USB_VID_GTEK,      USB_PID_TINYTWIN_3)},
-       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_SVEON_STV22)},
-       {0},
+       [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);
 
@@ -1362,68 +1523,104 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                .devices = {
                        {
                                .name = "Afatech AF9015 DVB-T USB2.0 stick",
-                               .cold_ids = {&af9015_usb_table[0],
-                                            &af9015_usb_table[1], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[AFATECH_9015],
+                                       &af9015_usb_table[AFATECH_9016],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "Leadtek WinFast DTV Dongle Gold",
-                               .cold_ids = {&af9015_usb_table[2], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[WINFAST_DTV_GOLD],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "Pinnacle PCTV 71e",
-                               .cold_ids = {&af9015_usb_table[3], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[PINNACLE_PCTV_71E],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "KWorld PlusTV Dual DVB-T Stick " \
                                        "(DVB-T 399U)",
-                               .cold_ids = {&af9015_usb_table[4],
-                                            &af9015_usb_table[25], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[KWORLD_PLUSTV_399U],
+                                       &af9015_usb_table[KWORLD_399U_2],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "DigitalNow TinyTwin DVB-T Receiver",
-                               .cold_ids = {&af9015_usb_table[5],
-                                            &af9015_usb_table[28],
-                                            &af9015_usb_table[36], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[TINYTWIN],
+                                       &af9015_usb_table[TINYTWIN_2],
+                                       &af9015_usb_table[TINYTWIN_3],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "TwinHan AzureWave AD-TU700(704J)",
-                               .cold_ids = {&af9015_usb_table[6], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[AZUREWAVE_TU700],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "TerraTec Cinergy T USB XE",
-                               .cold_ids = {&af9015_usb_table[7], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[TERRATEC_AF9015],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "KWorld PlusTV Dual DVB-T PCI " \
                                        "(DVB-T PC160-2T)",
-                               .cold_ids = {&af9015_usb_table[8], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[KWORLD_PLUSTV_PC160],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "AVerMedia AVerTV DVB-T Volar X",
-                               .cold_ids = {&af9015_usb_table[9], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[AVERTV_VOLAR_X],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "TerraTec Cinergy T Stick RC",
-                               .cold_ids = {&af9015_usb_table[33], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[CINERGY_T_STICK_RC],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "TerraTec Cinergy T Stick Dual RC",
-                               .cold_ids = {&af9015_usb_table[34], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[CINERGY_T_DUAL_RC],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "AverMedia AVerTV Red HD+ (A850T)",
-                               .cold_ids = {&af9015_usb_table[35], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[AVERTV_A850T],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                }
@@ -1496,57 +1693,87 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                .devices = {
                        {
                                .name = "Xtensions XD-380",
-                               .cold_ids = {&af9015_usb_table[10], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[XTENSIONS_380U],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "MSI DIGIVOX Duo",
-                               .cold_ids = {&af9015_usb_table[11], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[MSI_DIGIVOX_DUO],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "Fujitsu-Siemens Slim Mobile USB DVB-T",
-                               .cold_ids = {&af9015_usb_table[12], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[AVERTV_VOLAR_X_REV2],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "Telestar Starstick 2",
-                               .cold_ids = {&af9015_usb_table[13], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[TELESTAR_STARSTICK_2],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "AVerMedia A309",
-                               .cold_ids = {&af9015_usb_table[14], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[AVERMEDIA_A309_USB],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "MSI Digi VOX mini III",
-                               .cold_ids = {&af9015_usb_table[15], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[MSI_DIGIVOX_MINI_III],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "KWorld USB DVB-T TV Stick II " \
                                        "(VS-DVB-T 395U)",
-                               .cold_ids = {&af9015_usb_table[16],
-                                            &af9015_usb_table[17],
-                                            &af9015_usb_table[18],
-                                            &af9015_usb_table[31], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[KWORLD_E396],
+                                       &af9015_usb_table[KWORLD_E39B],
+                                       &af9015_usb_table[KWORLD_E395],
+                                       &af9015_usb_table[KWORLD_E39A],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "TrekStor DVB-T USB Stick",
-                               .cold_ids = {&af9015_usb_table[19], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[TREKSTOR_DVBT],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "AverMedia AVerTV Volar Black HD " \
                                        "(A850)",
-                               .cold_ids = {&af9015_usb_table[20], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[AVERTV_A850],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "Sveon STV22 Dual USB DVB-T Tuner HDTV",
-                               .cold_ids = {&af9015_usb_table[37], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[SVEON_STV22],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                }
@@ -1619,50 +1846,77 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                .devices = {
                        {
                                .name = "AverMedia AVerTV Volar GPS 805 (A805)",
-                               .cold_ids = {&af9015_usb_table[21], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[AVERTV_A805],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \
                                        "V3.0",
-                               .cold_ids = {&af9015_usb_table[22], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[CONCEPTRONIC_CTVDIGRCU],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "KWorld Digial MC-810",
-                               .cold_ids = {&af9015_usb_table[23], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[KWORLD_MC810],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "Genius TVGo DVB-T03",
-                               .cold_ids = {&af9015_usb_table[24], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[GENIUS_TVGO_DVB_T03],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "KWorld PlusTV DVB-T PCI Pro Card " \
                                        "(DVB-T PC160-T)",
-                               .cold_ids = {&af9015_usb_table[26], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[KWORLD_PC160_T],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "Sveon STV20 Tuner USB DVB-T HDTV",
-                               .cold_ids = {&af9015_usb_table[27], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[SVEON_STV20],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "Leadtek WinFast DTV2000DS",
-                               .cold_ids = {&af9015_usb_table[29], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[WINFAST_DTV2000DS],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "KWorld USB DVB-T Stick Mobile " \
                                        "(UB383-T)",
-                               .cold_ids = {&af9015_usb_table[30], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[KWORLD_UB383_T],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                        {
                                .name = "AverMedia AVerTV Volar M (A815Mac)",
-                               .cold_ids = {&af9015_usb_table[32], NULL},
+                               .cold_ids = {
+                                       &af9015_usb_table[AVERMEDIA_A815M],
+                                       NULL
+                               },
                                .warm_ids = {NULL},
                        },
                }
index 6252ea6c19042b75a92e6aee88b3d9ec258f24da..f619063fa72f6a03f663da283ce91d1e7d3b6623 100644 (file)
@@ -102,6 +102,12 @@ struct af9015_state {
        u8 rc_repeat;
        u32 rc_keycode;
        u8 rc_last[4];
+
+       /* for demod callback override */
+       int (*set_frontend[2]) (struct dvb_frontend *fe);
+       int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status);
+       int (*init[2]) (struct dvb_frontend *fe);
+       int (*sleep[2]) (struct dvb_frontend *fe);
 };
 
 struct af9015_config {
index b39f14f85e7163fb8fa7948c4c6c1c9b8e4e2770..1455e2644ab5e4e08a0a5324a0d3e873b9941256 100644 (file)
@@ -41,6 +41,7 @@
 #include "stv0900.h"
 #include "stv6110.h"
 #include "isl6423.h"
+#include "cxd2820r.h"
 
 /* debug */
 static int dvb_usb_anysee_debug;
@@ -66,10 +67,12 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
        if (mutex_lock_interruptible(&anysee_usb_mutex) < 0)
                return -EAGAIN;
 
+       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);
-
        if (!ret) {
                /* receive 2nd answer */
                ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
@@ -79,7 +82,10 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
                        err("%s: recv bulk message failed: %d", __func__, ret);
                else {
                        deb_xfer("<<< ");
-                       debug_dump(buf, act_len, deb_xfer);
+                       debug_dump(buf, rlen, deb_xfer);
+
+                       if (buf[63] != 0x4f)
+                               deb_info("%s: cmd failed\n", __func__);
                }
        }
 
@@ -129,6 +135,29 @@ static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
        return anysee_write_reg(d, reg, val);
 }
 
+/* read single register with mask */
+static int anysee_rd_reg_mask(struct dvb_usb_device *d, u16 reg, u8 *val,
+       u8 mask)
+{
+       int ret, i;
+       u8 tmp;
+
+       ret = anysee_read_reg(d, reg, &tmp);
+       if (ret)
+               return ret;
+
+       tmp &= mask;
+
+       /* find position of the first bit */
+       for (i = 0; i < 8; i++) {
+               if ((mask >> i) & 0x01)
+                       break;
+       }
+       *val = tmp >> i;
+
+       return 0;
+}
+
 static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
 {
        u8 buf[] = {CMD_GET_HW_INFO};
@@ -156,22 +185,6 @@ static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff)
        return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
 }
 
-static int anysee_init(struct dvb_usb_device *d)
-{
-       int ret;
-       /* LED light */
-       ret = anysee_led_ctrl(d, 0x01, 0x03);
-       if (ret)
-               return ret;
-
-       /* enable IR */
-       ret = anysee_ir_ctrl(d, 1);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
 /* I2C */
 static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
        int num)
@@ -297,7 +310,7 @@ static struct tda10023_config anysee_tda10023_tda18212_config = {
        .pll_m  = 12,
        .pll_p  = 3,
        .pll_n  = 1,
-       .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
+       .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B,
        .deltaf = 0xba02,
 };
 
@@ -309,6 +322,17 @@ static struct tda18212_config anysee_tda18212_config = {
        .if_dvbc = 5000,
 };
 
+static struct tda18212_config anysee_tda18212_config2 = {
+       .i2c_address = 0x60 /* (0xc0 >> 1) */,
+       .if_dvbt_6 = 3550,
+       .if_dvbt_7 = 3700,
+       .if_dvbt_8 = 4150,
+       .if_dvbt2_6 = 3250,
+       .if_dvbt2_7 = 4000,
+       .if_dvbt2_8 = 4000,
+       .if_dvbc = 5000,
+};
+
 static struct cx24116_config anysee_cx24116_config = {
        .demod_address = (0xaa >> 1),
        .mpg_clk_pos_pol = 0x00,
@@ -339,6 +363,11 @@ static struct isl6423_config anysee_isl6423_config = {
        .addr = (0x10 >> 1),
 };
 
+static struct cxd2820r_config anysee_cxd2820r_config = {
+       .i2c_address = 0x6d, /* (0xda >> 1) */
+       .ts_mode = 0x38,
+};
+
 /*
  * New USB device strings: Mfr=1, Product=2, SerialNumber=0
  * Manufacturer: AMT.CO.KR
@@ -421,6 +450,14 @@ static struct isl6423_config anysee_isl6423_config = {
  * IOA[7] TS 1=enabled
  * IOE[5] STV0903 1=enabled
  *
+ * E7 T2C VID=1c73 PID=861f HW=20 FW=0.1 AMTCI=0.5 "anysee-E7T2C(LP)"
+ * PCB: 508T2C (rev0.3)
+ * parts: DNOQ44QCH106A(CXD2820R, TDA18212), TDA8024
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4
+ * IOA[7] TS 1=enabled
+ * IOE[5] CXD2820R 1=enabled
+ *
  * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)"
  * PCB: 508PTC (rev0.5)
  * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
@@ -437,7 +474,7 @@ static struct isl6423_config anysee_isl6423_config = {
  * IOD[6] ZL10353 1=enabled
  * IOE[0] IF 0=enabled
  *
- * E7 S2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)"
+ * E7 PS2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)"
  * PCB: 508PS2 (rev0.4)
  * parts: DNBU10512IST(STV0903, STV6110), ISL6423
  * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
@@ -446,6 +483,16 @@ static struct isl6423_config anysee_isl6423_config = {
  * IOE[5] STV0903 1=enabled
  */
 
+
+/* 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);
+}
+
 static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff)
 {
        struct dvb_usb_adapter *adap = fe->dvb->priv;
@@ -577,7 +624,8 @@ 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 bug).
+                * 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)
@@ -606,14 +654,14 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                        break;
 
                /* attach demod */
-               adap->fe_adap[0].fe = dvb_attach(mt352_attach, &anysee_mt352_config,
-                       &adap->dev->i2c_adap);
+               adap->fe_adap[0].fe = dvb_attach(mt352_attach,
+                       &anysee_mt352_config, &adap->dev->i2c_adap);
                if (adap->fe_adap[0].fe)
                        break;
 
                /* attach demod */
-               adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
-                       &adap->dev->i2c_adap);
+               adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
+                       &anysee_zl10353_config, &adap->dev->i2c_adap);
 
                break;
        case ANYSEE_HW_507CD: /* 6 */
@@ -665,8 +713,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                        goto error;
 
                /* attach demod */
-               adap->fe_adap[0].fe = dvb_attach(cx24116_attach, &anysee_cx24116_config,
-                       &adap->dev->i2c_adap);
+               adap->fe_adap[0].fe = dvb_attach(cx24116_attach,
+                       &anysee_cx24116_config, &adap->dev->i2c_adap);
 
                break;
        case ANYSEE_HW_507FA: /* 15 */
@@ -747,17 +795,19 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                        }
                }
 
+               /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+               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;
+               }
+
                break;
        case ANYSEE_HW_508TC: /* 18 */
        case ANYSEE_HW_508PTC: /* 21 */
                /* E7 TC */
                /* E7 PTC */
 
-               /* enable transport stream on IOA[7] */
-               ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
-               if (ret)
-                       goto error;
-
                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),
@@ -772,7 +822,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                                goto error;
 
                        /* attach demod */
-                       adap->fe_adap[state->fe_id].fe = dvb_attach(tda10023_attach,
+                       adap->fe_adap[state->fe_id].fe =
+                               dvb_attach(tda10023_attach,
                                &anysee_tda10023_tda18212_config,
                                &adap->dev->i2c_adap, 0x48);
                } else {
@@ -789,11 +840,19 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                                goto error;
 
                        /* attach demod */
-                       adap->fe_adap[state->fe_id].fe = dvb_attach(zl10353_attach,
+                       adap->fe_adap[state->fe_id].fe =
+                               dvb_attach(zl10353_attach,
                                &anysee_zl10353_tda18212_config,
                                &adap->dev->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;
+
+               state->has_ci = true;
+
                break;
        case ANYSEE_HW_508S2: /* 19 */
        case ANYSEE_HW_508PS2: /* 22 */
@@ -803,19 +862,35 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                if (state->fe_id)
                        break;
 
-               /* enable transport stream on IOA[7] */
-               ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
+               /* enable DVB-S/S2 demod on IOE[5] */
+               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20);
                if (ret)
                        goto error;
 
-               /* enable DVB-S/S2 demod on IOE[5] */
+               /* attach demod */
+               adap->fe_adap[0].fe = dvb_attach(stv0900_attach,
+                       &anysee_stv0900_config, &adap->dev->i2c_adap, 0);
+
+               state->has_ci = true;
+
+               break;
+       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);
                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_adap[state->fe_id].fe = dvb_attach(cxd2820r_attach,
+                               &anysee_cxd2820r_config, &adap->dev->i2c_adap,
+                               NULL);
+
+               state->has_ci = true;
 
                break;
        }
@@ -842,24 +917,26 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                /* 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_adap[0].fe,
+                       (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_adap[0].fe,
+                       (0xc2 >> 1), &adap->dev->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_adap[0].fe,
+                       (0xc0 >> 1), &adap->dev->i2c_adap,
+                       DVB_PLL_SAMSUNG_DTOS403IH102A);
 
                break;
        case ANYSEE_HW_507SI: /* 11 */
@@ -877,22 +954,12 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                /* Try first attach TDA18212 silicon tuner on IOE[4], if that
                 * fails attach old simple PLL. */
 
-               /* enable tuner on IOE[4] */
-               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
-               if (ret)
-                       goto error;
-
                /* attach tuner */
                fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
                        &adap->dev->i2c_adap, &anysee_tda18212_config);
                if (fe)
                        break;
 
-               /* disable tuner on IOE[4] */
-               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10);
-               if (ret)
-                       goto error;
-
                /* attach tuner */
                fe = dvb_attach(dvb_pll_attach, adap->fe_adap[state->fe_id].fe,
                        (0xc0 >> 1), &adap->dev->i2c_adap,
@@ -904,11 +971,6 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                /* E7 TC */
                /* E7 PTC */
 
-               /* enable tuner on IOE[4] */
-               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
-               if (ret)
-                       goto error;
-
                /* attach tuner */
                fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
                        &adap->dev->i2c_adap, &anysee_tda18212_config);
@@ -930,6 +992,15 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                }
 
                break;
+
+       case ANYSEE_HW_508T2C: /* 20 */
+               /* E7 T2C */
+
+               /* attach tuner */
+               fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
+                       &adap->dev->i2c_adap, &anysee_tda18212_config2);
+
+               break;
        default:
                fe = NULL;
        }
@@ -939,7 +1010,6 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
        else
                ret = -ENODEV;
 
-error:
        return ret;
 }
 
@@ -969,6 +1039,201 @@ static int anysee_rc_query(struct dvb_usb_device *d)
        return 0;
 }
 
+static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot,
+       int addr)
+{
+       struct dvb_usb_device *d = ci->data;
+       int ret;
+       u8 buf[] = {CMD_CI, 0x02, 0x40 | addr >> 8, addr & 0xff, 0x00, 1};
+       u8 val;
+
+       ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1);
+       if (ret)
+               return ret;
+
+       return val;
+}
+
+static int anysee_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, int slot,
+       int addr, u8 val)
+{
+       struct dvb_usb_device *d = ci->data;
+       int ret;
+       u8 buf[] = {CMD_CI, 0x03, 0x40 | addr >> 8, addr & 0xff, 0x00, 1, val};
+
+       ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int anysee_ci_read_cam_control(struct dvb_ca_en50221 *ci, int slot,
+       u8 addr)
+{
+       struct dvb_usb_device *d = ci->data;
+       int ret;
+       u8 buf[] = {CMD_CI, 0x04, 0x40, addr, 0x00, 1};
+       u8 val;
+
+       ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1);
+       if (ret)
+               return ret;
+
+       return val;
+}
+
+static int anysee_ci_write_cam_control(struct dvb_ca_en50221 *ci, int slot,
+       u8 addr, u8 val)
+{
+       struct dvb_usb_device *d = ci->data;
+       int ret;
+       u8 buf[] = {CMD_CI, 0x05, 0x40, addr, 0x00, 1, val};
+
+       ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+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;
+
+       state->ci_cam_ready = jiffies + msecs_to_jiffies(1000);
+
+       ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80);
+       if (ret)
+               return ret;
+
+       msleep(300);
+
+       ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int anysee_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot)
+{
+       struct dvb_usb_device *d = ci->data;
+       int ret;
+
+       ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80);
+       if (ret)
+               return ret;
+
+       msleep(30);
+
+       ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int anysee_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot)
+{
+       struct dvb_usb_device *d = ci->data;
+       int ret;
+
+       ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+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;
+       int ret;
+       u8 tmp;
+
+       ret = anysee_rd_reg_mask(d, REG_IOC, &tmp, 0x40);
+       if (ret)
+               return ret;
+
+       if (tmp == 0) {
+               ret = DVB_CA_EN50221_POLL_CAM_PRESENT;
+               if (time_after(jiffies, state->ci_cam_ready))
+                       ret |= DVB_CA_EN50221_POLL_CAM_READY;
+       }
+
+       return ret;
+}
+
+static int anysee_ci_init(struct dvb_usb_device *d)
+{
+       struct anysee_state *state = d->priv;
+       int ret;
+
+       state->ci.owner               = THIS_MODULE;
+       state->ci.read_attribute_mem  = anysee_ci_read_attribute_mem;
+       state->ci.write_attribute_mem = anysee_ci_write_attribute_mem;
+       state->ci.read_cam_control    = anysee_ci_read_cam_control;
+       state->ci.write_cam_control   = anysee_ci_write_cam_control;
+       state->ci.slot_reset          = anysee_ci_slot_reset;
+       state->ci.slot_shutdown       = anysee_ci_slot_shutdown;
+       state->ci.slot_ts_enable      = anysee_ci_slot_ts_enable;
+       state->ci.poll_slot_status    = anysee_ci_poll_slot_status;
+       state->ci.data                = d;
+
+       ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80);
+       if (ret)
+               return ret;
+
+       ret = dvb_ca_en50221_init(&d->adapter[0].dvb_adap, &state->ci, 0, 1);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void anysee_ci_release(struct dvb_usb_device *d)
+{
+       struct anysee_state *state = d->priv;
+
+       /* detach CI */
+       if (state->has_ci)
+               dvb_ca_en50221_release(&state->ci);
+
+       return;
+}
+
+static int anysee_init(struct dvb_usb_device *d)
+{
+       struct anysee_state *state = d->priv;
+       int ret;
+
+       /* LED light */
+       ret = anysee_led_ctrl(d, 0x01, 0x03);
+       if (ret)
+               return ret;
+
+       /* enable IR */
+       ret = anysee_ir_ctrl(d, 1);
+       if (ret)
+               return ret;
+
+       /* attach CI */
+       if (state->has_ci) {
+               ret = anysee_ci_init(d);
+               if (ret) {
+                       state->has_ci = false;
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 /* DVB USB Driver stuff */
 static struct dvb_usb_device_properties anysee_properties;
 
@@ -1010,6 +1275,16 @@ static int anysee_probe(struct usb_interface *intf,
        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;
+}
+
 static struct usb_device_id anysee_table[] = {
        { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) },
        { USB_DEVICE(USB_VID_AMT,     USB_PID_ANYSEE) },
@@ -1029,7 +1304,7 @@ static struct dvb_usb_device_properties anysee_properties = {
                {
                .num_frontends    = 2,
                .frontend_ctrl    = anysee_frontend_ctrl,
-               .fe = {{
+               .fe = { {
                        .streaming_ctrl   = anysee_streaming_ctrl,
                        .frontend_attach  = anysee_frontend_attach,
                        .tuner_attach     = anysee_tuner_attach,
@@ -1057,7 +1332,7 @@ static struct dvb_usb_device_properties anysee_properties = {
                                        }
                                }
                        },
-               }},
+               } },
                }
        },
 
@@ -1087,7 +1362,7 @@ static struct dvb_usb_device_properties anysee_properties = {
 static struct usb_driver anysee_driver = {
        .name       = "dvb_usb_anysee",
        .probe      = anysee_probe,
-       .disconnect = dvb_usb_device_exit,
+       .disconnect = anysee_disconnect,
        .id_table   = anysee_table,
 };
 
index 57ee500b8c0e1c16d8c41e8bf51d40b1e6058014..8ac8794315401d06a087dcf4614444ce98c8d12b 100644 (file)
@@ -36,6 +36,7 @@
 
 #define DVB_USB_LOG_PREFIX "anysee"
 #include "dvb-usb.h"
+#include "dvb_ca_en50221.h"
 
 #define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args)
 #define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args)
@@ -54,12 +55,16 @@ enum cmd {
        CMD_GET_IR_CODE         = 0x41,
        CMD_GET_HW_INFO         = 0x19,
        CMD_SMARTCARD           = 0x34,
+       CMD_CI                  = 0x37,
 };
 
 struct anysee_state {
        u8 hw; /* PCB ID */
        u8 seq;
        u8 fe_id:1; /* frondend ID */
+       u8 has_ci:1;
+       struct dvb_ca_en50221 ci;
+       unsigned long ci_cam_ready; /* jiffies */
 };
 
 #define ANYSEE_HW_507T    2 /* E30 */
@@ -69,6 +74,7 @@ struct anysee_state {
 #define ANYSEE_HW_507FA  15 /* E30 Combo Plus / E30 C Plus */
 #define ANYSEE_HW_508TC  18 /* E7 TC */
 #define ANYSEE_HW_508S2  19 /* E7 S2 */
+#define ANYSEE_HW_508T2C 20 /* E7 T2C */
 #define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */
 #define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */
 
index 9cd51ac12076eec16039c77fe6396735da9b559c..8a57ed8272dec10adfbbd989f81442ed6cc48ef9 100644 (file)
@@ -40,9 +40,8 @@
  *  We replace errornous fields by default TPS fields (the ones with value 0).
  */
 
-static uint16_t compute_tps(struct dvb_frontend_parameters *p)
+static uint16_t compute_tps(struct dtv_frontend_properties *op)
 {
-       struct dvb_ofdm_parameters *op = &p->u.ofdm;
        uint16_t tps = 0;
 
        switch (op->code_rate_HP) {
@@ -83,7 +82,7 @@ static uint16_t compute_tps(struct dvb_frontend_parameters *p)
                /* tps |= (0 << 4) */;
        }
 
-       switch (op->constellation) {
+       switch (op->modulation) {
        case QAM_16:
                tps |= (1 << 13);
                break;
@@ -119,7 +118,7 @@ static uint16_t compute_tps(struct dvb_frontend_parameters *p)
                /* tps |= (0 << 2) */;
        }
 
-       switch (op->hierarchy_information) {
+       switch (op->hierarchy) {
        case HIERARCHY_1:
                tps |= (1 << 10);
                break;
@@ -263,9 +262,9 @@ static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe,
        return 0;
 }
 
-static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe,
-                                 struct dvb_frontend_parameters *fep)
+static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct cinergyt2_fe_state *state = fe->demodulator_priv;
        struct dvbt_set_parameters_msg param;
        char result[2];
@@ -274,9 +273,20 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe,
        param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
        param.tps = cpu_to_le16(compute_tps(fep));
        param.freq = cpu_to_le32(fep->frequency / 1000);
-       param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
        param.flags = 0;
 
+       switch (fep->bandwidth_hz) {
+       case 8000000:
+               param.bandwidth = 0;
+               break;
+       case 7000000:
+               param.bandwidth = 1;
+               break;
+       case 6000000:
+               param.bandwidth = 2;
+               break;
+       }
+
        err = dvb_usb_generic_rw(state->d,
                        (char *)&param, sizeof(param),
                        result, sizeof(result), 0);
@@ -286,12 +296,6 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe,
        return (err < 0) ? err : 0;
 }
 
-static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe,
-                                 struct dvb_frontend_parameters *fep)
-{
-       return 0;
-}
-
 static void cinergyt2_fe_release(struct dvb_frontend *fe)
 {
        struct cinergyt2_fe_state *state = fe->demodulator_priv;
@@ -316,9 +320,9 @@ struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d)
 
 
 static struct dvb_frontend_ops cinergyt2_fe_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = DRIVER_NAME,
-               .type                   = FE_OFDM,
                .frequency_min          = 174000000,
                .frequency_max          = 862000000,
                .frequency_stepsize     = 166667,
@@ -341,7 +345,6 @@ static struct dvb_frontend_ops cinergyt2_fe_ops = {
        .sleep                  = cinergyt2_fe_sleep,
 
        .set_frontend           = cinergyt2_fe_set_frontend,
-       .get_frontend           = cinergyt2_fe_get_frontend,
        .get_tune_settings      = cinergyt2_fe_get_tune_settings,
 
        .read_status            = cinergyt2_fe_read_status,
index 949ea1bc0aae8ae9a48982674251a4442316fed1..3940bb0f9ef62dd8b3121d3ee0a7739669581d90 100644 (file)
@@ -1067,18 +1067,17 @@ static struct dib0070_config dib7070p_dib0070_config = {
 };
 
 struct dib0700_adapter_state {
-       int (*set_param_save) (struct dvb_frontend *,
-                              struct dvb_frontend_parameters *);
+       int (*set_param_save) (struct dvb_frontend *);
 };
 
-static int dib7070_set_param_override(struct dvb_frontend *fe,
-                                     struct dvb_frontend_parameters *fep)
+static int dib7070_set_param_override(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct dvb_usb_adapter *adap = fe->dvb->priv;
        struct dib0700_adapter_state *state = adap->priv;
 
        u16 offset;
-       u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+       u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
        switch (band) {
        case BAND_VHF: offset = 950; break;
        default:
@@ -1087,7 +1086,7 @@ static int dib7070_set_param_override(struct dvb_frontend *fe,
 
        dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
 
-       return state->set_param_save(fe, fep);
+       return state->set_param_save(fe);
 }
 
 static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap)
index 9bd6d51b3b938b21659dffe90f7ee68877ad6302..7de125c0b36f4576f951ea8e90a87d7c308f0857 100644 (file)
@@ -48,6 +48,8 @@ struct dib0700_state {
        u8 disable_streaming_master_mode;
        u32 fw_version;
        u32 nb_packet_buffer_size;
+       int (*read_status)(struct dvb_frontend *, fe_status_t *);
+       int (*sleep)(struct dvb_frontend* fe);
        u8 buf[255];
 };
 
index 206999476f028238c430797ba11b762b55dee379..070e82aa53f53248f33448d9e61d22b484e6b28a 100644 (file)
@@ -834,6 +834,7 @@ static struct usb_driver dib0700_driver = {
 
 module_usb_driver(dib0700_driver);
 
+MODULE_FIRMWARE("dvb-usb-dib0700-1.20.fw");
 MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
 MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge");
 MODULE_VERSION("1.0");
index f313182eb9d5ed0f2b9ff7fd6f248c9f4f98df7a..f9e966aa26e75d19b0ce129221be038bd6787fe5 100644 (file)
@@ -30,7 +30,7 @@ MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplif
                "if applicable for the device (default: 0=automatic/off).");
 
 struct dib0700_adapter_state {
-       int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *);
+       int (*set_param_save) (struct dvb_frontend *);
        const struct firmware *frontend_firmware;
 };
 
@@ -804,13 +804,14 @@ static struct dib0070_config dib7770p_dib0070_config = {
         .charge_pump = 2,
 };
 
-static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib7070_set_param_override(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct dvb_usb_adapter *adap = fe->dvb->priv;
        struct dib0700_adapter_state *state = adap->priv;
 
        u16 offset;
-       u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+       u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
        switch (band) {
                case BAND_VHF: offset = 950; break;
                case BAND_UHF:
@@ -818,17 +819,17 @@ static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_fronte
        }
        deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
        dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
-       return state->set_param_save(fe, fep);
+       return state->set_param_save(fe);
 }
 
-static int dib7770_set_param_override(struct dvb_frontend *fe,
-               struct dvb_frontend_parameters *fep)
+static int dib7770_set_param_override(struct dvb_frontend *fe)
 {
-        struct dvb_usb_adapter *adap = fe->dvb->priv;
-        struct dib0700_adapter_state *state = adap->priv;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dib0700_adapter_state *state = adap->priv;
 
         u16 offset;
-        u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+        u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
         switch (band) {
         case BAND_VHF:
                  dib7000p_set_gpio(fe, 0, 0, 1);
@@ -842,7 +843,7 @@ static int dib7770_set_param_override(struct dvb_frontend *fe,
         }
         deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
         dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
-        return state->set_param_save(fe, fep);
+        return state->set_param_save(fe);
 }
 
 static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap)
@@ -1205,14 +1206,14 @@ static struct dib0070_config dib807x_dib0070_config[2] = {
        }
 };
 
-static int dib807x_set_param_override(struct dvb_frontend *fe,
-               struct dvb_frontend_parameters *fep)
+static int dib807x_set_param_override(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct dvb_usb_adapter *adap = fe->dvb->priv;
        struct dib0700_adapter_state *state = adap->priv;
 
        u16 offset = dib0070_wbd_offset(fe);
-       u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+       u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
        switch (band) {
        case BAND_VHF:
                offset += 750;
@@ -1224,7 +1225,7 @@ static int dib807x_set_param_override(struct dvb_frontend *fe,
        deb_info("WBD for DiB8000: %d\n", offset);
        dib8000_set_wbd_ref(fe, offset);
 
-       return state->set_param_save(fe, fep);
+       return state->set_param_save(fe);
 }
 
 static int dib807x_tuner_attach(struct dvb_usb_adapter *adap)
@@ -1279,7 +1280,7 @@ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap)
        dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
 
        dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
-                               0x80);
+                               0x80, 0);
 
        adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
                              &dib807x_dib8000_config[0]);
@@ -1308,7 +1309,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
        dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
 
        /* initialize IC 0 */
-       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80);
+       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80, 0);
 
        adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
                              &dib807x_dib8000_config[0]);
@@ -1319,7 +1320,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
 static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
 {
        /* initialize IC 1 */
-       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82);
+       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82, 0);
 
        adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82,
                              &dib807x_dib8000_config[1]);
@@ -1328,7 +1329,7 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
 }
 
 /* STK8096GP */
-struct dibx000_agc_config dib8090_agc_config[2] = {
+static struct dibx000_agc_config dib8090_agc_config[2] = {
        {
        BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
        /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
@@ -1503,22 +1504,22 @@ static struct dib0090_config dib809x_dib0090_config = {
        .fref_clock_ratio = 6,
 };
 
-static int dib8096_set_param_override(struct dvb_frontend *fe,
-               struct dvb_frontend_parameters *fep)
+static int dib8096_set_param_override(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct dvb_usb_adapter *adap = fe->dvb->priv;
        struct dib0700_adapter_state *state = adap->priv;
-       u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+       u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
        u16 target;
        int ret = 0;
        enum frontend_tune_state tune_state = CT_SHUTDOWN;
        u16 ltgain, rf_gain_limit;
 
-       ret = state->set_param_save(fe, fep);
+       ret = state->set_param_save(fe);
        if (ret < 0)
                return ret;
 
-       target = (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2;
+       target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
        dib8000_set_wbd_ref(fe, target);
 
 
@@ -1578,7 +1579,7 @@ static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
        msleep(10);
        dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
 
-       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80);
+       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0);
 
        adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
 
@@ -1629,7 +1630,7 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap)
        msleep(20);
        dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
 
-       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80);
+       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80, 0);
 
        adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
        if (adap->fe_adap[0].fe == NULL)
@@ -1641,6 +1642,261 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap)
        return fe_slave == NULL ?  -ENODEV : 0;
 }
 
+/* TFE8096P */
+static struct dibx000_agc_config dib8096p_agc_config[2] = {
+       {
+               .band_caps              = BAND_UHF,
+               /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
+                  P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
+                  P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+                  P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
+                  P_agc_write=0 */
+               .setup                  = (0 << 15) | (0 << 14) | (5 << 11)
+                       | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5)
+                       | (0 << 4) | (5 << 1) | (0 << 0),
+
+               .inv_gain               = 684,
+               .time_stabiliz  = 10,
+
+               .alpha_level    = 0,
+               .thlock                 = 118,
+
+               .wbd_inv                = 0,
+               .wbd_ref                = 1200,
+               .wbd_sel                = 3,
+               .wbd_alpha              = 5,
+
+               .agc1_max               = 65535,
+               .agc1_min               = 0,
+
+               .agc2_max               = 32767,
+               .agc2_min               = 0,
+
+               .agc1_pt1               = 0,
+               .agc1_pt2               = 0,
+               .agc1_pt3               = 105,
+               .agc1_slope1    = 0,
+               .agc1_slope2    = 156,
+               .agc2_pt1               = 105,
+               .agc2_pt2               = 255,
+               .agc2_slope1    = 54,
+               .agc2_slope2    = 0,
+
+               .alpha_mant             = 28,
+               .alpha_exp              = 26,
+               .beta_mant              = 31,
+               .beta_exp               = 51,
+
+               .perform_agc_softsplit = 0,
+       } , {
+               .band_caps              = BAND_FM | BAND_VHF | BAND_CBAND,
+               /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0,
+                  P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0,
+                  P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+                  P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5,
+                  P_agc_write=0 */
+               .setup                  = (0 << 15) | (0 << 14) | (5 << 11)
+                       | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5)
+                       | (0 << 4) | (5 << 1) | (0 << 0),
+
+               .inv_gain               = 732,
+               .time_stabiliz  = 10,
+
+               .alpha_level    = 0,
+               .thlock                 = 118,
+
+               .wbd_inv                = 0,
+               .wbd_ref                = 1200,
+               .wbd_sel                = 3,
+               .wbd_alpha              = 5,
+
+               .agc1_max               = 65535,
+               .agc1_min               = 0,
+
+               .agc2_max               = 32767,
+               .agc2_min               = 0,
+
+               .agc1_pt1               = 0,
+               .agc1_pt2               = 0,
+               .agc1_pt3               = 98,
+               .agc1_slope1    = 0,
+               .agc1_slope2    = 167,
+               .agc2_pt1               = 98,
+               .agc2_pt2               = 255,
+               .agc2_slope1    = 52,
+               .agc2_slope2    = 0,
+
+               .alpha_mant             = 28,
+               .alpha_exp              = 26,
+               .beta_mant              = 31,
+               .beta_exp               = 51,
+
+               .perform_agc_softsplit = 0,
+       }
+};
+
+static struct dibx000_bandwidth_config dib8096p_clock_config_12_mhz = {
+       108000, 13500,
+       1, 9, 1, 0, 0,
+       0, 0, 0, 0, 2,
+       (3 << 14) | (1 << 12) | (524 << 0),
+       (0 << 25) | 0,
+       20199729,
+       12000000,
+};
+
+static struct dib8000_config tfe8096p_dib8000_config = {
+       .output_mpeg2_in_188_bytes      = 1,
+       .hostbus_diversity                      = 1,
+       .update_lna                                     = NULL,
+
+       .agc_config_count                       = 2,
+       .agc                                            = dib8096p_agc_config,
+       .pll                                            = &dib8096p_clock_config_12_mhz,
+
+       .gpio_dir                                       = DIB8000_GPIO_DEFAULT_DIRECTIONS,
+       .gpio_val                                       = DIB8000_GPIO_DEFAULT_VALUES,
+       .gpio_pwm_pos                           = DIB8000_GPIO_DEFAULT_PWM_POS,
+
+       .agc_control                            = NULL,
+       .diversity_delay                        = 48,
+       .output_mode                            = OUTMODE_MPEG2_FIFO,
+       .enMpegOutput                           = 1,
+};
+
+static struct dib0090_wbd_slope dib8096p_wbd_table[] = {
+       { 380, 81, 850, 64, 540, 4},
+       { 860, 51, 866, 21, 375, 4},
+       {1700, 0, 250, 0, 100, 6},
+       {2600, 0, 250, 0, 100, 6},
+       { 0xFFFF, 0, 0, 0, 0, 0},
+};
+
+static const struct dib0090_config tfe8096p_dib0090_config = {
+       .io.clock_khz                   = 12000,
+       .io.pll_bypass                  = 0,
+       .io.pll_range                   = 0,
+       .io.pll_prediv                  = 3,
+       .io.pll_loopdiv                 = 6,
+       .io.adc_clock_ratio             = 0,
+       .io.pll_int_loop_filt   = 0,
+       .reset                                  = dib8096p_tuner_sleep,
+       .sleep                                  = dib8096p_tuner_sleep,
+
+       .freq_offset_khz_uhf    = -143,
+       .freq_offset_khz_vhf    = -143,
+
+       .get_adc_power                  = dib8090_get_adc_power,
+
+       .clkouttobamse                  = 1,
+       .analog_output                  = 0,
+
+       .wbd_vhf_offset                 = 0,
+       .wbd_cband_offset               = 0,
+       .use_pwm_agc                    = 1,
+       .clkoutdrive                    = 0,
+
+       .fref_clock_ratio               = 1,
+
+       .wbd                                    = dib8096p_wbd_table,
+
+       .ls_cfg_pad_drv                 = 0,
+       .data_tx_drv                    = 0,
+       .low_if                                 = NULL,
+       .in_soc                                 = 1,
+       .force_cband_input              = 0,
+};
+
+struct dibx090p_adc {
+       u32 freq;                       /* RF freq MHz */
+       u32 timf;                       /* New Timf */
+       u32 pll_loopdiv;        /* New prediv */
+       u32 pll_prediv;         /* New loopdiv */
+};
+
+struct dibx090p_adc dib8090p_adc_tab[] = {
+       { 50000, 17043521, 16, 3}, /* 64 MHz */
+       {878000, 20199729, 9, 1}, /* 60 MHz */
+       {0xffffffff, 0, 0, 0}, /* 60 MHz */
+};
+
+static int dib8096p_agc_startup(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dib0700_adapter_state *state = adap->priv;
+       struct dibx000_bandwidth_config pll;
+       u16 target;
+       int better_sampling_freq = 0, ret;
+       struct dibx090p_adc *adc_table = &dib8090p_adc_tab[0];
+
+       ret = state->set_param_save(fe);
+       if (ret < 0)
+               return ret;
+       memset(&pll, 0, sizeof(struct dibx000_bandwidth_config));
+
+       dib0090_pwm_gain_reset(fe);
+       /* dib0090_get_wbd_target is returning any possible
+          temperature compensated wbd-target */
+       target = (dib0090_get_wbd_target(fe) * 8  + 1) / 2;
+       dib8000_set_wbd_ref(fe, target);
+
+
+       while (p->frequency / 1000 > adc_table->freq) {
+               better_sampling_freq = 1;
+               adc_table++;
+       }
+
+       if ((adc_table->freq != 0xffffffff) && better_sampling_freq) {
+               pll.pll_ratio  = adc_table->pll_loopdiv;
+               pll.pll_prediv = adc_table->pll_prediv;
+               dib8000_update_pll(fe, &pll);
+               dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf);
+       }
+       return 0;
+}
+
+static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+       dib0700_ctrl_clock(adap->dev, 72, 1);
+
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80, 1);
+
+       adap->fe_adap[0].fe = dvb_attach(dib8000_attach,
+                       &adap->dev->i2c_adap, 0x80, &tfe8096p_dib8000_config);
+
+       return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
+}
+
+static int tfe8096p_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c = dib8096p_get_i2c_tuner(adap->fe_adap[0].fe);
+
+       if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
+                               &tfe8096p_dib0090_config) == NULL)
+               return -ENODEV;
+
+       dib8000_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+
+       st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+       adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096p_agc_startup;
+       return 0;
+}
+
 /* STK9090M */
 static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
 {
@@ -1883,7 +2139,7 @@ static int dib9090_tuner_attach(struct dvb_usb_adapter *adap)
        i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
        if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0)
                return -ENODEV;
-       dib0700_set_i2c_speed(adap->dev, 2000);
+       dib0700_set_i2c_speed(adap->dev, 1500);
        if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0)
                return -ENODEV;
        release_firmware(state->frontend_firmware);
@@ -1962,7 +2218,8 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
        i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
        if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0)
                return -ENODEV;
-       dib0700_set_i2c_speed(adap->dev, 2000);
+
+       dib0700_set_i2c_speed(adap->dev, 1500);
        if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0)
                return -ENODEV;
 
@@ -1975,7 +2232,7 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
                if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL)
                        return -ENODEV;
                fe_slave->dvb = adap->fe_adap[0].fe->dvb;
-               dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 2000);
+               dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 1500);
                if (dib9000_firmware_post_pll_init(fe_slave) < 0)
                        return -ENODEV;
        }
@@ -2064,7 +2321,7 @@ static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_
                return 0;
 }
 
-static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib7090_agc_startup(struct dvb_frontend *fe)
 {
        struct dvb_usb_adapter *adap = fe->dvb->priv;
        struct dib0700_adapter_state *state = adap->priv;
@@ -2073,13 +2330,13 @@ static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_para
        struct dib7090p_best_adc adc;
        int ret;
 
-       ret = state->set_param_save(fe, fep);
+       ret = state->set_param_save(fe);
        if (ret < 0)
                return ret;
 
        memset(&pll, 0, sizeof(struct dibx000_bandwidth_config));
        dib0090_pwm_gain_reset(fe);
-       target = (dib0090_get_wbd_offset(fe) * 8 + 1) / 2;
+       target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2;
        dib7000p_set_wbd_ref(fe, target);
 
        if (dib7090p_get_best_sampling(fe, &adc) == 0) {
@@ -2092,6 +2349,49 @@ static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_para
        return 0;
 }
 
+static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
+{
+       deb_info("AGC restart callback: %d", restart);
+       if (restart == 0) /* before AGC startup */
+               dib0090_set_dc_servo(fe, 1);
+       return 0;
+}
+
+static int dib7090e_update_lna(struct dvb_frontend *fe, u16 agc_global)
+{
+       u16 agc1 = 0, agc2, wbd = 0, wbd_target, wbd_offset, threshold_agc1;
+       s16 wbd_delta;
+
+       if ((fe->dtv_property_cache.frequency) < 400000000)
+               threshold_agc1 = 25000;
+       else
+               threshold_agc1 = 30000;
+
+       wbd_target = (dib0090_get_wbd_target(fe)*8+1)/2;
+       wbd_offset = dib0090_get_wbd_offset(fe);
+       dib7000p_get_agc_values(fe, NULL, &agc1, &agc2, &wbd);
+       wbd_delta = (s16)wbd - (((s16)wbd_offset+10)*4) ;
+
+       deb_info("update lna, agc_global=%d agc1=%d agc2=%d",
+                       agc_global, agc1, agc2);
+       deb_info("update lna, wbd=%d wbd target=%d wbd offset=%d wbd delta=%d",
+                       wbd, wbd_target, wbd_offset, wbd_delta);
+
+       if ((agc1 < threshold_agc1) && (wbd_delta > 0)) {
+               dib0090_set_switch(fe, 1, 1, 1);
+               dib0090_set_vga(fe, 0);
+               dib0090_update_rframp_7090(fe, 0);
+               dib0090_update_tuning_table_7090(fe, 0);
+       } else {
+               dib0090_set_vga(fe, 1);
+               dib0090_update_rframp_7090(fe, 1);
+               dib0090_update_tuning_table_7090(fe, 1);
+               dib0090_set_switch(fe, 0, 0, 0);
+       }
+
+       return 0;
+}
+
 static struct dib0090_wbd_slope dib7090_wbd_table[] = {
        { 380,   81, 850, 64, 540,  4},
        { 860,   51, 866, 21,  375, 4},
@@ -2100,7 +2400,16 @@ static struct dib0090_wbd_slope dib7090_wbd_table[] = {
        { 0xFFFF, 0,   0, 0,   0,   0},
 };
 
-struct dibx000_agc_config dib7090_agc_config[2] = {
+static struct dib0090_wbd_slope dib7090e_wbd_table[] = {
+       { 380,   81, 850, 64, 540,      4},
+       { 700,   51, 866, 21,  320,     4},
+       { 860,   48, 666, 18,  330,     6},
+       {1700,    0, 250, 0,   100, 6},
+       {2600,    0, 250, 0,   100, 6},
+       { 0xFFFF, 0,   0, 0,   0,       0},
+};
+
+static struct dibx000_agc_config dib7090_agc_config[2] = {
        {
                .band_caps      = BAND_UHF,
                /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
@@ -2278,6 +2587,34 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
        }
 };
 
+static struct dib7000p_config tfe7090e_dib7000p_config = {
+       .output_mpeg2_in_188_bytes  = 1,
+       .hostbus_diversity                      = 1,
+       .tuner_is_baseband                      = 1,
+       .update_lna                                     = dib7090e_update_lna,
+
+       .agc_config_count                       = 2,
+       .agc                                            = dib7090_agc_config,
+
+       .bw                                                     = &dib7090_clock_config_12_mhz,
+
+       .gpio_dir                                       = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+       .gpio_val                                       = DIB7000P_GPIO_DEFAULT_VALUES,
+       .gpio_pwm_pos                           = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+       .pwm_freq_div                           = 0,
+
+       .agc_control                            = dib7090_agc_restart,
+
+       .spur_protect                           = 0,
+       .disable_sample_and_hold        = 0,
+       .enable_current_mirror          = 0,
+       .diversity_delay                        = 0,
+
+       .output_mode                            = OUTMODE_MPEG2_FIFO,
+       .enMpegOutput                           = 1,
+};
+
 static const struct dib0090_config nim7090_dib0090_config = {
        .io.clock_khz = 12000,
        .io.pll_bypass = 0,
@@ -2312,6 +2649,107 @@ static const struct dib0090_config nim7090_dib0090_config = {
        .in_soc = 1,
 };
 
+static const struct dib0090_config tfe7090e_dib0090_config = {
+       .io.clock_khz = 12000,
+       .io.pll_bypass = 0,
+       .io.pll_range = 0,
+       .io.pll_prediv = 3,
+       .io.pll_loopdiv = 6,
+       .io.adc_clock_ratio = 0,
+       .io.pll_int_loop_filt = 0,
+       .reset = dib7090_tuner_sleep,
+       .sleep = dib7090_tuner_sleep,
+
+       .freq_offset_khz_uhf = 0,
+       .freq_offset_khz_vhf = 0,
+
+       .get_adc_power = dib7090_get_adc_power,
+
+       .clkouttobamse = 1,
+       .analog_output = 0,
+
+       .wbd_vhf_offset = 0,
+       .wbd_cband_offset = 0,
+       .use_pwm_agc = 1,
+       .clkoutdrive = 0,
+
+       .fref_clock_ratio = 0,
+
+       .wbd = dib7090e_wbd_table,
+
+       .ls_cfg_pad_drv = 0,
+       .data_tx_drv = 0,
+       .low_if = NULL,
+       .in_soc = 1,
+       .force_cband_input = 1,
+       .is_dib7090e = 1,
+};
+
+static struct dib7000p_config tfe7790e_dib7000p_config = {
+       .output_mpeg2_in_188_bytes  = 1,
+       .hostbus_diversity                      = 1,
+       .tuner_is_baseband                      = 1,
+       .update_lna                                     = dib7090e_update_lna,
+
+       .agc_config_count                       = 2,
+       .agc                                            = dib7090_agc_config,
+
+       .bw                                                     = &dib7090_clock_config_12_mhz,
+
+       .gpio_dir                                       = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+       .gpio_val                                       = DIB7000P_GPIO_DEFAULT_VALUES,
+       .gpio_pwm_pos                           = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+       .pwm_freq_div                           = 0,
+
+       .agc_control                            = dib7090_agc_restart,
+
+       .spur_protect                           = 0,
+       .disable_sample_and_hold        = 0,
+       .enable_current_mirror          = 0,
+       .diversity_delay                        = 0,
+
+       .output_mode                            = OUTMODE_MPEG2_PAR_GATED_CLK,
+       .enMpegOutput                           = 1,
+};
+
+static const struct dib0090_config tfe7790e_dib0090_config = {
+       .io.clock_khz = 12000,
+       .io.pll_bypass = 0,
+       .io.pll_range = 0,
+       .io.pll_prediv = 3,
+       .io.pll_loopdiv = 6,
+       .io.adc_clock_ratio = 0,
+       .io.pll_int_loop_filt = 0,
+       .reset = dib7090_tuner_sleep,
+       .sleep = dib7090_tuner_sleep,
+
+       .freq_offset_khz_uhf = 0,
+       .freq_offset_khz_vhf = 0,
+
+       .get_adc_power = dib7090_get_adc_power,
+
+       .clkouttobamse = 1,
+       .analog_output = 0,
+
+       .wbd_vhf_offset = 0,
+       .wbd_cband_offset = 0,
+       .use_pwm_agc = 1,
+       .clkoutdrive = 0,
+
+       .fref_clock_ratio = 0,
+
+       .wbd = dib7090e_wbd_table,
+
+       .ls_cfg_pad_drv = 0,
+       .data_tx_drv = 0,
+       .low_if = NULL,
+       .in_soc = 1,
+       .force_cband_input = 1,
+       .is_dib7090e = 1,
+       .force_crystal_mode = 1,
+};
+
 static const struct dib0090_config tfe7090pvr_dib0090_config[2] = {
        {
                .io.clock_khz = 12000,
@@ -2504,6 +2942,97 @@ static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
+static int tfe7090e_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+       if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
+                               1, 0x10, &tfe7090e_dib7000p_config) != 0) {
+               err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
+                               __func__);
+               return -ENODEV;
+       }
+       adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
+                       0x80, &tfe7090e_dib7000p_config);
+
+       return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
+}
+
+static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_state *st = adap->dev->priv;
+
+       /* The TFE7790E requires the dib0700 to not be in master mode */
+       st->disable_streaming_master_mode = 1;
+
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+       msleep(20);
+       dib0700_ctrl_clock(adap->dev, 72, 1);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+       if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
+                               1, 0x10, &tfe7790e_dib7000p_config) != 0) {
+               err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
+                               __func__);
+               return -ENODEV;
+       }
+       adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
+                       0x80, &tfe7790e_dib7000p_config);
+
+       return adap->fe_adap[0].fe == NULL ?  -ENODEV : 0;
+}
+
+static int tfe7790e_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c =
+               dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
+
+       if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
+                               &tfe7790e_dib0090_config) == NULL)
+               return -ENODEV;
+
+       dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+
+       st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+       adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+       return 0;
+}
+
+static int tfe7090e_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c =
+               dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
+
+       if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
+                               &tfe7090e_dib0090_config) == NULL)
+               return -ENODEV;
+
+       dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+
+       st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+       adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+       return 0;
+}
+
 /* STK7070PD */
 static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
        {
@@ -2537,19 +3066,25 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
        }
 };
 
-static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
+static void stk7070pd_init(struct dvb_usb_device *dev)
 {
-       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       dib0700_set_gpio(dev, GPIO6, GPIO_OUT, 1);
        msleep(10);
-       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
-       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
-       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+       dib0700_set_gpio(dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(dev, GPIO7, GPIO_OUT, 1);
+       dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 0);
 
-       dib0700_ctrl_clock(adap->dev, 72, 1);
+       dib0700_ctrl_clock(dev, 72, 1);
 
        msleep(10);
-       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 1);
+}
+
+static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
+{
+       stk7070pd_init(adap->dev);
+
        msleep(10);
        dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
 
@@ -2570,6 +3105,77 @@ static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
        return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
+static int novatd_read_status_override(struct dvb_frontend *fe,
+               fe_status_t *stat)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dvb_usb_device *dev = adap->dev;
+       struct dib0700_state *state = dev->priv;
+       int ret;
+
+       ret = state->read_status(fe, stat);
+
+       if (!ret)
+               dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT,
+                               !!(*stat & FE_HAS_LOCK));
+
+       return ret;
+}
+
+static int novatd_sleep_override(struct dvb_frontend* fe)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dvb_usb_device *dev = adap->dev;
+       struct dib0700_state *state = dev->priv;
+
+       /* turn off LED */
+       dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT, 0);
+
+       return state->sleep(fe);
+}
+
+/**
+ * novatd_frontend_attach - Nova-TD specific attach
+ *
+ * Nova-TD has GPIO0, 1 and 2 for LEDs. So do not fiddle with them except for
+ * information purposes.
+ */
+static int novatd_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dvb_usb_device *dev = adap->dev;
+       struct dib0700_state *st = dev->priv;
+
+       if (adap->id == 0) {
+               stk7070pd_init(dev);
+
+               /* turn the power LED on, the other two off (just in case) */
+               dib0700_set_gpio(dev, GPIO0, GPIO_OUT, 0);
+               dib0700_set_gpio(dev, GPIO1, GPIO_OUT, 0);
+               dib0700_set_gpio(dev, GPIO2, GPIO_OUT, 1);
+
+               if (dib7000p_i2c_enumeration(&dev->i2c_adap, 2, 18,
+                                            stk7070pd_dib7000p_config) != 0) {
+                       err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n",
+                           __func__);
+                       return -ENODEV;
+               }
+       }
+
+       adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &dev->i2c_adap,
+                       adap->id == 0 ? 0x80 : 0x82,
+                       &stk7070pd_dib7000p_config[adap->id]);
+
+       if (adap->fe_adap[0].fe == NULL)
+               return -ENODEV;
+
+       st->read_status = adap->fe_adap[0].fe->ops.read_status;
+       adap->fe_adap[0].fe->ops.read_status = novatd_read_status_override;
+       st->sleep = adap->fe_adap[0].fe->ops.sleep;
+       adap->fe_adap[0].fe->ops.sleep = novatd_sleep_override;
+
+       return 0;
+}
+
 /* S5H1411 */
 static struct s5h1411_config pinnacle_801e_config = {
        .output_mode   = S5H1411_PARALLEL_OUTPUT,
@@ -2960,6 +3566,9 @@ struct usb_device_id dib0700_usb_id_table[] = {
 /* 75 */{ USB_DEVICE(USB_VID_MEDION,    USB_PID_CREATIX_CTX1921) },
        { USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV340E) },
        { USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV340E_SE) },
+       { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7090E) },
+       { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7790E) },
+/* 80 */{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE8096P) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -3329,6 +3938,57 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                },
        }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
+               .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       = stk70x0p_pid_filter,
+                               .pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+                               .frontend_attach  = novatd_frontend_attach,
+                               .tuner_attach     = dib7070p_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+                       }},
+                               .size_of_priv     = sizeof(struct dib0700_adapter_state),
+                       }, {
+                       .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       = stk70x0p_pid_filter,
+                               .pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+                               .frontend_attach  = novatd_frontend_attach,
+                               .tuner_attach     = dib7070p_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+                       }},
+                               .size_of_priv     = sizeof(struct dib0700_adapter_state),
+                       }
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "Hauppauge Nova-TD Stick (52009)",
+                               { &dib0700_usb_id_table[35], NULL },
+                               { NULL },
+                       },
+               },
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
                .num_adapters = 2,
                .adapter = {
                        {
@@ -3360,7 +4020,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        }
                },
 
-               .num_device_descs = 6,
+               .num_device_descs = 5,
                .devices = {
                        {   "DiBcom STK7070PD reference design",
                                { &dib0700_usb_id_table[17], NULL },
@@ -3370,10 +4030,6 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[18], NULL },
                                { NULL },
                        },
-                       {   "Hauppauge Nova-TD Stick (52009)",
-                               { &dib0700_usb_id_table[35], NULL },
-                               { NULL },
-                       },
                        {   "Hauppauge Nova-TD-500 (84xxx)",
                                { &dib0700_usb_id_table[36], NULL },
                                { NULL },
@@ -4015,6 +4671,127 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { NULL },
                        },
                },
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .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 = stk70x0p_pid_filter,
+                                       .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+                                       .frontend_attach  = tfe7090e_frontend_attach,
+                                       .tuner_attach     = tfe7090e_tuner_attach,
+
+                                       DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+                               } },
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "DiBcom TFE7090E reference design",
+                               { &dib0700_usb_id_table[78], NULL },
+                               { NULL },
+                       },
+               },
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .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 = stk70x0p_pid_filter,
+                                       .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+                                       .frontend_attach  = tfe7790e_frontend_attach,
+                                       .tuner_attach     = tfe7790e_tuner_attach,
+
+                                       DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+                               } },
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "DiBcom TFE7790E reference design",
+                               { &dib0700_usb_id_table[79], NULL },
+                               { NULL },
+                       },
+               },
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .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 = stk80xx_pid_filter,
+                                       .pid_filter_ctrl = stk80xx_pid_filter_ctrl,
+                                       .frontend_attach  = tfe8096p_frontend_attach,
+                                       .tuner_attach     = tfe8096p_tuner_attach,
+
+                                       DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               } },
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "DiBcom TFE8096P reference design",
+                               { &dib0700_usb_id_table[80], NULL },
+                               { NULL },
+                       },
+               },
+
                .rc.core = {
                        .rc_interval      = DEFAULT_RC_INTERVAL,
                        .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
index 0a9a79820f261402c0cfa8778f3f379aa54bde66..ff34419a4c88438ca74ac0eac19180d9fbeafd07 100644 (file)
@@ -118,12 +118,12 @@ static struct mt352_config digitv_mt352_config = {
        .demod_init = digitv_mt352_demod_init,
 };
 
-static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe)
 {
        struct dvb_usb_adapter *adap = fe->dvb->priv;
        u8 b[5];
 
-       fe->ops.tuner_ops.calc_regs(fe, fep, b, sizeof(b));
+       fe->ops.tuner_ops.calc_regs(fe, b, sizeof(b));
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
        return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
index 17413adec7a1fbd92199c97d0a45f2dfa37e8875..3d81daa4917229ff3c92a8d7c59dc20eae34f8cc 100644 (file)
@@ -16,7 +16,7 @@ struct dtt200u_fe_state {
 
        fe_status_t stat;
 
-       struct dvb_frontend_parameters fep;
+       struct dtv_frontend_properties fep;
        struct dvb_frontend frontend;
 };
 
@@ -100,22 +100,27 @@ static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_fron
        return 0;
 }
 
-static int dtt200u_fe_set_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep)
+static int dtt200u_fe_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct dtt200u_fe_state *state = fe->demodulator_priv;
        int i;
        fe_status_t st;
        u16 freq = fep->frequency / 250000;
        u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 };
 
-       switch (fep->u.ofdm.bandwidth) {
-               case BANDWIDTH_8_MHZ: bwbuf[1] = 8; break;
-               case BANDWIDTH_7_MHZ: bwbuf[1] = 7; break;
-               case BANDWIDTH_6_MHZ: bwbuf[1] = 6; break;
-               case BANDWIDTH_AUTO: return -EOPNOTSUPP;
-               default:
-                       return -EINVAL;
+       switch (fep->bandwidth_hz) {
+       case 8000000:
+               bwbuf[1] = 8;
+               break;
+       case 7000000:
+               bwbuf[1] = 7;
+               break;
+       case 6000000:
+               bwbuf[1] = 6;
+               break;
+       default:
+               return -EINVAL;
        }
 
        dvb_usb_generic_write(state->d,bwbuf,2);
@@ -134,11 +139,11 @@ static int dtt200u_fe_set_frontend(struct dvb_frontend* fe,
        return 0;
 }
 
-static int dtt200u_fe_get_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep)
+static int dtt200u_fe_get_frontend(struct dvb_frontend* fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct dtt200u_fe_state *state = fe->demodulator_priv;
-       memcpy(fep,&state->fep,sizeof(struct dvb_frontend_parameters));
+       memcpy(fep, &state->fep, sizeof(struct dtv_frontend_properties));
        return 0;
 }
 
@@ -172,9 +177,9 @@ error:
 }
 
 static struct dvb_frontend_ops dtt200u_fe_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "WideView USB DVB-T",
-               .type                   = FE_OFDM,
                .frequency_min          = 44250000,
                .frequency_max          = 867250000,
                .frequency_stepsize     = 250000,
index ba4a7517354ff96f52e94f4830c1c0a1c2efc137..ddf282f355b3c78f9f71608f4f445f196d68d3fc 100644 (file)
@@ -141,11 +141,17 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
                goto err_dmx_dev;
        }
 
-       dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
+       if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net,
+                                               &adap->demux.dmx)) < 0) {
+               err("dvb_net_init failed: error %d",ret);
+               goto err_net_init;
+       }
 
        adap->state |= DVB_USB_ADAP_STATE_DVB;
        return 0;
 
+err_net_init:
+       dvb_dmxdev_release(&adap->dmxdev);
 err_dmx_dev:
        dvb_dmx_release(&adap->demux);
 err_dmx:
index 2d08c9b5128a2759a60f04e7a3bf9e31cd23fd88..d390ddaa5a53f7a6daf37bf5d341c965814a6214 100644 (file)
 #define USB_PID_DIBCOM_STK807XPVR                      0x1f98
 #define USB_PID_DIBCOM_STK8096GP                        0x1fa0
 #define USB_PID_DIBCOM_NIM8096MD                        0x1fa8
+#define USB_PID_DIBCOM_TFE8096P                                0x1f9C
 #define USB_PID_DIBCOM_ANCHOR_2135_COLD                        0x2131
 #define USB_PID_DIBCOM_STK7770P                                0x1e80
 #define USB_PID_DIBCOM_NIM7090                         0x1bb2
 #define USB_PID_DIBCOM_TFE7090PVR                      0x1bb4
+#define USB_PID_DIBCOM_TFE7090E                                0x1bb7
+#define USB_PID_DIBCOM_TFE7790E                                0x1e6e
 #define USB_PID_DIBCOM_NIM9090M                                0x2383
 #define USB_PID_DIBCOM_NIM9090MD                       0x2384
 #define USB_PID_DPOSH_M9206_COLD                       0x9206
 #define USB_PID_GRANDTEC_DVBT_USB_WARM                 0x0fa1
 #define USB_PID_INTEL_CE9500                           0x9500
 #define USB_PID_ITETECH_IT9135                         0x9135
+#define USB_PID_ITETECH_IT9135_9005                    0x9005
+#define USB_PID_ITETECH_IT9135_9006                    0x9006
 #define USB_PID_KWORLD_399U                            0xe399
 #define USB_PID_KWORLD_399U_2                          0xe400
 #define USB_PID_KWORLD_395U                            0xe396
 #define USB_PID_TVWAY_PLUS                             0x0002
 #define USB_PID_SVEON_STV20                            0xe39d
 #define USB_PID_SVEON_STV22                            0xe401
+#define USB_PID_SVEON_STV22_IT9137                     0xe411
 #define USB_PID_AZUREWAVE_AZ6027                       0x3275
 #define USB_PID_TERRATEC_DVBS2CI_V1                    0x10a4
 #define USB_PID_TERRATEC_DVBS2CI_V2                    0x10ac
index ff941d20e6b7a1eeb7b2d4fd43740a9422c9f671..451c5a7adfb2da284c02593f29801e87909fe403 100644 (file)
@@ -1435,22 +1435,40 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        return 0;
 }
 
+enum dw2102_table_entry {
+       CYPRESS_DW2102,
+       CYPRESS_DW2101,
+       CYPRESS_DW2104,
+       TEVII_S650,
+       TERRATEC_CINERGY_S,
+       CYPRESS_DW3101,
+       TEVII_S630,
+       PROF_1100,
+       TEVII_S660,
+       PROF_7500,
+       GENIATECH_SU3000,
+       TERRATEC_CINERGY_S2,
+       TEVII_S480_1,
+       TEVII_S480_2,
+       X3M_SPC1400HD,
+};
+
 static struct usb_device_id dw2102_table[] = {
-       {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
-       {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
-       {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
-       {USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
-       {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
-       {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
-       {USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
-       {USB_DEVICE(0x3011, USB_PID_PROF_1100)},
-       {USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
-       {USB_DEVICE(0x3034, 0x7500)},
-       {USB_DEVICE(0x1f4d, 0x3000)},
-       {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)},
-       {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
-       {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
-       {USB_DEVICE(0x1f4d, 0x3100)},
+       [CYPRESS_DW2102] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
+       [CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
+       [CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
+       [TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
+       [TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
+       [CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
+       [TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
+       [PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)},
+       [TEVII_S660] = {USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
+       [PROF_7500] = {USB_DEVICE(0x3034, 0x7500)},
+       [GENIATECH_SU3000] = {USB_DEVICE(0x1f4d, 0x3000)},
+       [TERRATEC_CINERGY_S2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)},
+       [TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
+       [TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
+       [X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
        { }
 };
 
@@ -1610,15 +1628,15 @@ static struct dvb_usb_device_properties dw2102_properties = {
        .num_device_descs = 3,
        .devices = {
                {"DVBWorld DVB-S 2102 USB2.0",
-                       {&dw2102_table[0], NULL},
+                       {&dw2102_table[CYPRESS_DW2102], NULL},
                        {NULL},
                },
                {"DVBWorld DVB-S 2101 USB2.0",
-                       {&dw2102_table[1], NULL},
+                       {&dw2102_table[CYPRESS_DW2101], NULL},
                        {NULL},
                },
                {"TerraTec Cinergy S USB",
-                       {&dw2102_table[4], NULL},
+                       {&dw2102_table[TERRATEC_CINERGY_S], NULL},
                        {NULL},
                },
        }
@@ -1664,11 +1682,11 @@ static struct dvb_usb_device_properties dw2104_properties = {
        .num_device_descs = 2,
        .devices = {
                { "DVBWorld DW2104 USB2.0",
-                       {&dw2102_table[2], NULL},
+                       {&dw2102_table[CYPRESS_DW2104], NULL},
                        {NULL},
                },
                { "TeVii S650 USB2.0",
-                       {&dw2102_table[3], NULL},
+                       {&dw2102_table[TEVII_S650], NULL},
                        {NULL},
                },
        }
@@ -1715,7 +1733,7 @@ static struct dvb_usb_device_properties dw3101_properties = {
        .num_device_descs = 1,
        .devices = {
                { "DVBWorld DVB-C 3101 USB2.0",
-                       {&dw2102_table[5], NULL},
+                       {&dw2102_table[CYPRESS_DW3101], NULL},
                        {NULL},
                },
        }
@@ -1761,7 +1779,7 @@ static struct dvb_usb_device_properties s6x0_properties = {
        .num_device_descs = 1,
        .devices = {
                {"TeVii S630 USB",
-                       {&dw2102_table[6], NULL},
+                       {&dw2102_table[TEVII_S630], NULL},
                        {NULL},
                },
        }
@@ -1770,33 +1788,33 @@ static struct dvb_usb_device_properties s6x0_properties = {
 struct dvb_usb_device_properties *p1100;
 static struct dvb_usb_device_description d1100 = {
        "Prof 1100 USB ",
-       {&dw2102_table[7], NULL},
+       {&dw2102_table[PROF_1100], NULL},
        {NULL},
 };
 
 struct dvb_usb_device_properties *s660;
 static struct dvb_usb_device_description d660 = {
        "TeVii S660 USB",
-       {&dw2102_table[8], NULL},
+       {&dw2102_table[TEVII_S660], NULL},
        {NULL},
 };
 
 static struct dvb_usb_device_description d480_1 = {
        "TeVii S480.1 USB",
-       {&dw2102_table[12], NULL},
+       {&dw2102_table[TEVII_S480_1], NULL},
        {NULL},
 };
 
 static struct dvb_usb_device_description d480_2 = {
        "TeVii S480.2 USB",
-       {&dw2102_table[13], NULL},
+       {&dw2102_table[TEVII_S480_2], NULL},
        {NULL},
 };
 
 struct dvb_usb_device_properties *p7500;
 static struct dvb_usb_device_description d7500 = {
        "Prof 7500 USB DVB-S2",
-       {&dw2102_table[9], NULL},
+       {&dw2102_table[PROF_7500], NULL},
        {NULL},
 };
 
@@ -1842,15 +1860,15 @@ static struct dvb_usb_device_properties su3000_properties = {
        .num_device_descs = 3,
        .devices = {
                { "SU3000HD DVB-S USB2.0",
-                       { &dw2102_table[10], NULL },
+                       { &dw2102_table[GENIATECH_SU3000], NULL },
                        { NULL },
                },
                { "Terratec Cinergy S2 USB HD",
-                       { &dw2102_table[11], NULL },
+                       { &dw2102_table[TERRATEC_CINERGY_S2], NULL },
                        { NULL },
                },
                { "X3M TV SPC1400HD PCI",
-                       { &dw2102_table[14], NULL },
+                       { &dw2102_table[X3M_SPC1400HD], NULL },
                        { NULL },
                },
        }
@@ -1859,12 +1877,11 @@ static struct dvb_usb_device_properties su3000_properties = {
 static int dw2102_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
-       p1100 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+       p1100 = kmemdup(&s6x0_properties,
+                       sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
        if (!p1100)
                return -ENOMEM;
        /* copy default structure */
-       memcpy(p1100, &s6x0_properties,
-                       sizeof(struct dvb_usb_device_properties));
        /* fill only different fields */
        p1100->firmware = "dvb-usb-p1100.fw";
        p1100->devices[0] = d1100;
@@ -1872,13 +1889,12 @@ static int dw2102_probe(struct usb_interface *intf,
        p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
        p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach;
 
-       s660 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+       s660 = kmemdup(&s6x0_properties,
+                      sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
        if (!s660) {
                kfree(p1100);
                return -ENOMEM;
        }
-       memcpy(s660, &s6x0_properties,
-                       sizeof(struct dvb_usb_device_properties));
        s660->firmware = "dvb-usb-s660.fw";
        s660->num_device_descs = 3;
        s660->devices[0] = d660;
@@ -1886,14 +1902,13 @@ static int dw2102_probe(struct usb_interface *intf,
        s660->devices[2] = d480_2;
        s660->adapter->fe[0].frontend_attach = ds3000_frontend_attach;
 
-       p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+       p7500 = kmemdup(&s6x0_properties,
+                       sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
        if (!p7500) {
                kfree(p1100);
                kfree(s660);
                return -ENOMEM;
        }
-       memcpy(p7500, &s6x0_properties,
-                       sizeof(struct dvb_usb_device_properties));
        p7500->firmware = "dvb-usb-p7500.fw";
        p7500->devices[0] = d7500;
        p7500->rc.legacy.rc_map_table = rc_map_tbs_table;
index 015b4e8af1a58d950ca446f57da894c82ad9cea1..90a70c66a96e12a019654a6f3ff74934fefde85c 100644 (file)
@@ -282,23 +282,24 @@ static int jdvbt90502_set_property(struct dvb_frontend *fe,
        return r;
 }
 
-static int jdvbt90502_get_frontend(struct dvb_frontend *fe,
-                                  struct dvb_frontend_parameters *p)
+static int jdvbt90502_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        p->inversion = INVERSION_AUTO;
-       p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
-       p->u.ofdm.code_rate_HP = FEC_AUTO;
-       p->u.ofdm.code_rate_LP = FEC_AUTO;
-       p->u.ofdm.constellation = QAM_64;
-       p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
-       p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
-       p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;
+       p->bandwidth_hz = 6000000;
+       p->code_rate_HP = FEC_AUTO;
+       p->code_rate_LP = FEC_AUTO;
+       p->modulation = QAM_64;
+       p->transmission_mode = TRANSMISSION_MODE_AUTO;
+       p->guard_interval = GUARD_INTERVAL_AUTO;
+       p->hierarchy = HIERARCHY_AUTO;
        return 0;
 }
 
-static int jdvbt90502_set_frontend(struct dvb_frontend *fe,
-                                  struct dvb_frontend_parameters *p)
+static int jdvbt90502_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
        /**
         * NOTE: ignore all the parameters except frequency.
         *       others should be fixed to the proper value for ISDB-T,
@@ -438,14 +439,12 @@ error:
 }
 
 static struct dvb_frontend_ops jdvbt90502_ops = {
-
+       .delsys = { SYS_ISDBT },
        .info = {
                .name                   = "Comtech JDVBT90502 ISDB-T",
-               .type                   = FE_OFDM,
                .frequency_min          = 473000000, /* UHF 13ch, center */
                .frequency_max          = 767142857, /* UHF 62ch, center */
-               .frequency_stepsize     = JDVBT90502_PLL_CLK /
-                                                       JDVBT90502_PLL_DIVIDER,
+               .frequency_stepsize     = JDVBT90502_PLL_CLK / JDVBT90502_PLL_DIVIDER,
                .frequency_tolerance    = 0,
 
                /* NOTE: this driver ignores all parameters but frequency. */
index 5426267980c7567af09ed9646e58533e76e8df12..67957dd99ede5bf4bf70e06c287f56478728c5b1 100644 (file)
@@ -113,28 +113,12 @@ static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front
        return 0;
 }
 
-static int gp8psk_fe_set_property(struct dvb_frontend *fe,
-       struct dtv_property *tvp)
-{
-       deb_fe("%s(..)\n", __func__);
-       return 0;
-}
-
-static int gp8psk_fe_get_property(struct dvb_frontend *fe,
-       struct dtv_property *tvp)
-{
-       deb_fe("%s(..)\n", __func__);
-       return 0;
-}
-
-
-static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep)
+static int gp8psk_fe_set_frontend(struct dvb_frontend *fe)
 {
        struct gp8psk_fe_state *state = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        u8 cmd[10];
-       u32 freq = fep->frequency * 1000;
+       u32 freq = c->frequency * 1000;
        int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct);
 
        deb_fe("%s()\n", __func__);
@@ -342,9 +326,9 @@ success:
 
 
 static struct dvb_frontend_ops gp8psk_fe_ops = {
+       .delsys = { SYS_DVBS },
        .info = {
                .name                   = "Genpix DVB-S",
-               .type                   = FE_QPSK,
                .frequency_min          = 800000,
                .frequency_max          = 2250000,
                .frequency_stepsize     = 100,
@@ -366,8 +350,6 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
        .init = NULL,
        .sleep = NULL,
 
-       .set_property = gp8psk_fe_set_property,
-       .get_property = gp8psk_fe_get_property,
        .set_frontend = gp8psk_fe_set_frontend,
 
        .get_tune_settings = gp8psk_fe_get_tune_settings,
index 67094b879bb40d812600e33d0954fe5615280727..9f01cd7a6e3fbd6d67bf8be402b23b0413ee7ffc 100644 (file)
@@ -52,42 +52,59 @@ static int pid_filter;
 module_param_named(pid, pid_filter, int, 0644);
 MODULE_PARM_DESC(pid, "set default 0=on 1=off");
 
+static int dvb_usb_it913x_firmware;
+module_param_named(firmware, dvb_usb_it913x_firmware, int, 0644);
+MODULE_PARM_DESC(firmware, "set firmware 0=auto 1=IT9137 2=IT9135V1");
+
+
 int cmd_counter;
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 struct it913x_state {
        u8 id;
-};
-
-struct ite_config {
-       u8 chip_ver;
-       u16 chip_type;
-       u32 firmware;
-       u8 tuner_id_0;
-       u8 tuner_id_1;
-       u8 dual_mode;
+       struct ite_config it913x_config;
 };
 
 struct ite_config it913x_config;
 
+#define IT913X_RETRY   10
+#define IT913X_SND_TIMEOUT     100
+#define IT913X_RCV_TIMEOUT     200
+
 static int it913x_bulk_write(struct usb_device *dev,
                                u8 *snd, int len, u8 pipe)
 {
-       int ret, actual_l;
+       int ret, actual_l, i;
+
+       for (i = 0; i < IT913X_RETRY; i++) {
+               ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
+                               snd, len , &actual_l, IT913X_SND_TIMEOUT);
+               if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT)
+                       break;
+       }
+
+       if (len != actual_l && ret == 0)
+               ret = -EAGAIN;
 
-       ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
-                               snd, len , &actual_l, 100);
        return ret;
 }
 
 static int it913x_bulk_read(struct usb_device *dev,
                                u8 *rev, int len, u8 pipe)
 {
-       int ret, actual_l;
+       int ret, actual_l, i;
+
+       for (i = 0; i < IT913X_RETRY; i++) {
+               ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
+                                rev, len , &actual_l, IT913X_RCV_TIMEOUT);
+               if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT)
+                       break;
+       }
+
+       if (len != actual_l && ret == 0)
+               ret = -EAGAIN;
 
-       ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
-                                rev, len , &actual_l, 200);
        return ret;
 }
 
@@ -100,7 +117,7 @@ static u16 check_sum(u8 *p, u8 len)
        return ~sum;
 }
 
-static int it913x_io(struct usb_device *udev, u8 mode, u8 pro,
+static int it913x_usb_talk(struct usb_device *udev, u8 mode, u8 pro,
                        u8 cmd, u32 reg, u8 addr, u8 *data, u8 len)
 {
        int ret = 0, i, buf_size = 1;
@@ -159,22 +176,41 @@ static int it913x_io(struct usb_device *udev, u8 mode, u8 pro,
        buff[buf_size++] = (chk_sum & 0xff);
 
        ret = it913x_bulk_write(udev, buff, buf_size , 0x02);
+       if (ret < 0)
+               goto error;
 
-       ret |= it913x_bulk_read(udev, buff, (mode & 1) ?
+       ret = it913x_bulk_read(udev, buff, (mode & 1) ?
                        5 : len + 5 , 0x01);
+       if (ret < 0)
+               goto error;
 
        rlen = (mode & 0x1) ? 0x1 : len;
 
        if (mode & 1)
-               ret |= buff[2];
+               ret = buff[2];
        else
                memcpy(data, &buff[3], rlen);
 
        cmd_counter++;
 
-       kfree(buff);
+error: kfree(buff);
 
-       return (ret < 0) ? -ENODEV : 0;
+       return ret;
+}
+
+static int it913x_io(struct usb_device *udev, u8 mode, u8 pro,
+                       u8 cmd, u32 reg, u8 addr, u8 *data, u8 len)
+{
+       int ret, i;
+
+       for (i = 0; i < IT913X_RETRY; i++) {
+               ret = it913x_usb_talk(udev, mode, pro,
+                       cmd, reg, addr, data, len);
+               if (ret != -EAGAIN)
+                       break;
+       }
+
+       return ret;
 }
 
 static int it913x_wr_reg(struct usb_device *udev, u8 pro, u32 reg , u8 data)
@@ -223,15 +259,15 @@ static u32 it913x_query(struct usb_device *udev, u8 pro)
 
 static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
-       int ret = 0;
+       struct usb_device *udev = adap->dev->udev;
+       int ret;
        u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
 
        if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
                        return -EAGAIN;
        deb_info(1, "PID_C  (%02x)", onoff);
 
-       if (!onoff)
-               ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1);
+       ret = it913x_wr_reg(udev, pro, PID_EN, onoff);
 
        mutex_unlock(&adap->dev->i2c_mutex);
        return ret;
@@ -241,27 +277,20 @@ static int it913x_pid_filter(struct dvb_usb_adapter *adap,
                int index, u16 pid, int onoff)
 {
        struct usb_device *udev = adap->dev->udev;
-       int ret = 0;
+       int ret;
        u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
 
-       if (pid_filter > 0)
-               return 0;
-
        if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
                        return -EAGAIN;
        deb_info(1, "PID_F  (%02x)", onoff);
-       if (onoff) {
-               ret = it913x_wr_reg(udev, pro, PID_EN, 0x1);
-
-               ret |= it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff));
 
-               ret |= it913x_wr_reg(udev, pro, PID_MSB, (u8)(pid >> 8));
+       ret = it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff));
 
-               ret |= it913x_wr_reg(udev, pro, PID_INX_EN, (u8)onoff);
+       ret |= it913x_wr_reg(udev, pro, PID_MSB, (u8)(pid >> 8));
 
-               ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f));
+       ret |= it913x_wr_reg(udev, pro, PID_INX_EN, (u8)onoff);
 
-       }
+       ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f));
 
        mutex_unlock(&adap->dev->i2c_mutex);
        return 0;
@@ -337,15 +366,73 @@ static int it913x_rc_query(struct dvb_usb_device *d)
 
        if ((ibuf[2] + ibuf[3]) == 0xff) {
                key = ibuf[2];
-               key += ibuf[0] << 8;
-               deb_info(1, "INT Key =%08x", key);
+               key += ibuf[0] << 16;
+               key += ibuf[1] << 8;
+               deb_info(1, "NEC Extended Key =%08x", key);
                if (d->rc_dev != NULL)
                        rc_keydown(d->rc_dev, key, 0);
        }
+
        mutex_unlock(&d->i2c_mutex);
 
        return ret;
 }
+
+/* Firmware sets raw */
+const char fw_it9135_v1[] = "dvb-usb-it9135-01.fw";
+const char fw_it9135_v2[] = "dvb-usb-it9135-02.fw";
+const char fw_it9137[] = "dvb-usb-it9137-01.fw";
+
+static int ite_firmware_select(struct usb_device *udev,
+       struct dvb_usb_device_properties *props)
+{
+       int sw;
+       /* auto switch */
+       if (le16_to_cpu(udev->descriptor.idProduct) ==
+                       USB_PID_ITETECH_IT9135)
+               sw = IT9135_V1_FW;
+       else if (le16_to_cpu(udev->descriptor.idProduct) ==
+                       USB_PID_ITETECH_IT9135_9005)
+               sw = IT9135_V1_FW;
+       else if (le16_to_cpu(udev->descriptor.idProduct) ==
+                       USB_PID_ITETECH_IT9135_9006) {
+               sw = IT9135_V2_FW;
+               if (it913x_config.tuner_id_0 == 0)
+                       it913x_config.tuner_id_0 = IT9135_60;
+       } else
+               sw = IT9137_FW;
+
+       /* force switch */
+       if (dvb_usb_it913x_firmware != IT9135_AUTO)
+               sw = dvb_usb_it913x_firmware;
+
+       switch (sw) {
+       case IT9135_V1_FW:
+               it913x_config.firmware_ver = 1;
+               it913x_config.adc_x2 = 1;
+               props->firmware = fw_it9135_v1;
+               break;
+       case IT9135_V2_FW:
+               it913x_config.firmware_ver = 1;
+               it913x_config.adc_x2 = 1;
+               props->firmware = fw_it9135_v2;
+               break;
+       case IT9137_FW:
+       default:
+               it913x_config.firmware_ver = 0;
+               it913x_config.adc_x2 = 0;
+               props->firmware = fw_it9137;
+       }
+
+       return 0;
+}
+
+#define TS_MPEG_PKT_SIZE       188
+#define EP_LOW                 21
+#define TS_BUFFER_SIZE_PID     (EP_LOW*TS_MPEG_PKT_SIZE)
+#define EP_HIGH                        348
+#define TS_BUFFER_SIZE_MAX     (EP_HIGH*TS_MPEG_PKT_SIZE)
+
 static int it913x_identify_state(struct usb_device *udev,
                struct dvb_usb_device_properties *props,
                struct dvb_usb_device_description **desc,
@@ -359,6 +446,19 @@ static int it913x_identify_state(struct usb_device *udev,
        /* checnk for dual mode */
        it913x_config.dual_mode =  it913x_read_reg(udev, 0x49c5);
 
+       if (udev->speed != USB_SPEED_HIGH) {
+               props->adapter[0].fe[0].pid_filter_count = 5;
+               info("USB 1 low speed mode - connect to USB 2 port");
+               if (pid_filter > 0)
+                       pid_filter = 0;
+               if (it913x_config.dual_mode) {
+                       it913x_config.dual_mode = 0;
+                       info("Dual mode not supported in USB 1");
+               }
+       } else /* For replugging */
+               if(props->adapter[0].fe[0].pid_filter_count == 5)
+                       props->adapter[0].fe[0].pid_filter_count = 31;
+
        /* TODO different remotes */
        remote = it913x_read_reg(udev, 0x49ac); /* Remote */
        if (remote == 0)
@@ -370,6 +470,28 @@ static int it913x_identify_state(struct usb_device *udev,
        info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode
                , remote, it913x_config.tuner_id_0);
 
+       /* Select Stream Buffer Size and pid filter option*/
+       if (pid_filter) {
+               props->adapter[0].fe[0].stream.u.bulk.buffersize =
+                       TS_BUFFER_SIZE_MAX;
+               props->adapter[0].fe[0].caps &=
+                       ~DVB_USB_ADAP_NEED_PID_FILTERING;
+       } else
+               props->adapter[0].fe[0].stream.u.bulk.buffersize =
+                       TS_BUFFER_SIZE_PID;
+
+       if (it913x_config.dual_mode) {
+               props->adapter[1].fe[0].stream.u.bulk.buffersize =
+                       props->adapter[0].fe[0].stream.u.bulk.buffersize;
+               props->num_adapters = 2;
+               if (pid_filter)
+                       props->adapter[1].fe[0].caps =
+                               props->adapter[0].fe[0].caps;
+       } else
+               props->num_adapters = 1;
+
+       ret = ite_firmware_select(udev, props);
+
        if (firm_no > 0) {
                *cold = 0;
                return 0;
@@ -391,18 +513,22 @@ static int it913x_identify_state(struct usb_device *udev,
                                ret = it913x_wr_reg(udev, DEV_0,
                                        GPIOH1_O, 0x0);
                }
-               props->num_adapters = 2;
-       } else
-               props->num_adapters = 1;
+       }
 
        reg = it913x_read_reg(udev, IO_MUX_POWER_CLK);
 
        if (it913x_config.dual_mode) {
                ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR);
-               ret |= it913x_wr_reg(udev, DEV_0,  CLK_O_EN, 0x1);
+               if (it913x_config.firmware_ver == 1)
+                       ret |= it913x_wr_reg(udev, DEV_0,  0xcfff, 0x1);
+               else
+                       ret |= it913x_wr_reg(udev, DEV_0,  CLK_O_EN, 0x1);
        } else {
                ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, 0x0);
-               ret |= it913x_wr_reg(udev, DEV_0,  CLK_O_EN, 0x0);
+               if (it913x_config.firmware_ver == 1)
+                       ret |= it913x_wr_reg(udev, DEV_0,  0xcfff, 0x0);
+               else
+                       ret |= it913x_wr_reg(udev, DEV_0,  CLK_O_EN, 0x0);
        }
 
        *cold = 1;
@@ -428,35 +554,45 @@ static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        return ret;
 }
 
-
 static int it913x_download_firmware(struct usb_device *udev,
                                        const struct firmware *fw)
 {
-       int ret = 0, i;
-       u8 packet_size, dlen;
+       int ret = 0, i = 0, pos = 0;
+       u8 packet_size, min_pkt;
        u8 *fw_data;
 
-       packet_size = 0x29;
-
        ret = it913x_wr_reg(udev, DEV_0,  I2C_CLK, I2C_CLK_100);
 
        info("FRM Starting Firmware Download");
-       /* This uses scatter write firmware headers follow */
-       /* 03 XX 00     XX = chip number? */ 
-
-       for (i = 0; i < fw->size; i += packet_size) {
-                       if (i > 0)
-                               packet_size = 0x39;
-                       fw_data = (u8 *)(fw->data + i);
-                       dlen = ((i + packet_size) > fw->size)
-                               ? (fw->size - i) : packet_size;
-                       ret |= it913x_io(udev, WRITE_DATA, DEV_0,
-                               CMD_SCATTER_WRITE, 0, 0, fw_data, dlen);
-                       udelay(1000);
+
+       /* Multi firmware loader */
+       /* This uses scatter write firmware headers */
+       /* The firmware must start with 03 XX 00 */
+       /* and be the extact firmware length */
+
+       if (it913x_config.chip_ver == 2)
+               min_pkt = 0x11;
+       else
+               min_pkt = 0x19;
+
+       while (i <= fw->size) {
+               if (((fw->data[i] == 0x3) && (fw->data[i + 2] == 0x0))
+                       || (i == fw->size)) {
+                       packet_size = i - pos;
+                       if ((packet_size > min_pkt) || (i == fw->size)) {
+                               fw_data = (u8 *)(fw->data + pos);
+                               pos += packet_size;
+                               if (packet_size > 0)
+                                       ret |= it913x_io(udev, WRITE_DATA,
+                                               DEV_0, CMD_SCATTER_WRITE, 0,
+                                               0, fw_data, packet_size);
+                               udelay(1000);
+                       }
+               }
+               i++;
        }
 
-       ret |= it913x_io(udev, WRITE_CMD, DEV_0,
-                       CMD_BOOT, 0, 0, NULL, 0);
+       ret |= it913x_io(udev, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0);
 
        msleep(100);
 
@@ -474,12 +610,17 @@ static int it913x_download_firmware(struct usb_device *udev,
        /* Tuner function */
        if (it913x_config.dual_mode)
                ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0);
-
-       ret |= it913x_wr_reg(udev, DEV_0,  PADODPU, 0x0);
-       ret |= it913x_wr_reg(udev, DEV_0,  AGC_O_D, 0x0);
-       if (it913x_config.dual_mode) {
-               ret |= it913x_wr_reg(udev, DEV_1,  PADODPU, 0x0);
-               ret |= it913x_wr_reg(udev, DEV_1,  AGC_O_D, 0x0);
+       else
+               ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0x68);
+
+       if ((it913x_config.chip_ver == 1) &&
+               (it913x_config.chip_type == 0x9135)) {
+               ret |= it913x_wr_reg(udev, DEV_0,  PADODPU, 0x0);
+               ret |= it913x_wr_reg(udev, DEV_0,  AGC_O_D, 0x0);
+               if (it913x_config.dual_mode) {
+                       ret |= it913x_wr_reg(udev, DEV_1,  PADODPU, 0x0);
+                       ret |= it913x_wr_reg(udev, DEV_1,  AGC_O_D, 0x0);
+               }
        }
 
        return (ret < 0) ? -ENODEV : 0;
@@ -500,32 +641,23 @@ static int it913x_name(struct dvb_usb_adapter *adap)
 static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
 {
        struct usb_device *udev = adap->dev->udev;
+       struct it913x_state *st = adap->dev->priv;
        int ret = 0;
-       u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK);
        u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5);
-       u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize;
-       u8 tuner_id, tuner_type;
+       u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize / 4;
+       u8 pkt_size = 0x80;
+
+       if (adap->dev->udev->speed != USB_SPEED_HIGH)
+               pkt_size = 0x10;
+
+       it913x_config.adf = it913x_read_reg(udev, IO_MUX_POWER_CLK);
 
        if (adap->id == 0)
-               tuner_id = it913x_config.tuner_id_0;
-       else
-               tuner_id = it913x_config.tuner_id_1;
-
-       /* TODO we always use IT9137 possible references here*/
-       /* Documentation suggests don't care */
-       switch (tuner_id) {
-       case 0x51:
-       case 0x52:
-       case 0x60:
-       case 0x61:
-       case 0x62:
-       default:
-       case 0x38:
-               tuner_type = IT9137;
-       }
+               memcpy(&st->it913x_config, &it913x_config,
+                       sizeof(struct ite_config));
 
        adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach,
-               &adap->dev->i2c_adap, adap_addr, adf, tuner_type);
+               &adap->dev->i2c_adap, adap_addr, &st->it913x_config);
 
        if (adap->id == 0 && adap->fe_adap[0].fe) {
                ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1);
@@ -536,13 +668,13 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap)
                ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_LSB,
                                        ep_size & 0xff);
                ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8);
-               ret = it913x_wr_reg(udev, DEV_0, EP4_MAX_PKT, 0x80);
+               ret = it913x_wr_reg(udev, DEV_0, EP4_MAX_PKT, pkt_size);
        } else if (adap->id == 1 && adap->fe_adap[0].fe) {
                ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x6f);
                ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_LSB,
                                        ep_size & 0xff);
                ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8);
-               ret = it913x_wr_reg(udev, DEV_0, EP5_MAX_PKT, 0x80);
+               ret = it913x_wr_reg(udev, DEV_0, EP5_MAX_PKT, pkt_size);
                ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_EN, 0x1);
                ret = it913x_wr_reg(udev, DEV_1_DMOD, MP2IF_SERIAL, 0x1);
                ret = it913x_wr_reg(udev, DEV_1, TOP_HOSTB_SER_MODE, 0x1);
@@ -582,6 +714,9 @@ static int it913x_probe(struct usb_interface *intf,
 static struct usb_device_id it913x_table[] = {
        { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) },
        { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135) },
+       { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137) },
+       { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005) },
+       { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006) },
        {}              /* Terminating entry */
 };
 
@@ -614,8 +749,8 @@ static struct dvb_usb_device_properties it913x_properties = {
                                .endpoint = 0x04,
                                .u = {/* Keep Low if PID filter on */
                                        .bulk = {
-                                               .buffersize = 3584,
-
+                                       .buffersize =
+                                               TS_BUFFER_SIZE_PID,
                                        }
                                }
                        }
@@ -639,8 +774,8 @@ static struct dvb_usb_device_properties it913x_properties = {
                                .endpoint = 0x05,
                                .u = {
                                        .bulk = {
-                                               .buffersize = 3584,
-
+                                               .buffersize =
+                                                       TS_BUFFER_SIZE_PID,
                                        }
                                }
                        }
@@ -654,10 +789,10 @@ static struct dvb_usb_device_properties it913x_properties = {
                .rc_query       = it913x_rc_query,
                .rc_interval    = IT913X_POLL,
                .allowed_protos = RC_TYPE_NEC,
-               .rc_codes       = RC_MAP_KWORLD_315U,
+               .rc_codes       = RC_MAP_MSI_DIGIVOX_III,
        },
        .i2c_algo         = &it913x_i2c_algo,
-       .num_device_descs = 2,
+       .num_device_descs = 5,
        .devices = {
                {   "Kworld UB499-2T T09(IT9137)",
                        { &it913x_table[0], NULL },
@@ -665,6 +800,15 @@ static struct dvb_usb_device_properties it913x_properties = {
                {   "ITE 9135 Generic",
                        { &it913x_table[1], NULL },
                        },
+               {   "Sveon STV22 Dual DVB-T HDTV(IT9137)",
+                       { &it913x_table[2], NULL },
+                       },
+               {   "ITE 9135(9005) Generic",
+                       { &it913x_table[3], NULL },
+                       },
+               {   "ITE 9135(9006) Generic",
+                       { &it913x_table[4], NULL },
+                       },
        }
 };
 
@@ -679,5 +823,5 @@ module_usb_driver(it913x_driver);
 
 MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
 MODULE_DESCRIPTION("it913x USB 2 Driver");
-MODULE_VERSION("1.07");
+MODULE_VERSION("1.22");
 MODULE_LICENSE("GPL");
index 1a876a65ed56d6df38087cef69d7a5301fe2e325..b3fe05bbffc955bcbd45ea9830729f7bd22a6d53 100644 (file)
@@ -388,8 +388,7 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
        deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__,
                pid, index, onoff);
 
-       if (onoff)
-               if (!pid_filter) {
+       if (onoff) {
                        ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
                        if (ret < 0)
                                return -EAGAIN;
@@ -654,6 +653,9 @@ static int lme2510_identify_state(struct usb_device *udev,
                struct dvb_usb_device_description **desc,
                int *cold)
 {
+       if (pid_filter > 0)
+               props->adapter[0].fe[0].caps &=
+                       ~DVB_USB_ADAP_NEED_PID_FILTERING;
        *cold = 0;
        return 0;
 }
@@ -1293,5 +1295,5 @@ module_usb_driver(lme2510_driver);
 
 MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
 MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.90");
+MODULE_VERSION("1.91");
 MODULE_LICENSE("GPL");
index d1f58371c7119209c24a74bafb54a328a530fdb7..d83df4bb72d352308f8baff11e7fe6ad72a63026 100644 (file)
@@ -102,8 +102,8 @@ fail:
 }
 
 static
-int mxl1x1sf_demod_get_tps_constellation(struct mxl111sf_demod_state *state,
-                                        fe_modulation_t *constellation)
+int mxl1x1sf_demod_get_tps_modulation(struct mxl111sf_demod_state *state,
+                                        fe_modulation_t *modulation)
 {
        u8 val;
        int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val);
@@ -113,13 +113,13 @@ int mxl1x1sf_demod_get_tps_constellation(struct mxl111sf_demod_state *state,
 
        switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) {
        case 0:
-               *constellation = QPSK;
+               *modulation = QPSK;
                break;
        case 1:
-               *constellation = QAM_16;
+               *modulation = QAM_16;
                break;
        case 2:
-               *constellation = QAM_64;
+               *modulation = QAM_64;
                break;
        }
 fail:
@@ -284,8 +284,7 @@ static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state)
 
 /* ------------------------------------------------------------------------ */
 
-static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe,
-                                      struct dvb_frontend_parameters *param)
+static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe)
 {
        struct mxl111sf_demod_state *state = fe->demodulator_priv;
        int ret = 0;
@@ -303,7 +302,7 @@ static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe,
        mxl_dbg("()");
 
        if (fe->ops.tuner_ops.set_params) {
-               ret = fe->ops.tuner_ops.set_params(fe, param);
+               ret = fe->ops.tuner_ops.set_params(fe);
                if (mxl_fail(ret))
                        goto fail;
                msleep(50);
@@ -481,13 +480,13 @@ static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe,
                                               u16 *signal_strength)
 {
        struct mxl111sf_demod_state *state = fe->demodulator_priv;
-       fe_modulation_t constellation;
+       fe_modulation_t modulation;
        u16 snr;
 
        mxl111sf_demod_calc_snr(state, &snr);
-       mxl1x1sf_demod_get_tps_constellation(state, &constellation);
+       mxl1x1sf_demod_get_tps_modulation(state, &modulation);
 
-       switch (constellation) {
+       switch (modulation) {
        case QPSK:
                *signal_strength = (snr >= 1300) ?
                        min(65535, snr * 44) : snr * 38;
@@ -508,9 +507,9 @@ static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe,
        return 0;
 }
 
-static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe,
-                                      struct dvb_frontend_parameters *p)
+static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct mxl111sf_demod_state *state = fe->demodulator_priv;
 
        mxl_dbg("()");
@@ -518,18 +517,18 @@ static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe,
        p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF;
 #endif
        if (fe->ops.tuner_ops.get_bandwidth)
-               fe->ops.tuner_ops.get_bandwidth(fe, &p->u.ofdm.bandwidth);
+               fe->ops.tuner_ops.get_bandwidth(fe, &p->bandwidth_hz);
        if (fe->ops.tuner_ops.get_frequency)
                fe->ops.tuner_ops.get_frequency(fe, &p->frequency);
-       mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_HP);
-       mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_LP);
-       mxl1x1sf_demod_get_tps_constellation(state, &p->u.ofdm.constellation);
+       mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_HP);
+       mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_LP);
+       mxl1x1sf_demod_get_tps_modulation(state, &p->modulation);
        mxl1x1sf_demod_get_tps_guard_fft_mode(state,
-                                             &p->u.ofdm.transmission_mode);
+                                             &p->transmission_mode);
        mxl1x1sf_demod_get_tps_guard_interval(state,
-                                             &p->u.ofdm.guard_interval);
+                                             &p->guard_interval);
        mxl1x1sf_demod_get_tps_hierarchy(state,
-                                        &p->u.ofdm.hierarchy_information);
+                                        &p->hierarchy);
 
        return 0;
 }
@@ -551,10 +550,9 @@ static void mxl111sf_demod_release(struct dvb_frontend *fe)
 }
 
 static struct dvb_frontend_ops mxl111sf_demod_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name               = "MaxLinear MxL111SF DVB-T demodulator",
-               .type               = FE_OFDM,
                .frequency_min      = 177000000,
                .frequency_max      = 858000000,
                .frequency_stepsize = 166666,
index a6341058c4e71da379f0774bed2f2a985d31534f..72db6eef4b9c32f69140992216dd954b821c6e4c 100644 (file)
@@ -38,6 +38,8 @@ struct mxl111sf_tuner_state {
 
        struct mxl111sf_tuner_config *cfg;
 
+       enum mxl_if_freq if_freq;
+
        u32 frequency;
        u32 bandwidth;
 };
@@ -186,7 +188,10 @@ static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state)
        ctrl = iffcw & 0x00ff;
 #endif
        ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl);
-       mxl_fail(ret);
+       if (mxl_fail(ret))
+               goto fail;
+
+       state->if_freq = state->cfg->if_freq;
 fail:
        return ret;
 }
@@ -267,55 +272,49 @@ static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state,
 
 /* ------------------------------------------------------------------------ */
 
-static int mxl111sf_tuner_set_params(struct dvb_frontend *fe,
-                                    struct dvb_frontend_parameters *params)
+static int mxl111sf_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 delsys  = c->delivery_system;
        struct mxl111sf_tuner_state *state = fe->tuner_priv;
        int ret;
        u8 bw;
 
        mxl_dbg("()");
 
-       if (fe->ops.info.type == FE_ATSC) {
-               switch (params->u.vsb.modulation) {
-               case VSB_8:
-               case VSB_16:
-                       bw = 0; /* ATSC */
-                       break;
-               case QAM_64:
-               case QAM_256:
-                       bw = 1; /* US CABLE */
-                       break;
-               default:
-                       err("%s: modulation not set!", __func__);
-                       return -EINVAL;
-               }
-       } else if (fe->ops.info.type == FE_OFDM) {
-               switch (params->u.ofdm.bandwidth) {
-               case BANDWIDTH_6_MHZ:
+       switch (delsys) {
+       case SYS_ATSC:
+               bw = 0; /* ATSC */
+               break;
+       case SYS_DVBC_ANNEX_B:
+               bw = 1; /* US CABLE */
+               break;
+       case SYS_DVBT:
+               switch (c->bandwidth_hz) {
+               case 6000000:
                        bw = 6;
                        break;
-               case BANDWIDTH_7_MHZ:
+               case 7000000:
                        bw = 7;
                        break;
-               case BANDWIDTH_8_MHZ:
+               case 8000000:
                        bw = 8;
                        break;
                default:
                        err("%s: bandwidth not set!", __func__);
                        return -EINVAL;
                }
-       } else {
+               break;
+       default:
                err("%s: modulation type not supported!", __func__);
                return -EINVAL;
        }
-       ret = mxl1x1sf_tune_rf(fe, params->frequency, bw);
+       ret = mxl1x1sf_tune_rf(fe, c->frequency, bw);
        if (mxl_fail(ret))
                goto fail;
 
-       state->frequency = params->frequency;
-       state->bandwidth = (fe->ops.info.type == FE_OFDM) ?
-               params->u.ofdm.bandwidth : 0;
+       state->frequency = c->frequency;
+       state->bandwidth = c->bandwidth_hz;
 fail:
        return ret;
 }
@@ -407,6 +406,54 @@ static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
        return 0;
 }
 
+static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe,
+                                          u32 *frequency)
+{
+       struct mxl111sf_tuner_state *state = fe->tuner_priv;
+
+       *frequency = 0;
+
+       switch (state->if_freq) {
+       case MXL_IF_4_0:   /* 4.0   MHz */
+               *frequency = 4000000;
+               break;
+       case MXL_IF_4_5:   /* 4.5   MHz */
+               *frequency = 4500000;
+               break;
+       case MXL_IF_4_57:  /* 4.57  MHz */
+               *frequency = 4570000;
+               break;
+       case MXL_IF_5_0:   /* 5.0   MHz */
+               *frequency = 5000000;
+               break;
+       case MXL_IF_5_38:  /* 5.38  MHz */
+               *frequency = 5380000;
+               break;
+       case MXL_IF_6_0:   /* 6.0   MHz */
+               *frequency = 6000000;
+               break;
+       case MXL_IF_6_28:  /* 6.28  MHz */
+               *frequency = 6280000;
+               break;
+       case MXL_IF_7_2:   /* 7.2   MHz */
+               *frequency = 7200000;
+               break;
+       case MXL_IF_35_25: /* 35.25 MHz */
+               *frequency = 35250000;
+               break;
+       case MXL_IF_36:    /* 36    MHz */
+               *frequency = 36000000;
+               break;
+       case MXL_IF_36_15: /* 36.15 MHz */
+               *frequency = 36150000;
+               break;
+       case MXL_IF_44:    /* 44    MHz */
+               *frequency = 44000000;
+               break;
+       }
+       return 0;
+}
+
 static int mxl111sf_tuner_release(struct dvb_frontend *fe)
 {
        struct mxl111sf_tuner_state *state = fe->tuner_priv;
@@ -436,6 +483,7 @@ static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = {
        .get_rf_strength   = mxl111sf_get_rf_strength,
        .get_frequency     = mxl111sf_tuner_get_frequency,
        .get_bandwidth     = mxl111sf_tuner_get_bandwidth,
+       .get_if_frequency  = mxl111sf_tuner_get_if_frequency,
        .release           = mxl111sf_tuner_release,
 };
 
index 825a8b242e09b41ac6a62cc8881a80de9e6cead7..38ef0253d3b5b9c79aa1daade821f241f90e6800 100644 (file)
@@ -758,6 +758,7 @@ 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,                       \
@@ -772,6 +773,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table);
 
 /* 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,                       \
@@ -788,6 +790,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table);
        }
 
 #define MXL111SF_EP6_BULK_STREAMING_CONFIG             \
+       .size_of_priv = sizeof(struct mxl111sf_adap_state), \
        .streaming_ctrl = mxl111sf_ep6_streaming_ctrl,  \
        .stream = {                                     \
                .type = USB_BULK,                       \
@@ -802,6 +805,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table);
 
 /* 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,                       \
@@ -839,8 +843,6 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = {
                .fe_ioctl_override = mxl111sf_fe_ioctl_override,
                .num_frontends = 1,
                .fe = {{
-                       .size_of_priv     = sizeof(struct mxl111sf_adap_state),
-
                        .frontend_attach  = mxl111sf_attach_demod,
                        .tuner_attach     = mxl111sf_attach_tuner,
 
@@ -883,8 +885,6 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = {
                .fe_ioctl_override = mxl111sf_fe_ioctl_override,
                .num_frontends = 1,
                .fe = {{
-                       .size_of_priv     = sizeof(struct mxl111sf_adap_state),
-
                        .frontend_attach  = mxl111sf_attach_demod,
                        .tuner_attach     = mxl111sf_attach_tuner,
 
@@ -927,16 +927,12 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = {
                .fe_ioctl_override = mxl111sf_fe_ioctl_override,
                .num_frontends = 2,
                .fe = {{
-                       .size_of_priv     = sizeof(struct mxl111sf_adap_state),
-
                        .frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
                        .tuner_attach     = mxl111sf_attach_tuner,
 
                        MXL111SF_EP6_BULK_STREAMING_CONFIG,
                },
                {
-                       .size_of_priv     = sizeof(struct mxl111sf_adap_state),
-
                        .frontend_attach  = mxl111sf_attach_demod,
                        .tuner_attach     = mxl111sf_attach_tuner,
 
@@ -992,16 +988,12 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
                .fe_ioctl_override = mxl111sf_fe_ioctl_override,
                .num_frontends = 2,
                .fe = {{
-                       .size_of_priv     = sizeof(struct mxl111sf_adap_state),
-
                        .frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
                        .tuner_attach     = mxl111sf_attach_tuner,
 
                        MXL111SF_EP6_ISOC_STREAMING_CONFIG,
                },
                {
-                       .size_of_priv     = sizeof(struct mxl111sf_adap_state),
-
                        .frontend_attach  = mxl111sf_attach_demod,
                        .tuner_attach     = mxl111sf_attach_tuner,
 
index 56acf8e55d506fd05517d4586f847e31b0b92974..e53a1061cb8e4451eeda3251376c9c0461106761 100644 (file)
@@ -75,10 +75,18 @@ static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
                u8 *wbuf, int wlen, u8 *rbuf, int rlen)
 {
        struct ttusb2_state *st = d->priv;
-       u8 s[wlen+4],r[64] = { 0 };
+       u8 *s, *r = NULL;
        int ret = 0;
 
-       memset(s,0,wlen+4);
+       s = kzalloc(wlen+4, GFP_KERNEL);
+       if (!s)
+               return -ENOMEM;
+
+       r = kzalloc(64, GFP_KERNEL);
+       if (!r) {
+               kfree(s);
+               return -ENOMEM;
+       }
 
        s[0] = 0xaa;
        s[1] = ++st->id;
@@ -94,12 +102,17 @@ static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
                r[2] != cmd ||
                (rlen > 0 && r[3] != rlen)) {
                warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]);
+               kfree(s);
+               kfree(r);
                return -EIO;
        }
 
        if (rlen > 0)
                memcpy(rbuf, &r[4], rlen);
 
+       kfree(s);
+       kfree(r);
+
        return 0;
 }
 
@@ -384,7 +397,7 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
 
                memcpy(&obuf[3], msg[i].buf, msg[i].len);
 
-               if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) {
+               if (ttusb2_msg(d, CMD_I2C_XFER, obuf, obuf[1]+3, ibuf, obuf[2] + 3) < 0) {
                        err("i2c transfer failed.");
                        break;
                }
index 2bb8d4cc8d881765d76faa6b7fc7533672d80dde..5eab468dd9046adbe76738c157c60efd1bd66b76 100644 (file)
@@ -135,9 +135,9 @@ static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front
        return 0;
 }
 
-static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep)
+static int vp702x_fe_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct vp702x_fe_state *st = fe->demodulator_priv;
        struct vp702x_device_state *dst = st->d->priv;
        u32 freq = fep->frequency/1000;
@@ -155,14 +155,14 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
        cmd[1] =  freq       & 0xff;
        cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */
 
-       sr = (u64) (fep->u.qpsk.symbol_rate/1000) << 20;
+       sr = (u64) (fep->symbol_rate/1000) << 20;
        do_div(sr,88000);
        cmd[3] = (sr >> 12) & 0xff;
        cmd[4] = (sr >> 4)  & 0xff;
        cmd[5] = (sr << 4)  & 0xf0;
 
        deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n",
-                       fep->frequency,freq,freq, fep->u.qpsk.symbol_rate,
+                       fep->frequency, freq, freq, fep->symbol_rate,
                        (unsigned long) sr, (unsigned long) sr);
 
 /*     if (fep->inversion == INVERSION_ON)
@@ -171,7 +171,7 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
        if (st->voltage == SEC_VOLTAGE_18)
                cmd[6] |= 0x40;
 
-/*     if (fep->u.qpsk.symbol_rate > 8000000)
+/*     if (fep->symbol_rate > 8000000)
                cmd[6] |= 0x20;
 
        if (fep->frequency < 1531000)
@@ -211,13 +211,6 @@ static int vp702x_fe_sleep(struct dvb_frontend *fe)
        return 0;
 }
 
-static int vp702x_fe_get_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep)
-{
-       deb_fe("%s\n",__func__);
-       return 0;
-}
-
 static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
                                    struct dvb_diseqc_master_cmd *m)
 {
@@ -350,9 +343,9 @@ error:
 
 
 static struct dvb_frontend_ops vp702x_fe_ops = {
+       .delsys = { SYS_DVBS },
        .info = {
                .name           = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S",
-               .type           = FE_QPSK,
                .frequency_min       = 950000,
                .frequency_max       = 2150000,
                .frequency_stepsize  = 1000,   /* kHz for QPSK frontends */
@@ -371,7 +364,6 @@ static struct dvb_frontend_ops vp702x_fe_ops = {
        .sleep = vp702x_fe_sleep,
 
        .set_frontend = vp702x_fe_set_frontend,
-       .get_frontend = vp702x_fe_get_frontend,
        .get_tune_settings = vp702x_fe_get_tune_settings,
 
        .read_status = vp702x_fe_read_status,
index 8452eef90322be8d97e9a08c81881cc47f6cf311..b8825b18c003a32c52066f616b26ef0b95758f21 100644 (file)
@@ -103,9 +103,9 @@ static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front
        return 0;
 }
 
-static int vp7045_fe_set_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep)
+static int vp7045_fe_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct vp7045_fe_state *state = fe->demodulator_priv;
        u8 buf[5];
        u32 freq = fep->frequency / 1000;
@@ -115,25 +115,24 @@ static int vp7045_fe_set_frontend(struct dvb_frontend* fe,
        buf[2] =  freq        & 0xff;
        buf[3] = 0;
 
-       switch (fep->u.ofdm.bandwidth) {
-               case BANDWIDTH_8_MHZ: buf[4] = 8; break;
-               case BANDWIDTH_7_MHZ: buf[4] = 7; break;
-               case BANDWIDTH_6_MHZ: buf[4] = 6; break;
-               case BANDWIDTH_AUTO: return -EOPNOTSUPP;
-               default:
-                       return -EINVAL;
+       switch (fep->bandwidth_hz) {
+       case 8000000:
+               buf[4] = 8;
+               break;
+       case 7000000:
+               buf[4] = 7;
+               break;
+       case 6000000:
+               buf[4] = 6;
+               break;
+       default:
+               return -EINVAL;
        }
 
        vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200);
        return 0;
 }
 
-static int vp7045_fe_get_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep)
-{
-       return 0;
-}
-
 static void vp7045_fe_release(struct dvb_frontend* fe)
 {
        struct vp7045_fe_state *state = fe->demodulator_priv;
@@ -159,9 +158,9 @@ error:
 
 
 static struct dvb_frontend_ops vp7045_fe_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "Twinhan VP7045/46 USB DVB-T",
-               .type                   = FE_OFDM,
                .frequency_min          = 44250000,
                .frequency_max          = 867250000,
                .frequency_stepsize     = 1000,
@@ -181,7 +180,6 @@ static struct dvb_frontend_ops vp7045_fe_ops = {
        .sleep = vp7045_fe_sleep,
 
        .set_frontend = vp7045_fe_set_frontend,
-       .get_frontend = vp7045_fe_get_frontend,
        .get_tune_settings = vp7045_fe_get_tune_settings,
 
        .read_status = vp7045_fe_read_status,
index 489ae8245867bc51d83cfa062c71fc09952531b9..d1a1a1324ef87018e030ba0aa149de3c79856085 100644 (file)
@@ -335,7 +335,7 @@ static int add_pid_filter(struct firedtv *fdtv, u8 *operand)
  * (not supported by the AVC standard)
  */
 static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
-                             struct dvb_frontend_parameters *params)
+                             struct dtv_frontend_properties *p)
 {
        struct avc_command_frame *c = (void *)fdtv->avc_data;
 
@@ -349,15 +349,15 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
        else
                c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK;
 
-       c->operand[4] = (params->frequency >> 24) & 0xff;
-       c->operand[5] = (params->frequency >> 16) & 0xff;
-       c->operand[6] = (params->frequency >> 8) & 0xff;
-       c->operand[7] = params->frequency & 0xff;
+       c->operand[4] = (p->frequency >> 24) & 0xff;
+       c->operand[5] = (p->frequency >> 16) & 0xff;
+       c->operand[6] = (p->frequency >> 8) & 0xff;
+       c->operand[7] = p->frequency & 0xff;
 
-       c->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff;
-       c->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff;
+       c->operand[8] = ((p->symbol_rate / 1000) >> 8) & 0xff;
+       c->operand[9] = (p->symbol_rate / 1000) & 0xff;
 
-       switch (params->u.qpsk.fec_inner) {
+       switch (p->fec_inner) {
        case FEC_1_2:   c->operand[10] = 0x1; break;
        case FEC_2_3:   c->operand[10] = 0x2; break;
        case FEC_3_4:   c->operand[10] = 0x3; break;
@@ -392,10 +392,11 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
                        default:                c->operand[13] = 0x2; break;
                        }
                        switch (fdtv->fe.dtv_property_cache.rolloff) {
-                       case ROLLOFF_AUTO:      c->operand[14] = 0x2; break;
                        case ROLLOFF_35:        c->operand[14] = 0x2; break;
                        case ROLLOFF_20:        c->operand[14] = 0x0; break;
                        case ROLLOFF_25:        c->operand[14] = 0x1; break;
+                       case ROLLOFF_AUTO:
+                       default:                c->operand[14] = 0x2; break;
                        /* case ROLLOFF_NONE:   c->operand[14] = 0xff; break; */
                        }
                        switch (fdtv->fe.dtv_property_cache.pilot) {
@@ -415,7 +416,7 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
 }
 
 static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
-                              struct dvb_frontend_parameters *params)
+                              struct dtv_frontend_properties *p)
 {
        struct avc_command_frame *c = (void *)fdtv->avc_data;
 
@@ -434,8 +435,8 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
                        | 1 << 4 /* Frequency */
                        | 1 << 3 /* Symbol_Rate */
                        | 0 << 2 /* FEC_outer */
-                       | (params->u.qam.fec_inner  != FEC_AUTO ? 1 << 1 : 0)
-                       | (params->u.qam.modulation != QAM_AUTO ? 1 << 0 : 0);
+                       | (p->fec_inner  != FEC_AUTO ? 1 << 1 : 0)
+                       | (p->modulation != QAM_AUTO ? 1 << 0 : 0);
 
        /* multiplex_valid_flags, low byte */
        c->operand[6] =   0 << 7 /* NetworkID */
@@ -446,15 +447,15 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
        c->operand[9]  = 0x00;
        c->operand[10] = 0x00;
 
-       c->operand[11] = (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6);
-       c->operand[12] = ((params->frequency / 4000) >> 8) & 0xff;
-       c->operand[13] = (params->frequency / 4000) & 0xff;
-       c->operand[14] = ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff;
-       c->operand[15] = ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff;
-       c->operand[16] = ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0;
+       c->operand[11] = (((p->frequency / 4000) >> 16) & 0xff) | (2 << 6);
+       c->operand[12] = ((p->frequency / 4000) >> 8) & 0xff;
+       c->operand[13] = (p->frequency / 4000) & 0xff;
+       c->operand[14] = ((p->symbol_rate / 1000) >> 12) & 0xff;
+       c->operand[15] = ((p->symbol_rate / 1000) >> 4) & 0xff;
+       c->operand[16] = ((p->symbol_rate / 1000) << 4) & 0xf0;
        c->operand[17] = 0x00;
 
-       switch (params->u.qpsk.fec_inner) {
+       switch (p->fec_inner) {
        case FEC_1_2:   c->operand[18] = 0x1; break;
        case FEC_2_3:   c->operand[18] = 0x2; break;
        case FEC_3_4:   c->operand[18] = 0x3; break;
@@ -466,7 +467,7 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
        default:        c->operand[18] = 0x0;
        }
 
-       switch (params->u.qam.modulation) {
+       switch (p->modulation) {
        case QAM_16:    c->operand[19] = 0x08; break;
        case QAM_32:    c->operand[19] = 0x10; break;
        case QAM_64:    c->operand[19] = 0x18; break;
@@ -483,9 +484,8 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
 }
 
 static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
-                              struct dvb_frontend_parameters *params)
+                              struct dtv_frontend_properties *p)
 {
-       struct dvb_ofdm_parameters *ofdm = &params->u.ofdm;
        struct avc_command_frame *c = (void *)fdtv->avc_data;
 
        c->opcode = AVC_OPCODE_DSD;
@@ -500,42 +500,42 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
        c->operand[5] =
              0 << 7 /* reserved */
            | 1 << 6 /* CenterFrequency */
-           | (ofdm->bandwidth      != BANDWIDTH_AUTO        ? 1 << 5 : 0)
-           | (ofdm->constellation  != QAM_AUTO              ? 1 << 4 : 0)
-           | (ofdm->hierarchy_information != HIERARCHY_AUTO ? 1 << 3 : 0)
-           | (ofdm->code_rate_HP   != FEC_AUTO              ? 1 << 2 : 0)
-           | (ofdm->code_rate_LP   != FEC_AUTO              ? 1 << 1 : 0)
-           | (ofdm->guard_interval != GUARD_INTERVAL_AUTO   ? 1 << 0 : 0);
+           | (p->bandwidth_hz != 0        ? 1 << 5 : 0)
+           | (p->modulation  != QAM_AUTO              ? 1 << 4 : 0)
+           | (p->hierarchy != HIERARCHY_AUTO ? 1 << 3 : 0)
+           | (p->code_rate_HP   != FEC_AUTO              ? 1 << 2 : 0)
+           | (p->code_rate_LP   != FEC_AUTO              ? 1 << 1 : 0)
+           | (p->guard_interval != GUARD_INTERVAL_AUTO   ? 1 << 0 : 0);
 
        /* multiplex_valid_flags, low byte */
        c->operand[6] =
              0 << 7 /* NetworkID */
-           | (ofdm->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0)
+           | (p->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0)
            | 0 << 5 /* OtherFrequencyFlag */
            | 0 << 0 /* reserved */ ;
 
        c->operand[7]  = 0x0;
-       c->operand[8]  = (params->frequency / 10) >> 24;
-       c->operand[9]  = ((params->frequency / 10) >> 16) & 0xff;
-       c->operand[10] = ((params->frequency / 10) >>  8) & 0xff;
-       c->operand[11] = (params->frequency / 10) & 0xff;
-
-       switch (ofdm->bandwidth) {
-       case BANDWIDTH_7_MHZ:   c->operand[12] = 0x20; break;
-       case BANDWIDTH_8_MHZ:
-       case BANDWIDTH_6_MHZ:   /* not defined by AVC spec */
-       case BANDWIDTH_AUTO:
+       c->operand[8]  = (p->frequency / 10) >> 24;
+       c->operand[9]  = ((p->frequency / 10) >> 16) & 0xff;
+       c->operand[10] = ((p->frequency / 10) >>  8) & 0xff;
+       c->operand[11] = (p->frequency / 10) & 0xff;
+
+       switch (p->bandwidth_hz) {
+       case 7000000:   c->operand[12] = 0x20; break;
+       case 8000000:
+       case 6000000:   /* not defined by AVC spec */
+       case 0:
        default:                c->operand[12] = 0x00;
        }
 
-       switch (ofdm->constellation) {
+       switch (p->modulation) {
        case QAM_16:    c->operand[13] = 1 << 6; break;
        case QAM_64:    c->operand[13] = 2 << 6; break;
        case QPSK:
        default:        c->operand[13] = 0x00;
        }
 
-       switch (ofdm->hierarchy_information) {
+       switch (p->hierarchy) {
        case HIERARCHY_1:       c->operand[13] |= 1 << 3; break;
        case HIERARCHY_2:       c->operand[13] |= 2 << 3; break;
        case HIERARCHY_4:       c->operand[13] |= 3 << 3; break;
@@ -544,7 +544,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
        default:                break;
        }
 
-       switch (ofdm->code_rate_HP) {
+       switch (p->code_rate_HP) {
        case FEC_2_3:   c->operand[13] |= 1; break;
        case FEC_3_4:   c->operand[13] |= 2; break;
        case FEC_5_6:   c->operand[13] |= 3; break;
@@ -553,7 +553,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
        default:        break;
        }
 
-       switch (ofdm->code_rate_LP) {
+       switch (p->code_rate_LP) {
        case FEC_2_3:   c->operand[14] = 1 << 5; break;
        case FEC_3_4:   c->operand[14] = 2 << 5; break;
        case FEC_5_6:   c->operand[14] = 3 << 5; break;
@@ -562,7 +562,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
        default:        c->operand[14] = 0x00; break;
        }
 
-       switch (ofdm->guard_interval) {
+       switch (p->guard_interval) {
        case GUARD_INTERVAL_1_16:       c->operand[14] |= 1 << 3; break;
        case GUARD_INTERVAL_1_8:        c->operand[14] |= 2 << 3; break;
        case GUARD_INTERVAL_1_4:        c->operand[14] |= 3 << 3; break;
@@ -571,7 +571,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
        default:                        break;
        }
 
-       switch (ofdm->transmission_mode) {
+       switch (p->transmission_mode) {
        case TRANSMISSION_MODE_8K:      c->operand[14] |= 1 << 1; break;
        case TRANSMISSION_MODE_2K:
        case TRANSMISSION_MODE_AUTO:
@@ -585,7 +585,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
 }
 
 int avc_tuner_dsd(struct firedtv *fdtv,
-                 struct dvb_frontend_parameters *params)
+                 struct dtv_frontend_properties *p)
 {
        struct avc_command_frame *c = (void *)fdtv->avc_data;
        int pos, ret;
@@ -597,9 +597,9 @@ int avc_tuner_dsd(struct firedtv *fdtv,
 
        switch (fdtv->type) {
        case FIREDTV_DVB_S:
-       case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, params); break;
-       case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, params); break;
-       case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, params); break;
+       case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, p); break;
+       case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, p); break;
+       case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, p); break;
        default:
                BUG();
        }
index fd8bbbfa5c598e39896aaae1ea5e001002bdb6d5..eb7496eab130cfb54d5daa39717e61ed3594a695 100644 (file)
@@ -203,7 +203,9 @@ int fdtv_dvb_register(struct firedtv *fdtv, const char *name)
        if (err)
                goto fail_rem_frontend;
 
-       dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
+       err = dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
+       if (err)
+               goto fail_disconnect_frontend;
 
        fdtv_frontend_init(fdtv, name);
        err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
@@ -218,6 +220,7 @@ int fdtv_dvb_register(struct firedtv *fdtv, const char *name)
 
 fail_net_release:
        dvb_net_release(&fdtv->dvbnet);
+fail_disconnect_frontend:
        fdtv->demux.dmx.close(&fdtv->demux.dmx);
 fail_rem_frontend:
        fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
index 8748a61be73d2d8e32d0b65fd95396c2c4269b5b..6fe9793b98b3cfe19dfc22f664c3696ad78d71f3 100644 (file)
@@ -141,28 +141,12 @@ static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks)
        return -EOPNOTSUPP;
 }
 
-static int fdtv_set_frontend(struct dvb_frontend *fe,
-                            struct dvb_frontend_parameters *params)
+static int fdtv_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct firedtv *fdtv = fe->sec_priv;
 
-       return avc_tuner_dsd(fdtv, params);
-}
-
-static int fdtv_get_frontend(struct dvb_frontend *fe,
-                            struct dvb_frontend_parameters *params)
-{
-       return -EOPNOTSUPP;
-}
-
-static int fdtv_get_property(struct dvb_frontend *fe, struct dtv_property *tvp)
-{
-       return 0;
-}
-
-static int fdtv_set_property(struct dvb_frontend *fe, struct dtv_property *tvp)
-{
-       return 0;
+       return avc_tuner_dsd(fdtv, p);
 }
 
 void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
@@ -174,10 +158,6 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
        ops->sleep                      = fdtv_sleep;
 
        ops->set_frontend               = fdtv_set_frontend;
-       ops->get_frontend               = fdtv_get_frontend;
-
-       ops->get_property               = fdtv_get_property;
-       ops->set_property               = fdtv_set_property;
 
        ops->read_status                = fdtv_read_status;
        ops->read_ber                   = fdtv_read_ber;
@@ -192,7 +172,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
 
        switch (fdtv->type) {
        case FIREDTV_DVB_S:
-               fi->type                = FE_QPSK;
+               ops->delsys[0]          = SYS_DVBS;
 
                fi->frequency_min       = 950000;
                fi->frequency_max       = 2150000;
@@ -211,7 +191,8 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
                break;
 
        case FIREDTV_DVB_S2:
-               fi->type                = FE_QPSK;
+               ops->delsys[0]          = SYS_DVBS;
+               ops->delsys[1]          = SYS_DVBS2;
 
                fi->frequency_min       = 950000;
                fi->frequency_max       = 2150000;
@@ -231,7 +212,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
                break;
 
        case FIREDTV_DVB_C:
-               fi->type                = FE_QAM;
+               ops->delsys[0]          = SYS_DVBC_ANNEX_A;
 
                fi->frequency_min       = 47000000;
                fi->frequency_max       = 866000000;
@@ -249,7 +230,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
                break;
 
        case FIREDTV_DVB_T:
-               fi->type                = FE_OFDM;
+               ops->delsys[0]          = SYS_DVBT;
 
                fi->frequency_min       = 49000000;
                fi->frequency_max       = 861000000;
index bd00b04e079ddd0b7f667b9581118b47633cc2f5..4fdcd8cb753010416bbbf1d7c271208541b4b157 100644 (file)
@@ -112,8 +112,8 @@ struct firedtv {
 /* firedtv-avc.c */
 int avc_recv(struct firedtv *fdtv, void *data, size_t length);
 int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat);
-struct dvb_frontend_parameters;
-int avc_tuner_dsd(struct firedtv *fdtv, struct dvb_frontend_parameters *params);
+struct dtv_frontend_properties;
+int avc_tuner_dsd(struct firedtv *fdtv, struct dtv_frontend_properties *params);
 int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]);
 int avc_tuner_get_ts(struct firedtv *fdtv);
 int avc_identify_subunit(struct firedtv *fdtv);
index 4a2d2e6c91ab9f78f17715234cc4961a3397becd..ebb5ed7a7783ee7da77a3a87fa7e406db9a0bb61 100644 (file)
@@ -404,6 +404,13 @@ config DVB_EC100
        help
          Say Y when you want to support this frontend.
 
+config DVB_HD29L2
+       tristate "HDIC HD29L2"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         Say Y when you want to support this frontend.
+
 config DVB_STV0367
        tristate "ST STV0367 based"
        depends on DVB_CORE && I2C
index f639f67815515d40c8ff51b3a41a2ec52c456760..00a20636df62aad0944fc431c4cfdf026c7a7128 100644 (file)
@@ -84,6 +84,7 @@ obj-$(CONFIG_DVB_STV090x) += stv090x.o
 obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
 obj-$(CONFIG_DVB_ISL6423) += isl6423.o
 obj-$(CONFIG_DVB_EC100) += ec100.o
+obj-$(CONFIG_DVB_HD29L2) += hd29l2.o
 obj-$(CONFIG_DVB_DS3000) += ds3000.o
 obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
 obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
index 345311c333838ace3ee21fd751051a74cb472270..6bcbcf543b38ea6be973e98b52d0247af8ab96b0 100644 (file)
@@ -2,6 +2,7 @@
  * Afatech AF9013 demodulator driver
  *
  * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
  *
  * Thanks to Afatech who kindly provided information.
  *
  *
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/firmware.h>
-
-#include "dvb_frontend.h"
 #include "af9013_priv.h"
-#include "af9013.h"
 
 int af9013_debug;
+module_param_named(debug, af9013_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
 struct af9013_state {
        struct i2c_adapter *i2c;
-       struct dvb_frontend frontend;
-
+       struct dvb_frontend fe;
        struct af9013_config config;
 
        /* tuner/demod RF and IF AGC limits used for signal strength calc */
@@ -48,107 +39,178 @@ struct af9013_state {
        u32 ber;
        u32 ucblocks;
        u16 snr;
-       u32 frequency;
-       unsigned long next_statistics_check;
+       u32 bandwidth_hz;
+       fe_status_t fe_status;
+       unsigned long set_frontend_jiffies;
+       unsigned long read_status_jiffies;
+       bool first_tune;
+       bool i2c_gate_state;
+       unsigned int statistics_step:3;
+       struct delayed_work statistics_work;
 };
 
-static u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
-
-static int af9013_write_regs(struct af9013_state *state, u8 mbox, u16 reg,
-       u8 *val, u8 len)
+/* write multiple registers */
+static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg,
+       const u8 *val, int len)
 {
+       int ret;
        u8 buf[3+len];
-       struct i2c_msg msg = {
-               .addr = state->config.demod_address,
-               .flags = 0,
-               .len = sizeof(buf),
-               .buf = buf };
-
-       buf[0] = reg >> 8;
-       buf[1] = reg & 0xff;
+       struct i2c_msg msg[1] = {
+               {
+                       .addr = priv->config.i2c_addr,
+                       .flags = 0,
+                       .len = sizeof(buf),
+                       .buf = buf,
+               }
+       };
+
+       buf[0] = (reg >> 8) & 0xff;
+       buf[1] = (reg >> 0) & 0xff;
        buf[2] = mbox;
        memcpy(&buf[3], val, len);
 
-       if (i2c_transfer(state->i2c, &msg, 1) != 1) {
-               warn("I2C write failed reg:%04x len:%d", reg, len);
-               return -EREMOTEIO;
+       ret = i2c_transfer(priv->i2c, msg, 1);
+       if (ret == 1) {
+               ret = 0;
+       } else {
+               warn("i2c wr failed=%d reg=%04x len=%d", ret, reg, len);
+               ret = -EREMOTEIO;
        }
-       return 0;
+       return ret;
 }
 
-static int af9013_write_ofdm_regs(struct af9013_state *state, u16 reg, u8 *val,
-       u8 len)
+/* read multiple registers */
+static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg,
+       u8 *val, int len)
 {
-       u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(0 << 6)|(0 << 7);
-       return af9013_write_regs(state, mbox, reg, val, len);
+       int ret;
+       u8 buf[3];
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = priv->config.i2c_addr,
+                       .flags = 0,
+                       .len = 3,
+                       .buf = buf,
+               }, {
+                       .addr = priv->config.i2c_addr,
+                       .flags = I2C_M_RD,
+                       .len = len,
+                       .buf = val,
+               }
+       };
+
+       buf[0] = (reg >> 8) & 0xff;
+       buf[1] = (reg >> 0) & 0xff;
+       buf[2] = mbox;
+
+       ret = i2c_transfer(priv->i2c, msg, 2);
+       if (ret == 2) {
+               ret = 0;
+       } else {
+               warn("i2c rd failed=%d reg=%04x len=%d", ret, reg, len);
+               ret = -EREMOTEIO;
+       }
+       return ret;
 }
 
-static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val,
-       u8 len)
+/* write multiple registers */
+static int af9013_wr_regs(struct af9013_state *priv, u16 reg, const u8 *val,
+       int len)
 {
-       u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(1 << 6)|(1 << 7);
-       return af9013_write_regs(state, mbox, reg, val, len);
+       int ret, i;
+       u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0);
+
+       if ((priv->config.ts_mode == AF9013_TS_USB) &&
+               ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) {
+               mbox |= ((len - 1) << 2);
+               ret = af9013_wr_regs_i2c(priv, mbox, reg, val, len);
+       } else {
+               for (i = 0; i < len; i++) {
+                       ret = af9013_wr_regs_i2c(priv, mbox, reg+i, val+i, 1);
+                       if (ret)
+                               goto err;
+               }
+       }
+
+err:
+       return 0;
+}
+
+/* read multiple registers */
+static int af9013_rd_regs(struct af9013_state *priv, u16 reg, u8 *val, int len)
+{
+       int ret, i;
+       u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(0 << 0);
+
+       if ((priv->config.ts_mode == AF9013_TS_USB) &&
+               ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) {
+               mbox |= ((len - 1) << 2);
+               ret = af9013_rd_regs_i2c(priv, mbox, reg, val, len);
+       } else {
+               for (i = 0; i < len; i++) {
+                       ret = af9013_rd_regs_i2c(priv, mbox, reg+i, val+i, 1);
+                       if (ret)
+                               goto err;
+               }
+       }
+
+err:
+       return 0;
 }
 
 /* write single register */
-static int af9013_write_reg(struct af9013_state *state, u16 reg, u8 val)
+static int af9013_wr_reg(struct af9013_state *priv, u16 reg, u8 val)
 {
-       return af9013_write_ofdm_regs(state, reg, &val, 1);
+       return af9013_wr_regs(priv, reg, &val, 1);
 }
 
 /* read single register */
-static int af9013_read_reg(struct af9013_state *state, u16 reg, u8 *val)
+static int af9013_rd_reg(struct af9013_state *priv, u16 reg, u8 *val)
 {
-       u8 obuf[3] = { reg >> 8, reg & 0xff, 0 };
-       u8 ibuf[1];
-       struct i2c_msg msg[2] = {
-               {
-                       .addr = state->config.demod_address,
-                       .flags = 0,
-                       .len = sizeof(obuf),
-                       .buf = obuf
-               }, {
-                       .addr = state->config.demod_address,
-                       .flags = I2C_M_RD,
-                       .len = sizeof(ibuf),
-                       .buf = ibuf
-               }
-       };
+       return af9013_rd_regs(priv, reg, val, 1);
+}
 
-       if (i2c_transfer(state->i2c, msg, 2) != 2) {
-               warn("I2C read failed reg:%04x", reg);
-               return -EREMOTEIO;
-       }
-       *val = ibuf[0];
-       return 0;
+static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val,
+       u8 len)
+{
+       u8 mbox = (1 << 7)|(1 << 6)|((len - 1) << 2)|(1 << 1)|(1 << 0);
+       return af9013_wr_regs_i2c(state, mbox, reg, val, len);
 }
 
-static int af9013_write_reg_bits(struct af9013_state *state, u16 reg, u8 pos,
-       u8 len, u8 val)
+static int af9013_wr_reg_bits(struct af9013_state *state, u16 reg, int pos,
+       int len, u8 val)
 {
        int ret;
        u8 tmp, mask;
 
-       ret = af9013_read_reg(state, reg, &tmp);
-       if (ret)
-               return ret;
+       /* no need for read if whole reg is written */
+       if (len != 8) {
+               ret = af9013_rd_reg(state, reg, &tmp);
+               if (ret)
+                       return ret;
 
-       mask = regmask[len - 1] << pos;
-       tmp = (tmp & ~mask) | ((val << pos) & mask);
+               mask = (0xff >> (8 - len)) << pos;
+               val <<= pos;
+               tmp &= ~mask;
+               val |= tmp;
+       }
 
-       return af9013_write_reg(state, reg, tmp);
+       return af9013_wr_reg(state, reg, val);
 }
 
-static int af9013_read_reg_bits(struct af9013_state *state, u16 reg, u8 pos,
-       u8 len, u8 *val)
+static int af9013_rd_reg_bits(struct af9013_state *state, u16 reg, int pos,
+       int len, u8 *val)
 {
        int ret;
        u8 tmp;
 
-       ret = af9013_read_reg(state, reg, &tmp);
+       ret = af9013_rd_reg(state, reg, &tmp);
        if (ret)
                return ret;
-       *val = (tmp >> pos) & regmask[len - 1];
+
+       *val = (tmp >> pos);
+       *val &= (0xff >> (8 - len));
+
        return 0;
 }
 
@@ -157,10 +219,13 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval)
        int ret;
        u8 pos;
        u16 addr;
-       deb_info("%s: gpio:%d gpioval:%02x\n", __func__, gpio, gpioval);
 
-/* GPIO0 & GPIO1 0xd735
-   GPIO2 & GPIO3 0xd736 */
+       dbg("%s: gpio=%d gpioval=%02x", __func__, gpio, gpioval);
+
+       /*
+        * GPIO0 & GPIO1 0xd735
+        * GPIO2 & GPIO3 0xd736
+        */
 
        switch (gpio) {
        case 0:
@@ -175,7 +240,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval)
        default:
                err("invalid gpio:%d\n", gpio);
                ret = -EINVAL;
-               goto error;
+               goto err;
        };
 
        switch (gpio) {
@@ -190,16 +255,21 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval)
                break;
        };
 
-       ret = af9013_write_reg_bits(state, addr, pos, 4, gpioval);
+       ret = af9013_wr_reg_bits(state, addr, pos, 4, gpioval);
+       if (ret)
+               goto err;
 
-error:
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
        return ret;
 }
 
 static u32 af913_div(u32 a, u32 b, u32 x)
 {
        u32 r = 0, c = 0, i;
-       deb_info("%s: a:%d b:%d x:%d\n", __func__, a, b, x);
+
+       dbg("%s: a=%d b=%d x=%d", __func__, a, b, x);
 
        if (a > b) {
                c = a / b;
@@ -216,205 +286,407 @@ static u32 af913_div(u32 a, u32 b, u32 x)
        }
        r = (c << (u32)x) + r;
 
-       deb_info("%s: a:%d b:%d x:%d r:%d r:%x\n", __func__, a, b, x, r, r);
+       dbg("%s: a=%d b=%d x=%d r=%x", __func__, a, b, x, r);
        return r;
 }
 
-static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw)
+static int af9013_power_ctrl(struct af9013_state *state, u8 onoff)
 {
-       int ret, i, j, found;
-       deb_info("%s: adc_clock:%d bw:%d\n", __func__,
-               state->config.adc_clock, bw);
-
-       /* lookup coeff from table */
-       for (i = 0, found = 0; i < ARRAY_SIZE(coeff_table); i++) {
-               if (coeff_table[i].adc_clock == state->config.adc_clock &&
-                       coeff_table[i].bw == bw) {
-                       found = 1;
-                       break;
-               }
-       }
+       int ret, i;
+       u8 tmp;
 
-       if (!found) {
-               err("invalid bw or clock");
-               ret = -EINVAL;
-               goto error;
+       dbg("%s: onoff=%d", __func__, onoff);
+
+       /* enable reset */
+       ret = af9013_wr_reg_bits(state, 0xd417, 4, 1, 1);
+       if (ret)
+               goto err;
+
+       /* start reset mechanism */
+       ret = af9013_wr_reg(state, 0xaeff, 1);
+       if (ret)
+               goto err;
+
+       /* wait reset performs */
+       for (i = 0; i < 150; i++) {
+               ret = af9013_rd_reg_bits(state, 0xd417, 1, 1, &tmp);
+               if (ret)
+                       goto err;
+
+               if (tmp)
+                       break; /* reset done */
+
+               usleep_range(5000, 25000);
        }
 
-       deb_info("%s: coeff: ", __func__);
-       debug_dump(coeff_table[i].val, sizeof(coeff_table[i].val), deb_info);
+       if (!tmp)
+               return -ETIMEDOUT;
 
-       /* program */
-       for (j = 0; j < sizeof(coeff_table[i].val); j++) {
-               ret = af9013_write_reg(state, 0xae00 + j,
-                       coeff_table[i].val[j]);
+       if (onoff) {
+               /* clear reset */
+               ret = af9013_wr_reg_bits(state, 0xd417, 1, 1, 0);
                if (ret)
-                       break;
+                       goto err;
+
+               /* disable reset */
+               ret = af9013_wr_reg_bits(state, 0xd417, 4, 1, 0);
+
+               /* power on */
+               ret = af9013_wr_reg_bits(state, 0xd73a, 3, 1, 0);
+       } else {
+               /* power off */
+               ret = af9013_wr_reg_bits(state, 0xd73a, 3, 1, 1);
        }
 
-error:
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
        return ret;
 }
 
-static int af9013_set_adc_ctrl(struct af9013_state *state)
+static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe)
 {
+       struct af9013_state *state = fe->demodulator_priv;
        int ret;
-       u8 buf[3], tmp, i;
-       u32 adc_cw;
 
-       deb_info("%s: adc_clock:%d\n", __func__, state->config.adc_clock);
+       dbg("%s", __func__);
 
-       /* adc frequency type */
-       switch (state->config.adc_clock) {
-       case 28800: /* 28.800 MHz */
-               tmp = 0;
-               break;
-       case 20480: /* 20.480 MHz */
-               tmp = 1;
+       /* reset and start BER counter */
+       ret = af9013_wr_reg_bits(state, 0xd391, 4, 1, 1);
+       if (ret)
+               goto err;
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int af9013_statistics_ber_unc_result(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+       u8 buf[5];
+
+       dbg("%s", __func__);
+
+       /* check if error bit count is ready */
+       ret = af9013_rd_reg_bits(state, 0xd391, 4, 1, &buf[0]);
+       if (ret)
+               goto err;
+
+       if (!buf[0]) {
+               dbg("%s: not ready", __func__);
+               return 0;
+       }
+
+       ret = af9013_rd_regs(state, 0xd387, buf, 5);
+       if (ret)
+               goto err;
+
+       state->ber = (buf[2] << 16) | (buf[1] << 8) | buf[0];
+       state->ucblocks += (buf[4] << 8) | buf[3];
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int af9013_statistics_snr_start(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+
+       dbg("%s", __func__);
+
+       /* start SNR meas */
+       ret = af9013_wr_reg_bits(state, 0xd2e1, 3, 1, 1);
+       if (ret)
+               goto err;
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int af9013_statistics_snr_result(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret, i, len;
+       u8 buf[3], tmp;
+       u32 snr_val;
+       const struct af9013_snr *uninitialized_var(snr_lut);
+
+       dbg("%s", __func__);
+
+       /* check if SNR ready */
+       ret = af9013_rd_reg_bits(state, 0xd2e1, 3, 1, &tmp);
+       if (ret)
+               goto err;
+
+       if (!tmp) {
+               dbg("%s: not ready", __func__);
+               return 0;
+       }
+
+       /* read value */
+       ret = af9013_rd_regs(state, 0xd2e3, buf, 3);
+       if (ret)
+               goto err;
+
+       snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+       /* read current modulation */
+       ret = af9013_rd_reg(state, 0xd3c1, &tmp);
+       if (ret)
+               goto err;
+
+       switch ((tmp >> 6) & 3) {
+       case 0:
+               len = ARRAY_SIZE(qpsk_snr_lut);
+               snr_lut = qpsk_snr_lut;
                break;
-       case 28000: /* 28.000 MHz */
-               tmp = 2;
+       case 1:
+               len = ARRAY_SIZE(qam16_snr_lut);
+               snr_lut = qam16_snr_lut;
                break;
-       case 25000: /* 25.000 MHz */
-               tmp = 3;
+       case 2:
+               len = ARRAY_SIZE(qam64_snr_lut);
+               snr_lut = qam64_snr_lut;
                break;
        default:
-               err("invalid xtal");
-               return -EINVAL;
+               goto err;
+               break;
        }
 
-       adc_cw = af913_div(state->config.adc_clock*1000, 1000000ul, 19ul);
+       for (i = 0; i < len; i++) {
+               tmp = snr_lut[i].snr;
 
-       buf[0] = (u8) ((adc_cw & 0x000000ff));
-       buf[1] = (u8) ((adc_cw & 0x0000ff00) >> 8);
-       buf[2] = (u8) ((adc_cw & 0x00ff0000) >> 16);
+               if (snr_val < snr_lut[i].val)
+                       break;
+       }
+       state->snr = tmp * 10; /* dB/10 */
 
-       deb_info("%s: adc_cw:", __func__);
-       debug_dump(buf, sizeof(buf), deb_info);
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int af9013_statistics_signal_strength(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret = 0;
+       u8 buf[2], rf_gain, if_gain;
+       int signal_strength;
+
+       dbg("%s", __func__);
+
+       if (!state->signal_strength_en)
+               return 0;
+
+       ret = af9013_rd_regs(state, 0xd07c, buf, 2);
+       if (ret)
+               goto err;
+
+       rf_gain = buf[0];
+       if_gain = buf[1];
+
+       signal_strength = (0xffff / \
+               (9 * (state->rf_50 + state->if_50) - \
+               11 * (state->rf_80 + state->if_80))) * \
+               (10 * (rf_gain + if_gain) - \
+               11 * (state->rf_80 + state->if_80));
+       if (signal_strength < 0)
+               signal_strength = 0;
+       else if (signal_strength > 0xffff)
+               signal_strength = 0xffff;
+
+       state->signal_strength = signal_strength;
 
-       /* program */
-       for (i = 0; i < sizeof(buf); i++) {
-               ret = af9013_write_reg(state, 0xd180 + i, buf[i]);
-               if (ret)
-                       goto error;
-       }
-       ret = af9013_write_reg_bits(state, 0x9bd2, 0, 4, tmp);
-error:
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
        return ret;
 }
 
-static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw)
+static void af9013_statistics_work(struct work_struct *work)
 {
        int ret;
-       u16 addr;
-       u8 buf[3], i, j;
-       u32 adc_freq, freq_cw;
-       s8 bfs_spec_inv;
-       int if_sample_freq;
-
-       for (j = 0; j < 3; j++) {
-               if (j == 0) {
-                       addr = 0xd140; /* fcw normal */
-                       bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1;
-               } else if (j == 1) {
-                       addr = 0x9be7; /* fcw dummy ram */
-                       bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1;
-               } else {
-                       addr = 0x9bea; /* fcw inverted */
-                       bfs_spec_inv = state->config.rf_spec_inv ? 1 : -1;
-               }
+       struct af9013_state *state = container_of(work,
+               struct af9013_state, statistics_work.work);
+       unsigned int next_msec;
+
+       /* update only signal strength when demod is not locked */
+       if (!(state->fe_status & FE_HAS_LOCK)) {
+               state->statistics_step = 0;
+               state->ber = 0;
+               state->snr = 0;
+       }
+
+       switch (state->statistics_step) {
+       default:
+               state->statistics_step = 0;
+       case 0:
+               ret = af9013_statistics_signal_strength(&state->fe);
+               state->statistics_step++;
+               next_msec = 300;
+               break;
+       case 1:
+               ret = af9013_statistics_snr_start(&state->fe);
+               state->statistics_step++;
+               next_msec = 200;
+               break;
+       case 2:
+               ret = af9013_statistics_ber_unc_start(&state->fe);
+               state->statistics_step++;
+               next_msec = 1000;
+               break;
+       case 3:
+               ret = af9013_statistics_snr_result(&state->fe);
+               state->statistics_step++;
+               next_msec = 400;
+               break;
+       case 4:
+               ret = af9013_statistics_ber_unc_result(&state->fe);
+               state->statistics_step++;
+               next_msec = 100;
+               break;
+       }
 
-               adc_freq       = state->config.adc_clock * 1000;
-               if_sample_freq = state->config.tuner_if * 1000;
+       schedule_delayed_work(&state->statistics_work,
+               msecs_to_jiffies(next_msec));
 
-               /* TDA18271 uses different sampling freq for every bw */
-               if (state->config.tuner == AF9013_TUNER_TDA18271) {
-                       switch (bw) {
-                       case BANDWIDTH_6_MHZ:
-                               if_sample_freq = 3300000; /* 3.3 MHz */
-                               break;
-                       case BANDWIDTH_7_MHZ:
-                               if_sample_freq = 3500000; /* 3.5 MHz */
-                               break;
-                       case BANDWIDTH_8_MHZ:
-                       default:
-                               if_sample_freq = 4000000; /* 4.0 MHz */
-                               break;
-                       }
-               } else if (state->config.tuner == AF9013_TUNER_TDA18218) {
-                       switch (bw) {
-                       case BANDWIDTH_6_MHZ:
-                               if_sample_freq = 3000000; /* 3 MHz */
-                               break;
-                       case BANDWIDTH_7_MHZ:
-                               if_sample_freq = 3500000; /* 3.5 MHz */
-                               break;
-                       case BANDWIDTH_8_MHZ:
-                       default:
-                               if_sample_freq = 4000000; /* 4 MHz */
+       return;
+}
+
+static int af9013_get_tune_settings(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *fesettings)
+{
+       fesettings->min_delay_ms = 800;
+       fesettings->step_size = 0;
+       fesettings->max_drift = 0;
+
+       return 0;
+}
+
+static int af9013_set_frontend(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret, i, sampling_freq;
+       bool auto_mode, spec_inv;
+       u8 buf[6];
+       u32 if_frequency, freq_cw;
+
+       dbg("%s: frequency=%d bandwidth_hz=%d", __func__,
+               c->frequency, c->bandwidth_hz);
+
+       /* program tuner */
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe);
+
+       /* program CFOE coefficients */
+       if (c->bandwidth_hz != state->bandwidth_hz) {
+               for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) {
+                       if (coeff_lut[i].clock == state->config.clock &&
+                               coeff_lut[i].bandwidth_hz == c->bandwidth_hz) {
                                break;
                        }
                }
 
-               while (if_sample_freq > (adc_freq / 2))
-                       if_sample_freq = if_sample_freq - adc_freq;
+               ret = af9013_wr_regs(state, 0xae00, coeff_lut[i].val,
+                       sizeof(coeff_lut[i].val));
+       }
 
-               if (if_sample_freq >= 0)
-                       bfs_spec_inv = bfs_spec_inv * (-1);
+       /* program frequency control */
+       if (c->bandwidth_hz != state->bandwidth_hz || state->first_tune) {
+               /* get used IF frequency */
+               if (fe->ops.tuner_ops.get_if_frequency)
+                       fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
                else
-                       if_sample_freq = if_sample_freq * (-1);
+                       if_frequency = state->config.if_frequency;
 
-               freq_cw = af913_div(if_sample_freq, adc_freq, 23ul);
+               sampling_freq = if_frequency;
 
-               if (bfs_spec_inv == -1)
-                       freq_cw = 0x00800000 - freq_cw;
+               while (sampling_freq > (state->config.clock / 2))
+                       sampling_freq -= state->config.clock;
 
-               buf[0] = (u8) ((freq_cw & 0x000000ff));
-               buf[1] = (u8) ((freq_cw & 0x0000ff00) >> 8);
-               buf[2] = (u8) ((freq_cw & 0x007f0000) >> 16);
+               if (sampling_freq < 0) {
+                       sampling_freq *= -1;
+                       spec_inv = state->config.spec_inv;
+               } else {
+                       spec_inv = !state->config.spec_inv;
+               }
 
+               freq_cw = af913_div(sampling_freq, state->config.clock, 23);
 
-               deb_info("%s: freq_cw:", __func__);
-               debug_dump(buf, sizeof(buf), deb_info);
+               if (spec_inv)
+                       freq_cw = 0x800000 - freq_cw;
 
-               /* program */
-               for (i = 0; i < sizeof(buf); i++) {
-                       ret = af9013_write_reg(state, addr++, buf[i]);
-                       if (ret)
-                               goto error;
-               }
+               buf[0] = (freq_cw >>  0) & 0xff;
+               buf[1] = (freq_cw >>  8) & 0xff;
+               buf[2] = (freq_cw >> 16) & 0x7f;
+
+               freq_cw = 0x800000 - freq_cw;
+
+               buf[3] = (freq_cw >>  0) & 0xff;
+               buf[4] = (freq_cw >>  8) & 0xff;
+               buf[5] = (freq_cw >> 16) & 0x7f;
+
+               ret = af9013_wr_regs(state, 0xd140, buf, 3);
+               if (ret)
+                       goto err;
+
+               ret = af9013_wr_regs(state, 0x9be7, buf, 6);
+               if (ret)
+                       goto err;
        }
-error:
-       return ret;
-}
 
-static int af9013_set_ofdm_params(struct af9013_state *state,
-       struct dvb_ofdm_parameters *params, u8 *auto_mode)
-{
-       int ret;
-       u8 i, buf[3] = {0, 0, 0};
-       *auto_mode = 0; /* set if parameters are requested to auto set */
+       /* clear TPS lock flag */
+       ret = af9013_wr_reg_bits(state, 0xd330, 3, 1, 1);
+       if (ret)
+               goto err;
 
-       /* Try auto-detect transmission parameters in case of AUTO requested or
-          garbage parameters given by application for compatibility.
-          MPlayer seems to provide garbage parameters currently. */
+       /* clear MPEG2 lock flag */
+       ret = af9013_wr_reg_bits(state, 0xd507, 6, 1, 0);
+       if (ret)
+               goto err;
 
-       switch (params->transmission_mode) {
+       /* empty channel function */
+       ret = af9013_wr_reg_bits(state, 0x9bfe, 0, 1, 0);
+       if (ret)
+               goto err;
+
+       /* empty DVB-T channel function */
+       ret = af9013_wr_reg_bits(state, 0x9bc2, 0, 1, 0);
+       if (ret)
+               goto err;
+
+       /* transmission parameters */
+       auto_mode = false;
+       memset(buf, 0, 3);
+
+       switch (c->transmission_mode) {
        case TRANSMISSION_MODE_AUTO:
-               *auto_mode = 1;
+               auto_mode = 1;
+               break;
        case TRANSMISSION_MODE_2K:
                break;
        case TRANSMISSION_MODE_8K:
                buf[0] |= (1 << 0);
                break;
        default:
-               deb_info("%s: invalid transmission_mode\n", __func__);
-               *auto_mode = 1;
+               dbg("%s: invalid transmission_mode", __func__);
+               auto_mode = 1;
        }
 
-       switch (params->guard_interval) {
+       switch (c->guard_interval) {
        case GUARD_INTERVAL_AUTO:
-               *auto_mode = 1;
+               auto_mode = 1;
+               break;
        case GUARD_INTERVAL_1_32:
                break;
        case GUARD_INTERVAL_1_16:
@@ -427,13 +699,14 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
                buf[0] |= (3 << 2);
                break;
        default:
-               deb_info("%s: invalid guard_interval\n", __func__);
-               *auto_mode = 1;
+               dbg("%s: invalid guard_interval", __func__);
+               auto_mode = 1;
        }
 
-       switch (params->hierarchy_information) {
+       switch (c->hierarchy) {
        case HIERARCHY_AUTO:
-               *auto_mode = 1;
+               auto_mode = 1;
+               break;
        case HIERARCHY_NONE:
                break;
        case HIERARCHY_1:
@@ -446,13 +719,14 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
                buf[0] |= (3 << 4);
                break;
        default:
-               deb_info("%s: invalid hierarchy_information\n", __func__);
-               *auto_mode = 1;
+               dbg("%s: invalid hierarchy", __func__);
+               auto_mode = 1;
        };
 
-       switch (params->constellation) {
+       switch (c->modulation) {
        case QAM_AUTO:
-               *auto_mode = 1;
+               auto_mode = 1;
+               break;
        case QPSK:
                break;
        case QAM_16:
@@ -462,16 +736,17 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
                buf[1] |= (2 << 6);
                break;
        default:
-               deb_info("%s: invalid constellation\n", __func__);
-               *auto_mode = 1;
+               dbg("%s: invalid modulation", __func__);
+               auto_mode = 1;
        }
 
        /* Use HP. How and which case we can switch to LP? */
        buf[1] |= (1 << 4);
 
-       switch (params->code_rate_HP) {
+       switch (c->code_rate_HP) {
        case FEC_AUTO:
-               *auto_mode = 1;
+               auto_mode = 1;
+               break;
        case FEC_1_2:
                break;
        case FEC_2_3:
@@ -487,16 +762,14 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
                buf[2] |= (4 << 0);
                break;
        default:
-               deb_info("%s: invalid code_rate_HP\n", __func__);
-               *auto_mode = 1;
+               dbg("%s: invalid code_rate_HP", __func__);
+               auto_mode = 1;
        }
 
-       switch (params->code_rate_LP) {
+       switch (c->code_rate_LP) {
        case FEC_AUTO:
-       /* if HIERARCHY_NONE and FEC_NONE then LP FEC is set to FEC_AUTO
-          by dvb_frontend.c for compatibility */
-               if (params->hierarchy_information != HIERARCHY_NONE)
-                       *auto_mode = 1;
+               auto_mode = 1;
+               break;
        case FEC_1_2:
                break;
        case FEC_2_3:
@@ -512,709 +785,373 @@ static int af9013_set_ofdm_params(struct af9013_state *state,
                buf[2] |= (4 << 3);
                break;
        case FEC_NONE:
-               if (params->hierarchy_information == HIERARCHY_AUTO)
-                       break;
+               break;
        default:
-               deb_info("%s: invalid code_rate_LP\n", __func__);
-               *auto_mode = 1;
+               dbg("%s: invalid code_rate_LP", __func__);
+               auto_mode = 1;
        }
 
-       switch (params->bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       switch (c->bandwidth_hz) {
+       case 6000000:
                break;
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                buf[1] |= (1 << 2);
                break;
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
                buf[1] |= (2 << 2);
                break;
        default:
-               deb_info("%s: invalid bandwidth\n", __func__);
-               buf[1] |= (2 << 2); /* cannot auto-detect BW, try 8 MHz */
-       }
-
-       /* program */
-       for (i = 0; i < sizeof(buf); i++) {
-               ret = af9013_write_reg(state, 0xd3c0 + i, buf[i]);
-               if (ret)
-                       break;
+               dbg("%s: invalid bandwidth_hz", __func__);
+               ret = -EINVAL;
+               goto err;
        }
 
-       return ret;
-}
-
-static int af9013_reset(struct af9013_state *state, u8 sleep)
-{
-       int ret;
-       u8 tmp, i;
-       deb_info("%s\n", __func__);
-
-       /* enable OFDM reset */
-       ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 1);
+       ret = af9013_wr_regs(state, 0xd3c0, buf, 3);
        if (ret)
-               goto error;
+               goto err;
 
-       /* start reset mechanism */
-       ret = af9013_write_reg(state, 0xaeff, 1);
-       if (ret)
-               goto error;
-
-       /* reset is done when bit 1 is set */
-       for (i = 0; i < 150; i++) {
-               ret = af9013_read_reg_bits(state, 0xd417, 1, 1, &tmp);
-               if (ret)
-                       goto error;
-               if (tmp)
-                       break; /* reset done */
-               msleep(10);
-       }
-       if (!tmp)
-               return -ETIMEDOUT;
-
-       /* don't clear reset when going to sleep */
-       if (!sleep) {
-               /* clear OFDM reset */
-               ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0);
+       if (auto_mode) {
+               /* clear easy mode flag */
+               ret = af9013_wr_reg(state, 0xaefd, 0);
                if (ret)
-                       goto error;
+                       goto err;
 
-               /* disable OFDM reset */
-               ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0);
-       }
-error:
-       return ret;
-}
-
-static int af9013_power_ctrl(struct af9013_state *state, u8 onoff)
-{
-       int ret;
-       deb_info("%s: onoff:%d\n", __func__, onoff);
-
-       if (onoff) {
-               /* power on */
-               ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 0);
-               if (ret)
-                       goto error;
-               ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0);
-               if (ret)
-                       goto error;
-               ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0);
+               dbg("%s: auto params", __func__);
        } else {
-               /* power off */
-               ret = af9013_reset(state, 1);
+               /* set easy mode flag */
+               ret = af9013_wr_reg(state, 0xaefd, 1);
                if (ret)
-                       goto error;
-               ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 1);
-       }
-error:
-       return ret;
-}
-
-static int af9013_lock_led(struct af9013_state *state, u8 onoff)
-{
-       deb_info("%s: onoff:%d\n", __func__, onoff);
-
-       return af9013_write_reg_bits(state, 0xd730, 0, 1, onoff);
-}
-
-static int af9013_set_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params)
-{
-       struct af9013_state *state = fe->demodulator_priv;
-       int ret;
-       u8 auto_mode; /* auto set TPS */
-
-       deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency,
-               params->u.ofdm.bandwidth);
-
-       state->frequency = params->frequency;
-
-       /* program tuner */
-       if (fe->ops.tuner_ops.set_params)
-               fe->ops.tuner_ops.set_params(fe, params);
-
-       /* program CFOE coefficients */
-       ret = af9013_set_coeff(state, params->u.ofdm.bandwidth);
-       if (ret)
-               goto error;
-
-       /* program frequency control */
-       ret = af9013_set_freq_ctrl(state, params->u.ofdm.bandwidth);
-       if (ret)
-               goto error;
-
-       /* clear TPS lock flag (inverted flag) */
-       ret = af9013_write_reg_bits(state, 0xd330, 3, 1, 1);
-       if (ret)
-               goto error;
-
-       /* clear MPEG2 lock flag */
-       ret = af9013_write_reg_bits(state, 0xd507, 6, 1, 0);
-       if (ret)
-               goto error;
-
-       /* empty channel function */
-       ret = af9013_write_reg_bits(state, 0x9bfe, 0, 1, 0);
-       if (ret)
-               goto error;
-
-       /* empty DVB-T channel function */
-       ret = af9013_write_reg_bits(state, 0x9bc2, 0, 1, 0);
-       if (ret)
-               goto error;
+                       goto err;
 
-       /* program TPS and bandwidth, check if auto mode needed */
-       ret = af9013_set_ofdm_params(state, &params->u.ofdm, &auto_mode);
-       if (ret)
-               goto error;
-
-       if (auto_mode) {
-               /* clear easy mode flag */
-               ret = af9013_write_reg(state, 0xaefd, 0);
-               deb_info("%s: auto TPS\n", __func__);
-       } else {
-               /* set easy mode flag */
-               ret = af9013_write_reg(state, 0xaefd, 1);
+               ret = af9013_wr_reg(state, 0xaefe, 0);
                if (ret)
-                       goto error;
-               ret = af9013_write_reg(state, 0xaefe, 0);
-               deb_info("%s: manual TPS\n", __func__);
+                       goto err;
+
+               dbg("%s: manual params", __func__);
        }
-       if (ret)
-               goto error;
 
-       /* everything is set, lets try to receive channel - OFSM GO! */
-       ret = af9013_write_reg(state, 0xffff, 0);
+       /* tune */
+       ret = af9013_wr_reg(state, 0xffff, 0);
        if (ret)
-               goto error;
+               goto err;
+
+       state->bandwidth_hz = c->bandwidth_hz;
+       state->set_frontend_jiffies = jiffies;
+       state->first_tune = false;
 
-error:
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
        return ret;
 }
 
-static int af9013_get_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int af9013_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct af9013_state *state = fe->demodulator_priv;
        int ret;
-       u8 i, buf[3];
-       deb_info("%s\n", __func__);
+       u8 buf[3];
 
-       /* read TPS registers */
-       for (i = 0; i < 3; i++) {
-               ret = af9013_read_reg(state, 0xd3c0 + i, &buf[i]);
-               if (ret)
-                       goto error;
-       }
+       dbg("%s", __func__);
+
+       ret = af9013_rd_regs(state, 0xd3c0, buf, 3);
+       if (ret)
+               goto err;
 
        switch ((buf[1] >> 6) & 3) {
        case 0:
-               p->u.ofdm.constellation = QPSK;
+               c->modulation = QPSK;
                break;
        case 1:
-               p->u.ofdm.constellation = QAM_16;
+               c->modulation = QAM_16;
                break;
        case 2:
-               p->u.ofdm.constellation = QAM_64;
+               c->modulation = QAM_64;
                break;
        }
 
        switch ((buf[0] >> 0) & 3) {
        case 0:
-               p->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+               c->transmission_mode = TRANSMISSION_MODE_2K;
                break;
        case 1:
-               p->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+               c->transmission_mode = TRANSMISSION_MODE_8K;
        }
 
        switch ((buf[0] >> 2) & 3) {
        case 0:
-               p->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+               c->guard_interval = GUARD_INTERVAL_1_32;
                break;
        case 1:
-               p->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+               c->guard_interval = GUARD_INTERVAL_1_16;
                break;
        case 2:
-               p->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+               c->guard_interval = GUARD_INTERVAL_1_8;
                break;
        case 3:
-               p->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+               c->guard_interval = GUARD_INTERVAL_1_4;
                break;
        }
 
        switch ((buf[0] >> 4) & 7) {
        case 0:
-               p->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+               c->hierarchy = HIERARCHY_NONE;
                break;
        case 1:
-               p->u.ofdm.hierarchy_information = HIERARCHY_1;
+               c->hierarchy = HIERARCHY_1;
                break;
        case 2:
-               p->u.ofdm.hierarchy_information = HIERARCHY_2;
+               c->hierarchy = HIERARCHY_2;
                break;
        case 3:
-               p->u.ofdm.hierarchy_information = HIERARCHY_4;
+               c->hierarchy = HIERARCHY_4;
                break;
        }
 
        switch ((buf[2] >> 0) & 7) {
        case 0:
-               p->u.ofdm.code_rate_HP = FEC_1_2;
+               c->code_rate_HP = FEC_1_2;
                break;
        case 1:
-               p->u.ofdm.code_rate_HP = FEC_2_3;
-               break;
-       case 2:
-               p->u.ofdm.code_rate_HP = FEC_3_4;
-               break;
-       case 3:
-               p->u.ofdm.code_rate_HP = FEC_5_6;
-               break;
-       case 4:
-               p->u.ofdm.code_rate_HP = FEC_7_8;
-               break;
-       }
-
-       switch ((buf[2] >> 3) & 7) {
-       case 0:
-               p->u.ofdm.code_rate_LP = FEC_1_2;
-               break;
-       case 1:
-               p->u.ofdm.code_rate_LP = FEC_2_3;
-               break;
-       case 2:
-               p->u.ofdm.code_rate_LP = FEC_3_4;
-               break;
-       case 3:
-               p->u.ofdm.code_rate_LP = FEC_5_6;
-               break;
-       case 4:
-               p->u.ofdm.code_rate_LP = FEC_7_8;
-               break;
-       }
-
-       switch ((buf[1] >> 2) & 3) {
-       case 0:
-               p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
-               break;
-       case 1:
-               p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
-               break;
-       case 2:
-               p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
-               break;
-       }
-
-       p->inversion = INVERSION_AUTO;
-       p->frequency = state->frequency;
-
-error:
-       return ret;
-}
-
-static int af9013_update_ber_unc(struct dvb_frontend *fe)
-{
-       struct af9013_state *state = fe->demodulator_priv;
-       int ret;
-       u8 buf[3], i;
-       u32 error_bit_count = 0;
-       u32 total_bit_count = 0;
-       u32 abort_packet_count = 0;
-
-       state->ber = 0;
-
-       /* check if error bit count is ready */
-       ret = af9013_read_reg_bits(state, 0xd391, 4, 1, &buf[0]);
-       if (ret)
-               goto error;
-       if (!buf[0])
-               goto exit;
-
-       /* get RSD packet abort count */
-       for (i = 0; i < 2; i++) {
-               ret = af9013_read_reg(state, 0xd38a + i, &buf[i]);
-               if (ret)
-                       goto error;
-       }
-       abort_packet_count = (buf[1] << 8) + buf[0];
-
-       /* get error bit count */
-       for (i = 0; i < 3; i++) {
-               ret = af9013_read_reg(state, 0xd387 + i, &buf[i]);
-               if (ret)
-                       goto error;
-       }
-       error_bit_count = (buf[2] << 16) + (buf[1] << 8) + buf[0];
-       error_bit_count = error_bit_count - abort_packet_count * 8 * 8;
-
-       /* get used RSD counting period (10000 RSD packets used) */
-       for (i = 0; i < 2; i++) {
-               ret = af9013_read_reg(state, 0xd385 + i, &buf[i]);
-               if (ret)
-                       goto error;
-       }
-       total_bit_count = (buf[1] << 8) + buf[0];
-       total_bit_count = total_bit_count - abort_packet_count;
-       total_bit_count = total_bit_count * 204 * 8;
-
-       if (total_bit_count)
-               state->ber = error_bit_count * 1000000000 / total_bit_count;
-
-       state->ucblocks += abort_packet_count;
-
-       deb_info("%s: err bits:%d total bits:%d abort count:%d\n", __func__,
-               error_bit_count, total_bit_count, abort_packet_count);
-
-       /* set BER counting range */
-       ret = af9013_write_reg(state, 0xd385, 10000 & 0xff);
-       if (ret)
-               goto error;
-       ret = af9013_write_reg(state, 0xd386, 10000 >> 8);
-       if (ret)
-               goto error;
-       /* reset and start BER counter */
-       ret = af9013_write_reg_bits(state, 0xd391, 4, 1, 1);
-       if (ret)
-               goto error;
-
-exit:
-error:
-       return ret;
-}
-
-static int af9013_update_snr(struct dvb_frontend *fe)
-{
-       struct af9013_state *state = fe->demodulator_priv;
-       int ret;
-       u8 buf[3], i, len;
-       u32 quant = 0;
-       struct snr_table *uninitialized_var(snr_table);
-
-       /* check if quantizer ready (for snr) */
-       ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]);
-       if (ret)
-               goto error;
-       if (buf[0]) {
-               /* quantizer ready - read it */
-               for (i = 0; i < 3; i++) {
-                       ret = af9013_read_reg(state, 0xd2e3 + i, &buf[i]);
-                       if (ret)
-                               goto error;
-               }
-               quant = (buf[2] << 16) + (buf[1] << 8) + buf[0];
-
-               /* read current constellation */
-               ret = af9013_read_reg(state, 0xd3c1, &buf[0]);
-               if (ret)
-                       goto error;
-
-               switch ((buf[0] >> 6) & 3) {
-               case 0:
-                       len = ARRAY_SIZE(qpsk_snr_table);
-                       snr_table = qpsk_snr_table;
-                       break;
-               case 1:
-                       len = ARRAY_SIZE(qam16_snr_table);
-                       snr_table = qam16_snr_table;
-                       break;
-               case 2:
-                       len = ARRAY_SIZE(qam64_snr_table);
-                       snr_table = qam64_snr_table;
-                       break;
-               default:
-                       len = 0;
-                       break;
-               }
-
-               if (len) {
-                       for (i = 0; i < len; i++) {
-                               if (quant < snr_table[i].val) {
-                                       state->snr = snr_table[i].snr * 10;
-                                       break;
-                               }
-                       }
-               }
-
-               /* set quantizer super frame count */
-               ret = af9013_write_reg(state, 0xd2e2, 1);
-               if (ret)
-                       goto error;
-
-               /* check quantizer availability */
-               for (i = 0; i < 10; i++) {
-                       msleep(10);
-                       ret = af9013_read_reg_bits(state, 0xd2e6, 0, 1,
-                               &buf[0]);
-                       if (ret)
-                               goto error;
-                       if (!buf[0])
-                               break;
-               }
-
-               /* reset quantizer */
-               ret = af9013_write_reg_bits(state, 0xd2e1, 3, 1, 1);
-               if (ret)
-                       goto error;
+               c->code_rate_HP = FEC_2_3;
+               break;
+       case 2:
+               c->code_rate_HP = FEC_3_4;
+               break;
+       case 3:
+               c->code_rate_HP = FEC_5_6;
+               break;
+       case 4:
+               c->code_rate_HP = FEC_7_8;
+               break;
        }
 
-error:
-       return ret;
-}
-
-static int af9013_update_signal_strength(struct dvb_frontend *fe)
-{
-       struct af9013_state *state = fe->demodulator_priv;
-       int ret = 0;
-       u8 rf_gain, if_gain;
-       int signal_strength;
-
-       deb_info("%s\n", __func__);
+       switch ((buf[2] >> 3) & 7) {
+       case 0:
+               c->code_rate_LP = FEC_1_2;
+               break;
+       case 1:
+               c->code_rate_LP = FEC_2_3;
+               break;
+       case 2:
+               c->code_rate_LP = FEC_3_4;
+               break;
+       case 3:
+               c->code_rate_LP = FEC_5_6;
+               break;
+       case 4:
+               c->code_rate_LP = FEC_7_8;
+               break;
+       }
 
-       if (state->signal_strength_en) {
-               ret = af9013_read_reg(state, 0xd07c, &rf_gain);
-               if (ret)
-                       goto error;
-               ret = af9013_read_reg(state, 0xd07d, &if_gain);
-               if (ret)
-                       goto error;
-               signal_strength = (0xffff / \
-                       (9 * (state->rf_50 + state->if_50) - \
-                       11 * (state->rf_80 + state->if_80))) * \
-                       (10 * (rf_gain + if_gain) - \
-                       11 * (state->rf_80 + state->if_80));
-               if (signal_strength < 0)
-                       signal_strength = 0;
-               else if (signal_strength > 0xffff)
-                       signal_strength = 0xffff;
-
-               state->signal_strength = signal_strength;
-       } else {
-               state->signal_strength = 0;
+       switch ((buf[1] >> 2) & 3) {
+       case 0:
+               c->bandwidth_hz = 6000000;
+               break;
+       case 1:
+               c->bandwidth_hz = 7000000;
+               break;
+       case 2:
+               c->bandwidth_hz = 8000000;
+               break;
        }
 
-error:
        return ret;
-}
-
-static int af9013_update_statistics(struct dvb_frontend *fe)
-{
-       struct af9013_state *state = fe->demodulator_priv;
-       int ret;
-
-       if (time_before(jiffies, state->next_statistics_check))
-               return 0;
-
-       /* set minimum statistic update interval */
-       state->next_statistics_check = jiffies + msecs_to_jiffies(1200);
-
-       ret = af9013_update_signal_strength(fe);
-       if (ret)
-               goto error;
-       ret = af9013_update_snr(fe);
-       if (ret)
-               goto error;
-       ret = af9013_update_ber_unc(fe);
-       if (ret)
-               goto error;
-
-error:
+err:
+       dbg("%s: failed=%d", __func__, ret);
        return ret;
 }
 
-static int af9013_get_tune_settings(struct dvb_frontend *fe,
-       struct dvb_frontend_tune_settings *fesettings)
-{
-       fesettings->min_delay_ms = 800;
-       fesettings->step_size = 0;
-       fesettings->max_drift = 0;
-
-       return 0;
-}
-
 static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
        struct af9013_state *state = fe->demodulator_priv;
-       int ret = 0;
+       int ret;
        u8 tmp;
-       *status = 0;
+
+       /*
+        * Return status from the cache if it is younger than 2000ms with the
+        * exception of last tune is done during 4000ms.
+        */
+       if (time_is_after_jiffies(
+               state->read_status_jiffies + msecs_to_jiffies(2000)) &&
+               time_is_before_jiffies(
+               state->set_frontend_jiffies + msecs_to_jiffies(4000))
+       ) {
+                       *status = state->fe_status;
+                       return 0;
+       } else {
+               *status = 0;
+       }
 
        /* MPEG2 lock */
-       ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp);
+       ret = af9013_rd_reg_bits(state, 0xd507, 6, 1, &tmp);
        if (ret)
-               goto error;
+               goto err;
+
        if (tmp)
                *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
                        FE_HAS_SYNC | FE_HAS_LOCK;
 
        if (!*status) {
                /* TPS lock */
-               ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp);
+               ret = af9013_rd_reg_bits(state, 0xd330, 3, 1, &tmp);
                if (ret)
-                       goto error;
+                       goto err;
+
                if (tmp)
                        *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
                                FE_HAS_VITERBI;
        }
 
-       if (!*status) {
-               /* CFO lock */
-               ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp);
-               if (ret)
-                       goto error;
-               if (tmp)
-                       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
-       }
-
-       if (!*status) {
-               /* SFOE lock */
-               ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp);
-               if (ret)
-                       goto error;
-               if (tmp)
-                       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
-       }
-
-       if (!*status) {
-               /* AGC lock */
-               ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp);
-               if (ret)
-                       goto error;
-               if (tmp)
-                       *status |= FE_HAS_SIGNAL;
-       }
-
-       ret = af9013_update_statistics(fe);
+       state->fe_status = *status;
+       state->read_status_jiffies = jiffies;
 
-error:
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
        return ret;
 }
 
-
-static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber)
+static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
        struct af9013_state *state = fe->demodulator_priv;
-       int ret;
-       ret = af9013_update_statistics(fe);
-       *ber = state->ber;
-       return ret;
+       *snr = state->snr;
+       return 0;
 }
 
 static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
        struct af9013_state *state = fe->demodulator_priv;
-       int ret;
-       ret = af9013_update_statistics(fe);
        *strength = state->signal_strength;
-       return ret;
+       return 0;
 }
 
-static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr)
+static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
        struct af9013_state *state = fe->demodulator_priv;
-       int ret;
-       ret = af9013_update_statistics(fe);
-       *snr = state->snr;
-       return ret;
+       *ber = state->ber;
+       return 0;
 }
 
 static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
        struct af9013_state *state = fe->demodulator_priv;
-       int ret;
-       ret = af9013_update_statistics(fe);
        *ucblocks = state->ucblocks;
-       return ret;
-}
-
-static int af9013_sleep(struct dvb_frontend *fe)
-{
-       struct af9013_state *state = fe->demodulator_priv;
-       int ret;
-       deb_info("%s\n", __func__);
-
-       ret = af9013_lock_led(state, 0);
-       if (ret)
-               goto error;
-
-       ret = af9013_power_ctrl(state, 0);
-error:
-       return ret;
+       return 0;
 }
 
 static int af9013_init(struct dvb_frontend *fe)
 {
        struct af9013_state *state = fe->demodulator_priv;
        int ret, i, len;
-       u8 tmp0, tmp1;
-       struct regdesc *init;
-       deb_info("%s\n", __func__);
+       u8 buf[3], tmp;
+       u32 adc_cw;
+       const struct af9013_reg_bit *init;
 
-       /* reset OFDM */
-       ret = af9013_reset(state, 0);
-       if (ret)
-               goto error;
+       dbg("%s", __func__);
 
        /* power on */
        ret = af9013_power_ctrl(state, 1);
        if (ret)
-               goto error;
+               goto err;
 
        /* enable ADC */
-       ret = af9013_write_reg(state, 0xd73a, 0xa4);
+       ret = af9013_wr_reg(state, 0xd73a, 0xa4);
        if (ret)
-               goto error;
+               goto err;
 
        /* write API version to firmware */
-       for (i = 0; i < sizeof(state->config.api_version); i++) {
-               ret = af9013_write_reg(state, 0x9bf2 + i,
-                       state->config.api_version[i]);
-               if (ret)
-                       goto error;
-       }
+       ret = af9013_wr_regs(state, 0x9bf2, state->config.api_version, 4);
+       if (ret)
+               goto err;
 
        /* program ADC control */
-       ret = af9013_set_adc_ctrl(state);
+       switch (state->config.clock) {
+       case 28800000: /* 28.800 MHz */
+               tmp = 0;
+               break;
+       case 20480000: /* 20.480 MHz */
+               tmp = 1;
+               break;
+       case 28000000: /* 28.000 MHz */
+               tmp = 2;
+               break;
+       case 25000000: /* 25.000 MHz */
+               tmp = 3;
+               break;
+       default:
+               err("invalid clock");
+               return -EINVAL;
+       }
+
+       adc_cw = af913_div(state->config.clock, 1000000ul, 19);
+       buf[0] = (adc_cw >>  0) & 0xff;
+       buf[1] = (adc_cw >>  8) & 0xff;
+       buf[2] = (adc_cw >> 16) & 0xff;
+
+       ret = af9013_wr_regs(state, 0xd180, buf, 3);
+       if (ret)
+               goto err;
+
+       ret = af9013_wr_reg_bits(state, 0x9bd2, 0, 4, tmp);
        if (ret)
-               goto error;
+               goto err;
 
        /* set I2C master clock */
-       ret = af9013_write_reg(state, 0xd416, 0x14);
+       ret = af9013_wr_reg(state, 0xd416, 0x14);
        if (ret)
-               goto error;
+               goto err;
 
        /* set 16 embx */
-       ret = af9013_write_reg_bits(state, 0xd700, 1, 1, 1);
+       ret = af9013_wr_reg_bits(state, 0xd700, 1, 1, 1);
        if (ret)
-               goto error;
+               goto err;
 
        /* set no trigger */
-       ret = af9013_write_reg_bits(state, 0xd700, 2, 1, 0);
+       ret = af9013_wr_reg_bits(state, 0xd700, 2, 1, 0);
        if (ret)
-               goto error;
+               goto err;
 
        /* set read-update bit for constellation */
-       ret = af9013_write_reg_bits(state, 0xd371, 1, 1, 1);
+       ret = af9013_wr_reg_bits(state, 0xd371, 1, 1, 1);
        if (ret)
-               goto error;
+               goto err;
 
-       /* enable FEC monitor */
-       ret = af9013_write_reg_bits(state, 0xd392, 1, 1, 1);
+       /* settings for mp2if */
+       if (state->config.ts_mode == AF9013_TS_USB) {
+               /* AF9015 split PSB to 1.5k + 0.5k */
+               ret = af9013_wr_reg_bits(state, 0xd50b, 2, 1, 1);
+               if (ret)
+                       goto err;
+       } else {
+               /* AF9013 change the output bit to data7 */
+               ret = af9013_wr_reg_bits(state, 0xd500, 3, 1, 1);
+               if (ret)
+                       goto err;
+
+               /* AF9013 set mpeg to full speed */
+               ret = af9013_wr_reg_bits(state, 0xd502, 4, 1, 1);
+               if (ret)
+                       goto err;
+       }
+
+       ret = af9013_wr_reg_bits(state, 0xd520, 4, 1, 1);
        if (ret)
-               goto error;
+               goto err;
 
        /* load OFSM settings */
-       deb_info("%s: load ofsm settings\n", __func__);
+       dbg("%s: load ofsm settings", __func__);
        len = ARRAY_SIZE(ofsm_init);
        init = ofsm_init;
        for (i = 0; i < len; i++) {
-               ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos,
+               ret = af9013_wr_reg_bits(state, init[i].addr, init[i].pos,
                        init[i].len, init[i].val);
                if (ret)
-                       goto error;
+                       goto err;
        }
 
        /* load tuner specific settings */
-       deb_info("%s: load tuner specific settings\n", __func__);
+       dbg("%s: load tuner specific settings", __func__);
        switch (state->config.tuner) {
        case AF9013_TUNER_MXL5003D:
                len = ARRAY_SIZE(tuner_init_mxl5003d);
@@ -1260,65 +1197,133 @@ static int af9013_init(struct dvb_frontend *fe)
        }
 
        for (i = 0; i < len; i++) {
-               ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos,
+               ret = af9013_wr_reg_bits(state, init[i].addr, init[i].pos,
                        init[i].len, init[i].val);
                if (ret)
-                       goto error;
+                       goto err;
        }
 
-       /* set TS mode */
-       deb_info("%s: setting ts mode\n", __func__);
-       tmp0 = 0; /* parallel mode */
-       tmp1 = 0; /* serial mode */
-       switch (state->config.output_mode) {
-       case AF9013_OUTPUT_MODE_PARALLEL:
-               tmp0 = 1;
-               break;
-       case AF9013_OUTPUT_MODE_SERIAL:
-               tmp1 = 1;
-               break;
-       case AF9013_OUTPUT_MODE_USB:
-               /* usb mode for AF9015 */
-       default:
-               break;
-       }
-       ret = af9013_write_reg_bits(state, 0xd500, 1, 1, tmp0); /* parallel */
+       /* TS mode */
+       ret = af9013_wr_reg_bits(state, 0xd500, 1, 2, state->config.ts_mode);
        if (ret)
-               goto error;
-       ret = af9013_write_reg_bits(state, 0xd500, 2, 1, tmp1); /* serial */
-       if (ret)
-               goto error;
+               goto err;
 
        /* enable lock led */
-       ret = af9013_lock_led(state, 1);
+       ret = af9013_wr_reg_bits(state, 0xd730, 0, 1, 1);
        if (ret)
-               goto error;
+               goto err;
 
-       /* read values needed for signal strength calculation */
-       ret = af9013_read_reg_bits(state, 0x9bee, 0, 1,
-               &state->signal_strength_en);
-       if (ret)
-               goto error;
+       /* check if we support signal strength */
+       if (!state->signal_strength_en) {
+               ret = af9013_rd_reg_bits(state, 0x9bee, 0, 1,
+                       &state->signal_strength_en);
+               if (ret)
+                       goto err;
+       }
 
-       if (state->signal_strength_en) {
-               ret = af9013_read_reg(state, 0x9bbd, &state->rf_50);
+       /* read values needed for signal strength calculation */
+       if (state->signal_strength_en && !state->rf_50) {
+               ret = af9013_rd_reg(state, 0x9bbd, &state->rf_50);
                if (ret)
-                       goto error;
-               ret = af9013_read_reg(state, 0x9bd0, &state->rf_80);
+                       goto err;
+
+               ret = af9013_rd_reg(state, 0x9bd0, &state->rf_80);
                if (ret)
-                       goto error;
-               ret = af9013_read_reg(state, 0x9be2, &state->if_50);
+                       goto err;
+
+               ret = af9013_rd_reg(state, 0x9be2, &state->if_50);
                if (ret)
-                       goto error;
-               ret = af9013_read_reg(state, 0x9be4, &state->if_80);
+                       goto err;
+
+               ret = af9013_rd_reg(state, 0x9be4, &state->if_80);
                if (ret)
-                       goto error;
+                       goto err;
        }
 
-error:
+       /* SNR */
+       ret = af9013_wr_reg(state, 0xd2e2, 1);
+       if (ret)
+               goto err;
+
+       /* BER / UCB */
+       buf[0] = (10000 >> 0) & 0xff;
+       buf[1] = (10000 >> 8) & 0xff;
+       ret = af9013_wr_regs(state, 0xd385, buf, 2);
+       if (ret)
+               goto err;
+
+       /* enable FEC monitor */
+       ret = af9013_wr_reg_bits(state, 0xd392, 1, 1, 1);
+       if (ret)
+               goto err;
+
+       state->first_tune = true;
+       schedule_delayed_work(&state->statistics_work, msecs_to_jiffies(400));
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int af9013_sleep(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       int ret;
+
+       dbg("%s", __func__);
+
+       /* stop statistics polling */
+       cancel_delayed_work_sync(&state->statistics_work);
+
+       /* disable lock led */
+       ret = af9013_wr_reg_bits(state, 0xd730, 0, 1, 0);
+       if (ret)
+               goto err;
+
+       /* power off */
+       ret = af9013_power_ctrl(state, 0);
+       if (ret)
+               goto err;
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       int ret;
+       struct af9013_state *state = fe->demodulator_priv;
+
+       dbg("%s: enable=%d", __func__, enable);
+
+       /* gate already open or close */
+       if (state->i2c_gate_state == enable)
+               return 0;
+
+       if (state->config.ts_mode == AF9013_TS_USB)
+               ret = af9013_wr_reg_bits(state, 0xd417, 3, 1, enable);
+       else
+               ret = af9013_wr_reg_bits(state, 0xd607, 2, 1, enable);
+       if (ret)
+               goto err;
+
+       state->i2c_gate_state = enable;
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
        return ret;
 }
 
+static void af9013_release(struct dvb_frontend *fe)
+{
+       struct af9013_state *state = fe->demodulator_priv;
+       kfree(state);
+}
+
 static struct dvb_frontend_ops af9013_ops;
 
 static int af9013_download_firmware(struct af9013_state *state)
@@ -1332,11 +1337,11 @@ static int af9013_download_firmware(struct af9013_state *state)
 
        msleep(100);
        /* check whether firmware is already running */
-       ret = af9013_read_reg(state, 0x98be, &val);
+       ret = af9013_rd_reg(state, 0x98be, &val);
        if (ret)
-               goto error;
+               goto err;
        else
-               deb_info("%s: firmware status:%02x\n", __func__, val);
+               dbg("%s: firmware status=%02x", __func__, val);
 
        if (val == 0x0c) /* fw is running, no need for download */
                goto exit;
@@ -1351,7 +1356,7 @@ static int af9013_download_firmware(struct af9013_state *state)
                        "Please see linux/Documentation/dvb/ for more details" \
                        " on firmware-problems. (%d)",
                        fw_file, ret);
-               goto error;
+               goto err;
        }
 
        info("downloading firmware from file '%s'", fw_file);
@@ -1369,7 +1374,7 @@ static int af9013_download_firmware(struct af9013_state *state)
        ret = af9013_write_ofsm_regs(state, 0x50fc,
                fw_params, sizeof(fw_params));
        if (ret)
-               goto error_release;
+               goto err_release;
 
        #define FW_ADDR 0x5100 /* firmware start address */
        #define LEN_MAX 16 /* max packet size */
@@ -1383,24 +1388,24 @@ static int af9013_download_firmware(struct af9013_state *state)
                        (u8 *) &fw->data[fw->size - remaining], len);
                if (ret) {
                        err("firmware download failed:%d", ret);
-                       goto error_release;
+                       goto err_release;
                }
        }
 
        /* request boot firmware */
-       ret = af9013_write_reg(state, 0xe205, 1);
+       ret = af9013_wr_reg(state, 0xe205, 1);
        if (ret)
-               goto error_release;
+               goto err_release;
 
        for (i = 0; i < 15; i++) {
                msleep(100);
 
                /* check firmware status */
-               ret = af9013_read_reg(state, 0x98be, &val);
+               ret = af9013_rd_reg(state, 0x98be, &val);
                if (ret)
-                       goto error_release;
+                       goto err_release;
 
-               deb_info("%s: firmware status:%02x\n", __func__, val);
+               dbg("%s: firmware status=%02x", __func__, val);
 
                if (val == 0x0c || val == 0x04) /* success or fail */
                        break;
@@ -1408,43 +1413,21 @@ static int af9013_download_firmware(struct af9013_state *state)
 
        if (val == 0x04) {
                err("firmware did not run");
-               ret = -1;
+               ret = -ENODEV;
        } else if (val != 0x0c) {
                err("firmware boot timeout");
-               ret = -1;
+               ret = -ENODEV;
        }
 
-error_release:
+err_release:
        release_firmware(fw);
-error:
+err:
 exit:
        if (!ret)
                info("found a '%s' in warm state.", af9013_ops.info.name);
        return ret;
 }
 
-static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-       int ret;
-       struct af9013_state *state = fe->demodulator_priv;
-       deb_info("%s: enable:%d\n", __func__, enable);
-
-       if (state->config.output_mode == AF9013_OUTPUT_MODE_USB)
-               ret = af9013_write_reg_bits(state, 0xd417, 3, 1, enable);
-       else
-               ret = af9013_write_reg_bits(state, 0xd607, 2, 1, enable);
-
-       return ret;
-}
-
-static void af9013_release(struct dvb_frontend *fe)
-{
-       struct af9013_state *state = fe->demodulator_priv;
-       kfree(state);
-}
-
-static struct dvb_frontend_ops af9013_ops;
-
 struct dvb_frontend *af9013_attach(const struct af9013_config *config,
        struct i2c_adapter *i2c)
 {
@@ -1455,91 +1438,65 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config,
        /* allocate memory for the internal state */
        state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL);
        if (state == NULL)
-               goto error;
+               goto err;
 
        /* setup the state */
        state->i2c = i2c;
        memcpy(&state->config, config, sizeof(struct af9013_config));
 
        /* download firmware */
-       if (state->config.output_mode != AF9013_OUTPUT_MODE_USB) {
+       if (state->config.ts_mode != AF9013_TS_USB) {
                ret = af9013_download_firmware(state);
                if (ret)
-                       goto error;
+                       goto err;
        }
 
        /* firmware version */
-       for (i = 0; i < 4; i++) {
-               ret = af9013_read_reg(state, 0x5103 + i, &buf[i]);
-               if (ret)
-                       goto error;
-       }
-       info("firmware version:%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]);
-
-       /* chip version */
-       ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]);
+       ret = af9013_rd_regs(state, 0x5103, buf, 4);
        if (ret)
-               goto error;
-
-       /* ROM version */
-       for (i = 0; i < 2; i++) {
-               ret = af9013_read_reg(state, 0x116b + i, &buf[i]);
-               if (ret)
-                       goto error;
-       }
-       deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__,
-               buf[2], buf[0], buf[1]);
+               goto err;
 
-       /* settings for mp2if */
-       if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) {
-               /* AF9015 split PSB to 1.5k + 0.5k */
-               ret = af9013_write_reg_bits(state, 0xd50b, 2, 1, 1);
-       } else {
-               /* AF9013 change the output bit to data7 */
-               ret = af9013_write_reg_bits(state, 0xd500, 3, 1, 1);
-               if (ret)
-                       goto error;
-               /* AF9013 set mpeg to full speed */
-               ret = af9013_write_reg_bits(state, 0xd502, 4, 1, 1);
-       }
-       if (ret)
-               goto error;
-       ret = af9013_write_reg_bits(state, 0xd520, 4, 1, 1);
-       if (ret)
-               goto error;
+       info("firmware version %d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]);
 
        /* set GPIOs */
        for (i = 0; i < sizeof(state->config.gpio); i++) {
                ret = af9013_set_gpio(state, i, state->config.gpio[i]);
                if (ret)
-                       goto error;
+                       goto err;
        }
 
        /* create dvb_frontend */
-       memcpy(&state->frontend.ops, &af9013_ops,
+       memcpy(&state->fe.ops, &af9013_ops,
                sizeof(struct dvb_frontend_ops));
-       state->frontend.demodulator_priv = state;
+       state->fe.demodulator_priv = state;
+
+       INIT_DELAYED_WORK(&state->statistics_work, af9013_statistics_work);
 
-       return &state->frontend;
-error:
+       return &state->fe;
+err:
        kfree(state);
        return NULL;
 }
 EXPORT_SYMBOL(af9013_attach);
 
 static struct dvb_frontend_ops af9013_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
-               .name = "Afatech AF9013 DVB-T",
-               .type = FE_OFDM,
+               .name = "Afatech AF9013",
                .frequency_min = 174000000,
                .frequency_max = 862000000,
                .frequency_stepsize = 250000,
                .frequency_tolerance = 0,
-               .caps =
-                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-                       FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-                       FE_CAN_QPSK | FE_CAN_QAM_16 |
-                       FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+               .caps = FE_CAN_FEC_1_2 |
+                       FE_CAN_FEC_2_3 |
+                       FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 |
+                       FE_CAN_FEC_7_8 |
+                       FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK |
+                       FE_CAN_QAM_16 |
+                       FE_CAN_QAM_64 |
+                       FE_CAN_QAM_AUTO |
                        FE_CAN_TRANSMISSION_MODE_AUTO |
                        FE_CAN_GUARD_INTERVAL_AUTO |
                        FE_CAN_HIERARCHY_AUTO |
@@ -1548,24 +1505,22 @@ static struct dvb_frontend_ops af9013_ops = {
        },
 
        .release = af9013_release,
+
        .init = af9013_init,
        .sleep = af9013_sleep,
-       .i2c_gate_ctrl = af9013_i2c_gate_ctrl,
 
+       .get_tune_settings = af9013_get_tune_settings,
        .set_frontend = af9013_set_frontend,
        .get_frontend = af9013_get_frontend,
 
-       .get_tune_settings = af9013_get_tune_settings,
-
        .read_status = af9013_read_status,
-       .read_ber = af9013_read_ber,
-       .read_signal_strength = af9013_read_signal_strength,
        .read_snr = af9013_read_snr,
+       .read_signal_strength = af9013_read_signal_strength,
+       .read_ber = af9013_read_ber,
        .read_ucblocks = af9013_read_ucblocks,
-};
 
-module_param_named(debug, af9013_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+       .i2c_gate_ctrl = af9013_i2c_gate_ctrl,
+};
 
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver");
index e53d873f75557e273735179be49e968ad2fc44c9..b973fc5a03844d68db01ee8ed2743192688b9263 100644 (file)
@@ -2,6 +2,7 @@
  * Afatech AF9013 demodulator driver
  *
  * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
  *
  * Thanks to Afatech who kindly provided information.
  *
  *
  */
 
-#ifndef _AF9013_H_
-#define _AF9013_H_
+#ifndef AF9013_H
+#define AF9013_H
 
 #include <linux/dvb/frontend.h>
 
-enum af9013_ts_mode {
-       AF9013_OUTPUT_MODE_PARALLEL,
-       AF9013_OUTPUT_MODE_SERIAL,
-       AF9013_OUTPUT_MODE_USB, /* only for AF9015 */
-};
-
-enum af9013_tuner {
-       AF9013_TUNER_MXL5003D   =   3, /* MaxLinear */
-       AF9013_TUNER_MXL5005D   =  13, /* MaxLinear */
-       AF9013_TUNER_MXL5005R   =  30, /* MaxLinear */
-       AF9013_TUNER_ENV77H11D5 = 129, /* Panasonic */
-       AF9013_TUNER_MT2060     = 130, /* Microtune */
-       AF9013_TUNER_MC44S803   = 133, /* Freescale */
-       AF9013_TUNER_QT1010     = 134, /* Quantek */
-       AF9013_TUNER_UNKNOWN    = 140, /* for can tuners ? */
-       AF9013_TUNER_MT2060_2   = 147, /* Microtune */
-       AF9013_TUNER_TDA18271   = 156, /* NXP */
-       AF9013_TUNER_QT1010A    = 162, /* Quantek */
-       AF9013_TUNER_MXL5007T   = 177, /* MaxLinear */
-       AF9013_TUNER_TDA18218   = 179, /* NXP */
-};
-
 /* AF9013/5 GPIOs (mostly guessed)
    demod#1-gpio#0 - set demod#2 i2c-addr for dual devices
    demod#1-gpio#1 - xtal setting (?)
@@ -55,44 +34,74 @@ enum af9013_tuner {
    demod#2-gpio#0 - tuner#2
    demod#2-gpio#1 - xtal setting (?)
 */
+
+struct af9013_config {
+       /*
+        * I2C address
+        */
+       u8 i2c_addr;
+
+       /*
+        * clock
+        * 20480000, 25000000, 28000000, 28800000
+        */
+       u32 clock;
+
+       /*
+        * tuner
+        */
+#define AF9013_TUNER_MXL5003D      3 /* MaxLinear */
+#define AF9013_TUNER_MXL5005D     13 /* MaxLinear */
+#define AF9013_TUNER_MXL5005R     30 /* MaxLinear */
+#define AF9013_TUNER_ENV77H11D5  129 /* Panasonic */
+#define AF9013_TUNER_MT2060      130 /* Microtune */
+#define AF9013_TUNER_MC44S803    133 /* Freescale */
+#define AF9013_TUNER_QT1010      134 /* Quantek */
+#define AF9013_TUNER_UNKNOWN     140 /* for can tuners ? */
+#define AF9013_TUNER_MT2060_2    147 /* Microtune */
+#define AF9013_TUNER_TDA18271    156 /* NXP */
+#define AF9013_TUNER_QT1010A     162 /* Quantek */
+#define AF9013_TUNER_MXL5007T    177 /* MaxLinear */
+#define AF9013_TUNER_TDA18218    179 /* NXP */
+       u8 tuner;
+
+       /*
+        * IF frequency
+        */
+       u32 if_frequency;
+
+       /*
+        * TS settings
+        */
+#define AF9013_TS_USB       0
+#define AF9013_TS_PARALLEL  1
+#define AF9013_TS_SERIAL    2
+       u8 ts_mode:2;
+
+       /*
+        * input spectrum inversion
+        */
+       bool spec_inv;
+
+       /*
+        * firmware API version
+        */
+       u8 api_version[4];
+
+       /*
+        * GPIOs
+        */
 #define AF9013_GPIO_ON (1 << 0)
 #define AF9013_GPIO_EN (1 << 1)
 #define AF9013_GPIO_O  (1 << 2)
 #define AF9013_GPIO_I  (1 << 3)
-
 #define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN)
 #define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
-
 #define AF9013_GPIO_TUNER_ON  (AF9013_GPIO_ON|AF9013_GPIO_EN)
 #define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O)
-
-struct af9013_config {
-       /* demodulator's I2C address */
-       u8 demod_address;
-
-       /* frequencies in kHz */
-       u32 adc_clock;
-
-       /* tuner ID */
-       u8 tuner;
-
-       /* tuner IF */
-       u16 tuner_if;
-
-       /* TS data output mode */
-       u8 output_mode:2;
-
-       /* RF spectrum inversion */
-       u8 rf_spec_inv:1;
-
-       /* API version */
-       u8 api_version[4];
-
-       /* GPIOs */
        u8 gpio[4];
 };
 
-
 #if defined(CONFIG_DVB_AF9013) || \
        (defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE))
 extern struct dvb_frontend *af9013_attach(const struct af9013_config *config,
@@ -106,4 +115,4 @@ const struct af9013_config *config, struct i2c_adapter *i2c)
 }
 #endif /* CONFIG_DVB_AF9013 */
 
-#endif /* _AF9013_H_ */
+#endif /* AF9013_H */
index e00b2a4a2db6503a190a430066c7156c71fe3959..fa848af6e9b403fe6b8c7d9eec07d9b06647776b 100644 (file)
@@ -2,6 +2,7 @@
  * Afatech AF9013 demodulator driver
  *
  * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
  *
  * Thanks to Afatech who kindly provided information.
  *
  *
  */
 
-#ifndef _AF9013_PRIV_
-#define _AF9013_PRIV_
+#ifndef AF9013_PRIV_H
+#define AF9013_PRIV_H
 
-#define LOG_PREFIX "af9013"
-extern int af9013_debug;
-
-#define dprintk(var, level, args...) \
-           do { if ((var & level)) printk(args); } while (0)
+#include "dvb_frontend.h"
+#include "af9013.h"
+#include <linux/firmware.h>
 
-#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(af9013_debug, 0x01, args)
+#define LOG_PREFIX "af9013"
 
+#undef dbg
+#define dbg(f, arg...) \
+       if (af9013_debug) \
+               printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
 #undef err
 #define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
 #undef info
@@ -48,70 +44,71 @@ extern int af9013_debug;
 
 #define AF9013_DEFAULT_FIRMWARE     "dvb-fe-af9013.fw"
 
-struct regdesc {
+struct af9013_reg_bit {
        u16 addr;
        u8  pos:4;
        u8  len:4;
        u8  val;
 };
 
-struct snr_table {
+struct af9013_snr {
        u32 val;
        u8 snr;
 };
 
-struct coeff {
-       u32 adc_clock;
-       fe_bandwidth_t bw;
+struct af9013_coeff {
+       u32 clock;
+       u32 bandwidth_hz;
        u8 val[24];
 };
 
 /* pre-calculated coeff lookup table */
-static struct coeff coeff_table[] = {
+static const struct af9013_coeff coeff_lut[] = {
        /* 28.800 MHz */
-       { 28800, BANDWIDTH_8_MHZ, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14,
+       { 28800000, 8000000, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14,
                0x51, 0x11, 0x00, 0xa2, 0x8f, 0x3d, 0x00, 0xa2, 0x8a,
                0x29, 0x00, 0xa2, 0x85, 0x14, 0x01, 0x45, 0x14, 0x14 } },
-       { 28800, BANDWIDTH_7_MHZ, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71,
+       { 28800000, 7000000, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71,
                0xc7, 0x07, 0x00, 0x8e, 0x3d, 0x55, 0x00, 0x8e, 0x38,
                0xe4, 0x00, 0x8e, 0x34, 0x72, 0x01, 0x1c, 0x71, 0x32 } },
-       { 28800, BANDWIDTH_6_MHZ, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf,
+       { 28800000, 6000000, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf,
                0x3c, 0x3d, 0x00, 0x79, 0xeb, 0x6e, 0x00, 0x79, 0xe7,
                0x9e, 0x00, 0x79, 0xe3, 0xcf, 0x00, 0xf3, 0xcf, 0x0f } },
        /* 20.480 MHz */
-       { 20480, BANDWIDTH_8_MHZ, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24,
+       { 20480000, 8000000, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24,
                0x92, 0x13, 0x00, 0xe4, 0x99, 0x6e, 0x00, 0xe4, 0x92,
                0x49, 0x00, 0xe4, 0x8b, 0x25, 0x01, 0xc9, 0x24, 0x25 } },
-       { 20480, BANDWIDTH_7_MHZ, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40,
+       { 20480000, 7000000, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40,
                0x00, 0x00, 0x00, 0xc8, 0x06, 0x40, 0x00, 0xc8, 0x00,
                0x00, 0x00, 0xc7, 0xf9, 0xc0, 0x01, 0x90, 0x00, 0x00 } },
-       { 20480, BANDWIDTH_6_MHZ, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b,
+       { 20480000, 6000000, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b,
                0x6d, 0x2e, 0x00, 0xab, 0x73, 0x13, 0x00, 0xab, 0x6d,
                0xb7, 0x00, 0xab, 0x68, 0x5c, 0x01, 0x56, 0xdb, 0x1c } },
        /* 28.000 MHz */
-       { 28000, BANDWIDTH_8_MHZ, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39,
+       { 28000000, 8000000, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39,
                0x78, 0x0a, 0x00, 0xa7, 0x34, 0x3f, 0x00, 0xa7, 0x2f,
                0x05, 0x00, 0xa7, 0x29, 0xcc, 0x01, 0x4e, 0x5e, 0x03 } },
-       { 28000, BANDWIDTH_7_MHZ, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92,
+       { 28000000, 7000000, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92,
                0x49, 0x09, 0x00, 0x92, 0x4d, 0xb7, 0x00, 0x92, 0x49,
                0x25, 0x00, 0x92, 0x44, 0x92, 0x01, 0x24, 0x92, 0x12 } },
-       { 28000, BANDWIDTH_6_MHZ, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb,
+       { 28000000, 6000000, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb,
                0x1a, 0x08, 0x00, 0x7d, 0x67, 0x2f, 0x00, 0x7d, 0x63,
                0x44, 0x00, 0x7d, 0x5f, 0x59, 0x00, 0xfa, 0xc6, 0x22 } },
        /* 25.000 MHz */
-       { 25000, BANDWIDTH_8_MHZ, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9,
+       { 25000000, 8000000, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9,
                0xf7, 0x0e, 0x00, 0xbb, 0x44, 0xc1, 0x00, 0xbb, 0x3e,
                0xe7, 0x00, 0xbb, 0x39, 0x0d, 0x01, 0x76, 0x7d, 0x34 } },
-       { 25000, BANDWIDTH_7_MHZ, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e,
+       { 25000000, 7000000, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e,
                0xb8, 0x14, 0x00, 0xa3, 0xdc, 0x29, 0x00, 0xa3, 0xd7,
                0x0a, 0x00, 0xa3, 0xd1, 0xec, 0x01, 0x47, 0xae, 0x05 } },
-       { 25000, BANDWIDTH_6_MHZ, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63,
+       { 25000000, 6000000, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63,
                0x79, 0x1b, 0x00, 0x8c, 0x73, 0x91, 0x00, 0x8c, 0x6f,
                0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } },
 };
 
 /* QPSK SNR lookup table */
-static struct snr_table qpsk_snr_table[] = {
+static const struct af9013_snr qpsk_snr_lut[] = {
+       { 0x000000,  0 },
        { 0x0b4771,  0 },
        { 0x0c1aed,  1 },
        { 0x0d0d27,  2 },
@@ -131,7 +128,8 @@ static struct snr_table qpsk_snr_table[] = {
 };
 
 /* QAM16 SNR lookup table */
-static struct snr_table qam16_snr_table[] = {
+static const struct af9013_snr qam16_snr_lut[] = {
+       { 0x000000,  0 },
        { 0x05eb62,  5 },
        { 0x05fecf,  6 },
        { 0x060b80,  7 },
@@ -151,7 +149,8 @@ static struct snr_table qam16_snr_table[] = {
 };
 
 /* QAM64 SNR lookup table */
-static struct snr_table qam64_snr_table[] = {
+static const struct af9013_snr qam64_snr_lut[] = {
+       { 0x000000,  0 },
        { 0x03109b, 12 },
        { 0x0310d4, 13 },
        { 0x031920, 14 },
@@ -170,7 +169,7 @@ static struct snr_table qam64_snr_table[] = {
        { 0xffffff, 27 },
 };
 
-static struct regdesc ofsm_init[] = {
+static const struct af9013_reg_bit ofsm_init[] = {
        { 0xd73a, 0, 8, 0xa1 },
        { 0xd73b, 0, 8, 0x1f },
        { 0xd73c, 4, 4, 0x0a },
@@ -252,7 +251,7 @@ static struct regdesc ofsm_init[] = {
 
 /* Panasonic ENV77H11D5 tuner init
    AF9013_TUNER_ENV77H11D5 = 129 */
-static struct regdesc tuner_init_env77h11d5[] = {
+static const struct af9013_reg_bit tuner_init_env77h11d5[] = {
        { 0x9bd5, 0, 8, 0x01 },
        { 0x9bd6, 0, 8, 0x03 },
        { 0x9bbe, 0, 8, 0x01 },
@@ -318,7 +317,7 @@ static struct regdesc tuner_init_env77h11d5[] = {
 
 /* Microtune MT2060 tuner init
    AF9013_TUNER_MT2060     = 130 */
-static struct regdesc tuner_init_mt2060[] = {
+static const struct af9013_reg_bit tuner_init_mt2060[] = {
        { 0x9bd5, 0, 8, 0x01 },
        { 0x9bd6, 0, 8, 0x07 },
        { 0xd1a0, 1, 1, 0x01 },
@@ -395,7 +394,7 @@ static struct regdesc tuner_init_mt2060[] = {
 
 /* Microtune MT2060 tuner init
    AF9013_TUNER_MT2060_2   = 147 */
-static struct regdesc tuner_init_mt2060_2[] = {
+static const struct af9013_reg_bit tuner_init_mt2060_2[] = {
        { 0x9bd5, 0, 8, 0x01 },
        { 0x9bd6, 0, 8, 0x06 },
        { 0x9bbe, 0, 8, 0x01 },
@@ -462,7 +461,7 @@ static struct regdesc tuner_init_mt2060_2[] = {
 
 /* MaxLinear MXL5003 tuner init
    AF9013_TUNER_MXL5003D   =   3 */
-static struct regdesc tuner_init_mxl5003d[] = {
+static const struct af9013_reg_bit tuner_init_mxl5003d[] = {
        { 0x9bd5, 0, 8, 0x01 },
        { 0x9bd6, 0, 8, 0x09 },
        { 0xd1a0, 1, 1, 0x01 },
@@ -534,7 +533,7 @@ static struct regdesc tuner_init_mxl5003d[] = {
    AF9013_TUNER_MXL5005D   =  13
    AF9013_TUNER_MXL5005R   =  30
    AF9013_TUNER_MXL5007T   = 177 */
-static struct regdesc tuner_init_mxl5005[] = {
+static const struct af9013_reg_bit tuner_init_mxl5005[] = {
        { 0x9bd5, 0, 8, 0x01 },
        { 0x9bd6, 0, 8, 0x07 },
        { 0xd1a0, 1, 1, 0x01 },
@@ -613,7 +612,7 @@ static struct regdesc tuner_init_mxl5005[] = {
 /* Quantek QT1010 tuner init
    AF9013_TUNER_QT1010     = 134
    AF9013_TUNER_QT1010A    = 162 */
-static struct regdesc tuner_init_qt1010[] = {
+static const struct af9013_reg_bit tuner_init_qt1010[] = {
        { 0x9bd5, 0, 8, 0x01 },
        { 0x9bd6, 0, 8, 0x09 },
        { 0xd1a0, 1, 1, 0x01 },
@@ -690,7 +689,7 @@ static struct regdesc tuner_init_qt1010[] = {
 
 /* Freescale MC44S803 tuner init
    AF9013_TUNER_MC44S803   = 133 */
-static struct regdesc tuner_init_mc44s803[] = {
+static const struct af9013_reg_bit tuner_init_mc44s803[] = {
        { 0x9bd5, 0, 8, 0x01 },
        { 0x9bd6, 0, 8, 0x06 },
        { 0xd1a0, 1, 1, 0x01 },
@@ -772,7 +771,7 @@ static struct regdesc tuner_init_mc44s803[] = {
 
 /* unknown, probably for tin can tuner, tuner init
    AF9013_TUNER_UNKNOWN   = 140 */
-static struct regdesc tuner_init_unknown[] = {
+static const struct af9013_reg_bit tuner_init_unknown[] = {
        { 0x9bd5, 0, 8, 0x01 },
        { 0x9bd6, 0, 8, 0x02 },
        { 0xd1a0, 1, 1, 0x01 },
@@ -845,7 +844,7 @@ static struct regdesc tuner_init_unknown[] = {
 /* NXP TDA18271 & TDA18218 tuner init
    AF9013_TUNER_TDA18271   = 156
    AF9013_TUNER_TDA18218   = 179 */
-static struct regdesc tuner_init_tda18271[] = {
+static const struct af9013_reg_bit tuner_init_tda18271[] = {
        { 0x9bd5, 0, 8, 0x01 },
        { 0x9bd6, 0, 8, 0x04 },
        { 0xd1a0, 1, 1, 0x01 },
@@ -920,4 +919,4 @@ static struct regdesc tuner_init_tda18271[] = {
        { 0x9bee, 0, 1, 0x01 },
 };
 
-#endif /* _AF9013_PRIV_ */
+#endif /* AF9013_PRIV_H */
index 1539ea1f81acc9abee58b96bc04c182866febb91..a2261ea2cf82a3cf148dbb5515e3add5a309756d 100644 (file)
@@ -267,8 +267,7 @@ static void atbm8830_release(struct dvb_frontend *fe)
        kfree(state);
 }
 
-static int atbm8830_set_fe(struct dvb_frontend *fe,
-                         struct dvb_frontend_parameters *fe_params)
+static int atbm8830_set_fe(struct dvb_frontend *fe)
 {
        struct atbm_state *priv = fe->demodulator_priv;
        int i;
@@ -279,7 +278,7 @@ static int atbm8830_set_fe(struct dvb_frontend *fe,
        if (fe->ops.tuner_ops.set_params) {
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 1);
-               fe->ops.tuner_ops.set_params(fe, fe_params);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
@@ -298,31 +297,31 @@ static int atbm8830_set_fe(struct dvb_frontend *fe,
        return 0;
 }
 
-static int atbm8830_get_fe(struct dvb_frontend *fe,
-                         struct dvb_frontend_parameters *fe_params)
+static int atbm8830_get_fe(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        dprintk("%s\n", __func__);
 
        /* TODO: get real readings from device */
        /* inversion status */
-       fe_params->inversion = INVERSION_OFF;
+       c->inversion = INVERSION_OFF;
 
        /* bandwidth */
-       fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+       c->bandwidth_hz = 8000000;
 
-       fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
-       fe_params->u.ofdm.code_rate_LP = FEC_AUTO;
+       c->code_rate_HP = FEC_AUTO;
+       c->code_rate_LP = FEC_AUTO;
 
-       fe_params->u.ofdm.constellation = QAM_AUTO;
+       c->modulation = QAM_AUTO;
 
        /* transmission mode */
-       fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+       c->transmission_mode = TRANSMISSION_MODE_AUTO;
 
        /* guard interval */
-       fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+       c->guard_interval = GUARD_INTERVAL_AUTO;
 
        /* hierarchy */
-       fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+       c->hierarchy = HIERARCHY_NONE;
 
        return 0;
 }
@@ -429,9 +428,9 @@ static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 }
 
 static struct dvb_frontend_ops atbm8830_ops = {
+       .delsys = { SYS_DMBTH },
        .info = {
                .name = "AltoBeam ATBM8830/8831 DMB-TH",
-               .type = FE_OFDM,
                .frequency_min = 474000000,
                .frequency_max = 858000000,
                .frequency_stepsize = 10000,
index 1d572940e243637994b302f16a56bdb5b7caa7c6..c688b95df48645682fec8c2cefbd17cb51b5271e 100644 (file)
@@ -576,19 +576,19 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
 }
 
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int au8522_set_frontend(struct dvb_frontend *fe,
-                              struct dvb_frontend_parameters *p)
+static int au8522_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct au8522_state *state = fe->demodulator_priv;
        int ret = -EINVAL;
 
-       dprintk("%s(frequency=%d)\n", __func__, p->frequency);
+       dprintk("%s(frequency=%d)\n", __func__, c->frequency);
 
-       if ((state->current_frequency == p->frequency) &&
-           (state->current_modulation == p->u.vsb.modulation))
+       if ((state->current_frequency == c->frequency) &&
+           (state->current_modulation == c->modulation))
                return 0;
 
-       au8522_enable_modulation(fe, p->u.vsb.modulation);
+       au8522_enable_modulation(fe, c->modulation);
 
        /* Allow the demod to settle */
        msleep(100);
@@ -596,7 +596,7 @@ static int au8522_set_frontend(struct dvb_frontend *fe,
        if (fe->ops.tuner_ops.set_params) {
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 1);
-               ret = fe->ops.tuner_ops.set_params(fe, p);
+               ret = fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
@@ -604,7 +604,7 @@ static int au8522_set_frontend(struct dvb_frontend *fe,
        if (ret < 0)
                return ret;
 
-       state->current_frequency = p->frequency;
+       state->current_frequency = c->frequency;
 
        return 0;
 }
@@ -862,7 +862,36 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
 static int au8522_read_signal_strength(struct dvb_frontend *fe,
                                       u16 *signal_strength)
 {
-       return au8522_read_snr(fe, signal_strength);
+       /* borrowed from lgdt330x.c
+        *
+        * Calculate strength from SNR up to 35dB
+        * Even though the SNR can go higher than 35dB,
+        * there is some comfort factor in having a range of
+        * strong signals that can show at 100%
+        */
+       u16 snr;
+       u32 tmp;
+       int ret = au8522_read_snr(fe, &snr);
+
+       *signal_strength = 0;
+
+       if (0 == ret) {
+               /* The following calculation method was chosen
+                * purely for the sake of code re-use from the
+                * other demod drivers that use this method */
+
+               /* Convert from SNR in dB * 10 to 8.24 fixed-point */
+               tmp = (snr * ((1 << 24) / 10));
+
+               /* Convert from 8.24 fixed-point to
+                * scale the range 0 - 35*2^24 into 0 - 65535*/
+               if (tmp >= 8960 * 0x10000)
+                       *signal_strength = 0xffff;
+               else
+                       *signal_strength = tmp / 8960;
+       }
+
+       return ret;
 }
 
 static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
@@ -882,13 +911,13 @@ static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
        return au8522_read_ucblocks(fe, ber);
 }
 
-static int au8522_get_frontend(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *p)
+static int au8522_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct au8522_state *state = fe->demodulator_priv;
 
-       p->frequency = state->current_frequency;
-       p->u.vsb.modulation = state->current_modulation;
+       c->frequency = state->current_frequency;
+       c->modulation = state->current_modulation;
 
        return 0;
 }
@@ -981,10 +1010,9 @@ error:
 EXPORT_SYMBOL(au8522_attach);
 
 static struct dvb_frontend_ops au8522_ops = {
-
+       .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
        .info = {
                .name                   = "Auvitek AU8522 QAM/8VSB Frontend",
-               .type                   = FE_ATSC,
                .frequency_min          = 54000000,
                .frequency_max          = 858000000,
                .frequency_stepsize     = 62500,
index 8aff5868a5e1f4b814c084a93bf3185c397224bc..033cd7ad3ca2cb9d76f7bace048fdb1f72974bdd 100644 (file)
@@ -479,16 +479,16 @@ static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq)
        return -EINVAL;
 }
 
-static int bcm3510_set_frontend(struct dvb_frontend* fe,
-                                            struct dvb_frontend_parameters *p)
+static int bcm3510_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct bcm3510_state* st = fe->demodulator_priv;
        struct bcm3510_hab_cmd_ext_acquire cmd;
        struct bcm3510_hab_cmd_bert_control bert;
        int ret;
 
        memset(&cmd,0,sizeof(cmd));
-       switch (p->u.vsb.modulation) {
+       switch (c->modulation) {
                case QAM_256:
                        cmd.ACQUIRE0.MODE = 0x1;
                        cmd.ACQUIRE1.SYM_RATE = 0x1;
@@ -499,7 +499,8 @@ static int bcm3510_set_frontend(struct dvb_frontend* fe,
                        cmd.ACQUIRE1.SYM_RATE = 0x2;
                        cmd.ACQUIRE1.IF_FREQ = 0x1;
                        break;
-/*             case QAM_256:
+#if 0
+               case QAM_256:
                        cmd.ACQUIRE0.MODE = 0x3;
                        break;
                case QAM_128:
@@ -513,7 +514,8 @@ static int bcm3510_set_frontend(struct dvb_frontend* fe,
                        break;
                case QAM_16:
                        cmd.ACQUIRE0.MODE = 0x7;
-                       break;*/
+                       break;
+#endif
                case VSB_8:
                        cmd.ACQUIRE0.MODE = 0x8;
                        cmd.ACQUIRE1.SYM_RATE = 0x0;
@@ -552,7 +554,8 @@ static int bcm3510_set_frontend(struct dvb_frontend* fe,
 
        bcm3510_bert_reset(st);
 
-       if ((ret = bcm3510_set_freq(st,p->frequency)) < 0)
+       ret = bcm3510_set_freq(st, c->frequency);
+       if (ret < 0)
                return ret;
 
        memset(&st->status1,0,sizeof(st->status1));
@@ -819,10 +822,9 @@ error:
 EXPORT_SYMBOL(bcm3510_attach);
 
 static struct dvb_frontend_ops bcm3510_ops = {
-
+       .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
        .info = {
                .name = "Broadcom BCM3510 VSB/QAM frontend",
-               .type = FE_ATSC,
                .frequency_min =  54000000,
                .frequency_max = 803000000,
                /* stepsize is just a guess */
index 5e431ebd089b44d997490af145a567608905732e..53e4d0dbb745ccabd5001c5b0780631e547d0f78 100644 (file)
@@ -69,18 +69,19 @@ static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra
        return 0;
 }
 
-static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int alps_bsbe1_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        int ret;
        u8 data[4];
        u32 div;
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
        struct i2c_adapter *i2c = fe->tuner_priv;
 
-       if ((params->frequency < 950000) || (params->frequency > 2150000))
+       if ((p->frequency < 950000) || (p->frequency > 2150000))
                return -EINVAL;
 
-       div = params->frequency / 1000;
+       div = p->frequency / 1000;
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
        data[2] = 0x80 | ((div & 0x18000) >> 10) | 0x1;
index c480c839b302ba2260ca49e5bcda4f4356852f1f..c2a578e1314dce5ffb4495de51c5e97277036c12 100644 (file)
@@ -101,23 +101,24 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ra
        return 0;
 }
 
-static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        u8 buf[4];
        u32 div;
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
        struct i2c_adapter *i2c = fe->tuner_priv;
 
-       if ((params->frequency < 950000) || (params->frequency > 2150000))
+       if ((p->frequency < 950000) || (p->frequency > 2150000))
                return -EINVAL;
 
-       div = (params->frequency + (125 - 1)) / 125;    // round correctly
+       div = (p->frequency + (125 - 1)) / 125; /* round correctly */
        buf[0] = (div >> 8) & 0x7f;
        buf[1] = div & 0xff;
        buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
        buf[3] = 0xC4;
 
-       if (params->frequency > 1530000)
+       if (p->frequency > 1530000)
                buf[3] = 0xc0;
 
        if (fe->ops.i2c_gate_ctrl)
index 0142214b013363735ce084a8ed63871908fccd3c..f2a90f990ce330548079b7e5ce8e9b74f1a034c9 100644 (file)
@@ -121,7 +121,8 @@ static int cx22700_set_inversion (struct cx22700_state* state, int inversion)
        }
 }
 
-static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_parameters *p)
+static int cx22700_set_tps(struct cx22700_state *state,
+                          struct dtv_frontend_properties *p)
 {
        static const u8 qam_tab [4] = { 0, 1, 0, 2 };
        static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 };
@@ -146,25 +147,25 @@ static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_paramet
            p->transmission_mode != TRANSMISSION_MODE_8K)
                return -EINVAL;
 
-       if (p->constellation != QPSK &&
-           p->constellation != QAM_16 &&
-           p->constellation != QAM_64)
+       if (p->modulation != QPSK &&
+           p->modulation != QAM_16 &&
+           p->modulation != QAM_64)
                return -EINVAL;
 
-       if (p->hierarchy_information < HIERARCHY_NONE ||
-           p->hierarchy_information > HIERARCHY_4)
+       if (p->hierarchy < HIERARCHY_NONE ||
+           p->hierarchy > HIERARCHY_4)
                return -EINVAL;
 
-       if (p->bandwidth < BANDWIDTH_8_MHZ || p->bandwidth > BANDWIDTH_6_MHZ)
+       if (p->bandwidth_hz > 8000000 || p->bandwidth_hz < 6000000)
                return -EINVAL;
 
-       if (p->bandwidth == BANDWIDTH_7_MHZ)
+       if (p->bandwidth_hz == 7000000)
                cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 | 0x10));
        else
                cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 & ~0x10));
 
-       val = qam_tab[p->constellation - QPSK];
-       val |= p->hierarchy_information - HIERARCHY_NONE;
+       val = qam_tab[p->modulation - QPSK];
+       val |= p->hierarchy - HIERARCHY_NONE;
 
        cx22700_writereg (state, 0x04, val);
 
@@ -184,7 +185,8 @@ static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_paramet
        return 0;
 }
 
-static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_parameters *p)
+static int cx22700_get_tps(struct cx22700_state *state,
+                          struct dtv_frontend_properties *p)
 {
        static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 };
        static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4,
@@ -199,14 +201,14 @@ static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_paramet
        val = cx22700_readreg (state, 0x01);
 
        if ((val & 0x7) > 4)
-               p->hierarchy_information = HIERARCHY_AUTO;
+               p->hierarchy = HIERARCHY_AUTO;
        else
-               p->hierarchy_information = HIERARCHY_NONE + (val & 0x7);
+               p->hierarchy = HIERARCHY_NONE + (val & 0x7);
 
        if (((val >> 3) & 0x3) > 2)
-               p->constellation = QAM_AUTO;
+               p->modulation = QAM_AUTO;
        else
-               p->constellation = qam_tab[(val >> 3) & 0x3];
+               p->modulation = qam_tab[(val >> 3) & 0x3];
 
        val = cx22700_readreg (state, 0x02);
 
@@ -318,33 +320,35 @@ static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        return 0;
 }
 
-static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx22700_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct cx22700_state* state = fe->demodulator_priv;
 
        cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
        cx22700_writereg (state, 0x00, 0x00);
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
-       cx22700_set_inversion (state, p->inversion);
-       cx22700_set_tps (state, &p->u.ofdm);
+       cx22700_set_inversion(state, c->inversion);
+       cx22700_set_tps(state, c);
        cx22700_writereg (state, 0x37, 0x01);  /* PAL loop filter off */
        cx22700_writereg (state, 0x00, 0x01);  /* restart acquire */
 
        return 0;
 }
 
-static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx22700_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct cx22700_state* state = fe->demodulator_priv;
        u8 reg09 = cx22700_readreg (state, 0x09);
 
-       p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF;
-       return cx22700_get_tps (state, &p->u.ofdm);
+       c->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF;
+       return cx22700_get_tps(state, c);
 }
 
 static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
@@ -401,10 +405,9 @@ error:
 }
 
 static struct dvb_frontend_ops cx22700_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "Conexant CX22700 DVB-T",
-               .type                   = FE_OFDM,
                .frequency_min          = 470000000,
                .frequency_max          = 860000000,
                .frequency_stepsize     = 166667,
index 3139558148bacb1f92a972dbaff2baf27ef4f18a..faba8248508625cccc9eec3c291c51f4191031a1 100644 (file)
@@ -146,7 +146,7 @@ static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
 
 /* Retrieve the demod settings */
 static int cx22702_get_tps(struct cx22702_state *state,
-       struct dvb_ofdm_parameters *p)
+                          struct dtv_frontend_properties *p)
 {
        u8 val;
 
@@ -157,27 +157,27 @@ static int cx22702_get_tps(struct cx22702_state *state,
        val = cx22702_readreg(state, 0x01);
        switch ((val & 0x18) >> 3) {
        case 0:
-               p->constellation = QPSK;
+               p->modulation = QPSK;
                break;
        case 1:
-               p->constellation = QAM_16;
+               p->modulation = QAM_16;
                break;
        case 2:
-               p->constellation = QAM_64;
+               p->modulation = QAM_64;
                break;
        }
        switch (val & 0x07) {
        case 0:
-               p->hierarchy_information = HIERARCHY_NONE;
+               p->hierarchy = HIERARCHY_NONE;
                break;
        case 1:
-               p->hierarchy_information = HIERARCHY_1;
+               p->hierarchy = HIERARCHY_1;
                break;
        case 2:
-               p->hierarchy_information = HIERARCHY_2;
+               p->hierarchy = HIERARCHY_2;
                break;
        case 3:
-               p->hierarchy_information = HIERARCHY_4;
+               p->hierarchy = HIERARCHY_4;
                break;
        }
 
@@ -260,14 +260,14 @@ static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 }
 
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int cx22702_set_tps(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int cx22702_set_tps(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        u8 val;
        struct cx22702_state *state = fe->demodulator_priv;
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
@@ -277,14 +277,14 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
 
        /* set bandwidth */
        val = cx22702_readreg(state, 0x0C) & 0xcf;
-       switch (p->u.ofdm.bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       switch (p->bandwidth_hz) {
+       case 6000000:
                val |= 0x20;
                break;
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                val |= 0x10;
                break;
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
                break;
        default:
                dprintk("%s: invalid bandwidth\n", __func__);
@@ -292,15 +292,15 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
        }
        cx22702_writereg(state, 0x0C, val);
 
-       p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
+       p->code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
 
        /* use auto configuration? */
-       if ((p->u.ofdm.hierarchy_information == HIERARCHY_AUTO) ||
-          (p->u.ofdm.constellation == QAM_AUTO) ||
-          (p->u.ofdm.code_rate_HP == FEC_AUTO) ||
-          (p->u.ofdm.code_rate_LP == FEC_AUTO) ||
-          (p->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO) ||
-          (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO)) {
+       if ((p->hierarchy == HIERARCHY_AUTO) ||
+          (p->modulation == QAM_AUTO) ||
+          (p->code_rate_HP == FEC_AUTO) ||
+          (p->code_rate_LP == FEC_AUTO) ||
+          (p->guard_interval == GUARD_INTERVAL_AUTO) ||
+          (p->transmission_mode == TRANSMISSION_MODE_AUTO)) {
 
                /* TPS Source - use hardware driven values */
                cx22702_writereg(state, 0x06, 0x10);
@@ -316,7 +316,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
        }
 
        /* manually programmed values */
-       switch (p->u.ofdm.constellation) {              /* mask 0x18 */
+       switch (p->modulation) {                /* mask 0x18 */
        case QPSK:
                val = 0x00;
                break;
@@ -327,10 +327,10 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
                val = 0x10;
                break;
        default:
-               dprintk("%s: invalid constellation\n", __func__);
+               dprintk("%s: invalid modulation\n", __func__);
                return -EINVAL;
        }
-       switch (p->u.ofdm.hierarchy_information) {      /* mask 0x07 */
+       switch (p->hierarchy) { /* mask 0x07 */
        case HIERARCHY_NONE:
                break;
        case HIERARCHY_1:
@@ -348,7 +348,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
        }
        cx22702_writereg(state, 0x06, val);
 
-       switch (p->u.ofdm.code_rate_HP) {               /* mask 0x38 */
+       switch (p->code_rate_HP) {              /* mask 0x38 */
        case FEC_NONE:
        case FEC_1_2:
                val = 0x00;
@@ -369,7 +369,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
                dprintk("%s: invalid code_rate_HP\n", __func__);
                return -EINVAL;
        }
-       switch (p->u.ofdm.code_rate_LP) {               /* mask 0x07 */
+       switch (p->code_rate_LP) {              /* mask 0x07 */
        case FEC_NONE:
        case FEC_1_2:
                break;
@@ -391,7 +391,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
        }
        cx22702_writereg(state, 0x07, val);
 
-       switch (p->u.ofdm.guard_interval) {             /* mask 0x0c */
+       switch (p->guard_interval) {            /* mask 0x0c */
        case GUARD_INTERVAL_1_32:
                val = 0x00;
                break;
@@ -408,7 +408,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
                dprintk("%s: invalid guard_interval\n", __func__);
                return -EINVAL;
        }
-       switch (p->u.ofdm.transmission_mode) {          /* mask 0x03 */
+       switch (p->transmission_mode) {         /* mask 0x03 */
        case TRANSMISSION_MODE_2K:
                break;
        case TRANSMISSION_MODE_8K:
@@ -546,15 +546,15 @@ static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
        return 0;
 }
 
-static int cx22702_get_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int cx22702_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct cx22702_state *state = fe->demodulator_priv;
 
        u8 reg0C = cx22702_readreg(state, 0x0C);
 
-       p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
-       return cx22702_get_tps(state, &p->u.ofdm);
+       c->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
+       return cx22702_get_tps(state, c);
 }
 
 static int cx22702_get_tune_settings(struct dvb_frontend *fe,
@@ -603,10 +603,9 @@ error:
 EXPORT_SYMBOL(cx22702_attach);
 
 static const struct dvb_frontend_ops cx22702_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "Conexant CX22702 DVB-T",
-               .type                   = FE_OFDM,
                .frequency_min          = 177000000,
                .frequency_max          = 858000000,
                .frequency_stepsize     = 166666,
index bf9c999aa47051d7b71420cd20be6e3f2a781589..5101f10f2d7a010cd4a2702e20ceabd0ca8eb2b7 100644 (file)
@@ -531,26 +531,27 @@ static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        return 0;
 }
 
-static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24110_set_frontend(struct dvb_frontend *fe)
 {
        struct cx24110_state *state = fe->demodulator_priv;
-
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
-       cx24110_set_inversion (state, p->inversion);
-       cx24110_set_fec (state, p->u.qpsk.fec_inner);
-       cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate);
+       cx24110_set_inversion(state, p->inversion);
+       cx24110_set_fec(state, p->fec_inner);
+       cx24110_set_symbolrate(state, p->symbol_rate);
        cx24110_writereg(state,0x04,0x05); /* start acquisition */
 
        return 0;
 }
 
-static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24110_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct cx24110_state *state = fe->demodulator_priv;
        s32 afc; unsigned sclk;
 
@@ -571,7 +572,7 @@ static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        p->frequency += afc;
        p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ?
                                INVERSION_ON : INVERSION_OFF;
-       p->u.qpsk.fec_inner = cx24110_get_fec (state);
+       p->fec_inner = cx24110_get_fec(state);
 
        return 0;
 }
@@ -623,10 +624,9 @@ error:
 }
 
 static struct dvb_frontend_ops cx24110_ops = {
-
+       .delsys = { SYS_DVBS },
        .info = {
                .name = "Conexant CX24110 DVB-S",
-               .type = FE_QPSK,
                .frequency_min = 950000,
                .frequency_max = 2150000,
                .frequency_stepsize = 1011,  /* kHz for QPSK frontends */
index c341d57d5e818d9c57d34e09e790eb937f0e5475..3883c3b31aef3d98109059242b73063d8a40d468 100644 (file)
@@ -476,21 +476,21 @@ static int cx24113_init(struct dvb_frontend *fe)
        return ret;
 }
 
-static int cx24113_set_params(struct dvb_frontend *fe,
-               struct dvb_frontend_parameters *p)
+static int cx24113_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct cx24113_state *state = fe->tuner_priv;
        /* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */
        u32 roll_off = 675;
        u32 bw;
 
-       bw  = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000;
+       bw  = ((c->symbol_rate/100) * roll_off) / 1000;
        bw += (10000000/100) + 5;
        bw /= 10;
        bw += 1000;
        cx24113_set_bandwidth(state, bw);
 
-       cx24113_set_frequency(state, p->frequency);
+       cx24113_set_frequency(state, c->frequency);
        msleep(5);
        return cx24113_get_status(fe, &bw);
 }
@@ -547,11 +547,9 @@ static const struct dvb_tuner_ops cx24113_tuner_ops = {
        .release       = cx24113_release,
 
        .init          = cx24113_init,
-       .sleep         = NULL,
 
        .set_params    = cx24113_set_params,
        .get_frequency = cx24113_get_frequency,
-       .get_bandwidth = NULL,
        .get_status    = cx24113_get_status,
 };
 
index ccd05255d52730225530580b6bedec2a8df99336..b4887918653719740f34398e762e604869000c05 100644 (file)
@@ -1212,25 +1212,10 @@ static int cx24116_sleep(struct dvb_frontend *fe)
        return 0;
 }
 
-static int cx24116_set_property(struct dvb_frontend *fe,
-       struct dtv_property *tvp)
-{
-       dprintk("%s(..)\n", __func__);
-       return 0;
-}
-
-static int cx24116_get_property(struct dvb_frontend *fe,
-       struct dtv_property *tvp)
-{
-       dprintk("%s(..)\n", __func__);
-       return 0;
-}
-
 /* dvb-core told us to tune, the tv property cache will be complete,
  * it's safe for is to pull values and use them for tuning purposes.
  */
-static int cx24116_set_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int cx24116_set_frontend(struct dvb_frontend *fe)
 {
        struct cx24116_state *state = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -1455,12 +1440,20 @@ tuned:  /* Set/Reset B/W */
        return cx24116_cmd_execute(fe, &cmd);
 }
 
-static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params,
+static int cx24116_tune(struct dvb_frontend *fe, bool re_tune,
        unsigned int mode_flags, unsigned int *delay, fe_status_t *status)
 {
+       /*
+        * It is safe to discard "params" here, as the DVB core will sync
+        * fe->dtv_property_cache with fepriv->parameters_in, where the
+        * DVBv3 params are stored. The only practical usage for it indicate
+        * that re-tuning is needed, e. g. (fepriv->state & FESTATE_RETUNE) is
+        * true.
+        */
+
        *delay = HZ / 5;
-       if (params) {
-               int ret = cx24116_set_frontend(fe, params);
+       if (re_tune) {
+               int ret = cx24116_set_frontend(fe);
                if (ret)
                        return ret;
        }
@@ -1473,10 +1466,9 @@ static int cx24116_get_algo(struct dvb_frontend *fe)
 }
 
 static struct dvb_frontend_ops cx24116_ops = {
-
+       .delsys = { SYS_DVBS, SYS_DVBS2 },
        .info = {
                .name = "Conexant CX24116/CX24118",
-               .type = FE_QPSK,
                .frequency_min = 950000,
                .frequency_max = 2150000,
                .frequency_stepsize = 1011, /* kHz for QPSK frontends */
@@ -1507,8 +1499,6 @@ static struct dvb_frontend_ops cx24116_ops = {
        .get_frontend_algo = cx24116_get_algo,
        .tune = cx24116_tune,
 
-       .set_property = cx24116_set_property,
-       .get_property = cx24116_get_property,
        .set_frontend = cx24116_set_frontend,
 };
 
index b1dd8acc607a4d70133524501f643e3deb89f081..7e28b4ee7d4febb9f815ea569fbfc14f38764b6a 100644 (file)
@@ -526,9 +526,9 @@ static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate)
  * to be configured and the correct band selected.
  * Calculate those values.
  */
-static int cx24123_pll_calculate(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int cx24123_pll_calculate(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct cx24123_state *state = fe->demodulator_priv;
        u32 ndiv = 0, adiv = 0, vco_div = 0;
        int i = 0;
@@ -548,8 +548,8 @@ static int cx24123_pll_calculate(struct dvb_frontend *fe,
         * FILTUNE programming bits */
        for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++) {
                agcv = &cx24123_AGC_vals[i];
-               if ((agcv->symbolrate_low <= p->u.qpsk.symbol_rate) &&
-                   (agcv->symbolrate_high >= p->u.qpsk.symbol_rate)) {
+               if ((agcv->symbolrate_low <= p->symbol_rate) &&
+                   (agcv->symbolrate_high >= p->symbol_rate)) {
                        state->VCAarg = agcv->VCAprogdata;
                        state->VGAarg = agcv->VGAprogdata;
                        state->FILTune = agcv->FILTune;
@@ -601,8 +601,7 @@ static int cx24123_pll_calculate(struct dvb_frontend *fe,
  * Tuner cx24109 is written through a dedicated 3wire interface
  * on the demod chip.
  */
-static int cx24123_pll_writereg(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p, u32 data)
+static int cx24123_pll_writereg(struct dvb_frontend *fe, u32 data)
 {
        struct cx24123_state *state = fe->demodulator_priv;
        unsigned long timeout;
@@ -659,26 +658,26 @@ static int cx24123_pll_writereg(struct dvb_frontend *fe,
        return 0;
 }
 
-static int cx24123_pll_tune(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int cx24123_pll_tune(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct cx24123_state *state = fe->demodulator_priv;
        u8 val;
 
        dprintk("frequency=%i\n", p->frequency);
 
-       if (cx24123_pll_calculate(fe, p) != 0) {
+       if (cx24123_pll_calculate(fe) != 0) {
                err("%s: cx24123_pll_calcutate failed\n", __func__);
                return -EINVAL;
        }
 
        /* Write the new VCO/VGA */
-       cx24123_pll_writereg(fe, p, state->VCAarg);
-       cx24123_pll_writereg(fe, p, state->VGAarg);
+       cx24123_pll_writereg(fe, state->VCAarg);
+       cx24123_pll_writereg(fe, state->VGAarg);
 
        /* Write the new bandselect and pll args */
-       cx24123_pll_writereg(fe, p, state->bandselectarg);
-       cx24123_pll_writereg(fe, p, state->pllarg);
+       cx24123_pll_writereg(fe, state->bandselectarg);
+       cx24123_pll_writereg(fe, state->pllarg);
 
        /* set the FILTUNE voltage */
        val = cx24123_readreg(state, 0x28) & ~0x3;
@@ -925,10 +924,10 @@ static int cx24123_read_snr(struct dvb_frontend *fe, u16 *snr)
        return 0;
 }
 
-static int cx24123_set_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int cx24123_set_frontend(struct dvb_frontend *fe)
 {
        struct cx24123_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 
        dprintk("\n");
 
@@ -936,16 +935,16 @@ static int cx24123_set_frontend(struct dvb_frontend *fe,
                state->config->set_ts_params(fe, 0);
 
        state->currentfreq = p->frequency;
-       state->currentsymbolrate = p->u.qpsk.symbol_rate;
+       state->currentsymbolrate = p->symbol_rate;
 
        cx24123_set_inversion(state, p->inversion);
-       cx24123_set_fec(state, p->u.qpsk.fec_inner);
-       cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate);
+       cx24123_set_fec(state, p->fec_inner);
+       cx24123_set_symbolrate(state, p->symbol_rate);
 
        if (!state->config->dont_use_pll)
-               cx24123_pll_tune(fe, p);
+               cx24123_pll_tune(fe);
        else if (fe->ops.tuner_ops.set_params)
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
        else
                err("it seems I don't have a tuner...");
 
@@ -960,9 +959,9 @@ static int cx24123_set_frontend(struct dvb_frontend *fe,
        return 0;
 }
 
-static int cx24123_get_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int cx24123_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct cx24123_state *state = fe->demodulator_priv;
 
        dprintk("\n");
@@ -971,12 +970,12 @@ static int cx24123_get_frontend(struct dvb_frontend *fe,
                err("%s: Failed to get inversion status\n", __func__);
                return -EREMOTEIO;
        }
-       if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) {
+       if (cx24123_get_fec(state, &p->fec_inner) != 0) {
                err("%s: Failed to get fec status\n", __func__);
                return -EREMOTEIO;
        }
        p->frequency = state->currentfreq;
-       p->u.qpsk.symbol_rate = state->currentsymbolrate;
+       p->symbol_rate = state->currentsymbolrate;
 
        return 0;
 }
@@ -1007,15 +1006,15 @@ static int cx24123_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
 }
 
 static int cx24123_tune(struct dvb_frontend *fe,
-                       struct dvb_frontend_parameters *params,
+                       bool re_tune,
                        unsigned int mode_flags,
                        unsigned int *delay,
                        fe_status_t *status)
 {
        int retval = 0;
 
-       if (params != NULL)
-               retval = cx24123_set_frontend(fe, params);
+       if (re_tune)
+               retval = cx24123_set_frontend(fe);
 
        if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
                cx24123_read_status(fe, status);
@@ -1126,10 +1125,9 @@ error:
 EXPORT_SYMBOL(cx24123_attach);
 
 static struct dvb_frontend_ops cx24123_ops = {
-
+       .delsys = { SYS_DVBS },
        .info = {
                .name = "Conexant CX24123/CX24109",
-               .type = FE_QPSK,
                .frequency_min = 950000,
                .frequency_max = 2150000,
                .frequency_stepsize = 1011, /* kHz for QPSK frontends */
index 03cab7b547fbac253331206de193848acc8b93a0..cf0f546aa1d1bdf94f47666692c0313cf69d6643 100644 (file)
@@ -63,19 +63,6 @@ struct cxd2820r_config {
         */
        bool spec_inv;
 
-       /* IFs for all used modes.
-        * Default: none, must set
-        * Values: <kHz>
-        */
-       u16 if_dvbt_6;
-       u16 if_dvbt_7;
-       u16 if_dvbt_8;
-       u16 if_dvbt2_5;
-       u16 if_dvbt2_6;
-       u16 if_dvbt2_7;
-       u16 if_dvbt2_8;
-       u16 if_dvbc;
-
        /* GPIOs for all used modes.
         * Default: none, disabled
         * Values: <see above>
index b85f5011e344623fc3a03fbfb10d09d8df59a54f..945404991529d1517a046281d807b23385aed6c3 100644 (file)
 
 #include "cxd2820r_priv.h"
 
-int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params)
+int cxd2820r_set_frontend_c(struct dvb_frontend *fe)
 {
        struct cxd2820r_priv *priv = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret, i;
        u8 buf[2];
+       u32 if_freq;
        u16 if_ctl;
        u64 num;
        struct reg_val_mask tab[] = {
@@ -56,9 +56,9 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
 
        /* program tuner */
        if (fe->ops.tuner_ops.set_params)
-               fe->ops.tuner_ops.set_params(fe, params);
+               fe->ops.tuner_ops.set_params(fe);
 
-       if (priv->delivery_system !=  SYS_DVBC_ANNEX_AC) {
+       if (priv->delivery_system !=  SYS_DVBC_ANNEX_A) {
                for (i = 0; i < ARRAY_SIZE(tab); i++) {
                        ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
                                tab[i].val, tab[i].mask);
@@ -67,10 +67,20 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
                }
        }
 
-       priv->delivery_system = SYS_DVBC_ANNEX_AC;
+       priv->delivery_system = SYS_DVBC_ANNEX_A;
        priv->ber_running = 0; /* tune stops BER counter */
 
-       num = priv->cfg.if_dvbc;
+       /* program IF frequency */
+       if (fe->ops.tuner_ops.get_if_frequency) {
+               ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+               if (ret)
+                       goto error;
+       } else
+               if_freq = 0;
+
+       dbg("%s: if_freq=%d", __func__, if_freq);
+
+       num = if_freq / 1000; /* Hz => kHz */
        num *= 0x4000;
        if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
        buf[0] = (if_ctl >> 8) & 0x3f;
@@ -94,8 +104,7 @@ error:
        return ret;
 }
 
-int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+int cxd2820r_get_frontend_c(struct dvb_frontend *fe)
 {
        struct cxd2820r_priv *priv = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
index 036480f967b7b73c21a42004e17e1a8d2bc018ef..caae7f79c8379323d1bce9c6b998bc996c63fda4 100644 (file)
@@ -240,422 +240,239 @@ error:
        return ret;
 }
 
-/* lock FE */
-static int cxd2820r_lock(struct cxd2820r_priv *priv, int active_fe)
-{
-       int ret = 0;
-       dbg("%s: active_fe=%d", __func__, active_fe);
-
-       mutex_lock(&priv->fe_lock);
-
-       /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */
-       if (priv->active_fe == active_fe)
-               ;
-       else if (priv->active_fe == -1)
-               priv->active_fe = active_fe;
-       else
-               ret = -EBUSY;
-
-       mutex_unlock(&priv->fe_lock);
-
-       return ret;
-}
-
-/* unlock FE */
-static void cxd2820r_unlock(struct cxd2820r_priv *priv, int active_fe)
-{
-       dbg("%s: active_fe=%d", __func__, active_fe);
-
-       mutex_lock(&priv->fe_lock);
-
-       /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */
-       if (priv->active_fe == active_fe)
-               priv->active_fe = -1;
-
-       mutex_unlock(&priv->fe_lock);
-
-       return;
-}
-
 /* 64 bit div with round closest, like DIV_ROUND_CLOSEST but 64 bit */
 u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor)
 {
        return div_u64(dividend + (divisor / 2), divisor);
 }
 
-static int cxd2820r_set_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int cxd2820r_set_frontend(struct dvb_frontend *fe)
 {
-       struct cxd2820r_priv *priv = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret;
-       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
 
-       if (fe->ops.info.type == FE_OFDM) {
-               /* DVB-T/T2 */
-               ret = cxd2820r_lock(priv, 0);
-               if (ret)
-                       return ret;
-
-               switch (priv->delivery_system) {
-               case SYS_UNDEFINED:
-                       if (c->delivery_system == SYS_DVBT) {
-                               /* SLEEP => DVB-T */
-                               ret = cxd2820r_set_frontend_t(fe, p);
-                       } else {
-                               /* SLEEP => DVB-T2 */
-                               ret = cxd2820r_set_frontend_t2(fe, p);
-                       }
-                       break;
-               case SYS_DVBT:
-                       if (c->delivery_system == SYS_DVBT) {
-                               /* DVB-T => DVB-T */
-                               ret = cxd2820r_set_frontend_t(fe, p);
-                       } else if (c->delivery_system == SYS_DVBT2) {
-                               /* DVB-T => DVB-T2 */
-                               ret = cxd2820r_sleep_t(fe);
-                               if (ret)
-                                       break;
-                               ret = cxd2820r_set_frontend_t2(fe, p);
-                       }
-                       break;
-               case SYS_DVBT2:
-                       if (c->delivery_system == SYS_DVBT2) {
-                               /* DVB-T2 => DVB-T2 */
-                               ret = cxd2820r_set_frontend_t2(fe, p);
-                       } else if (c->delivery_system == SYS_DVBT) {
-                               /* DVB-T2 => DVB-T */
-                               ret = cxd2820r_sleep_t2(fe);
-                               if (ret)
-                                       break;
-                               ret = cxd2820r_set_frontend_t(fe, p);
-                       }
-                       break;
-               default:
-                       dbg("%s: error state=%d", __func__,
-                               priv->delivery_system);
-                       ret = -EINVAL;
-               }
-       } else {
-               /* DVB-C */
-               ret = cxd2820r_lock(priv, 1);
-               if (ret)
-                       return ret;
-
-               ret = cxd2820r_set_frontend_c(fe, p);
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+       switch (c->delivery_system) {
+       case SYS_DVBT:
+               ret = cxd2820r_init_t(fe);
+               if (ret < 0)
+                       goto err;
+               ret = cxd2820r_set_frontend_t(fe);
+               if (ret < 0)
+                       goto err;
+               break;
+       case SYS_DVBT2:
+               ret = cxd2820r_init_t(fe);
+               if (ret < 0)
+                       goto err;
+               ret = cxd2820r_set_frontend_t2(fe);
+               if (ret < 0)
+                       goto err;
+               break;
+       case SYS_DVBC_ANNEX_A:
+               ret = cxd2820r_init_c(fe);
+               if (ret < 0)
+                       goto err;
+               ret = cxd2820r_set_frontend_c(fe);
+               if (ret < 0)
+                       goto err;
+               break;
+       default:
+               dbg("%s: error state=%d", __func__, fe->dtv_property_cache.delivery_system);
+               ret = -EINVAL;
+               break;
        }
-
+err:
        return ret;
 }
-
 static int cxd2820r_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
-       struct cxd2820r_priv *priv = fe->demodulator_priv;
        int ret;
-       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
-       if (fe->ops.info.type == FE_OFDM) {
-               /* DVB-T/T2 */
-               ret = cxd2820r_lock(priv, 0);
-               if (ret)
-                       return ret;
-
-               switch (fe->dtv_property_cache.delivery_system) {
-               case SYS_DVBT:
-                       ret = cxd2820r_read_status_t(fe, status);
-                       break;
-               case SYS_DVBT2:
-                       ret = cxd2820r_read_status_t2(fe, status);
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
-       } else {
-               /* DVB-C */
-               ret = cxd2820r_lock(priv, 1);
-               if (ret)
-                       return ret;
 
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+       switch (fe->dtv_property_cache.delivery_system) {
+       case SYS_DVBT:
+               ret = cxd2820r_read_status_t(fe, status);
+               break;
+       case SYS_DVBT2:
+               ret = cxd2820r_read_status_t2(fe, status);
+               break;
+       case SYS_DVBC_ANNEX_A:
                ret = cxd2820r_read_status_c(fe, status);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
        }
-
        return ret;
 }
 
-static int cxd2820r_get_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int cxd2820r_get_frontend(struct dvb_frontend *fe)
 {
        struct cxd2820r_priv *priv = fe->demodulator_priv;
        int ret;
-       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
 
-       if (fe->ops.info.type == FE_OFDM) {
-               /* DVB-T/T2 */
-               ret = cxd2820r_lock(priv, 0);
-               if (ret)
-                       return ret;
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
 
-               switch (fe->dtv_property_cache.delivery_system) {
-               case SYS_DVBT:
-                       ret = cxd2820r_get_frontend_t(fe, p);
-                       break;
-               case SYS_DVBT2:
-                       ret = cxd2820r_get_frontend_t2(fe, p);
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
-       } else {
-               /* DVB-C */
-               ret = cxd2820r_lock(priv, 1);
-               if (ret)
-                       return ret;
+       if (priv->delivery_system == SYS_UNDEFINED)
+               return 0;
 
-               ret = cxd2820r_get_frontend_c(fe, p);
+       switch (fe->dtv_property_cache.delivery_system) {
+       case SYS_DVBT:
+               ret = cxd2820r_get_frontend_t(fe);
+               break;
+       case SYS_DVBT2:
+               ret = cxd2820r_get_frontend_t2(fe);
+               break;
+       case SYS_DVBC_ANNEX_A:
+               ret = cxd2820r_get_frontend_c(fe);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
        }
-
        return ret;
 }
 
 static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-       struct cxd2820r_priv *priv = fe->demodulator_priv;
        int ret;
-       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
-       if (fe->ops.info.type == FE_OFDM) {
-               /* DVB-T/T2 */
-               ret = cxd2820r_lock(priv, 0);
-               if (ret)
-                       return ret;
-
-               switch (fe->dtv_property_cache.delivery_system) {
-               case SYS_DVBT:
-                       ret = cxd2820r_read_ber_t(fe, ber);
-                       break;
-               case SYS_DVBT2:
-                       ret = cxd2820r_read_ber_t2(fe, ber);
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
-       } else {
-               /* DVB-C */
-               ret = cxd2820r_lock(priv, 1);
-               if (ret)
-                       return ret;
 
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+       switch (fe->dtv_property_cache.delivery_system) {
+       case SYS_DVBT:
+               ret = cxd2820r_read_ber_t(fe, ber);
+               break;
+       case SYS_DVBT2:
+               ret = cxd2820r_read_ber_t2(fe, ber);
+               break;
+       case SYS_DVBC_ANNEX_A:
                ret = cxd2820r_read_ber_c(fe, ber);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
        }
-
        return ret;
 }
 
 static int cxd2820r_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
-       struct cxd2820r_priv *priv = fe->demodulator_priv;
        int ret;
-       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
-       if (fe->ops.info.type == FE_OFDM) {
-               /* DVB-T/T2 */
-               ret = cxd2820r_lock(priv, 0);
-               if (ret)
-                       return ret;
-
-               switch (fe->dtv_property_cache.delivery_system) {
-               case SYS_DVBT:
-                       ret = cxd2820r_read_signal_strength_t(fe, strength);
-                       break;
-               case SYS_DVBT2:
-                       ret = cxd2820r_read_signal_strength_t2(fe, strength);
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
-       } else {
-               /* DVB-C */
-               ret = cxd2820r_lock(priv, 1);
-               if (ret)
-                       return ret;
 
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+       switch (fe->dtv_property_cache.delivery_system) {
+       case SYS_DVBT:
+               ret = cxd2820r_read_signal_strength_t(fe, strength);
+               break;
+       case SYS_DVBT2:
+               ret = cxd2820r_read_signal_strength_t2(fe, strength);
+               break;
+       case SYS_DVBC_ANNEX_A:
                ret = cxd2820r_read_signal_strength_c(fe, strength);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
        }
-
        return ret;
 }
 
 static int cxd2820r_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-       struct cxd2820r_priv *priv = fe->demodulator_priv;
        int ret;
-       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
-       if (fe->ops.info.type == FE_OFDM) {
-               /* DVB-T/T2 */
-               ret = cxd2820r_lock(priv, 0);
-               if (ret)
-                       return ret;
-
-               switch (fe->dtv_property_cache.delivery_system) {
-               case SYS_DVBT:
-                       ret = cxd2820r_read_snr_t(fe, snr);
-                       break;
-               case SYS_DVBT2:
-                       ret = cxd2820r_read_snr_t2(fe, snr);
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
-       } else {
-               /* DVB-C */
-               ret = cxd2820r_lock(priv, 1);
-               if (ret)
-                       return ret;
 
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+       switch (fe->dtv_property_cache.delivery_system) {
+       case SYS_DVBT:
+               ret = cxd2820r_read_snr_t(fe, snr);
+               break;
+       case SYS_DVBT2:
+               ret = cxd2820r_read_snr_t2(fe, snr);
+               break;
+       case SYS_DVBC_ANNEX_A:
                ret = cxd2820r_read_snr_c(fe, snr);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
        }
-
        return ret;
 }
 
 static int cxd2820r_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
-       struct cxd2820r_priv *priv = fe->demodulator_priv;
        int ret;
-       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
-       if (fe->ops.info.type == FE_OFDM) {
-               /* DVB-T/T2 */
-               ret = cxd2820r_lock(priv, 0);
-               if (ret)
-                       return ret;
-
-               switch (fe->dtv_property_cache.delivery_system) {
-               case SYS_DVBT:
-                       ret = cxd2820r_read_ucblocks_t(fe, ucblocks);
-                       break;
-               case SYS_DVBT2:
-                       ret = cxd2820r_read_ucblocks_t2(fe, ucblocks);
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
-       } else {
-               /* DVB-C */
-               ret = cxd2820r_lock(priv, 1);
-               if (ret)
-                       return ret;
 
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+       switch (fe->dtv_property_cache.delivery_system) {
+       case SYS_DVBT:
+               ret = cxd2820r_read_ucblocks_t(fe, ucblocks);
+               break;
+       case SYS_DVBT2:
+               ret = cxd2820r_read_ucblocks_t2(fe, ucblocks);
+               break;
+       case SYS_DVBC_ANNEX_A:
                ret = cxd2820r_read_ucblocks_c(fe, ucblocks);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
        }
-
        return ret;
 }
 
 static int cxd2820r_init(struct dvb_frontend *fe)
 {
-       struct cxd2820r_priv *priv = fe->demodulator_priv;
-       int ret;
-       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
-       priv->delivery_system = SYS_UNDEFINED;
-       /* delivery system is unknown at that (init) phase */
-
-       if (fe->ops.info.type == FE_OFDM) {
-               /* DVB-T/T2 */
-               ret = cxd2820r_lock(priv, 0);
-               if (ret)
-                       return ret;
-
-               ret = cxd2820r_init_t(fe);
-       } else {
-               /* DVB-C */
-               ret = cxd2820r_lock(priv, 1);
-               if (ret)
-                       return ret;
-
-               ret = cxd2820r_init_c(fe);
-       }
-
-       return ret;
+       return 0;
 }
 
 static int cxd2820r_sleep(struct dvb_frontend *fe)
 {
-       struct cxd2820r_priv *priv = fe->demodulator_priv;
        int ret;
-       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
-       if (fe->ops.info.type == FE_OFDM) {
-               /* DVB-T/T2 */
-               ret = cxd2820r_lock(priv, 0);
-               if (ret)
-                       return ret;
-
-               switch (fe->dtv_property_cache.delivery_system) {
-               case SYS_DVBT:
-                       ret = cxd2820r_sleep_t(fe);
-                       break;
-               case SYS_DVBT2:
-                       ret = cxd2820r_sleep_t2(fe);
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
-
-               cxd2820r_unlock(priv, 0);
-       } else {
-               /* DVB-C */
-               ret = cxd2820r_lock(priv, 1);
-               if (ret)
-                       return ret;
 
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+       switch (fe->dtv_property_cache.delivery_system) {
+       case SYS_DVBT:
+               ret = cxd2820r_sleep_t(fe);
+               break;
+       case SYS_DVBT2:
+               ret = cxd2820r_sleep_t2(fe);
+               break;
+       case SYS_DVBC_ANNEX_A:
                ret = cxd2820r_sleep_c(fe);
-
-               cxd2820r_unlock(priv, 1);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
        }
-
        return ret;
 }
 
 static int cxd2820r_get_tune_settings(struct dvb_frontend *fe,
-       struct dvb_frontend_tune_settings *s)
+                                     struct dvb_frontend_tune_settings *s)
 {
-       struct cxd2820r_priv *priv = fe->demodulator_priv;
        int ret;
-       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
-
-       if (fe->ops.info.type == FE_OFDM) {
-               /* DVB-T/T2 */
-               ret = cxd2820r_lock(priv, 0);
-               if (ret)
-                       return ret;
-
-               switch (fe->dtv_property_cache.delivery_system) {
-               case SYS_DVBT:
-                       ret = cxd2820r_get_tune_settings_t(fe, s);
-                       break;
-               case SYS_DVBT2:
-                       ret = cxd2820r_get_tune_settings_t2(fe, s);
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
-       } else {
-               /* DVB-C */
-               ret = cxd2820r_lock(priv, 1);
-               if (ret)
-                       return ret;
 
+       dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+       switch (fe->dtv_property_cache.delivery_system) {
+       case SYS_DVBT:
+               ret = cxd2820r_get_tune_settings_t(fe, s);
+               break;
+       case SYS_DVBT2:
+               ret = cxd2820r_get_tune_settings_t2(fe, s);
+               break;
+       case SYS_DVBC_ANNEX_A:
                ret = cxd2820r_get_tune_settings_c(fe, s);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
        }
-
        return ret;
 }
 
-static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe)
 {
        struct cxd2820r_priv *priv = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -667,12 +484,12 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe,
        if (priv->last_tune_failed) {
                if (priv->delivery_system == SYS_DVBT)
                        c->delivery_system = SYS_DVBT2;
-               else
+               else if (priv->delivery_system == SYS_DVBT2)
                        c->delivery_system = SYS_DVBT;
        }
 
        /* set frontend */
-       ret = cxd2820r_set_frontend(fe, p);
+       ret = cxd2820r_set_frontend(fe);
        if (ret)
                goto error;
 
@@ -680,6 +497,7 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe,
        /* frontend lock wait loop count */
        switch (priv->delivery_system) {
        case SYS_DVBT:
+       case SYS_DVBC_ANNEX_A:
                i = 20;
                break;
        case SYS_DVBT2:
@@ -727,9 +545,7 @@ static void cxd2820r_release(struct dvb_frontend *fe)
        struct cxd2820r_priv *priv = fe->demodulator_priv;
        dbg("%s", __func__);
 
-       if (fe->ops.info.type == FE_OFDM)
-               kfree(priv);
-
+       kfree(priv);
        return;
 }
 
@@ -742,128 +558,79 @@ static int cxd2820r_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
        return cxd2820r_wr_reg_mask(priv, 0xdb, enable ? 1 : 0, 0x1);
 }
 
-static const struct dvb_frontend_ops cxd2820r_ops[2];
+static const struct dvb_frontend_ops cxd2820r_ops = {
+       .delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A },
+       /* default: DVB-T/T2 */
+       .info = {
+               .name = "Sony CXD2820R (DVB-T/T2)",
+
+               .caps = FE_CAN_FEC_1_2                  |
+                       FE_CAN_FEC_2_3                  |
+                       FE_CAN_FEC_3_4                  |
+                       FE_CAN_FEC_5_6                  |
+                       FE_CAN_FEC_7_8                  |
+                       FE_CAN_FEC_AUTO                 |
+                       FE_CAN_QPSK                     |
+                       FE_CAN_QAM_16                   |
+                       FE_CAN_QAM_64                   |
+                       FE_CAN_QAM_256                  |
+                       FE_CAN_QAM_AUTO                 |
+                       FE_CAN_TRANSMISSION_MODE_AUTO   |
+                       FE_CAN_GUARD_INTERVAL_AUTO      |
+                       FE_CAN_HIERARCHY_AUTO           |
+                       FE_CAN_MUTE_TS                  |
+                       FE_CAN_2G_MODULATION
+               },
 
-struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
-       struct i2c_adapter *i2c, struct dvb_frontend *fe)
-{
-       int ret;
-       struct cxd2820r_priv *priv = NULL;
-       u8 tmp;
+       .release                = cxd2820r_release,
+       .init                   = cxd2820r_init,
+       .sleep                  = cxd2820r_sleep,
 
-       if (fe == NULL) {
-               /* FE0 */
-               /* allocate memory for the internal priv */
-               priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL);
-               if (priv == NULL)
-                       goto error;
+       .get_tune_settings      = cxd2820r_get_tune_settings,
+       .i2c_gate_ctrl          = cxd2820r_i2c_gate_ctrl,
 
-               /* setup the priv */
-               priv->i2c = i2c;
-               memcpy(&priv->cfg, cfg, sizeof(struct cxd2820r_config));
-               mutex_init(&priv->fe_lock);
+       .get_frontend           = cxd2820r_get_frontend,
 
-               priv->active_fe = -1; /* NONE */
+       .get_frontend_algo      = cxd2820r_get_frontend_algo,
+       .search                 = cxd2820r_search,
 
-               /* check if the demod is there */
-               priv->bank[0] = priv->bank[1] = 0xff;
-               ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp);
-               dbg("%s: chip id=%02x", __func__, tmp);
-               if (ret || tmp != 0xe1)
-                       goto error;
+       .read_status            = cxd2820r_read_status,
+       .read_snr               = cxd2820r_read_snr,
+       .read_ber               = cxd2820r_read_ber,
+       .read_ucblocks          = cxd2820r_read_ucblocks,
+       .read_signal_strength   = cxd2820r_read_signal_strength,
+};
 
-               /* create frontends */
-               memcpy(&priv->fe[0].ops, &cxd2820r_ops[0],
-                       sizeof(struct dvb_frontend_ops));
-               memcpy(&priv->fe[1].ops, &cxd2820r_ops[1],
-                       sizeof(struct dvb_frontend_ops));
+struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
+                                    struct i2c_adapter *i2c,
+                                    struct dvb_frontend *fe)
+{
+       struct cxd2820r_priv *priv = NULL;
+       int ret;
+       u8 tmp;
 
-               priv->fe[0].demodulator_priv = priv;
-               priv->fe[1].demodulator_priv = priv;
+       priv = kzalloc(sizeof (struct cxd2820r_priv), GFP_KERNEL);
+       if (!priv)
+               goto error;
 
-               return &priv->fe[0];
+       priv->i2c = i2c;
+       memcpy(&priv->cfg, cfg, sizeof (struct cxd2820r_config));
 
-       } else {
-               /* FE1: FE0 given as pointer, just return FE1 we have
-                * already created */
-               priv = fe->demodulator_priv;
-               return &priv->fe[1];
-       }
+       priv->bank[0] = priv->bank[1] = 0xff;
+       ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp);
+       dbg("%s: chip id=%02x", __func__, tmp);
+       if (ret || tmp != 0xe1)
+               goto error;
 
+       memcpy(&priv->fe.ops, &cxd2820r_ops, sizeof (struct dvb_frontend_ops));
+       priv->fe.demodulator_priv = priv;
+       return &priv->fe;
 error:
        kfree(priv);
        return NULL;
 }
 EXPORT_SYMBOL(cxd2820r_attach);
 
-static const struct dvb_frontend_ops cxd2820r_ops[2] = {
-       {
-               /* DVB-T/T2 */
-               .info = {
-                       .name = "Sony CXD2820R (DVB-T/T2)",
-                       .type = FE_OFDM,
-                       .caps =
-                               FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
-                               FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
-                               FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-                               FE_CAN_QPSK | FE_CAN_QAM_16 |
-                               FE_CAN_QAM_64 | FE_CAN_QAM_256 |
-                               FE_CAN_QAM_AUTO |
-                               FE_CAN_TRANSMISSION_MODE_AUTO |
-                               FE_CAN_GUARD_INTERVAL_AUTO |
-                               FE_CAN_HIERARCHY_AUTO |
-                               FE_CAN_MUTE_TS |
-                               FE_CAN_2G_MODULATION
-               },
-
-               .release = cxd2820r_release,
-               .init = cxd2820r_init,
-               .sleep = cxd2820r_sleep,
-
-               .get_tune_settings = cxd2820r_get_tune_settings,
-               .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl,
-
-               .get_frontend = cxd2820r_get_frontend,
-
-               .get_frontend_algo = cxd2820r_get_frontend_algo,
-               .search = cxd2820r_search,
-
-               .read_status = cxd2820r_read_status,
-               .read_snr = cxd2820r_read_snr,
-               .read_ber = cxd2820r_read_ber,
-               .read_ucblocks = cxd2820r_read_ucblocks,
-               .read_signal_strength = cxd2820r_read_signal_strength,
-       },
-       {
-               /* DVB-C */
-               .info = {
-                       .name = "Sony CXD2820R (DVB-C)",
-                       .type = FE_QAM,
-                       .caps =
-                               FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
-                               FE_CAN_QAM_128 | FE_CAN_QAM_256 |
-                               FE_CAN_FEC_AUTO
-               },
-
-               .release = cxd2820r_release,
-               .init = cxd2820r_init,
-               .sleep = cxd2820r_sleep,
-
-               .get_tune_settings = cxd2820r_get_tune_settings,
-               .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl,
-
-               .set_frontend = cxd2820r_set_frontend,
-               .get_frontend = cxd2820r_get_frontend,
-
-               .read_status = cxd2820r_read_status,
-               .read_snr = cxd2820r_read_snr,
-               .read_ber = cxd2820r_read_ber,
-               .read_ucblocks = cxd2820r_read_ucblocks,
-               .read_signal_strength = cxd2820r_read_signal_strength,
-       },
-};
-
-
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_DESCRIPTION("Sony CXD2820R demodulator driver");
 MODULE_LICENSE("GPL");
index 95539134efdb796c911543b908a37390e6eb2121..9a9822cad9cd59de41dce73474c51f44fa0e802c 100644 (file)
@@ -48,12 +48,9 @@ struct reg_val_mask {
 
 struct cxd2820r_priv {
        struct i2c_adapter *i2c;
-       struct dvb_frontend fe[2];
+       struct dvb_frontend fe;
        struct cxd2820r_config cfg;
 
-       struct mutex fe_lock; /* FE lock */
-       int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */
-
        bool ber_running;
 
        u8 bank[2];
@@ -89,11 +86,9 @@ int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val);
 
 /* cxd2820r_c.c */
 
-int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p);
+int cxd2820r_get_frontend_c(struct dvb_frontend *fe);
 
-int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params);
+int cxd2820r_set_frontend_c(struct dvb_frontend *fe);
 
 int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status);
 
@@ -114,11 +109,9 @@ int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
 
 /* cxd2820r_t.c */
 
-int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p);
+int cxd2820r_get_frontend_t(struct dvb_frontend *fe);
 
-int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params);
+int cxd2820r_set_frontend_t(struct dvb_frontend *fe);
 
 int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status);
 
@@ -139,11 +132,9 @@ int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
 
 /* cxd2820r_t2.c */
 
-int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p);
+int cxd2820r_get_frontend_t2(struct dvb_frontend *fe);
 
-int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params);
+int cxd2820r_set_frontend_t2(struct dvb_frontend *fe);
 
 int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status);
 
index a04f9c810101652138b2685973c1969d3cdf9c31..1a026239cdcc081afeb2b3f6d3e172d73a4c224c 100644 (file)
 
 #include "cxd2820r_priv.h"
 
-int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+int cxd2820r_set_frontend_t(struct dvb_frontend *fe)
 {
        struct cxd2820r_priv *priv = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       int ret, i;
-       u32 if_khz, if_ctl;
+       int ret, i, bw_i;
+       u32 if_freq, if_ctl;
        u64 num;
        u8 buf[3], bw_param;
        u8 bw_params1[][5] = {
@@ -57,6 +56,23 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
 
        dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
 
+       switch (c->bandwidth_hz) {
+       case 6000000:
+               bw_i = 0;
+               bw_param = 2;
+               break;
+       case 7000000:
+               bw_i = 1;
+               bw_param = 1;
+               break;
+       case 8000000:
+               bw_i = 2;
+               bw_param = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
        /* update GPIOs */
        ret = cxd2820r_gpio(fe);
        if (ret)
@@ -64,7 +80,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
 
        /* program tuner */
        if (fe->ops.tuner_ops.set_params)
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
 
        if (priv->delivery_system != SYS_DVBT) {
                for (i = 0; i < ARRAY_SIZE(tab); i++) {
@@ -78,27 +94,17 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
        priv->delivery_system = SYS_DVBT;
        priv->ber_running = 0; /* tune stops BER counter */
 
-       switch (c->bandwidth_hz) {
-       case 6000000:
-               if_khz = priv->cfg.if_dvbt_6;
-               i = 0;
-               bw_param = 2;
-               break;
-       case 7000000:
-               if_khz = priv->cfg.if_dvbt_7;
-               i = 1;
-               bw_param = 1;
-               break;
-       case 8000000:
-               if_khz = priv->cfg.if_dvbt_8;
-               i = 2;
-               bw_param = 0;
-               break;
-       default:
-               return -EINVAL;
-       }
+       /* program IF frequency */
+       if (fe->ops.tuner_ops.get_if_frequency) {
+               ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+               if (ret)
+                       goto error;
+       } else
+               if_freq = 0;
+
+       dbg("%s: if_freq=%d", __func__, if_freq);
 
-       num = if_khz;
+       num = if_freq / 1000; /* Hz => kHz */
        num *= 0x1000000;
        if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
        buf[0] = ((if_ctl >> 16) & 0xff);
@@ -109,7 +115,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
        if (ret)
                goto error;
 
-       ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[i], 5);
+       ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[bw_i], 5);
        if (ret)
                goto error;
 
@@ -117,7 +123,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
        if (ret)
                goto error;
 
-       ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[i], 2);
+       ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[bw_i], 2);
        if (ret)
                goto error;
 
@@ -135,8 +141,7 @@ error:
        return ret;
 }
 
-int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+int cxd2820r_get_frontend_t(struct dvb_frontend *fe)
 {
        struct cxd2820r_priv *priv = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
index 6548588309f7986ffc347e7c2915cc30fef0ec9c..3a5759e0d2352c3d6753acd400bd9d32442e6cdf 100644 (file)
 
 #include "cxd2820r_priv.h"
 
-int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params)
+int cxd2820r_set_frontend_t2(struct dvb_frontend *fe)
 {
        struct cxd2820r_priv *priv = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       int ret, i;
-       u32 if_khz, if_ctl;
+       int ret, i, bw_i;
+       u32 if_freq, if_ctl;
        u64 num;
        u8 buf[3], bw_param;
        u8 bw_params1[][5] = {
@@ -71,6 +70,27 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
 
        dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
 
+       switch (c->bandwidth_hz) {
+       case 5000000:
+               bw_i = 0;
+               bw_param = 3;
+               break;
+       case 6000000:
+               bw_i = 1;
+               bw_param = 2;
+               break;
+       case 7000000:
+               bw_i = 2;
+               bw_param = 1;
+               break;
+       case 8000000:
+               bw_i = 3;
+               bw_param = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
        /* update GPIOs */
        ret = cxd2820r_gpio(fe);
        if (ret)
@@ -78,7 +98,7 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
 
        /* program tuner */
        if (fe->ops.tuner_ops.set_params)
-               fe->ops.tuner_ops.set_params(fe, params);
+               fe->ops.tuner_ops.set_params(fe);
 
        if (priv->delivery_system != SYS_DVBT2) {
                for (i = 0; i < ARRAY_SIZE(tab); i++) {
@@ -91,32 +111,17 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
 
        priv->delivery_system = SYS_DVBT2;
 
-       switch (c->bandwidth_hz) {
-       case 5000000:
-               if_khz = priv->cfg.if_dvbt2_5;
-               i = 0;
-               bw_param = 3;
-               break;
-       case 6000000:
-               if_khz = priv->cfg.if_dvbt2_6;
-               i = 1;
-               bw_param = 2;
-               break;
-       case 7000000:
-               if_khz = priv->cfg.if_dvbt2_7;
-               i = 2;
-               bw_param = 1;
-               break;
-       case 8000000:
-               if_khz = priv->cfg.if_dvbt2_8;
-               i = 3;
-               bw_param = 0;
-               break;
-       default:
-               return -EINVAL;
-       }
+       /* program IF frequency */
+       if (fe->ops.tuner_ops.get_if_frequency) {
+               ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+               if (ret)
+                       goto error;
+       } else
+               if_freq = 0;
+
+       dbg("%s: if_freq=%d", __func__, if_freq);
 
-       num = if_khz;
+       num = if_freq / 1000; /* Hz => kHz */
        num *= 0x1000000;
        if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
        buf[0] = ((if_ctl >> 16) & 0xff);
@@ -127,7 +132,7 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
        if (ret)
                goto error;
 
-       ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[i], 5);
+       ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[bw_i], 5);
        if (ret)
                goto error;
 
@@ -150,8 +155,7 @@ error:
 
 }
 
-int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+int cxd2820r_get_frontend_t2(struct dvb_frontend *fe)
 {
        struct cxd2820r_priv *priv = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
index dc1cb17a6ea716993fe5e31c187bcd1f41881838..3b024bfe980aec8ef10cc5f5ae6fb78ff647e68e 100644 (file)
@@ -150,7 +150,7 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
     } \
 } while (0)
 
-static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+static int dib0070_set_bandwidth(struct dvb_frontend *fe)
 {
     struct dib0070_state *state = fe->tuner_priv;
     u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff;
@@ -335,7 +335,7 @@ static const struct dib0070_lna_match dib0070_lna[] = {
 };
 
 #define LPF    100
-static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+static int dib0070_tune_digital(struct dvb_frontend *fe)
 {
     struct dib0070_state *state = fe->tuner_priv;
 
@@ -507,7 +507,7 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par
 
        *tune_state = CT_TUNER_STEP_5;
     } else if (*tune_state == CT_TUNER_STEP_5) {
-       dib0070_set_bandwidth(fe, ch);
+       dib0070_set_bandwidth(fe);
        *tune_state = CT_TUNER_STOP;
     } else {
        ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
@@ -516,7 +516,7 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par
 }
 
 
-static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int dib0070_tune(struct dvb_frontend *fe)
 {
     struct dib0070_state *state = fe->tuner_priv;
     uint32_t ret;
@@ -524,7 +524,7 @@ static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters
     state->tune_state = CT_TUNER_START;
 
     do {
-       ret = dib0070_tune_digital(fe, p);
+       ret = dib0070_tune_digital(fe);
        if (ret != FE_CALLBACK_TIME_NEVER)
                msleep(ret/10);
        else
index b174d1c78583ee1001b8892626c80b00450f25fa..224d81e8509136ecaa5334702aaafea81b4135d3 100644 (file)
@@ -717,6 +717,34 @@ static const u16 rf_ramp_pwm_cband_7090[] = {
        (0 << 10) | 109,        /* RF_RAMP4, LNA 4 */
 };
 
+static const uint16_t rf_ramp_pwm_cband_7090e_sensitivity[] = {
+       186,
+       40,
+       746,
+       (10 << 10) | 345,
+       (0  << 10) | 746,
+       (0 << 10) | 0,
+       (0  << 10) | 0,
+       (28 << 10) | 200,
+       (0  << 10) | 345,
+       (20 << 10) | 0,
+       (0  << 10) | 200,
+};
+
+static const uint16_t rf_ramp_pwm_cband_7090e_aci[] = {
+       86,
+       40,
+       345,
+       (0 << 10) | 0,
+       (0 << 10) | 0,
+       (0 << 10) | 0,
+       (0 << 10) | 0,
+       (28 << 10) | 200,
+       (0  << 10) | 345,
+       (20 << 10) | 0,
+       (0  << 10) | 200,
+};
+
 static const u16 rf_ramp_pwm_cband_8090[] = {
        345,                    /* max RF gain in 10th of dB */
        29,                     /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
@@ -1076,8 +1104,16 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
                                dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
                                if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
                                        dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090);
-                               else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
-                                       dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
+                               else if (state->identity.version == SOC_7090_P1G_11R1
+                                               || state->identity.version == SOC_7090_P1G_21R1) {
+                                       if (state->config->is_dib7090e) {
+                                               if (state->rf_ramp == NULL)
+                                                       dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090e_sensitivity);
+                                               else
+                                                       dib0090_set_rframp_pwm(state, state->rf_ramp);
+                                       } else
+                                               dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
+                               }
                        } else {
                                dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
                                dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
@@ -1112,13 +1148,21 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
                else
                        dib0090_write_reg(state, 0x32, (0 << 11));
 
-               dib0090_write_reg(state, 0x04, 0x01);
+               dib0090_write_reg(state, 0x04, 0x03);
                dib0090_write_reg(state, 0x39, (1 << 10));
        }
 }
 
 EXPORT_SYMBOL(dib0090_pwm_gain_reset);
 
+void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
+{
+       struct dib0090_state *state = fe->tuner_priv;
+       if (DC_servo_cutoff < 4)
+               dib0090_write_reg(state, 0x04, DC_servo_cutoff);
+}
+EXPORT_SYMBOL(dib0090_set_dc_servo);
+
 static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
 {
        u16 adc_val = dib0090_read_reg(state, 0x1d);
@@ -1305,7 +1349,7 @@ void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 *
 
 EXPORT_SYMBOL(dib0090_get_current_gain);
 
-u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
+u16 dib0090_get_wbd_target(struct dvb_frontend *fe)
 {
        struct dib0090_state *state = fe->tuner_priv;
        u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
@@ -1342,9 +1386,57 @@ u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
 
        return state->wbd_offset + wbd_tcold;
 }
+EXPORT_SYMBOL(dib0090_get_wbd_target);
 
+u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
+{
+       struct dib0090_state *state = fe->tuner_priv;
+       return state->wbd_offset;
+}
 EXPORT_SYMBOL(dib0090_get_wbd_offset);
 
+int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3)
+{
+       struct dib0090_state *state = fe->tuner_priv;
+
+       dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xfff8)
+                       | ((sw3 & 1) << 2) | ((sw2 & 1) << 1) | (sw1 & 1));
+
+       return 0;
+}
+EXPORT_SYMBOL(dib0090_set_switch);
+
+int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff)
+{
+       struct dib0090_state *state = fe->tuner_priv;
+
+       dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x7fff)
+                       | ((onoff & 1) << 15));
+       return 0;
+}
+EXPORT_SYMBOL(dib0090_set_vga);
+
+int dib0090_update_rframp_7090(struct dvb_frontend *fe, u8 cfg_sensitivity)
+{
+       struct dib0090_state *state = fe->tuner_priv;
+
+       if ((!state->identity.p1g) || (!state->identity.in_soc)
+                       || ((state->identity.version != SOC_7090_P1G_21R1)
+                               && (state->identity.version != SOC_7090_P1G_11R1))) {
+               dprintk("%s() function can only be used for dib7090P", __func__);
+               return -ENODEV;
+       }
+
+       if (cfg_sensitivity)
+               state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
+       else
+               state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_aci;
+       dib0090_pwm_gain_reset(fe);
+
+       return 0;
+}
+EXPORT_SYMBOL(dib0090_update_rframp_7090);
+
 static const u16 dib0090_defaults[] = {
 
        25, 0x01,
@@ -1430,7 +1522,7 @@ static void dib0090_set_default_config(struct dib0090_state *state, const u16 *
 #define POLY_MIN      (u8)  0
 #define POLY_MAX      (u8)  8
 
-void dib0090_set_EFUSE(struct dib0090_state *state)
+static void dib0090_set_EFUSE(struct dib0090_state *state)
 {
        u8 c, h, n;
        u16 e2, e4;
@@ -1505,7 +1597,10 @@ static int dib0090_reset(struct dvb_frontend *fe)
                dib0090_set_EFUSE(state);
 
        /* Congigure in function of the crystal */
-       if (state->config->io.clock_khz >= 24000)
+       if (state->config->force_crystal_mode != 0)
+               dib0090_write_reg(state, 0x14,
+                               state->config->force_crystal_mode & 3);
+       else if (state->config->io.clock_khz >= 24000)
                dib0090_write_reg(state, 0x14, 1);
        else
                dib0090_write_reg(state, 0x14, 2);
@@ -1951,6 +2046,52 @@ static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
 #endif
 };
 
+static const struct dib0090_tuning dib0090_tuning_table_cband_7090e_sensitivity[] = {
+#ifdef CONFIG_BAND_CBAND
+       { 300000,  0 ,  3,  0x8105, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
+       { 380000,  0 ,  10, 0x810F, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
+       { 600000,  0 ,  10, 0x815E, 0x280, 0x2d12, 0xb84e, EN_CAB },
+       { 660000,  0 ,  5,  0x85E3, 0x280, 0x2d12, 0xb84e, EN_CAB },
+       { 720000,  0 ,  5,  0x852E, 0x280, 0x2d12, 0xb84e, EN_CAB },
+       { 860000,  0 ,  4,  0x85E5, 0x280, 0x2d12, 0xb84e, EN_CAB },
+#endif
+};
+
+int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
+               u8 cfg_sensitivity)
+{
+       struct dib0090_state *state = fe->tuner_priv;
+       const struct dib0090_tuning *tune =
+               dib0090_tuning_table_cband_7090e_sensitivity;
+       const struct dib0090_tuning dib0090_tuning_table_cband_7090e_aci[] = {
+               { 300000,  0 ,  3,  0x8165, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
+               { 650000,  0 ,  4,  0x815B, 0x280, 0x2d12, 0xb84e, EN_CAB },
+               { 860000,  0 ,  5,  0x84EF, 0x280, 0x2d12, 0xb84e, EN_CAB },
+       };
+
+       if ((!state->identity.p1g) || (!state->identity.in_soc)
+                       || ((state->identity.version != SOC_7090_P1G_21R1)
+                               && (state->identity.version != SOC_7090_P1G_11R1))) {
+               dprintk("%s() function can only be used for dib7090", __func__);
+               return -ENODEV;
+       }
+
+       if (cfg_sensitivity)
+               tune = dib0090_tuning_table_cband_7090e_sensitivity;
+       else
+               tune = dib0090_tuning_table_cband_7090e_aci;
+
+       while (state->rf_request > tune->max_freq)
+               tune++;
+
+       dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x8000)
+                       | (tune->lna_bias & 0x7fff));
+       dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xf83f)
+                       | ((tune->lna_tune << 6) & 0x07c0));
+       return 0;
+}
+EXPORT_SYMBOL(dib0090_update_tuning_table_7090);
+
 static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
 {
        int ret = 0;
@@ -2199,12 +2340,18 @@ static int dib0090_tune(struct dvb_frontend *fe)
                                        if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
                                                        || state->current_band & BAND_UHF) {
                                                state->current_band = BAND_CBAND;
-                                               tune = dib0090_tuning_table_cband_7090;
+                                               if (state->config->is_dib7090e)
+                                                       tune = dib0090_tuning_table_cband_7090e_sensitivity;
+                                               else
+                                                       tune = dib0090_tuning_table_cband_7090;
                                        }
                                } else {        /* Use the CBAND input for all band under UHF */
                                        if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
                                                state->current_band = BAND_CBAND;
-                                               tune = dib0090_tuning_table_cband_7090;
+                                               if (state->config->is_dib7090e)
+                                                       tune = dib0090_tuning_table_cband_7090e_sensitivity;
+                                               else
+                                                       tune = dib0090_tuning_table_cband_7090;
                                        }
                                }
                        } else
@@ -2419,7 +2566,7 @@ static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
        return 0;
 }
 
-static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int dib0090_set_params(struct dvb_frontend *fe)
 {
        struct dib0090_state *state = fe->tuner_priv;
        u32 ret;
index 13d85244ec160048cec20fb9ee6ac16f0a3211ca..781dc49de45b218b779411b413a565012761995b 100644 (file)
@@ -71,6 +71,8 @@ struct dib0090_config {
        u8 fref_clock_ratio;
        u16 force_cband_input;
        struct dib0090_wbd_slope *wbd;
+       u8 is_dib7090e;
+       u8 force_crystal_mode;
 };
 
 #if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE))
@@ -78,13 +80,21 @@ extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c
 extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
 extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast);
 extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe);
-extern u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner);
+extern u16 dib0090_get_wbd_target(struct dvb_frontend *tuner);
+extern u16 dib0090_get_wbd_offset(struct dvb_frontend *fe);
 extern int dib0090_gain_control(struct dvb_frontend *fe);
 extern enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe);
 extern int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state);
 extern void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt);
+extern void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff);
+extern int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3);
+extern int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff);
+extern int dib0090_update_rframp_7090(struct dvb_frontend *fe,
+               u8 cfg_sensitivity);
+extern int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
+               u8 cfg_sensitivity);
 #else
-static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config)
+static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
@@ -106,7 +116,13 @@ static inline void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 }
 
-static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner)
+static inline u16 dib0090_get_wbd_target(struct dvb_frontend *tuner)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return 0;
+}
+
+static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return 0;
@@ -134,6 +150,38 @@ static inline void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 }
+
+static inline void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+
+static inline int dib0090_set_switch(struct dvb_frontend *fe,
+               u8 sw1, u8 sw2, u8 sw3)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline int dib0090_update_rframp_7090(struct dvb_frontend *fe,
+               u8 cfg_sensitivity)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
+               u8 cfg_sensitivity)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
 #endif
 
 #endif
index 437904cbf3e6c5000660da6da0c92aeda5e4da99..af91e0c92339a994dea3a342c869aa9d43441489 100644 (file)
@@ -112,39 +112,37 @@ static u16 dib3000_seq[2][2][2] =     /* fft,gua,   inv   */
                }
        };
 
-static int dib3000mb_get_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep);
+static int dib3000mb_get_frontend(struct dvb_frontend* fe);
 
-static int dib3000mb_set_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep, int tuner)
+static int dib3000mb_set_frontend(struct dvb_frontend *fe, int tuner)
 {
        struct dib3000_state* state = fe->demodulator_priv;
-       struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        fe_code_rate_t fe_cr = FEC_NONE;
        int search_state, seq;
 
        if (tuner && fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, fep);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 
                deb_setf("bandwidth: ");
-               switch (ofdm->bandwidth) {
-                       case BANDWIDTH_8_MHZ:
+               switch (c->bandwidth_hz) {
+                       case 8000000:
                                deb_setf("8 MHz\n");
                                wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]);
                                wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz);
                                break;
-                       case BANDWIDTH_7_MHZ:
+                       case 7000000:
                                deb_setf("7 MHz\n");
                                wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[1]);
                                wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_7mhz);
                                break;
-                       case BANDWIDTH_6_MHZ:
+                       case 6000000:
                                deb_setf("6 MHz\n");
                                wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[0]);
                                wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_6mhz);
                                break;
-                       case BANDWIDTH_AUTO:
+                       case 0:
                                return -EOPNOTSUPP;
                        default:
                                err("unknown bandwidth value.");
@@ -154,7 +152,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
        wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4);
 
        deb_setf("transmission mode: ");
-       switch (ofdm->transmission_mode) {
+       switch (c->transmission_mode) {
                case TRANSMISSION_MODE_2K:
                        deb_setf("2k\n");
                        wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_2K);
@@ -171,7 +169,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
        }
 
        deb_setf("guard: ");
-       switch (ofdm->guard_interval) {
+       switch (c->guard_interval) {
                case GUARD_INTERVAL_1_32:
                        deb_setf("1_32\n");
                        wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_32);
@@ -196,7 +194,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
        }
 
        deb_setf("inversion: ");
-       switch (fep->inversion) {
+       switch (c->inversion) {
                case INVERSION_OFF:
                        deb_setf("off\n");
                        wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_OFF);
@@ -212,8 +210,8 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
                        return -EINVAL;
        }
 
-       deb_setf("constellation: ");
-       switch (ofdm->constellation) {
+       deb_setf("modulation: ");
+       switch (c->modulation) {
                case QPSK:
                        deb_setf("qpsk\n");
                        wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_QPSK);
@@ -232,7 +230,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
                        return -EINVAL;
        }
        deb_setf("hierarchy: ");
-       switch (ofdm->hierarchy_information) {
+       switch (c->hierarchy) {
                case HIERARCHY_NONE:
                        deb_setf("none ");
                        /* fall through */
@@ -256,16 +254,16 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
        }
 
        deb_setf("hierarchy: ");
-       if (ofdm->hierarchy_information == HIERARCHY_NONE) {
+       if (c->hierarchy == HIERARCHY_NONE) {
                deb_setf("none\n");
                wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_OFF);
                wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_HP);
-               fe_cr = ofdm->code_rate_HP;
-       } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) {
+               fe_cr = c->code_rate_HP;
+       } else if (c->hierarchy != HIERARCHY_AUTO) {
                deb_setf("on\n");
                wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_ON);
                wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_LP);
-               fe_cr = ofdm->code_rate_LP;
+               fe_cr = c->code_rate_LP;
        }
        deb_setf("fec: ");
        switch (fe_cr) {
@@ -300,9 +298,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
        }
 
        seq = dib3000_seq
-               [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO]
-               [ofdm->guard_interval == GUARD_INTERVAL_AUTO]
-               [fep->inversion == INVERSION_AUTO];
+               [c->transmission_mode == TRANSMISSION_MODE_AUTO]
+               [c->guard_interval == GUARD_INTERVAL_AUTO]
+               [c->inversion == INVERSION_AUTO];
 
        deb_setf("seq? %d\n", seq);
 
@@ -310,8 +308,8 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
 
        wr(DIB3000MB_REG_ISI, seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE);
 
-       if (ofdm->transmission_mode == TRANSMISSION_MODE_2K) {
-               if (ofdm->guard_interval == GUARD_INTERVAL_1_8) {
+       if (c->transmission_mode == TRANSMISSION_MODE_2K) {
+               if (c->guard_interval == GUARD_INTERVAL_1_8) {
                        wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_2K_1_8);
                } else {
                        wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_DEFAULT);
@@ -339,10 +337,10 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
        wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low);
 
        /* something has to be auto searched */
-       if (ofdm->constellation == QAM_AUTO ||
-               ofdm->hierarchy_information == HIERARCHY_AUTO ||
+       if (c->modulation == QAM_AUTO ||
+               c->hierarchy == HIERARCHY_AUTO ||
                fe_cr == FEC_AUTO ||
-               fep->inversion == INVERSION_AUTO) {
+               c->inversion == INVERSION_AUTO) {
                int as_count=0;
 
                deb_setf("autosearch enabled.\n");
@@ -361,10 +359,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
                deb_setf("search_state after autosearch %d after %d checks\n",search_state,as_count);
 
                if (search_state == 1) {
-                       struct dvb_frontend_parameters feps;
-                       if (dib3000mb_get_frontend(fe, &feps) == 0) {
+                       if (dib3000mb_get_frontend(fe) == 0) {
                                deb_setf("reading tuning data from frontend succeeded.\n");
-                               return dib3000mb_set_frontend(fe, &feps, 0);
+                               return dib3000mb_set_frontend(fe, 0);
                        }
                }
 
@@ -453,11 +450,10 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
        return 0;
 }
 
-static int dib3000mb_get_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep)
+static int dib3000mb_get_frontend(struct dvb_frontend* fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct dib3000_state* state = fe->demodulator_priv;
-       struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
        fe_code_rate_t *cr;
        u16 tps_val;
        int inv_test1,inv_test2;
@@ -484,25 +480,25 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
        else
                inv_test2 = 2;
 
-       fep->inversion =
+       c->inversion =
                ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) ||
                ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ?
                INVERSION_ON : INVERSION_OFF;
 
-       deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion);
+       deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, c->inversion);
 
        switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) {
                case DIB3000_CONSTELLATION_QPSK:
                        deb_getf("QPSK ");
-                       ofdm->constellation = QPSK;
+                       c->modulation = QPSK;
                        break;
                case DIB3000_CONSTELLATION_16QAM:
                        deb_getf("QAM16 ");
-                       ofdm->constellation = QAM_16;
+                       c->modulation = QAM_16;
                        break;
                case DIB3000_CONSTELLATION_64QAM:
                        deb_getf("QAM64 ");
-                       ofdm->constellation = QAM_64;
+                       c->modulation = QAM_64;
                        break;
                default:
                        err("Unexpected constellation returned by TPS (%d)", tps_val);
@@ -512,24 +508,24 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
 
        if (rd(DIB3000MB_REG_TPS_HRCH)) {
                deb_getf("HRCH ON\n");
-               cr = &ofdm->code_rate_LP;
-               ofdm->code_rate_HP = FEC_NONE;
+               cr = &c->code_rate_LP;
+               c->code_rate_HP = FEC_NONE;
                switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) {
                        case DIB3000_ALPHA_0:
                                deb_getf("HIERARCHY_NONE ");
-                               ofdm->hierarchy_information = HIERARCHY_NONE;
+                               c->hierarchy = HIERARCHY_NONE;
                                break;
                        case DIB3000_ALPHA_1:
                                deb_getf("HIERARCHY_1 ");
-                               ofdm->hierarchy_information = HIERARCHY_1;
+                               c->hierarchy = HIERARCHY_1;
                                break;
                        case DIB3000_ALPHA_2:
                                deb_getf("HIERARCHY_2 ");
-                               ofdm->hierarchy_information = HIERARCHY_2;
+                               c->hierarchy = HIERARCHY_2;
                                break;
                        case DIB3000_ALPHA_4:
                                deb_getf("HIERARCHY_4 ");
-                               ofdm->hierarchy_information = HIERARCHY_4;
+                               c->hierarchy = HIERARCHY_4;
                                break;
                        default:
                                err("Unexpected ALPHA value returned by TPS (%d)", tps_val);
@@ -540,9 +536,9 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
                tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP);
        } else {
                deb_getf("HRCH OFF\n");
-               cr = &ofdm->code_rate_HP;
-               ofdm->code_rate_LP = FEC_NONE;
-               ofdm->hierarchy_information = HIERARCHY_NONE;
+               cr = &c->code_rate_HP;
+               c->code_rate_LP = FEC_NONE;
+               c->hierarchy = HIERARCHY_NONE;
 
                tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP);
        }
@@ -577,19 +573,19 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
        switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) {
                case DIB3000_GUARD_TIME_1_32:
                        deb_getf("GUARD_INTERVAL_1_32 ");
-                       ofdm->guard_interval = GUARD_INTERVAL_1_32;
+                       c->guard_interval = GUARD_INTERVAL_1_32;
                        break;
                case DIB3000_GUARD_TIME_1_16:
                        deb_getf("GUARD_INTERVAL_1_16 ");
-                       ofdm->guard_interval = GUARD_INTERVAL_1_16;
+                       c->guard_interval = GUARD_INTERVAL_1_16;
                        break;
                case DIB3000_GUARD_TIME_1_8:
                        deb_getf("GUARD_INTERVAL_1_8 ");
-                       ofdm->guard_interval = GUARD_INTERVAL_1_8;
+                       c->guard_interval = GUARD_INTERVAL_1_8;
                        break;
                case DIB3000_GUARD_TIME_1_4:
                        deb_getf("GUARD_INTERVAL_1_4 ");
-                       ofdm->guard_interval = GUARD_INTERVAL_1_4;
+                       c->guard_interval = GUARD_INTERVAL_1_4;
                        break;
                default:
                        err("Unexpected Guard Time returned by TPS (%d)", tps_val);
@@ -600,11 +596,11 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe,
        switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) {
                case DIB3000_TRANSMISSION_MODE_2K:
                        deb_getf("TRANSMISSION_MODE_2K ");
-                       ofdm->transmission_mode = TRANSMISSION_MODE_2K;
+                       c->transmission_mode = TRANSMISSION_MODE_2K;
                        break;
                case DIB3000_TRANSMISSION_MODE_8K:
                        deb_getf("TRANSMISSION_MODE_8K ");
-                       ofdm->transmission_mode = TRANSMISSION_MODE_8K;
+                       c->transmission_mode = TRANSMISSION_MODE_8K;
                        break;
                default:
                        err("unexpected transmission mode return by TPS (%d)", tps_val);
@@ -701,9 +697,9 @@ static int dib3000mb_fe_init_nonmobile(struct dvb_frontend* fe)
        return dib3000mb_fe_init(fe, 0);
 }
 
-static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep)
+static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend *fe)
 {
-       return dib3000mb_set_frontend(fe, fep, 1);
+       return dib3000mb_set_frontend(fe, 1);
 }
 
 static void dib3000mb_release(struct dvb_frontend* fe)
@@ -794,10 +790,9 @@ error:
 }
 
 static struct dvb_frontend_ops dib3000mb_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "DiBcom 3000M-B DVB-T",
-               .type                   = FE_OFDM,
                .frequency_min          = 44250000,
                .frequency_max          = 867250000,
                .frequency_stepsize     = 62500,
index 16c526591f363c512e96d464b75548ee599a3dc3..9dc235aa44b71a712ba7c57918f9c786dd237e15 100644 (file)
@@ -98,7 +98,7 @@ struct dib3000_state {
        int timing_offset;
        int timing_offset_comp_done;
 
-       fe_bandwidth_t last_tuned_bw;
+       u32 last_tuned_bw;
        u32 last_tuned_freq;
 };
 
index 088e7fadbe3db11d01828606ed478096086c5c51..ffad181a96920bf90250d3aba9757247f1b56cec 100644 (file)
@@ -40,7 +40,7 @@ struct dib3000mc_state {
 
        u32 timf;
 
-       fe_bandwidth_t current_bandwidth;
+       u32 current_bandwidth;
 
        u16 dev_id;
 
@@ -438,11 +438,14 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
                dib3000mc_write_word(state, reg, cfg[reg - 129]);
 }
 
-static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq)
+static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state,
+                                     struct dtv_frontend_properties *ch, u16 seq)
 {
        u16 value;
-    dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
-       dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0);
+       u32 bw = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
+
+       dib3000mc_set_bandwidth(state, bw);
+       dib3000mc_set_timing(state, ch->transmission_mode, bw, 0);
 
 //     if (boost)
 //             dib3000mc_write_word(state, 100, (11 << 6) + 6);
@@ -471,22 +474,22 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_
        dib3000mc_write_word(state, 97,0);
        dib3000mc_write_word(state, 98,0);
 
-       dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode);
+       dib3000mc_set_impulse_noise(state, 0, ch->transmission_mode);
 
        value = 0;
-       switch (ch->u.ofdm.transmission_mode) {
+       switch (ch->transmission_mode) {
                case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
                default:
                case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
        }
-       switch (ch->u.ofdm.guard_interval) {
+       switch (ch->guard_interval) {
                case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
                case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
                case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;
                default:
                case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;
        }
-       switch (ch->u.ofdm.constellation) {
+       switch (ch->modulation) {
                case QPSK:  value |= (0 << 3); break;
                case QAM_16: value |= (1 << 3); break;
                default:
@@ -502,11 +505,11 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_
        dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
 
        value = 0;
-       if (ch->u.ofdm.hierarchy_information == 1)
+       if (ch->hierarchy == 1)
                value |= (1 << 4);
        if (1 == 1)
                value |= 1;
-       switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+       switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
                case FEC_2_3: value |= (2 << 1); break;
                case FEC_3_4: value |= (3 << 1); break;
                case FEC_5_6: value |= (5 << 1); break;
@@ -517,12 +520,12 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_
        dib3000mc_write_word(state, 181, value);
 
        // diversity synchro delay add 50% SFN margin
-       switch (ch->u.ofdm.transmission_mode) {
+       switch (ch->transmission_mode) {
                case TRANSMISSION_MODE_8K: value = 256; break;
                case TRANSMISSION_MODE_2K:
                default: value = 64; break;
        }
-       switch (ch->u.ofdm.guard_interval) {
+       switch (ch->guard_interval) {
                case GUARD_INTERVAL_1_16: value *= 2; break;
                case GUARD_INTERVAL_1_8:  value *= 4; break;
                case GUARD_INTERVAL_1_4:  value *= 8; break;
@@ -540,27 +543,28 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_
 
        msleep(30);
 
-       dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode);
+       dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->transmission_mode);
 }
 
-static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan)
+static int dib3000mc_autosearch_start(struct dvb_frontend *demod)
 {
+       struct dtv_frontend_properties *chan = &demod->dtv_property_cache;
        struct dib3000mc_state *state = demod->demodulator_priv;
        u16 reg;
 //     u32 val;
-       struct dvb_frontend_parameters schan;
+       struct dtv_frontend_properties schan;
 
        schan = *chan;
 
        /* TODO what is that ? */
 
        /* a channel for autosearch */
-       schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
-       schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
-       schan.u.ofdm.constellation = QAM_64;
-       schan.u.ofdm.code_rate_HP = FEC_2_3;
-       schan.u.ofdm.code_rate_LP = FEC_2_3;
-       schan.u.ofdm.hierarchy_information = 0;
+       schan.transmission_mode = TRANSMISSION_MODE_8K;
+       schan.guard_interval = GUARD_INTERVAL_1_32;
+       schan.modulation = QAM_64;
+       schan.code_rate_HP = FEC_2_3;
+       schan.code_rate_LP = FEC_2_3;
+       schan.hierarchy = 0;
 
        dib3000mc_set_channel_cfg(state, &schan, 11);
 
@@ -586,8 +590,9 @@ static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
        return 0; // still pending
 }
 
-static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib3000mc_tune(struct dvb_frontend *demod)
 {
+       struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
        struct dib3000mc_state *state = demod->demodulator_priv;
 
        // ** configure demod **
@@ -603,8 +608,8 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame
                dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift
        }
 
-       dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation);
-       if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) {
+       dib3000mc_set_adp_cfg(state, (u8)ch->modulation);
+       if (ch->transmission_mode == TRANSMISSION_MODE_8K) {
                dib3000mc_write_word(state, 26, 38528);
                dib3000mc_write_word(state, 33, 8);
        } else {
@@ -613,7 +618,8 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame
        }
 
        if (dib3000mc_read_word(state, 509) & 0x80)
-               dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1);
+               dib3000mc_set_timing(state, ch->transmission_mode,
+                                    BANDWIDTH_TO_KHZ(ch->bandwidth_hz), 1);
 
        return 0;
 }
@@ -626,87 +632,87 @@ struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod,
 
 EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);
 
-static int dib3000mc_get_frontend(struct dvb_frontend* fe,
-                               struct dvb_frontend_parameters *fep)
+static int dib3000mc_get_frontend(struct dvb_frontend* fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct dib3000mc_state *state = fe->demodulator_priv;
        u16 tps = dib3000mc_read_word(state,458);
 
        fep->inversion = INVERSION_AUTO;
 
-       fep->u.ofdm.bandwidth = state->current_bandwidth;
+       fep->bandwidth_hz = state->current_bandwidth;
 
        switch ((tps >> 8) & 0x1) {
-               case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
-               case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
+               case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break;
+               case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break;
        }
 
        switch (tps & 0x3) {
-               case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
-               case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
-               case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
-               case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
+               case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break;
+               case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break;
+               case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break;
+               case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break;
        }
 
        switch ((tps >> 13) & 0x3) {
-               case 0: fep->u.ofdm.constellation = QPSK; break;
-               case 1: fep->u.ofdm.constellation = QAM_16; break;
+               case 0: fep->modulation = QPSK; break;
+               case 1: fep->modulation = QAM_16; break;
                case 2:
-               default: fep->u.ofdm.constellation = QAM_64; break;
+               default: fep->modulation = QAM_64; break;
        }
 
        /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
        /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */
 
-       fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+       fep->hierarchy = HIERARCHY_NONE;
        switch ((tps >> 5) & 0x7) {
-               case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
-               case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
-               case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
-               case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
+               case 1: fep->code_rate_HP = FEC_1_2; break;
+               case 2: fep->code_rate_HP = FEC_2_3; break;
+               case 3: fep->code_rate_HP = FEC_3_4; break;
+               case 5: fep->code_rate_HP = FEC_5_6; break;
                case 7:
-               default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
+               default: fep->code_rate_HP = FEC_7_8; break;
 
        }
 
        switch ((tps >> 2) & 0x7) {
-               case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
-               case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
-               case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
-               case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
+               case 1: fep->code_rate_LP = FEC_1_2; break;
+               case 2: fep->code_rate_LP = FEC_2_3; break;
+               case 3: fep->code_rate_LP = FEC_3_4; break;
+               case 5: fep->code_rate_LP = FEC_5_6; break;
                case 7:
-               default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
+               default: fep->code_rate_LP = FEC_7_8; break;
        }
 
        return 0;
 }
 
-static int dib3000mc_set_frontend(struct dvb_frontend* fe,
-                               struct dvb_frontend_parameters *fep)
+static int dib3000mc_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct dib3000mc_state *state = fe->demodulator_priv;
-    int ret;
+       int ret;
 
        dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
 
-       state->current_bandwidth = fep->u.ofdm.bandwidth;
-       dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+       state->current_bandwidth = fep->bandwidth_hz;
+       dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz));
 
        /* maybe the parameter has been changed */
        state->sfn_workaround_active = buggy_sfn_workaround;
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, fep);
+               fe->ops.tuner_ops.set_params(fe);
                msleep(100);
        }
 
-       if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
-               fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||
-               fep->u.ofdm.constellation     == QAM_AUTO ||
-               fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
+       if (fep->transmission_mode  == TRANSMISSION_MODE_AUTO ||
+           fep->guard_interval == GUARD_INTERVAL_AUTO ||
+           fep->modulation     == QAM_AUTO ||
+           fep->code_rate_HP   == FEC_AUTO) {
                int i = 1000, found;
 
-               dib3000mc_autosearch_start(fe, fep);
+               dib3000mc_autosearch_start(fe);
                do {
                        msleep(1);
                        found = dib3000mc_autosearch_is_irq(fe);
@@ -716,14 +722,14 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
                if (found == 0 || found == 1)
                        return 0; // no channel found
 
-               dib3000mc_get_frontend(fe, fep);
+               dib3000mc_get_frontend(fe);
        }
 
-    ret = dib3000mc_tune(fe, fep);
+       ret = dib3000mc_tune(fe);
 
        /* make this a config parameter */
        dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
-    return ret;
+       return ret;
 }
 
 static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@@ -897,9 +903,9 @@ error:
 EXPORT_SYMBOL(dib3000mc_attach);
 
 static struct dvb_frontend_ops dib3000mc_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                .name = "DiBcom 3000MC/P",
-               .type = FE_OFDM,
                .frequency_min      = 44250000,
                .frequency_max      = 867250000,
                .frequency_stepsize = 62500,
index dbb76d75c932fecb36784a62be7451a3d63fb4c8..148bf79236fbcb858e01d98500424939b03a6f47 100644 (file)
@@ -38,7 +38,7 @@ struct dib7000m_state {
        u16 wbd_ref;
 
        u8 current_band;
-       fe_bandwidth_t current_bandwidth;
+       u32 current_bandwidth;
        struct dibx000_agc_config *current_agc;
        u32 timf;
        u32 timf_default;
@@ -313,6 +313,9 @@ static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw)
 {
        u32 timf;
 
+       if (!bw)
+               bw = 8000;
+
        // store the current bandwidth for later use
        state->current_bandwidth = bw;
 
@@ -742,8 +745,9 @@ static void dib7000m_update_timf(struct dib7000m_state *state)
        dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default);
 }
 
-static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib7000m_agc_startup(struct dvb_frontend *demod)
 {
+       struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
        struct dib7000m_state *state = demod->demodulator_priv;
        u16 cfg_72 = dib7000m_read_word(state, 72);
        int ret = -1;
@@ -832,28 +836,29 @@ static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_
        return ret;
 }
 
-static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq)
+static void dib7000m_set_channel(struct dib7000m_state *state, struct dtv_frontend_properties *ch,
+                                u8 seq)
 {
        u16 value, est[4];
 
-       dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+       dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
 
        /* nfft, guard, qam, alpha */
        value = 0;
-       switch (ch->u.ofdm.transmission_mode) {
+       switch (ch->transmission_mode) {
                case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
                case TRANSMISSION_MODE_4K: value |= (2 << 7); break;
                default:
                case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
        }
-       switch (ch->u.ofdm.guard_interval) {
+       switch (ch->guard_interval) {
                case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
                case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
                case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;
                default:
                case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;
        }
-       switch (ch->u.ofdm.constellation) {
+       switch (ch->modulation) {
                case QPSK:  value |= (0 << 3); break;
                case QAM_16: value |= (1 << 3); break;
                default:
@@ -872,11 +877,11 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte
        value = 0;
        if (1 != 0)
                value |= (1 << 6);
-       if (ch->u.ofdm.hierarchy_information == 1)
+       if (ch->hierarchy == 1)
                value |= (1 << 4);
        if (1 == 1)
                value |= 1;
-       switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+       switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
                case FEC_2_3: value |= (2 << 1); break;
                case FEC_3_4: value |= (3 << 1); break;
                case FEC_5_6: value |= (5 << 1); break;
@@ -901,13 +906,13 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte
        dib7000m_write_word(state, 33, (0 << 4) | 0x5);
 
        /* P_dvsy_sync_wait */
-       switch (ch->u.ofdm.transmission_mode) {
+       switch (ch->transmission_mode) {
                case TRANSMISSION_MODE_8K: value = 256; break;
                case TRANSMISSION_MODE_4K: value = 128; break;
                case TRANSMISSION_MODE_2K:
                default: value = 64; break;
        }
-       switch (ch->u.ofdm.guard_interval) {
+       switch (ch->guard_interval) {
                case GUARD_INTERVAL_1_16: value *= 2; break;
                case GUARD_INTERVAL_1_8:  value *= 4; break;
                case GUARD_INTERVAL_1_4:  value *= 8; break;
@@ -925,7 +930,7 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte
        dib7000m_set_diversity_in(&state->demod, state->div_state);
 
        /* channel estimation fine configuration */
-       switch (ch->u.ofdm.constellation) {
+       switch (ch->modulation) {
                case QAM_64:
                        est[0] = 0x0148;       /* P_adp_regul_cnt 0.04 */
                        est[1] = 0xfff0;       /* P_adp_noise_cnt -0.002 */
@@ -952,25 +957,26 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte
        dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
 }
 
-static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib7000m_autosearch_start(struct dvb_frontend *demod)
 {
+       struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
        struct dib7000m_state *state = demod->demodulator_priv;
-       struct dvb_frontend_parameters schan;
+       struct dtv_frontend_properties schan;
        int ret = 0;
        u32 value, factor;
 
        schan = *ch;
 
-       schan.u.ofdm.constellation = QAM_64;
-       schan.u.ofdm.guard_interval        = GUARD_INTERVAL_1_32;
-       schan.u.ofdm.transmission_mode         = TRANSMISSION_MODE_8K;
-       schan.u.ofdm.code_rate_HP = FEC_2_3;
-       schan.u.ofdm.code_rate_LP = FEC_3_4;
-       schan.u.ofdm.hierarchy_information         = 0;
+       schan.modulation = QAM_64;
+       schan.guard_interval        = GUARD_INTERVAL_1_32;
+       schan.transmission_mode         = TRANSMISSION_MODE_8K;
+       schan.code_rate_HP = FEC_2_3;
+       schan.code_rate_LP = FEC_3_4;
+       schan.hierarchy    = 0;
 
        dib7000m_set_channel(state, &schan, 7);
 
-       factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
+       factor = BANDWIDTH_TO_KHZ(schan.bandwidth_hz);
        if (factor >= 5000)
                factor = 1;
        else
@@ -1027,8 +1033,9 @@ static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod)
                return dib7000m_autosearch_irq(state, 537);
 }
 
-static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib7000m_tune(struct dvb_frontend *demod)
 {
+       struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
        struct dib7000m_state *state = demod->demodulator_priv;
        int ret = 0;
        u16 value;
@@ -1055,7 +1062,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
        //dump_reg(state);
        /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
        value = (6 << 8) | 0x80;
-       switch (ch->u.ofdm.transmission_mode) {
+       switch (ch->transmission_mode) {
                case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
                case TRANSMISSION_MODE_4K: value |= (8 << 12); break;
                default:
@@ -1065,7 +1072,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
 
        /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
        value = (0 << 4);
-       switch (ch->u.ofdm.transmission_mode) {
+       switch (ch->transmission_mode) {
                case TRANSMISSION_MODE_2K: value |= 0x6; break;
                case TRANSMISSION_MODE_4K: value |= 0x7; break;
                default:
@@ -1075,7 +1082,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
 
        /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
        value = (0 << 4);
-       switch (ch->u.ofdm.transmission_mode) {
+       switch (ch->transmission_mode) {
                case TRANSMISSION_MODE_2K: value |= 0x6; break;
                case TRANSMISSION_MODE_4K: value |= 0x7; break;
                default:
@@ -1087,7 +1094,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
        if ((dib7000m_read_word(state, 535) >> 6)  & 0x1)
                dib7000m_update_timf(state);
 
-    dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+       dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
        return ret;
 }
 
@@ -1147,57 +1154,57 @@ static int dib7000m_identify(struct dib7000m_state *state)
 }
 
 
-static int dib7000m_get_frontend(struct dvb_frontend* fe,
-                               struct dvb_frontend_parameters *fep)
+static int dib7000m_get_frontend(struct dvb_frontend* fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct dib7000m_state *state = fe->demodulator_priv;
        u16 tps = dib7000m_read_word(state,480);
 
        fep->inversion = INVERSION_AUTO;
 
-       fep->u.ofdm.bandwidth = state->current_bandwidth;
+       fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
 
        switch ((tps >> 8) & 0x3) {
-               case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
-               case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
-               /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
+               case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break;
+               case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break;
+               /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
        }
 
        switch (tps & 0x3) {
-               case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
-               case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
-               case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
-               case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
+               case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break;
+               case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break;
+               case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break;
+               case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break;
        }
 
        switch ((tps >> 14) & 0x3) {
-               case 0: fep->u.ofdm.constellation = QPSK; break;
-               case 1: fep->u.ofdm.constellation = QAM_16; break;
+               case 0: fep->modulation = QPSK; break;
+               case 1: fep->modulation = QAM_16; break;
                case 2:
-               default: fep->u.ofdm.constellation = QAM_64; break;
+               default: fep->modulation = QAM_64; break;
        }
 
        /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
        /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
 
-       fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+       fep->hierarchy = HIERARCHY_NONE;
        switch ((tps >> 5) & 0x7) {
-               case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
-               case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
-               case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
-               case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
+               case 1: fep->code_rate_HP = FEC_1_2; break;
+               case 2: fep->code_rate_HP = FEC_2_3; break;
+               case 3: fep->code_rate_HP = FEC_3_4; break;
+               case 5: fep->code_rate_HP = FEC_5_6; break;
                case 7:
-               default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
+               default: fep->code_rate_HP = FEC_7_8; break;
 
        }
 
        switch ((tps >> 2) & 0x7) {
-               case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
-               case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
-               case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
-               case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
+               case 1: fep->code_rate_LP = FEC_1_2; break;
+               case 2: fep->code_rate_LP = FEC_2_3; break;
+               case 3: fep->code_rate_LP = FEC_3_4; break;
+               case 5: fep->code_rate_LP = FEC_5_6; break;
                case 7:
-               default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
+               default: fep->code_rate_LP = FEC_7_8; break;
        }
 
        /* native interleaver: (dib7000m_read_word(state, 481) >>  5) & 0x1 */
@@ -1205,35 +1212,34 @@ static int dib7000m_get_frontend(struct dvb_frontend* fe,
        return 0;
 }
 
-static int dib7000m_set_frontend(struct dvb_frontend* fe,
-                               struct dvb_frontend_parameters *fep)
+static int dib7000m_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct dib7000m_state *state = fe->demodulator_priv;
        int time, ret;
 
-    dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
+       dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
 
-       state->current_bandwidth = fep->u.ofdm.bandwidth;
-       dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+       dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz));
 
        if (fe->ops.tuner_ops.set_params)
-               fe->ops.tuner_ops.set_params(fe, fep);
+               fe->ops.tuner_ops.set_params(fe);
 
        /* start up the AGC */
        state->agc_state = 0;
        do {
-               time = dib7000m_agc_startup(fe, fep);
+               time = dib7000m_agc_startup(fe);
                if (time != -1)
                        msleep(time);
        } while (time != -1);
 
-       if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
-               fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||
-               fep->u.ofdm.constellation     == QAM_AUTO ||
-               fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
+       if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
+               fep->guard_interval    == GUARD_INTERVAL_AUTO ||
+               fep->modulation        == QAM_AUTO ||
+               fep->code_rate_HP      == FEC_AUTO) {
                int i = 800, found;
 
-               dib7000m_autosearch_start(fe, fep);
+               dib7000m_autosearch_start(fe);
                do {
                        msleep(1);
                        found = dib7000m_autosearch_is_irq(fe);
@@ -1243,10 +1249,10 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
                if (found == 0 || found == 1)
                        return 0; // no channel found
 
-               dib7000m_get_frontend(fe, fep);
+               dib7000m_get_frontend(fe);
        }
 
-       ret = dib7000m_tune(fe, fep);
+       ret = dib7000m_tune(fe);
 
        /* make this a config parameter */
        dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
@@ -1430,9 +1436,9 @@ error:
 EXPORT_SYMBOL(dib7000m_attach);
 
 static struct dvb_frontend_ops dib7000m_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                .name = "DiBcom 7000MA/MB/PA/PB/MC",
-               .type = FE_OFDM,
                .frequency_min      = 44250000,
                .frequency_max      = 867250000,
                .frequency_stepsize = 62500,
index ce8534ff142efe448de4cf2b7f325edc74fadaab..5ceadc285b3ad59ef187d4c074db352ff1155d5c 100644 (file)
@@ -70,6 +70,8 @@ struct dib7000p_state {
        u8 i2c_write_buffer[4];
        u8 i2c_read_buffer[2];
        struct mutex i2c_buffer_lock;
+
+       u8 input_mode_mpeg;
 };
 
 enum dib7000p_power_mode {
@@ -78,8 +80,11 @@ enum dib7000p_power_mode {
        DIB7000P_POWER_INTERFACE_ONLY,
 };
 
+/* dib7090 specific fonctions */
 static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
 static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
+static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
+static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
 
 static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
 {
@@ -276,17 +281,23 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p
        dib7000p_write_word(state, 774, reg_774);
        dib7000p_write_word(state, 775, reg_775);
        dib7000p_write_word(state, 776, reg_776);
-       dib7000p_write_word(state, 899, reg_899);
        dib7000p_write_word(state, 1280, reg_1280);
+       if (state->version != SOC7090)
+               dib7000p_write_word(state, 899, reg_899);
 
        return 0;
 }
 
 static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
 {
-       u16 reg_908 = dib7000p_read_word(state, 908), reg_909 = dib7000p_read_word(state, 909);
+       u16 reg_908 = 0, reg_909 = 0;
        u16 reg;
 
+       if (state->version != SOC7090) {
+               reg_908 = dib7000p_read_word(state, 908);
+               reg_909 = dib7000p_read_word(state, 909);
+       }
+
        switch (no) {
        case DIBX000_SLOW_ADC_ON:
                if (state->version == SOC7090) {
@@ -342,8 +353,10 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad
        reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
        reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
 
-       dib7000p_write_word(state, 908, reg_908);
-       dib7000p_write_word(state, 909, reg_909);
+       if (state->version != SOC7090) {
+               dib7000p_write_word(state, 908, reg_908);
+               dib7000p_write_word(state, 909, reg_909);
+       }
 }
 
 static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
@@ -398,6 +411,24 @@ int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
 }
 EXPORT_SYMBOL(dib7000p_set_wbd_ref);
 
+int dib7000p_get_agc_values(struct dvb_frontend *fe,
+               u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+
+       if (agc_global != NULL)
+               *agc_global = dib7000p_read_word(state, 394);
+       if (agc1 != NULL)
+               *agc1 = dib7000p_read_word(state, 392);
+       if (agc2 != NULL)
+               *agc2 = dib7000p_read_word(state, 393);
+       if (wbd != NULL)
+               *wbd = dib7000p_read_word(state, 397);
+
+       return 0;
+}
+EXPORT_SYMBOL(dib7000p_get_agc_values);
+
 static void dib7000p_reset_pll(struct dib7000p_state *state)
 {
        struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
@@ -519,7 +550,7 @@ static u16 dib7000p_defaults[] = {
        // auto search configuration
        3, 2,
        0x0004,
-       0x1000,
+       (1<<3)|(1<<11)|(1<<12)|(1<<13),
        0x0814,                 /* Equal Lock */
 
        12, 6,
@@ -595,13 +626,6 @@ static u16 dib7000p_defaults[] = {
        1, 235,
        0x0062,
 
-       2, 901,
-       0x0006,
-       (3 << 10) | (1 << 6),
-
-       1, 905,
-       0x2c8e,
-
        0,
 };
 
@@ -618,15 +642,18 @@ static int dib7000p_demod_reset(struct dib7000p_state *state)
        dib7000p_write_word(state, 770, 0xffff);
        dib7000p_write_word(state, 771, 0xffff);
        dib7000p_write_word(state, 772, 0x001f);
-       dib7000p_write_word(state, 898, 0x0003);
        dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
 
        dib7000p_write_word(state, 770, 0);
        dib7000p_write_word(state, 771, 0);
        dib7000p_write_word(state, 772, 0);
-       dib7000p_write_word(state, 898, 0);
        dib7000p_write_word(state, 1280, 0);
 
+       if (state->version != SOC7090) {
+               dib7000p_write_word(state,  898, 0x0003);
+               dib7000p_write_word(state,  898, 0);
+       }
+
        /* default */
        dib7000p_reset_pll(state);
 
@@ -640,7 +667,7 @@ static int dib7000p_demod_reset(struct dib7000p_state *state)
                dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
                dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
                dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
-               dib7000p_write_word(state, 273, (1<<6) | 30);
+               dib7000p_write_word(state, 273, (0<<6) | 30);
        }
        if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
                dprintk("OUTPUT_MODE could not be reset.");
@@ -655,7 +682,7 @@ static int dib7000p_demod_reset(struct dib7000p_state *state)
        dib7000p_set_bandwidth(state, 8000);
 
        if (state->version == SOC7090) {
-               dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
+               dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
        } else {
                if (state->cfg.tuner_is_baseband)
                        dib7000p_write_word(state, 36, 0x0755);
@@ -664,6 +691,11 @@ static int dib7000p_demod_reset(struct dib7000p_state *state)
        }
 
        dib7000p_write_tab(state, dib7000p_defaults);
+       if (state->version != SOC7090) {
+               dib7000p_write_word(state, 901, 0x0006);
+               dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
+               dib7000p_write_word(state, 905, 0x2c8e);
+       }
 
        dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
 
@@ -780,8 +812,9 @@ static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
        }
 }
 
-static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib7000p_agc_startup(struct dvb_frontend *demod)
 {
+       struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
        struct dib7000p_state *state = demod->demodulator_priv;
        int ret = -1;
        u8 *agc_state = &state->agc_state;
@@ -904,15 +937,16 @@ u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
 }
 EXPORT_SYMBOL(dib7000p_ctrl_timf);
 
-static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
+static void dib7000p_set_channel(struct dib7000p_state *state,
+                                struct dtv_frontend_properties *ch, u8 seq)
 {
        u16 value, est[4];
 
-       dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+       dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
 
        /* nfft, guard, qam, alpha */
        value = 0;
-       switch (ch->u.ofdm.transmission_mode) {
+       switch (ch->transmission_mode) {
        case TRANSMISSION_MODE_2K:
                value |= (0 << 7);
                break;
@@ -924,7 +958,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
                value |= (1 << 7);
                break;
        }
-       switch (ch->u.ofdm.guard_interval) {
+       switch (ch->guard_interval) {
        case GUARD_INTERVAL_1_32:
                value |= (0 << 5);
                break;
@@ -939,7 +973,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
                value |= (2 << 5);
                break;
        }
-       switch (ch->u.ofdm.constellation) {
+       switch (ch->modulation) {
        case QPSK:
                value |= (0 << 3);
                break;
@@ -970,11 +1004,11 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
        value = 0;
        if (1 != 0)
                value |= (1 << 6);
-       if (ch->u.ofdm.hierarchy_information == 1)
+       if (ch->hierarchy == 1)
                value |= (1 << 4);
        if (1 == 1)
                value |= 1;
-       switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+       switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
        case FEC_2_3:
                value |= (2 << 1);
                break;
@@ -1001,7 +1035,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
        dib7000p_write_word(state, 33, 0x0005);
 
        /* P_dvsy_sync_wait */
-       switch (ch->u.ofdm.transmission_mode) {
+       switch (ch->transmission_mode) {
        case TRANSMISSION_MODE_8K:
                value = 256;
                break;
@@ -1013,7 +1047,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
                value = 64;
                break;
        }
-       switch (ch->u.ofdm.guard_interval) {
+       switch (ch->guard_interval) {
        case GUARD_INTERVAL_1_16:
                value *= 2;
                break;
@@ -1034,11 +1068,11 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
                state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
 
        /* deactive the possibility of diversity reception if extended interleaver */
-       state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
+       state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K;
        dib7000p_set_diversity_in(&state->demod, state->div_state);
 
        /* channel estimation fine configuration */
-       switch (ch->u.ofdm.constellation) {
+       switch (ch->modulation) {
        case QAM_64:
                est[0] = 0x0148;        /* P_adp_regul_cnt 0.04 */
                est[1] = 0xfff0;        /* P_adp_noise_cnt -0.002 */
@@ -1062,27 +1096,31 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
                dib7000p_write_word(state, 187 + value, est[value]);
 }
 
-static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib7000p_autosearch_start(struct dvb_frontend *demod)
 {
+       struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
        struct dib7000p_state *state = demod->demodulator_priv;
-       struct dvb_frontend_parameters schan;
+       struct dtv_frontend_properties schan;
        u32 value, factor;
        u32 internal = dib7000p_get_internal_freq(state);
 
        schan = *ch;
-       schan.u.ofdm.constellation = QAM_64;
-       schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
-       schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
-       schan.u.ofdm.code_rate_HP = FEC_2_3;
-       schan.u.ofdm.code_rate_LP = FEC_3_4;
-       schan.u.ofdm.hierarchy_information = 0;
+       schan.modulation = QAM_64;
+       schan.guard_interval = GUARD_INTERVAL_1_32;
+       schan.transmission_mode = TRANSMISSION_MODE_8K;
+       schan.code_rate_HP = FEC_2_3;
+       schan.code_rate_LP = FEC_3_4;
+       schan.hierarchy = 0;
 
        dib7000p_set_channel(state, &schan, 7);
 
-       factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
-       if (factor >= 5000)
-               factor = 1;
-       else
+       factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
+       if (factor >= 5000) {
+               if (state->version == SOC7090)
+                       factor = 2;
+               else
+                       factor = 1;
+       } else
                factor = 6;
 
        value = 30 * internal * factor;
@@ -1205,8 +1243,9 @@ static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32
        dib7000p_write_word(state, 143, 0);
 }
 
-static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+static int dib7000p_tune(struct dvb_frontend *demod)
 {
+       struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
        struct dib7000p_state *state = demod->demodulator_priv;
        u16 tmp = 0;
 
@@ -1239,7 +1278,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
 
        /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
        tmp = (6 << 8) | 0x80;
-       switch (ch->u.ofdm.transmission_mode) {
+       switch (ch->transmission_mode) {
        case TRANSMISSION_MODE_2K:
                tmp |= (2 << 12);
                break;
@@ -1255,7 +1294,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
 
        /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
        tmp = (0 << 4);
-       switch (ch->u.ofdm.transmission_mode) {
+       switch (ch->transmission_mode) {
        case TRANSMISSION_MODE_2K:
                tmp |= 0x6;
                break;
@@ -1271,7 +1310,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
 
        /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
        tmp = (0 << 4);
-       switch (ch->u.ofdm.transmission_mode) {
+       switch (ch->transmission_mode) {
        case TRANSMISSION_MODE_2K:
                tmp |= 0x6;
                break;
@@ -1303,9 +1342,9 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
        }
 
        if (state->cfg.spur_protect)
-               dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+               dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
 
-       dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+       dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
        return 0;
 }
 
@@ -1323,7 +1362,7 @@ static int dib7000p_sleep(struct dvb_frontend *demod)
 {
        struct dib7000p_state *state = demod->demodulator_priv;
        if (state->version == SOC7090)
-               return dib7090_set_output_mode(demod, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
+               return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
        return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
 }
 
@@ -1345,93 +1384,94 @@ static int dib7000p_identify(struct dib7000p_state *st)
        return 0;
 }
 
-static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib7000p_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct dib7000p_state *state = fe->demodulator_priv;
        u16 tps = dib7000p_read_word(state, 463);
 
        fep->inversion = INVERSION_AUTO;
 
-       fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
+       fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
 
        switch ((tps >> 8) & 0x3) {
        case 0:
-               fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+               fep->transmission_mode = TRANSMISSION_MODE_2K;
                break;
        case 1:
-               fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+               fep->transmission_mode = TRANSMISSION_MODE_8K;
                break;
-       /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
+       /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
        }
 
        switch (tps & 0x3) {
        case 0:
-               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+               fep->guard_interval = GUARD_INTERVAL_1_32;
                break;
        case 1:
-               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+               fep->guard_interval = GUARD_INTERVAL_1_16;
                break;
        case 2:
-               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+               fep->guard_interval = GUARD_INTERVAL_1_8;
                break;
        case 3:
-               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+               fep->guard_interval = GUARD_INTERVAL_1_4;
                break;
        }
 
        switch ((tps >> 14) & 0x3) {
        case 0:
-               fep->u.ofdm.constellation = QPSK;
+               fep->modulation = QPSK;
                break;
        case 1:
-               fep->u.ofdm.constellation = QAM_16;
+               fep->modulation = QAM_16;
                break;
        case 2:
        default:
-               fep->u.ofdm.constellation = QAM_64;
+               fep->modulation = QAM_64;
                break;
        }
 
        /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
        /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
 
-       fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+       fep->hierarchy = HIERARCHY_NONE;
        switch ((tps >> 5) & 0x7) {
        case 1:
-               fep->u.ofdm.code_rate_HP = FEC_1_2;
+               fep->code_rate_HP = FEC_1_2;
                break;
        case 2:
-               fep->u.ofdm.code_rate_HP = FEC_2_3;
+               fep->code_rate_HP = FEC_2_3;
                break;
        case 3:
-               fep->u.ofdm.code_rate_HP = FEC_3_4;
+               fep->code_rate_HP = FEC_3_4;
                break;
        case 5:
-               fep->u.ofdm.code_rate_HP = FEC_5_6;
+               fep->code_rate_HP = FEC_5_6;
                break;
        case 7:
        default:
-               fep->u.ofdm.code_rate_HP = FEC_7_8;
+               fep->code_rate_HP = FEC_7_8;
                break;
 
        }
 
        switch ((tps >> 2) & 0x7) {
        case 1:
-               fep->u.ofdm.code_rate_LP = FEC_1_2;
+               fep->code_rate_LP = FEC_1_2;
                break;
        case 2:
-               fep->u.ofdm.code_rate_LP = FEC_2_3;
+               fep->code_rate_LP = FEC_2_3;
                break;
        case 3:
-               fep->u.ofdm.code_rate_LP = FEC_3_4;
+               fep->code_rate_LP = FEC_3_4;
                break;
        case 5:
-               fep->u.ofdm.code_rate_LP = FEC_5_6;
+               fep->code_rate_LP = FEC_5_6;
                break;
        case 7:
        default:
-               fep->u.ofdm.code_rate_LP = FEC_7_8;
+               fep->code_rate_LP = FEC_7_8;
                break;
        }
 
@@ -1440,36 +1480,36 @@ static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_pa
        return 0;
 }
 
-static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib7000p_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct dib7000p_state *state = fe->demodulator_priv;
        int time, ret;
 
-       if (state->version == SOC7090) {
+       if (state->version == SOC7090)
                dib7090_set_diversity_in(fe, 0);
-               dib7090_set_output_mode(fe, OUTMODE_HIGH_Z);
-       } else
+       else
                dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
 
        /* maybe the parameter has been changed */
        state->sfn_workaround_active = buggy_sfn_workaround;
 
        if (fe->ops.tuner_ops.set_params)
-               fe->ops.tuner_ops.set_params(fe, fep);
+               fe->ops.tuner_ops.set_params(fe);
 
        /* start up the AGC */
        state->agc_state = 0;
        do {
-               time = dib7000p_agc_startup(fe, fep);
+               time = dib7000p_agc_startup(fe);
                if (time != -1)
                        msleep(time);
        } while (time != -1);
 
-       if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
-               fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) {
+       if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
+               fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) {
                int i = 800, found;
 
-               dib7000p_autosearch_start(fe, fep);
+               dib7000p_autosearch_start(fe);
                do {
                        msleep(1);
                        found = dib7000p_autosearch_is_irq(fe);
@@ -1479,15 +1519,19 @@ static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_pa
                if (found == 0 || found == 1)
                        return 0;
 
-               dib7000p_get_frontend(fe, fep);
+               dib7000p_get_frontend(fe);
        }
 
-       ret = dib7000p_tune(fe, fep);
+       ret = dib7000p_tune(fe);
 
        /* make this a config parameter */
-       if (state->version == SOC7090)
+       if (state->version == SOC7090) {
                dib7090_set_output_mode(fe, state->cfg.output_mode);
-       else
+               if (state->cfg.enMpegOutput == 0) {
+                       dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
+                       dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+               }
+       } else
                dib7000p_set_output_mode(state, state->cfg.output_mode);
 
        return ret;
@@ -1831,7 +1875,8 @@ static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg m
        return num;
 }
 
-int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address)
+static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
+               struct i2c_msg msg[], int num, u16 apb_address)
 {
        struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
        u16 word;
@@ -1933,10 +1978,10 @@ static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[]
                apb_address = 915;
                break;
        case 0x27:
-               apb_address = 916;
+               apb_address = 917;
                break;
        case 0x28:
-               apb_address = 917;
+               apb_address = 916;
                break;
        case 0x1d:
                i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
@@ -2031,12 +2076,7 @@ static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32
 
 static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
 {
-       u8 index_buf;
-       u16 rx_copy_buf[22];
-
        dprintk("Configure DibStream Tx");
-       for (index_buf = 0; index_buf < 22; index_buf++)
-               rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf);
 
        dib7000p_write_word(state, 1615, 1);
        dib7000p_write_word(state, 1603, P_Kin);
@@ -2048,9 +2088,6 @@ static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout
        dib7000p_write_word(state, 1612, syncSize);
        dib7000p_write_word(state, 1615, 0);
 
-       for (index_buf = 0; index_buf < 22; index_buf++)
-               dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]);
-
        return 0;
 }
 
@@ -2077,109 +2114,121 @@ static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout
        return 0;
 }
 
-static int dib7090_enDivOnHostBus(struct dib7000p_state *state)
-{
-       u16 reg;
-
-       dprintk("Enable Diversity on host bus");
-       reg = (1 << 8) | (1 << 5);
-       dib7000p_write_word(state, 1288, reg);
-
-       return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
-}
-
-static int dib7090_enAdcOnHostBus(struct dib7000p_state *state)
-{
-       u16 reg;
-
-       dprintk("Enable ADC on host bus");
-       reg = (1 << 7) | (1 << 5);
-       dib7000p_write_word(state, 1288, reg);
-
-       return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
-}
-
-static int dib7090_enMpegOnHostBus(struct dib7000p_state *state)
+static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
 {
-       u16 reg;
-
-       dprintk("Enable Mpeg on host bus");
-       reg = (1 << 9) | (1 << 5);
-       dib7000p_write_word(state, 1288, reg);
+       u16 reg_1287 = dib7000p_read_word(state, 1287);
 
-       return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
-}
+       switch (onoff) {
+       case 1:
+                       reg_1287 &= ~(1<<7);
+                       break;
+       case 0:
+                       reg_1287 |= (1<<7);
+                       break;
+       }
 
-static int dib7090_enMpegInput(struct dib7000p_state *state)
-{
-       dprintk("Enable Mpeg input");
-       return dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);   /*outputRate = 8 */
+       dib7000p_write_word(state, 1287, reg_1287);
 }
 
-static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
+static void dib7090_configMpegMux(struct dib7000p_state *state,
+               u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
 {
-       u16 reg = (1 << 7) | ((pulseWidth & 0x1f) << 2) | ((enSerialMode & 0x1) << 1) | (enSerialClkDiv2 & 0x1);
-
        dprintk("Enable Mpeg mux");
-       dib7000p_write_word(state, 1287, reg);
 
-       reg &= ~(1 << 7);
-       dib7000p_write_word(state, 1287, reg);
+       dib7090_enMpegMux(state, 0);
 
-       reg = (1 << 4);
-       dib7000p_write_word(state, 1288, reg);
+       /* If the input mode is MPEG do not divide the serial clock */
+       if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
+               enSerialClkDiv2 = 0;
 
-       return 0;
+       dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
+                       | ((enSerialMode & 0x1) << 1)
+                       | (enSerialClkDiv2 & 0x1));
+
+       dib7090_enMpegMux(state, 1);
 }
 
-static int dib7090_disableMpegMux(struct dib7000p_state *state)
+static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
 {
-       u16 reg;
-
-       dprintk("Disable Mpeg mux");
-       dib7000p_write_word(state, 1288, 0);
-
-       reg = dib7000p_read_word(state, 1287);
-       reg &= ~(1 << 7);
-       dib7000p_write_word(state, 1287, reg);
+       u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
 
-       return 0;
+       switch (mode) {
+       case MPEG_ON_DIBTX:
+                       dprintk("SET MPEG ON DIBSTREAM TX");
+                       dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
+                       reg_1288 |= (1<<9);
+                       break;
+       case DIV_ON_DIBTX:
+                       dprintk("SET DIV_OUT ON DIBSTREAM TX");
+                       dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
+                       reg_1288 |= (1<<8);
+                       break;
+       case ADC_ON_DIBTX:
+                       dprintk("SET ADC_OUT ON DIBSTREAM TX");
+                       dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
+                       reg_1288 |= (1<<7);
+                       break;
+       default:
+                       break;
+       }
+       dib7000p_write_word(state, 1288, reg_1288);
 }
 
-static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode)
+static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
 {
-       struct dib7000p_state *state = fe->demodulator_priv;
+       u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
 
        switch (mode) {
-       case INPUT_MODE_DIVERSITY:
-                       dprintk("Enable diversity INPUT");
-                       dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
+       case DEMOUT_ON_HOSTBUS:
+                       dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
+                       dib7090_enMpegMux(state, 0);
+                       reg_1288 |= (1<<6);
+                       break;
+       case DIBTX_ON_HOSTBUS:
+                       dprintk("SET DIBSTREAM TX ON HOST BUS");
+                       dib7090_enMpegMux(state, 0);
+                       reg_1288 |= (1<<5);
                        break;
-       case INPUT_MODE_MPEG:
-                       dprintk("Enable Mpeg INPUT");
-                       dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */
+       case MPEG_ON_HOSTBUS:
+                       dprintk("SET MPEG MUX ON HOST BUS");
+                       reg_1288 |= (1<<4);
                        break;
-       case INPUT_MODE_OFF:
        default:
-                       dprintk("Disable INPUT");
-                       dib7090_cfg_DibRx(state, 0, 0, 0, 0, 0, 0, 0);
                        break;
        }
-       return 0;
+       dib7000p_write_word(state, 1288, reg_1288);
 }
 
-static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
+int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
 {
+       struct dib7000p_state *state = fe->demodulator_priv;
+       u16 reg_1287;
+
        switch (onoff) {
-       case 0:         /* only use the internal way - not the diversity input */
-               dib7090_set_input_mode(fe, INPUT_MODE_MPEG);
-               break;
-       case 1:         /* both ways */
-       case 2:         /* only the diversity input */
-               dib7090_set_input_mode(fe, INPUT_MODE_DIVERSITY);
-               break;
+       case 0: /* only use the internal way - not the diversity input */
+                       dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__);
+                       dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
+
+                       /* Do not divide the serial clock of MPEG MUX */
+                       /* in SERIAL MODE in case input mode MPEG is used */
+                       reg_1287 = dib7000p_read_word(state, 1287);
+                       /* enSerialClkDiv2 == 1 ? */
+                       if ((reg_1287 & 0x1) == 1) {
+                               /* force enSerialClkDiv2 = 0 */
+                               reg_1287 &= ~0x1;
+                               dib7000p_write_word(state, 1287, reg_1287);
+                       }
+                       state->input_mode_mpeg = 1;
+                       break;
+       case 1: /* both ways */
+       case 2: /* only the diversity input */
+                       dprintk("%s ON : Enable diversity INPUT", __func__);
+                       dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
+                       state->input_mode_mpeg = 0;
+                       break;
        }
 
+       dib7000p_set_diversity_in(&state->demod, onoff);
        return 0;
 }
 
@@ -2204,69 +2253,63 @@ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
 
        case OUTMODE_MPEG2_SERIAL:
                if (prefer_mpeg_mux_use) {
-                       dprintk("Sip 7090P setting output mode TS_SERIAL using Mpeg Mux");
-                       dib7090_enMpegOnHostBus(state);
-                       dib7090_enMpegInput(state);
-                       if (state->cfg.enMpegOutput == 1)
-                               dib7090_enMpegMux(state, 3, 1, 1);
-
-               } else {        /* Use Smooth block */
-                       dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc");
-                       dib7090_disableMpegMux(state);
-                       dib7000p_write_word(state, 1288, (1 << 6));
-                       outreg |= (2 << 6) | (0 << 1);
+                       dprintk("setting output mode TS_SERIAL using Mpeg Mux");
+                       dib7090_configMpegMux(state, 3, 1, 1);
+                       dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
+               } else {/* Use Smooth block */
+                       dprintk("setting output mode TS_SERIAL using Smooth bloc");
+                       dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+                       outreg |= (2<<6) | (0 << 1);
                }
                break;
 
        case OUTMODE_MPEG2_PAR_GATED_CLK:
                if (prefer_mpeg_mux_use) {
-                       dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
-                       dib7090_enMpegOnHostBus(state);
-                       dib7090_enMpegInput(state);
-                       if (state->cfg.enMpegOutput == 1)
-                               dib7090_enMpegMux(state, 2, 0, 0);
-               } else {        /* Use Smooth block */
-                       dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block");
-                       dib7090_disableMpegMux(state);
-                       dib7000p_write_word(state, 1288, (1 << 6));
-                       outreg |= (0 << 6);
+                       dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux");
+                       dib7090_configMpegMux(state, 2, 0, 0);
+                       dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
+               } else { /* Use Smooth block */
+                       dprintk("setting output mode TS_PARALLEL_GATED using Smooth block");
+                       dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+                       outreg |= (0<<6);
                }
                break;
 
        case OUTMODE_MPEG2_PAR_CONT_CLK:        /* Using Smooth block only */
-               dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block");
-               dib7090_disableMpegMux(state);
-               dib7000p_write_word(state, 1288, (1 << 6));
-               outreg |= (1 << 6);
+               dprintk("setting output mode TS_PARALLEL_CONT using Smooth block");
+               dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+               outreg |= (1<<6);
                break;
 
        case OUTMODE_MPEG2_FIFO:        /* Using Smooth block because not supported by new Mpeg Mux bloc */
-               dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block");
-               dib7090_disableMpegMux(state);
-               dib7000p_write_word(state, 1288, (1 << 6));
-               outreg |= (5 << 6);
+               dprintk("setting output mode TS_FIFO using Smooth block");
+               dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+               outreg |= (5<<6);
                smo_mode |= (3 << 1);
                fifo_threshold = 512;
                break;
 
        case OUTMODE_DIVERSITY:
-               dprintk("Sip 7090P setting output mode MODE_DIVERSITY");
-               dib7090_disableMpegMux(state);
-               dib7090_enDivOnHostBus(state);
+               dprintk("setting output mode MODE_DIVERSITY");
+               dib7090_setDibTxMux(state, DIV_ON_DIBTX);
+               dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
                break;
 
        case OUTMODE_ANALOG_ADC:
-               dprintk("Sip 7090P setting output mode MODE_ANALOG_ADC");
-               dib7090_enAdcOnHostBus(state);
+               dprintk("setting output mode MODE_ANALOG_ADC");
+               dib7090_setDibTxMux(state, ADC_ON_DIBTX);
+               dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
                break;
        }
+       if (mode != OUTMODE_HIGH_Z)
+               outreg |= (1 << 10);
 
        if (state->cfg.output_mpeg2_in_188_bytes)
                smo_mode |= (1 << 5);
 
        ret |= dib7000p_write_word(state, 235, smo_mode);
        ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
-       ret |= dib7000p_write_word(state, 1286, outreg | (1 << 10));    /* allways set Dout active = 1 !!! */
+       ret |= dib7000p_write_word(state, 1286, outreg);
 
        return ret;
 }
@@ -2296,13 +2339,6 @@ int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
 }
 EXPORT_SYMBOL(dib7090_tuner_sleep);
 
-int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
-{
-       dprintk("AGC restart callback: %d", restart);
-       return 0;
-}
-EXPORT_SYMBOL(dib7090_agc_restart);
-
 int dib7090_get_adc_power(struct dvb_frontend *fe)
 {
        return dib7000p_get_adc_power(fe);
@@ -2391,9 +2427,9 @@ error:
 EXPORT_SYMBOL(dib7000p_attach);
 
 static struct dvb_frontend_ops dib7000p_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                 .name = "DiBcom 7000PC",
-                .type = FE_OFDM,
                 .frequency_min = 44250000,
                 .frequency_max = 867250000,
                 .frequency_stepsize = 62500,
index 0179f9474bac050054c2842626edb97697e53b6f..b61b03a6e1edad8480005dccb5817f662e0c0253 100644 (file)
@@ -56,11 +56,12 @@ extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
 extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
 extern int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw);
 extern u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf);
-extern int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart);
 extern int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff);
 extern int dib7090_get_adc_power(struct dvb_frontend *fe);
 extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe);
 extern int dib7090_slave_reset(struct dvb_frontend *fe);
+extern int dib7000p_get_agc_values(struct dvb_frontend *fe,
+               u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd);
 #else
 static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
 {
@@ -122,12 +123,6 @@ static inline u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
        return 0;
 }
 
-static inline int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
-{
-       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-       return -ENODEV;
-}
-
 static inline int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
@@ -151,6 +146,13 @@ static inline int dib7090_slave_reset(struct dvb_frontend *fe)
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return -ENODEV;
 }
+
+static inline int dib7000p_get_agc_values(struct dvb_frontend *fe,
+               u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
 #endif
 
 #endif
index fe284d5292f5422f16a846e1077c7df34c576098..9ca34f495009dc29f15509f9075986af3247fe48 100644 (file)
@@ -81,11 +81,15 @@ struct dib8000_state {
        u8 i2c_write_buffer[4];
        u8 i2c_read_buffer[2];
        struct mutex i2c_buffer_lock;
+       u8 input_mode_mpeg;
+
+       u16 tuner_enable;
+       struct i2c_adapter dib8096p_tuner_adap;
 };
 
 enum dib8000_power_mode {
-       DIB8000M_POWER_ALL = 0,
-       DIB8000M_POWER_INTERFACE_ONLY,
+       DIB8000_POWER_ALL = 0,
+       DIB8000_POWER_INTERFACE_ONLY,
 };
 
 static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
@@ -428,20 +432,31 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow
        /* by default everything is going to be powered off */
        u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
                reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
+               reg_1280;
+
+       if (state->revision != 0x8090)
                reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
+       else
+               reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
 
        /* now, depending on the requested mode, we power on */
        switch (mode) {
                /* power up everything in the demod */
-       case DIB8000M_POWER_ALL:
+       case DIB8000_POWER_ALL:
                reg_774 = 0x0000;
                reg_775 = 0x0000;
                reg_776 = 0x0000;
                reg_900 &= 0xfffc;
-               reg_1280 &= 0x00ff;
+               if (state->revision != 0x8090)
+                       reg_1280 &= 0x00ff;
+               else
+                       reg_1280 &= 0x707f;
                break;
-       case DIB8000M_POWER_INTERFACE_ONLY:
-               reg_1280 &= 0x00ff;
+       case DIB8000_POWER_INTERFACE_ONLY:
+               if (state->revision != 0x8090)
+                       reg_1280 &= 0x00ff;
+               else
+                       reg_1280 &= 0xfa7b;
                break;
        }
 
@@ -453,19 +468,67 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow
        dib8000_write_word(state, 1280, reg_1280);
 }
 
+static int dib8000_init_sdram(struct dib8000_state *state)
+{
+       u16 reg = 0;
+       dprintk("Init sdram");
+
+       reg = dib8000_read_word(state, 274)&0xfff0;
+       /* P_dintlv_delay_ram = 7 because of MobileSdram */
+       dib8000_write_word(state, 274, reg | 0x7);
+
+       dib8000_write_word(state, 1803, (7<<2));
+
+       reg = dib8000_read_word(state, 1280);
+       /* force restart P_restart_sdram */
+       dib8000_write_word(state, 1280,  reg | (1<<2));
+
+       /* release restart P_restart_sdram */
+       dib8000_write_word(state, 1280,  reg);
+
+       return 0;
+}
+
 static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
 {
        int ret = 0;
-       u16 reg_907 = dib8000_read_word(state, 907), reg_908 = dib8000_read_word(state, 908);
+       u16 reg, reg_907 = dib8000_read_word(state, 907);
+       u16 reg_908 = dib8000_read_word(state, 908);
 
        switch (no) {
        case DIBX000_SLOW_ADC_ON:
-               reg_908 |= (1 << 1) | (1 << 0);
-               ret |= dib8000_write_word(state, 908, reg_908);
-               reg_908 &= ~(1 << 1);
+               if (state->revision != 0x8090) {
+                       reg_908 |= (1 << 1) | (1 << 0);
+                       ret |= dib8000_write_word(state, 908, reg_908);
+                       reg_908 &= ~(1 << 1);
+               } else {
+                       reg = dib8000_read_word(state, 1925);
+                       /* en_slowAdc = 1 & reset_sladc = 1 */
+                       dib8000_write_word(state, 1925, reg |
+                                       (1<<4) | (1<<2));
+
+                       /* read acces to make it works... strange ... */
+                       reg = dib8000_read_word(state, 1925);
+                       msleep(20);
+                       /* en_slowAdc = 1 & reset_sladc = 0 */
+                       dib8000_write_word(state, 1925, reg & ~(1<<4));
+
+                       reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
+                                       | (0x3 << 12));
+                       /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
+                          (Vin2 = Vcm) */
+                       dib8000_write_word(state, 921, reg | (1 << 14)
+                                       | (3 << 12));
+               }
                break;
 
        case DIBX000_SLOW_ADC_OFF:
+               if (state->revision == 0x8090) {
+                       reg = dib8000_read_word(state, 1925);
+                       /* reset_sladc = 1 en_slowAdc = 0 */
+                       dib8000_write_word(state, 1925,
+                                       (reg & ~(1<<2)) | (1<<4));
+               }
                reg_908 |= (1 << 1) | (1 << 0);
                break;
 
@@ -521,7 +584,12 @@ static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
 
 static int dib8000_sad_calib(struct dib8000_state *state)
 {
-/* internal */
+       if (state->revision == 0x8090) {
+               dprintk("%s: the sad calibration is not needed for the dib8096P",
+                               __func__);
+               return 0;
+       }
+       /* internal */
        dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
        dib8000_write_word(state, 924, 776);    // 0.625*3.3 / 4096
 
@@ -546,48 +614,129 @@ EXPORT_SYMBOL(dib8000_set_wbd_ref);
 static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
 {
        dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
-       dib8000_write_word(state, 23, (u16) (((bw->internal * 1000) >> 16) & 0xffff));  /* P_sec_len */
-       dib8000_write_word(state, 24, (u16) ((bw->internal * 1000) & 0xffff));
+       if (state->revision != 0x8090) {
+               dib8000_write_word(state, 23,
+                               (u16) (((bw->internal * 1000) >> 16) & 0xffff));
+               dib8000_write_word(state, 24,
+                               (u16) ((bw->internal * 1000) & 0xffff));
+       } else {
+               dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
+               dib8000_write_word(state, 24,
+                               (u16) ((bw->internal  / 2 * 1000) & 0xffff));
+       }
        dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
        dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
        dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
 
-       dib8000_write_word(state, 922, bw->sad_cfg);
+       if (state->revision != 0x8090)
+               dib8000_write_word(state, 922, bw->sad_cfg);
 }
 
 static void dib8000_reset_pll(struct dib8000_state *state)
 {
        const struct dibx000_bandwidth_config *pll = state->cfg.pll;
-       u16 clk_cfg1;
-
-       // clk_cfg0
-       dib8000_write_word(state, 901, (pll->pll_prediv << 8) | (pll->pll_ratio << 0));
-
-       // clk_cfg1
-       clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
-               (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) |
-               (pll->pll_range << 1) | (pll->pll_reset << 0);
-
-       dib8000_write_word(state, 902, clk_cfg1);
-       clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
-       dib8000_write_word(state, 902, clk_cfg1);
-
-       dprintk("clk_cfg1: 0x%04x", clk_cfg1);  /* 0x507 1 0 1 000 0 0 11 1 */
-
-       /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
-       if (state->cfg.pll->ADClkSrc == 0)
-               dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) |
-                               (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
-       else if (state->cfg.refclksel != 0)
-               dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
-                               ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) |
-                               (pll->ADClkSrc << 7) | (0 << 1));
-       else
-               dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
+       u16 clk_cfg1, reg;
+
+       if (state->revision != 0x8090) {
+               dib8000_write_word(state, 901,
+                               (pll->pll_prediv << 8) | (pll->pll_ratio << 0));
+
+               clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
+                       (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
+                       (1 << 3) | (pll->pll_range << 1) |
+                       (pll->pll_reset << 0);
+
+               dib8000_write_word(state, 902, clk_cfg1);
+               clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
+               dib8000_write_word(state, 902, clk_cfg1);
+
+               dprintk("clk_cfg1: 0x%04x", clk_cfg1);
+
+               /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
+               if (state->cfg.pll->ADClkSrc == 0)
+                       dib8000_write_word(state, 904,
+                                       (0 << 15) | (0 << 12) | (0 << 10) |
+                                       (pll->modulo << 8) |
+                                       (pll->ADClkSrc << 7) | (0 << 1));
+               else if (state->cfg.refclksel != 0)
+                       dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
+                                       ((state->cfg.refclksel & 0x3) << 10) |
+                                       (pll->modulo << 8) |
+                                       (pll->ADClkSrc << 7) | (0 << 1));
+               else
+                       dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
+                                       (3 << 10) | (pll->modulo << 8) |
+                                       (pll->ADClkSrc << 7) | (0 << 1));
+       } else {
+               dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
+                               (pll->pll_range<<12) | (pll->pll_ratio<<6) |
+                               (pll->pll_prediv));
+
+               reg = dib8000_read_word(state, 1857);
+               dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
+
+               reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
+               dib8000_write_word(state, 1858, reg | 1);
+
+               dib8000_write_word(state, 904, (pll->modulo << 8));
+       }
 
        dib8000_reset_pll_common(state, pll);
 }
 
+int dib8000_update_pll(struct dvb_frontend *fe,
+               struct dibx000_bandwidth_config *pll)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+       u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
+       u8 loopdiv, prediv;
+       u32 internal, xtal;
+
+       /* get back old values */
+       prediv = reg_1856 & 0x3f;
+       loopdiv = (reg_1856 >> 6) & 0x3f;
+
+       if ((pll != NULL) && (pll->pll_prediv != prediv ||
+                               pll->pll_ratio != loopdiv)) {
+               dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
+               reg_1856 &= 0xf000;
+               reg_1857 = dib8000_read_word(state, 1857);
+               /* disable PLL */
+               dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
+
+               dib8000_write_word(state, 1856, reg_1856 |
+                               ((pll->pll_ratio & 0x3f) << 6) |
+                               (pll->pll_prediv & 0x3f));
+
+               /* write new system clk into P_sec_len */
+               internal = dib8000_read32(state, 23) / 1000;
+               dprintk("Old Internal = %d", internal);
+               xtal = 2 * (internal / loopdiv) * prediv;
+               internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
+               dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000);
+               dprintk("New Internal = %d", internal);
+
+               dib8000_write_word(state, 23,
+                               (u16) (((internal / 2) >> 16) & 0xffff));
+               dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
+               /* enable PLL */
+               dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
+
+               while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
+                       dprintk("Waiting for PLL to lock");
+
+               /* verify */
+               reg_1856 = dib8000_read_word(state, 1856);
+               dprintk("PLL Updated with prediv = %d and loopdiv = %d",
+                               reg_1856&0x3f, (reg_1856>>6)&0x3f);
+
+               return 0;
+       }
+       return -EINVAL;
+}
+EXPORT_SYMBOL(dib8000_update_pll);
+
+
 static int dib8000_reset_gpio(struct dib8000_state *st)
 {
        /* reset the GPIOs */
@@ -721,9 +870,6 @@ static const u16 dib8000_defaults[] = {
                (3 << 5) |              /* P_ctrl_pre_freq_step=3 */
                (1 << 0),               /* P_pre_freq_win_len=1 */
 
-       1, 903,
-       (0 << 4) | 2,           // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW)
-
        0,
 };
 
@@ -740,7 +886,8 @@ static u16 dib8000_identify(struct i2c_device *client)
        }
 
        value = dib8000_i2c_read16(client, 897);
-       if (value != 0x8000 && value != 0x8001 && value != 0x8002) {
+       if (value != 0x8000 && value != 0x8001 &&
+                       value != 0x8002 && value != 0x8090) {
                dprintk("wrong Device ID (%x)", value);
                return 0;
        }
@@ -755,6 +902,9 @@ static u16 dib8000_identify(struct i2c_device *client)
        case 0x8002:
                dprintk("found DiB8000C");
                break;
+       case 0x8090:
+               dprintk("found DiB8096P");
+               break;
        }
        return value;
 }
@@ -763,17 +913,19 @@ static int dib8000_reset(struct dvb_frontend *fe)
 {
        struct dib8000_state *state = fe->demodulator_priv;
 
-       dib8000_write_word(state, 1287, 0x0003);        /* sram lead in, rdy */
-
        if ((state->revision = dib8000_identify(&state->i2c)) == 0)
                return -EINVAL;
 
+       /* sram lead in, rdy */
+       if (state->revision != 0x8090)
+               dib8000_write_word(state, 1287, 0x0003);
+
        if (state->revision == 0x8000)
                dprintk("error : dib8000 MA not supported");
 
        dibx000_reset_i2c_master(&state->i2c_master);
 
-       dib8000_set_power_mode(state, DIB8000M_POWER_ALL);
+       dib8000_set_power_mode(state, DIB8000_POWER_ALL);
 
        /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
        dib8000_set_adc_state(state, DIBX000_VBG_ENABLE);
@@ -782,8 +934,10 @@ static int dib8000_reset(struct dvb_frontend *fe)
        dib8000_write_word(state, 770, 0xffff);
        dib8000_write_word(state, 771, 0xffff);
        dib8000_write_word(state, 772, 0xfffc);
-       dib8000_write_word(state, 898, 0x000c); // sad
-       dib8000_write_word(state, 1280, 0x004d);
+       if (state->revision == 0x8090)
+               dib8000_write_word(state, 1280, 0x0045);
+       else
+               dib8000_write_word(state, 1280, 0x004d);
        dib8000_write_word(state, 1281, 0x000c);
 
        dib8000_write_word(state, 770, 0x0000);
@@ -794,19 +948,25 @@ static int dib8000_reset(struct dvb_frontend *fe)
        dib8000_write_word(state, 1281, 0x0000);
 
        /* drives */
-       if (state->cfg.drives)
-               dib8000_write_word(state, 906, state->cfg.drives);
-       else {
-               dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
-               dib8000_write_word(state, 906, 0x2d98); // min drive SDRAM - not optimal - adjust
+       if (state->revision != 0x8090) {
+               if (state->cfg.drives)
+                       dib8000_write_word(state, 906, state->cfg.drives);
+               else {
+                       dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
+                       /* min drive SDRAM - not optimal - adjust */
+                       dib8000_write_word(state, 906, 0x2d98);
+               }
        }
 
        dib8000_reset_pll(state);
+       if (state->revision != 0x8090)
+               dib8000_write_word(state, 898, 0x0004);
 
        if (dib8000_reset_gpio(state) != 0)
                dprintk("GPIO reset was not successful.");
 
-       if (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)
+       if ((state->revision != 0x8090) &&
+                       (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
                dprintk("OUTPUT_MODE could not be resetted.");
 
        state->current_agc = NULL;
@@ -832,6 +992,8 @@ static int dib8000_reset(struct dvb_frontend *fe)
                        l = *n++;
                }
        }
+       if (state->revision != 0x8090)
+               dib8000_write_word(state, 903, (0 << 4) | 2);
        state->isdbt_cfg_loaded = 0;
 
        //div_cfg override for special configs
@@ -844,10 +1006,12 @@ static int dib8000_reset(struct dvb_frontend *fe)
        dib8000_set_bandwidth(fe, 6000);
 
        dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
-       dib8000_sad_calib(state);
-       dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+       if (state->revision != 0x8090) {
+               dib8000_sad_calib(state);
+               dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+       }
 
-       dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);
+       dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
 
        return 0;
 }
@@ -879,6 +1043,8 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
 {
        struct dibx000_agc_config *agc = NULL;
        int i;
+       u16 reg;
+
        if (state->current_band == band && state->current_agc != NULL)
                return 0;
        state->current_band = band;
@@ -914,6 +1080,12 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
                dib8000_write_word(state, 106, state->wbd_ref);
        else                    // use default
                dib8000_write_word(state, 106, agc->wbd_ref);
+
+       if (state->revision == 0x8090) {
+               reg = dib8000_read_word(state, 922) & (0x3 << 2);
+               dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
+       }
+
        dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
        dib8000_write_word(state, 108, agc->agc1_max);
        dib8000_write_word(state, 109, agc->agc1_min);
@@ -925,7 +1097,10 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
        dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
 
        dib8000_write_word(state, 75, agc->agc1_pt3);
-       dib8000_write_word(state, 923, (dib8000_read_word(state, 923) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));   /*LB : 929 -> 923 */
+       if (state->revision != 0x8090)
+               dib8000_write_word(state, 923,
+                               (dib8000_read_word(state, 923) & 0xffe3) |
+                               (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
 
        return 0;
 }
@@ -968,14 +1143,30 @@ static int dib8000_agc_startup(struct dvb_frontend *fe)
 {
        struct dib8000_state *state = fe->demodulator_priv;
        enum frontend_tune_state *tune_state = &state->tune_state;
-
        int ret = 0;
+       u16 reg, upd_demod_gain_period = 0x8000;
 
        switch (*tune_state) {
        case CT_AGC_START:
                // set power-up level: interf+analog+AGC
 
-               dib8000_set_adc_state(state, DIBX000_ADC_ON);
+               if (state->revision != 0x8090)
+                       dib8000_set_adc_state(state, DIBX000_ADC_ON);
+               else {
+                       dib8000_set_power_mode(state, DIB8000_POWER_ALL);
+
+                       reg = dib8000_read_word(state, 1947)&0xff00;
+                       dib8000_write_word(state, 1946,
+                                       upd_demod_gain_period & 0xFFFF);
+                       /* bit 14 = enDemodGain */
+                       dib8000_write_word(state, 1947, reg | (1<<14) |
+                                       ((upd_demod_gain_period >> 16) & 0xFF));
+
+                       /* enable adc i & q */
+                       reg = dib8000_read_word(state, 1920);
+                       dib8000_write_word(state, 1920, (reg | 0x3) &
+                                       (~(1 << 7)));
+               }
 
                if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
                        *tune_state = CT_AGC_STOP;
@@ -1026,6 +1217,579 @@ static int dib8000_agc_startup(struct dvb_frontend *fe)
 
 }
 
+static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
+{
+       u16 reg;
+
+       drive &= 0x7;
+
+       /* drive host bus 2, 3, 4 */
+       reg = dib8000_read_word(state, 1798) &
+               ~(0x7 | (0x7 << 6) | (0x7 << 12));
+       reg |= (drive<<12) | (drive<<6) | drive;
+       dib8000_write_word(state, 1798, reg);
+
+       /* drive host bus 5,6 */
+       reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
+       reg |= (drive<<8) | (drive<<2);
+       dib8000_write_word(state, 1799, reg);
+
+       /* drive host bus 7, 8, 9 */
+       reg = dib8000_read_word(state, 1800) &
+               ~(0x7 | (0x7 << 6) | (0x7 << 12));
+       reg |= (drive<<12) | (drive<<6) | drive;
+       dib8000_write_word(state, 1800, reg);
+
+       /* drive host bus 10, 11 */
+       reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
+       reg |= (drive<<8) | (drive<<2);
+       dib8000_write_word(state, 1801, reg);
+
+       /* drive host bus 12, 13, 14 */
+       reg = dib8000_read_word(state, 1802) &
+               ~(0x7 | (0x7 << 6) | (0x7 << 12));
+       reg |= (drive<<12) | (drive<<6) | drive;
+       dib8000_write_word(state, 1802, reg);
+}
+
+static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
+               u32 insertExtSynchro, u32 syncSize)
+{
+       u32 quantif = 3;
+       u32 nom = (insertExtSynchro * P_Kin+syncSize);
+       u32 denom = P_Kout;
+       u32 syncFreq = ((nom << quantif) / denom);
+
+       if ((syncFreq & ((1 << quantif) - 1)) != 0)
+               syncFreq = (syncFreq >> quantif) + 1;
+       else
+               syncFreq = (syncFreq >> quantif);
+
+       if (syncFreq != 0)
+               syncFreq = syncFreq - 1;
+
+       return syncFreq;
+}
+
+static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
+               u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
+               u32 syncWord, u32 syncSize)
+{
+       dprintk("Configure DibStream Tx");
+
+       dib8000_write_word(state, 1615, 1);
+       dib8000_write_word(state, 1603, P_Kin);
+       dib8000_write_word(state, 1605, P_Kout);
+       dib8000_write_word(state, 1606, insertExtSynchro);
+       dib8000_write_word(state, 1608, synchroMode);
+       dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
+       dib8000_write_word(state, 1610, syncWord & 0xffff);
+       dib8000_write_word(state, 1612, syncSize);
+       dib8000_write_word(state, 1615, 0);
+}
+
+static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
+               u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
+               u32 syncWord, u32 syncSize, u32 dataOutRate)
+{
+       u32 syncFreq;
+
+       dprintk("Configure DibStream Rx synchroMode = %d", synchroMode);
+
+       if ((P_Kin != 0) && (P_Kout != 0)) {
+               syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
+                               insertExtSynchro, syncSize);
+               dib8000_write_word(state, 1542, syncFreq);
+       }
+
+       dib8000_write_word(state, 1554, 1);
+       dib8000_write_word(state, 1536, P_Kin);
+       dib8000_write_word(state, 1537, P_Kout);
+       dib8000_write_word(state, 1539, synchroMode);
+       dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
+       dib8000_write_word(state, 1541, syncWord & 0xffff);
+       dib8000_write_word(state, 1543, syncSize);
+       dib8000_write_word(state, 1544, dataOutRate);
+       dib8000_write_word(state, 1554, 0);
+}
+
+static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
+{
+       u16 reg_1287;
+
+       reg_1287 = dib8000_read_word(state, 1287);
+
+       switch (onoff) {
+       case 1:
+                       reg_1287 &= ~(1 << 8);
+                       break;
+       case 0:
+                       reg_1287 |= (1 << 8);
+                       break;
+       }
+
+       dib8000_write_word(state, 1287, reg_1287);
+}
+
+static void dib8096p_configMpegMux(struct dib8000_state *state,
+               u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
+{
+       u16 reg_1287;
+
+       dprintk("Enable Mpeg mux");
+
+       dib8096p_enMpegMux(state, 0);
+
+       /* If the input mode is MPEG do not divide the serial clock */
+       if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
+               enSerialClkDiv2 = 0;
+
+       reg_1287 = ((pulseWidth & 0x1f) << 3) |
+               ((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
+       dib8000_write_word(state, 1287, reg_1287);
+
+       dib8096p_enMpegMux(state, 1);
+}
+
+static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
+{
+       u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
+
+       switch (mode) {
+       case MPEG_ON_DIBTX:
+                       dprintk("SET MPEG ON DIBSTREAM TX");
+                       dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
+                       reg_1288 |= (1 << 9); break;
+       case DIV_ON_DIBTX:
+                       dprintk("SET DIV_OUT ON DIBSTREAM TX");
+                       dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
+                       reg_1288 |= (1 << 8); break;
+       case ADC_ON_DIBTX:
+                       dprintk("SET ADC_OUT ON DIBSTREAM TX");
+                       dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
+                       reg_1288 |= (1 << 7); break;
+       default:
+                       break;
+       }
+       dib8000_write_word(state, 1288, reg_1288);
+}
+
+static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
+{
+       u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
+
+       switch (mode) {
+       case DEMOUT_ON_HOSTBUS:
+                       dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
+                       dib8096p_enMpegMux(state, 0);
+                       reg_1288 |= (1 << 6);
+                       break;
+       case DIBTX_ON_HOSTBUS:
+                       dprintk("SET DIBSTREAM TX ON HOST BUS");
+                       dib8096p_enMpegMux(state, 0);
+                       reg_1288 |= (1 << 5);
+                       break;
+       case MPEG_ON_HOSTBUS:
+                       dprintk("SET MPEG MUX ON HOST BUS");
+                       reg_1288 |= (1 << 4);
+                       break;
+       default:
+                       break;
+       }
+       dib8000_write_word(state, 1288, reg_1288);
+}
+
+static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+       u16 reg_1287;
+
+       switch (onoff) {
+       case 0: /* only use the internal way - not the diversity input */
+                       dprintk("%s mode OFF : by default Enable Mpeg INPUT",
+                                       __func__);
+                       /* outputRate = 8 */
+                       dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
+
+                       /* Do not divide the serial clock of MPEG MUX in
+                          SERIAL MODE in case input mode MPEG is used */
+                       reg_1287 = dib8000_read_word(state, 1287);
+                       /* enSerialClkDiv2 == 1 ? */
+                       if ((reg_1287 & 0x1) == 1) {
+                               /* force enSerialClkDiv2 = 0 */
+                               reg_1287 &= ~0x1;
+                               dib8000_write_word(state, 1287, reg_1287);
+                       }
+                       state->input_mode_mpeg = 1;
+                       break;
+       case 1: /* both ways */
+       case 2: /* only the diversity input */
+                       dprintk("%s ON : Enable diversity INPUT", __func__);
+                       dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
+                       state->input_mode_mpeg = 0;
+                       break;
+       }
+
+       dib8000_set_diversity_in(state->fe[0], onoff);
+       return 0;
+}
+
+static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+       u16 outreg, smo_mode, fifo_threshold;
+       u8 prefer_mpeg_mux_use = 1;
+       int ret = 0;
+
+       dib8096p_host_bus_drive(state, 1);
+
+       fifo_threshold = 1792;
+       smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
+       outreg   = dib8000_read_word(state, 1286) &
+               ~((1 << 10) | (0x7 << 6) | (1 << 1));
+
+       switch (mode) {
+       case OUTMODE_HIGH_Z:
+                       outreg = 0;
+                       break;
+
+       case OUTMODE_MPEG2_SERIAL:
+                       if (prefer_mpeg_mux_use) {
+                               dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux");
+                               dib8096p_configMpegMux(state, 3, 1, 1);
+                               dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
+                       } else {/* Use Smooth block */
+                               dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc");
+                               dib8096p_setHostBusMux(state,
+                                               DEMOUT_ON_HOSTBUS);
+                               outreg |= (2 << 6) | (0 << 1);
+                       }
+                       break;
+
+       case OUTMODE_MPEG2_PAR_GATED_CLK:
+                       if (prefer_mpeg_mux_use) {
+                               dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
+                               dib8096p_configMpegMux(state, 2, 0, 0);
+                               dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
+                       } else { /* Use Smooth block */
+                               dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block");
+                               dib8096p_setHostBusMux(state,
+                                               DEMOUT_ON_HOSTBUS);
+                               outreg |= (0 << 6);
+                       }
+                       break;
+
+       case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
+                       dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block");
+                       dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+                       outreg |= (1 << 6);
+                       break;
+
+       case OUTMODE_MPEG2_FIFO:
+                       /* Using Smooth block because not supported
+                          by new Mpeg Mux bloc */
+                       dprintk("dib8096P setting output mode TS_FIFO using Smooth block");
+                       dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
+                       outreg |= (5 << 6);
+                       smo_mode |= (3 << 1);
+                       fifo_threshold = 512;
+                       break;
+
+       case OUTMODE_DIVERSITY:
+                       dprintk("dib8096P setting output mode MODE_DIVERSITY");
+                       dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
+                       dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+                       break;
+
+       case OUTMODE_ANALOG_ADC:
+                       dprintk("dib8096P setting output mode MODE_ANALOG_ADC");
+                       dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
+                       dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+                       break;
+       }
+
+       if (mode != OUTMODE_HIGH_Z)
+               outreg |= (1<<10);
+
+       dprintk("output_mpeg2_in_188_bytes = %d",
+                       state->cfg.output_mpeg2_in_188_bytes);
+       if (state->cfg.output_mpeg2_in_188_bytes)
+               smo_mode |= (1 << 5);
+
+       ret |= dib8000_write_word(state, 299, smo_mode);
+       /* synchronous fread */
+       ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
+       ret |= dib8000_write_word(state, 1286, outreg);
+
+       return ret;
+}
+
+static int map_addr_to_serpar_number(struct i2c_msg *msg)
+{
+       if (msg->buf[0] <= 15)
+               msg->buf[0] -= 1;
+       else if (msg->buf[0] == 17)
+               msg->buf[0] = 15;
+       else if (msg->buf[0] == 16)
+               msg->buf[0] = 17;
+       else if (msg->buf[0] == 19)
+               msg->buf[0] = 16;
+       else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
+               msg->buf[0] -= 3;
+       else if (msg->buf[0] == 28)
+               msg->buf[0] = 23;
+       else if (msg->buf[0] == 99)
+               msg->buf[0] = 99;
+       else
+               return -EINVAL;
+       return 0;
+}
+
+static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
+               struct i2c_msg msg[], int num)
+{
+       struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
+       u8 n_overflow = 1;
+       u16 i = 1000;
+       u16 serpar_num = msg[0].buf[0];
+
+       while (n_overflow == 1 && i) {
+               n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
+               i--;
+               if (i == 0)
+                       dprintk("Tuner ITF: write busy (overflow)");
+       }
+       dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
+       dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
+
+       return num;
+}
+
+static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
+               struct i2c_msg msg[], int num)
+{
+       struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
+       u8 n_overflow = 1, n_empty = 1;
+       u16 i = 1000;
+       u16 serpar_num = msg[0].buf[0];
+       u16 read_word;
+
+       while (n_overflow == 1 && i) {
+               n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
+               i--;
+               if (i == 0)
+                       dprintk("TunerITF: read busy (overflow)");
+       }
+       dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
+
+       i = 1000;
+       while (n_empty == 1 && i) {
+               n_empty = dib8000_read_word(state, 1984)&0x1;
+               i--;
+               if (i == 0)
+                       dprintk("TunerITF: read busy (empty)");
+       }
+
+       read_word = dib8000_read_word(state, 1987);
+       msg[1].buf[0] = (read_word >> 8) & 0xff;
+       msg[1].buf[1] = (read_word) & 0xff;
+
+       return num;
+}
+
+static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
+               struct i2c_msg msg[], int num)
+{
+       if (map_addr_to_serpar_number(&msg[0]) == 0) {
+               if (num == 1) /* write */
+                       return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
+               else /* read */
+                       return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
+       }
+       return num;
+}
+
+static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
+               struct i2c_msg msg[], int num, u16 apb_address)
+{
+       struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
+       u16 word;
+
+       if (num == 1) {         /* write */
+               dib8000_write_word(state, apb_address,
+                               ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
+       } else {
+               word = dib8000_read_word(state, apb_address);
+               msg[1].buf[0] = (word >> 8) & 0xff;
+               msg[1].buf[1] = (word) & 0xff;
+       }
+       return num;
+}
+
+static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
+               struct i2c_msg msg[], int num)
+{
+       struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
+       u16 apb_address = 0, word;
+       int i = 0;
+
+       switch (msg[0].buf[0]) {
+       case 0x12:
+                       apb_address = 1920;
+                       break;
+       case 0x14:
+                       apb_address = 1921;
+                       break;
+       case 0x24:
+                       apb_address = 1922;
+                       break;
+       case 0x1a:
+                       apb_address = 1923;
+                       break;
+       case 0x22:
+                       apb_address = 1924;
+                       break;
+       case 0x33:
+                       apb_address = 1926;
+                       break;
+       case 0x34:
+                       apb_address = 1927;
+                       break;
+       case 0x35:
+                       apb_address = 1928;
+                       break;
+       case 0x36:
+                       apb_address = 1929;
+                       break;
+       case 0x37:
+                       apb_address = 1930;
+                       break;
+       case 0x38:
+                       apb_address = 1931;
+                       break;
+       case 0x39:
+                       apb_address = 1932;
+                       break;
+       case 0x2a:
+                       apb_address = 1935;
+                       break;
+       case 0x2b:
+                       apb_address = 1936;
+                       break;
+       case 0x2c:
+                       apb_address = 1937;
+                       break;
+       case 0x2d:
+                       apb_address = 1938;
+                       break;
+       case 0x2e:
+                       apb_address = 1939;
+                       break;
+       case 0x2f:
+                       apb_address = 1940;
+                       break;
+       case 0x30:
+                       apb_address = 1941;
+                       break;
+       case 0x31:
+                       apb_address = 1942;
+                       break;
+       case 0x32:
+                       apb_address = 1943;
+                       break;
+       case 0x3e:
+                       apb_address = 1944;
+                       break;
+       case 0x3f:
+                       apb_address = 1945;
+                       break;
+       case 0x40:
+                       apb_address = 1948;
+                       break;
+       case 0x25:
+                       apb_address = 936;
+                       break;
+       case 0x26:
+                       apb_address = 937;
+                       break;
+       case 0x27:
+                       apb_address = 938;
+                       break;
+       case 0x28:
+                       apb_address = 939;
+                       break;
+       case 0x1d:
+                       /* get sad sel request */
+                       i = ((dib8000_read_word(state, 921) >> 12)&0x3);
+                       word = dib8000_read_word(state, 924+i);
+                       msg[1].buf[0] = (word >> 8) & 0xff;
+                       msg[1].buf[1] = (word) & 0xff;
+                       return num;
+       case 0x1f:
+                       if (num == 1) { /* write */
+                               word = (u16) ((msg[0].buf[1] << 8) |
+                                               msg[0].buf[2]);
+                               /* in the VGAMODE Sel are located on bit 0/1 */
+                               word &= 0x3;
+                               word = (dib8000_read_word(state, 921) &
+                                               ~(3<<12)) | (word<<12);
+                               /* Set the proper input */
+                               dib8000_write_word(state, 921, word);
+                               return num;
+                       }
+       }
+
+       if (apb_address != 0) /* R/W acces via APB */
+               return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
+       else  /* R/W access via SERPAR  */
+               return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
+
+       return 0;
+}
+
+static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
+       .master_xfer = dib8096p_tuner_xfer,
+       .functionality = dib8096p_i2c_func,
+};
+
+struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
+{
+       struct dib8000_state *st = fe->demodulator_priv;
+       return &st->dib8096p_tuner_adap;
+}
+EXPORT_SYMBOL(dib8096p_get_i2c_tuner);
+
+int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+       u16 en_cur_state;
+
+       dprintk("sleep dib8096p: %d", onoff);
+
+       en_cur_state = dib8000_read_word(state, 1922);
+
+       /* LNAs and MIX are ON and therefore it is a valid configuration */
+       if (en_cur_state > 0xff)
+               state->tuner_enable = en_cur_state ;
+
+       if (onoff)
+               en_cur_state &= 0x00ff;
+       else {
+               if (state->tuner_enable != 0)
+                       en_cur_state = state->tuner_enable;
+       }
+
+       dib8000_write_word(state, 1922, en_cur_state);
+
+       return 0;
+}
+EXPORT_SYMBOL(dib8096p_tuner_sleep);
+
 static const s32 lut_1000ln_mant[] =
 {
        908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
@@ -1051,6 +1815,26 @@ s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
 }
 EXPORT_SYMBOL(dib8000_get_adc_power);
 
+int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+       int val = 0;
+
+       switch (IQ) {
+       case 1:
+                       val = dib8000_read_word(state, 403);
+                       break;
+       case 0:
+                       val = dib8000_read_word(state, 404);
+                       break;
+       }
+       if (val  & 0x200)
+               val -= 1024;
+
+       return val;
+}
+EXPORT_SYMBOL(dib8090p_get_dc_power);
+
 static void dib8000_update_timf(struct dib8000_state *state)
 {
        u32 timf = state->timf = dib8000_read32(state, 435);
@@ -1060,6 +1844,26 @@ static void dib8000_update_timf(struct dib8000_state *state)
        dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
 }
 
+u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+
+       switch (op) {
+       case DEMOD_TIMF_SET:
+                       state->timf = timf;
+                       break;
+       case DEMOD_TIMF_UPDATE:
+                       dib8000_update_timf(state);
+                       break;
+       case DEMOD_TIMF_GET:
+                       break;
+       }
+       dib8000_set_bandwidth(state->fe[0], 6000);
+
+       return state->timf;
+}
+EXPORT_SYMBOL(dib8000_ctrl_timf);
+
 static const u16 adc_target_16dB[11] = {
        (1 << 13) - 825 - 117,
        (1 << 13) - 837 - 117,
@@ -1086,6 +1890,9 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
        u16 init_prbs = 0xfff;
        u16 ana_gain = 0;
 
+       if (state->revision == 0x8090)
+               dib8000_init_sdram(state);
+
        if (state->ber_monitored_layer != LAYER_ALL)
                dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
        else
@@ -1418,7 +2225,10 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
        dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask);
 
        state->differential_constellation = (seg_diff_mask != 0);
-       dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
+       if (state->revision != 0x8090)
+               dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
+       else
+               dib8096p_set_diversity_in(state->fe[0], state->diversity_onoff);
 
        if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
                if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
@@ -1870,7 +2680,7 @@ static int dib8000_tune(struct dvb_frontend *fe)
 {
        struct dib8000_state *state = fe->demodulator_priv;
        int ret = 0;
-       u16 value, mode = fft_to_mode(state);
+       u16 lock, value, mode = fft_to_mode(state);
 
        // we are already tuned - just resuming from suspend
        if (state == NULL)
@@ -1924,7 +2734,11 @@ static int dib8000_tune(struct dvb_frontend *fe)
        }
 
        // we achieved a coff_cpil_lock - it's time to update the timf
-       if ((dib8000_read_word(state, 568) >> 11) & 0x1)
+       if (state->revision != 0x8090)
+               lock = dib8000_read_word(state, 568);
+       else
+               lock = dib8000_read_word(state, 570);
+       if ((lock >> 11) & 0x1)
                dib8000_update_timf(state);
 
        //now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start
@@ -1946,11 +2760,14 @@ static int dib8000_wakeup(struct dvb_frontend *fe)
        u8 index_frontend;
        int ret;
 
-       dib8000_set_power_mode(state, DIB8000M_POWER_ALL);
+       dib8000_set_power_mode(state, DIB8000_POWER_ALL);
        dib8000_set_adc_state(state, DIBX000_ADC_ON);
        if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
                dprintk("could not start Slow ADC");
 
+       if (state->revision != 0x8090)
+               dib8000_sad_calib(state);
+
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
                ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
                if (ret < 0)
@@ -1972,8 +2789,9 @@ static int dib8000_sleep(struct dvb_frontend *fe)
                        return ret;
        }
 
-       dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
-       dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);
+       if (state->revision != 0x8090)
+               dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
+       dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
        return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
 }
 
@@ -1992,7 +2810,7 @@ int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tun
 }
 EXPORT_SYMBOL(dib8000_set_tune_state);
 
-static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib8000_get_frontend(struct dvb_frontend *fe)
 {
        struct dib8000_state *state = fe->demodulator_priv;
        u16 i, val = 0;
@@ -2006,7 +2824,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
                if (stat&FE_HAS_SYNC) {
                        dprintk("TMCC lock on the slave%i", index_frontend);
                        /* synchronize the cache with the other frontends */
-                       state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep);
+                       state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
                        for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
                                if (sub_index_frontend != index_frontend) {
                                        state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
@@ -2028,7 +2846,10 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
 
        fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
 
-       val = dib8000_read_word(state, 570);
+       if (state->revision == 0x8090)
+               val = dib8000_read_word(state, 572);
+       else
+               val = dib8000_read_word(state, 570);
        fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
        switch ((val & 0x30) >> 4) {
        case 1:
@@ -2135,7 +2956,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
        return 0;
 }
 
-static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib8000_set_frontend(struct dvb_frontend *fe)
 {
        struct dib8000_state *state = fe->demodulator_priv;
        u8 nbr_pending, exit_condition, index_frontend;
@@ -2158,9 +2979,14 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
                state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
                memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
 
-               dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z);
+               if (state->revision != 0x8090)
+                       dib8000_set_output_mode(state->fe[index_frontend],
+                                       OUTMODE_HIGH_Z);
+               else
+                       dib8096p_set_output_mode(state->fe[index_frontend],
+                                       OUTMODE_HIGH_Z);
                if (state->fe[index_frontend]->ops.tuner_ops.set_params)
-                       state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend], fep);
+                       state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
 
                dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
        }
@@ -2215,7 +3041,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
                         ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||
                          ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
                         ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) {
-               int i = 80000;
+               int i = 100;
                u8 found = 0;
                u8 tune_failed = 0;
 
@@ -2243,6 +3069,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
                                        default:
                                                 dprintk("unhandled autosearch result");
                                        case 1:
+                                                tune_failed |= (1 << index_frontend);
                                                 dprintk("autosearch failed for the frontend%i", index_frontend);
                                                 break;
                                        }
@@ -2261,21 +3088,44 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
 
                dprintk("tune success on frontend%i", index_frontend_success);
 
-               dib8000_get_frontend(fe, fep);
+               dib8000_get_frontend(fe);
        }
 
        for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
                ret = dib8000_tune(state->fe[index_frontend]);
 
        /* set output mode and diversity input */
-       dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
-       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-               dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY);
-               dib8000_set_diversity_in(state->fe[index_frontend-1], 1);
-       }
+       if (state->revision != 0x8090) {
+               dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
+               for (index_frontend = 1;
+                               (index_frontend < MAX_NUMBER_OF_FRONTENDS) &&
+                               (state->fe[index_frontend] != NULL);
+                               index_frontend++) {
+                       dib8000_set_output_mode(state->fe[index_frontend],
+                                       OUTMODE_DIVERSITY);
+                       dib8000_set_diversity_in(state->fe[index_frontend-1], 1);
+               }
 
-       /* turn off the diversity of the last chip */
-       dib8000_set_diversity_in(state->fe[index_frontend-1], 0);
+               /* turn off the diversity of the last chip */
+               dib8000_set_diversity_in(state->fe[index_frontend-1], 0);
+       } else {
+               dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
+               if (state->cfg.enMpegOutput == 0) {
+                       dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
+                       dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
+               }
+               for (index_frontend = 1;
+                               (index_frontend < MAX_NUMBER_OF_FRONTENDS) &&
+                               (state->fe[index_frontend] != NULL);
+                               index_frontend++) {
+                       dib8096p_set_output_mode(state->fe[index_frontend],
+                                       OUTMODE_DIVERSITY);
+                       dib8096p_set_diversity_in(state->fe[index_frontend-1], 1);
+               }
+
+               /* turn off the diversity of the last chip */
+               dib8096p_set_diversity_in(state->fe[index_frontend-1], 0);
+       }
 
        return ret;
 }
@@ -2284,15 +3134,22 @@ static u16 dib8000_read_lock(struct dvb_frontend *fe)
 {
        struct dib8000_state *state = fe->demodulator_priv;
 
+       if (state->revision == 0x8090)
+               return dib8000_read_word(state, 570);
        return dib8000_read_word(state, 568);
 }
 
 static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
 {
        struct dib8000_state *state = fe->demodulator_priv;
-       u16 lock_slave = 0, lock = dib8000_read_word(state, 568);
+       u16 lock_slave = 0, lock;
        u8 index_frontend;
 
+       if (state->revision == 0x8090)
+               lock = dib8000_read_word(state, 570);
+       else
+               lock = dib8000_read_word(state, 568);
+
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
                lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
 
@@ -2330,14 +3187,26 @@ static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
 static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
 {
        struct dib8000_state *state = fe->demodulator_priv;
-       *ber = (dib8000_read_word(state, 560) << 16) | dib8000_read_word(state, 561);   // 13 segments
+
+       /* 13 segments */
+       if (state->revision == 0x8090)
+               *ber = (dib8000_read_word(state, 562) << 16) |
+                       dib8000_read_word(state, 563);
+       else
+               *ber = (dib8000_read_word(state, 560) << 16) |
+                       dib8000_read_word(state, 561);
        return 0;
 }
 
 static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
 {
        struct dib8000_state *state = fe->demodulator_priv;
-       *unc = dib8000_read_word(state, 565);   // packet error on 13 seg
+
+       /* packet error on 13 seg */
+       if (state->revision == 0x8090)
+               *unc = dib8000_read_word(state, 567);
+       else
+               *unc = dib8000_read_word(state, 565);
        return 0;
 }
 
@@ -2370,14 +3239,20 @@ static u32 dib8000_get_snr(struct dvb_frontend *fe)
        u32 n, s, exp;
        u16 val;
 
-       val = dib8000_read_word(state, 542);
+       if (state->revision != 0x8090)
+               val = dib8000_read_word(state, 542);
+       else
+               val = dib8000_read_word(state, 544);
        n = (val >> 6) & 0xff;
        exp = (val & 0x3f);
        if ((exp & 0x20) != 0)
                exp -= 0x40;
        n <<= exp+16;
 
-       val = dib8000_read_word(state, 543);
+       if (state->revision != 0x8090)
+               val = dib8000_read_word(state, 543);
+       else
+               val = dib8000_read_word(state, 545);
        s = (val >> 6) & 0xff;
        exp = (val & 0x3f);
        if ((exp & 0x20) != 0)
@@ -2401,7 +3276,7 @@ static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
                snr_master += dib8000_get_snr(state->fe[index_frontend]);
 
-       if (snr_master != 0) {
+       if ((snr_master >> 16) != 0) {
                snr_master = 10*intlog10(snr_master>>16);
                *snr = snr_master / ((1 << 24) / 10);
        }
@@ -2458,7 +3333,8 @@ struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int sla
 EXPORT_SYMBOL(dib8000_get_slave_frontend);
 
 
-int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
+int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
+               u8 default_addr, u8 first_addr, u8 is_dib8096p)
 {
        int k = 0, ret = 0;
        u8 new_addr = 0;
@@ -2488,9 +3364,12 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
                new_addr = first_addr + (k << 1);
 
                client.addr = new_addr;
-               dib8000_i2c_write16(&client, 1287, 0x0003);     /* sram lead in, rdy */
-               if (dib8000_identify(&client) == 0) {
+               if (!is_dib8096p)
                        dib8000_i2c_write16(&client, 1287, 0x0003);     /* sram lead in, rdy */
+               if (dib8000_identify(&client) == 0) {
+                       /* sram lead in, rdy */
+                       if (!is_dib8096p)
+                               dib8000_i2c_write16(&client, 1287, 0x0003);
                        client.addr = default_addr;
                        if (dib8000_identify(&client) == 0) {
                                dprintk("#%d: not identified", k);
@@ -2549,6 +3428,7 @@ static void dib8000_release(struct dvb_frontend *fe)
                dvb_frontend_detach(st->fe[index_frontend]);
 
        dibx000_exit_i2c_master(&st->i2c_master);
+       i2c_del_adapter(&st->dib8096p_tuner_adap);
        kfree(st->fe[0]);
        kfree(st);
 }
@@ -2581,9 +3461,9 @@ int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
 EXPORT_SYMBOL(dib8000_pid_filter);
 
 static const struct dvb_frontend_ops dib8000_ops = {
+       .delsys = { SYS_ISDBT },
        .info = {
                 .name = "DiBcom 8000 ISDB-T",
-                .type = FE_OFDM,
                 .frequency_min = 44250000,
                 .frequency_max = 867250000,
                 .frequency_stepsize = 62500,
@@ -2651,6 +3531,15 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s
 
        dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
 
+       /* init 8096p tuner adapter */
+       strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
+                       sizeof(state->dib8096p_tuner_adap.name));
+       state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
+       state->dib8096p_tuner_adap.algo_data = NULL;
+       state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
+       i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
+       i2c_add_adapter(&state->dib8096p_tuner_adap);
+
        dib8000_reset(fe);
 
        dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));     /* ber_rs_len = 3 */
index 617f9eba3a0967787eaa49b7da18f08d61473725..39591bb172c1e0fa4fed5a349e736bba221c3d4a 100644 (file)
@@ -32,6 +32,7 @@ struct dib8000_config {
        u8 div_cfg;
        u8 output_mode;
        u8 refclksel;
+       u8 enMpegOutput:1;
 };
 
 #define DEFAULT_DIB8000_I2C_ADDRESS 18
@@ -40,7 +41,8 @@ struct dib8000_config {
 extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg);
 extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
 
-extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr);
+extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
+               u8 default_addr, u8 first_addr, u8 is_dib8096p);
 
 extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
 extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value);
@@ -50,6 +52,13 @@ extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_st
 extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe);
 extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe);
 extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode);
+extern struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe);
+extern int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff);
+extern int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ);
+extern u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
+               uint8_t op, uint32_t timf);
+extern int dib8000_update_pll(struct dvb_frontend *fe,
+               struct dibx000_bandwidth_config *pll);
 extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
 extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe);
 extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index);
@@ -66,7 +75,9 @@ static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe
        return NULL;
 }
 
-static inline int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
+static inline int dib8000_i2c_enumeration(struct i2c_adapter *host,
+               int no_of_demods, u8 default_addr, u8 first_addr,
+               u8 is_dib8096p)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return -ENODEV;
@@ -109,11 +120,38 @@ static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 }
+static inline struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+static inline int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return 0;
+}
 static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return 0;
 }
+static inline int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return 0;
+}
+static inline u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
+               uint8_t op, uint32_t timf)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return 0;
+}
+static inline int dib8000_update_pll(struct dvb_frontend *fe,
+               struct dibx000_bandwidth_config *pll)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
 static inline int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
index 660f80661ed48f5af1eb21c5e584e9d89f3a592f..863ef3cfab9f908b59c195a77960c7bb779b120c 100644 (file)
@@ -1136,7 +1136,7 @@ static int dib9000_fw_init(struct dib9000_state *state)
        return 0;
 }
 
-static void dib9000_fw_set_channel_head(struct dib9000_state *state, struct dvb_frontend_parameters *ch)
+static void dib9000_fw_set_channel_head(struct dib9000_state *state)
 {
        u8 b[9];
        u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000;
@@ -1157,7 +1157,7 @@ static void dib9000_fw_set_channel_head(struct dib9000_state *state, struct dvb_
        dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b);
 }
 
-static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel)
+static int dib9000_fw_get_channel(struct dvb_frontend *fe)
 {
        struct dib9000_state *state = fe->demodulator_priv;
        struct dibDVBTChannel {
@@ -1309,7 +1309,7 @@ error:
        return ret;
 }
 
-static int dib9000_fw_set_channel_union(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel)
+static int dib9000_fw_set_channel_union(struct dvb_frontend *fe)
 {
        struct dib9000_state *state = fe->demodulator_priv;
        struct dibDVBTChannel {
@@ -1454,7 +1454,7 @@ static int dib9000_fw_set_channel_union(struct dvb_frontend *fe, struct dvb_fron
        return 0;
 }
 
-static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+static int dib9000_fw_tune(struct dvb_frontend *fe)
 {
        struct dib9000_state *state = fe->demodulator_priv;
        int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN;
@@ -1462,7 +1462,7 @@ static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_paramete
 
        switch (state->tune_state) {
        case CT_DEMOD_START:
-               dib9000_fw_set_channel_head(state, ch);
+               dib9000_fw_set_channel_head(state);
 
                /* write the channel context - a channel is initialized to 0, so it is OK */
                dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info);
@@ -1471,7 +1471,7 @@ static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_paramete
                if (search)
                        dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0);
                else {
-                       dib9000_fw_set_channel_union(fe, ch);
+                       dib9000_fw_set_channel_union(fe);
                        dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0);
                }
                state->tune_state = CT_DEMOD_STEP_1;
@@ -1867,7 +1867,7 @@ static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_fron
        return 0;
 }
 
-static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib9000_get_frontend(struct dvb_frontend *fe)
 {
        struct dib9000_state *state = fe->demodulator_priv;
        u8 index_frontend, sub_index_frontend;
@@ -1883,7 +1883,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
                        dprintk("TPS lock on the slave%i", index_frontend);
 
                        /* synchronize the cache with the other frontends */
-                       state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep);
+                       state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
                        for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL);
                             sub_index_frontend++) {
                                if (sub_index_frontend != index_frontend) {
@@ -1911,7 +1911,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
        }
 
        /* get the channel from master chip */
-       ret = dib9000_fw_get_channel(fe, fep);
+       ret = dib9000_fw_get_channel(fe);
        if (ret != 0)
                goto return_value;
 
@@ -1958,7 +1958,7 @@ static int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_fronte
        return 0;
 }
 
-static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int dib9000_set_frontend(struct dvb_frontend *fe)
 {
        struct dib9000_state *state = fe->demodulator_priv;
        int sleep_time, sleep_time_slave;
@@ -1983,8 +1983,10 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
        fe->dtv_property_cache.delivery_system = SYS_DVBT;
 
        /* set the master status */
-       if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
-           fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) {
+       if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO ||
+           state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO ||
+           state->fe[0]->dtv_property_cache.modulation == QAM_AUTO ||
+           state->fe[0]->dtv_property_cache.code_rate_HP == FEC_AUTO) {
                /* no channel specified, autosearch the channel */
                state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN;
        } else
@@ -2008,9 +2010,9 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
        exit_condition = 0;     /* 0: tune pending; 1: tune failed; 2:tune success */
        index_frontend_success = 0;
        do {
-               sleep_time = dib9000_fw_tune(state->fe[0], NULL);
+               sleep_time = dib9000_fw_tune(state->fe[0]);
                for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
-                       sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL);
+                       sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]);
                        if (sleep_time == FE_CALLBACK_TIME_NEVER)
                                sleep_time = sleep_time_slave;
                        else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
@@ -2052,7 +2054,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
 
        /* synchronize all the channel cache */
        state->get_frontend_internal = 1;
-       dib9000_get_frontend(state->fe[0], fep);
+       dib9000_get_frontend(state->fe[0]);
        state->get_frontend_internal = 0;
 
        /* retune the other frontends with the found channel */
@@ -2068,7 +2070,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
                sleep_time = FE_CALLBACK_TIME_NEVER;
                for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
                        if (index_frontend != index_frontend_success) {
-                               sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL);
+                               sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]);
                                if (sleep_time == FE_CALLBACK_TIME_NEVER)
                                        sleep_time = sleep_time_slave;
                                else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
@@ -2495,9 +2497,9 @@ error:
 EXPORT_SYMBOL(dib9000_attach);
 
 static struct dvb_frontend_ops dib9000_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                 .name = "DiBcom 9000",
-                .type = FE_OFDM,
                 .frequency_min = 44250000,
                 .frequency_max = 867250000,
                 .frequency_stepsize = 62500,
index 5e011474be430658b1b13d283bd2f7e11d5c2ca6..5f484881d7b1d07735af0cb4bf7219c441e74ac7 100644 (file)
@@ -146,14 +146,8 @@ enum dibx000_adc_states {
        DIBX000_VBG_DISABLE,
 };
 
-#define BANDWIDTH_TO_KHZ(v) ((v) == BANDWIDTH_8_MHZ  ? 8000 : \
-                               (v) == BANDWIDTH_7_MHZ  ? 7000 : \
-                               (v) == BANDWIDTH_6_MHZ  ? 6000 : 8000)
-
-#define BANDWIDTH_TO_INDEX(v) ( \
-       (v) == 8000 ? BANDWIDTH_8_MHZ : \
-               (v) == 7000 ? BANDWIDTH_7_MHZ : \
-               (v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ )
+#define BANDWIDTH_TO_KHZ(v)    ((v) / 1000)
+#define BANDWIDTH_TO_HZ(v)     ((v) * 1000)
 
 /* Chip output mode. */
 #define OUTMODE_HIGH_Z              0
@@ -276,4 +270,11 @@ struct dibSubbandSelection {
 #define DEMOD_TIMF_GET    0x01
 #define DEMOD_TIMF_UPDATE 0x02
 
+#define MPEG_ON_DIBTX          1
+#define DIV_ON_DIBTX           2
+#define ADC_ON_DIBTX           3
+#define DEMOUT_ON_HOSTBUS      4
+#define DIBTX_ON_HOSTBUS       5
+#define MPEG_ON_HOSTBUS                6
+
 #endif
index 7113535844f2304f58e24571f538b9a71528cfb9..34398738f9bcc42fce6352db66966a2557f22b64 100644 (file)
@@ -48,8 +48,6 @@ struct drxd_config {
        u8 disable_i2c_gate_ctrl;
 
        u32 IF;
-       int (*pll_set) (void *priv, void *priv_params,
-                       u8 pll_addr, u8 demoda_addr, s32 *off);
         s16(*osc_deviation) (void *priv, s16 dev, int flag);
 };
 
index 88e46f4cdbb26c77a14fbeef942fb6df3682fa4f..7bf39cda83c55ef8305a72e5ca9a571db9d86e8b 100644 (file)
@@ -120,7 +120,7 @@ enum EIFFilter {
 struct drxd_state {
        struct dvb_frontend frontend;
        struct dvb_frontend_ops ops;
-       struct dvb_frontend_parameters param;
+       struct dtv_frontend_properties props;
 
        const struct firmware *fw;
        struct device *dev;
@@ -914,14 +914,13 @@ static int load_firmware(struct drxd_state *state, const char *fw_name)
                return -EIO;
        }
 
-       state->microcode = kmalloc(fw->size, GFP_KERNEL);
+       state->microcode = kmemdup(fw->data, fw->size, GFP_KERNEL);
        if (state->microcode == NULL) {
                release_firmware(fw);
                printk(KERN_ERR "drxd: firmware load failure: no memory\n");
                return -ENOMEM;
        }
 
-       memcpy(state->microcode, fw->data, fw->size);
        state->microcode_length = fw->size;
        release_firmware(fw);
        return 0;
@@ -1622,14 +1621,14 @@ static int CorrectSysClockDeviation(struct drxd_state *state)
                                break;
                }
 
-               switch (state->param.u.ofdm.bandwidth) {
-               case BANDWIDTH_8_MHZ:
+               switch (state->props.bandwidth_hz) {
+               case 8000000:
                        bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
                        break;
-               case BANDWIDTH_7_MHZ:
+               case 7000000:
                        bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
                        break;
-               case BANDWIDTH_6_MHZ:
+               case 6000000:
                        bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
                        break;
                default:
@@ -1804,7 +1803,7 @@ static int StartDiversity(struct drxd_state *state)
                        status = WriteTable(state, state->m_StartDiversityEnd);
                        if (status < 0)
                                break;
-                       if (state->param.u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
+                       if (state->props.bandwidth_hz == 8000000) {
                                status = WriteTable(state, state->m_DiversityDelay8MHZ);
                                if (status < 0)
                                        break;
@@ -1906,7 +1905,7 @@ static int SetCfgNoiseCalibration(struct drxd_state *state,
 
 static int DRX_Start(struct drxd_state *state, s32 off)
 {
-       struct dvb_ofdm_parameters *p = &state->param.u.ofdm;
+       struct dtv_frontend_properties *p = &state->props;
        int status;
 
        u16 transmissionParams = 0;
@@ -1971,7 +1970,7 @@ static int DRX_Start(struct drxd_state *state, s32 off)
                if (status < 0)
                        break;
 
-               mirrorFreqSpect = (state->param.inversion == INVERSION_ON);
+               mirrorFreqSpect = (state->props.inversion == INVERSION_ON);
 
                switch (p->transmission_mode) {
                default:        /* Not set, detect it automatically */
@@ -2021,7 +2020,7 @@ static int DRX_Start(struct drxd_state *state, s32 off)
                        break;
                }
 
-               switch (p->hierarchy_information) {
+               switch (p->hierarchy) {
                case HIERARCHY_1:
                        transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A1;
                        if (state->type_A) {
@@ -2147,7 +2146,7 @@ static int DRX_Start(struct drxd_state *state, s32 off)
                if (status < 0)
                        break;
 
-               switch (p->constellation) {
+               switch (p->modulation) {
                default:
                        operationMode |= SC_RA_RAM_OP_AUTO_CONST__M;
                        /* fall through , try first guess
@@ -2331,9 +2330,11 @@ static int DRX_Start(struct drxd_state *state, s32 off)
                   by SC for fix for some 8K,1/8 guard but is restored by
                   InitEC and ResetEC
                   functions */
-               switch (p->bandwidth) {
-               case BANDWIDTH_AUTO:
-               case BANDWIDTH_8_MHZ:
+               switch (p->bandwidth_hz) {
+               case 0:
+                       p->bandwidth_hz = 8000000;
+                       /* fall through */
+               case 8000000:
                        /* (64/7)*(8/8)*1000000 */
                        bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
 
@@ -2341,14 +2342,14 @@ static int DRX_Start(struct drxd_state *state, s32 off)
                        status = Write16(state,
                                         FE_AG_REG_IND_DEL__A, 50, 0x0000);
                        break;
-               case BANDWIDTH_7_MHZ:
+               case 7000000:
                        /* (64/7)*(7/8)*1000000 */
                        bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
                        bandwidthParam = 0x4807;        /*binary:0100 1000 0000 0111 */
                        status = Write16(state,
                                         FE_AG_REG_IND_DEL__A, 59, 0x0000);
                        break;
-               case BANDWIDTH_6_MHZ:
+               case 6000000:
                        /* (64/7)*(6/8)*1000000 */
                        bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
                        bandwidthParam = 0x0F07;        /*binary: 0000 1111 0000 0111 */
@@ -2887,41 +2888,26 @@ static int drxd_sleep(struct dvb_frontend *fe)
        return 0;
 }
 
-static int drxd_get_frontend(struct dvb_frontend *fe,
-                            struct dvb_frontend_parameters *param)
-{
-       return 0;
-}
-
 static int drxd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
        return drxd_config_i2c(fe, enable);
 }
 
-static int drxd_set_frontend(struct dvb_frontend *fe,
-                            struct dvb_frontend_parameters *param)
+static int drxd_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct drxd_state *state = fe->demodulator_priv;
        s32 off = 0;
 
-       state->param = *param;
+       state->props = *p;
        DRX_Stop(state);
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, param);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
-       /* FIXME: move PLL drivers */
-       if (state->config.pll_set &&
-           state->config.pll_set(state->priv, param,
-                                 state->config.pll_address,
-                                 state->config.demoda_address, &off) < 0) {
-               printk(KERN_ERR "Error in pll_set\n");
-               return -1;
-       }
-
        msleep(200);
 
        return DRX_Start(state, off);
@@ -2935,10 +2921,9 @@ static void drxd_release(struct dvb_frontend *fe)
 }
 
 static struct dvb_frontend_ops drxd_ops = {
-
+       .delsys = { SYS_DVBT},
        .info = {
                 .name = "Micronas DRXD DVB-T",
-                .type = FE_OFDM,
                 .frequency_min = 47125000,
                 .frequency_max = 855250000,
                 .frequency_stepsize = 166667,
@@ -2958,7 +2943,6 @@ static struct dvb_frontend_ops drxd_ops = {
        .i2c_gate_ctrl = drxd_i2c_gate_ctrl,
 
        .set_frontend = drxd_set_frontend,
-       .get_frontend = drxd_get_frontend,
        .get_tune_settings = drxd_get_tune_settings,
 
        .read_status = drxd_read_status,
index 58baf419560cedb55f11ca5b788cbcd9eff77069..020981844a86940c8e2cbe0f5ca0d45cff989048 100644 (file)
@@ -8,6 +8,8 @@
  * struct drxk_config - Configure the initial parameters for DRX-K
  *
  * adr:                        I2C Address of the DRX-K
+ * parallel_ts:                true means that the device uses parallel TS,
+ *                     Serial otherwise.
  * single_master:      Device is on the single master mode
  * no_i2c_bridge:      Don't switch the I2C bridge to talk with tuner
  * antenna_gpio:       GPIO bit used to control the antenna
@@ -22,22 +24,23 @@ struct drxk_config {
        u8      adr;
        bool    single_master;
        bool    no_i2c_bridge;
+       bool    parallel_ts;
 
        bool    antenna_dvbt;
        u16     antenna_gpio;
 
+       int    chunk_size;
+
        const char *microcode_name;
 };
 
 #if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \
         && defined(MODULE))
 extern struct dvb_frontend *drxk_attach(const struct drxk_config *config,
-                                       struct i2c_adapter *i2c,
-                                       struct dvb_frontend **fe_t);
+                                       struct i2c_adapter *i2c);
 #else
 static inline struct dvb_frontend *drxk_attach(const struct drxk_config *config,
-                                       struct i2c_adapter *i2c,
-                                       struct dvb_frontend **fe_t)
+                                       struct i2c_adapter *i2c)
 {
         printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
         return NULL;
index f6431ef827dc1f86e6b4748ae08c5edb141919ff..6980ed7b8786b6048b5e4271db0f7758bb277204 100644 (file)
@@ -368,10 +368,10 @@ static int i2c_read(struct i2c_adapter *adap,
        }
        if (debug > 2) {
                int i;
-               dprintk(2, ": read from ");
+               dprintk(2, ": read from");
                for (i = 0; i < len; i++)
                        printk(KERN_CONT " %02x", msg[i]);
-               printk(KERN_CONT "Value = ");
+               printk(KERN_CONT ", value = ");
                for (i = 0; i < alen; i++)
                        printk(KERN_CONT " %02x", answ[i]);
                printk(KERN_CONT "\n");
@@ -660,7 +660,6 @@ static int init_state(struct drxk_state *state)
        /* io_pad_cfg_mode output mode is drive always */
        /* io_pad_cfg_drive is set to power 2 (23 mA) */
        u32 ulGPIOCfg = 0x0113;
-       u32 ulSerialMode = 1;
        u32 ulInvertTSClock = 0;
        u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH;
        u32 ulTSClockkStrength = DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH;
@@ -681,7 +680,8 @@ static int init_state(struct drxk_state *state)
        state->m_hasOOB = false;
        state->m_hasAudio = false;
 
-       state->m_ChunkSize = 124;
+       if (!state->m_ChunkSize)
+               state->m_ChunkSize = 124;
 
        state->m_oscClockFreq = 0;
        state->m_smartAntInverted = false;
@@ -810,8 +810,6 @@ static int init_state(struct drxk_state *state)
        /* MPEG output configuration */
        state->m_enableMPEGOutput = true;       /* If TRUE; enable MPEG ouput */
        state->m_insertRSByte = false;  /* If TRUE; insert RS byte */
-       state->m_enableParallel = true; /* If TRUE;
-                                          parallel out otherwise serial */
        state->m_invertDATA = false;    /* If TRUE; invert DATA signals */
        state->m_invertERR = false;     /* If TRUE; invert ERR signal */
        state->m_invertSTR = false;     /* If TRUE; invert STR signals */
@@ -856,8 +854,6 @@ static int init_state(struct drxk_state *state)
        state->m_bPowerDown = false;
        state->m_currentPowerMode = DRX_POWER_DOWN;
 
-       state->m_enableParallel = (ulSerialMode == 0);
-
        state->m_rfmirror = (ulRfMirror == 0);
        state->m_IfAgcPol = false;
        return 0;
@@ -946,6 +942,9 @@ static int GetDeviceCapabilities(struct drxk_state *state)
        status = read32(state, SIO_TOP_JTAGID_LO__A, &sioTopJtagidLo);
        if (status < 0)
                goto error;
+
+printk(KERN_ERR "drxk: status = 0x%08x\n", sioTopJtagidLo);
+
        /* driver 0.9.0 */
        switch ((sioTopJtagidLo >> 29) & 0xF) {
        case 0:
@@ -963,7 +962,8 @@ static int GetDeviceCapabilities(struct drxk_state *state)
        default:
                state->m_deviceSpin = DRXK_SPIN_UNKNOWN;
                status = -EINVAL;
-               printk(KERN_ERR "drxk: Spin unknown\n");
+               printk(KERN_ERR "drxk: Spin %d unknown\n",
+                      (sioTopJtagidLo >> 29) & 0xF);
                goto error2;
        }
        switch ((sioTopJtagidLo >> 12) & 0xFF) {
@@ -1190,7 +1190,9 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
        u16 sioPdrMclkCfg = 0;
        u16 sioPdrMdxCfg = 0;
 
-       dprintk(1, "\n");
+       dprintk(1, ": mpeg %s, %s mode\n",
+               mpegEnable ? "enable" : "disable",
+               state->m_enableParallel ? "parallel" : "serial");
 
        /* stop lock indicator process */
        status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
@@ -1846,6 +1848,7 @@ static int SetOperationMode(struct drxk_state *state,
                */
        switch (oMode) {
        case OM_DVBT:
+               dprintk(1, ": DVB-T\n");
                state->m_OperationMode = oMode;
                status = SetDVBTStandard(state, oMode);
                if (status < 0)
@@ -1853,6 +1856,8 @@ static int SetOperationMode(struct drxk_state *state,
                break;
        case OM_QAM_ITU_A:      /* fallthrough */
        case OM_QAM_ITU_C:
+               dprintk(1, ": DVB-C Annex %c\n",
+                       (state->m_OperationMode == OM_QAM_ITU_A) ? 'A' : 'C');
                state->m_OperationMode = oMode;
                status = SetQAMStandard(state, oMode);
                if (status < 0)
@@ -1881,7 +1886,7 @@ static int Start(struct drxk_state *state, s32 offsetFreq,
                state->m_DrxkState != DRXK_DTV_STARTED)
                goto error;
 
-       state->m_bMirrorFreqSpect = (state->param.inversion == INVERSION_ON);
+       state->m_bMirrorFreqSpect = (state->props.inversion == INVERSION_ON);
 
        if (IntermediateFrequency < 0) {
                state->m_bMirrorFreqSpect = !state->m_bMirrorFreqSpect;
@@ -2503,7 +2508,7 @@ static int GetQAMSignalToNoise(struct drxk_state *state,
        u16 qamSlErrPower = 0;  /* accum. error between
                                        raw and sliced symbols */
        u32 qamSlSigPower = 0;  /* used for MER, depends of
-                                       QAM constellation */
+                                       QAM modulation */
        u32 qamSlMer = 0;       /* QAM MER */
 
        dprintk(1, "\n");
@@ -2517,7 +2522,7 @@ static int GetQAMSignalToNoise(struct drxk_state *state,
                return -EINVAL;
        }
 
-       switch (state->param.u.qam.modulation) {
+       switch (state->props.modulation) {
        case QAM_16:
                qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM16 << 2;
                break;
@@ -2748,7 +2753,7 @@ static int GetDVBCQuality(struct drxk_state *state, s32 *pQuality)
                if (status < 0)
                        break;
 
-               switch (state->param.u.qam.modulation) {
+               switch (state->props.modulation) {
                case QAM_16:
                        SignalToNoiseRel = SignalToNoise - 200;
                        break;
@@ -3813,7 +3818,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
        /*== Write channel settings to device =====================================*/
 
        /* mode */
-       switch (state->param.u.ofdm.transmission_mode) {
+       switch (state->props.transmission_mode) {
        case TRANSMISSION_MODE_AUTO:
        default:
                operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M;
@@ -3827,7 +3832,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
        }
 
        /* guard */
-       switch (state->param.u.ofdm.guard_interval) {
+       switch (state->props.guard_interval) {
        default:
        case GUARD_INTERVAL_AUTO:
                operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M;
@@ -3847,7 +3852,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
        }
 
        /* hierarchy */
-       switch (state->param.u.ofdm.hierarchy_information) {
+       switch (state->props.hierarchy) {
        case HIERARCHY_AUTO:
        case HIERARCHY_NONE:
        default:
@@ -3867,8 +3872,8 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
        }
 
 
-       /* constellation */
-       switch (state->param.u.ofdm.constellation) {
+       /* modulation */
+       switch (state->props.modulation) {
        case QAM_AUTO:
        default:
                operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M;
@@ -3911,7 +3916,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
 #endif
 
        /* coderate */
-       switch (state->param.u.ofdm.code_rate_HP) {
+       switch (state->props.code_rate_HP) {
        case FEC_AUTO:
        default:
                operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M;
@@ -3940,9 +3945,11 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
        /* Also set parameters for EC_OC fix, note EC_OC_REG_TMD_HIL_MAR is changed
                by SC for fix for some 8K,1/8 guard but is restored by InitEC and ResetEC
                functions */
-       switch (state->param.u.ofdm.bandwidth) {
-       case BANDWIDTH_AUTO:
-       case BANDWIDTH_8_MHZ:
+       switch (state->props.bandwidth_hz) {
+       case 0:
+               state->props.bandwidth_hz = 8000000;
+               /* fall though */
+       case 8000000:
                bandwidth = DRXK_BANDWIDTH_8MHZ_IN_HZ;
                status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3052);
                if (status < 0)
@@ -3961,7 +3968,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
                if (status < 0)
                        goto error;
                break;
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                bandwidth = DRXK_BANDWIDTH_7MHZ_IN_HZ;
                status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3491);
                if (status < 0)
@@ -3980,7 +3987,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
                if (status < 0)
                        goto error;
                break;
-       case BANDWIDTH_6_MHZ:
+       case 6000000:
                bandwidth = DRXK_BANDWIDTH_6MHZ_IN_HZ;
                status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 4073);
                if (status < 0)
@@ -4187,7 +4194,7 @@ error:
 /**
 * \brief Setup of the QAM Measurement intervals for signal quality
 * \param demod instance of demod.
-* \param constellation current constellation.
+* \param modulation current modulation.
 * \return DRXStatus_t.
 *
 *  NOTE:
@@ -4196,7 +4203,7 @@ error:
 *
 */
 static int SetQAMMeasurement(struct drxk_state *state,
-                            enum EDrxkConstellation constellation,
+                            enum EDrxkConstellation modulation,
                             u32 symbolRate)
 {
        u32 fecBitsDesired = 0; /* BER accounting period */
@@ -4210,11 +4217,11 @@ static int SetQAMMeasurement(struct drxk_state *state,
        fecRsPrescale = 1;
        /* fecBitsDesired = symbolRate [kHz] *
                FrameLenght [ms] *
-               (constellation + 1) *
+               (modulation + 1) *
                SyncLoss (== 1) *
                ViterbiLoss (==1)
                */
-       switch (constellation) {
+       switch (modulation) {
        case DRX_CONSTELLATION_QAM16:
                fecBitsDesired = 4 * symbolRate;
                break;
@@ -5281,12 +5288,12 @@ static int QAMSetSymbolrate(struct drxk_state *state)
        /* Select & calculate correct IQM rate */
        adcFrequency = (state->m_sysClockFreq * 1000) / 3;
        ratesel = 0;
-       /* printk(KERN_DEBUG "drxk: SR %d\n", state->param.u.qam.symbol_rate); */
-       if (state->param.u.qam.symbol_rate <= 1188750)
+       /* printk(KERN_DEBUG "drxk: SR %d\n", state->props.symbol_rate); */
+       if (state->props.symbol_rate <= 1188750)
                ratesel = 3;
-       else if (state->param.u.qam.symbol_rate <= 2377500)
+       else if (state->props.symbol_rate <= 2377500)
                ratesel = 2;
-       else if (state->param.u.qam.symbol_rate <= 4755000)
+       else if (state->props.symbol_rate <= 4755000)
                ratesel = 1;
        status = write16(state, IQM_FD_RATESEL__A, ratesel);
        if (status < 0)
@@ -5295,7 +5302,7 @@ static int QAMSetSymbolrate(struct drxk_state *state)
        /*
                IqmRcRate = ((Fadc / (symbolrate * (4<<ratesel))) - 1) * (1<<23)
                */
-       symbFreq = state->param.u.qam.symbol_rate * (1 << ratesel);
+       symbFreq = state->props.symbol_rate * (1 << ratesel);
        if (symbFreq == 0) {
                /* Divide by zero */
                status = -EINVAL;
@@ -5311,7 +5318,7 @@ static int QAMSetSymbolrate(struct drxk_state *state)
        /*
                LcSymbFreq = round (.125 *  symbolrate / adcFreq * (1<<15))
                */
-       symbFreq = state->param.u.qam.symbol_rate;
+       symbFreq = state->props.symbol_rate;
        if (adcFrequency == 0) {
                /* Divide by zero */
                status = -EINVAL;
@@ -5412,7 +5419,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
                goto error;
 
        /* Set params */
-       switch (state->param.u.qam.modulation) {
+       switch (state->props.modulation) {
        case QAM_256:
                state->m_Constellation = DRX_CONSTELLATION_QAM256;
                break;
@@ -5435,7 +5442,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
        }
        if (status < 0)
                goto error;
-       setParamParameters[0] = state->m_Constellation; /* constellation     */
+       setParamParameters[0] = state->m_Constellation; /* modulation     */
        setParamParameters[1] = DRXK_QAM_I12_J17;       /* interleave mode   */
        if (state->m_OperationMode == OM_QAM_ITU_C)
                setParamParameters[2] = QAM_TOP_ANNEX_C;
@@ -5457,7 +5464,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
                if (status < 0)
                        goto error;
 
-               setParamParameters[0] = state->m_Constellation; /* constellation     */
+               setParamParameters[0] = state->m_Constellation; /* modulation     */
                setParamParameters[1] = DRXK_QAM_I12_J17;       /* interleave mode   */
                status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 2, setParamParameters, 1, &cmdResult);
        }
@@ -5466,7 +5473,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
 
        /*
         * STEP 3: enable the system in a mode where the ADC provides valid
-        * signal setup constellation independent registers
+        * signal setup modulation independent registers
         */
 #if 0
        status = SetFrequency(channel, tunerFreqOffset));
@@ -5478,7 +5485,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
                goto error;
 
        /* Setup BER measurement */
-       status = SetQAMMeasurement(state, state->m_Constellation, state->param.u. qam.symbol_rate);
+       status = SetQAMMeasurement(state, state->m_Constellation, state->props.symbol_rate);
        if (status < 0)
                goto error;
 
@@ -5560,8 +5567,8 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
        if (status < 0)
                goto error;
 
-       /* STEP 4: constellation specific setup */
-       switch (state->param.u.qam.modulation) {
+       /* STEP 4: modulation specific setup */
+       switch (state->props.modulation) {
        case QAM_16:
                status = SetQAM16(state);
                break;
@@ -5591,7 +5598,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
                goto error;
 
        /* Re-configure MPEG output, requires knowledge of channel bitrate */
-       /* extAttr->currentChannel.constellation = channel->constellation; */
+       /* extAttr->currentChannel.modulation = channel->modulation; */
        /* extAttr->currentChannel.symbolrate    = channel->symbolrate; */
        status = MPEGTSDtoSetup(state, state->m_OperationMode);
        if (status < 0)
@@ -6167,7 +6174,7 @@ error:
        return status;
 }
 
-static void drxk_c_release(struct dvb_frontend *fe)
+static void drxk_release(struct dvb_frontend *fe)
 {
        struct drxk_state *state = fe->demodulator_priv;
 
@@ -6175,24 +6182,12 @@ static void drxk_c_release(struct dvb_frontend *fe)
        kfree(state);
 }
 
-static int drxk_c_init(struct dvb_frontend *fe)
-{
-       struct drxk_state *state = fe->demodulator_priv;
-
-       dprintk(1, "\n");
-       if (mutex_trylock(&state->ctlock) == 0)
-               return -EBUSY;
-       SetOperationMode(state, OM_QAM_ITU_A);
-       return 0;
-}
-
-static int drxk_c_sleep(struct dvb_frontend *fe)
+static int drxk_sleep(struct dvb_frontend *fe)
 {
        struct drxk_state *state = fe->demodulator_priv;
 
        dprintk(1, "\n");
        ShutDown(state);
-       mutex_unlock(&state->ctlock);
        return 0;
 }
 
@@ -6204,9 +6199,10 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
        return ConfigureI2CBridge(state, enable ? true : false);
 }
 
-static int drxk_set_parameters(struct dvb_frontend *fe,
-                              struct dvb_frontend_parameters *p)
+static int drxk_set_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+       u32 delsys  = p->delivery_system, old_delsys;
        struct drxk_state *state = fe->demodulator_priv;
        u32 IF;
 
@@ -6218,14 +6214,39 @@ static int drxk_set_parameters(struct dvb_frontend *fe,
                return -EINVAL;
        }
 
-
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
        if (fe->ops.tuner_ops.set_params)
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0);
-       state->param = *p;
+
+       old_delsys = state->props.delivery_system;
+       state->props = *p;
+
+       if (old_delsys != delsys) {
+               ShutDown(state);
+               switch (delsys) {
+               case SYS_DVBC_ANNEX_A:
+               case SYS_DVBC_ANNEX_C:
+                       if (!state->m_hasDVBC)
+                               return -EINVAL;
+                       state->m_itut_annex_c = (delsys == SYS_DVBC_ANNEX_C) ? true : false;
+                       if (state->m_itut_annex_c)
+                               SetOperationMode(state, OM_QAM_ITU_C);
+                       else
+                               SetOperationMode(state, OM_QAM_ITU_A);
+                       break;
+               case SYS_DVBT:
+                       if (!state->m_hasDVBT)
+                               return -EINVAL;
+                       SetOperationMode(state, OM_DVBT);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
        fe->ops.tuner_ops.get_if_frequency(fe, &IF);
        Start(state, 0, IF);
 
@@ -6234,13 +6255,6 @@ static int drxk_set_parameters(struct dvb_frontend *fe,
        return 0;
 }
 
-static int drxk_c_get_frontend(struct dvb_frontend *fe,
-                              struct dvb_frontend_parameters *p)
-{
-       dprintk(1, "\n");
-       return 0;
-}
-
 static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
        struct drxk_state *state = fe->demodulator_priv;
@@ -6300,102 +6314,54 @@ static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
        return 0;
 }
 
-static int drxk_c_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings
+static int drxk_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings
                                    *sets)
 {
-       dprintk(1, "\n");
-       sets->min_delay_ms = 3000;
-       sets->max_drift = 0;
-       sets->step_size = 0;
-       return 0;
-}
-
-static void drxk_t_release(struct dvb_frontend *fe)
-{
-       /*
-        * There's nothing to release here, as the state struct
-        * is already freed by drxk_c_release.
-        */
-}
-
-static int drxk_t_init(struct dvb_frontend *fe)
-{
-       struct drxk_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 
        dprintk(1, "\n");
-       if (mutex_trylock(&state->ctlock) == 0)
-               return -EBUSY;
-       SetOperationMode(state, OM_DVBT);
-       return 0;
-}
-
-static int drxk_t_sleep(struct dvb_frontend *fe)
-{
-       struct drxk_state *state = fe->demodulator_priv;
-
-       dprintk(1, "\n");
-       mutex_unlock(&state->ctlock);
-       return 0;
-}
-
-static int drxk_t_get_frontend(struct dvb_frontend *fe,
-                              struct dvb_frontend_parameters *p)
-{
-       dprintk(1, "\n");
-
-       return 0;
+       switch (p->delivery_system) {
+       case SYS_DVBC_ANNEX_A:
+       case SYS_DVBC_ANNEX_C:
+               sets->min_delay_ms = 3000;
+               sets->max_drift = 0;
+               sets->step_size = 0;
+               return 0;
+       default:
+               /*
+                * For DVB-T, let it use the default DVB core way, that is:
+                *      fepriv->step_size = fe->ops.info.frequency_stepsize * 2
+                */
+               return -EINVAL;
+       }
 }
 
-static struct dvb_frontend_ops drxk_c_ops = {
+static struct dvb_frontend_ops drxk_ops = {
+       /* .delsys will be filled dynamically */
        .info = {
-                .name = "DRXK DVB-C",
-                .type = FE_QAM,
-                .frequency_stepsize = 62500,
-                .frequency_min = 47000000,
-                .frequency_max = 862000000,
-                .symbol_rate_min = 870000,
-                .symbol_rate_max = 11700000,
-                .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
-                FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO},
-       .release = drxk_c_release,
-       .init = drxk_c_init,
-       .sleep = drxk_c_sleep,
+               .name = "DRXK",
+               .frequency_min = 47000000,
+               .frequency_max = 865000000,
+                /* For DVB-C */
+               .symbol_rate_min = 870000,
+               .symbol_rate_max = 11700000,
+               /* For DVB-T */
+               .frequency_stepsize = 166667,
+
+               .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+                       FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO |
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_MUTE_TS |
+                       FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER |
+                       FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO
+       },
+
+       .release = drxk_release,
+       .sleep = drxk_sleep,
        .i2c_gate_ctrl = drxk_gate_ctrl,
 
        .set_frontend = drxk_set_parameters,
-       .get_frontend = drxk_c_get_frontend,
-       .get_tune_settings = drxk_c_get_tune_settings,
-
-       .read_status = drxk_read_status,
-       .read_ber = drxk_read_ber,
-       .read_signal_strength = drxk_read_signal_strength,
-       .read_snr = drxk_read_snr,
-       .read_ucblocks = drxk_read_ucblocks,
-};
-
-static struct dvb_frontend_ops drxk_t_ops = {
-       .info = {
-                .name = "DRXK DVB-T",
-                .type = FE_OFDM,
-                .frequency_min = 47125000,
-                .frequency_max = 865000000,
-                .frequency_stepsize = 166667,
-                .frequency_tolerance = 0,
-                .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
-                FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
-                FE_CAN_FEC_AUTO |
-                FE_CAN_QAM_16 | FE_CAN_QAM_64 |
-                FE_CAN_QAM_AUTO |
-                FE_CAN_TRANSMISSION_MODE_AUTO |
-                FE_CAN_GUARD_INTERVAL_AUTO |
-                FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS},
-       .release = drxk_t_release,
-       .init = drxk_t_init,
-       .sleep = drxk_t_sleep,
-       .i2c_gate_ctrl = drxk_gate_ctrl,
-
-       .set_frontend = drxk_set_parameters,
-       .get_frontend = drxk_t_get_frontend,
+       .get_tune_settings = drxk_get_tune_settings,
 
        .read_status = drxk_read_status,
        .read_ber = drxk_read_ber,
@@ -6405,9 +6371,10 @@ static struct dvb_frontend_ops drxk_t_ops = {
 };
 
 struct dvb_frontend *drxk_attach(const struct drxk_config *config,
-                                struct i2c_adapter *i2c,
-                                struct dvb_frontend **fe_t)
+                                struct i2c_adapter *i2c)
 {
+       int n;
+
        struct drxk_state *state = NULL;
        u8 adr = config->adr;
 
@@ -6423,6 +6390,12 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
        state->no_i2c_bridge = config->no_i2c_bridge;
        state->antenna_gpio = config->antenna_gpio;
        state->antenna_dvbt = config->antenna_dvbt;
+       state->m_ChunkSize = config->chunk_size;
+
+       if (config->parallel_ts)
+               state->m_enableParallel = true;
+       else
+               state->m_enableParallel = false;
 
        /* NOTE: as more UIO bits will be used, add them to the mask */
        state->UIO_mask = config->antenna_gpio;
@@ -6434,21 +6407,30 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
                state->m_GPIO &= ~state->antenna_gpio;
 
        mutex_init(&state->mutex);
-       mutex_init(&state->ctlock);
 
-       memcpy(&state->c_frontend.ops, &drxk_c_ops,
-              sizeof(struct dvb_frontend_ops));
-       memcpy(&state->t_frontend.ops, &drxk_t_ops,
-              sizeof(struct dvb_frontend_ops));
-       state->c_frontend.demodulator_priv = state;
-       state->t_frontend.demodulator_priv = state;
+       memcpy(&state->frontend.ops, &drxk_ops, sizeof(drxk_ops));
+       state->frontend.demodulator_priv = state;
 
        init_state(state);
        if (init_drxk(state) < 0)
                goto error;
-       *fe_t = &state->t_frontend;
 
-       return &state->c_frontend;
+       /* Initialize the supported delivery systems */
+       n = 0;
+       if (state->m_hasDVBC) {
+               state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
+               state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C;
+               strlcat(state->frontend.ops.info.name, " DVB-C",
+                       sizeof(state->frontend.ops.info.name));
+       }
+       if (state->m_hasDVBT) {
+               state->frontend.ops.delsys[n++] = SYS_DVBT;
+               strlcat(state->frontend.ops.info.name, " DVB-T",
+                       sizeof(state->frontend.ops.info.name));
+       }
+
+       printk(KERN_INFO "drxk: frontend initialized.\n");
+       return &state->frontend;
 
 error:
        printk(KERN_ERR "drxk: not found\n");
index a05c32eecdcc7de893a297c6faf53b54324a040c..3a58b73eb9b97f158e16f28b43c41a47a704bddd 100644 (file)
@@ -195,9 +195,8 @@ struct DRXKOfdmScCmd_t {
 };
 
 struct drxk_state {
-       struct dvb_frontend c_frontend;
-       struct dvb_frontend t_frontend;
-       struct dvb_frontend_parameters param;
+       struct dvb_frontend frontend;
+       struct dtv_frontend_properties props;
        struct device *dev;
 
        struct i2c_adapter *i2c;
@@ -205,7 +204,6 @@ struct drxk_state {
        void  *priv;
 
        struct mutex mutex;
-       struct mutex ctlock;
 
        u32    m_Instance;           /**< Channel 1,2,3 or 4 */
 
@@ -263,6 +261,8 @@ struct drxk_state {
        u8     m_TSDataStrength;
        u8     m_TSClockkStrength;
 
+       bool   m_itut_annex_c;      /* If true, uses ITU-T DVB-C Annex C, instead of Annex A */
+
        enum DRXMPEGStrWidth_t  m_widthSTR;    /**< MPEG start width */
        u32    m_mpegTsStaticBitrate;          /**< Maximum bitrate in b/s in case
                                                    static clockrate is selected */
index 90bf573308b0eb51c7507d99206e01ac9af4747a..af65d013db11e8ed843c555fe0dc73d114103729 100644 (file)
@@ -934,20 +934,6 @@ error2:
 }
 EXPORT_SYMBOL(ds3000_attach);
 
-static int ds3000_set_property(struct dvb_frontend *fe,
-       struct dtv_property *tvp)
-{
-       dprintk("%s(..)\n", __func__);
-       return 0;
-}
-
-static int ds3000_get_property(struct dvb_frontend *fe,
-       struct dtv_property *tvp)
-{
-       dprintk("%s(..)\n", __func__);
-       return 0;
-}
-
 static int ds3000_set_carrier_offset(struct dvb_frontend *fe,
                                        s32 carrier_offset_khz)
 {
@@ -967,8 +953,7 @@ static int ds3000_set_carrier_offset(struct dvb_frontend *fe,
        return 0;
 }
 
-static int ds3000_set_frontend(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *p)
+static int ds3000_set_frontend(struct dvb_frontend *fe)
 {
        struct ds3000_state *state = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -994,15 +979,15 @@ static int ds3000_set_frontend(struct dvb_frontend *fe,
        div4 = 0;
 
        /* calculate and set freq divider */
-       if (p->frequency < 1146000) {
+       if (c->frequency < 1146000) {
                ds3000_tuner_writereg(state, 0x10, 0x11);
                div4 = 1;
-               ndiv = ((p->frequency * (6 + 8) * 4) +
+               ndiv = ((c->frequency * (6 + 8) * 4) +
                                (DS3000_XTAL_FREQ / 2)) /
                                DS3000_XTAL_FREQ - 1024;
        } else {
                ds3000_tuner_writereg(state, 0x10, 0x01);
-               ndiv = ((p->frequency * (6 + 8) * 2) +
+               ndiv = ((c->frequency * (6 + 8) * 2) +
                                (DS3000_XTAL_FREQ / 2)) /
                                DS3000_XTAL_FREQ - 1024;
        }
@@ -1101,7 +1086,7 @@ static int ds3000_set_frontend(struct dvb_frontend *fe,
        msleep(60);
 
        offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ
-               / (6 + 8) / (div4 + 1) / 2 - p->frequency;
+               / (6 + 8) / (div4 + 1) / 2 - c->frequency;
 
        /* ds3000 global reset */
        ds3000_writereg(state, 0x07, 0x80);
@@ -1210,7 +1195,7 @@ static int ds3000_set_frontend(struct dvb_frontend *fe,
 
        for (i = 0; i < 30 ; i++) {
                ds3000_read_status(fe, &status);
-               if (status && FE_HAS_LOCK)
+               if (status & FE_HAS_LOCK)
                        break;
 
                msleep(10);
@@ -1220,13 +1205,13 @@ static int ds3000_set_frontend(struct dvb_frontend *fe,
 }
 
 static int ds3000_tune(struct dvb_frontend *fe,
-                       struct dvb_frontend_parameters *p,
+                       bool re_tune,
                        unsigned int mode_flags,
                        unsigned int *delay,
                        fe_status_t *status)
 {
-       if (p) {
-               int ret = ds3000_set_frontend(fe, p);
+       if (re_tune) {
+               int ret = ds3000_set_frontend(fe);
                if (ret)
                        return ret;
        }
@@ -1279,10 +1264,9 @@ static int ds3000_sleep(struct dvb_frontend *fe)
 }
 
 static struct dvb_frontend_ops ds3000_ops = {
-
+       .delsys = { SYS_DVBS, SYS_DVBS2},
        .info = {
                .name = "Montage Technology DS3000/TS2020",
-               .type = FE_QPSK,
                .frequency_min = 950000,
                .frequency_max = 2150000,
                .frequency_stepsize = 1011, /* kHz for QPSK frontends */
@@ -1312,8 +1296,6 @@ static struct dvb_frontend_ops ds3000_ops = {
        .diseqc_send_burst = ds3000_diseqc_send_burst,
        .get_frontend_algo = ds3000_get_algo,
 
-       .set_property = ds3000_set_property,
-       .get_property = ds3000_get_property,
        .set_frontend = ds3000_set_frontend,
        .tune = ds3000_tune,
 };
index 62a65efdf8d6133817beb5b8dbbaf0f2e47d12e2..1ab34838221c0b14d09bdfec5bb67bbce382bd1c 100644 (file)
@@ -61,8 +61,7 @@ struct dvb_pll_desc {
        u32  min;
        u32  max;
        u32  iffreq;
-       void (*set)(struct dvb_frontend *fe, u8 *buf,
-                   const struct dvb_frontend_parameters *params);
+       void (*set)(struct dvb_frontend *fe, u8 *buf);
        u8   *initdata;
        u8   *initdata2;
        u8   *sleepdata;
@@ -93,10 +92,10 @@ static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
        },
 };
 
-static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf,
-                              const struct dvb_frontend_parameters *params)
+static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf)
 {
-       if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth)
+       u32 bw = fe->dtv_property_cache.bandwidth_hz;
+       if (bw == 7000000)
                buf[3] |= 0x10;
 }
 
@@ -186,10 +185,10 @@ static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
 /* Philips TDA6650/TDA6651
  * used in Panasonic ENV77H11D5
  */
-static void tda665x_bw(struct dvb_frontend *fe, u8 *buf,
-                      const struct dvb_frontend_parameters *params)
+static void tda665x_bw(struct dvb_frontend *fe, u8 *buf)
 {
-       if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+       u32 bw = fe->dtv_property_cache.bandwidth_hz;
+       if (bw == 8000000)
                buf[3] |= 0x08;
 }
 
@@ -220,10 +219,10 @@ static struct dvb_pll_desc dvb_pll_tda665x = {
 /* Infineon TUA6034
  * used in LG TDTP E102P
  */
-static void tua6034_bw(struct dvb_frontend *fe, u8 *buf,
-                      const struct dvb_frontend_parameters *params)
+static void tua6034_bw(struct dvb_frontend *fe, u8 *buf)
 {
-       if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth)
+       u32 bw = fe->dtv_property_cache.bandwidth_hz;
+       if (bw == 7000000)
                buf[3] |= 0x08;
 }
 
@@ -244,10 +243,10 @@ static struct dvb_pll_desc dvb_pll_tua6034 = {
 /* ALPS TDED4
  * used in Nebula-Cards and USB boxes
  */
-static void tded4_bw(struct dvb_frontend *fe, u8 *buf,
-                    const struct dvb_frontend_parameters *params)
+static void tded4_bw(struct dvb_frontend *fe, u8 *buf)
 {
-       if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+       u32 bw = fe->dtv_property_cache.bandwidth_hz;
+       if (bw == 8000000)
                buf[3] |= 0x04;
 }
 
@@ -319,11 +318,11 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
        },
 };
 
-static void opera1_bw(struct dvb_frontend *fe, u8 *buf,
-                     const struct dvb_frontend_parameters *params)
+static void opera1_bw(struct dvb_frontend *fe, u8 *buf)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct dvb_pll_priv *priv = fe->tuner_priv;
-       u32 b_w  = (params->u.qpsk.symbol_rate * 27) / 32000;
+       u32 b_w  = (c->symbol_rate * 27) / 32000;
        struct i2c_msg msg = {
                .addr = priv->pll_i2c_address,
                .flags = 0,
@@ -392,8 +391,7 @@ static struct dvb_pll_desc dvb_pll_opera1 = {
        }
 };
 
-static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf,
-                      const struct dvb_frontend_parameters *params)
+static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf)
 {
        struct dvb_pll_priv *priv = fe->tuner_priv;
        struct i2c_msg msg = {
@@ -537,30 +535,29 @@ static struct dvb_pll_desc *pll_list[] = {
 /* code                                                        */
 
 static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf,
-                            const struct dvb_frontend_parameters *params)
+                            const u32 frequency)
 {
        struct dvb_pll_priv *priv = fe->tuner_priv;
        struct dvb_pll_desc *desc = priv->pll_desc;
        u32 div;
        int i;
 
-       if (params->frequency != 0 && (params->frequency < desc->min ||
-                                      params->frequency > desc->max))
+       if (frequency && (frequency < desc->min || frequency > desc->max))
                return -EINVAL;
 
        for (i = 0; i < desc->count; i++) {
-               if (params->frequency > desc->entries[i].limit)
+               if (frequency > desc->entries[i].limit)
                        continue;
                break;
        }
 
        if (debug)
                printk("pll: %s: freq=%d | i=%d/%d\n", desc->name,
-                      params->frequency, i, desc->count);
+                      frequency, i, desc->count);
        if (i == desc->count)
                return -EINVAL;
 
-       div = (params->frequency + desc->iffreq +
+       div = (frequency + desc->iffreq +
               desc->entries[i].stepsize/2) / desc->entries[i].stepsize;
        buf[0] = div >> 8;
        buf[1] = div & 0xff;
@@ -568,7 +565,7 @@ static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf,
        buf[3] = desc->entries[i].cb;
 
        if (desc->set)
-               desc->set(fe, buf, params);
+               desc->set(fe, buf);
 
        if (debug)
                printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
@@ -611,9 +608,9 @@ static int dvb_pll_sleep(struct dvb_frontend *fe)
        return -EINVAL;
 }
 
-static int dvb_pll_set_params(struct dvb_frontend *fe,
-                             struct dvb_frontend_parameters *params)
+static int dvb_pll_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct dvb_pll_priv *priv = fe->tuner_priv;
        u8 buf[4];
        struct i2c_msg msg =
@@ -625,7 +622,8 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
        if (priv->i2c == NULL)
                return -EINVAL;
 
-       if ((result = dvb_pll_configure(fe, buf, params)) < 0)
+       result = dvb_pll_configure(fe, buf, c->frequency);
+       if (result < 0)
                return result;
        else
                frequency = result;
@@ -637,15 +635,15 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
        }
 
        priv->frequency = frequency;
-       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+       priv->bandwidth = c->bandwidth_hz;
 
        return 0;
 }
 
 static int dvb_pll_calc_regs(struct dvb_frontend *fe,
-                            struct dvb_frontend_parameters *params,
                             u8 *buf, int buf_len)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct dvb_pll_priv *priv = fe->tuner_priv;
        int result;
        u32 frequency = 0;
@@ -653,7 +651,8 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
        if (buf_len < 5)
                return -EINVAL;
 
-       if ((result = dvb_pll_configure(fe, buf+1, params)) < 0)
+       result = dvb_pll_configure(fe, buf + 1, c->frequency);
+       if (result < 0)
                return result;
        else
                frequency = result;
@@ -661,7 +660,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
        buf[0] = priv->pll_i2c_address;
 
        priv->frequency = frequency;
-       priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+       priv->bandwidth = c->bandwidth_hz;
 
        return 5;
 }
index a7fc7e53a5518f6b20edbb7d96d050c8a2a5dbe3..dcfc902c8678be0c64b04989f549639e8114fa47 100644 (file)
@@ -68,15 +68,18 @@ static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        return 0;
 }
 
-static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+/*
+ * Only needed if it actually reads something from the hardware
+ */
+static int dvb_dummy_fe_get_frontend(struct dvb_frontend *fe)
 {
        return 0;
 }
 
-static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int dvb_dummy_fe_set_frontend(struct dvb_frontend *fe)
 {
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
@@ -171,10 +174,9 @@ error:
 }
 
 static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "Dummy DVB-T",
-               .type                   = FE_OFDM,
                .frequency_min          = 0,
                .frequency_max          = 863250000,
                .frequency_stepsize     = 62500,
@@ -203,10 +205,9 @@ static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = {
 };
 
 static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = {
-
+       .delsys = { SYS_DVBC_ANNEX_A },
        .info = {
                .name                   = "Dummy DVB-C",
-               .type                   = FE_QAM,
                .frequency_stepsize     = 62500,
                .frequency_min          = 51000000,
                .frequency_max          = 858000000,
@@ -233,10 +234,9 @@ static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = {
 };
 
 static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = {
-
+       .delsys = { SYS_DVBS },
        .info = {
                .name                   = "Dummy DVB-S",
-               .type                   = FE_QPSK,
                .frequency_min          = 950000,
                .frequency_max          = 2150000,
                .frequency_stepsize     = 250,           /* kHz for QPSK frontends */
index 2414dc6ee5d992f29c387788e452fb35736e088c..c56fddbf53b77b56b5cb9ea4c1ca34e59e6e96d0 100644 (file)
@@ -76,19 +76,19 @@ static int ec100_read_reg(struct ec100_state *state, u8 reg, u8 *val)
        return 0;
 }
 
-static int ec100_set_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params)
+static int ec100_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct ec100_state *state = fe->demodulator_priv;
        int ret;
        u8 tmp, tmp2;
 
-       deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency,
-               params->u.ofdm.bandwidth);
+       deb_info("%s: freq:%d bw:%d\n", __func__, c->frequency,
+               c->bandwidth_hz);
 
        /* program tuner */
        if (fe->ops.tuner_ops.set_params)
-               fe->ops.tuner_ops.set_params(fe, params);
+               fe->ops.tuner_ops.set_params(fe);
 
        ret = ec100_write_reg(state, 0x04, 0x06);
        if (ret)
@@ -108,16 +108,16 @@ static int ec100_set_frontend(struct dvb_frontend *fe,
           B 0x1b | 0xb7 | 0x00 | 0x49
           B 0x1c | 0x55 | 0x64 | 0x72 */
 
-       switch (params->u.ofdm.bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       switch (c->bandwidth_hz) {
+       case 6000000:
                tmp = 0xb7;
                tmp2 = 0x55;
                break;
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                tmp = 0x00;
                tmp2 = 0x64;
                break;
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
        default:
                tmp = 0x49;
                tmp2 = 0x72;
@@ -306,9 +306,9 @@ error:
 EXPORT_SYMBOL(ec100_attach);
 
 static struct dvb_frontend_ops ec100_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                .name = "E3C EC100 DVB-T",
-               .type = FE_OFDM,
                .caps =
                        FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
                        FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
diff --git a/drivers/media/dvb/frontends/hd29l2.c b/drivers/media/dvb/frontends/hd29l2.c
new file mode 100644 (file)
index 0000000..a003181
--- /dev/null
@@ -0,0 +1,861 @@
+/*
+ * HDIC HD29L2 DMB-TH demodulator driver
+ *
+ * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
+ *
+ * Author: 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "hd29l2_priv.h"
+
+int hd29l2_debug;
+module_param_named(debug, hd29l2_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+/* write multiple registers */
+static int hd29l2_wr_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len)
+{
+       int ret;
+       u8 buf[2 + len];
+       struct i2c_msg msg[1] = {
+               {
+                       .addr = priv->cfg.i2c_addr,
+                       .flags = 0,
+                       .len = sizeof(buf),
+                       .buf = buf,
+               }
+       };
+
+       buf[0] = 0x00;
+       buf[1] = reg;
+       memcpy(&buf[2], val, len);
+
+       ret = i2c_transfer(priv->i2c, msg, 1);
+       if (ret == 1) {
+               ret = 0;
+       } else {
+               warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+               ret = -EREMOTEIO;
+       }
+
+       return ret;
+}
+
+/* read multiple registers */
+static int hd29l2_rd_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len)
+{
+       int ret;
+       u8 buf[2] = { 0x00, reg };
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = priv->cfg.i2c_addr,
+                       .flags = 0,
+                       .len = 2,
+                       .buf = buf,
+               }, {
+                       .addr = priv->cfg.i2c_addr,
+                       .flags = I2C_M_RD,
+                       .len = len,
+                       .buf = val,
+               }
+       };
+
+       ret = i2c_transfer(priv->i2c, msg, 2);
+       if (ret == 2) {
+               ret = 0;
+       } else {
+               warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+               ret = -EREMOTEIO;
+       }
+
+       return ret;
+}
+
+/* write single register */
+static int hd29l2_wr_reg(struct hd29l2_priv *priv, u8 reg, u8 val)
+{
+       return hd29l2_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+static int hd29l2_rd_reg(struct hd29l2_priv *priv, u8 reg, u8 *val)
+{
+       return hd29l2_rd_regs(priv, reg, val, 1);
+}
+
+/* write single register with mask */
+static int hd29l2_wr_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 val, u8 mask)
+{
+       int ret;
+       u8 tmp;
+
+       /* no need for read if whole reg is written */
+       if (mask != 0xff) {
+               ret = hd29l2_rd_regs(priv, reg, &tmp, 1);
+               if (ret)
+                       return ret;
+
+               val &= mask;
+               tmp &= ~mask;
+               val |= tmp;
+       }
+
+       return hd29l2_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register with mask */
+int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask)
+{
+       int ret, i;
+       u8 tmp;
+
+       ret = hd29l2_rd_regs(priv, reg, &tmp, 1);
+       if (ret)
+               return ret;
+
+       tmp &= mask;
+
+       /* find position of the first bit */
+       for (i = 0; i < 8; i++) {
+               if ((mask >> i) & 0x01)
+                       break;
+       }
+       *val = tmp >> i;
+
+       return 0;
+}
+
+static int hd29l2_soft_reset(struct hd29l2_priv *priv)
+{
+       int ret;
+       u8 tmp;
+
+       ret = hd29l2_rd_reg(priv, 0x26, &tmp);
+       if (ret)
+               goto err;
+
+       ret = hd29l2_wr_reg(priv, 0x26, 0x0d);
+       if (ret)
+               goto err;
+
+       usleep_range(10000, 20000);
+
+       ret = hd29l2_wr_reg(priv, 0x26, tmp);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int hd29l2_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       int ret, i;
+       struct hd29l2_priv *priv = fe->demodulator_priv;
+       u8 tmp;
+
+       dbg("%s: enable=%d", __func__, enable);
+
+       /* set tuner address for demod */
+       if (!priv->tuner_i2c_addr_programmed && enable) {
+               /* no need to set tuner address every time, once is enough */
+               ret = hd29l2_wr_reg(priv, 0x9d, priv->cfg.tuner_i2c_addr << 1);
+               if (ret)
+                       goto err;
+
+               priv->tuner_i2c_addr_programmed = true;
+       }
+
+       /* open / close gate */
+       ret = hd29l2_wr_reg(priv, 0x9f, enable);
+       if (ret)
+               goto err;
+
+       /* wait demod ready */
+       for (i = 10; i; i--) {
+               ret = hd29l2_rd_reg(priv, 0x9e, &tmp);
+               if (ret)
+                       goto err;
+
+               if (tmp == enable)
+                       break;
+
+               usleep_range(5000, 10000);
+       }
+
+       dbg("%s: loop=%d", __func__, i);
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int hd29l2_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       int ret;
+       struct hd29l2_priv *priv = fe->demodulator_priv;
+       u8 buf[2];
+
+       *status = 0;
+
+       ret = hd29l2_rd_reg(priv, 0x05, &buf[0]);
+       if (ret)
+               goto err;
+
+       if (buf[0] & 0x01) {
+               /* full lock */
+               *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+                       FE_HAS_SYNC | FE_HAS_LOCK;
+       } else {
+               ret = hd29l2_rd_reg(priv, 0x0d, &buf[1]);
+               if (ret)
+                       goto err;
+
+               if ((buf[1] & 0xfe) == 0x78)
+                       /* partial lock */
+                       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                               FE_HAS_VITERBI | FE_HAS_SYNC;
+       }
+
+       priv->fe_status = *status;
+
+       return 0;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int hd29l2_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       int ret;
+       struct hd29l2_priv *priv = fe->demodulator_priv;
+       u8 buf[2];
+       u16 tmp;
+
+       if (!(priv->fe_status & FE_HAS_LOCK)) {
+               *snr = 0;
+               ret = 0;
+               goto err;
+       }
+
+       ret = hd29l2_rd_regs(priv, 0x0b, buf, 2);
+       if (ret)
+               goto err;
+
+       tmp = (buf[0] << 8) | buf[1];
+
+       /* report SNR in dB * 10 */
+       #define LOG10_20736_24 72422627 /* log10(20736) << 24 */
+       if (tmp)
+               *snr = (LOG10_20736_24 - intlog10(tmp)) / ((1 << 24) / 100);
+       else
+               *snr = 0;
+
+       return 0;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int hd29l2_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       int ret;
+       struct hd29l2_priv *priv = fe->demodulator_priv;
+       u8 buf[2];
+       u16 tmp;
+
+       *strength = 0;
+
+       ret = hd29l2_rd_regs(priv, 0xd5, buf, 2);
+       if (ret)
+               goto err;
+
+       tmp = buf[0] << 8 | buf[1];
+       tmp = ~tmp & 0x0fff;
+
+       /* scale value to 0x0000-0xffff from 0x0000-0x0fff */
+       *strength = tmp * 0xffff / 0x0fff;
+
+       return 0;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int hd29l2_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       int ret;
+       struct hd29l2_priv *priv = fe->demodulator_priv;
+       u8 buf[2];
+
+       if (!(priv->fe_status & FE_HAS_SYNC)) {
+               *ber = 0;
+               ret = 0;
+               goto err;
+       }
+
+       ret = hd29l2_rd_regs(priv, 0xd9, buf, 2);
+       if (ret) {
+               *ber = 0;
+               goto err;
+       }
+
+       /* LDPC BER */
+       *ber = ((buf[0] & 0x0f) << 8) | buf[1];
+
+       return 0;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int hd29l2_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       /* no way to read? */
+       *ucblocks = 0;
+       return 0;
+}
+
+static enum dvbfe_search hd29l2_search(struct dvb_frontend *fe)
+{
+       int ret, i;
+       struct hd29l2_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u8 tmp, buf[3];
+       u8 modulation, carrier, guard_interval, interleave, code_rate;
+       u64 num64;
+       u32 if_freq, if_ctl;
+       bool auto_mode;
+
+       dbg("%s: delivery_system=%d frequency=%d bandwidth_hz=%d " \
+               "modulation=%d inversion=%d fec_inner=%d guard_interval=%d",
+                __func__,
+               c->delivery_system, c->frequency, c->bandwidth_hz,
+               c->modulation, c->inversion, c->fec_inner, c->guard_interval);
+
+       /* as for now we detect always params automatically */
+       auto_mode = true;
+
+       /* program tuner */
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe);
+
+       /* get and program IF */
+       if (fe->ops.tuner_ops.get_if_frequency)
+               fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+       else
+               if_freq = 0;
+
+       if (if_freq) {
+               /* normal IF */
+
+               /* calc IF control value */
+               num64 = if_freq;
+               num64 *= 0x800000;
+               num64 = div_u64(num64, HD29L2_XTAL);
+               num64 -= 0x800000;
+               if_ctl = num64;
+
+               tmp = 0xfc; /* tuner type normal */
+       } else {
+               /* zero IF */
+               if_ctl = 0;
+               tmp = 0xfe; /* tuner type Zero-IF */
+       }
+
+       buf[0] = ((if_ctl >>  0) & 0xff);
+       buf[1] = ((if_ctl >>  8) & 0xff);
+       buf[2] = ((if_ctl >> 16) & 0xff);
+
+       /* program IF control */
+       ret = hd29l2_wr_regs(priv, 0x14, buf, 3);
+       if (ret)
+               goto err;
+
+       /* program tuner type */
+       ret = hd29l2_wr_reg(priv, 0xab, tmp);
+       if (ret)
+               goto err;
+
+       dbg("%s: if_freq=%d if_ctl=%x", __func__, if_freq, if_ctl);
+
+       if (auto_mode) {
+               /*
+                * use auto mode
+                */
+
+               /* disable quick mode */
+               ret = hd29l2_wr_reg_mask(priv, 0xac, 0 << 7, 0x80);
+               if (ret)
+                       goto err;
+
+               ret = hd29l2_wr_reg_mask(priv, 0x82, 1 << 1, 0x02);
+               if (ret)
+                       goto err;
+
+               /* enable auto mode */
+               ret = hd29l2_wr_reg_mask(priv, 0x7d, 1 << 6, 0x40);
+               if (ret)
+                       goto err;
+
+               ret = hd29l2_wr_reg_mask(priv, 0x81, 1 << 3, 0x08);
+               if (ret)
+                       goto err;
+
+               /* soft reset */
+               ret = hd29l2_soft_reset(priv);
+               if (ret)
+                       goto err;
+
+               /* detect modulation */
+               for (i = 30; i; i--) {
+                       msleep(100);
+
+                       ret = hd29l2_rd_reg(priv, 0x0d, &tmp);
+                       if (ret)
+                               goto err;
+
+                       if ((((tmp & 0xf0) >= 0x10) &&
+                               ((tmp & 0x0f) == 0x08)) || (tmp >= 0x2c))
+                               break;
+               }
+
+               dbg("%s: loop=%d", __func__, i);
+
+               if (i == 0)
+                       /* detection failed */
+                       return DVBFE_ALGO_SEARCH_FAILED;
+
+               /* read modulation */
+               ret = hd29l2_rd_reg_mask(priv, 0x7d, &modulation, 0x07);
+               if (ret)
+                       goto err;
+       } else {
+               /*
+                * use manual mode
+                */
+
+               modulation = HD29L2_QAM64;
+               carrier = HD29L2_CARRIER_MULTI;
+               guard_interval = HD29L2_PN945;
+               interleave = HD29L2_INTERLEAVER_420;
+               code_rate = HD29L2_CODE_RATE_08;
+
+               tmp = (code_rate << 3) | modulation;
+               ret = hd29l2_wr_reg_mask(priv, 0x7d, tmp, 0x5f);
+               if (ret)
+                       goto err;
+
+               tmp = (carrier << 2) | guard_interval;
+               ret = hd29l2_wr_reg_mask(priv, 0x81, tmp, 0x0f);
+               if (ret)
+                       goto err;
+
+               tmp = interleave;
+               ret = hd29l2_wr_reg_mask(priv, 0x82, tmp, 0x03);
+               if (ret)
+                       goto err;
+       }
+
+       /* ensure modulation validy */
+       /* 0=QAM4_NR, 1=QAM4, 2=QAM16, 3=QAM32, 4=QAM64 */
+       if (modulation > (ARRAY_SIZE(reg_mod_vals_tab[0].val) - 1)) {
+               dbg("%s: modulation=%d not valid", __func__, modulation);
+               goto err;
+       }
+
+       /* program registers according to modulation */
+       for (i = 0; i < ARRAY_SIZE(reg_mod_vals_tab); i++) {
+               ret = hd29l2_wr_reg(priv, reg_mod_vals_tab[i].reg,
+                       reg_mod_vals_tab[i].val[modulation]);
+               if (ret)
+                       goto err;
+       }
+
+       /* read guard interval */
+       ret = hd29l2_rd_reg_mask(priv, 0x81, &guard_interval, 0x03);
+       if (ret)
+               goto err;
+
+       /* read carrier mode */
+       ret = hd29l2_rd_reg_mask(priv, 0x81, &carrier, 0x04);
+       if (ret)
+               goto err;
+
+       dbg("%s: modulation=%d guard_interval=%d carrier=%d",
+               __func__, modulation, guard_interval, carrier);
+
+       if ((carrier == HD29L2_CARRIER_MULTI) && (modulation == HD29L2_QAM64) &&
+               (guard_interval == HD29L2_PN945)) {
+               dbg("%s: C=3780 && QAM64 && PN945", __func__);
+
+               ret = hd29l2_wr_reg(priv, 0x42, 0x33);
+               if (ret)
+                       goto err;
+
+               ret = hd29l2_wr_reg(priv, 0xdd, 0x01);
+               if (ret)
+                       goto err;
+       }
+
+       usleep_range(10000, 20000);
+
+       /* soft reset */
+       ret = hd29l2_soft_reset(priv);
+       if (ret)
+               goto err;
+
+       /* wait demod lock */
+       for (i = 30; i; i--) {
+               msleep(100);
+
+               /* read lock bit */
+               ret = hd29l2_rd_reg_mask(priv, 0x05, &tmp, 0x01);
+               if (ret)
+                       goto err;
+
+               if (tmp)
+                       break;
+       }
+
+       dbg("%s: loop=%d", __func__, i);
+
+       if (i == 0)
+               return DVBFE_ALGO_SEARCH_AGAIN;
+
+       return DVBFE_ALGO_SEARCH_SUCCESS;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+static int hd29l2_get_frontend_algo(struct dvb_frontend *fe)
+{
+       return DVBFE_ALGO_CUSTOM;
+}
+
+static int hd29l2_get_frontend(struct dvb_frontend *fe)
+{
+       int ret;
+       struct hd29l2_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u8 buf[3];
+       u32 if_ctl;
+       char *str_constellation, *str_code_rate, *str_constellation_code_rate,
+               *str_guard_interval, *str_carrier, *str_guard_interval_carrier,
+               *str_interleave, *str_interleave_;
+
+       ret = hd29l2_rd_reg(priv, 0x7d, &buf[0]);
+       if (ret)
+               goto err;
+
+       ret = hd29l2_rd_regs(priv, 0x81, &buf[1], 2);
+       if (ret)
+               goto err;
+
+       /* constellation, 0x7d[2:0] */
+       switch ((buf[0] >> 0) & 0x07) {
+       case 0: /* QAM4NR */
+               str_constellation = "QAM4NR";
+               c->modulation = QAM_AUTO; /* FIXME */
+               break;
+       case 1: /* QAM4 */
+               str_constellation = "QAM4";
+               c->modulation = QPSK; /* FIXME */
+               break;
+       case 2:
+               str_constellation = "QAM16";
+               c->modulation = QAM_16;
+               break;
+       case 3:
+               str_constellation = "QAM32";
+               c->modulation = QAM_32;
+               break;
+       case 4:
+               str_constellation = "QAM64";
+               c->modulation = QAM_64;
+               break;
+       default:
+               str_constellation = "?";
+       }
+
+       /* LDPC code rate, 0x7d[4:3] */
+       switch ((buf[0] >> 3) & 0x03) {
+       case 0: /* 0.4 */
+               str_code_rate = "0.4";
+               c->fec_inner = FEC_AUTO; /* FIXME */
+               break;
+       case 1: /* 0.6 */
+               str_code_rate = "0.6";
+               c->fec_inner = FEC_3_5;
+               break;
+       case 2: /* 0.8 */
+               str_code_rate = "0.8";
+               c->fec_inner = FEC_4_5;
+               break;
+       default:
+               str_code_rate = "?";
+       }
+
+       /* constellation & code rate set, 0x7d[6] */
+       switch ((buf[0] >> 6) & 0x01) {
+       case 0:
+               str_constellation_code_rate = "manual";
+               break;
+       case 1:
+               str_constellation_code_rate = "auto";
+               break;
+       default:
+               str_constellation_code_rate = "?";
+       }
+
+       /* frame header, 0x81[1:0] */
+       switch ((buf[1] >> 0) & 0x03) {
+       case 0: /* PN945 */
+               str_guard_interval = "PN945";
+               c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
+               break;
+       case 1: /* PN595 */
+               str_guard_interval = "PN595";
+               c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
+               break;
+       case 2: /* PN420 */
+               str_guard_interval = "PN420";
+               c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
+               break;
+       default:
+               str_guard_interval = "?";
+       }
+
+       /* carrier, 0x81[2] */
+       switch ((buf[1] >> 2) & 0x01) {
+       case 0:
+               str_carrier = "C=1";
+               break;
+       case 1:
+               str_carrier = "C=3780";
+               break;
+       default:
+               str_carrier = "?";
+       }
+
+       /* frame header & carrier set, 0x81[3] */
+       switch ((buf[1] >> 3) & 0x01) {
+       case 0:
+               str_guard_interval_carrier = "manual";
+               break;
+       case 1:
+               str_guard_interval_carrier = "auto";
+               break;
+       default:
+               str_guard_interval_carrier = "?";
+       }
+
+       /* interleave, 0x82[0] */
+       switch ((buf[2] >> 0) & 0x01) {
+       case 0:
+               str_interleave = "M=720";
+               break;
+       case 1:
+               str_interleave = "M=240";
+               break;
+       default:
+               str_interleave = "?";
+       }
+
+       /* interleave set, 0x82[1] */
+       switch ((buf[2] >> 1) & 0x01) {
+       case 0:
+               str_interleave_ = "manual";
+               break;
+       case 1:
+               str_interleave_ = "auto";
+               break;
+       default:
+               str_interleave_ = "?";
+       }
+
+       /*
+        * We can read out current detected NCO and use that value next
+        * time instead of calculating new value from targed IF.
+        * I think it will not effect receiver sensitivity but gaining lock
+        * after tune could be easier...
+        */
+       ret = hd29l2_rd_regs(priv, 0xb1, &buf[0], 3);
+       if (ret)
+               goto err;
+
+       if_ctl = (buf[0] << 16) | ((buf[1] - 7) << 8) | buf[2];
+
+       dbg("%s: %s %s %s | %s %s %s | %s %s | NCO=%06x", __func__,
+               str_constellation, str_code_rate, str_constellation_code_rate,
+               str_guard_interval, str_carrier, str_guard_interval_carrier,
+               str_interleave, str_interleave_, if_ctl);
+
+       return 0;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int hd29l2_init(struct dvb_frontend *fe)
+{
+       int ret, i;
+       struct hd29l2_priv *priv = fe->demodulator_priv;
+       u8 tmp;
+       static const struct reg_val tab[] = {
+               { 0x3a, 0x06 },
+               { 0x3b, 0x03 },
+               { 0x3c, 0x04 },
+               { 0xaf, 0x06 },
+               { 0xb0, 0x1b },
+               { 0x80, 0x64 },
+               { 0x10, 0x38 },
+       };
+
+       dbg("%s:", __func__);
+
+       /* reset demod */
+       /* it is recommended to HW reset chip using RST_N pin */
+       if (fe->callback) {
+               ret = fe->callback(fe, DVB_FRONTEND_COMPONENT_DEMOD, 0, 0);
+               if (ret)
+                       goto err;
+
+               /* reprogramming needed because HW reset clears registers */
+               priv->tuner_i2c_addr_programmed = false;
+       }
+
+       /* init */
+       for (i = 0; i < ARRAY_SIZE(tab); i++) {
+               ret = hd29l2_wr_reg(priv, tab[i].reg, tab[i].val);
+               if (ret)
+                       goto err;
+       }
+
+       /* TS params */
+       ret = hd29l2_rd_reg(priv, 0x36, &tmp);
+       if (ret)
+               goto err;
+
+       tmp &= 0x1b;
+       tmp |= priv->cfg.ts_mode;
+       ret = hd29l2_wr_reg(priv, 0x36, tmp);
+       if (ret)
+               goto err;
+
+       ret = hd29l2_rd_reg(priv, 0x31, &tmp);
+       tmp &= 0xef;
+
+       if (!(priv->cfg.ts_mode >> 7))
+               /* set b4 for serial TS */
+               tmp |= 0x10;
+
+       ret = hd29l2_wr_reg(priv, 0x31, tmp);
+       if (ret)
+               goto err;
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static void hd29l2_release(struct dvb_frontend *fe)
+{
+       struct hd29l2_priv *priv = fe->demodulator_priv;
+       kfree(priv);
+}
+
+static struct dvb_frontend_ops hd29l2_ops;
+
+struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config,
+       struct i2c_adapter *i2c)
+{
+       int ret;
+       struct hd29l2_priv *priv = NULL;
+       u8 tmp;
+
+       /* allocate memory for the internal state */
+       priv = kzalloc(sizeof(struct hd29l2_priv), GFP_KERNEL);
+       if (priv == NULL)
+               goto err;
+
+       /* setup the state */
+       priv->i2c = i2c;
+       memcpy(&priv->cfg, config, sizeof(struct hd29l2_config));
+
+
+       /* check if the demod is there */
+       ret = hd29l2_rd_reg(priv, 0x00, &tmp);
+       if (ret)
+               goto err;
+
+       /* create dvb_frontend */
+       memcpy(&priv->fe.ops, &hd29l2_ops, sizeof(struct dvb_frontend_ops));
+       priv->fe.demodulator_priv = priv;
+
+       return &priv->fe;
+err:
+       kfree(priv);
+       return NULL;
+}
+EXPORT_SYMBOL(hd29l2_attach);
+
+static struct dvb_frontend_ops hd29l2_ops = {
+       .delsys = { SYS_DVBT },
+       .info = {
+               .name = "HDIC HD29L2 DMB-TH",
+               .frequency_min = 474000000,
+               .frequency_max = 858000000,
+               .frequency_stepsize = 10000,
+               .caps = FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK |
+                       FE_CAN_QAM_16 |
+                       FE_CAN_QAM_32 |
+                       FE_CAN_QAM_64 |
+                       FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_BANDWIDTH_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_HIERARCHY_AUTO |
+                       FE_CAN_RECOVER
+       },
+
+       .release = hd29l2_release,
+
+       .init = hd29l2_init,
+
+       .get_frontend_algo = hd29l2_get_frontend_algo,
+       .search = hd29l2_search,
+       .get_frontend = hd29l2_get_frontend,
+
+       .read_status = hd29l2_read_status,
+       .read_snr = hd29l2_read_snr,
+       .read_signal_strength = hd29l2_read_signal_strength,
+       .read_ber = hd29l2_read_ber,
+       .read_ucblocks = hd29l2_read_ucblocks,
+
+       .i2c_gate_ctrl = hd29l2_i2c_gate_ctrl,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("HDIC HD29L2 DMB-TH demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/hd29l2.h b/drivers/media/dvb/frontends/hd29l2.h
new file mode 100644 (file)
index 0000000..a7a6443
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * HDIC HD29L2 DMB-TH demodulator driver
+ *
+ * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
+ *
+ * Author: 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef HD29L2_H
+#define HD29L2_H
+
+#include <linux/dvb/frontend.h>
+
+struct hd29l2_config {
+       /*
+        * demodulator I2C address
+        */
+       u8 i2c_addr;
+
+       /*
+        * tuner I2C address
+        * only needed when tuner is behind demod I2C-gate
+        */
+       u8 tuner_i2c_addr;
+
+       /*
+        * TS settings
+        */
+#define HD29L2_TS_SERIAL            0x00
+#define HD29L2_TS_PARALLEL          0x80
+#define HD29L2_TS_CLK_NORMAL        0x40
+#define HD29L2_TS_CLK_INVERTED      0x00
+#define HD29L2_TS_CLK_GATED         0x20
+#define HD29L2_TS_CLK_FREE          0x00
+       u8 ts_mode;
+};
+
+
+#if defined(CONFIG_DVB_HD29L2) || \
+       (defined(CONFIG_DVB_HD29L2_MODULE) && defined(MODULE))
+extern struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config,
+       struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *hd29l2_attach(
+const struct hd29l2_config *config, struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif /* HD29L2_H */
diff --git a/drivers/media/dvb/frontends/hd29l2_priv.h b/drivers/media/dvb/frontends/hd29l2_priv.h
new file mode 100644 (file)
index 0000000..ba16dc3
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * HDIC HD29L2 DMB-TH demodulator driver
+ *
+ * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
+ *
+ * Author: 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef HD29L2_PRIV
+#define HD29L2_PRIV
+
+#include <linux/dvb/version.h>
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "hd29l2.h"
+
+#define LOG_PREFIX "hd29l2"
+
+#undef dbg
+#define dbg(f, arg...) \
+       if (hd29l2_debug) \
+               printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+#define HD29L2_XTAL 30400000 /* Hz */
+
+
+#define HD29L2_QAM4NR 0x00
+#define HD29L2_QAM4   0x01
+#define HD29L2_QAM16  0x02
+#define HD29L2_QAM32  0x03
+#define HD29L2_QAM64  0x04
+
+#define HD29L2_CODE_RATE_04 0x00
+#define HD29L2_CODE_RATE_06 0x08
+#define HD29L2_CODE_RATE_08 0x10
+
+#define HD29L2_PN945 0x00
+#define HD29L2_PN595 0x01
+#define HD29L2_PN420 0x02
+
+#define HD29L2_CARRIER_SINGLE 0x00
+#define HD29L2_CARRIER_MULTI  0x01
+
+#define HD29L2_INTERLEAVER_720 0x00
+#define HD29L2_INTERLEAVER_420 0x01
+
+struct reg_val {
+       u8 reg;
+       u8 val;
+};
+
+struct reg_mod_vals {
+       u8 reg;
+       u8 val[5];
+};
+
+struct hd29l2_priv {
+       struct i2c_adapter *i2c;
+       struct dvb_frontend fe;
+       struct hd29l2_config cfg;
+       u8 tuner_i2c_addr_programmed:1;
+
+       fe_status_t fe_status;
+};
+
+static const struct reg_mod_vals reg_mod_vals_tab[] = {
+       /* REG, QAM4NR, QAM4,QAM16,QAM32,QAM64 */
+       { 0x01, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
+       { 0x02, { 0x07, 0x07, 0x07, 0x07, 0x07 } },
+       { 0x03, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
+       { 0x04, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x05, { 0x61, 0x60, 0x60, 0x61, 0x60 } },
+       { 0x06, { 0xff, 0xff, 0xff, 0xff, 0xff } },
+       { 0x07, { 0xff, 0xff, 0xff, 0xff, 0xff } },
+       { 0x08, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x09, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x0a, { 0x15, 0x15, 0x03, 0x03, 0x03 } },
+       { 0x0d, { 0x78, 0x78, 0x88, 0x78, 0x78 } },
+       { 0x0e, { 0xa0, 0x90, 0xa0, 0xa0, 0xa0 } },
+       { 0x0f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x10, { 0xa0, 0xa0, 0x58, 0x38, 0x38 } },
+       { 0x11, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x12, { 0x5a, 0x5a, 0x5a, 0x5a, 0x5a } },
+       { 0x13, { 0xa2, 0xa2, 0xa2, 0xa2, 0xa2 } },
+       { 0x17, { 0x40, 0x40, 0x40, 0x40, 0x40 } },
+       { 0x18, { 0x21, 0x21, 0x42, 0x52, 0x42 } },
+       { 0x19, { 0x21, 0x21, 0x62, 0x72, 0x62 } },
+       { 0x1a, { 0x32, 0x43, 0xa9, 0xb9, 0xa9 } },
+       { 0x1b, { 0x32, 0x43, 0xb9, 0xd8, 0xb9 } },
+       { 0x1c, { 0x02, 0x02, 0x03, 0x02, 0x03 } },
+       { 0x1d, { 0x0c, 0x0c, 0x01, 0x02, 0x02 } },
+       { 0x1e, { 0x02, 0x02, 0x02, 0x01, 0x02 } },
+       { 0x1f, { 0x02, 0x02, 0x01, 0x02, 0x04 } },
+       { 0x20, { 0x01, 0x02, 0x01, 0x01, 0x01 } },
+       { 0x21, { 0x08, 0x08, 0x0a, 0x0a, 0x0a } },
+       { 0x22, { 0x06, 0x06, 0x04, 0x05, 0x05 } },
+       { 0x23, { 0x06, 0x06, 0x05, 0x03, 0x05 } },
+       { 0x24, { 0x08, 0x08, 0x05, 0x07, 0x07 } },
+       { 0x25, { 0x16, 0x10, 0x10, 0x0a, 0x10 } },
+       { 0x26, { 0x14, 0x14, 0x04, 0x04, 0x04 } },
+       { 0x27, { 0x58, 0x58, 0x58, 0x5c, 0x58 } },
+       { 0x28, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+       { 0x29, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+       { 0x2a, { 0x08, 0x0a, 0x08, 0x08, 0x08 } },
+       { 0x2b, { 0x08, 0x08, 0x08, 0x08, 0x08 } },
+       { 0x2c, { 0x06, 0x06, 0x06, 0x06, 0x06 } },
+       { 0x2d, { 0x05, 0x06, 0x06, 0x06, 0x06 } },
+       { 0x2e, { 0x21, 0x21, 0x21, 0x21, 0x21 } },
+       { 0x2f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x30, { 0x14, 0x14, 0x14, 0x14, 0x14 } },
+       { 0x33, { 0xb7, 0xb7, 0xb7, 0xb7, 0xb7 } },
+       { 0x34, { 0x81, 0x81, 0x81, 0x81, 0x81 } },
+       { 0x35, { 0x80, 0x80, 0x80, 0x80, 0x80 } },
+       { 0x37, { 0x70, 0x70, 0x70, 0x70, 0x70 } },
+       { 0x38, { 0x04, 0x04, 0x02, 0x02, 0x02 } },
+       { 0x39, { 0x07, 0x07, 0x05, 0x05, 0x05 } },
+       { 0x3a, { 0x06, 0x06, 0x06, 0x06, 0x06 } },
+       { 0x3b, { 0x03, 0x03, 0x03, 0x03, 0x03 } },
+       { 0x3c, { 0x07, 0x06, 0x04, 0x04, 0x04 } },
+       { 0x3d, { 0xf0, 0xf0, 0xf0, 0xf0, 0x80 } },
+       { 0x3e, { 0x60, 0x60, 0x60, 0x60, 0xff } },
+       { 0x3f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x40, { 0x5b, 0x5b, 0x5b, 0x57, 0x50 } },
+       { 0x41, { 0x30, 0x30, 0x30, 0x30, 0x18 } },
+       { 0x42, { 0x20, 0x20, 0x20, 0x00, 0x30 } },
+       { 0x43, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x44, { 0x3f, 0x3f, 0x3f, 0x3f, 0x3f } },
+       { 0x45, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x46, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+       { 0x47, { 0x00, 0x00, 0x95, 0x00, 0x95 } },
+       { 0x48, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } },
+       { 0x49, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } },
+       { 0x4a, { 0x40, 0x40, 0x33, 0x11, 0x11 } },
+       { 0x4b, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+       { 0x4c, { 0x40, 0x40, 0x99, 0x11, 0x11 } },
+       { 0x4d, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+       { 0x4e, { 0x40, 0x40, 0x66, 0x77, 0x77 } },
+       { 0x4f, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+       { 0x50, { 0x40, 0x40, 0x88, 0x33, 0x11 } },
+       { 0x51, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+       { 0x52, { 0x40, 0x40, 0x88, 0x02, 0x02 } },
+       { 0x53, { 0x40, 0x40, 0x00, 0x02, 0x02 } },
+       { 0x54, { 0x00, 0x00, 0x88, 0x33, 0x33 } },
+       { 0x55, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
+       { 0x56, { 0x00, 0x00, 0x00, 0x0b, 0x00 } },
+       { 0x57, { 0x40, 0x40, 0x0a, 0x0b, 0x0a } },
+       { 0x58, { 0xaa, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x59, { 0x7a, 0x40, 0x02, 0x02, 0x02 } },
+       { 0x5a, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
+       { 0x5b, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
+       { 0x5c, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
+       { 0x5d, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
+       { 0x5e, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } },
+       { 0x5f, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } },
+       { 0x60, { 0x40, 0x40, 0x00, 0x30, 0x30 } },
+       { 0x61, { 0x40, 0x40, 0x10, 0x30, 0x30 } },
+       { 0x62, { 0x40, 0x40, 0x00, 0x30, 0x30 } },
+       { 0x63, { 0x40, 0x40, 0x05, 0x30, 0x30 } },
+       { 0x64, { 0x40, 0x40, 0x06, 0x00, 0x30 } },
+       { 0x65, { 0x40, 0x40, 0x06, 0x08, 0x30 } },
+       { 0x66, { 0x40, 0x40, 0x00, 0x00, 0x20 } },
+       { 0x67, { 0x40, 0x40, 0x01, 0x04, 0x20 } },
+       { 0x68, { 0x00, 0x00, 0x30, 0x00, 0x20 } },
+       { 0x69, { 0xa0, 0xa0, 0x00, 0x08, 0x20 } },
+       { 0x6a, { 0x00, 0x00, 0x30, 0x00, 0x25 } },
+       { 0x6b, { 0xa0, 0xa0, 0x00, 0x06, 0x25 } },
+       { 0x6c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x6d, { 0xa0, 0x60, 0x0c, 0x03, 0x0c } },
+       { 0x6e, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x6f, { 0xa0, 0x60, 0x04, 0x01, 0x04 } },
+       { 0x70, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } },
+       { 0x71, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } },
+       { 0x72, { 0x58, 0x58, 0xff, 0xff, 0xff } },
+       { 0x73, { 0x58, 0x58, 0xff, 0xff, 0xff } },
+       { 0x74, { 0x06, 0x06, 0x09, 0x05, 0x05 } },
+       { 0x75, { 0x06, 0x06, 0x0a, 0x10, 0x10 } },
+       { 0x76, { 0x10, 0x10, 0x06, 0x0a, 0x0a } },
+       { 0x77, { 0x12, 0x18, 0x28, 0x10, 0x28 } },
+       { 0x78, { 0xf8, 0xf8, 0xf8, 0xf8, 0xf8 } },
+       { 0x79, { 0x15, 0x15, 0x03, 0x03, 0x03 } },
+       { 0x7a, { 0x02, 0x02, 0x01, 0x04, 0x03 } },
+       { 0x7b, { 0x01, 0x02, 0x03, 0x03, 0x03 } },
+       { 0x7c, { 0x28, 0x28, 0x28, 0x28, 0x28 } },
+       { 0x7f, { 0x25, 0x92, 0x5f, 0x17, 0x2d } },
+       { 0x80, { 0x64, 0x64, 0x64, 0x74, 0x64 } },
+       { 0x83, { 0x06, 0x03, 0x04, 0x04, 0x04 } },
+       { 0x84, { 0xff, 0xff, 0xff, 0xff, 0xff } },
+       { 0x85, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
+       { 0x86, { 0x00, 0x00, 0x11, 0x11, 0x11 } },
+       { 0x87, { 0x03, 0x03, 0x03, 0x03, 0x03 } },
+       { 0x88, { 0x09, 0x09, 0x09, 0x09, 0x09 } },
+       { 0x89, { 0x20, 0x20, 0x30, 0x20, 0x20 } },
+       { 0x8a, { 0x03, 0x03, 0x02, 0x03, 0x02 } },
+       { 0x8b, { 0x00, 0x07, 0x09, 0x00, 0x09 } },
+       { 0x8c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x8d, { 0x4f, 0x4f, 0x4f, 0x3f, 0x4f } },
+       { 0x8e, { 0xf0, 0xf0, 0x60, 0xf0, 0xa0 } },
+       { 0x8f, { 0xe8, 0xe8, 0xe8, 0xe8, 0xe8 } },
+       { 0x90, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
+       { 0x91, { 0x40, 0x40, 0x70, 0x70, 0x10 } },
+       { 0x92, { 0x00, 0x00, 0x00, 0x00, 0x04 } },
+       { 0x93, { 0x60, 0x60, 0x60, 0x60, 0x60 } },
+       { 0x94, { 0x00, 0x00, 0x00, 0x00, 0x03 } },
+       { 0x95, { 0x09, 0x09, 0x47, 0x47, 0x47 } },
+       { 0x96, { 0x80, 0xa0, 0xa0, 0x40, 0xa0 } },
+       { 0x97, { 0x60, 0x60, 0x60, 0x60, 0x60 } },
+       { 0x98, { 0x50, 0x50, 0x50, 0x30, 0x50 } },
+       { 0x99, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
+       { 0x9a, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0x9b, { 0x40, 0x40, 0x40, 0x30, 0x40 } },
+       { 0x9c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xa0, { 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 } },
+       { 0xa1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xa2, { 0x30, 0x30, 0x00, 0x30, 0x00 } },
+       { 0xa3, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xa4, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xa5, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xa6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xa7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xa8, { 0x77, 0x77, 0x77, 0x77, 0x77 } },
+       { 0xa9, { 0x02, 0x02, 0x02, 0x02, 0x02 } },
+       { 0xaa, { 0x40, 0x40, 0x40, 0x40, 0x40 } },
+       { 0xac, { 0x1f, 0x1f, 0x1f, 0x1f, 0x1f } },
+       { 0xad, { 0x14, 0x14, 0x14, 0x14, 0x14 } },
+       { 0xae, { 0x78, 0x78, 0x78, 0x78, 0x78 } },
+       { 0xaf, { 0x06, 0x06, 0x06, 0x06, 0x07 } },
+       { 0xb0, { 0x1b, 0x1b, 0x1b, 0x19, 0x1b } },
+       { 0xb1, { 0x18, 0x17, 0x17, 0x18, 0x17 } },
+       { 0xb2, { 0x35, 0x82, 0x82, 0x38, 0x82 } },
+       { 0xb3, { 0xb6, 0xce, 0xc7, 0x5c, 0xb0 } },
+       { 0xb4, { 0x3f, 0x3e, 0x3e, 0x3f, 0x3e } },
+       { 0xb5, { 0x70, 0x58, 0x50, 0x68, 0x50 } },
+       { 0xb6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xb7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xb8, { 0x03, 0x03, 0x01, 0x01, 0x01 } },
+       { 0xb9, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xba, { 0x06, 0x06, 0x0a, 0x05, 0x0a } },
+       { 0xbb, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xbc, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xbd, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xbe, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xbf, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xc0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xc1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xc2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xc3, { 0x00, 0x00, 0x88, 0x66, 0x88 } },
+       { 0xc4, { 0x10, 0x10, 0x00, 0x00, 0x00 } },
+       { 0xc5, { 0x00, 0x00, 0x44, 0x60, 0x44 } },
+       { 0xc6, { 0x10, 0x0a, 0x00, 0x00, 0x00 } },
+       { 0xc7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xc8, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xc9, { 0x90, 0x04, 0x00, 0x00, 0x00 } },
+       { 0xca, { 0x90, 0x08, 0x01, 0x01, 0x01 } },
+       { 0xcb, { 0xa0, 0x04, 0x00, 0x44, 0x00 } },
+       { 0xcc, { 0xa0, 0x10, 0x03, 0x00, 0x03 } },
+       { 0xcd, { 0x06, 0x06, 0x06, 0x05, 0x06 } },
+       { 0xce, { 0x05, 0x05, 0x01, 0x01, 0x01 } },
+       { 0xcf, { 0x40, 0x20, 0x18, 0x18, 0x18 } },
+       { 0xd0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xd1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xd2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xd3, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xd4, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
+       { 0xd5, { 0x05, 0x05, 0x05, 0x03, 0x05 } },
+       { 0xd6, { 0xac, 0x22, 0xca, 0x8f, 0xca } },
+       { 0xd7, { 0x20, 0x20, 0x20, 0x20, 0x20 } },
+       { 0xd8, { 0x01, 0x01, 0x01, 0x01, 0x01 } },
+       { 0xd9, { 0x00, 0x00, 0x0f, 0x00, 0x0f } },
+       { 0xda, { 0x00, 0xff, 0xff, 0x0e, 0xff } },
+       { 0xdb, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+       { 0xdc, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+       { 0xdd, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
+       { 0xde, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+       { 0xdf, { 0x42, 0x42, 0x44, 0x44, 0x04 } },
+       { 0xe0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xe1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xe2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xe3, { 0x00, 0x00, 0x26, 0x06, 0x26 } },
+       { 0xe4, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xe5, { 0x01, 0x0a, 0x01, 0x01, 0x01 } },
+       { 0xe6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xe7, { 0x08, 0x08, 0x08, 0x08, 0x08 } },
+       { 0xe8, { 0x63, 0x63, 0x63, 0x63, 0x63 } },
+       { 0xe9, { 0x59, 0x59, 0x59, 0x59, 0x59 } },
+       { 0xea, { 0x80, 0x80, 0x20, 0x80, 0x80 } },
+       { 0xeb, { 0x37, 0x37, 0x78, 0x37, 0x77 } },
+       { 0xec, { 0x1f, 0x1f, 0x25, 0x25, 0x25 } },
+       { 0xed, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
+       { 0xee, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+       { 0xef, { 0x70, 0x70, 0x58, 0x38, 0x58 } },
+       { 0xf0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
+};
+
+#endif /* HD29L2_PRIV */
index 1c6fb4b662556ddd18bfdf8ec897ad9d268bec92..93b086ea7e1cda446d9197d5af938194a590aa2b 100644 (file)
@@ -22,126 +22,126 @@ struct adctable { u32 adcFrequency;
 /* clock and coeff tables only table 3 is used with IT9137*/
 /* TODO other tables relate AF9035 may be removed */
 static struct adctable tab1[] = {
-       {       20156250, BANDWIDTH_6_MHZ,
+       {       20156250, 6000000,
                0x02b8ba6e, 0x015c5d37, 0x00ae340d, 0x00ae2e9b, 0x00ae292a,
                0x015c5d37, 0x00ae2e9b, 0x0057174e, 0x02f1, 0x015c      },
-       {       20156250, BANDWIDTH_7_MHZ,
+       {       20156250, 7000000,
                0x032cd980, 0x01966cc0, 0x00cb3cba, 0x00cb3660, 0x00cb3007,
                0x01966cc0, 0x00cb3660, 0x00659b30, 0x0285, 0x0196      },
-       {       20156250, BANDWIDTH_8_MHZ,
+       {       20156250, 8000000,
                0x03a0f893, 0x01d07c49, 0x00e84567, 0x00e83e25, 0x00e836e3,
                0x01d07c49, 0x00e83e25, 0x00741f12, 0x0234, 0x01d0      },
-       {       20156250, BANDWIDTH_5_MHZ,
+       {       20156250, 5000000,
                0x02449b5c, 0x01224dae, 0x00912b60, 0x009126d7, 0x0091224e,
                0x01224dae, 0x009126d7, 0x0048936b, 0x0387, 0x0122      }
 };
 
 static struct adctable tab2[] = {
-       {       20187500, BANDWIDTH_6_MHZ,
+       {       20187500, 6000000,
                0x02b7a654, 0x015bd32a, 0x00adef04, 0x00ade995, 0x00ade426,
                0x015bd32a, 0x00ade995, 0x0056f4ca, 0x02f2, 0x015c      },
-       {       20187500, BANDWIDTH_7_MHZ,
+       {       20187500, 7000000,
                0x032b9761, 0x0195cbb1, 0x00caec30, 0x00cae5d8, 0x00cadf81,
                0x0195cbb1, 0x00cae5d8, 0x006572ec, 0x0286, 0x0196      },
-       {       20187500, BANDWIDTH_8_MHZ,
+       {       20187500, 8000000,
                0x039f886f, 0x01cfc438, 0x00e7e95b, 0x00e7e21c, 0x00e7dadd,
                0x01cfc438, 0x00e7e21c, 0x0073f10e, 0x0235, 0x01d0      },
-       {       20187500, BANDWIDTH_5_MHZ,
+       {       20187500, 5000000,
                0x0243b546, 0x0121daa3, 0x0090f1d9, 0x0090ed51, 0x0090e8ca,
                0x0121daa3, 0x0090ed51, 0x004876a9, 0x0388, 0x0122      }
 
 };
 
 static struct adctable tab3[] = {
-       {       20250000, BANDWIDTH_6_MHZ,
+       {       20250000, 6000000,
                0x02b580ad, 0x015ac057, 0x00ad6597, 0x00ad602b, 0x00ad5ac1,
                0x015ac057, 0x00ad602b, 0x0056b016, 0x02f4, 0x015b      },
-       {       20250000, BANDWIDTH_7_MHZ,
+       {       20250000, 7000000,
                0x03291620, 0x01948b10, 0x00ca4bda, 0x00ca4588, 0x00ca3f36,
                0x01948b10, 0x00ca4588, 0x006522c4, 0x0288, 0x0195      },
-       {       20250000, BANDWIDTH_8_MHZ,
+       {       20250000, 8000000,
                0x039cab92, 0x01ce55c9, 0x00e7321e, 0x00e72ae4, 0x00e723ab,
                0x01ce55c9, 0x00e72ae4, 0x00739572, 0x0237, 0x01ce      },
-       {       20250000, BANDWIDTH_5_MHZ,
+       {       20250000, 5000000,
                0x0241eb3b, 0x0120f59e, 0x00907f53, 0x00907acf, 0x0090764b,
                0x0120f59e, 0x00907acf, 0x00483d67, 0x038b, 0x0121      }
 
 };
 
 static struct adctable tab4[] = {
-       {       20583333, BANDWIDTH_6_MHZ,
+       {       20583333, 6000000,
                0x02aa4598, 0x015522cc, 0x00aa96bb, 0x00aa9166, 0x00aa8c12,
                0x015522cc, 0x00aa9166, 0x005548b3, 0x0300, 0x0155      },
-       {       20583333, BANDWIDTH_7_MHZ,
+       {       20583333, 7000000,
                0x031bfbdc, 0x018dfdee, 0x00c7052f, 0x00c6fef7, 0x00c6f8bf,
                0x018dfdee, 0x00c6fef7, 0x00637f7b, 0x0293, 0x018e      },
-       {       20583333, BANDWIDTH_8_MHZ,
+       {       20583333, 8000000,
                0x038db21f, 0x01c6d910, 0x00e373a3, 0x00e36c88, 0x00e3656d,
                0x01c6d910, 0x00e36c88, 0x0071b644, 0x0240, 0x01c7      },
-       {       20583333, BANDWIDTH_5_MHZ,
+       {       20583333, 5000000,
                0x02388f54, 0x011c47aa, 0x008e2846, 0x008e23d5, 0x008e1f64,
                0x011c47aa, 0x008e23d5, 0x004711ea, 0x039a, 0x011c      }
 
 };
 
 static struct adctable tab5[] = {
-       {       20416667, BANDWIDTH_6_MHZ,
+       {       20416667, 6000000,
                0x02afd765, 0x0157ebb3, 0x00abfb39, 0x00abf5d9, 0x00abf07a,
                0x0157ebb3, 0x00abf5d9, 0x0055faed, 0x02fa, 0x0158      },
-       {       20416667, BANDWIDTH_7_MHZ,
+       {       20416667, 7000000,
                0x03227b4b, 0x01913da6, 0x00c8a518, 0x00c89ed3, 0x00c8988e,
                0x01913da6, 0x00c89ed3, 0x00644f69, 0x028d, 0x0191      },
-       {       20416667, BANDWIDTH_8_MHZ,
+       {       20416667, 8000000,
                0x03951f32, 0x01ca8f99, 0x00e54ef7, 0x00e547cc, 0x00e540a2,
                0x01ca8f99, 0x00e547cc, 0x0072a3e6, 0x023c, 0x01cb      },
-       {       20416667, BANDWIDTH_5_MHZ,
+       {       20416667, 5000000,
                0x023d337f, 0x011e99c0, 0x008f515a, 0x008f4ce0, 0x008f4865,
                0x011e99c0, 0x008f4ce0, 0x0047a670, 0x0393, 0x011f      }
 
 };
 
 static struct adctable tab6[] = {
-       {       20480000, BANDWIDTH_6_MHZ,
+       {       20480000, 6000000,
                0x02adb6db, 0x0156db6e, 0x00ab7312, 0x00ab6db7, 0x00ab685c,
                0x0156db6e, 0x00ab6db7, 0x0055b6db, 0x02fd, 0x0157      },
-       {       20480000, BANDWIDTH_7_MHZ,
+       {       20480000, 7000000,
                0x03200000, 0x01900000, 0x00c80640, 0x00c80000, 0x00c7f9c0,
                0x01900000, 0x00c80000, 0x00640000, 0x028f, 0x0190      },
-       {       20480000, BANDWIDTH_8_MHZ,
+       {       20480000, 8000000,
                0x03924925, 0x01c92492, 0x00e4996e, 0x00e49249, 0x00e48b25,
                0x01c92492, 0x00e49249, 0x00724925, 0x023d, 0x01c9      },
-       {       20480000, BANDWIDTH_5_MHZ,
+       {       20480000, 5000000,
                0x023b6db7, 0x011db6db, 0x008edfe5, 0x008edb6e, 0x008ed6f7,
                0x011db6db, 0x008edb6e, 0x00476db7, 0x0396, 0x011e      }
 };
 
 static struct adctable tab7[] = {
-       {       20500000, BANDWIDTH_6_MHZ,
+       {       20500000, 6000000,
                0x02ad0b99, 0x015685cc, 0x00ab4840, 0x00ab42e6, 0x00ab3d8c,
                0x015685cc, 0x00ab42e6, 0x0055a173, 0x02fd, 0x0157      },
-       {       20500000, BANDWIDTH_7_MHZ,
+       {       20500000, 7000000,
                0x031f3832, 0x018f9c19, 0x00c7d44b, 0x00c7ce0c, 0x00c7c7ce,
                0x018f9c19, 0x00c7ce0c, 0x0063e706, 0x0290, 0x0190      },
-       {       20500000, BANDWIDTH_8_MHZ,
+       {       20500000, 8000000,
                0x039164cb, 0x01c8b266, 0x00e46056, 0x00e45933, 0x00e45210,
                0x01c8b266, 0x00e45933, 0x00722c99, 0x023e, 0x01c9      },
-       {       20500000, BANDWIDTH_5_MHZ,
+       {       20500000, 5000000,
                0x023adeff, 0x011d6f80, 0x008ebc36, 0x008eb7c0, 0x008eb34a,
                0x011d6f80, 0x008eb7c0, 0x00475be0, 0x0396, 0x011d      }
 
 };
 
 static struct adctable tab8[] = {
-       {       20625000, BANDWIDTH_6_MHZ,
+       {       20625000, 6000000,
                0x02a8e4bd, 0x0154725e, 0x00aa3e81, 0x00aa392f, 0x00aa33de,
                0x0154725e, 0x00aa392f, 0x00551c98, 0x0302, 0x0154      },
-       {       20625000, BANDWIDTH_7_MHZ,
+       {       20625000, 7000000,
                0x031a6032, 0x018d3019, 0x00c69e41, 0x00c6980c, 0x00c691d8,
                0x018d3019, 0x00c6980c, 0x00634c06, 0x0294, 0x018d      },
-       {       20625000, BANDWIDTH_8_MHZ,
+       {       20625000, 8000000,
                0x038bdba6, 0x01c5edd3, 0x00e2fe02, 0x00e2f6ea, 0x00e2efd2,
                0x01c5edd3, 0x00e2f6ea, 0x00717b75, 0x0242, 0x01c6      },
-       {       20625000, BANDWIDTH_5_MHZ,
+       {       20625000, 5000000,
                0x02376948, 0x011bb4a4, 0x008ddec1, 0x008dda52, 0x008dd5e3,
                0x011bb4a4, 0x008dda52, 0x0046ed29, 0x039c, 0x011c      }
 
@@ -153,8 +153,7 @@ struct table {
 };
 
 static struct table fe_clockTable[] = {
-               {12000000, tab3},       /* FPGA     */
-               {16384000, tab6},       /* 16.38MHz */
+               {12000000, tab3},       /* 12.00MHz */
                {20480000, tab6},       /* 20.48MHz */
                {36000000, tab3},       /* 36.00MHz */
                {30000000, tab1},       /* 30.00MHz */
@@ -164,7 +163,6 @@ static struct table fe_clockTable[] = {
                {34000000, tab2},       /* 34.00MHz */
                {24000000, tab1},       /* 24.00MHz */
                {22000000, tab8},       /* 22.00MHz */
-               {12000000, tab3}        /* 12.00MHz */
 };
 
 /* fe get */
@@ -205,6 +203,10 @@ fe_modulation_t fe_con[] = {
 
 /* Standard demodulator functions */
 static struct it913xset set_solo_fe[] = {
+       {PRO_LINK, GPIOH5_EN, {0x01}, 0x01},
+       {PRO_LINK, GPIOH5_ON, {0x01}, 0x01},
+       {PRO_LINK, GPIOH5_O, {0x00}, 0x01},
+       {PRO_LINK, GPIOH5_O, {0x01}, 0x01},
        {PRO_LINK, DVBT_INTEN, {0x04}, 0x01},
        {PRO_LINK, DVBT_ENABLE, {0x05}, 0x01},
        {PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01},
@@ -228,13 +230,127 @@ static struct it913xset init_1[] = {
        {PRO_LINK, LOCK3_OUT, {0x01}, 0x01},
        {PRO_LINK, PADMISCDRSR, {0x01}, 0x01},
        {PRO_LINK, PADMISCDR2, {0x00}, 0x01},
+       {PRO_DMOD, 0xec57, {0x00, 0x00}, 0x02},
        {PRO_LINK, PADMISCDR4, {0x00}, 0x01}, /* Power up */
        {PRO_LINK, PADMISCDR8, {0x00}, 0x01},
        {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
 };
 
-/* ---------IT9137 0x38 tuner init---------- */
-static struct it913xset it9137_set[] = {
+
+/* Version 1 types */
+static struct it913xset it9135_v1[] = {
+       {PRO_DMOD, 0x0051, {0x01}, 0x01},
+       {PRO_DMOD, 0x0070, {0x0a}, 0x01},
+       {PRO_DMOD, 0x007e, {0x04}, 0x01},
+       {PRO_DMOD, 0x0081, {0x0a}, 0x01},
+       {PRO_DMOD, 0x008a, {0x01}, 0x01},
+       {PRO_DMOD, 0x008e, {0x01}, 0x01},
+       {PRO_DMOD, 0x0092, {0x06}, 0x01},
+       {PRO_DMOD, 0x0099, {0x01}, 0x01},
+       {PRO_DMOD, 0x009f, {0xe1}, 0x01},
+       {PRO_DMOD, 0x00a0, {0xcf}, 0x01},
+       {PRO_DMOD, 0x00a3, {0x01}, 0x01},
+       {PRO_DMOD, 0x00a5, {0x01}, 0x01},
+       {PRO_DMOD, 0x00a6, {0x01}, 0x01},
+       {PRO_DMOD, 0x00a9, {0x00}, 0x01},
+       {PRO_DMOD, 0x00aa, {0x01}, 0x01},
+       {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+       {PRO_DMOD, 0x00c2, {0x05}, 0x01},
+       {PRO_DMOD, 0x00c6, {0x19}, 0x01},
+       {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+       {PRO_DMOD, 0xf016, {0x10}, 0x01},
+       {PRO_DMOD, 0xf017, {0x04}, 0x01},
+       {PRO_DMOD, 0xf018, {0x05}, 0x01},
+       {PRO_DMOD, 0xf019, {0x04}, 0x01},
+       {PRO_DMOD, 0xf01a, {0x05}, 0x01},
+       {PRO_DMOD, 0xf021, {0x03}, 0x01},
+       {PRO_DMOD, 0xf022, {0x0a}, 0x01},
+       {PRO_DMOD, 0xf023, {0x0a}, 0x01},
+       {PRO_DMOD, 0xf02b, {0x00}, 0x01},
+       {PRO_DMOD, 0xf02c, {0x01}, 0x01},
+       {PRO_DMOD, 0xf064, {0x03}, 0x01},
+       {PRO_DMOD, 0xf065, {0xf9}, 0x01},
+       {PRO_DMOD, 0xf066, {0x03}, 0x01},
+       {PRO_DMOD, 0xf067, {0x01}, 0x01},
+       {PRO_DMOD, 0xf06f, {0xe0}, 0x01},
+       {PRO_DMOD, 0xf070, {0x03}, 0x01},
+       {PRO_DMOD, 0xf072, {0x0f}, 0x01},
+       {PRO_DMOD, 0xf073, {0x03}, 0x01},
+       {PRO_DMOD, 0xf078, {0x00}, 0x01},
+       {PRO_DMOD, 0xf087, {0x00}, 0x01},
+       {PRO_DMOD, 0xf09b, {0x3f}, 0x01},
+       {PRO_DMOD, 0xf09c, {0x00}, 0x01},
+       {PRO_DMOD, 0xf09d, {0x20}, 0x01},
+       {PRO_DMOD, 0xf09e, {0x00}, 0x01},
+       {PRO_DMOD, 0xf09f, {0x0c}, 0x01},
+       {PRO_DMOD, 0xf0a0, {0x00}, 0x01},
+       {PRO_DMOD, 0xf130, {0x04}, 0x01},
+       {PRO_DMOD, 0xf132, {0x04}, 0x01},
+       {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+       {PRO_DMOD, 0xf146, {0x00}, 0x01},
+       {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+       {PRO_DMOD, 0xf14c, {0x00}, 0x01},
+       {PRO_DMOD, 0xf14d, {0x00}, 0x01},
+       {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+       {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+       {PRO_DMOD, 0xf15a, {0x00}, 0x01},
+       {PRO_DMOD, 0xf15b, {0x08}, 0x01},
+       {PRO_DMOD, 0xf15d, {0x03}, 0x01},
+       {PRO_DMOD, 0xf15e, {0x05}, 0x01},
+       {PRO_DMOD, 0xf163, {0x05}, 0x01},
+       {PRO_DMOD, 0xf166, {0x01}, 0x01},
+       {PRO_DMOD, 0xf167, {0x40}, 0x01},
+       {PRO_DMOD, 0xf168, {0x0f}, 0x01},
+       {PRO_DMOD, 0xf17a, {0x00}, 0x01},
+       {PRO_DMOD, 0xf17b, {0x00}, 0x01},
+       {PRO_DMOD, 0xf183, {0x01}, 0x01},
+       {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+       {PRO_DMOD, 0xf1bc, {0x36}, 0x01},
+       {PRO_DMOD, 0xf1bd, {0x00}, 0x01},
+       {PRO_DMOD, 0xf1cb, {0xa0}, 0x01},
+       {PRO_DMOD, 0xf1cc, {0x01}, 0x01},
+       {PRO_DMOD, 0xf204, {0x10}, 0x01},
+       {PRO_DMOD, 0xf214, {0x00}, 0x01},
+       {PRO_DMOD, 0xf40e, {0x0a}, 0x01},
+       {PRO_DMOD, 0xf40f, {0x40}, 0x01},
+       {PRO_DMOD, 0xf410, {0x08}, 0x01},
+       {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+       {PRO_DMOD, 0xf561, {0x15}, 0x01},
+       {PRO_DMOD, 0xf562, {0x20}, 0x01},
+       {PRO_DMOD, 0xf5df, {0xfb}, 0x01},
+       {PRO_DMOD, 0xf5e0, {0x00}, 0x01},
+       {PRO_DMOD, 0xf5e3, {0x09}, 0x01},
+       {PRO_DMOD, 0xf5e4, {0x01}, 0x01},
+       {PRO_DMOD, 0xf5e5, {0x01}, 0x01},
+       {PRO_DMOD, 0xf5f8, {0x01}, 0x01},
+       {PRO_DMOD, 0xf5fd, {0x01}, 0x01},
+       {PRO_DMOD, 0xf600, {0x05}, 0x01},
+       {PRO_DMOD, 0xf601, {0x08}, 0x01},
+       {PRO_DMOD, 0xf602, {0x0b}, 0x01},
+       {PRO_DMOD, 0xf603, {0x0e}, 0x01},
+       {PRO_DMOD, 0xf604, {0x11}, 0x01},
+       {PRO_DMOD, 0xf605, {0x14}, 0x01},
+       {PRO_DMOD, 0xf606, {0x17}, 0x01},
+       {PRO_DMOD, 0xf607, {0x1f}, 0x01},
+       {PRO_DMOD, 0xf60e, {0x00}, 0x01},
+       {PRO_DMOD, 0xf60f, {0x04}, 0x01},
+       {PRO_DMOD, 0xf610, {0x32}, 0x01},
+       {PRO_DMOD, 0xf611, {0x10}, 0x01},
+       {PRO_DMOD, 0xf707, {0xfc}, 0x01},
+       {PRO_DMOD, 0xf708, {0x00}, 0x01},
+       {PRO_DMOD, 0xf709, {0x37}, 0x01},
+       {PRO_DMOD, 0xf70a, {0x00}, 0x01},
+       {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+       {PRO_DMOD, 0xf80f, {0x40}, 0x01},
+       {PRO_DMOD, 0xf810, {0x54}, 0x01},
+       {PRO_DMOD, 0xf811, {0x5a}, 0x01},
+       {PRO_DMOD, 0xf905, {0x01}, 0x01},
+       {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+       {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+       {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_38[] = {
        {PRO_DMOD, 0x0043, {0x00}, 0x01},
        {PRO_DMOD, 0x0046, {0x38}, 0x01},
        {PRO_DMOD, 0x0051, {0x01}, 0x01},
@@ -244,7 +360,7 @@ static struct it913xset it9137_set[] = {
        {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05},
        {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
        {PRO_DMOD, 0x0081, {    0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc8, 0xb8,
-                               0xd0, 0xc3, 0x01        }, 0x0a},
+                               0xd0, 0xc3, 0x01}, 0x0a},
        {PRO_DMOD, 0x008e, {0x01}, 0x01},
        {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
        {PRO_DMOD, 0x0099, {0x01}, 0x01},
@@ -262,15 +378,25 @@ static struct it913xset it9137_set[] = {
        {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
        {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
        {PRO_DMOD, 0x00fc, {    0x02, 0x02, 0x02, 0x09, 0x50, 0x7b, 0x77,
-                               0x00, 0x02, 0xc8, 0x05, 0x7b    }, 0x0c},
+                               0x00, 0x02, 0xc8, 0x05, 0x7b}, 0x0c},
        {PRO_DMOD, 0x0109, {0x02}, 0x01},
-       {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
-       {PRO_DMOD, 0x011a, {0xc8, 0x7b, 0xbc, 0xa0}, 0x04},
+       {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
+       {PRO_DMOD, 0x011a, {0xc8, 0x7b, 0x8a, 0xa0}, 0x04},
        {PRO_DMOD, 0x0122, {0x02, 0x18, 0xc3}, 0x03},
        {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
        {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
        {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05},
-       {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8}, 0x04},
+       {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8, 0x59}, 0x05},
+       {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+       {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
+       {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
+       {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
+       {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+       {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+       {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+       {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+       {PRO_DMOD, 0xf085, {0x00, 0x02, 0x00}, 0x03},
+       {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
        {PRO_DMOD, 0xf130, {0x04}, 0x01},
        {PRO_DMOD, 0xf132, {0x04}, 0x01},
        {PRO_DMOD, 0xf144, {0x1a}, 0x01},
@@ -301,7 +427,7 @@ static struct it913xset it9137_set[] = {
        {PRO_DMOD, 0xf5f8, {0x01}, 0x01},
        {PRO_DMOD, 0xf5fd, {0x01}, 0x01},
        {PRO_DMOD, 0xf600, {    0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
-                               0x1f    }, 0x08},
+                               0x1f}, 0x08},
        {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
        {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
        {PRO_DMOD, 0xf78b, {0x01}, 0x01},
@@ -309,21 +435,605 @@ static struct it913xset it9137_set[] = {
        {PRO_DMOD, 0xf905, {0x01}, 0x01},
        {PRO_DMOD, 0xfb06, {0x03}, 0x01},
        {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
-       {PRO_LINK, GPIOH5_EN, {0x01}, 0x01},
-       {PRO_LINK, GPIOH5_ON, {0x01}, 0x01},
-       {PRO_LINK, GPIOH5_O, {0x00}, 0x01},
-       {PRO_LINK, GPIOH5_O, {0x01}, 0x01},
-       {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+       {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_51[] = {
+       {PRO_DMOD, 0x0043, {0x00}, 0x01},
+       {PRO_DMOD, 0x0046, {0x51}, 0x01},
+       {PRO_DMOD, 0x0051, {0x01}, 0x01},
+       {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0x0068, {0x0a}, 0x01},
+       {PRO_DMOD, 0x0070, {0x0a, 0x06, 0x02}, 0x03},
+       {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05},
+       {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
+       {PRO_DMOD, 0x0081, {    0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc0, 0x96,
+                               0xcf, 0xc3, 0x01}, 0x0a},
+       {PRO_DMOD, 0x008e, {0x01}, 0x01},
+       {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+       {PRO_DMOD, 0x0099, {0x01}, 0x01},
+       {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+       {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+       {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
+       {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+       {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+       {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02},
+       {PRO_DMOD, 0x00b6, {0x14}, 0x01},
+       {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
+       {PRO_DMOD, 0x00c4, {0x00}, 0x01},
+       {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+       {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
+       {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
+       {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+       {PRO_DMOD, 0x00fc, {    0x03, 0x02, 0x02, 0x09, 0x50, 0x7a, 0x77,
+                               0x01, 0x02, 0xb0, 0x02, 0x7a}, 0x0c},
+       {PRO_DMOD, 0x0109, {0x02}, 0x01},
+       {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
+       {PRO_DMOD, 0x011a, {0xc0, 0x7a, 0xac, 0x8c}, 0x04},
+       {PRO_DMOD, 0x0122, {0x02, 0x70, 0xa4}, 0x03},
+       {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
+       {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
+       {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05},
+       {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc0, 0x59}, 0x05},
+       {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+       {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
+       {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
+       {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
+       {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+       {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+       {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+       {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+       {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03},
+       {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+       {PRO_DMOD, 0xf130, {0x04}, 0x01},
+       {PRO_DMOD, 0xf132, {0x04}, 0x01},
+       {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+       {PRO_DMOD, 0xf146, {0x00}, 0x01},
+       {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+       {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+       {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+       {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+       {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+       {PRO_DMOD, 0xf163, {0x05}, 0x01},
+       {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+       {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0xf183, {0x01}, 0x01},
+       {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+       {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+       {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+       {PRO_DMOD, 0xf204, {0x10}, 0x01},
+       {PRO_DMOD, 0xf214, {0x00}, 0x01},
+       {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+       {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+       {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+       {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+       {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+       {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+       {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
+       {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+       {PRO_DMOD, 0xf5f8, {0x01}, 0x01},
+       {PRO_DMOD, 0xf5fd, {0x01}, 0x01},
+       {PRO_DMOD, 0xf600, {    0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+                               0x1f}, 0x08},
+       {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+       {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+       {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+       {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+       {PRO_DMOD, 0xf905, {0x01}, 0x01},
+       {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+       {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+       {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_52[] = {
+       {PRO_DMOD, 0x0043, {0x00}, 0x01},
+       {PRO_DMOD, 0x0046, {0x52}, 0x01},
+       {PRO_DMOD, 0x0051, {0x01}, 0x01},
+       {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0x0068, {0x10}, 0x01},
+       {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+       {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xa0, 0x01}, 0x05},
+       {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02},
+       {PRO_DMOD, 0x0081, {    0x0a, 0x12, 0x03, 0x0a, 0x03, 0xb3, 0x97,
+                               0xc0, 0x9e, 0x01}, 0x0a},
+       {PRO_DMOD, 0x008e, {0x01}, 0x01},
+       {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+       {PRO_DMOD, 0x0099, {0x01}, 0x01},
+       {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+       {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+       {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04},
+       {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+       {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+       {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02},
+       {PRO_DMOD, 0x00b6, {0x14}, 0x01},
+       {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03},
+       {PRO_DMOD, 0x00c4, {0x00}, 0x01},
+       {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+       {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03},
+       {PRO_DMOD, 0x00f3, {0x05, 0x91, 0x8c}, 0x03},
+       {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+       {PRO_DMOD, 0x00fc, {    0x03, 0x02, 0x02, 0x09, 0x50, 0x74, 0x77,
+                               0x02, 0x02, 0xae, 0x02, 0x6e}, 0x0c},
+       {PRO_DMOD, 0x0109, {0x02}, 0x01},
+       {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04},
+       {PRO_DMOD, 0x011a, {0xcd, 0x62, 0xa4, 0x8c}, 0x04},
+       {PRO_DMOD, 0x0122, {0x03, 0x18, 0x9e}, 0x03},
+       {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02},
+       {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
+       {PRO_DMOD, 0x0137, {0x00, 0x00, 0x07, 0x00, 0x06}, 0x05},
+       {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xb6, 0x59}, 0x05},
+       {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+       {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05},
+       {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05},
+       {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04},
+       {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+       {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+       {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+       {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+       {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03},
+       {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+       {PRO_DMOD, 0xf130, {0x04}, 0x01},
+       {PRO_DMOD, 0xf132, {0x04}, 0x01},
+       {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+       {PRO_DMOD, 0xf146, {0x00}, 0x01},
+       {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+       {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+       {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+       {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+       {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+       {PRO_DMOD, 0xf163, {0x05}, 0x01},
+       {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+       {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0xf183, {0x01}, 0x01},
+       {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+       {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+       {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+       {PRO_DMOD, 0xf204, {0x10}, 0x01},
+       {PRO_DMOD, 0xf214, {0x00}, 0x01},
+       {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+       {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+       {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+       {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+       {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+       {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+       {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02},
+       {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+       {PRO_DMOD, 0xf5f8, {0x01}, 0x01},
+       {PRO_DMOD, 0xf5fd, {0x01}, 0x01},
+       {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+                               0x1f}, 0x08},
+       {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+       {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+       {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+       {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+       {PRO_DMOD, 0xf905, {0x01}, 0x01},
+       {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+       {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+       {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
 };
 
+/* Version 2 types */
+static struct it913xset it9135_v2[] = {
+       {PRO_DMOD, 0x0051, {0x01}, 0x01},
+       {PRO_DMOD, 0x0070, {0x0a}, 0x01},
+       {PRO_DMOD, 0x007e, {0x04}, 0x01},
+       {PRO_DMOD, 0x0081, {0x0a}, 0x01},
+       {PRO_DMOD, 0x008a, {0x01}, 0x01},
+       {PRO_DMOD, 0x008e, {0x01}, 0x01},
+       {PRO_DMOD, 0x0092, {0x06}, 0x01},
+       {PRO_DMOD, 0x0099, {0x01}, 0x01},
+       {PRO_DMOD, 0x009f, {0xe1}, 0x01},
+       {PRO_DMOD, 0x00a0, {0xcf}, 0x01},
+       {PRO_DMOD, 0x00a3, {0x01}, 0x01},
+       {PRO_DMOD, 0x00a5, {0x01}, 0x01},
+       {PRO_DMOD, 0x00a6, {0x01}, 0x01},
+       {PRO_DMOD, 0x00a9, {0x00}, 0x01},
+       {PRO_DMOD, 0x00aa, {0x01}, 0x01},
+       {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+       {PRO_DMOD, 0x00c2, {0x05}, 0x01},
+       {PRO_DMOD, 0x00c6, {0x19}, 0x01},
+       {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+       {PRO_DMOD, 0xf02b, {0x00}, 0x01},
+       {PRO_DMOD, 0xf064, {0x03}, 0x01},
+       {PRO_DMOD, 0xf065, {0xf9}, 0x01},
+       {PRO_DMOD, 0xf066, {0x03}, 0x01},
+       {PRO_DMOD, 0xf067, {0x01}, 0x01},
+       {PRO_DMOD, 0xf06f, {0xe0}, 0x01},
+       {PRO_DMOD, 0xf070, {0x03}, 0x01},
+       {PRO_DMOD, 0xf072, {0x0f}, 0x01},
+       {PRO_DMOD, 0xf073, {0x03}, 0x01},
+       {PRO_DMOD, 0xf078, {0x00}, 0x01},
+       {PRO_DMOD, 0xf087, {0x00}, 0x01},
+       {PRO_DMOD, 0xf09b, {0x3f}, 0x01},
+       {PRO_DMOD, 0xf09c, {0x00}, 0x01},
+       {PRO_DMOD, 0xf09d, {0x20}, 0x01},
+       {PRO_DMOD, 0xf09e, {0x00}, 0x01},
+       {PRO_DMOD, 0xf09f, {0x0c}, 0x01},
+       {PRO_DMOD, 0xf0a0, {0x00}, 0x01},
+       {PRO_DMOD, 0xf130, {0x04}, 0x01},
+       {PRO_DMOD, 0xf132, {0x04}, 0x01},
+       {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+       {PRO_DMOD, 0xf146, {0x00}, 0x01},
+       {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+       {PRO_DMOD, 0xf14c, {0x00}, 0x01},
+       {PRO_DMOD, 0xf14d, {0x00}, 0x01},
+       {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+       {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+       {PRO_DMOD, 0xf15a, {0x00}, 0x01},
+       {PRO_DMOD, 0xf15b, {0x08}, 0x01},
+       {PRO_DMOD, 0xf15d, {0x03}, 0x01},
+       {PRO_DMOD, 0xf15e, {0x05}, 0x01},
+       {PRO_DMOD, 0xf163, {0x05}, 0x01},
+       {PRO_DMOD, 0xf166, {0x01}, 0x01},
+       {PRO_DMOD, 0xf167, {0x40}, 0x01},
+       {PRO_DMOD, 0xf168, {0x0f}, 0x01},
+       {PRO_DMOD, 0xf17a, {0x00}, 0x01},
+       {PRO_DMOD, 0xf17b, {0x00}, 0x01},
+       {PRO_DMOD, 0xf183, {0x01}, 0x01},
+       {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+       {PRO_DMOD, 0xf1bc, {0x36}, 0x01},
+       {PRO_DMOD, 0xf1bd, {0x00}, 0x01},
+       {PRO_DMOD, 0xf1cb, {0xa0}, 0x01},
+       {PRO_DMOD, 0xf1cc, {0x01}, 0x01},
+       {PRO_DMOD, 0xf204, {0x10}, 0x01},
+       {PRO_DMOD, 0xf214, {0x00}, 0x01},
+       {PRO_DMOD, 0xf40e, {0x0a}, 0x01},
+       {PRO_DMOD, 0xf40f, {0x40}, 0x01},
+       {PRO_DMOD, 0xf410, {0x08}, 0x01},
+       {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+       {PRO_DMOD, 0xf561, {0x15}, 0x01},
+       {PRO_DMOD, 0xf562, {0x20}, 0x01},
+       {PRO_DMOD, 0xf5e3, {0x09}, 0x01},
+       {PRO_DMOD, 0xf5e4, {0x01}, 0x01},
+       {PRO_DMOD, 0xf5e5, {0x01}, 0x01},
+       {PRO_DMOD, 0xf600, {0x05}, 0x01},
+       {PRO_DMOD, 0xf601, {0x08}, 0x01},
+       {PRO_DMOD, 0xf602, {0x0b}, 0x01},
+       {PRO_DMOD, 0xf603, {0x0e}, 0x01},
+       {PRO_DMOD, 0xf604, {0x11}, 0x01},
+       {PRO_DMOD, 0xf605, {0x14}, 0x01},
+       {PRO_DMOD, 0xf606, {0x17}, 0x01},
+       {PRO_DMOD, 0xf607, {0x1f}, 0x01},
+       {PRO_DMOD, 0xf60e, {0x00}, 0x01},
+       {PRO_DMOD, 0xf60f, {0x04}, 0x01},
+       {PRO_DMOD, 0xf610, {0x32}, 0x01},
+       {PRO_DMOD, 0xf611, {0x10}, 0x01},
+       {PRO_DMOD, 0xf707, {0xfc}, 0x01},
+       {PRO_DMOD, 0xf708, {0x00}, 0x01},
+       {PRO_DMOD, 0xf709, {0x37}, 0x01},
+       {PRO_DMOD, 0xf70a, {0x00}, 0x01},
+       {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+       {PRO_DMOD, 0xf80f, {0x40}, 0x01},
+       {PRO_DMOD, 0xf810, {0x54}, 0x01},
+       {PRO_DMOD, 0xf811, {0x5a}, 0x01},
+       {PRO_DMOD, 0xf905, {0x01}, 0x01},
+       {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+       {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+       {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_60[] = {
+       {PRO_DMOD, 0x0043, {0x00}, 0x01},
+       {PRO_DMOD, 0x0046, {0x60}, 0x01},
+       {PRO_DMOD, 0x0051, {0x01}, 0x01},
+       {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0x0068, {0x0a}, 0x01},
+       {PRO_DMOD, 0x006a, {0x03}, 0x01},
+       {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+       {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05},
+       {PRO_DMOD, 0x007e, {0x04}, 0x01},
+       {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
+       {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbe, 0xa0, 0xc6, 0xb6, 0x01}, 0x07},
+       {PRO_DMOD, 0x008e, {0x01}, 0x01},
+       {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+       {PRO_DMOD, 0x0099, {0x01}, 0x01},
+       {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+       {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+       {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
+       {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+       {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+       {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
+       {PRO_DMOD, 0x00b6, {0x14}, 0x01},
+       {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
+       {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+       {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
+       {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03},
+       {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+       {PRO_DMOD, 0x00fc, {    0x03, 0x03, 0x02, 0x0a, 0x50, 0x7b, 0x8c,
+                               0x00, 0x02, 0xbe, 0x00}, 0x0b},
+       {PRO_DMOD, 0x0109, {0x02}, 0x01},
+       {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
+       {PRO_DMOD, 0x011a, {0xbe}, 0x01},
+       {PRO_DMOD, 0x0124, {0xae}, 0x01},
+       {PRO_DMOD, 0x0127, {0x00}, 0x01},
+       {PRO_DMOD, 0x012a, {0x56, 0x50, 0x47, 0x42}, 0x04},
+       {PRO_DMOD, 0x0137, {0x00}, 0x01},
+       {PRO_DMOD, 0x013b, {0x08}, 0x01},
+       {PRO_DMOD, 0x013f, {0x5b}, 0x01},
+       {PRO_DMOD, 0x0141, {    0x59, 0xf9, 0x19, 0x19, 0x8c, 0x8c, 0x8c,
+                               0x6e, 0x8c, 0x50, 0x8c, 0x8c, 0xac, 0xc6,
+                               0x33}, 0x0f},
+       {PRO_DMOD, 0x0151, {0x28}, 0x01},
+       {PRO_DMOD, 0x0153, {0xbc}, 0x01},
+       {PRO_DMOD, 0x0178, {0x09}, 0x01},
+       {PRO_DMOD, 0x0181, {0x94, 0x6e}, 0x02},
+       {PRO_DMOD, 0x0185, {0x24}, 0x01},
+       {PRO_DMOD, 0x0187, {0x00, 0x00, 0xbe, 0x02, 0x80}, 0x05},
+       {PRO_DMOD, 0xed02, {0xff}, 0x01},
+       {PRO_DMOD, 0xee42, {0xff}, 0x01},
+       {PRO_DMOD, 0xee82, {0xff}, 0x01},
+       {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+       {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
+       {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
+       {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+       {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+       {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+       {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+       {PRO_DMOD, 0xf087, {0x00}, 0x01},
+       {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+       {PRO_DMOD, 0xf130, {0x04}, 0x01},
+       {PRO_DMOD, 0xf132, {0x04}, 0x01},
+       {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+       {PRO_DMOD, 0xf146, {0x00}, 0x01},
+       {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+       {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+       {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+       {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+       {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+       {PRO_DMOD, 0xf163, {0x05}, 0x01},
+       {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+       {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0xf183, {0x01}, 0x01},
+       {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+       {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+       {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+       {PRO_DMOD, 0xf204, {0x10}, 0x01},
+       {PRO_DMOD, 0xf214, {0x00}, 0x01},
+       {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+       {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+       {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+       {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+       {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+       {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+       {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+       {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17
+               , 0x1f}, 0x08},
+       {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+       {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+       {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+       {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+       {PRO_DMOD, 0xf905, {0x01}, 0x01},
+       {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+       {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+       {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_61[] = {
+       {PRO_DMOD, 0x0043, {0x00}, 0x01},
+       {PRO_DMOD, 0x0046, {0x61}, 0x01},
+       {PRO_DMOD, 0x0051, {0x01}, 0x01},
+       {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0x0068, {0x06}, 0x01},
+       {PRO_DMOD, 0x006a, {0x03}, 0x01},
+       {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+       {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x90, 0x01}, 0x05},
+       {PRO_DMOD, 0x007e, {0x04}, 0x01},
+       {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
+       {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbc, 0x9c, 0xcc, 0xa8, 0x01}, 0x07},
+       {PRO_DMOD, 0x008e, {0x01}, 0x01},
+       {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+       {PRO_DMOD, 0x0099, {0x01}, 0x01},
+       {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+       {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+       {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04},
+       {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+       {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+       {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
+       {PRO_DMOD, 0x00b6, {0x14}, 0x01},
+       {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
+       {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+       {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
+       {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03},
+       {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+       {PRO_DMOD, 0x00fc, {    0x03, 0x03, 0x02, 0x08, 0x50, 0x7b, 0x8c,
+                               0x01, 0x02, 0xc8, 0x00}, 0x0b},
+       {PRO_DMOD, 0x0109, {0x02}, 0x01},
+       {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
+       {PRO_DMOD, 0x011a, {0xc6}, 0x01},
+       {PRO_DMOD, 0x0124, {0xa8}, 0x01},
+       {PRO_DMOD, 0x0127, {0x00}, 0x01},
+       {PRO_DMOD, 0x012a, {0x59, 0x50, 0x47, 0x42}, 0x04},
+       {PRO_DMOD, 0x0137, {0x00}, 0x01},
+       {PRO_DMOD, 0x013b, {0x05}, 0x01},
+       {PRO_DMOD, 0x013f, {0x5b}, 0x01},
+       {PRO_DMOD, 0x0141, {    0x59, 0xf9, 0x59, 0x59, 0x8c, 0x8c, 0x8c,
+                               0x7b, 0x8c, 0x50, 0x8c, 0x8c, 0xa8, 0xc6,
+                               0x33}, 0x0f},
+       {PRO_DMOD, 0x0151, {0x28}, 0x01},
+       {PRO_DMOD, 0x0153, {0xcc}, 0x01},
+       {PRO_DMOD, 0x0178, {0x09}, 0x01},
+       {PRO_DMOD, 0x0181, {0x9c, 0x76}, 0x02},
+       {PRO_DMOD, 0x0185, {0x28}, 0x01},
+       {PRO_DMOD, 0x0187, {0x01, 0x00, 0xaa, 0x02, 0x80}, 0x05},
+       {PRO_DMOD, 0xed02, {0xff}, 0x01},
+       {PRO_DMOD, 0xee42, {0xff}, 0x01},
+       {PRO_DMOD, 0xee82, {0xff}, 0x01},
+       {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+       {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
+       {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
+       {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+       {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+       {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+       {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+       {PRO_DMOD, 0xf087, {0x00}, 0x01},
+       {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+       {PRO_DMOD, 0xf130, {0x04}, 0x01},
+       {PRO_DMOD, 0xf132, {0x04}, 0x01},
+       {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+       {PRO_DMOD, 0xf146, {0x00}, 0x01},
+       {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+       {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+       {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+       {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+       {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+       {PRO_DMOD, 0xf163, {0x05}, 0x01},
+       {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+       {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0xf183, {0x01}, 0x01},
+       {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+       {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+       {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+       {PRO_DMOD, 0xf204, {0x10}, 0x01},
+       {PRO_DMOD, 0xf214, {0x00}, 0x01},
+       {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+       {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+       {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+       {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+       {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+       {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+       {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+       {PRO_DMOD, 0xf600, {    0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+                               0x1f}, 0x08},
+       {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+       {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+       {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+       {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+       {PRO_DMOD, 0xf905, {0x01}, 0x01},
+       {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+       {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+       {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+static struct it913xset it9135_62[] = {
+       {PRO_DMOD, 0x0043, {0x00}, 0x01},
+       {PRO_DMOD, 0x0046, {0x62}, 0x01},
+       {PRO_DMOD, 0x0051, {0x01}, 0x01},
+       {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0x0068, {0x0a}, 0x01},
+       {PRO_DMOD, 0x006a, {0x03}, 0x01},
+       {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03},
+       {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05},
+       {PRO_DMOD, 0x007e, {0x04}, 0x01},
+       {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02},
+       {PRO_DMOD, 0x0084, {    0x0a, 0x33, 0xb8, 0x9c, 0xb2, 0xa6, 0x01},
+                               0x07},
+       {PRO_DMOD, 0x008e, {0x01}, 0x01},
+       {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05},
+       {PRO_DMOD, 0x0099, {0x01}, 0x01},
+       {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02},
+       {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02},
+       {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04},
+       {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02},
+       {PRO_DMOD, 0x00b0, {0x01}, 0x01},
+       {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02},
+       {PRO_DMOD, 0x00b6, {0x14}, 0x01},
+       {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05},
+       {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02},
+       {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04},
+       {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03},
+       {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03},
+       {PRO_DMOD, 0x00fc, {    0x02, 0x03, 0x02, 0x09, 0x50, 0x6e, 0x8c,
+                               0x02, 0x02, 0xc2, 0x00}, 0x0b},
+       {PRO_DMOD, 0x0109, {0x02}, 0x01},
+       {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02},
+       {PRO_DMOD, 0x011a, {0xb8}, 0x01},
+       {PRO_DMOD, 0x0124, {0xa8}, 0x01},
+       {PRO_DMOD, 0x0127, {0x00}, 0x01},
+       {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04},
+       {PRO_DMOD, 0x0137, {0x00}, 0x01},
+       {PRO_DMOD, 0x013b, {0x05}, 0x01},
+       {PRO_DMOD, 0x013f, {0x5b}, 0x01},
+       {PRO_DMOD, 0x0141, {    0x59, 0xf9, 0x59, 0x19, 0x8c, 0x8c, 0x8c,
+                               0x7b, 0x8c, 0x50, 0x70, 0x8c, 0x96, 0xd0,
+                               0x33}, 0x0f},
+       {PRO_DMOD, 0x0151, {0x28}, 0x01},
+       {PRO_DMOD, 0x0153, {0xb2}, 0x01},
+       {PRO_DMOD, 0x0178, {0x09}, 0x01},
+       {PRO_DMOD, 0x0181, {0x9c, 0x6e}, 0x02},
+       {PRO_DMOD, 0x0185, {0x24}, 0x01},
+       {PRO_DMOD, 0x0187, {0x00, 0x00, 0xb8, 0x02, 0x80}, 0x05},
+       {PRO_DMOD, 0xed02, {0xff}, 0x01},
+       {PRO_DMOD, 0xee42, {0xff}, 0x01},
+       {PRO_DMOD, 0xee82, {0xff}, 0x01},
+       {PRO_DMOD, 0xf000, {0x0f}, 0x01},
+       {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02},
+       {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03},
+       {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04},
+       {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02},
+       {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02},
+       {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02},
+       {PRO_DMOD, 0xf087, {0x00}, 0x01},
+       {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06},
+       {PRO_DMOD, 0xf130, {0x04}, 0x01},
+       {PRO_DMOD, 0xf132, {0x04}, 0x01},
+       {PRO_DMOD, 0xf144, {0x1a}, 0x01},
+       {PRO_DMOD, 0xf146, {0x00}, 0x01},
+       {PRO_DMOD, 0xf14a, {0x01}, 0x01},
+       {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0xf14f, {0x04}, 0x01},
+       {PRO_DMOD, 0xf158, {0x7f}, 0x01},
+       {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02},
+       {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02},
+       {PRO_DMOD, 0xf163, {0x05}, 0x01},
+       {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03},
+       {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02},
+       {PRO_DMOD, 0xf183, {0x01}, 0x01},
+       {PRO_DMOD, 0xf19d, {0x40}, 0x01},
+       {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02},
+       {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02},
+       {PRO_DMOD, 0xf204, {0x10}, 0x01},
+       {PRO_DMOD, 0xf214, {0x00}, 0x01},
+       {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04},
+       {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05},
+       {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04},
+       {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03},
+       {PRO_DMOD, 0xf55f, {0x0a}, 0x01},
+       {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02},
+       {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03},
+       {PRO_DMOD, 0xf600, {    0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17,
+                               0x1f}, 0x08},
+       {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04},
+       {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04},
+       {PRO_DMOD, 0xf78b, {0x01}, 0x01},
+       {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03},
+       {PRO_DMOD, 0xf905, {0x01}, 0x01},
+       {PRO_DMOD, 0xfb06, {0x03}, 0x01},
+       {PRO_DMOD, 0xfd8b, {0x00}, 0x01},
+       {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */
+};
+
+/* Tuner setting scripts (still keeping it9137) */
 static struct it913xset it9137_tuner_off[] = {
        {PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off  */
        {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */
        {PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04},
+       {PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00}, 0x0c},
+       {PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04},
+       {PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00}, 0x09},
+       {PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00}, 0x0a},
+       {PRO_DMOD, 0xec20, {0x00}, 0x01},
        {PRO_DMOD, 0xec3f, {0x01}, 0x01},
        {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
 };
 
+static struct it913xset set_it9135_template[] = {
+       {PRO_DMOD, 0xee06, {0x00}, 0x01},
+       {PRO_DMOD, 0xec56, {0x00}, 0x01},
+       {PRO_DMOD, 0xec4c, {0x00}, 0x01},
+       {PRO_DMOD, 0xec4d, {0x00}, 0x01},
+       {PRO_DMOD, 0xec4e, {0x00}, 0x01},
+       {PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */
+       {PRO_DMOD, 0x011f, {0x00}, 0x01},
+       {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+};
+
 static struct it913xset set_it9137_template[] = {
        {PRO_DMOD, 0xee06, {0x00}, 0x01},
        {PRO_DMOD, 0xec56, {0x00}, 0x01},
index d4bd24eb4700d36d612f674cc0793317f0d70ada..ccc36bf2deb403b3a7e769963e0659004d34f75d 100644 (file)
@@ -46,13 +46,17 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
          dprintk(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(format, arg...) \
+       printk(KERN_INFO "it913x-fe: " format "\n" , ## arg)
 
 struct it913x_fe_state {
        struct dvb_frontend frontend;
        struct i2c_adapter *i2c_adap;
+       struct ite_config *config;
        u8 i2c_addr;
        u32 frequency;
-       u8 adf;
+       fe_modulation_t constellation;
+       fe_transmit_mode_t transmission_mode;
        u32 crystalFrequency;
        u32 adcFrequency;
        u8 tuner_type;
@@ -62,6 +66,7 @@ struct it913x_fe_state {
        u8 tun_fdiv;
        u8 tun_clk_mode;
        u32 tun_fn_min;
+       u32 ucblocks;
 };
 
 static int it913x_read_reg(struct it913x_fe_state *state,
@@ -211,20 +216,24 @@ static int it913x_init_tuner(struct it913x_fe_state *state)
        state->tun_fn_min /= (state->tun_fdiv * nv_val);
        deb_info("Tuner fn_min %d", state->tun_fn_min);
 
-       for (i = 0; i < 50; i++) {
-               reg = it913x_read_reg_u8(state, 0xec82);
-               if (reg > 0)
-                       break;
-               if (reg < 0)
-                       return -ENODEV;
-               udelay(2000);
+       if (state->config->chip_ver > 1)
+               msleep(50);
+       else {
+               for (i = 0; i < 50; i++) {
+                       reg = it913x_read_reg_u8(state, 0xec82);
+                       if (reg > 0)
+                               break;
+                       if (reg < 0)
+                               return -ENODEV;
+                       udelay(2000);
+               }
        }
 
        return it913x_write_reg(state, PRO_DMOD, 0xed81, val);
 }
 
 static int it9137_set_tuner(struct it913x_fe_state *state,
-               enum fe_bandwidth bandwidth, u32 frequency_m)
+               u32 bandwidth, u32 frequency_m)
 {
        struct it913xset *set_tuner = set_it9137_template;
        int ret, reg;
@@ -237,6 +246,11 @@ static int it9137_set_tuner(struct it913x_fe_state *state,
        u8 lna_band;
        u8 bw;
 
+       if (state->config->firmware_ver == 1)
+               set_tuner = set_it9135_template;
+       else
+               set_tuner = set_it9137_template;
+
        deb_info("Tuner Frequency %d Bandwidth %d", frequency, bandwidth);
 
        if (frequency >= 51000 && frequency <= 440000) {
@@ -273,16 +287,21 @@ static int it9137_set_tuner(struct it913x_fe_state *state,
                return -EINVAL;
        set_tuner[0].reg[0] = lna_band;
 
-       if (bandwidth == BANDWIDTH_5_MHZ)
+       switch (bandwidth) {
+       case 5000000:
                bw = 0;
-       else if (bandwidth == BANDWIDTH_6_MHZ)
+               break;
+       case 6000000:
                bw = 2;
-       else if (bandwidth == BANDWIDTH_7_MHZ)
+               break;
+       case 7000000:
                bw = 4;
-       else if (bandwidth == BANDWIDTH_8_MHZ)
-               bw = 6;
-       else
+               break;
+       default:
+       case 8000000:
                bw = 6;
+               break;
+       }
 
        set_tuner[1].reg[0] = bw;
        set_tuner[2].reg[0] = 0xa0 | (l_band << 3);
@@ -361,7 +380,7 @@ static int it9137_set_tuner(struct it913x_fe_state *state,
 }
 
 static int it913x_fe_select_bw(struct it913x_fe_state *state,
-                       enum fe_bandwidth bandwidth, u32 adcFrequency)
+                       u32 bandwidth, u32 adcFrequency)
 {
        int ret, i;
        u8 buffer[256];
@@ -374,17 +393,21 @@ static int it913x_fe_select_bw(struct it913x_fe_state *state,
 
        deb_info("Bandwidth %d Adc %d", bandwidth, adcFrequency);
 
-       if (bandwidth == BANDWIDTH_5_MHZ)
+       switch (bandwidth) {
+       case 5000000:
                bw = 3;
-       else if (bandwidth == BANDWIDTH_6_MHZ)
+               break;
+       case 6000000:
                bw = 0;
-       else if (bandwidth == BANDWIDTH_7_MHZ)
+               break;
+       case 7000000:
                bw = 1;
-       else if (bandwidth == BANDWIDTH_8_MHZ)
-               bw = 2;
-       else
+               break;
+       default:
+       case 8000000:
                bw = 2;
-
+               break;
+       }
        ret = it913x_write_reg(state, PRO_DMOD, REG_BW, bw);
 
        if (state->table == NULL)
@@ -492,31 +515,79 @@ static int it913x_fe_read_signal_strength(struct dvb_frontend *fe,
        return 0;
 }
 
-static int it913x_fe_read_snr(struct dvb_frontend *fe, u16snr)
+static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
        struct it913x_fe_state *state = fe->demodulator_priv;
-       int ret = it913x_read_reg_u8(state, SIGNAL_QUALITY);
-       ret = (ret * 0xff) / 0x64;
-       ret |= (ret << 0x8);
-       *snr = ~ret;
-       return 0;
+       int ret;
+       u8 reg[3];
+       u32 snr_val, snr_min, snr_max;
+       u32 temp;
+
+       ret = it913x_read_reg(state, 0x2c, reg, sizeof(reg));
+
+       snr_val = (u32)(reg[2] << 16) | (reg[1] << 8) | reg[0];
+
+       ret |= it913x_read_reg(state, 0xf78b, reg, 1);
+       if (reg[0])
+               snr_val /= reg[0];
+
+       if (state->transmission_mode == TRANSMISSION_MODE_2K)
+               snr_val *= 4;
+       else if (state->transmission_mode == TRANSMISSION_MODE_4K)
+               snr_val *= 2;
+
+       if (state->constellation == QPSK) {
+               snr_min = 0xb4711;
+               snr_max = 0x191451;
+       } else if (state->constellation == QAM_16) {
+               snr_min = 0x4f0d5;
+               snr_max = 0xc7925;
+       } else if (state->constellation == QAM_64) {
+               snr_min = 0x256d0;
+               snr_max = 0x626be;
+       } else
+               return -EINVAL;
+
+       if (snr_val < snr_min)
+               *snr = 0;
+       else if (snr_val < snr_max) {
+               temp = (snr_val - snr_min) >> 5;
+               temp *= 0xffff;
+               temp /= (snr_max - snr_min) >> 5;
+               *snr = (u16)temp;
+       } else
+               *snr = 0xffff;
+
+       return (ret < 0) ? -ENODEV : 0;
 }
 
 static int it913x_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-       *ber = 0;
+       struct it913x_fe_state *state = fe->demodulator_priv;
+       int ret;
+       u8 reg[5];
+       /* Read Aborted Packets and Pre-Viterbi error rate 5 bytes */
+       ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
+       state->ucblocks += (u32)(reg[1] << 8) | reg[0];
+       *ber = (u32)(reg[4] << 16) | (reg[3] << 8) | reg[2];
        return 0;
 }
 
 static int it913x_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
-       *ucblocks = 0;
-       return 0;
+       struct it913x_fe_state *state = fe->demodulator_priv;
+       int ret;
+       u8 reg[2];
+       /* Aborted Packets */
+       ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
+       state->ucblocks += (u32)(reg[1] << 8) | reg[0];
+       *ucblocks = state->ucblocks;
+       return ret;
 }
 
-static int it913x_fe_get_frontend(struct dvb_frontend *fe,
-                       struct dvb_frontend_parameters *p)
+static int it913x_fe_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct it913x_fe_state *state = fe->demodulator_priv;
        int ret;
        u8 reg[8];
@@ -524,26 +595,30 @@ static int it913x_fe_get_frontend(struct dvb_frontend *fe,
        ret = it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg));
 
        if (reg[3] < 3)
-               p->u.ofdm.constellation = fe_con[reg[3]];
+               p->modulation = fe_con[reg[3]];
 
        if (reg[0] < 3)
-               p->u.ofdm.transmission_mode = fe_mode[reg[0]];
+               p->transmission_mode = fe_mode[reg[0]];
 
        if (reg[1] < 4)
-               p->u.ofdm.guard_interval = fe_gi[reg[1]];
+               p->guard_interval = fe_gi[reg[1]];
 
        if (reg[2] < 4)
-               p->u.ofdm.hierarchy_information = fe_hi[reg[2]];
+               p->hierarchy = fe_hi[reg[2]];
+
+       p->code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE;
+       p->code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE;
 
-       p->u.ofdm.code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE;
-       p->u.ofdm.code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE;
+       /* Update internal state to reflect the autodetected props */
+       state->constellation = p->modulation;
+       state->transmission_mode = p->transmission_mode;
 
        return 0;
 }
 
-static int it913x_fe_set_frontend(struct dvb_frontend *fe,
-                       struct dvb_frontend_parameters *p)
+static int it913x_fe_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct it913x_fe_state *state = fe->demodulator_priv;
        int ret, i;
        u8 empty_ch, last_ch;
@@ -551,7 +626,7 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe,
        state->it913x_status = 0;
 
        /* Set bw*/
-       ret = it913x_fe_select_bw(state, p->u.ofdm.bandwidth,
+       ret = it913x_fe_select_bw(state, p->bandwidth_hz,
                state->adcFrequency);
 
        /* Training Mode Off */
@@ -571,20 +646,25 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe,
                        i = 1;
        else if ((p->frequency >= 1450000000) && (p->frequency <= 1680000000))
                        i = 2;
-               else
-                       return -EOPNOTSUPP;
+       else
+               return -EOPNOTSUPP;
 
        ret = it913x_write_reg(state, PRO_DMOD, FREE_BAND, i);
 
        deb_info("Frontend Set Tuner Type %02x", state->tuner_type);
        switch (state->tuner_type) {
-       case IT9137: /* Tuner type 0x38 */
+       case IT9135_38:
+       case IT9135_51:
+       case IT9135_52:
+       case IT9135_60:
+       case IT9135_61:
+       case IT9135_62:
                ret = it9137_set_tuner(state,
-                       p->u.ofdm.bandwidth, p->frequency);
+                       p->bandwidth_hz, p->frequency);
                break;
        default:
                if (fe->ops.tuner_ops.set_params) {
-                       fe->ops.tuner_ops.set_params(fe, p);
+                       fe->ops.tuner_ops.set_params(fe);
                        if (fe->ops.i2c_gate_ctrl)
                                fe->ops.i2c_gate_ctrl(fe, 0);
                }
@@ -678,16 +758,19 @@ static u32 compute_div(u32 a, u32 b, u32 x)
 
 static int it913x_fe_start(struct it913x_fe_state *state)
 {
-       struct it913xset *set_fe;
+       struct it913xset *set_lna;
        struct it913xset *set_mode;
        int ret;
-       u8 adf = (state->adf & 0xf);
+       u8 adf = (state->config->adf & 0xf);
        u32 adc, xtal;
        u8 b[4];
 
-       ret = it913x_init_tuner(state);
+       if (state->config->chip_ver == 1)
+               ret = it913x_init_tuner(state);
+
+       info("ADF table value   :%02x", adf);
 
-       if (adf < 12) {
+       if (adf < 10) {
                state->crystalFrequency = fe_clockTable[adf].xtal ;
                state->table = fe_clockTable[adf].table;
                state->adcFrequency = state->table->adcFrequency;
@@ -698,9 +781,6 @@ static int it913x_fe_start(struct it913x_fe_state *state)
        } else
                return -EINVAL;
 
-       deb_info("Xtal Freq :%d Adc Freq :%d Adc %08x Xtal %08x",
-               state->crystalFrequency, state->adcFrequency, adc, xtal);
-
        /* Set LED indicator on GPIOH3 */
        ret = it913x_write_reg(state, PRO_LINK, GPIOH3_EN, 0x1);
        ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_ON, 0x1);
@@ -721,22 +801,71 @@ static int it913x_fe_start(struct it913x_fe_state *state)
        b[2] = (adc >> 16) & 0xff;
        ret |= it913x_write(state, PRO_DMOD, ADC_FREQ, b, 3);
 
+       if (state->config->adc_x2)
+               ret |= it913x_write_reg(state, PRO_DMOD, ADC_X_2, 0x01);
+       b[0] = 0;
+       b[1] = 0;
+       b[2] = 0;
+       ret |= it913x_write(state, PRO_DMOD, 0x0029, b, 3);
+
+       info("Crystal Frequency :%d Adc Frequency :%d ADC X2: %02x",
+               state->crystalFrequency, state->adcFrequency,
+                       state->config->adc_x2);
+       deb_info("Xtal value :%04x Adc value :%04x", xtal, adc);
+
+       if (ret < 0)
+               return -ENODEV;
+
+       /* v1 or v2 tuner script */
+       if (state->config->chip_ver > 1)
+               ret = it913x_fe_script_loader(state, it9135_v2);
+       else
+               ret = it913x_fe_script_loader(state, it9135_v1);
+       if (ret < 0)
+               return ret;
+
+       /* LNA Scripts */
        switch (state->tuner_type) {
-       case IT9137: /* Tuner type 0x38 */
-               set_fe = it9137_set;
+       case IT9135_51:
+               set_lna = it9135_51;
+               break;
+       case IT9135_52:
+               set_lna = it9135_52;
+               break;
+       case IT9135_60:
+               set_lna = it9135_60;
+               break;
+       case IT9135_61:
+               set_lna = it9135_61;
                break;
+       case IT9135_62:
+               set_lna = it9135_62;
+               break;
+       case IT9135_38:
        default:
-               return -EINVAL;
+               set_lna = it9135_38;
        }
+       info("Tuner LNA type :%02x", state->tuner_type);
+
+       ret = it913x_fe_script_loader(state, set_lna);
+       if (ret < 0)
+               return ret;
+
+       if (state->config->chip_ver == 2) {
+               ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1);
+               ret |= it913x_write_reg(state, PRO_LINK, PADODPU, 0x0);
+               ret |= it913x_write_reg(state, PRO_LINK, AGC_O_D, 0x0);
+               ret |= it913x_init_tuner(state);
+       }
+       if (ret < 0)
+               return -ENODEV;
 
-       /* set the demod */
-       ret = it913x_fe_script_loader(state, set_fe);
        /* Always solo frontend */
        set_mode = set_solo_fe;
        ret |= it913x_fe_script_loader(state, set_mode);
 
        ret |= it913x_fe_suspend(state);
-       return 0;
+       return (ret < 0) ? -ENODEV : 0;
 }
 
 static int it913x_fe_init(struct dvb_frontend *fe)
@@ -746,17 +875,11 @@ static int it913x_fe_init(struct dvb_frontend *fe)
        /* Power Up Tuner - common all versions */
        ret = it913x_write_reg(state, PRO_DMOD, 0xec40, 0x1);
 
-       ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0);
-
        ret |= it913x_fe_script_loader(state, init_1);
 
-       switch (state->tuner_type) {
-       case IT9137:
-               ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0);
-               break;
-       default:
-               return -EINVAL;
-       }
+       ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0);
+
+       ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0);
 
        return (ret < 0) ? -ENODEV : 0;
 }
@@ -770,19 +893,34 @@ static void it913x_fe_release(struct dvb_frontend *fe)
 static struct dvb_frontend_ops it913x_fe_ofdm_ops;
 
 struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
-               u8 i2c_addr, u8 adf, u8 type)
+               u8 i2c_addr, struct ite_config *config)
 {
        struct it913x_fe_state *state = NULL;
        int ret;
+
        /* allocate memory for the internal state */
        state = kzalloc(sizeof(struct it913x_fe_state), GFP_KERNEL);
        if (state == NULL)
+               return NULL;
+       if (config == NULL)
                goto error;
 
        state->i2c_adap = i2c_adap;
        state->i2c_addr = i2c_addr;
-       state->adf = adf;
-       state->tuner_type = type;
+       state->config = config;
+
+       switch (state->config->tuner_id_0) {
+       case IT9135_51:
+       case IT9135_52:
+       case IT9135_60:
+       case IT9135_61:
+       case IT9135_62:
+               state->tuner_type = state->config->tuner_id_0;
+               break;
+       default:
+       case IT9135_38:
+               state->tuner_type = IT9135_38;
+       }
 
        ret = it913x_fe_start(state);
        if (ret < 0)
@@ -802,10 +940,9 @@ error:
 EXPORT_SYMBOL(it913x_fe_attach);
 
 static struct dvb_frontend_ops it913x_fe_ofdm_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "it913x-fe DVB-T",
-               .type                   = FE_OFDM,
                .frequency_min          = 51000000,
                .frequency_max          = 1680000000,
                .frequency_stepsize     = 62500,
@@ -835,5 +972,5 @@ static struct dvb_frontend_ops it913x_fe_ofdm_ops = {
 
 MODULE_DESCRIPTION("it913x Frontend and it9137 tuner");
 MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
-MODULE_VERSION("1.07");
+MODULE_VERSION("1.13");
 MODULE_LICENSE("GPL");
index 9d97f32e690b4261ea5980b2b964b2f499eaeb42..c4a908e354e0d3528a4ca94d17a9865e6356fc76 100644 (file)
 
 #include <linux/dvb/frontend.h>
 #include "dvb_frontend.h"
+
+struct ite_config {
+       u8 chip_ver;
+       u16 chip_type;
+       u32 firmware;
+       u8 firmware_ver;
+       u8 adc_x2;
+       u8 tuner_id_0;
+       u8 tuner_id_1;
+       u8 dual_mode;
+       u8 adf;
+};
+
 #if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \
 defined(MODULE))
 extern struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
-                       u8 i2c_addr, u8 adf, u8 type);
+                       u8 i2c_addr, struct ite_config *config);
 #else
 static inline struct dvb_frontend *it913x_fe_attach(
-               struct i2c_adapter *i2c_adap,   u8 i2c_addr, u8 adf, u8 type)
+               struct i2c_adapter *i2c_adap,
+                       u8 i2c_addr, struct ite_config *config)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
@@ -134,6 +148,16 @@ static inline struct dvb_frontend *it913x_fe_attach(
 #define COEFF_1_2048           0x0001
 #define XTAL_CLK               0x0025
 #define BFS_FCW                        0x0029
+
+/* Error Regs */
+#define RSD_ABORT_PKT_LSB      0x0032
+#define RSD_ABORT_PKT_MSB      0x0033
+#define RSD_BIT_ERR_0_7                0x0034
+#define RSD_BIT_ERR_8_15       0x0035
+#define RSD_BIT_ERR_23_16      0x0036
+#define RSD_BIT_COUNT_LSB      0x0037
+#define RSD_BIT_COUNT_MSB      0x0038
+
 #define TPSD_LOCK              0x003c
 #define TRAINING_MODE          0x0040
 #define ADC_X_2                        0x0045
@@ -144,8 +168,14 @@ static inline struct dvb_frontend *it913x_fe_attach(
 #define EST_SIGNAL_LEVEL       0x004a
 #define FREE_BAND              0x004b
 #define SUSPEND_FLAG           0x004c
-/* Build in tuners */
+/* Build in tuner types */
 #define IT9137 0x38
+#define IT9135_38 0x38
+#define IT9135_51 0x51
+#define IT9135_52 0x52
+#define IT9135_60 0x60
+#define IT9135_61 0x61
+#define IT9135_62 0x62
 
 enum {
        CMD_DEMOD_READ = 0,
@@ -193,4 +223,11 @@ enum {
        WRITE_CMD,
 };
 
+enum {
+       IT9135_AUTO = 0,
+       IT9137_FW,
+       IT9135_V1_FW,
+       IT9135_V2_FW,
+};
+
 #endif /* IT913X_FE_H */
index aa9ccb821fa51fe9a6f8612c5cbb491f065f7c2f..316457584fe7a6fe7a18ae430fe1c194393dbf7c 100644 (file)
@@ -250,13 +250,14 @@ static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz)
        itd1000_set_vco(state, freq_khz);
 }
 
-static int itd1000_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int itd1000_set_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct itd1000_state *state = fe->tuner_priv;
        u8 pllcon1;
 
-       itd1000_set_lo(state, p->frequency);
-       itd1000_set_lpf_bw(state, p->u.qpsk.symbol_rate);
+       itd1000_set_lo(state, c->frequency);
+       itd1000_set_lpf_bw(state, c->symbol_rate);
 
        pllcon1 = itd1000_read_reg(state, PLLCON1) & 0x7f;
        itd1000_write_reg(state, PLLCON1, pllcon1 | (1 << 7));
index 9a517a4bf96dea9a61611ead392713bedf0d637c..bc5a82082aaae7891d55dd2cd3c6eabff93e9b84 100644 (file)
@@ -129,12 +129,12 @@ static int ix2505v_release(struct dvb_frontend *fe)
  *  1 -> 8 -> 6
  */
 
-static int ix2505v_set_params(struct dvb_frontend *fe,
-               struct dvb_frontend_parameters *params)
+static int ix2505v_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct ix2505v_state *state = fe->tuner_priv;
-       u32 frequency = params->frequency;
-       u32 b_w  = (params->u.qpsk.symbol_rate * 27) / 32000;
+       u32 frequency = c->frequency;
+       u32 b_w  = (c->symbol_rate * 27) / 32000;
        u32 div_factor, N , A, x;
        int ret = 0, len;
        u8 gain, cc, ref, psc, local_osc, lpf;
index 445fa10680644c9d546d5aa8644947e6b5587573..36fcf559e3619147da5dde357aba6267213357fa 100644 (file)
@@ -117,18 +117,17 @@ static int reset_and_configure (struct l64781_state* state)
        return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV;
 }
 
-static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_parameters *param)
+static int apply_frontend_param(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct l64781_state* state = fe->demodulator_priv;
        /* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */
        static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 };
        /* QPSK, QAM_16, QAM_64 */
        static const u8 qam_tab [] = { 2, 4, 0, 6 };
-       static const u8 bw_tab [] = { 8, 7, 6 };  /* 8Mhz, 7MHz, 6MHz */
        static const u8 guard_tab [] = { 1, 2, 4, 8 };
        /* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */
        static const u32 ppm = 8000;
-       struct dvb_ofdm_parameters *p = &param->u.ofdm;
        u32 ddfs_offset_fixed;
 /*     u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */
 /*                     bw_tab[p->bandWidth]<<10)/15625; */
@@ -137,18 +136,29 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
        u8 val0x04;
        u8 val0x05;
        u8 val0x06;
-       int bw = p->bandwidth - BANDWIDTH_8_MHZ;
+       int bw;
+
+       switch (p->bandwidth_hz) {
+       case 8000000:
+               bw = 8;
+               break;
+       case 7000000:
+               bw = 7;
+               break;
+       case 6000000:
+               bw = 6;
+               break;
+       default:
+               return -EINVAL;
+       }
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, param);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
-       if (param->inversion != INVERSION_ON &&
-           param->inversion != INVERSION_OFF)
-               return -EINVAL;
-
-       if (bw < 0 || bw > 2)
+       if (p->inversion != INVERSION_ON &&
+           p->inversion != INVERSION_OFF)
                return -EINVAL;
 
        if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 &&
@@ -156,14 +166,14 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
            p->code_rate_HP != FEC_7_8)
                return -EINVAL;
 
-       if (p->hierarchy_information != HIERARCHY_NONE &&
+       if (p->hierarchy != HIERARCHY_NONE &&
            (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 &&
             p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 &&
             p->code_rate_LP != FEC_7_8))
                return -EINVAL;
 
-       if (p->constellation != QPSK && p->constellation != QAM_16 &&
-           p->constellation != QAM_64)
+       if (p->modulation != QPSK && p->modulation != QAM_16 &&
+           p->modulation != QAM_64)
                return -EINVAL;
 
        if (p->transmission_mode != TRANSMISSION_MODE_2K &&
@@ -174,22 +184,22 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
            p->guard_interval > GUARD_INTERVAL_1_4)
                return -EINVAL;
 
-       if (p->hierarchy_information < HIERARCHY_NONE ||
-           p->hierarchy_information > HIERARCHY_4)
+       if (p->hierarchy < HIERARCHY_NONE ||
+           p->hierarchy > HIERARCHY_4)
                return -EINVAL;
 
-       ddfs_offset_fixed = 0x4000-(ppm<<16)/bw_tab[p->bandwidth]/1000000;
+       ddfs_offset_fixed = 0x4000-(ppm<<16)/bw/1000000;
 
        /* This works up to 20000 ppm, it overflows if too large ppm! */
        init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) /
-                       bw_tab[p->bandwidth] & 0xFFFFFF);
+                       bw & 0xFFFFFF);
 
        /* SPI bias calculation is slightly modified to fit in 32bit */
        /* will work for high ppm only... */
        spi_bias = 378 * (1 << 10);
        spi_bias *= 16;
-       spi_bias *= bw_tab[p->bandwidth];
-       spi_bias *= qam_tab[p->constellation];
+       spi_bias *= bw;
+       spi_bias *= qam_tab[p->modulation];
        spi_bias /= p->code_rate_HP + 1;
        spi_bias /= (guard_tab[p->guard_interval] + 32);
        spi_bias *= 1000;
@@ -199,10 +209,10 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
        val0x04 = (p->transmission_mode << 2) | p->guard_interval;
        val0x05 = fec_tab[p->code_rate_HP];
 
-       if (p->hierarchy_information != HIERARCHY_NONE)
+       if (p->hierarchy != HIERARCHY_NONE)
                val0x05 |= (p->code_rate_LP - FEC_1_2) << 3;
 
-       val0x06 = (p->hierarchy_information << 2) | p->constellation;
+       val0x06 = (p->hierarchy << 2) | p->modulation;
 
        l64781_writereg (state, 0x04, val0x04);
        l64781_writereg (state, 0x05, val0x05);
@@ -220,7 +230,7 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
        l64781_writereg (state, 0x1b, spi_bias & 0xff);
        l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff);
        l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) |
-               (param->inversion == INVERSION_ON ? 0x80 : 0x00));
+               (p->inversion == INVERSION_ON ? 0x80 : 0x00));
 
        l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff);
        l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f);
@@ -233,8 +243,9 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
        return 0;
 }
 
-static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* param)
+static int get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct l64781_state* state = fe->demodulator_priv;
        int tmp;
 
@@ -242,98 +253,95 @@ static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters*
        tmp = l64781_readreg(state, 0x04);
        switch(tmp & 3) {
        case 0:
-               param->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+               p->guard_interval = GUARD_INTERVAL_1_32;
                break;
        case 1:
-               param->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+               p->guard_interval = GUARD_INTERVAL_1_16;
                break;
        case 2:
-               param->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+               p->guard_interval = GUARD_INTERVAL_1_8;
                break;
        case 3:
-               param->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+               p->guard_interval = GUARD_INTERVAL_1_4;
                break;
        }
        switch((tmp >> 2) & 3) {
        case 0:
-               param->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+               p->transmission_mode = TRANSMISSION_MODE_2K;
                break;
        case 1:
-               param->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+               p->transmission_mode = TRANSMISSION_MODE_8K;
                break;
        default:
-               printk("Unexpected value for transmission_mode\n");
+               printk(KERN_WARNING "Unexpected value for transmission_mode\n");
        }
 
-
-
        tmp = l64781_readreg(state, 0x05);
        switch(tmp & 7) {
        case 0:
-               param->u.ofdm.code_rate_HP = FEC_1_2;
+               p->code_rate_HP = FEC_1_2;
                break;
        case 1:
-               param->u.ofdm.code_rate_HP = FEC_2_3;
+               p->code_rate_HP = FEC_2_3;
                break;
        case 2:
-               param->u.ofdm.code_rate_HP = FEC_3_4;
+               p->code_rate_HP = FEC_3_4;
                break;
        case 3:
-               param->u.ofdm.code_rate_HP = FEC_5_6;
+               p->code_rate_HP = FEC_5_6;
                break;
        case 4:
-               param->u.ofdm.code_rate_HP = FEC_7_8;
+               p->code_rate_HP = FEC_7_8;
                break;
        default:
                printk("Unexpected value for code_rate_HP\n");
        }
        switch((tmp >> 3) & 7) {
        case 0:
-               param->u.ofdm.code_rate_LP = FEC_1_2;
+               p->code_rate_LP = FEC_1_2;
                break;
        case 1:
-               param->u.ofdm.code_rate_LP = FEC_2_3;
+               p->code_rate_LP = FEC_2_3;
                break;
        case 2:
-               param->u.ofdm.code_rate_LP = FEC_3_4;
+               p->code_rate_LP = FEC_3_4;
                break;
        case 3:
-               param->u.ofdm.code_rate_LP = FEC_5_6;
+               p->code_rate_LP = FEC_5_6;
                break;
        case 4:
-               param->u.ofdm.code_rate_LP = FEC_7_8;
+               p->code_rate_LP = FEC_7_8;
                break;
        default:
                printk("Unexpected value for code_rate_LP\n");
        }
 
-
        tmp = l64781_readreg(state, 0x06);
        switch(tmp & 3) {
        case 0:
-               param->u.ofdm.constellation = QPSK;
+               p->modulation = QPSK;
                break;
        case 1:
-               param->u.ofdm.constellation = QAM_16;
+               p->modulation = QAM_16;
                break;
        case 2:
-               param->u.ofdm.constellation = QAM_64;
+               p->modulation = QAM_64;
                break;
        default:
-               printk("Unexpected value for constellation\n");
+               printk(KERN_WARNING "Unexpected value for modulation\n");
        }
        switch((tmp >> 2) & 7) {
        case 0:
-               param->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+               p->hierarchy = HIERARCHY_NONE;
                break;
        case 1:
-               param->u.ofdm.hierarchy_information = HIERARCHY_1;
+               p->hierarchy = HIERARCHY_1;
                break;
        case 2:
-               param->u.ofdm.hierarchy_information = HIERARCHY_2;
+               p->hierarchy = HIERARCHY_2;
                break;
        case 3:
-               param->u.ofdm.hierarchy_information = HIERARCHY_4;
+               p->hierarchy = HIERARCHY_4;
                break;
        default:
                printk("Unexpected value for hierarchy\n");
@@ -341,12 +349,12 @@ static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters*
 
 
        tmp = l64781_readreg (state, 0x1d);
-       param->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF;
+       p->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF;
 
        tmp = (int) (l64781_readreg (state, 0x08) |
                     (l64781_readreg (state, 0x09) << 8) |
                     (l64781_readreg (state, 0x0a) << 16));
-       param->frequency += tmp;
+       p->frequency += tmp;
 
        return 0;
 }
@@ -564,10 +572,9 @@ error:
 }
 
 static struct dvb_frontend_ops l64781_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name = "LSI L64781 DVB-T",
-               .type = FE_OFDM,
        /*      .frequency_min = ???,*/
        /*      .frequency_max = ???,*/
                .frequency_stepsize = 166666,
index 3272881cb112922e30d829c010b9fde5fc3fe4f4..1d2c47378cf856b392534dd2b4599de7d3ac344f 100644 (file)
@@ -266,7 +266,7 @@ fail:
 }
 
 static int lgdt3305_set_modulation(struct lgdt3305_state *state,
-                                  struct dvb_frontend_parameters *param)
+                                  struct dtv_frontend_properties *p)
 {
        u8 opermode;
        int ret;
@@ -279,7 +279,7 @@ static int lgdt3305_set_modulation(struct lgdt3305_state *state,
 
        opermode &= ~0x03;
 
-       switch (param->u.vsb.modulation) {
+       switch (p->modulation) {
        case VSB_8:
                opermode |= 0x03;
                break;
@@ -298,11 +298,11 @@ fail:
 }
 
 static int lgdt3305_set_filter_extension(struct lgdt3305_state *state,
-                                        struct dvb_frontend_parameters *param)
+                                        struct dtv_frontend_properties *p)
 {
        int val;
 
-       switch (param->u.vsb.modulation) {
+       switch (p->modulation) {
        case VSB_8:
                val = 0;
                break;
@@ -321,11 +321,11 @@ static int lgdt3305_set_filter_extension(struct lgdt3305_state *state,
 /* ------------------------------------------------------------------------ */
 
 static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state,
-                                        struct dvb_frontend_parameters *param)
+                                        struct dtv_frontend_properties *p)
 {
        u16 agc_ref;
 
-       switch (param->u.vsb.modulation) {
+       switch (p->modulation) {
        case VSB_8:
                agc_ref = 0x32c4;
                break;
@@ -348,11 +348,11 @@ static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state,
 }
 
 static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
-                              struct dvb_frontend_parameters *param)
+                              struct dtv_frontend_properties *p)
 {
        u16 ifbw, rfbw, agcdelay;
 
-       switch (param->u.vsb.modulation) {
+       switch (p->modulation) {
        case VSB_8:
                agcdelay = 0x04c0;
                rfbw     = 0x8000;
@@ -398,11 +398,11 @@ static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
 }
 
 static int lgdt3305_agc_setup(struct lgdt3305_state *state,
-                             struct dvb_frontend_parameters *param)
+                             struct dtv_frontend_properties *p)
 {
        int lockdten, acqen;
 
-       switch (param->u.vsb.modulation) {
+       switch (p->modulation) {
        case VSB_8:
                lockdten = 0;
                acqen = 0;
@@ -432,15 +432,15 @@ static int lgdt3305_agc_setup(struct lgdt3305_state *state,
                return -EINVAL;
        }
 
-       return lgdt3305_rfagc_loop(state, param);
+       return lgdt3305_rfagc_loop(state, p);
 }
 
 static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state,
-                                     struct dvb_frontend_parameters *param)
+                                     struct dtv_frontend_properties *p)
 {
        u16 usref = 0;
 
-       switch (param->u.vsb.modulation) {
+       switch (p->modulation) {
        case VSB_8:
                if (state->cfg->usref_8vsb)
                        usref = state->cfg->usref_8vsb;
@@ -473,14 +473,14 @@ static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state,
 /* ------------------------------------------------------------------------ */
 
 static int lgdt3305_spectral_inversion(struct lgdt3305_state *state,
-                                      struct dvb_frontend_parameters *param,
+                                      struct dtv_frontend_properties *p,
                                       int inversion)
 {
        int ret;
 
        lg_dbg("(%d)\n", inversion);
 
-       switch (param->u.vsb.modulation) {
+       switch (p->modulation) {
        case VSB_8:
                ret = lgdt3305_write_reg(state, LGDT3305_CR_CTRL_7,
                                         inversion ? 0xf9 : 0x79);
@@ -497,13 +497,13 @@ static int lgdt3305_spectral_inversion(struct lgdt3305_state *state,
 }
 
 static int lgdt3305_set_if(struct lgdt3305_state *state,
-                          struct dvb_frontend_parameters *param)
+                          struct dtv_frontend_properties *p)
 {
        u16 if_freq_khz;
        u8 nco1, nco2, nco3, nco4;
        u64 nco;
 
-       switch (param->u.vsb.modulation) {
+       switch (p->modulation) {
        case VSB_8:
                if_freq_khz = state->cfg->vsb_if_khz;
                break;
@@ -517,7 +517,7 @@ static int lgdt3305_set_if(struct lgdt3305_state *state,
 
        nco = if_freq_khz / 10;
 
-       switch (param->u.vsb.modulation) {
+       switch (p->modulation) {
        case VSB_8:
                nco <<= 24;
                do_div(nco, 625);
@@ -677,37 +677,37 @@ fail:
        return ret;
 }
 
-static int lgdt3304_set_parameters(struct dvb_frontend *fe,
-                                  struct dvb_frontend_parameters *param)
+static int lgdt3304_set_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct lgdt3305_state *state = fe->demodulator_priv;
        int ret;
 
-       lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation);
+       lg_dbg("(%d, %d)\n", p->frequency, p->modulation);
 
        if (fe->ops.tuner_ops.set_params) {
-               ret = fe->ops.tuner_ops.set_params(fe, param);
+               ret = fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
                if (lg_fail(ret))
                        goto fail;
-               state->current_frequency = param->frequency;
+               state->current_frequency = p->frequency;
        }
 
-       ret = lgdt3305_set_modulation(state, param);
+       ret = lgdt3305_set_modulation(state, p);
        if (lg_fail(ret))
                goto fail;
 
-       ret = lgdt3305_passband_digital_agc(state, param);
+       ret = lgdt3305_passband_digital_agc(state, p);
        if (lg_fail(ret))
                goto fail;
 
-       ret = lgdt3305_agc_setup(state, param);
+       ret = lgdt3305_agc_setup(state, p);
        if (lg_fail(ret))
                goto fail;
 
        /* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */
-       switch (param->u.vsb.modulation) {
+       switch (p->modulation) {
        case VSB_8:
                lgdt3305_write_reg(state, 0x030d, 0x00);
                lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f);
@@ -718,7 +718,7 @@ static int lgdt3304_set_parameters(struct dvb_frontend *fe,
        case QAM_64:
        case QAM_256:
                lgdt3305_write_reg(state, 0x030d, 0x14);
-               ret = lgdt3305_set_if(state, param);
+               ret = lgdt3305_set_if(state, p);
                if (lg_fail(ret))
                        goto fail;
                break;
@@ -727,13 +727,13 @@ static int lgdt3304_set_parameters(struct dvb_frontend *fe,
        }
 
 
-       ret = lgdt3305_spectral_inversion(state, param,
+       ret = lgdt3305_spectral_inversion(state, p,
                                          state->cfg->spectral_inversion
                                          ? 1 : 0);
        if (lg_fail(ret))
                goto fail;
 
-       state->current_modulation = param->u.vsb.modulation;
+       state->current_modulation = p->modulation;
 
        ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
        if (lg_fail(ret))
@@ -747,34 +747,34 @@ fail:
        return ret;
 }
 
-static int lgdt3305_set_parameters(struct dvb_frontend *fe,
-                                  struct dvb_frontend_parameters *param)
+static int lgdt3305_set_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct lgdt3305_state *state = fe->demodulator_priv;
        int ret;
 
-       lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation);
+       lg_dbg("(%d, %d)\n", p->frequency, p->modulation);
 
        if (fe->ops.tuner_ops.set_params) {
-               ret = fe->ops.tuner_ops.set_params(fe, param);
+               ret = fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
                if (lg_fail(ret))
                        goto fail;
-               state->current_frequency = param->frequency;
+               state->current_frequency = p->frequency;
        }
 
-       ret = lgdt3305_set_modulation(state, param);
+       ret = lgdt3305_set_modulation(state, p);
        if (lg_fail(ret))
                goto fail;
 
-       ret = lgdt3305_passband_digital_agc(state, param);
+       ret = lgdt3305_passband_digital_agc(state, p);
        if (lg_fail(ret))
                goto fail;
-       ret = lgdt3305_set_agc_power_ref(state, param);
+       ret = lgdt3305_set_agc_power_ref(state, p);
        if (lg_fail(ret))
                goto fail;
-       ret = lgdt3305_agc_setup(state, param);
+       ret = lgdt3305_agc_setup(state, p);
        if (lg_fail(ret))
                goto fail;
 
@@ -786,20 +786,20 @@ static int lgdt3305_set_parameters(struct dvb_frontend *fe,
        if (lg_fail(ret))
                goto fail;
 
-       ret = lgdt3305_set_if(state, param);
+       ret = lgdt3305_set_if(state, p);
        if (lg_fail(ret))
                goto fail;
-       ret = lgdt3305_spectral_inversion(state, param,
+       ret = lgdt3305_spectral_inversion(state, p,
                                          state->cfg->spectral_inversion
                                          ? 1 : 0);
        if (lg_fail(ret))
                goto fail;
 
-       ret = lgdt3305_set_filter_extension(state, param);
+       ret = lgdt3305_set_filter_extension(state, p);
        if (lg_fail(ret))
                goto fail;
 
-       state->current_modulation = param->u.vsb.modulation;
+       state->current_modulation = p->modulation;
 
        ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
        if (lg_fail(ret))
@@ -813,15 +813,15 @@ fail:
        return ret;
 }
 
-static int lgdt3305_get_frontend(struct dvb_frontend *fe,
-                                struct dvb_frontend_parameters *param)
+static int lgdt3305_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct lgdt3305_state *state = fe->demodulator_priv;
 
        lg_dbg("\n");
 
-       param->u.vsb.modulation = state->current_modulation;
-       param->frequency = state->current_frequency;
+       p->modulation = state->current_modulation;
+       p->frequency = state->current_frequency;
        return 0;
 }
 
@@ -1166,9 +1166,9 @@ fail:
 EXPORT_SYMBOL(lgdt3305_attach);
 
 static struct dvb_frontend_ops lgdt3304_ops = {
+       .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
        .info = {
                .name = "LG Electronics LGDT3304 VSB/QAM Frontend",
-               .type               = FE_ATSC,
                .frequency_min      = 54000000,
                .frequency_max      = 858000000,
                .frequency_stepsize = 62500,
@@ -1188,9 +1188,9 @@ static struct dvb_frontend_ops lgdt3304_ops = {
 };
 
 static struct dvb_frontend_ops lgdt3305_ops = {
+       .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
        .info = {
                .name = "LG Electronics LGDT3305 VSB/QAM Frontend",
-               .type               = FE_ATSC,
                .frequency_min      = 54000000,
                .frequency_max      = 858000000,
                .frequency_stepsize = 62500,
index 43971e63baa727c5a3c7de9cbc05dc4c8fc4207e..c990d35a13dcdf2617d7efb65d7ea782735b9939 100644 (file)
@@ -288,6 +288,8 @@ static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        int err;
        u8 buf[2];
 
+       *ucblocks = 0;
+
        switch (state->config->demod_chip) {
        case LGDT3302:
                err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1,
@@ -302,14 +304,16 @@ static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
                       "Only LGDT3302 and LGDT3303 are supported chips.\n");
                err = -ENODEV;
        }
+       if (err < 0)
+               return err;
 
        *ucblocks = (buf[0] << 8) | buf[1];
        return 0;
 }
 
-static int lgdt330x_set_parameters(struct dvb_frontend* fe,
-                                  struct dvb_frontend_parameters *param)
+static int lgdt330x_set_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        /*
         * Array of byte pairs <address, value>
         * to initialize 8VSB for lgdt3303 chip 50 MHz IF
@@ -343,10 +347,10 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
 
        static u8 top_ctrl_cfg[]   = { TOP_CONTROL, 0x03 };
 
-       int err;
+       int err = 0;
        /* Change only if we are actually changing the modulation */
-       if (state->current_modulation != param->u.vsb.modulation) {
-               switch(param->u.vsb.modulation) {
+       if (state->current_modulation != p->modulation) {
+               switch (p->modulation) {
                case VSB_8:
                        dprintk("%s: VSB_8 MODE\n", __func__);
 
@@ -395,9 +399,14 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
                        }
                        break;
                default:
-                       printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, param->u.vsb.modulation);
+                       printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, p->modulation);
                        return -1;
                }
+               if (err < 0)
+                       printk(KERN_WARNING "lgdt330x: %s: error blasting "
+                              "bytes to lgdt3303 for modulation type(%d)\n",
+                              __func__, p->modulation);
+
                /*
                 * select serial or parallel MPEG harware interface
                 * Serial:   0x04 for LGDT3302 or 0x40 for LGDT3303
@@ -410,29 +419,29 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
                                      sizeof(top_ctrl_cfg));
                if (state->config->set_ts_params)
                        state->config->set_ts_params(fe, 0);
-               state->current_modulation = param->u.vsb.modulation;
+               state->current_modulation = p->modulation;
        }
 
        /* Tune to the specified frequency */
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, param);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
        /* Keep track of the new frequency */
        /* FIXME this is the wrong way to do this...           */
        /* The tuner is shared with the video4linux analog API */
-       state->current_frequency = param->frequency;
+       state->current_frequency = p->frequency;
 
        lgdt330x_SwReset(state);
        return 0;
 }
 
-static int lgdt330x_get_frontend(struct dvb_frontend* fe,
-                                struct dvb_frontend_parameters* param)
+static int lgdt330x_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct lgdt330x_state *state = fe->demodulator_priv;
-       param->frequency = state->current_frequency;
+       p->frequency = state->current_frequency;
        return 0;
 }
 
@@ -762,9 +771,9 @@ error:
 }
 
 static struct dvb_frontend_ops lgdt3302_ops = {
+       .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
        .info = {
                .name= "LG Electronics LGDT3302 VSB/QAM Frontend",
-               .type = FE_ATSC,
                .frequency_min= 54000000,
                .frequency_max= 858000000,
                .frequency_stepsize= 62500,
@@ -785,9 +794,9 @@ static struct dvb_frontend_ops lgdt3302_ops = {
 };
 
 static struct dvb_frontend_ops lgdt3303_ops = {
+       .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
        .info = {
                .name= "LG Electronics LGDT3303 VSB/QAM Frontend",
-               .type = FE_ATSC,
                .frequency_min= 54000000,
                .frequency_max= 858000000,
                .frequency_stepsize= 62500,
index bb37ed289a059542d2821b9612261a18e7751f1e..2cec8041a1068e7f0d7f6cef5a365d68434cfbed 100644 (file)
@@ -311,18 +311,18 @@ lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 
 
 static int
-lgs8gl5_set_frontend(struct dvb_frontend *fe,
-               struct dvb_frontend_parameters *p)
+lgs8gl5_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct lgs8gl5_state *state = fe->demodulator_priv;
 
        dprintk("%s\n", __func__);
 
-       if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ)
+       if (p->bandwidth_hz != 8000000)
                return -EINVAL;
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
@@ -336,22 +336,21 @@ lgs8gl5_set_frontend(struct dvb_frontend *fe,
 
 
 static int
-lgs8gl5_get_frontend(struct dvb_frontend *fe,
-               struct dvb_frontend_parameters *p)
+lgs8gl5_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct lgs8gl5_state *state = fe->demodulator_priv;
        u8 inv = lgs8gl5_read_reg(state, REG_INVERSION);
-       struct dvb_ofdm_parameters *o = &p->u.ofdm;
 
        p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF;
 
-       o->code_rate_HP = FEC_1_2;
-       o->code_rate_LP = FEC_7_8;
-       o->guard_interval = GUARD_INTERVAL_1_32;
-       o->transmission_mode = TRANSMISSION_MODE_2K;
-       o->constellation = QAM_64;
-       o->hierarchy_information = HIERARCHY_NONE;
-       o->bandwidth = BANDWIDTH_8_MHZ;
+       p->code_rate_HP = FEC_1_2;
+       p->code_rate_LP = FEC_7_8;
+       p->guard_interval = GUARD_INTERVAL_1_32;
+       p->transmission_mode = TRANSMISSION_MODE_2K;
+       p->modulation = QAM_64;
+       p->hierarchy = HIERARCHY_NONE;
+       p->bandwidth_hz = 8000000;
 
        return 0;
 }
@@ -413,9 +412,9 @@ EXPORT_SYMBOL(lgs8gl5_attach);
 
 
 static struct dvb_frontend_ops lgs8gl5_ops = {
+       .delsys = { SYS_DMBTH },
        .info = {
                .name                   = "Legend Silicon LGS-8GL5 DMB-TH",
-               .type                   = FE_OFDM,
                .frequency_min          = 474000000,
                .frequency_max          = 858000000,
                .frequency_stepsize     = 10000,
index 1172b54689f81df3e7888e320f11c82f96c069d5..4de1d3520cd23b47492591f63ccff4c41196ee13 100644 (file)
@@ -669,16 +669,16 @@ static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len)
        return lgs8gxx_write_reg(priv, buf[0], buf[1]);
 }
 
-static int lgs8gxx_set_fe(struct dvb_frontend *fe,
-                         struct dvb_frontend_parameters *fe_params)
+static int lgs8gxx_set_fe(struct dvb_frontend *fe)
 {
+
        struct lgs8gxx_state *priv = fe->demodulator_priv;
 
        dprintk("%s\n", __func__);
 
        /* set frequency */
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, fe_params);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
@@ -691,9 +691,9 @@ static int lgs8gxx_set_fe(struct dvb_frontend *fe,
        return 0;
 }
 
-static int lgs8gxx_get_fe(struct dvb_frontend *fe,
-                         struct dvb_frontend_parameters *fe_params)
+static int lgs8gxx_get_fe(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
        dprintk("%s\n", __func__);
 
        /* TODO: get real readings from device */
@@ -701,21 +701,21 @@ static int lgs8gxx_get_fe(struct dvb_frontend *fe,
        fe_params->inversion = INVERSION_OFF;
 
        /* bandwidth */
-       fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+       fe_params->bandwidth_hz = 8000000;
 
-       fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
-       fe_params->u.ofdm.code_rate_LP = FEC_AUTO;
+       fe_params->code_rate_HP = FEC_AUTO;
+       fe_params->code_rate_LP = FEC_AUTO;
 
-       fe_params->u.ofdm.constellation = QAM_AUTO;
+       fe_params->modulation = QAM_AUTO;
 
        /* transmission mode */
-       fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+       fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;
 
        /* guard interval */
-       fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+       fe_params->guard_interval = GUARD_INTERVAL_AUTO;
 
        /* hierarchy */
-       fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+       fe_params->hierarchy = HIERARCHY_NONE;
 
        return 0;
 }
@@ -994,9 +994,9 @@ static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 }
 
 static struct dvb_frontend_ops lgs8gxx_ops = {
+       .delsys = { SYS_DMBTH },
        .info = {
                .name = "Legend Silicon LGS8913/LGS8GXX DMB-TH",
-               .type = FE_OFDM,
                .frequency_min = 474000000,
                .frequency_max = 858000000,
                .frequency_stepsize = 10000,
index c283112051b16cd6b9596c03644961ed0ff23f13..9ae40abfd71a170fe6940e372edefb1e0e558720 100644 (file)
@@ -1621,13 +1621,13 @@ err:
        return -EREMOTEIO;
 }
 
-static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe,
-                                       struct dvb_frontend_parameters *p)
+static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct mb86a16_state *state = fe->demodulator_priv;
 
        state->frequency = p->frequency / 1000;
-       state->srate = p->u.qpsk.symbol_rate / 1000;
+       state->srate = p->symbol_rate / 1000;
 
        if (!mb86a16_set_fe(state)) {
                dprintk(verbose, MB86A16_ERROR, 1, "Successfully acquired LOCK");
@@ -1814,9 +1814,9 @@ static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe)
 }
 
 static struct dvb_frontend_ops mb86a16_ops = {
+       .delsys = { SYS_DVBS },
        .info = {
                .name                   = "Fujitsu MB86A16 DVB-S",
-               .type                   = FE_QPSK,
                .frequency_min          = 950000,
                .frequency_max          = 2150000,
                .frequency_stepsize     = 3000,
index 0f867a5055fb95b3368bc65ce744fd221caf8b83..fade566927c3ee93d65cba68a14309c798051d7b 100644 (file)
@@ -61,244 +61,111 @@ static struct regdata mb86a20s_init[] = {
        { 0x70, 0xff },
        { 0x08, 0x01 },
        { 0x09, 0x3e },
-       { 0x50, 0xd1 },
-       { 0x51, 0x22 },
+       { 0x50, 0xd1 }, { 0x51, 0x22 },
        { 0x39, 0x01 },
        { 0x71, 0x00 },
-       { 0x28, 0x2a },
-       { 0x29, 0x00 },
-       { 0x2a, 0xff },
-       { 0x2b, 0x80 },
-       { 0x28, 0x20 },
-       { 0x29, 0x33 },
-       { 0x2a, 0xdf },
-       { 0x2b, 0xa9 },
+       { 0x28, 0x2a }, { 0x29, 0x00 }, { 0x2a, 0xff }, { 0x2b, 0x80 },
+       { 0x28, 0x20 }, { 0x29, 0x33 }, { 0x2a, 0xdf }, { 0x2b, 0xa9 },
+       { 0x28, 0x22 }, { 0x29, 0x00 }, { 0x2a, 0x1f }, { 0x2b, 0xf0 },
        { 0x3b, 0x21 },
        { 0x3c, 0x3a },
        { 0x01, 0x0d },
-       { 0x04, 0x08 },
-       { 0x05, 0x05 },
-       { 0x04, 0x0e },
-       { 0x05, 0x00 },
-       { 0x04, 0x0f },
-       { 0x05, 0x14 },
-       { 0x04, 0x0b },
-       { 0x05, 0x8c },
-       { 0x04, 0x00 },
-       { 0x05, 0x00 },
-       { 0x04, 0x01 },
-       { 0x05, 0x07 },
-       { 0x04, 0x02 },
-       { 0x05, 0x0f },
-       { 0x04, 0x03 },
-       { 0x05, 0xa0 },
-       { 0x04, 0x09 },
-       { 0x05, 0x00 },
-       { 0x04, 0x0a },
-       { 0x05, 0xff },
-       { 0x04, 0x27 },
-       { 0x05, 0x64 },
-       { 0x04, 0x28 },
-       { 0x05, 0x00 },
-       { 0x04, 0x1e },
-       { 0x05, 0xff },
-       { 0x04, 0x29 },
-       { 0x05, 0x0a },
-       { 0x04, 0x32 },
-       { 0x05, 0x0a },
-       { 0x04, 0x14 },
-       { 0x05, 0x02 },
-       { 0x04, 0x04 },
-       { 0x05, 0x00 },
-       { 0x04, 0x05 },
-       { 0x05, 0x22 },
-       { 0x04, 0x06 },
-       { 0x05, 0x0e },
-       { 0x04, 0x07 },
-       { 0x05, 0xd8 },
-       { 0x04, 0x12 },
-       { 0x05, 0x00 },
-       { 0x04, 0x13 },
-       { 0x05, 0xff },
+       { 0x04, 0x08 }, { 0x05, 0x05 },
+       { 0x04, 0x0e }, { 0x05, 0x00 },
+       { 0x04, 0x0f }, { 0x05, 0x14 },
+       { 0x04, 0x0b }, { 0x05, 0x8c },
+       { 0x04, 0x00 }, { 0x05, 0x00 },
+       { 0x04, 0x01 }, { 0x05, 0x07 },
+       { 0x04, 0x02 }, { 0x05, 0x0f },
+       { 0x04, 0x03 }, { 0x05, 0xa0 },
+       { 0x04, 0x09 }, { 0x05, 0x00 },
+       { 0x04, 0x0a }, { 0x05, 0xff },
+       { 0x04, 0x27 }, { 0x05, 0x64 },
+       { 0x04, 0x28 }, { 0x05, 0x00 },
+       { 0x04, 0x1e }, { 0x05, 0xff },
+       { 0x04, 0x29 }, { 0x05, 0x0a },
+       { 0x04, 0x32 }, { 0x05, 0x0a },
+       { 0x04, 0x14 }, { 0x05, 0x02 },
+       { 0x04, 0x04 }, { 0x05, 0x00 },
+       { 0x04, 0x05 }, { 0x05, 0x22 },
+       { 0x04, 0x06 }, { 0x05, 0x0e },
+       { 0x04, 0x07 }, { 0x05, 0xd8 },
+       { 0x04, 0x12 }, { 0x05, 0x00 },
+       { 0x04, 0x13 }, { 0x05, 0xff },
+       { 0x04, 0x15 }, { 0x05, 0x4e },
+       { 0x04, 0x16 }, { 0x05, 0x20 },
        { 0x52, 0x01 },
-       { 0x50, 0xa7 },
-       { 0x51, 0x00 },
-       { 0x50, 0xa8 },
-       { 0x51, 0xff },
-       { 0x50, 0xa9 },
-       { 0x51, 0xff },
-       { 0x50, 0xaa },
-       { 0x51, 0x00 },
-       { 0x50, 0xab },
-       { 0x51, 0xff },
-       { 0x50, 0xac },
-       { 0x51, 0xff },
-       { 0x50, 0xad },
-       { 0x51, 0x00 },
-       { 0x50, 0xae },
-       { 0x51, 0xff },
-       { 0x50, 0xaf },
-       { 0x51, 0xff },
+       { 0x50, 0xa7 }, { 0x51, 0xff },
+       { 0x50, 0xa8 }, { 0x51, 0xff },
+       { 0x50, 0xa9 }, { 0x51, 0xff },
+       { 0x50, 0xaa }, { 0x51, 0xff },
+       { 0x50, 0xab }, { 0x51, 0xff },
+       { 0x50, 0xac }, { 0x51, 0xff },
+       { 0x50, 0xad }, { 0x51, 0xff },
+       { 0x50, 0xae }, { 0x51, 0xff },
+       { 0x50, 0xaf }, { 0x51, 0xff },
        { 0x5e, 0x07 },
-       { 0x50, 0xdc },
-       { 0x51, 0x01 },
-       { 0x50, 0xdd },
-       { 0x51, 0xf4 },
-       { 0x50, 0xde },
-       { 0x51, 0x01 },
-       { 0x50, 0xdf },
-       { 0x51, 0xf4 },
-       { 0x50, 0xe0 },
-       { 0x51, 0x01 },
-       { 0x50, 0xe1 },
-       { 0x51, 0xf4 },
-       { 0x50, 0xb0 },
-       { 0x51, 0x07 },
-       { 0x50, 0xb2 },
-       { 0x51, 0xff },
-       { 0x50, 0xb3 },
-       { 0x51, 0xff },
-       { 0x50, 0xb4 },
-       { 0x51, 0xff },
-       { 0x50, 0xb5 },
-       { 0x51, 0xff },
-       { 0x50, 0xb6 },
-       { 0x51, 0xff },
-       { 0x50, 0xb7 },
-       { 0x51, 0xff },
-       { 0x50, 0x50 },
-       { 0x51, 0x02 },
-       { 0x50, 0x51 },
-       { 0x51, 0x04 },
+       { 0x50, 0xdc }, { 0x51, 0x01 },
+       { 0x50, 0xdd }, { 0x51, 0xf4 },
+       { 0x50, 0xde }, { 0x51, 0x01 },
+       { 0x50, 0xdf }, { 0x51, 0xf4 },
+       { 0x50, 0xe0 }, { 0x51, 0x01 },
+       { 0x50, 0xe1 }, { 0x51, 0xf4 },
+       { 0x50, 0xb0 }, { 0x51, 0x07 },
+       { 0x50, 0xb2 }, { 0x51, 0xff },
+       { 0x50, 0xb3 }, { 0x51, 0xff },
+       { 0x50, 0xb4 }, { 0x51, 0xff },
+       { 0x50, 0xb5 }, { 0x51, 0xff },
+       { 0x50, 0xb6 }, { 0x51, 0xff },
+       { 0x50, 0xb7 }, { 0x51, 0xff },
+       { 0x50, 0x50 }, { 0x51, 0x02 },
+       { 0x50, 0x51 }, { 0x51, 0x04 },
        { 0x45, 0x04 },
        { 0x48, 0x04 },
-       { 0x50, 0xd5 },
-       { 0x51, 0x01 },         /* Serial */
-       { 0x50, 0xd6 },
-       { 0x51, 0x1f },
-       { 0x50, 0xd2 },
-       { 0x51, 0x03 },
-       { 0x50, 0xd7 },
-       { 0x51, 0x3f },
+       { 0x50, 0xd5 }, { 0x51, 0x01 },         /* Serial */
+       { 0x50, 0xd6 }, { 0x51, 0x1f },
+       { 0x50, 0xd2 }, { 0x51, 0x03 },
+       { 0x50, 0xd7 }, { 0x51, 0x3f },
+       { 0x28, 0x74 }, { 0x29, 0x00 }, { 0x28, 0x74 }, { 0x29, 0x40 },
+       { 0x28, 0x46 }, { 0x29, 0x2c }, { 0x28, 0x46 }, { 0x29, 0x0c },
+       { 0x04, 0x40 }, { 0x05, 0x01 },
+       { 0x28, 0x00 }, { 0x29, 0x10 },
+       { 0x28, 0x05 }, { 0x29, 0x02 },
        { 0x1c, 0x01 },
-       { 0x28, 0x06 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x03 },
-       { 0x28, 0x07 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x0d },
-       { 0x28, 0x08 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x02 },
-       { 0x28, 0x09 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x01 },
-       { 0x28, 0x0a },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x21 },
-       { 0x28, 0x0b },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x29 },
-       { 0x28, 0x0c },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x16 },
-       { 0x28, 0x0d },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x31 },
-       { 0x28, 0x0e },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x0e },
-       { 0x28, 0x0f },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x4e },
-       { 0x28, 0x10 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x46 },
-       { 0x28, 0x11 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x0f },
-       { 0x28, 0x12 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x56 },
-       { 0x28, 0x13 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x35 },
-       { 0x28, 0x14 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x01 },
-       { 0x2b, 0xbe },
-       { 0x28, 0x15 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x01 },
-       { 0x2b, 0x84 },
-       { 0x28, 0x16 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x03 },
-       { 0x2b, 0xee },
-       { 0x28, 0x17 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x98 },
-       { 0x28, 0x18 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x00 },
-       { 0x2b, 0x9f },
-       { 0x28, 0x19 },
-       { 0x29, 0x00 },
-       { 0x2a, 0x07 },
-       { 0x2b, 0xb2 },
-       { 0x28, 0x1a },
-       { 0x29, 0x00 },
-       { 0x2a, 0x06 },
-       { 0x2b, 0xc2 },
-       { 0x28, 0x1b },
-       { 0x29, 0x00 },
-       { 0x2a, 0x07 },
-       { 0x2b, 0x4a },
-       { 0x28, 0x1c },
-       { 0x29, 0x00 },
-       { 0x2a, 0x01 },
-       { 0x2b, 0xbc },
-       { 0x28, 0x1d },
-       { 0x29, 0x00 },
-       { 0x2a, 0x04 },
-       { 0x2b, 0xba },
-       { 0x28, 0x1e },
-       { 0x29, 0x00 },
-       { 0x2a, 0x06 },
-       { 0x2b, 0x14 },
-       { 0x50, 0x1e },
-       { 0x51, 0x5d },
-       { 0x50, 0x22 },
-       { 0x51, 0x00 },
-       { 0x50, 0x23 },
-       { 0x51, 0xc8 },
-       { 0x50, 0x24 },
-       { 0x51, 0x00 },
-       { 0x50, 0x25 },
-       { 0x51, 0xf0 },
-       { 0x50, 0x26 },
-       { 0x51, 0x00 },
-       { 0x50, 0x27 },
-       { 0x51, 0xc3 },
-       { 0x50, 0x39 },
-       { 0x51, 0x02 },
-       { 0x50, 0xd5 },
-       { 0x51, 0x01 },
+       { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x03 },
+       { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0d },
+       { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 },
+       { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x01 },
+       { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x21 },
+       { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x29 },
+       { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 },
+       { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x31 },
+       { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0e },
+       { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x4e },
+       { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x46 },
+       { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f },
+       { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x56 },
+       { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x35 },
+       { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbe },
+       { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0x84 },
+       { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x03 }, { 0x2b, 0xee },
+       { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x98 },
+       { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x9f },
+       { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xb2 },
+       { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0xc2 },
+       { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0x4a },
+       { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbc },
+       { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x04 }, { 0x2b, 0xba },
+       { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0x14 },
+       { 0x50, 0x1e }, { 0x51, 0x5d },
+       { 0x50, 0x22 }, { 0x51, 0x00 },
+       { 0x50, 0x23 }, { 0x51, 0xc8 },
+       { 0x50, 0x24 }, { 0x51, 0x00 },
+       { 0x50, 0x25 }, { 0x51, 0xf0 },
+       { 0x50, 0x26 }, { 0x51, 0x00 },
+       { 0x50, 0x27 }, { 0x51, 0xc3 },
+       { 0x50, 0x39 }, { 0x51, 0x02 },
+       { 0x28, 0x6a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 },
        { 0xd0, 0x00 },
 };
 
@@ -485,18 +352,23 @@ static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status)
        return 0;
 }
 
-static int mb86a20s_set_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int mb86a20s_set_frontend(struct dvb_frontend *fe)
 {
        struct mb86a20s_state *state = fe->demodulator_priv;
        int rc;
+#if 0
+       /*
+        * FIXME: Properly implement the set frontend properties
+        */
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+#endif
 
        dprintk("\n");
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
        dprintk("Calling tuner set parameters\n");
-       fe->ops.tuner_ops.set_params(fe, p);
+       fe->ops.tuner_ops.set_params(fe);
 
        /*
         * Make it more reliable: if, for some reason, the initial
@@ -520,22 +392,212 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe,
        return rc;
 }
 
-static int mb86a20s_get_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int mb86a20s_get_modulation(struct mb86a20s_state *state,
+                                  unsigned layer)
+{
+       int rc;
+       static unsigned char reg[] = {
+               [0] = 0x86,     /* Layer A */
+               [1] = 0x8a,     /* Layer B */
+               [2] = 0x8e,     /* Layer C */
+       };
+
+       if (layer >= ARRAY_SIZE(reg))
+               return -EINVAL;
+       rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
+       if (rc < 0)
+               return rc;
+       rc = mb86a20s_readreg(state, 0x6e);
+       if (rc < 0)
+               return rc;
+       switch ((rc & 0x70) >> 4) {
+       case 0:
+               return DQPSK;
+       case 1:
+               return QPSK;
+       case 2:
+               return QAM_16;
+       case 3:
+               return QAM_64;
+       default:
+               return QAM_AUTO;
+       }
+}
+
+static int mb86a20s_get_fec(struct mb86a20s_state *state,
+                           unsigned layer)
 {
+       int rc;
 
-       /* FIXME: For now, it does nothing */
+       static unsigned char reg[] = {
+               [0] = 0x87,     /* Layer A */
+               [1] = 0x8b,     /* Layer B */
+               [2] = 0x8f,     /* Layer C */
+       };
 
-       fe->dtv_property_cache.bandwidth_hz = 6000000;
-       fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
-       fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
-       fe->dtv_property_cache.isdbt_partial_reception = 0;
+       if (layer >= ARRAY_SIZE(reg))
+               return -EINVAL;
+       rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
+       if (rc < 0)
+               return rc;
+       rc = mb86a20s_readreg(state, 0x6e);
+       if (rc < 0)
+               return rc;
+       switch (rc) {
+       case 0:
+               return FEC_1_2;
+       case 1:
+               return FEC_2_3;
+       case 2:
+               return FEC_3_4;
+       case 3:
+               return FEC_5_6;
+       case 4:
+               return FEC_7_8;
+       default:
+               return FEC_AUTO;
+       }
+}
+
+static int mb86a20s_get_interleaving(struct mb86a20s_state *state,
+                                    unsigned layer)
+{
+       int rc;
+
+       static unsigned char reg[] = {
+               [0] = 0x88,     /* Layer A */
+               [1] = 0x8c,     /* Layer B */
+               [2] = 0x90,     /* Layer C */
+       };
+
+       if (layer >= ARRAY_SIZE(reg))
+               return -EINVAL;
+       rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
+       if (rc < 0)
+               return rc;
+       rc = mb86a20s_readreg(state, 0x6e);
+       if (rc < 0)
+               return rc;
+       if (rc > 3)
+               return -EINVAL; /* Not used */
+       return rc;
+}
+
+static int mb86a20s_get_segment_count(struct mb86a20s_state *state,
+                                     unsigned layer)
+{
+       int rc, count;
+
+       static unsigned char reg[] = {
+               [0] = 0x89,     /* Layer A */
+               [1] = 0x8d,     /* Layer B */
+               [2] = 0x91,     /* Layer C */
+       };
+
+       if (layer >= ARRAY_SIZE(reg))
+               return -EINVAL;
+       rc = mb86a20s_writereg(state, 0x6d, reg[layer]);
+       if (rc < 0)
+               return rc;
+       rc = mb86a20s_readreg(state, 0x6e);
+       if (rc < 0)
+               return rc;
+       count = (rc >> 4) & 0x0f;
+
+       return count;
+}
+
+static int mb86a20s_get_frontend(struct dvb_frontend *fe)
+{
+       struct mb86a20s_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+       int i, rc;
+
+       /* Fixed parameters */
+       p->delivery_system = SYS_ISDBT;
+       p->bandwidth_hz = 6000000;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       /* Check for partial reception */
+       rc = mb86a20s_writereg(state, 0x6d, 0x85);
+       if (rc >= 0)
+               rc = mb86a20s_readreg(state, 0x6e);
+       if (rc >= 0)
+               p->isdbt_partial_reception = (rc & 0x10) ? 1 : 0;
+
+       /* Get per-layer data */
+       p->isdbt_layer_enabled = 0;
+       for (i = 0; i < 3; i++) {
+               rc = mb86a20s_get_segment_count(state, i);
+                       if (rc >= 0 && rc < 14)
+                               p->layer[i].segment_count = rc;
+               if (rc == 0x0f)
+                       continue;
+               p->isdbt_layer_enabled |= 1 << i;
+               rc = mb86a20s_get_modulation(state, i);
+                       if (rc >= 0)
+                               p->layer[i].modulation = rc;
+               rc = mb86a20s_get_fec(state, i);
+                       if (rc >= 0)
+                               p->layer[i].fec = rc;
+               rc = mb86a20s_get_interleaving(state, i);
+                       if (rc >= 0)
+                               p->layer[i].interleaving = rc;
+       }
+
+       p->isdbt_sb_mode = 0;
+       rc = mb86a20s_writereg(state, 0x6d, 0x84);
+       if ((rc >= 0) && ((rc & 0x60) == 0x20)) {
+               p->isdbt_sb_mode = 1;
+               /* At least, one segment should exist */
+               if (!p->isdbt_sb_segment_count)
+                       p->isdbt_sb_segment_count = 1;
+       } else
+               p->isdbt_sb_segment_count = 0;
+
+       /* Get transmission mode and guard interval */
+       p->transmission_mode = TRANSMISSION_MODE_AUTO;
+       p->guard_interval = GUARD_INTERVAL_AUTO;
+       rc = mb86a20s_readreg(state, 0x07);
+       if (rc >= 0) {
+               if ((rc & 0x60) == 0x20) {
+                       switch (rc & 0x0c >> 2) {
+                       case 0:
+                               p->transmission_mode = TRANSMISSION_MODE_2K;
+                               break;
+                       case 1:
+                               p->transmission_mode = TRANSMISSION_MODE_4K;
+                               break;
+                       case 2:
+                               p->transmission_mode = TRANSMISSION_MODE_8K;
+                               break;
+                       }
+               }
+               if (!(rc & 0x10)) {
+                       switch (rc & 0x3) {
+                       case 0:
+                               p->guard_interval = GUARD_INTERVAL_1_4;
+                               break;
+                       case 1:
+                               p->guard_interval = GUARD_INTERVAL_1_8;
+                               break;
+                       case 2:
+                               p->guard_interval = GUARD_INTERVAL_1_16;
+                               break;
+                       }
+               }
+       }
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
 
        return 0;
 }
 
 static int mb86a20s_tune(struct dvb_frontend *fe,
-                       struct dvb_frontend_parameters *params,
+                       bool re_tune,
                        unsigned int mode_flags,
                        unsigned int *delay,
                        fe_status_t *status)
@@ -544,8 +606,8 @@ static int mb86a20s_tune(struct dvb_frontend *fe,
 
        dprintk("\n");
 
-       if (params != NULL)
-               rc = mb86a20s_set_frontend(fe, params);
+       if (re_tune)
+               rc = mb86a20s_set_frontend(fe);
 
        if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
                mb86a20s_read_status(fe, status);
@@ -608,10 +670,10 @@ error:
 EXPORT_SYMBOL(mb86a20s_attach);
 
 static struct dvb_frontend_ops mb86a20s_ops = {
+       .delsys = { SYS_ISDBT },
        /* Use dib8000 values per default */
        .info = {
                .name = "Fujitsu mb86A20s",
-               .type = FE_OFDM,
                .caps = FE_CAN_INVERSION_AUTO | FE_CAN_RECOVER |
                        FE_CAN_FEC_1_2  | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
                        FE_CAN_FEC_5_6  | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
index 83e6f1a1b7009cae02fb0c3579901a2d032be126..e20bf13aa860bb03f2d07945bf04497c6981eb2f 100644 (file)
@@ -531,9 +531,9 @@ static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc)
        return 0;
 }
 
-static int mt312_set_frontend(struct dvb_frontend *fe,
-                             struct dvb_frontend_parameters *p)
+static int mt312_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct mt312_state *state = fe->demodulator_priv;
        int ret;
        u8 buf[5], config_val;
@@ -553,16 +553,16 @@ static int mt312_set_frontend(struct dvb_frontend *fe,
            || (p->inversion > INVERSION_ON))
                return -EINVAL;
 
-       if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min)
-           || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max))
+       if ((p->symbol_rate < fe->ops.info.symbol_rate_min)
+           || (p->symbol_rate > fe->ops.info.symbol_rate_max))
                return -EINVAL;
 
-       if ((p->u.qpsk.fec_inner < FEC_NONE)
-           || (p->u.qpsk.fec_inner > FEC_AUTO))
+       if ((p->fec_inner < FEC_NONE)
+           || (p->fec_inner > FEC_AUTO))
                return -EINVAL;
 
-       if ((p->u.qpsk.fec_inner == FEC_4_5)
-           || (p->u.qpsk.fec_inner == FEC_8_9))
+       if ((p->fec_inner == FEC_4_5)
+           || (p->fec_inner == FEC_8_9))
                return -EINVAL;
 
        switch (state->id) {
@@ -574,7 +574,7 @@ static int mt312_set_frontend(struct dvb_frontend *fe,
                ret = mt312_readreg(state, CONFIG, &config_val);
                if (ret < 0)
                        return ret;
-               if (p->u.qpsk.symbol_rate >= 30000000) {
+               if (p->symbol_rate >= 30000000) {
                        /* Note that 30MS/s should use 90MHz */
                        if (state->freq_mult == 6) {
                                /* We are running 60MHz */
@@ -603,25 +603,25 @@ static int mt312_set_frontend(struct dvb_frontend *fe,
        }
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
        /* sr = (u16)(sr * 256.0 / 1000000.0) */
-       sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
+       sr = mt312_div(p->symbol_rate * 4, 15625);
 
        /* SYM_RATE */
        buf[0] = (sr >> 8) & 0x3f;
        buf[1] = (sr >> 0) & 0xff;
 
        /* VIT_MODE */
-       buf[2] = inv_tab[p->inversion] | fec_tab[p->u.qpsk.fec_inner];
+       buf[2] = inv_tab[p->inversion] | fec_tab[p->fec_inner];
 
        /* QPSK_CTRL */
        buf[3] = 0x40;          /* swap I and Q before QPSK demodulation */
 
-       if (p->u.qpsk.symbol_rate < 10000000)
+       if (p->symbol_rate < 10000000)
                buf[3] |= 0x04; /* use afc mode */
 
        /* GO */
@@ -636,9 +636,9 @@ static int mt312_set_frontend(struct dvb_frontend *fe,
        return 0;
 }
 
-static int mt312_get_frontend(struct dvb_frontend *fe,
-                             struct dvb_frontend_parameters *p)
+static int mt312_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct mt312_state *state = fe->demodulator_priv;
        int ret;
 
@@ -646,11 +646,11 @@ static int mt312_get_frontend(struct dvb_frontend *fe,
        if (ret < 0)
                return ret;
 
-       ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate);
+       ret = mt312_get_symbol_rate(state, &p->symbol_rate);
        if (ret < 0)
                return ret;
 
-       ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner);
+       ret = mt312_get_code_rate(state, &p->fec_inner);
        if (ret < 0)
                return ret;
 
@@ -738,10 +738,9 @@ static void mt312_release(struct dvb_frontend *fe)
 
 #define MT312_SYS_CLK          90000000UL      /* 90 MHz */
 static struct dvb_frontend_ops mt312_ops = {
-
+       .delsys = { SYS_DVBS },
        .info = {
                .name = "Zarlink ???? DVB-S",
-               .type = FE_QPSK,
                .frequency_min = 950000,
                .frequency_max = 2150000,
                /* FIXME: adjust freq to real used xtal */
index 319672f8e1a70c8ac04ec8940f1698d29ccf7bdc..2c3b50e828d7dbe7fa6e3761bc462bfa0f7827bc 100644 (file)
@@ -111,20 +111,20 @@ static int mt352_sleep(struct dvb_frontend* fe)
 }
 
 static void mt352_calc_nominal_rate(struct mt352_state* state,
-                                   enum fe_bandwidth bandwidth,
+                                   u32 bandwidth,
                                    unsigned char *buf)
 {
        u32 adc_clock = 20480; /* 20.340 MHz */
        u32 bw,value;
 
        switch (bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       case 6000000:
                bw = 6;
                break;
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                bw = 7;
                break;
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
        default:
                bw = 8;
                break;
@@ -166,15 +166,14 @@ static void mt352_calc_input_freq(struct mt352_state* state,
        buf[1] = lsb(value);
 }
 
-static int mt352_set_parameters(struct dvb_frontend* fe,
-                               struct dvb_frontend_parameters *param)
+static int mt352_set_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *op = &fe->dtv_property_cache;
        struct mt352_state* state = fe->demodulator_priv;
        unsigned char buf[13];
        static unsigned char tuner_go[] = { 0x5d, 0x01 };
        static unsigned char fsm_go[]   = { 0x5e, 0x01 };
        unsigned int tps = 0;
-       struct dvb_ofdm_parameters *op = &param->u.ofdm;
 
        switch (op->code_rate_HP) {
                case FEC_2_3:
@@ -213,14 +212,14 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
                case FEC_AUTO:
                        break;
                case FEC_NONE:
-                       if (op->hierarchy_information == HIERARCHY_AUTO ||
-                           op->hierarchy_information == HIERARCHY_NONE)
+                       if (op->hierarchy == HIERARCHY_AUTO ||
+                           op->hierarchy == HIERARCHY_NONE)
                                break;
                default:
                        return -EINVAL;
        }
 
-       switch (op->constellation) {
+       switch (op->modulation) {
                case QPSK:
                        break;
                case QAM_AUTO:
@@ -262,7 +261,7 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
                        return -EINVAL;
        }
 
-       switch (op->hierarchy_information) {
+       switch (op->hierarchy) {
                case HIERARCHY_AUTO:
                case HIERARCHY_NONE:
                        break;
@@ -288,12 +287,12 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
        buf[3] = 0x50;  // old
 //     buf[3] = 0xf4;  // pinnacle
 
-       mt352_calc_nominal_rate(state, op->bandwidth, buf+4);
+       mt352_calc_nominal_rate(state, op->bandwidth_hz, buf+4);
        mt352_calc_input_freq(state, buf+6);
 
        if (state->config.no_tuner) {
                if (fe->ops.tuner_ops.set_params) {
-                       fe->ops.tuner_ops.set_params(fe, param);
+                       fe->ops.tuner_ops.set_params(fe);
                        if (fe->ops.i2c_gate_ctrl)
                                fe->ops.i2c_gate_ctrl(fe, 0);
                }
@@ -302,7 +301,7 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
                _mt352_write(fe, fsm_go, 2);
        } else {
                if (fe->ops.tuner_ops.calc_regs) {
-                       fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5);
+                       fe->ops.tuner_ops.calc_regs(fe, buf+8, 5);
                        buf[8] <<= 1;
                        _mt352_write(fe, buf, sizeof(buf));
                        _mt352_write(fe, tuner_go, 2);
@@ -312,14 +311,13 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
        return 0;
 }
 
-static int mt352_get_parameters(struct dvb_frontend* fe,
-                               struct dvb_frontend_parameters *param)
+static int mt352_get_parameters(struct dvb_frontend* fe)
 {
+       struct dtv_frontend_properties *op = &fe->dtv_property_cache;
        struct mt352_state* state = fe->demodulator_priv;
        u16 tps;
        u16 div;
        u8 trl;
-       struct dvb_ofdm_parameters *op = &param->u.ofdm;
        static const u8 tps_fec_to_api[8] =
        {
                FEC_1_2,
@@ -348,16 +346,16 @@ static int mt352_get_parameters(struct dvb_frontend* fe,
        switch ( (tps >> 13) & 3)
        {
                case 0:
-                       op->constellation = QPSK;
+                       op->modulation = QPSK;
                        break;
                case 1:
-                       op->constellation = QAM_16;
+                       op->modulation = QAM_16;
                        break;
                case 2:
-                       op->constellation = QAM_64;
+                       op->modulation = QAM_64;
                        break;
                default:
-                       op->constellation = QAM_AUTO;
+                       op->modulation = QAM_AUTO;
                        break;
        }
 
@@ -385,36 +383,36 @@ static int mt352_get_parameters(struct dvb_frontend* fe,
        switch ( (tps >> 10) & 7)
        {
                case 0:
-                       op->hierarchy_information = HIERARCHY_NONE;
+                       op->hierarchy = HIERARCHY_NONE;
                        break;
                case 1:
-                       op->hierarchy_information = HIERARCHY_1;
+                       op->hierarchy = HIERARCHY_1;
                        break;
                case 2:
-                       op->hierarchy_information = HIERARCHY_2;
+                       op->hierarchy = HIERARCHY_2;
                        break;
                case 3:
-                       op->hierarchy_information = HIERARCHY_4;
+                       op->hierarchy = HIERARCHY_4;
                        break;
                default:
-                       op->hierarchy_information = HIERARCHY_AUTO;
+                       op->hierarchy = HIERARCHY_AUTO;
                        break;
        }
 
-       param->frequency = ( 500 * (div - IF_FREQUENCYx6) ) / 3 * 1000;
+       op->frequency = (500 * (div - IF_FREQUENCYx6)) / 3 * 1000;
 
        if (trl == 0x72)
-               op->bandwidth = BANDWIDTH_8_MHZ;
+               op->bandwidth_hz = 8000000;
        else if (trl == 0x64)
-               op->bandwidth = BANDWIDTH_7_MHZ;
+               op->bandwidth_hz = 7000000;
        else
-               op->bandwidth = BANDWIDTH_6_MHZ;
+               op->bandwidth_hz = 6000000;
 
 
        if (mt352_read_register(state, STATUS_2) & 0x02)
-               param->inversion = INVERSION_OFF;
+               op->inversion = INVERSION_OFF;
        else
-               param->inversion = INVERSION_ON;
+               op->inversion = INVERSION_ON;
 
        return 0;
 }
@@ -569,10 +567,9 @@ error:
 }
 
 static struct dvb_frontend_ops mt352_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "Zarlink MT352 DVB-T",
-               .type                   = FE_OFDM,
                .frequency_min          = 174000000,
                .frequency_max          = 862000000,
                .frequency_stepsize     = 166667,
index eac20650499fb510217a1ccf4bba9598083f60c7..49ca78d883b18031ec110a6329be86bf49c9acbe 100644 (file)
@@ -528,9 +528,9 @@ static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware
        return 0;
 };
 
-static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
-                                            struct dvb_frontend_parameters *p)
+static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct nxt200x_state* state = fe->demodulator_priv;
        u8 buf[5];
 
@@ -546,7 +546,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
        }
 
        /* set additional params */
-       switch (p->u.vsb.modulation) {
+       switch (p->modulation) {
                case QAM_64:
                case QAM_256:
                        /* Set punctured clock for QAM */
@@ -566,7 +566,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
 
        if (fe->ops.tuner_ops.calc_regs) {
                /* get tuning information */
-               fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+               fe->ops.tuner_ops.calc_regs(fe, buf, 5);
 
                /* write frequency information */
                nxt200x_writetuner(state, buf);
@@ -576,7 +576,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
        nxt200x_agc_reset(state);
 
        /* set target power level */
-       switch (p->u.vsb.modulation) {
+       switch (p->modulation) {
                case QAM_64:
                case QAM_256:
                        buf[0] = 0x74;
@@ -620,7 +620,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
        }
 
        /* write sdmx input */
-       switch (p->u.vsb.modulation) {
+       switch (p->modulation) {
                case QAM_64:
                                buf[0] = 0x68;
                                break;
@@ -714,7 +714,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
        }
 
        /* write agc ucgp0 */
-       switch (p->u.vsb.modulation) {
+       switch (p->modulation) {
                case QAM_64:
                                buf[0] = 0x02;
                                break;
@@ -1203,10 +1203,9 @@ error:
 }
 
 static struct dvb_frontend_ops nxt200x_ops = {
-
+       .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
        .info = {
                .name = "Nextwave NXT200X VSB/QAM frontend",
-               .type = FE_ATSC,
                .frequency_min =  54000000,
                .frequency_max = 860000000,
                .frequency_stepsize = 166666,   /* stepsize is just a guess */
index 6599b8fea9e9ad0d2c3bad2560565670b5e2486c..90ae6c72c0e3c085f792820dfbc995e831a588c9 100644 (file)
@@ -81,22 +81,21 @@ static void nxt6000_reset(struct nxt6000_state* state)
        nxt6000_writereg(state, OFDM_COR_CTL, val | COREACT);
 }
 
-static int nxt6000_set_bandwidth(struct nxt6000_state* state, fe_bandwidth_t bandwidth)
+static int nxt6000_set_bandwidth(struct nxt6000_state *state, u32 bandwidth)
 {
        u16 nominal_rate;
        int result;
 
        switch (bandwidth) {
-
-       case BANDWIDTH_6_MHZ:
+       case 6000000:
                nominal_rate = 0x55B7;
                break;
 
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                nominal_rate = 0x6400;
                break;
 
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
                nominal_rate = 0x7249;
                break;
 
@@ -457,23 +456,31 @@ static int nxt6000_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *param)
+static int nxt6000_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct nxt6000_state* state = fe->demodulator_priv;
        int result;
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, param);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
-       if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0)
+       result = nxt6000_set_bandwidth(state, p->bandwidth_hz);
+       if (result < 0)
                return result;
-       if ((result = nxt6000_set_guard_interval(state, param->u.ofdm.guard_interval)) < 0)
+
+       result = nxt6000_set_guard_interval(state, p->guard_interval);
+       if (result < 0)
                return result;
-       if ((result = nxt6000_set_transmission_mode(state, param->u.ofdm.transmission_mode)) < 0)
+
+       result = nxt6000_set_transmission_mode(state, p->transmission_mode);
+       if (result < 0)
                return result;
-       if ((result = nxt6000_set_inversion(state, param->inversion)) < 0)
+
+       result = nxt6000_set_inversion(state, p->inversion);
+       if (result < 0)
                return result;
 
        msleep(500);
@@ -566,10 +573,9 @@ error:
 }
 
 static struct dvb_frontend_ops nxt6000_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name = "NxtWave NXT6000 DVB-T",
-               .type = FE_OFDM,
                .frequency_min = 0,
                .frequency_max = 863250000,
                .frequency_stepsize = 62500,
index 38e67accb8c360af874fc9b3d57804c523d4a34a..5ef921823c1537088dd22914fdcfff41553412a4 100644 (file)
@@ -306,9 +306,9 @@ static int modulation_fw_class(fe_modulation_t modulation)
        }
 }
 
-static int or51132_set_parameters(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *param)
+static int or51132_set_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        int ret;
        struct or51132_state* state = fe->demodulator_priv;
        const struct firmware *fw;
@@ -317,8 +317,8 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
 
        /* Upload new firmware only if we need a different one */
        if (modulation_fw_class(state->current_modulation) !=
-           modulation_fw_class(param->u.vsb.modulation)) {
-               switch(modulation_fw_class(param->u.vsb.modulation)) {
+           modulation_fw_class(p->modulation)) {
+               switch (modulation_fw_class(p->modulation)) {
                case MOD_FWCLASS_VSB:
                        dprintk("set_parameters VSB MODE\n");
                        fwname = OR51132_VSB_FIRMWARE;
@@ -335,7 +335,7 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
                        break;
                default:
                        printk("or51132: Modulation type(%d) UNSUPPORTED\n",
-                              param->u.vsb.modulation);
+                              p->modulation);
                        return -1;
                }
                printk("or51132: Waiting for firmware upload(%s)...\n",
@@ -357,13 +357,13 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
                state->config->set_ts_params(fe, clock_mode);
        }
        /* Change only if we are actually changing the modulation */
-       if (state->current_modulation != param->u.vsb.modulation) {
-               state->current_modulation = param->u.vsb.modulation;
+       if (state->current_modulation != p->modulation) {
+               state->current_modulation = p->modulation;
                or51132_setmode(fe);
        }
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, param);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
@@ -371,13 +371,13 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
        or51132_setmode(fe);
 
        /* Update current frequency */
-       state->current_frequency = param->frequency;
+       state->current_frequency = p->frequency;
        return 0;
 }
 
-static int or51132_get_parameters(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *param)
+static int or51132_get_parameters(struct dvb_frontend* fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct or51132_state* state = fe->demodulator_priv;
        int status;
        int retry = 1;
@@ -389,21 +389,28 @@ start:
                return -EREMOTEIO;
        }
        switch(status&0xff) {
-               case 0x06: param->u.vsb.modulation = VSB_8; break;
-               case 0x43: param->u.vsb.modulation = QAM_64; break;
-               case 0x45: param->u.vsb.modulation = QAM_256; break;
-               default:
-                       if (retry--) goto start;
-                       printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
-                              status&0xff);
-                       return -EREMOTEIO;
+       case 0x06:
+               p->modulation = VSB_8;
+               break;
+       case 0x43:
+               p->modulation = QAM_64;
+               break;
+       case 0x45:
+               p->modulation = QAM_256;
+               break;
+       default:
+               if (retry--)
+                       goto start;
+               printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
+                      status&0xff);
+               return -EREMOTEIO;
        }
 
        /* FIXME: Read frequency from frontend, take AFC into account */
-       param->frequency = state->current_frequency;
+       p->frequency = state->current_frequency;
 
        /* FIXME: How to read inversion setting? Receiver 6 register? */
-       param->inversion = INVERSION_AUTO;
+       p->inversion = INVERSION_AUTO;
 
        return 0;
 }
@@ -579,10 +586,9 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
 }
 
 static struct dvb_frontend_ops or51132_ops = {
-
+       .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
        .info = {
                .name                   = "Oren OR51132 VSB/QAM Frontend",
-               .type                   = FE_ATSC,
                .frequency_min          = 44000000,
                .frequency_max          = 958000000,
                .frequency_stepsize     = 166666,
index c709ce6771c86ca831e9e17e1677e03da0b05e7c..c625b57b4333e499827ff9e024d98227eda78775 100644 (file)
@@ -218,15 +218,15 @@ static int or51211_setmode(struct dvb_frontend* fe, int mode)
        return 0;
 }
 
-static int or51211_set_parameters(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *param)
+static int or51211_set_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct or51211_state* state = fe->demodulator_priv;
 
        /* Change only if we are actually changing the channel */
-       if (state->current_frequency != param->frequency) {
+       if (state->current_frequency != p->frequency) {
                if (fe->ops.tuner_ops.set_params) {
-                       fe->ops.tuner_ops.set_params(fe, param);
+                       fe->ops.tuner_ops.set_params(fe);
                        if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
                }
 
@@ -234,7 +234,7 @@ static int or51211_set_parameters(struct dvb_frontend* fe,
                or51211_setmode(fe,0);
 
                /* Update current frequency */
-               state->current_frequency = param->frequency;
+               state->current_frequency = p->frequency;
        }
        return 0;
 }
@@ -544,10 +544,9 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
 }
 
 static struct dvb_frontend_ops or51211_ops = {
-
+       .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
        .info = {
                .name               = "Oren OR51211 VSB Frontend",
-               .type               = FE_ATSC,
                .frequency_min      = 44000000,
                .frequency_max      = 958000000,
                .frequency_stepsize = 166666,
index 0e2f61a8978ffe3febef2321bd1e2d5fcd790cbf..f71b06221e14c44c93cf934988c21b20fcf3f596 100644 (file)
@@ -631,9 +631,9 @@ static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe)
 }
 
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int s5h1409_set_frontend(struct dvb_frontend *fe,
-                                struct dvb_frontend_parameters *p)
+static int s5h1409_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct s5h1409_state *state = fe->demodulator_priv;
 
        dprintk("%s(frequency=%d)\n", __func__, p->frequency);
@@ -642,12 +642,12 @@ static int s5h1409_set_frontend(struct dvb_frontend *fe,
 
        state->current_frequency = p->frequency;
 
-       s5h1409_enable_modulation(fe, p->u.vsb.modulation);
+       s5h1409_enable_modulation(fe, p->modulation);
 
        if (fe->ops.tuner_ops.set_params) {
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 1);
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
@@ -879,7 +879,36 @@ static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr)
 static int s5h1409_read_signal_strength(struct dvb_frontend *fe,
                                        u16 *signal_strength)
 {
-       return s5h1409_read_snr(fe, signal_strength);
+       /* borrowed from lgdt330x.c
+        *
+        * Calculate strength from SNR up to 35dB
+        * Even though the SNR can go higher than 35dB,
+        * there is some comfort factor in having a range of
+        * strong signals that can show at 100%
+        */
+       u16 snr;
+       u32 tmp;
+       int ret = s5h1409_read_snr(fe, &snr);
+
+       *signal_strength = 0;
+
+       if (0 == ret) {
+               /* The following calculation method was chosen
+                * purely for the sake of code re-use from the
+                * other demod drivers that use this method */
+
+               /* Convert from SNR in dB * 10 to 8.24 fixed-point */
+               tmp = (snr * ((1 << 24) / 10));
+
+               /* Convert from 8.24 fixed-point to
+                * scale the range 0 - 35*2^24 into 0 - 65535*/
+               if (tmp >= 8960 * 0x10000)
+                       *signal_strength = 0xffff;
+               else
+                       *signal_strength = tmp / 8960;
+       }
+
+       return ret;
 }
 
 static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
@@ -896,13 +925,13 @@ static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber)
        return s5h1409_read_ucblocks(fe, ber);
 }
 
-static int s5h1409_get_frontend(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *p)
+static int s5h1409_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct s5h1409_state *state = fe->demodulator_priv;
 
        p->frequency = state->current_frequency;
-       p->u.vsb.modulation = state->current_modulation;
+       p->modulation = state->current_modulation;
 
        return 0;
 }
@@ -967,10 +996,9 @@ error:
 EXPORT_SYMBOL(s5h1409_attach);
 
 static struct dvb_frontend_ops s5h1409_ops = {
-
+       .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
        .info = {
                .name                   = "Samsung S5H1409 QAM/8VSB Frontend",
-               .type                   = FE_ATSC,
                .frequency_min          = 54000000,
                .frequency_max          = 858000000,
                .frequency_stepsize     = 62500,
index d8adf1e32019a9f7b62a712d693dd242ee79e036..6cc4b7a9dd60d588c3bc665080eeae68b78c8c21 100644 (file)
@@ -585,9 +585,9 @@ static int s5h1411_register_reset(struct dvb_frontend *fe)
 }
 
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int s5h1411_set_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int s5h1411_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct s5h1411_state *state = fe->demodulator_priv;
 
        dprintk("%s(frequency=%d)\n", __func__, p->frequency);
@@ -596,13 +596,13 @@ static int s5h1411_set_frontend(struct dvb_frontend *fe,
 
        state->current_frequency = p->frequency;
 
-       s5h1411_enable_modulation(fe, p->u.vsb.modulation);
+       s5h1411_enable_modulation(fe, p->modulation);
 
        if (fe->ops.tuner_ops.set_params) {
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 1);
 
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
 
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
@@ -794,7 +794,36 @@ static int s5h1411_read_snr(struct dvb_frontend *fe, u16 *snr)
 static int s5h1411_read_signal_strength(struct dvb_frontend *fe,
        u16 *signal_strength)
 {
-       return s5h1411_read_snr(fe, signal_strength);
+       /* borrowed from lgdt330x.c
+        *
+        * Calculate strength from SNR up to 35dB
+        * Even though the SNR can go higher than 35dB,
+        * there is some comfort factor in having a range of
+        * strong signals that can show at 100%
+        */
+       u16 snr;
+       u32 tmp;
+       int ret = s5h1411_read_snr(fe, &snr);
+
+       *signal_strength = 0;
+
+       if (0 == ret) {
+               /* The following calculation method was chosen
+                * purely for the sake of code re-use from the
+                * other demod drivers that use this method */
+
+               /* Convert from SNR in dB * 10 to 8.24 fixed-point */
+               tmp = (snr * ((1 << 24) / 10));
+
+               /* Convert from 8.24 fixed-point to
+                * scale the range 0 - 35*2^24 into 0 - 65535*/
+               if (tmp >= 8960 * 0x10000)
+                       *signal_strength = 0xffff;
+               else
+                       *signal_strength = tmp / 8960;
+       }
+
+       return ret;
 }
 
 static int s5h1411_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
@@ -811,13 +840,13 @@ static int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber)
        return s5h1411_read_ucblocks(fe, ber);
 }
 
-static int s5h1411_get_frontend(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *p)
+static int s5h1411_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct s5h1411_state *state = fe->demodulator_priv;
 
        p->frequency = state->current_frequency;
-       p->u.vsb.modulation = state->current_modulation;
+       p->modulation = state->current_modulation;
 
        return 0;
 }
@@ -886,10 +915,9 @@ error:
 EXPORT_SYMBOL(s5h1411_attach);
 
 static struct dvb_frontend_ops s5h1411_ops = {
-
+       .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
        .info = {
                .name                   = "Samsung S5H1411 QAM/8VSB Frontend",
-               .type                   = FE_ATSC,
                .frequency_min          = 54000000,
                .frequency_max          = 858000000,
                .frequency_stepsize     = 62500,
index 3879d2e378aa73da4ac1b923a7e163c6c54a48a6..2322257c69ae33bb5af5ed2ea200b82a671ff18a 100644 (file)
@@ -472,15 +472,15 @@ static void s5h1420_reset(struct s5h1420_state* state)
 }
 
 static void s5h1420_setsymbolrate(struct s5h1420_state* state,
-                                 struct dvb_frontend_parameters *p)
+                                 struct dtv_frontend_properties *p)
 {
        u8 v;
        u64 val;
 
        dprintk("enter %s\n", __func__);
 
-       val = ((u64) p->u.qpsk.symbol_rate / 1000ULL) * (1ULL<<24);
-       if (p->u.qpsk.symbol_rate < 29000000)
+       val = ((u64) p->symbol_rate / 1000ULL) * (1ULL<<24);
+       if (p->symbol_rate < 29000000)
                val *= 2;
        do_div(val, (state->fclk / 1000));
 
@@ -543,7 +543,7 @@ static int s5h1420_getfreqoffset(struct s5h1420_state* state)
 }
 
 static void s5h1420_setfec_inversion(struct s5h1420_state* state,
-                                    struct dvb_frontend_parameters *p)
+                                    struct dtv_frontend_properties *p)
 {
        u8 inversion = 0;
        u8 vit08, vit09;
@@ -555,11 +555,11 @@ static void s5h1420_setfec_inversion(struct s5h1420_state* state,
        else if (p->inversion == INVERSION_ON)
                inversion = state->config->invert ? 0 : 0x08;
 
-       if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
+       if ((p->fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
                vit08 = 0x3f;
                vit09 = 0;
        } else {
-               switch(p->u.qpsk.fec_inner) {
+               switch (p->fec_inner) {
                case FEC_1_2:
                        vit08 = 0x01; vit09 = 0x10;
                        break;
@@ -628,9 +628,9 @@ static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state)
        return INVERSION_OFF;
 }
 
-static int s5h1420_set_frontend(struct dvb_frontend* fe,
-                               struct dvb_frontend_parameters *p)
+static int s5h1420_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct s5h1420_state* state = fe->demodulator_priv;
        int frequency_delta;
        struct dvb_frontend_tune_settings fesettings;
@@ -639,17 +639,16 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
        dprintk("enter %s\n", __func__);
 
        /* check if we should do a fast-tune */
-       memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
        s5h1420_get_tune_settings(fe, &fesettings);
        frequency_delta = p->frequency - state->tunedfreq;
        if ((frequency_delta > -fesettings.max_drift) &&
                        (frequency_delta < fesettings.max_drift) &&
                        (frequency_delta != 0) &&
-                       (state->fec_inner == p->u.qpsk.fec_inner) &&
-                       (state->symbol_rate == p->u.qpsk.symbol_rate)) {
+                       (state->fec_inner == p->fec_inner) &&
+                       (state->symbol_rate == p->symbol_rate)) {
 
                if (fe->ops.tuner_ops.set_params) {
-                       fe->ops.tuner_ops.set_params(fe, p);
+                       fe->ops.tuner_ops.set_params(fe);
                        if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
                }
                if (fe->ops.tuner_ops.get_frequency) {
@@ -669,13 +668,13 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
        s5h1420_reset(state);
 
        /* set s5h1420 fclk PLL according to desired symbol rate */
-       if (p->u.qpsk.symbol_rate > 33000000)
+       if (p->symbol_rate > 33000000)
                state->fclk = 80000000;
-       else if (p->u.qpsk.symbol_rate > 28500000)
+       else if (p->symbol_rate > 28500000)
                state->fclk = 59000000;
-       else if (p->u.qpsk.symbol_rate > 25000000)
+       else if (p->symbol_rate > 25000000)
                state->fclk = 86000000;
-       else if (p->u.qpsk.symbol_rate > 1900000)
+       else if (p->symbol_rate > 1900000)
                state->fclk = 88000000;
        else
                state->fclk = 44000000;
@@ -705,7 +704,7 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
        s5h1420_writereg(state, DiS01, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
 
        /* TODO DC offset removal, config parameter ? */
-       if (p->u.qpsk.symbol_rate > 29000000)
+       if (p->symbol_rate > 29000000)
                s5h1420_writereg(state, QPSK01, 0xae | 0x10);
        else
                s5h1420_writereg(state, QPSK01, 0xac | 0x10);
@@ -718,15 +717,15 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
        s5h1420_writereg(state, Loop01, 0xF0);
        s5h1420_writereg(state, Loop02, 0x2a); /* e7 for s5h1420 */
        s5h1420_writereg(state, Loop03, 0x79); /* 78 for s5h1420 */
-       if (p->u.qpsk.symbol_rate > 20000000)
+       if (p->symbol_rate > 20000000)
                s5h1420_writereg(state, Loop04, 0x79);
        else
                s5h1420_writereg(state, Loop04, 0x58);
        s5h1420_writereg(state, Loop05, 0x6b);
 
-       if (p->u.qpsk.symbol_rate >= 8000000)
+       if (p->symbol_rate >= 8000000)
                s5h1420_writereg(state, Post01, (0 << 6) | 0x10);
-       else if (p->u.qpsk.symbol_rate >= 4000000)
+       else if (p->symbol_rate >= 4000000)
                s5h1420_writereg(state, Post01, (1 << 6) | 0x10);
        else
                s5h1420_writereg(state, Post01, (3 << 6) | 0x10);
@@ -744,7 +743,7 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
 
        /* set tuner PLL */
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
                s5h1420_setfreqoffset(state, 0);
@@ -757,8 +756,8 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
        /* start QPSK */
        s5h1420_writereg(state, QPSK01, s5h1420_readreg(state, QPSK01) | 1);
 
-       state->fec_inner = p->u.qpsk.fec_inner;
-       state->symbol_rate = p->u.qpsk.symbol_rate;
+       state->fec_inner = p->fec_inner;
+       state->symbol_rate = p->symbol_rate;
        state->postlocked = 0;
        state->tunedfreq = p->frequency;
 
@@ -766,15 +765,15 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
        return 0;
 }
 
-static int s5h1420_get_frontend(struct dvb_frontend* fe,
-                               struct dvb_frontend_parameters *p)
+static int s5h1420_get_frontend(struct dvb_frontend* fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct s5h1420_state* state = fe->demodulator_priv;
 
        p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state);
        p->inversion = s5h1420_getinversion(state);
-       p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state);
-       p->u.qpsk.fec_inner = s5h1420_getfec(state);
+       p->symbol_rate = s5h1420_getsymbolrate(state);
+       p->fec_inner = s5h1420_getfec(state);
 
        return 0;
 }
@@ -782,29 +781,30 @@ static int s5h1420_get_frontend(struct dvb_frontend* fe,
 static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
                                     struct dvb_frontend_tune_settings* fesettings)
 {
-       if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+       if (p->symbol_rate > 20000000) {
                fesettings->min_delay_ms = 50;
                fesettings->step_size = 2000;
                fesettings->max_drift = 8000;
-       } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) {
+       } else if (p->symbol_rate > 12000000) {
                fesettings->min_delay_ms = 100;
                fesettings->step_size = 1500;
                fesettings->max_drift = 9000;
-       } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) {
+       } else if (p->symbol_rate > 8000000) {
                fesettings->min_delay_ms = 100;
                fesettings->step_size = 1000;
                fesettings->max_drift = 8000;
-       } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) {
+       } else if (p->symbol_rate > 4000000) {
                fesettings->min_delay_ms = 100;
                fesettings->step_size = 500;
                fesettings->max_drift = 7000;
-       } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) {
+       } else if (p->symbol_rate > 2000000) {
                fesettings->min_delay_ms = 200;
-               fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+               fesettings->step_size = (p->symbol_rate / 8000);
                fesettings->max_drift = 14 * fesettings->step_size;
        } else {
                fesettings->min_delay_ms = 200;
-               fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+               fesettings->step_size = (p->symbol_rate / 8000);
                fesettings->max_drift = 18 * fesettings->step_size;
        }
 
@@ -937,10 +937,9 @@ error:
 EXPORT_SYMBOL(s5h1420_attach);
 
 static struct dvb_frontend_ops s5h1420_ops = {
-
+       .delsys = { SYS_DVBS },
        .info = {
                .name     = "Samsung S5H1420/PnpNetwork PN1010 DVB-S",
-               .type     = FE_QPSK,
                .frequency_min    = 950000,
                .frequency_max    = 2150000,
                .frequency_stepsize = 125,     /* kHz for QPSK frontends */
index 0c6dcb90d16826686d97f81be8aca55da555407b..8352ce1c95563798c06f86e4b0f68bec85c6cd7f 100644 (file)
@@ -178,9 +178,9 @@ static int s5h1432_set_IF(struct dvb_frontend *fe, u32 ifFreqHz)
 }
 
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
-static int s5h1432_set_frontend(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *p)
+static int s5h1432_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        u32 dvb_bandwidth = 8;
        struct s5h1432_state *state = fe->demodulator_priv;
 
@@ -188,26 +188,26 @@ static int s5h1432_set_frontend(struct dvb_frontend *fe,
                /*current_frequency = p->frequency; */
                /*state->current_frequency = p->frequency; */
        } else {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                msleep(300);
                s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
-               switch (p->u.ofdm.bandwidth) {
-               case BANDWIDTH_6_MHZ:
+               switch (p->bandwidth_hz) {
+               case 6000000:
                        dvb_bandwidth = 6;
                        s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
                        break;
-               case BANDWIDTH_7_MHZ:
+               case 7000000:
                        dvb_bandwidth = 7;
                        s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
                        break;
-               case BANDWIDTH_8_MHZ:
+               case 8000000:
                        dvb_bandwidth = 8;
                        s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
                        break;
                default:
                        return 0;
                }
-               /*fe->ops.tuner_ops.set_params(fe, p); */
+               /*fe->ops.tuner_ops.set_params(fe); */
 /*Soft Reset chip*/
                msleep(30);
                s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
@@ -215,23 +215,23 @@ static int s5h1432_set_frontend(struct dvb_frontend *fe,
                s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
 
                s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
-               switch (p->u.ofdm.bandwidth) {
-               case BANDWIDTH_6_MHZ:
+               switch (p->bandwidth_hz) {
+               case 6000000:
                        dvb_bandwidth = 6;
                        s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
                        break;
-               case BANDWIDTH_7_MHZ:
+               case 7000000:
                        dvb_bandwidth = 7;
                        s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
                        break;
-               case BANDWIDTH_8_MHZ:
+               case 8000000:
                        dvb_bandwidth = 8;
                        s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
                        break;
                default:
                        return 0;
                }
-               /*fe->ops.tuner_ops.set_params(fe,p); */
+               /*fe->ops.tuner_ops.set_params(fe); */
                /*Soft Reset chip*/
                msleep(30);
                s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
@@ -329,12 +329,6 @@ static int s5h1432_read_ber(struct dvb_frontend *fe, u32 *ber)
        return 0;
 }
 
-static int s5h1432_get_frontend(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *p)
-{
-       return 0;
-}
-
 static int s5h1432_get_tune_settings(struct dvb_frontend *fe,
                                     struct dvb_frontend_tune_settings *tune)
 {
@@ -381,10 +375,9 @@ error:
 EXPORT_SYMBOL(s5h1432_attach);
 
 static struct dvb_frontend_ops s5h1432_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                 .name = "Samsung s5h1432 DVB-T Frontend",
-                .type = FE_OFDM,
                 .frequency_min = 177000000,
                 .frequency_max = 858000000,
                 .frequency_stepsize = 166666,
@@ -397,7 +390,6 @@ static struct dvb_frontend_ops s5h1432_ops = {
        .init = s5h1432_init,
        .sleep = s5h1432_sleep,
        .set_frontend = s5h1432_set_frontend,
-       .get_frontend = s5h1432_get_frontend,
        .get_tune_settings = s5h1432_get_tune_settings,
        .read_status = s5h1432_read_status,
        .read_ber = s5h1432_read_ber,
index ca0103d5f148ae38938e6651bbf272ec13020dbc..cd2288c07147a7614d7d37ef0022400e6b05d318 100644 (file)
@@ -262,9 +262,9 @@ static int s921_i2c_readreg(struct s921_state *state, u8 i2c_addr, u8 reg)
        s921_i2c_writeregdata(state, state->config->demod_address, \
        regdata, ARRAY_SIZE(regdata))
 
-static int s921_pll_tune(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int s921_pll_tune(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct s921_state *state = fe->demodulator_priv;
        int band, rc, i;
        unsigned long f_offset;
@@ -414,9 +414,9 @@ static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
        return 0;
 }
 
-static int s921_set_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int s921_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct s921_state *state = fe->demodulator_priv;
        int rc;
 
@@ -424,7 +424,7 @@ static int s921_set_frontend(struct dvb_frontend *fe,
 
        /* FIXME: We don't know how to use non-auto mode */
 
-       rc = s921_pll_tune(fe, p);
+       rc = s921_pll_tune(fe);
        if (rc < 0)
                return rc;
 
@@ -433,19 +433,20 @@ static int s921_set_frontend(struct dvb_frontend *fe,
        return 0;
 }
 
-static int s921_get_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int s921_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct s921_state *state = fe->demodulator_priv;
 
        /* FIXME: Probably it is possible to get it from regs f1 and f2 */
        p->frequency = state->currentfreq;
+       p->delivery_system = SYS_ISDBT;
 
        return 0;
 }
 
 static int s921_tune(struct dvb_frontend *fe,
-                       struct dvb_frontend_parameters *params,
+                       bool re_tune,
                        unsigned int mode_flags,
                        unsigned int *delay,
                        fe_status_t *status)
@@ -454,8 +455,8 @@ static int s921_tune(struct dvb_frontend *fe,
 
        dprintk("\n");
 
-       if (params != NULL)
-               rc = s921_set_frontend(fe, params);
+       if (re_tune)
+               rc = s921_set_frontend(fe);
 
        if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
                s921_read_status(fe, status);
@@ -510,10 +511,10 @@ rcor:
 EXPORT_SYMBOL(s921_attach);
 
 static struct dvb_frontend_ops s921_ops = {
+       .delsys = { SYS_ISDBT },
        /* Use dib8000 values per default */
        .info = {
                .name = "Sharp S921",
-               .type = FE_OFDM,
                .frequency_min = 470000000,
                /*
                 * Max should be 770MHz instead, according with Sharp docs,
index 4b0c99a08a852ebb01b155cb7c21d27c9b969cd4..a68a64800df77ff7123ae6d18434820d6c95a2b4 100644 (file)
@@ -690,20 +690,7 @@ static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate,
        return status;
 }
 
-static int si21xx_set_property(struct dvb_frontend *fe, struct dtv_property *p)
-{
-       dprintk("%s(..)\n", __func__);
-       return 0;
-}
-
-static int si21xx_get_property(struct dvb_frontend *fe, struct dtv_property *p)
-{
-       dprintk("%s(..)\n", __func__);
-       return 0;
-}
-
-static int si21xx_set_frontend(struct dvb_frontend *fe,
-                                       struct dvb_frontend_parameters *dfp)
+static int si21xx_set_frontend(struct dvb_frontend *fe)
 {
        struct si21xx_state *state = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -877,10 +864,9 @@ static void si21xx_release(struct dvb_frontend *fe)
 }
 
 static struct dvb_frontend_ops si21xx_ops = {
-
+       .delsys = { SYS_DVBS },
        .info = {
                .name                   = "SL SI21XX DVB-S",
-               .type                   = FE_QPSK,
                .frequency_min          = 950000,
                .frequency_max          = 2150000,
                .frequency_stepsize     = 125,   /* kHz for QPSK frontends */
@@ -908,8 +894,6 @@ static struct dvb_frontend_ops si21xx_ops = {
        .set_tone = si21xx_set_tone,
        .set_voltage = si21xx_set_voltage,
 
-       .set_property = si21xx_set_property,
-       .get_property = si21xx_get_property,
        .set_frontend = si21xx_set_frontend,
 };
 
index b85eb60a893e34954a313382a2fad0b5d8a88499..e37274c8f14e004c6058c64d053304704f8196ee 100644 (file)
@@ -168,13 +168,13 @@ static int sp8870_read_data_valid_signal(struct sp8870_state* state)
        return (sp8870_readreg(state, 0x0D02) > 0);
 }
 
-static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
+static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05)
 {
        int known_parameters = 1;
 
        *reg0xc05 = 0x000;
 
-       switch (p->u.ofdm.constellation) {
+       switch (p->modulation) {
        case QPSK:
                break;
        case QAM_16:
@@ -190,7 +190,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
                return -EINVAL;
        };
 
-       switch (p->u.ofdm.hierarchy_information) {
+       switch (p->hierarchy) {
        case HIERARCHY_NONE:
                break;
        case HIERARCHY_1:
@@ -209,7 +209,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
                return -EINVAL;
        };
 
-       switch (p->u.ofdm.code_rate_HP) {
+       switch (p->code_rate_HP) {
        case FEC_1_2:
                break;
        case FEC_2_3:
@@ -245,9 +245,9 @@ static int sp8870_wake_up(struct sp8870_state* state)
        return sp8870_writereg(state, 0xC18, 0x00D);
 }
 
-static int sp8870_set_frontend_parameters (struct dvb_frontend* fe,
-                                          struct dvb_frontend_parameters *p)
+static int sp8870_set_frontend_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct sp8870_state* state = fe->demodulator_priv;
        int  err;
        u16 reg0xc05;
@@ -260,7 +260,7 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe,
 
        // set tuner parameters
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
@@ -277,15 +277,15 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe,
        sp8870_writereg(state, 0x030A, 0x0000);
 
        // filter for 6/7/8 Mhz channel
-       if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+       if (p->bandwidth_hz == 6000000)
                sp8870_writereg(state, 0x0311, 0x0002);
-       else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+       else if (p->bandwidth_hz == 7000000)
                sp8870_writereg(state, 0x0311, 0x0001);
        else
                sp8870_writereg(state, 0x0311, 0x0000);
 
        // scan order: 2k first = 0x0000, 8k first = 0x0001
-       if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K)
+       if (p->transmission_mode == TRANSMISSION_MODE_2K)
                sp8870_writereg(state, 0x0338, 0x0000);
        else
                sp8870_writereg(state, 0x0338, 0x0001);
@@ -459,8 +459,9 @@ static int lockups;
 /* only for debugging: counter for channel switches */
 static int switches;
 
-static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int sp8870_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct sp8870_state* state = fe->demodulator_priv;
 
        /*
@@ -479,7 +480,8 @@ static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_par
 
        for (trials = 1; trials <= MAXTRIALS; trials++) {
 
-               if ((err = sp8870_set_frontend_parameters(fe, p)))
+               err = sp8870_set_frontend_parameters(fe);
+               if (err)
                        return err;
 
                for (check_count = 0; check_count < MAXCHECKS; check_count++) {
@@ -579,10 +581,9 @@ error:
 }
 
 static struct dvb_frontend_ops sp8870_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "Spase SP8870 DVB-T",
-               .type                   = FE_OFDM,
                .frequency_min          = 470000000,
                .frequency_max          = 860000000,
                .frequency_stepsize     = 166666,
index 4a7c3d8426088bdccd39ab95b197b8b2963ab3d9..f4096ccb226e4b76146e001a4d78db1f52d7d756 100644 (file)
@@ -209,13 +209,13 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware
        return 0;
 };
 
-static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
+static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05)
 {
        int known_parameters = 1;
 
        *reg0xc05 = 0x000;
 
-       switch (p->u.ofdm.constellation) {
+       switch (p->modulation) {
        case QPSK:
                break;
        case QAM_16:
@@ -231,7 +231,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
                return -EINVAL;
        };
 
-       switch (p->u.ofdm.hierarchy_information) {
+       switch (p->hierarchy) {
        case HIERARCHY_NONE:
                break;
        case HIERARCHY_1:
@@ -250,7 +250,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
                return -EINVAL;
        };
 
-       switch (p->u.ofdm.code_rate_HP) {
+       switch (p->code_rate_HP) {
        case FEC_1_2:
                break;
        case FEC_2_3:
@@ -303,17 +303,30 @@ static void divide (int n, int d, int *quotient_i, int *quotient_f)
 }
 
 static void sp887x_correct_offsets (struct sp887x_state* state,
-                                   struct dvb_frontend_parameters *p,
+                                   struct dtv_frontend_properties *p,
                                    int actual_freq)
 {
        static const u32 srate_correction [] = { 1879617, 4544878, 8098561 };
-       int bw_index = p->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
+       int bw_index;
        int freq_offset = actual_freq - p->frequency;
        int sysclock = 61003; //[kHz]
        int ifreq = 36000000;
        int freq;
        int frequency_shift;
 
+       switch (p->bandwidth_hz) {
+       default:
+       case 8000000:
+               bw_index = 0;
+               break;
+       case 7000000:
+               bw_index = 1;
+               break;
+       case 6000000:
+               bw_index = 2;
+               break;
+       }
+
        if (p->inversion == INVERSION_ON)
                freq = ifreq - freq_offset;
        else
@@ -333,17 +346,17 @@ static void sp887x_correct_offsets (struct sp887x_state* state,
        sp887x_writereg(state, 0x30a, frequency_shift & 0xfff);
 }
 
-static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
-                                            struct dvb_frontend_parameters *p)
+static int sp887x_setup_frontend_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct sp887x_state* state = fe->demodulator_priv;
        unsigned actual_freq;
        int err;
        u16 val, reg0xc05;
 
-       if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ &&
-           p->u.ofdm.bandwidth != BANDWIDTH_7_MHZ &&
-           p->u.ofdm.bandwidth != BANDWIDTH_6_MHZ)
+       if (p->bandwidth_hz != 8000000 &&
+           p->bandwidth_hz != 7000000 &&
+           p->bandwidth_hz != 6000000)
                return -EINVAL;
 
        if ((err = configure_reg0xc05(p, &reg0xc05)))
@@ -353,7 +366,7 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
 
        /* setup the PLL */
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
        if (fe->ops.tuner_ops.get_frequency) {
@@ -369,9 +382,9 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
        sp887x_correct_offsets(state, p, actual_freq);
 
        /* filter for 6/7/8 Mhz channel */
-       if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+       if (p->bandwidth_hz == 6000000)
                val = 2;
-       else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+       else if (p->bandwidth_hz == 7000000)
                val = 1;
        else
                val = 0;
@@ -379,16 +392,16 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
        sp887x_writereg(state, 0x311, val);
 
        /* scan order: 2k first = 0, 8k first = 1 */
-       if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K)
+       if (p->transmission_mode == TRANSMISSION_MODE_2K)
                sp887x_writereg(state, 0x338, 0x000);
        else
                sp887x_writereg(state, 0x338, 0x001);
 
        sp887x_writereg(state, 0xc05, reg0xc05);
 
-       if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+       if (p->bandwidth_hz == 6000000)
                val = 2 << 3;
-       else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+       else if (p->bandwidth_hz == 7000000)
                val = 3 << 3;
        else
                val = 0 << 3;
@@ -579,10 +592,9 @@ error:
 }
 
 static struct dvb_frontend_ops sp887x_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name = "Spase SP887x DVB-T",
-               .type = FE_OFDM,
                .frequency_min =  50500000,
                .frequency_max = 858000000,
                .frequency_stepsize = 166666,
index 8408ef877b4be55e0e2e88bfc6c6ae6945024c63..38565beafe23a8594c22d8fbe5bc710fc74dd2f0 100644 (file)
@@ -1431,7 +1431,7 @@ static void stb0899_set_iterations(struct stb0899_state *state)
        stb0899_write_s2reg(state, STB0899_S2FEC, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg);
 }
 
-static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static enum dvbfe_search stb0899_search(struct dvb_frontend *fe)
 {
        struct stb0899_state *state = fe->demodulator_priv;
        struct stb0899_params *i_params = &state->params;
@@ -1441,8 +1441,8 @@ static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_fron
 
        u32 SearchRange, gain;
 
-       i_params->freq  = p->frequency;
-       i_params->srate = p->u.qpsk.symbol_rate;
+       i_params->freq  = props->frequency;
+       i_params->srate = props->symbol_rate;
        state->delsys = props->delivery_system;
        dprintk(state->verbose, FE_DEBUG, 1, "delivery system=%d", state->delsys);
 
@@ -1568,34 +1568,15 @@ static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_fron
 
        return DVBFE_ALGO_SEARCH_ERROR;
 }
-/*
- * stb0899_track
- * periodically check the signal level against a specified
- * threshold level and perform derotator centering.
- * called once we have a lock from a successful search
- * event.
- *
- * Will be called periodically called to maintain the
- * lock.
- *
- * Will be used to get parameters as well as info from
- * the decoded baseband header
- *
- * Once a new lock has established, the internal state
- * frequency (internal->freq) is updated
- */
-static int stb0899_track(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
-{
-       return 0;
-}
 
-static int stb0899_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int stb0899_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stb0899_state *state             = fe->demodulator_priv;
        struct stb0899_internal *internal       = &state->internal;
 
        dprintk(state->verbose, FE_DEBUG, 1, "Get params");
-       p->u.qpsk.symbol_rate = internal->srate;
+       p->symbol_rate = internal->srate;
 
        return 0;
 }
@@ -1606,10 +1587,9 @@ static enum dvbfe_algo stb0899_frontend_algo(struct dvb_frontend *fe)
 }
 
 static struct dvb_frontend_ops stb0899_ops = {
-
+       .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
        .info = {
                .name                   = "STB0899 Multistandard",
-               .type                   = FE_QPSK,
                .frequency_min          = 950000,
                .frequency_max          = 2150000,
                .frequency_stepsize     = 0,
@@ -1632,8 +1612,7 @@ static struct dvb_frontend_ops stb0899_ops = {
 
        .get_frontend_algo              = stb0899_frontend_algo,
        .search                         = stb0899_search,
-       .track                          = stb0899_track,
-       .get_frontend                   = stb0899_get_frontend,
+       .get_frontend                   = stb0899_get_frontend,
 
 
        .read_status                    = stb0899_read_status,
index ed699647050e5eec49422391e98f660d7c9611cf..a0c3c526b132415d5bc705c2f5c8064e64fb9243 100644 (file)
@@ -75,9 +75,9 @@ static int stb6000_sleep(struct dvb_frontend *fe)
        return (ret == 1) ? 0 : ret;
 }
 
-static int stb6000_set_params(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *params)
+static int stb6000_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stb6000_priv *priv = fe->tuner_priv;
        unsigned int n, m;
        int ret;
@@ -93,8 +93,8 @@ static int stb6000_set_params(struct dvb_frontend *fe,
 
        dprintk("%s:\n", __func__);
 
-       freq_mhz = params->frequency / 1000;
-       bandwidth = params->u.qpsk.symbol_rate / 1000000;
+       freq_mhz = p->frequency / 1000;
+       bandwidth = p->symbol_rate / 1000000;
 
        if (bandwidth > 31)
                bandwidth = 31;
index bc1a8af4f6e105181670ee33ebe111f98425e0ff..def88abb30bf14b630f5110bf39732881159a2da 100644 (file)
@@ -327,7 +327,7 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
        int rc;
        const struct stb6100_lkup *ptr;
        struct stb6100_state *state = fe->tuner_priv;
-       struct dvb_frontend_parameters p;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 
        u32 srate = 0, fvco, nint, nfrac;
        u8 regs[STB6100_NUMREGS];
@@ -337,9 +337,9 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
 
        if (fe->ops.get_frontend) {
                dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters");
-               fe->ops.get_frontend(fe, &p);
+               fe->ops.get_frontend(fe);
        }
-       srate = p.u.qpsk.symbol_rate;
+       srate = p->symbol_rate;
 
        /* Set up tuner cleanly, LPF calibration on */
        rc = stb6100_write_reg(state, STB6100_FCCK, 0x4d | STB6100_FCCK_FCCK);
index 0aa3962ff18bc37bb07d5e838fe43596405d9c20..fb5548a82208276281fdfe95e0d1206f8c9f18bd 100644 (file)
@@ -452,14 +452,7 @@ static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p)
        return 0;
 }
 
-static int stv0288_get_property(struct dvb_frontend *fe, struct dtv_property *p)
-{
-       dprintk("%s(..)\n", __func__);
-       return 0;
-}
-
-static int stv0288_set_frontend(struct dvb_frontend *fe,
-                                       struct dvb_frontend_parameters *dfp)
+static int stv0288_set_frontend(struct dvb_frontend *fe)
 {
        struct stv0288_state *state = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -481,10 +474,8 @@ static int stv0288_set_frontend(struct dvb_frontend *fe,
                state->config->set_ts_params(fe, 0);
 
        /* only frequency & symbol_rate are used for tuner*/
-       dfp->frequency = c->frequency;
-       dfp->u.qpsk.symbol_rate = c->symbol_rate;
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, dfp);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
@@ -545,10 +536,9 @@ static void stv0288_release(struct dvb_frontend *fe)
 }
 
 static struct dvb_frontend_ops stv0288_ops = {
-
+       .delsys = { SYS_DVBS },
        .info = {
                .name                   = "ST STV0288 DVB-S",
-               .type                   = FE_QPSK,
                .frequency_min          = 950000,
                .frequency_max          = 2150000,
                .frequency_stepsize     = 1000,  /* kHz for QPSK frontends */
@@ -578,7 +568,6 @@ static struct dvb_frontend_ops stv0288_ops = {
        .set_voltage = stv0288_set_voltage,
 
        .set_property = stv0288_set_property,
-       .get_property = stv0288_get_property,
        .set_frontend = stv0288_set_frontend,
 };
 
index 84d88f33275e060f690ffdf5b288d038431b561b..85c157a1fe5eec513623870e8424c4c4d197c280 100644 (file)
@@ -404,8 +404,9 @@ static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
        return 0;
 }
 
-static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int stv0297_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stv0297_state *state = fe->demodulator_priv;
        int u_threshold;
        int initial_u;
@@ -417,7 +418,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
        unsigned long timeout;
        fe_spectral_inversion_t inversion;
 
-       switch (p->u.qam.modulation) {
+       switch (p->modulation) {
        case QAM_16:
        case QAM_32:
        case QAM_64:
@@ -455,7 +456,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
 
        stv0297_init(fe);
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
@@ -519,16 +520,16 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
        stv0297_writereg_mask(state, 0x69, 0x0f, 0x00);
 
        /* set parameters */
-       stv0297_set_qam(state, p->u.qam.modulation);
-       stv0297_set_symbolrate(state, p->u.qam.symbol_rate / 1000);
-       stv0297_set_sweeprate(state, sweeprate, p->u.qam.symbol_rate / 1000);
+       stv0297_set_qam(state, p->modulation);
+       stv0297_set_symbolrate(state, p->symbol_rate / 1000);
+       stv0297_set_sweeprate(state, sweeprate, p->symbol_rate / 1000);
        stv0297_set_carrieroffset(state, carrieroffset);
        stv0297_set_inversion(state, inversion);
 
        /* kick off lock */
        /* Disable corner detection for higher QAMs */
-       if (p->u.qam.modulation == QAM_128 ||
-               p->u.qam.modulation == QAM_256)
+       if (p->modulation == QAM_128 ||
+               p->modulation == QAM_256)
                stv0297_writereg_mask(state, 0x88, 0x08, 0x00);
        else
                stv0297_writereg_mask(state, 0x88, 0x08, 0x08);
@@ -613,8 +614,9 @@ timeout:
        return 0;
 }
 
-static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static int stv0297_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stv0297_state *state = fe->demodulator_priv;
        int reg_00, reg_83;
 
@@ -625,24 +627,24 @@ static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
        p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF;
        if (state->config->invert)
                p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON;
-       p->u.qam.symbol_rate = stv0297_get_symbolrate(state) * 1000;
-       p->u.qam.fec_inner = FEC_NONE;
+       p->symbol_rate = stv0297_get_symbolrate(state) * 1000;
+       p->fec_inner = FEC_NONE;
 
        switch ((reg_00 >> 4) & 0x7) {
        case 0:
-               p->u.qam.modulation = QAM_16;
+               p->modulation = QAM_16;
                break;
        case 1:
-               p->u.qam.modulation = QAM_32;
+               p->modulation = QAM_32;
                break;
        case 2:
-               p->u.qam.modulation = QAM_128;
+               p->modulation = QAM_128;
                break;
        case 3:
-               p->u.qam.modulation = QAM_256;
+               p->modulation = QAM_256;
                break;
        case 4:
-               p->u.qam.modulation = QAM_64;
+               p->modulation = QAM_64;
                break;
        }
 
@@ -688,10 +690,9 @@ error:
 }
 
 static struct dvb_frontend_ops stv0297_ops = {
-
+       .delsys = { SYS_DVBC_ANNEX_A },
        .info = {
                 .name = "ST STV0297 DVB-C",
-                .type = FE_QAM,
                 .frequency_min = 47000000,
                 .frequency_max = 862000000,
                 .frequency_stepsize = 62500,
index 42684bec888374a6f8315a96b3b85b046947814d..057b5f8effc0dec16c24f3753329bf8ed354e8bb 100644 (file)
@@ -559,8 +559,9 @@ static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        return 0;
 }
 
-static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
+static int stv0299_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stv0299_state* state = fe->demodulator_priv;
        int invval = 0;
 
@@ -579,24 +580,25 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
-       stv0299_set_FEC (state, p->u.qpsk.fec_inner);
-       stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
+       stv0299_set_FEC(state, p->fec_inner);
+       stv0299_set_symbolrate(fe, p->symbol_rate);
        stv0299_writeregI(state, 0x22, 0x00);
        stv0299_writeregI(state, 0x23, 0x00);
 
        state->tuner_frequency = p->frequency;
-       state->fec_inner = p->u.qpsk.fec_inner;
-       state->symbol_rate = p->u.qpsk.symbol_rate;
+       state->fec_inner = p->fec_inner;
+       state->symbol_rate = p->symbol_rate;
 
        return 0;
 }
 
-static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
+static int stv0299_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stv0299_state* state = fe->demodulator_priv;
        s32 derot_freq;
        int invval;
@@ -614,8 +616,8 @@ static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        if (state->config->invert) invval = (~invval) & 1;
        p->inversion = invval ? INVERSION_ON : INVERSION_OFF;
 
-       p->u.qpsk.fec_inner = stv0299_get_fec (state);
-       p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state);
+       p->fec_inner = stv0299_get_fec(state);
+       p->symbol_rate = stv0299_get_symbolrate(state);
 
        return 0;
 }
@@ -646,14 +648,15 @@ static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
 static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
 {
        struct stv0299_state* state = fe->demodulator_priv;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 
        fesettings->min_delay_ms = state->config->min_delay_ms;
-       if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) {
-               fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000;
+       if (p->symbol_rate < 10000000) {
+               fesettings->step_size = p->symbol_rate / 32000;
                fesettings->max_drift = 5000;
        } else {
-               fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000;
-               fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000;
+               fesettings->step_size = p->symbol_rate / 16000;
+               fesettings->max_drift = p->symbol_rate / 2000;
        }
        return 0;
 }
@@ -705,10 +708,9 @@ error:
 }
 
 static struct dvb_frontend_ops stv0299_ops = {
-
+       .delsys = { SYS_DVBS },
        .info = {
                .name                   = "ST STV0299 DVB-S",
-               .type                   = FE_QPSK,
                .frequency_min          = 950000,
                .frequency_max          = 2150000,
                .frequency_stepsize     = 125,   /* kHz for QPSK frontends */
index e57ab53e2e27a7ad6bde437afdbdbc00a7278d85..fdd20c7737b57a968d4e5e8edf4d9900ef859d2b 100644 (file)
@@ -1577,9 +1577,9 @@ int stv0367ter_init(struct dvb_frontend *fe)
        return 0;
 }
 
-static int stv0367ter_algo(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *param)
+static int stv0367ter_algo(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stv0367_state *state = fe->demodulator_priv;
        struct stv0367ter_state *ter_state = state->ter_state;
        int offset = 0, tempo = 0;
@@ -1591,7 +1591,7 @@ static int stv0367ter_algo(struct dvb_frontend *fe,
 
        dprintk("%s:\n", __func__);
 
-       ter_state->frequency = param->frequency;
+       ter_state->frequency = p->frequency;
        ter_state->force = FE_TER_FORCENONE
                        + stv0367_readbits(state, F367TER_FORCE) * 2;
        ter_state->if_iq_mode = state->config->if_iq_mode;
@@ -1620,7 +1620,7 @@ static int stv0367ter_algo(struct dvb_frontend *fe,
 
        usleep_range(5000, 7000);
 
-       switch (param->inversion) {
+       switch (p->inversion) {
        case INVERSION_AUTO:
        default:
                dprintk("%s: inversion AUTO\n", __func__);
@@ -1636,10 +1636,10 @@ static int stv0367ter_algo(struct dvb_frontend *fe,
        case INVERSION_OFF:
                if (ter_state->if_iq_mode == FE_TER_IQ_TUNER)
                        stv0367_writebits(state, F367TER_IQ_INVERT,
-                                               param->inversion);
+                                               p->inversion);
                else
                        stv0367_writebits(state, F367TER_INV_SPECTR,
-                                               param->inversion);
+                                               p->inversion);
 
                break;
        }
@@ -1806,10 +1806,9 @@ static int stv0367ter_algo(struct dvb_frontend *fe,
        return 0;
 }
 
-static int stv0367ter_set_frontend(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *param)
+static int stv0367ter_set_frontend(struct dvb_frontend *fe)
 {
-       struct dvb_ofdm_parameters *op = &param->u.ofdm;
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stv0367_state *state = fe->demodulator_priv;
        struct stv0367ter_state *ter_state = state->ter_state;
 
@@ -1822,12 +1821,12 @@ static int stv0367ter_set_frontend(struct dvb_frontend *fe,
        if (fe->ops.tuner_ops.set_params) {
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 1);
-               fe->ops.tuner_ops.set_params(fe, param);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
-       switch (op->transmission_mode) {
+       switch (p->transmission_mode) {
        default:
        case TRANSMISSION_MODE_AUTO:
        case TRANSMISSION_MODE_2K:
@@ -1841,34 +1840,34 @@ static int stv0367ter_set_frontend(struct dvb_frontend *fe,
                break;
        }
 
-       switch (op->guard_interval) {
+       switch (p->guard_interval) {
        default:
        case GUARD_INTERVAL_1_32:
        case GUARD_INTERVAL_1_16:
        case GUARD_INTERVAL_1_8:
        case GUARD_INTERVAL_1_4:
-               ter_state->guard = op->guard_interval;
+               ter_state->guard = p->guard_interval;
                break;
        case GUARD_INTERVAL_AUTO:
                ter_state->guard = GUARD_INTERVAL_1_32;
                break;
        }
 
-       switch (op->bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       switch (p->bandwidth_hz) {
+       case 6000000:
                ter_state->bw = FE_TER_CHAN_BW_6M;
                break;
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                ter_state->bw = FE_TER_CHAN_BW_7M;
                break;
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
        default:
                ter_state->bw = FE_TER_CHAN_BW_8M;
        }
 
        ter_state->hierarchy = FE_TER_HIER_NONE;
 
-       switch (param->inversion) {
+       switch (p->inversion) {
        case INVERSION_OFF:
        case INVERSION_ON:
                num_trials = 1;
@@ -1885,14 +1884,14 @@ static int stv0367ter_set_frontend(struct dvb_frontend *fe,
 
        while (((index) < num_trials) && (ter_state->state != FE_TER_LOCKOK)) {
                if (!ter_state->first_lock) {
-                       if (param->inversion == INVERSION_AUTO)
+                       if (p->inversion == INVERSION_AUTO)
                                ter_state->sense = SenseTrials[index];
 
                }
-               stv0367ter_algo(fe,/* &pLook, result,*/ param);
+               stv0367ter_algo(fe);
 
                if ((ter_state->state == FE_TER_LOCKOK) &&
-                               (param->inversion == INVERSION_AUTO) &&
+                               (p->inversion == INVERSION_AUTO) &&
                                                                (index == 1)) {
                        /* invert spectrum sense */
                        SenseTrials[index] = SenseTrials[0];
@@ -1927,50 +1926,48 @@ static int stv0367ter_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
        return 0;
 }
 
-static int stv0367ter_get_frontend(struct dvb_frontend *fe,
-                                 struct dvb_frontend_parameters *param)
+static int stv0367ter_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stv0367_state *state = fe->demodulator_priv;
        struct stv0367ter_state *ter_state = state->ter_state;
-       struct dvb_ofdm_parameters *op = &param->u.ofdm;
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
        int error = 0;
        enum stv0367_ter_mode mode;
        int constell = 0,/* snr = 0,*/ Data = 0;
 
-       param->frequency = stv0367_get_tuner_freq(fe);
-       if ((int)param->frequency < 0)
-               param->frequency = c->frequency;
+       p->frequency = stv0367_get_tuner_freq(fe);
+       if ((int)p->frequency < 0)
+               p->frequency = -p->frequency;
 
        constell = stv0367_readbits(state, F367TER_TPS_CONST);
        if (constell == 0)
-               op->constellation = QPSK;
+               p->modulation = QPSK;
        else if (constell == 1)
-               op->constellation = QAM_16;
+               p->modulation = QAM_16;
        else
-               op->constellation = QAM_64;
+               p->modulation = QAM_64;
 
-       param->inversion = stv0367_readbits(state, F367TER_INV_SPECTR);
+       p->inversion = stv0367_readbits(state, F367TER_INV_SPECTR);
 
        /* Get the Hierarchical mode */
        Data = stv0367_readbits(state, F367TER_TPS_HIERMODE);
 
        switch (Data) {
        case 0:
-               op->hierarchy_information = HIERARCHY_NONE;
+               p->hierarchy = HIERARCHY_NONE;
                break;
        case 1:
-               op->hierarchy_information = HIERARCHY_1;
+               p->hierarchy = HIERARCHY_1;
                break;
        case 2:
-               op->hierarchy_information = HIERARCHY_2;
+               p->hierarchy = HIERARCHY_2;
                break;
        case 3:
-               op->hierarchy_information = HIERARCHY_4;
+               p->hierarchy = HIERARCHY_4;
                break;
        default:
-               op->hierarchy_information = HIERARCHY_AUTO;
+               p->hierarchy = HIERARCHY_AUTO;
                break; /* error */
        }
 
@@ -1982,22 +1979,22 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe,
 
        switch (Data) {
        case 0:
-               op->code_rate_HP = FEC_1_2;
+               p->code_rate_HP = FEC_1_2;
                break;
        case 1:
-               op->code_rate_HP = FEC_2_3;
+               p->code_rate_HP = FEC_2_3;
                break;
        case 2:
-               op->code_rate_HP = FEC_3_4;
+               p->code_rate_HP = FEC_3_4;
                break;
        case 3:
-               op->code_rate_HP = FEC_5_6;
+               p->code_rate_HP = FEC_5_6;
                break;
        case 4:
-               op->code_rate_HP = FEC_7_8;
+               p->code_rate_HP = FEC_7_8;
                break;
        default:
-               op->code_rate_HP = FEC_AUTO;
+               p->code_rate_HP = FEC_AUTO;
                break; /* error */
        }
 
@@ -2005,19 +2002,19 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe,
 
        switch (mode) {
        case FE_TER_MODE_2K:
-               op->transmission_mode = TRANSMISSION_MODE_2K;
+               p->transmission_mode = TRANSMISSION_MODE_2K;
                break;
 /*     case FE_TER_MODE_4K:
-               op->transmission_mode = TRANSMISSION_MODE_4K;
+               p->transmission_mode = TRANSMISSION_MODE_4K;
                break;*/
        case FE_TER_MODE_8K:
-               op->transmission_mode = TRANSMISSION_MODE_8K;
+               p->transmission_mode = TRANSMISSION_MODE_8K;
                break;
        default:
-               op->transmission_mode = TRANSMISSION_MODE_AUTO;
+               p->transmission_mode = TRANSMISSION_MODE_AUTO;
        }
 
-       op->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD);
+       p->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD);
 
        return error;
 }
@@ -2265,9 +2262,9 @@ static void stv0367_release(struct dvb_frontend *fe)
 }
 
 static struct dvb_frontend_ops stv0367ter_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "ST STV0367 DVB-T",
-               .type                   = FE_OFDM,
                .frequency_min          = 47000000,
                .frequency_max          = 862000000,
                .frequency_stepsize     = 15625,
@@ -2822,9 +2819,8 @@ int stv0367cab_init(struct dvb_frontend *fe)
 }
 static
 enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
-                               struct dvb_frontend_parameters *param)
+                                            struct dtv_frontend_properties *p)
 {
-       struct dvb_qam_parameters *op = &param->u.qam;
        struct stv0367cab_state *cab_state = state->cab_state;
        enum stv0367_cab_signal_type signalType = FE_CAB_NOAGC;
        u32     QAMFEC_Lock, QAM_Lock, u32_tmp,
@@ -2839,7 +2835,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
        /* A max lock time of 25 ms is allowed for delayed AGC */
        AGCTimeOut = 25;
        /* 100000 symbols needed by the TRL as a maximum value */
-       TRLTimeOut = 100000000 / op->symbol_rate;
+       TRLTimeOut = 100000000 / p->symbol_rate;
        /* CRLSymbols is the needed number of symbols to achieve a lock
           within [-4%, +4%] of the symbol rate.
           CRL timeout is calculated
@@ -2849,7 +2845,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
           A characterization must be performed
           with these echoes to get new timeout values.
        */
-       switch (op->modulation) {
+       switch (p->modulation) {
        case QAM_16:
                CRLSymbols = 150000;
                EQLTimeOut = 100;
@@ -2883,9 +2879,9 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
        } else
 #endif
        CRLTimeOut = (25 * CRLSymbols * (cab_state->search_range / 1000)) /
-                                       (op->symbol_rate / 1000);
+                                       (p->symbol_rate / 1000);
 
-       CRLTimeOut = (1000 * CRLTimeOut) / op->symbol_rate;
+       CRLTimeOut = (1000 * CRLTimeOut) / p->symbol_rate;
        /* Timeouts below 50ms are coerced */
        if (CRLTimeOut < 50)
                CRLTimeOut = 50;
@@ -2915,7 +2911,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
        stv0367cab_set_derot_freq(state, cab_state->adc_clk,
                (1000 * (s32)state->config->if_khz + cab_state->derot_offset));
        /* Disable the Allpass Filter when the symbol rate is out of range */
-       if ((op->symbol_rate > 10800000) | (op->symbol_rate < 1800000)) {
+       if ((p->symbol_rate > 10800000) | (p->symbol_rate < 1800000)) {
                stv0367_writebits(state, F367CAB_ADJ_EN, 0);
                stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0);
        }
@@ -2999,7 +2995,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
 
        if (QAMFEC_Lock) {
                signalType = FE_CAB_DATAOK;
-               cab_state->modulation = op->modulation;
+               cab_state->modulation = p->modulation;
                cab_state->spect_inv = stv0367_readbits(state,
                                                        F367CAB_QUAD_INV);
 #if 0
@@ -3081,20 +3077,19 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
        return signalType;
 }
 
-static int stv0367cab_set_frontend(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *param)
+static int stv0367cab_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stv0367_state *state = fe->demodulator_priv;
        struct stv0367cab_state *cab_state = state->cab_state;
-       struct dvb_qam_parameters *op = &param->u.qam;
        enum stv0367cab_mod QAMSize = 0;
 
        dprintk("%s: freq = %d, srate = %d\n", __func__,
-                                       param->frequency, op->symbol_rate);
+                                       p->frequency, p->symbol_rate);
 
        cab_state->derot_offset = 0;
 
-       switch (op->modulation) {
+       switch (p->modulation) {
        case QAM_16:
                QAMSize = FE_CAB_MOD_QAM16;
                break;
@@ -3120,77 +3115,76 @@ static int stv0367cab_set_frontend(struct dvb_frontend *fe,
        if (fe->ops.tuner_ops.set_params) {
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 1);
-               fe->ops.tuner_ops.set_params(fe, param);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
        stv0367cab_SetQamSize(
                        state,
-                       op->symbol_rate,
+                       p->symbol_rate,
                        QAMSize);
 
        stv0367cab_set_srate(state,
                        cab_state->adc_clk,
                        cab_state->mclk,
-                       op->symbol_rate,
+                       p->symbol_rate,
                        QAMSize);
        /* Search algorithm launch, [-1.1*RangeOffset, +1.1*RangeOffset] scan */
-       cab_state->state = stv0367cab_algo(state, param);
+       cab_state->state = stv0367cab_algo(state, p);
        return 0;
 }
 
-static int stv0367cab_get_frontend(struct dvb_frontend *fe,
-                                 struct dvb_frontend_parameters *param)
+static int stv0367cab_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stv0367_state *state = fe->demodulator_priv;
        struct stv0367cab_state *cab_state = state->cab_state;
-       struct dvb_qam_parameters *op = &param->u.qam;
 
        enum stv0367cab_mod QAMSize;
 
        dprintk("%s:\n", __func__);
 
-       op->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk);
+       p->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk);
 
        QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE);
        switch (QAMSize) {
        case FE_CAB_MOD_QAM16:
-               op->modulation = QAM_16;
+               p->modulation = QAM_16;
                break;
        case FE_CAB_MOD_QAM32:
-               op->modulation = QAM_32;
+               p->modulation = QAM_32;
                break;
        case FE_CAB_MOD_QAM64:
-               op->modulation = QAM_64;
+               p->modulation = QAM_64;
                break;
        case FE_CAB_MOD_QAM128:
-               op->modulation = QAM_128;
+               p->modulation = QAM_128;
                break;
        case QAM_256:
-               op->modulation = QAM_256;
+               p->modulation = QAM_256;
                break;
        default:
                break;
        }
 
-       param->frequency = stv0367_get_tuner_freq(fe);
+       p->frequency = stv0367_get_tuner_freq(fe);
 
-       dprintk("%s: tuner frequency = %d\n", __func__, param->frequency);
+       dprintk("%s: tuner frequency = %d\n", __func__, p->frequency);
 
        if (state->config->if_khz == 0) {
-               param->frequency +=
+               p->frequency +=
                        (stv0367cab_get_derot_freq(state, cab_state->adc_clk) -
                        cab_state->adc_clk / 4000);
                return 0;
        }
 
        if (state->config->if_khz > cab_state->adc_clk / 1000)
-               param->frequency += (state->config->if_khz
+               p->frequency += (state->config->if_khz
                        - stv0367cab_get_derot_freq(state, cab_state->adc_clk)
                        - cab_state->adc_clk / 1000);
        else
-               param->frequency += (state->config->if_khz
+               p->frequency += (state->config->if_khz
                        - stv0367cab_get_derot_freq(state, cab_state->adc_clk));
 
        return 0;
@@ -3386,9 +3380,9 @@ static int stv0367cab_read_ucblcks(struct dvb_frontend *fe, u32 *ucblocks)
 };
 
 static struct dvb_frontend_ops stv0367cab_ops = {
+       .delsys = { SYS_DVBC_ANNEX_A },
        .info = {
                .name = "ST STV0367 DVB-C",
-               .type = FE_QAM,
                .frequency_min = 47000000,
                .frequency_max = 862000000,
                .frequency_stepsize = 62500,
index 0ca316d6fffacf68733df21fe3e5419149b8ea0f..7f1badaf0d03044b2c2e4779ed746e2d03bbae0c 100644 (file)
@@ -973,22 +973,6 @@ static enum dvbfe_algo stv0900_frontend_algo(struct dvb_frontend *fe)
        return DVBFE_ALGO_CUSTOM;
 }
 
-static int stb0900_set_property(struct dvb_frontend *fe,
-                               struct dtv_property *tvp)
-{
-       dprintk("%s(..)\n", __func__);
-
-       return 0;
-}
-
-static int stb0900_get_property(struct dvb_frontend *fe,
-                               struct dtv_property *tvp)
-{
-       dprintk("%s(..)\n", __func__);
-
-       return 0;
-}
-
 void stv0900_start_search(struct stv0900_internal *intp,
                                enum fe_stv0900_demod_num demod)
 {
@@ -1574,8 +1558,7 @@ static int stv0900_status(struct stv0900_internal *intp,
        return locked;
 }
 
-static enum dvbfe_search stv0900_search(struct dvb_frontend *fe,
-                                       struct dvb_frontend_parameters *params)
+static enum dvbfe_search stv0900_search(struct dvb_frontend *fe)
 {
        struct stv0900_state *state = fe->demodulator_priv;
        struct stv0900_internal *intp = state->internal;
@@ -1675,12 +1658,6 @@ static int stv0900_read_status(struct dvb_frontend *fe, enum fe_status *status)
        return 0;
 }
 
-static int stv0900_track(struct dvb_frontend *fe,
-                       struct dvb_frontend_parameters *p)
-{
-       return 0;
-}
-
 static int stv0900_stop_ts(struct dvb_frontend *fe, int stop_ts)
 {
 
@@ -1866,24 +1843,23 @@ static int stv0900_sleep(struct dvb_frontend *fe)
        return 0;
 }
 
-static int stv0900_get_frontend(struct dvb_frontend *fe,
-                               struct dvb_frontend_parameters *p)
+static int stv0900_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct stv0900_state *state = fe->demodulator_priv;
        struct stv0900_internal *intp = state->internal;
        enum fe_stv0900_demod_num demod = state->demod;
        struct stv0900_signal_info p_result = intp->result[demod];
 
        p->frequency = p_result.locked ? p_result.frequency : 0;
-       p->u.qpsk.symbol_rate = p_result.locked ? p_result.symbol_rate : 0;
+       p->symbol_rate = p_result.locked ? p_result.symbol_rate : 0;
        return 0;
 }
 
 static struct dvb_frontend_ops stv0900_ops = {
-
+       .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
        .info = {
                .name                   = "STV0900 frontend",
-               .type                   = FE_QPSK,
                .frequency_min          = 950000,
                .frequency_max          = 2150000,
                .frequency_stepsize     = 125,
@@ -1907,10 +1883,7 @@ static struct dvb_frontend_ops stv0900_ops = {
        .diseqc_send_burst              = stv0900_send_burst,
        .diseqc_recv_slave_reply        = stv0900_recv_slave_reply,
        .set_tone                       = stv0900_set_tone,
-       .set_property                   = stb0900_set_property,
-       .get_property                   = stb0900_get_property,
        .search                         = stv0900_search,
-       .track                          = stv0900_track,
        .read_status                    = stv0900_read_status,
        .read_ber                       = stv0900_read_ber,
        .read_signal_strength           = stv0900_read_signal_strength,
index ebda41936b9094b3cc3259231337c507dd474360..4aef1877ed422deb38d9dd4f53658f7601b1afdc 100644 (file)
@@ -3427,17 +3427,17 @@ err:
        return -1;
 }
 
-static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static enum dvbfe_search stv090x_search(struct dvb_frontend *fe)
 {
        struct stv090x_state *state = fe->demodulator_priv;
        struct dtv_frontend_properties *props = &fe->dtv_property_cache;
 
-       if (p->frequency == 0)
+       if (props->frequency == 0)
                return DVBFE_ALGO_SEARCH_INVALID;
 
        state->delsys = props->delivery_system;
-       state->frequency = p->frequency;
-       state->srate = p->u.qpsk.symbol_rate;
+       state->frequency = props->frequency;
+       state->srate = props->symbol_rate;
        state->search_mode = STV090x_SEARCH_AUTO;
        state->algo = STV090x_COLD_SEARCH;
        state->fec = STV090x_PRERR;
@@ -4712,10 +4712,9 @@ int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value,
 EXPORT_SYMBOL(stv090x_set_gpio);
 
 static struct dvb_frontend_ops stv090x_ops = {
-
+       .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
        .info = {
                .name                   = "STV090x Multistandard",
-               .type                   = FE_QPSK,
                .frequency_min          = 950000,
                .frequency_max          = 2150000,
                .frequency_stepsize     = 0,
@@ -4743,7 +4742,7 @@ static struct dvb_frontend_ops stv090x_ops = {
        .read_status                    = stv090x_read_status,
        .read_ber                       = stv090x_read_per,
        .read_signal_strength           = stv090x_read_signal_strength,
-       .read_snr                       = stv090x_read_cnr
+       .read_snr                       = stv090x_read_cnr,
 };
 
 
index 2dca7c8e5148bb989b1e75b7ec5605afdf72851d..20b5fa92c53e7374977b55800ec95c831239966c 100644 (file)
@@ -347,8 +347,7 @@ static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency)
        return 0;
 }
 
-static int stv6110_set_params(struct dvb_frontend *fe,
-                             struct dvb_frontend_parameters *params)
+static int stv6110_set_params(struct dvb_frontend *fe)
 {
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        u32 bandwidth = carrier_width(c->symbol_rate, c->rolloff);
index 6ca533ea0f0ec047258a568335b7fa17e3762b96..1bff7f457e196257136fa71a2790010d5ec370bb 100644 (file)
@@ -224,47 +224,86 @@ static int tda10021_init (struct dvb_frontend *fe)
        return 0;
 }
 
-static int tda10021_set_parameters (struct dvb_frontend *fe,
-                           struct dvb_frontend_parameters *p)
+struct qam_params {
+       u8 conf, agcref, lthr, mseth, aref;
+};
+
+static int tda10021_set_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 delsys  = c->delivery_system;
+       unsigned qam = c->modulation;
+       bool is_annex_c;
+       u32 reg0x3d;
        struct tda10021_state* state = fe->demodulator_priv;
+       static const struct qam_params qam_params[] = {
+               /* Modulation  Conf  AGCref  LTHR  MSETH  AREF */
+               [QPSK]     = { 0x14, 0x78,   0x78, 0x8c,  0x96 },
+               [QAM_16]   = { 0x00, 0x8c,   0x87, 0xa2,  0x91 },
+               [QAM_32]   = { 0x04, 0x8c,   0x64, 0x74,  0x96 },
+               [QAM_64]   = { 0x08, 0x6a,   0x46, 0x43,  0x6a },
+               [QAM_128]  = { 0x0c, 0x78,   0x36, 0x34,  0x7e },
+               [QAM_256]  = { 0x10, 0x5c,   0x26, 0x23,  0x6b },
+       };
+
+       switch (delsys) {
+       case SYS_DVBC_ANNEX_A:
+               is_annex_c = false;
+               break;
+       case SYS_DVBC_ANNEX_C:
+               is_annex_c = true;
+               break;
+       default:
+               return -EINVAL;
+       }
 
-       //table for QAM4-QAM256 ready  QAM4  QAM16 QAM32 QAM64 QAM128 QAM256
-       //CONF
-       static const u8 reg0x00 [] = { 0x14, 0x00, 0x04, 0x08, 0x0c,  0x10 };
-       //AGCREF value
-       static const u8 reg0x01 [] = { 0x78, 0x8c, 0x8c, 0x6a, 0x78,  0x5c };
-       //LTHR value
-       static const u8 reg0x05 [] = { 0x78, 0x87, 0x64, 0x46, 0x36,  0x26 };
-       //MSETH
-       static const u8 reg0x08 [] = { 0x8c, 0xa2, 0x74, 0x43, 0x34,  0x23 };
-       //AREF
-       static const u8 reg0x09 [] = { 0x96, 0x91, 0x96, 0x6a, 0x7e,  0x6b };
-
-       int qam = p->u.qam.modulation;
-
-       if (qam < 0 || qam > 5)
+       /*
+        * gcc optimizes the code bellow the same way as it would code:
+        *           "if (qam > 5) return -EINVAL;"
+        * Yet, the code is clearer, as it shows what QAM standards are
+        * supported by the driver, and avoids the usage of magic numbers on
+        * it.
+        */
+       switch (qam) {
+       case QPSK:
+       case QAM_16:
+       case QAM_32:
+       case QAM_64:
+       case QAM_128:
+       case QAM_256:
+               break;
+       default:
                return -EINVAL;
+       }
 
-       if (p->inversion != INVERSION_ON && p->inversion != INVERSION_OFF)
+       if (c->inversion != INVERSION_ON && c->inversion != INVERSION_OFF)
                return -EINVAL;
 
-       //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate);
+       /*printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->symbol_rate);*/
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
-       tda10021_set_symbolrate (state, p->u.qam.symbol_rate);
-       _tda10021_writereg (state, 0x34, state->pwm);
-
-       _tda10021_writereg (state, 0x01, reg0x01[qam]);
-       _tda10021_writereg (state, 0x05, reg0x05[qam]);
-       _tda10021_writereg (state, 0x08, reg0x08[qam]);
-       _tda10021_writereg (state, 0x09, reg0x09[qam]);
-
-       tda10021_setup_reg0 (state, reg0x00[qam], p->inversion);
+       tda10021_set_symbolrate(state, c->symbol_rate);
+       _tda10021_writereg(state, 0x34, state->pwm);
+
+       _tda10021_writereg(state, 0x01, qam_params[qam].agcref);
+       _tda10021_writereg(state, 0x05, qam_params[qam].lthr);
+       _tda10021_writereg(state, 0x08, qam_params[qam].mseth);
+       _tda10021_writereg(state, 0x09, qam_params[qam].aref);
+
+       /*
+        * Bit 0 == 0 means roll-off = 0.15 (Annex A)
+        *       == 1 means roll-off = 0.13 (Annex C)
+        */
+       reg0x3d = tda10021_readreg (state, 0x3d);
+       if (is_annex_c)
+               _tda10021_writereg (state, 0x3d, 0x01 | reg0x3d);
+       else
+               _tda10021_writereg (state, 0x3d, 0xfe & reg0x3d);
+       tda10021_setup_reg0(state, qam_params[qam].conf, c->inversion);
 
        return 0;
 }
@@ -347,8 +386,9 @@ static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        return 0;
 }
 
-static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int tda10021_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct tda10021_state* state = fe->demodulator_priv;
        int sync;
        s8 afc = 0;
@@ -360,17 +400,17 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa
                printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" :
                                  "DVB: TDA10021(%d): [AFC (%d) %dHz]\n",
                        state->frontend.dvb->num, afc,
-                      -((s32)p->u.qam.symbol_rate * afc) >> 10);
+                      -((s32)p->symbol_rate * afc) >> 10);
        }
 
        p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF;
-       p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+       p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
 
-       p->u.qam.fec_inner = FEC_NONE;
+       p->fec_inner = FEC_NONE;
        p->frequency = ((p->frequency + 31250) / 62500) * 62500;
 
        if (sync & 2)
-               p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10;
+               p->frequency -= ((s32)p->symbol_rate * afc) >> 10;
 
        return 0;
 }
@@ -444,10 +484,9 @@ error:
 }
 
 static struct dvb_frontend_ops tda10021_ops = {
-
+       .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C },
        .info = {
                .name = "Philips TDA10021 DVB-C",
-               .type = FE_QAM,
                .frequency_stepsize = 62500,
                .frequency_min = 47000000,
                .frequency_max = 862000000,
index a3c34eecdee9a81315bf68b44c5d6f23923c5cda..ca1e0d54b69afcf343221120f7cb6636962a10d6 100644 (file)
@@ -298,42 +298,80 @@ static int tda10023_init (struct dvb_frontend *fe)
        return 0;
 }
 
-static int tda10023_set_parameters (struct dvb_frontend *fe,
-                           struct dvb_frontend_parameters *p)
+struct qam_params {
+       u8 qam, lockthr, mseth, aref, agcrefnyq, eragnyq_thd;
+};
+
+static int tda10023_set_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 delsys  = c->delivery_system;
+       unsigned qam = c->modulation;
+       bool is_annex_c;
        struct tda10023_state* state = fe->demodulator_priv;
-
-       static int qamvals[6][6] = {
-               //  QAM   LOCKTHR  MSETH   AREF AGCREFNYQ  ERAGCNYQ_THD
-               { (5<<2),  0x78,    0x8c,   0x96,   0x78,   0x4c  },  // 4 QAM
-               { (0<<2),  0x87,    0xa2,   0x91,   0x8c,   0x57  },  // 16 QAM
-               { (1<<2),  0x64,    0x74,   0x96,   0x8c,   0x57  },  // 32 QAM
-               { (2<<2),  0x46,    0x43,   0x6a,   0x6a,   0x44  },  // 64 QAM
-               { (3<<2),  0x36,    0x34,   0x7e,   0x78,   0x4c  },  // 128 QAM
-               { (4<<2),  0x26,    0x23,   0x6c,   0x5c,   0x3c  },  // 256 QAM
+       static const struct qam_params qam_params[] = {
+               /* Modulation  QAM    LOCKTHR   MSETH   AREF AGCREFNYQ ERAGCNYQ_THD */
+               [QPSK]    = { (5<<2),  0x78,    0x8c,   0x96,   0x78,   0x4c  },
+               [QAM_16]  = { (0<<2),  0x87,    0xa2,   0x91,   0x8c,   0x57  },
+               [QAM_32]  = { (1<<2),  0x64,    0x74,   0x96,   0x8c,   0x57  },
+               [QAM_64]  = { (2<<2),  0x46,    0x43,   0x6a,   0x6a,   0x44  },
+               [QAM_128] = { (3<<2),  0x36,    0x34,   0x7e,   0x78,   0x4c  },
+               [QAM_256] = { (4<<2),  0x26,    0x23,   0x6c,   0x5c,   0x3c  },
        };
 
-       int qam = p->u.qam.modulation;
+       switch (delsys) {
+       case SYS_DVBC_ANNEX_A:
+               is_annex_c = false;
+               break;
+       case SYS_DVBC_ANNEX_C:
+               is_annex_c = true;
+               break;
+       default:
+               return -EINVAL;
+       }
 
-       if (qam < 0 || qam > 5)
+       /*
+        * gcc optimizes the code bellow the same way as it would code:
+        *               "if (qam > 5) return -EINVAL;"
+        * Yet, the code is clearer, as it shows what QAM standards are
+        * supported by the driver, and avoids the usage of magic numbers on
+        * it.
+        */
+       switch (qam) {
+       case QPSK:
+       case QAM_16:
+       case QAM_32:
+       case QAM_64:
+       case QAM_128:
+       case QAM_256:
+               break;
+       default:
                return -EINVAL;
+       }
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
-       tda10023_set_symbolrate (state, p->u.qam.symbol_rate);
-       tda10023_writereg (state, 0x05, qamvals[qam][1]);
-       tda10023_writereg (state, 0x08, qamvals[qam][2]);
-       tda10023_writereg (state, 0x09, qamvals[qam][3]);
-       tda10023_writereg (state, 0xb4, qamvals[qam][4]);
-       tda10023_writereg (state, 0xb6, qamvals[qam][5]);
-
-//     tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32));
-//     tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20));
-       tda10023_writebit (state, 0x04, 0x40, 0x40);
-       tda10023_setup_reg0 (state, qamvals[qam][0]);
+       tda10023_set_symbolrate(state, c->symbol_rate);
+       tda10023_writereg(state, 0x05, qam_params[qam].lockthr);
+       tda10023_writereg(state, 0x08, qam_params[qam].mseth);
+       tda10023_writereg(state, 0x09, qam_params[qam].aref);
+       tda10023_writereg(state, 0xb4, qam_params[qam].agcrefnyq);
+       tda10023_writereg(state, 0xb6, qam_params[qam].eragnyq_thd);
+#if 0
+       tda10023_writereg(state, 0x04, (c->inversion ? 0x12 : 0x32));
+       tda10023_writebit(state, 0x04, 0x60, (c->inversion ? 0 : 0x20));
+#endif
+       tda10023_writebit(state, 0x04, 0x40, 0x40);
+
+       if (is_annex_c)
+               tda10023_writebit(state, 0x3d, 0xfc, 0x03);
+       else
+               tda10023_writebit(state, 0x3d, 0xfc, 0x02);
+
+       tda10023_setup_reg0(state, qam_params[qam].qam);
 
        return 0;
 }
@@ -418,8 +456,9 @@ static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        return 0;
 }
 
-static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int tda10023_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct tda10023_state* state = fe->demodulator_priv;
        int sync,inv;
        s8 afc = 0;
@@ -433,17 +472,17 @@ static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa
                printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" :
                                  "DVB: TDA10023(%d): [AFC (%d) %dHz]\n",
                        state->frontend.dvb->num, afc,
-                      -((s32)p->u.qam.symbol_rate * afc) >> 10);
+                      -((s32)p->symbol_rate * afc) >> 10);
        }
 
        p->inversion = (inv&0x20?0:1);
-       p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+       p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
 
-       p->u.qam.fec_inner = FEC_NONE;
+       p->fec_inner = FEC_NONE;
        p->frequency = ((p->frequency + 31250) / 62500) * 62500;
 
        if (sync & 2)
-               p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10;
+               p->frequency -= ((s32)p->symbol_rate * afc) >> 10;
 
        return 0;
 }
@@ -534,10 +573,9 @@ error:
 }
 
 static struct dvb_frontend_ops tda10023_ops = {
-
+       .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C },
        .info = {
                .name = "Philips TDA10023 DVB-C",
-               .type = FE_QAM,
                .frequency_stepsize = 62500,
                .frequency_min =  47000000,
                .frequency_max = 862000000,
@@ -557,7 +595,6 @@ static struct dvb_frontend_ops tda10023_ops = {
 
        .set_frontend = tda10023_set_parameters,
        .get_frontend = tda10023_get_frontend,
-
        .read_status = tda10023_read_status,
        .read_ber = tda10023_read_ber,
        .read_signal_strength = tda10023_read_signal_strength,
index 7f105946a4342171056e8b774c7032ec4970dedc..71fb63299de78414d003f507ebca09f2a2b86bb5 100644 (file)
@@ -153,7 +153,7 @@ struct tda10048_state {
        u32 pll_pfactor;
        u32 sample_freq;
 
-       enum fe_bandwidth bandwidth;
+       u32 bandwidth;
 };
 
 static struct init_tab {
@@ -341,21 +341,14 @@ static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz,
 {
        struct tda10048_state *state = fe->demodulator_priv;
        u64 t, z;
-       u32 b = 8000000;
 
        dprintk(1, "%s()\n", __func__);
 
        if (sample_freq_hz == 0)
                return -EINVAL;
 
-       if (bw == BANDWIDTH_6_MHZ)
-               b = 6000000;
-       else
-       if (bw == BANDWIDTH_7_MHZ)
-               b = 7000000;
-
        /* WREF = (B / (7 * fs)) * 2^31 */
-       t = b * 10;
+       t = bw * 10;
        /* avoid warning: this decimal constant is unsigned only in ISO C90 */
        /* t *= 2147483648 on 32bit platforms */
        t *= (2048 * 1024);
@@ -378,25 +371,18 @@ static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz,
 {
        struct tda10048_state *state = fe->demodulator_priv;
        u64 t;
-       u32 b = 8000000;
 
        dprintk(1, "%s()\n", __func__);
 
        if (sample_freq_hz == 0)
                return -EINVAL;
 
-       if (bw == BANDWIDTH_6_MHZ)
-               b = 6000000;
-       else
-       if (bw == BANDWIDTH_7_MHZ)
-               b = 7000000;
-
        /* INVWREF = ((7 * fs) / B) * 2^5 */
        t = sample_freq_hz;
        t *= 7;
        t *= 32;
        t *= 10;
-       do_div(t, b);
+       do_div(t, bw);
        t += 5;
        do_div(t, 10);
 
@@ -407,16 +393,16 @@ static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz,
 }
 
 static int tda10048_set_bandwidth(struct dvb_frontend *fe,
-       enum fe_bandwidth bw)
+       u32 bw)
 {
        struct tda10048_state *state = fe->demodulator_priv;
        dprintk(1, "%s(bw=%d)\n", __func__, bw);
 
        /* Bandwidth setting may need to be adjusted */
        switch (bw) {
-       case BANDWIDTH_6_MHZ:
-       case BANDWIDTH_7_MHZ:
-       case BANDWIDTH_8_MHZ:
+       case 6000000:
+       case 7000000:
+       case 8000000:
                tda10048_set_wref(fe, state->sample_freq, bw);
                tda10048_set_invwref(fe, state->sample_freq, bw);
                break;
@@ -430,7 +416,7 @@ static int tda10048_set_bandwidth(struct dvb_frontend *fe,
        return 0;
 }
 
-static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw)
+static int tda10048_set_if(struct dvb_frontend *fe, u32 bw)
 {
        struct tda10048_state *state = fe->demodulator_priv;
        struct tda10048_config *config = &state->config;
@@ -441,13 +427,13 @@ static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw)
 
        /* based on target bandwidth and clk we calculate pll factors */
        switch (bw) {
-       case BANDWIDTH_6_MHZ:
+       case 6000000:
                if_freq_khz = config->dtv6_if_freq_khz;
                break;
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                if_freq_khz = config->dtv7_if_freq_khz;
                break;
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
                if_freq_khz = config->dtv8_if_freq_khz;
                break;
        default:
@@ -601,7 +587,7 @@ static int tda10048_set_inversion(struct dvb_frontend *fe, int inversion)
 
 /* Retrieve the demod settings */
 static int tda10048_get_tps(struct tda10048_state *state,
-       struct dvb_ofdm_parameters *p)
+       struct dtv_frontend_properties *p)
 {
        u8 val;
 
@@ -612,27 +598,27 @@ static int tda10048_get_tps(struct tda10048_state *state,
        val = tda10048_readreg(state, TDA10048_OUT_CONF2);
        switch ((val & 0x60) >> 5) {
        case 0:
-               p->constellation = QPSK;
+               p->modulation = QPSK;
                break;
        case 1:
-               p->constellation = QAM_16;
+               p->modulation = QAM_16;
                break;
        case 2:
-               p->constellation = QAM_64;
+               p->modulation = QAM_64;
                break;
        }
        switch ((val & 0x18) >> 3) {
        case 0:
-               p->hierarchy_information = HIERARCHY_NONE;
+               p->hierarchy = HIERARCHY_NONE;
                break;
        case 1:
-               p->hierarchy_information = HIERARCHY_1;
+               p->hierarchy = HIERARCHY_1;
                break;
        case 2:
-               p->hierarchy_information = HIERARCHY_2;
+               p->hierarchy = HIERARCHY_2;
                break;
        case 3:
-               p->hierarchy_information = HIERARCHY_4;
+               p->hierarchy = HIERARCHY_4;
                break;
        }
        switch (val & 0x07) {
@@ -738,17 +724,17 @@ static int tda10048_output_mode(struct dvb_frontend *fe, int serial)
 
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
 /* TODO: Support manual tuning with specific params */
-static int tda10048_set_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int tda10048_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct tda10048_state *state = fe->demodulator_priv;
 
        dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency);
 
        /* Update the I/F pll's if the bandwidth changes */
-       if (p->u.ofdm.bandwidth != state->bandwidth) {
-               tda10048_set_if(fe, p->u.ofdm.bandwidth);
-               tda10048_set_bandwidth(fe, p->u.ofdm.bandwidth);
+       if (p->bandwidth_hz != state->bandwidth) {
+               tda10048_set_if(fe, p->bandwidth_hz);
+               tda10048_set_bandwidth(fe, p->bandwidth_hz);
        }
 
        if (fe->ops.tuner_ops.set_params) {
@@ -756,7 +742,7 @@ static int tda10048_set_frontend(struct dvb_frontend *fe,
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 1);
 
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
 
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
@@ -797,8 +783,8 @@ static int tda10048_init(struct dvb_frontend *fe)
        tda10048_set_inversion(fe, config->inversion);
 
        /* Establish default RF values */
-       tda10048_set_if(fe, BANDWIDTH_8_MHZ);
-       tda10048_set_bandwidth(fe, BANDWIDTH_8_MHZ);
+       tda10048_set_if(fe, 8000000);
+       tda10048_set_bandwidth(fe, 8000000);
 
        /* Ensure we leave the gate closed */
        tda10048_i2c_gate_ctrl(fe, 0);
@@ -1042,9 +1028,9 @@ static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
        return 0;
 }
 
-static int tda10048_get_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int tda10048_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct tda10048_state *state = fe->demodulator_priv;
 
        dprintk(1, "%s()\n", __func__);
@@ -1052,7 +1038,7 @@ static int tda10048_get_frontend(struct dvb_frontend *fe,
        p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1)
                & 0x20 ? INVERSION_ON : INVERSION_OFF;
 
-       return tda10048_get_tps(state, &p->u.ofdm);
+       return tda10048_get_tps(state, p);
 }
 
 static int tda10048_get_tune_settings(struct dvb_frontend *fe,
@@ -1126,7 +1112,7 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
        memcpy(&state->config, config, sizeof(*config));
        state->i2c = i2c;
        state->fwloaded = config->no_firmware;
-       state->bandwidth = BANDWIDTH_8_MHZ;
+       state->bandwidth = 8000000;
 
        /* check if the demod is present */
        if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048)
@@ -1152,11 +1138,11 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
        tda10048_establish_defaults(&state->frontend);
 
        /* Set the xtal and freq defaults */
-       if (tda10048_set_if(&state->frontend, BANDWIDTH_8_MHZ) != 0)
+       if (tda10048_set_if(&state->frontend, 8000000) != 0)
                goto error;
 
        /* Default bandwidth */
-       if (tda10048_set_bandwidth(&state->frontend, BANDWIDTH_8_MHZ) != 0)
+       if (tda10048_set_bandwidth(&state->frontend, 8000000) != 0)
                goto error;
 
        /* Leave the gate closed */
@@ -1171,10 +1157,9 @@ error:
 EXPORT_SYMBOL(tda10048_attach);
 
 static struct dvb_frontend_ops tda10048_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "NXP TDA10048HN DVB-T",
-               .type                   = FE_OFDM,
                .frequency_min          = 177000000,
                .frequency_max          = 858000000,
                .frequency_stepsize     = 166666,
index ea485d9235508c4053ff64c76125af960c8b6daf..ae6f22aae677e3e0a88988233f380e47e249f47d 100644 (file)
@@ -224,22 +224,22 @@ static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state)
 }
 
 static int tda10045h_set_bandwidth(struct tda1004x_state *state,
-                                  fe_bandwidth_t bandwidth)
+                                  u32 bandwidth)
 {
        static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
        static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };
        static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };
 
        switch (bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       case 6000000:
                tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz));
                break;
 
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz));
                break;
 
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
                tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));
                break;
 
@@ -253,7 +253,7 @@ static int tda10045h_set_bandwidth(struct tda1004x_state *state,
 }
 
 static int tda10046h_set_bandwidth(struct tda1004x_state *state,
-                                  fe_bandwidth_t bandwidth)
+                                  u32 bandwidth)
 {
        static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 };
        static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f };
@@ -270,7 +270,7 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state,
        else
                tda10046_clk53m = 1;
        switch (bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       case 6000000:
                if (tda10046_clk53m)
                        tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M,
                                                  sizeof(bandwidth_6mhz_53M));
@@ -283,7 +283,7 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state,
                }
                break;
 
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                if (tda10046_clk53m)
                        tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M,
                                                  sizeof(bandwidth_7mhz_53M));
@@ -296,7 +296,7 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state,
                }
                break;
 
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
                if (tda10046_clk53m)
                        tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M,
                                                  sizeof(bandwidth_8mhz_53M));
@@ -409,7 +409,7 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
        msleep(10);
 
        /* set parameters */
-       tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ);
+       tda10045h_set_bandwidth(state, 8000000);
 
        ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
        release_firmware(fw);
@@ -473,7 +473,7 @@ static void tda10046_init_plls(struct dvb_frontend* fe)
                tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f);
                break;
        }
-       tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
+       tda10046h_set_bandwidth(state, 8000000); /* default bandwidth 8 MHz */
        /* let the PLLs settle */
        msleep(120);
 }
@@ -697,9 +697,9 @@ static int tda10046_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int tda1004x_set_fe(struct dvb_frontend* fe,
-                          struct dvb_frontend_parameters *fe_params)
+static int tda1004x_set_fe(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
        struct tda1004x_state* state = fe->demodulator_priv;
        int tmp;
        int inversion;
@@ -718,7 +718,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
 
        // set frequency
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, fe_params);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
        }
@@ -726,37 +726,37 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
        // Hardcoded to use auto as much as possible on the TDA10045 as it
        // is very unreliable if AUTO mode is _not_ used.
        if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
-               fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
-               fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
-               fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+               fe_params->code_rate_HP = FEC_AUTO;
+               fe_params->guard_interval = GUARD_INTERVAL_AUTO;
+               fe_params->transmission_mode = TRANSMISSION_MODE_AUTO;
        }
 
        // Set standard params.. or put them to auto
-       if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) ||
-               (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
-               (fe_params->u.ofdm.constellation == QAM_AUTO) ||
-               (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
+       if ((fe_params->code_rate_HP == FEC_AUTO) ||
+               (fe_params->code_rate_LP == FEC_AUTO) ||
+               (fe_params->modulation == QAM_AUTO) ||
+               (fe_params->hierarchy == HIERARCHY_AUTO)) {
                tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1);        // enable auto
-               tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits
+               tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); /* turn off modulation bits */
                tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits
                tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits
        } else {
                tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0);        // disable auto
 
                // set HP FEC
-               tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP);
+               tmp = tda1004x_encode_fec(fe_params->code_rate_HP);
                if (tmp < 0)
                        return tmp;
                tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp);
 
                // set LP FEC
-               tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP);
+               tmp = tda1004x_encode_fec(fe_params->code_rate_LP);
                if (tmp < 0)
                        return tmp;
                tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3);
 
-               // set constellation
-               switch (fe_params->u.ofdm.constellation) {
+               /* set modulation */
+               switch (fe_params->modulation) {
                case QPSK:
                        tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0);
                        break;
@@ -774,7 +774,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
                }
 
                // set hierarchy
-               switch (fe_params->u.ofdm.hierarchy_information) {
+               switch (fe_params->hierarchy) {
                case HIERARCHY_NONE:
                        tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5);
                        break;
@@ -799,11 +799,11 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
        // set bandwidth
        switch (state->demod_type) {
        case TDA1004X_DEMOD_TDA10045:
-               tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth);
+               tda10045h_set_bandwidth(state, fe_params->bandwidth_hz);
                break;
 
        case TDA1004X_DEMOD_TDA10046:
-               tda10046h_set_bandwidth(state, fe_params->u.ofdm.bandwidth);
+               tda10046h_set_bandwidth(state, fe_params->bandwidth_hz);
                break;
        }
 
@@ -825,7 +825,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
        }
 
        // set guard interval
-       switch (fe_params->u.ofdm.guard_interval) {
+       switch (fe_params->guard_interval) {
        case GUARD_INTERVAL_1_32:
                tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0);
                tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2);
@@ -856,7 +856,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
        }
 
        // set transmission mode
-       switch (fe_params->u.ofdm.transmission_mode) {
+       switch (fe_params->transmission_mode) {
        case TRANSMISSION_MODE_2K:
                tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0);
                tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4);
@@ -895,8 +895,9 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
        return 0;
 }
 
-static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
+static int tda1004x_get_fe(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
        struct tda1004x_state* state = fe->demodulator_priv;
 
        dprintk("%s\n", __func__);
@@ -913,13 +914,13 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete
        case TDA1004X_DEMOD_TDA10045:
                switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) {
                case 0x14:
-                       fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+                       fe_params->bandwidth_hz = 8000000;
                        break;
                case 0xdb:
-                       fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+                       fe_params->bandwidth_hz = 7000000;
                        break;
                case 0x4f:
-                       fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+                       fe_params->bandwidth_hz = 6000000;
                        break;
                }
                break;
@@ -927,73 +928,73 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete
                switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) {
                case 0x5c:
                case 0x54:
-                       fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+                       fe_params->bandwidth_hz = 8000000;
                        break;
                case 0x6a:
                case 0x60:
-                       fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+                       fe_params->bandwidth_hz = 7000000;
                        break;
                case 0x7b:
                case 0x70:
-                       fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+                       fe_params->bandwidth_hz = 6000000;
                        break;
                }
                break;
        }
 
        // FEC
-       fe_params->u.ofdm.code_rate_HP =
+       fe_params->code_rate_HP =
            tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7);
-       fe_params->u.ofdm.code_rate_LP =
+       fe_params->code_rate_LP =
            tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7);
 
-       // constellation
+       /* modulation */
        switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) {
        case 0:
-               fe_params->u.ofdm.constellation = QPSK;
+               fe_params->modulation = QPSK;
                break;
        case 1:
-               fe_params->u.ofdm.constellation = QAM_16;
+               fe_params->modulation = QAM_16;
                break;
        case 2:
-               fe_params->u.ofdm.constellation = QAM_64;
+               fe_params->modulation = QAM_64;
                break;
        }
 
        // transmission mode
-       fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+       fe_params->transmission_mode = TRANSMISSION_MODE_2K;
        if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10)
-               fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+               fe_params->transmission_mode = TRANSMISSION_MODE_8K;
 
        // guard interval
        switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) {
        case 0:
-               fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+               fe_params->guard_interval = GUARD_INTERVAL_1_32;
                break;
        case 1:
-               fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+               fe_params->guard_interval = GUARD_INTERVAL_1_16;
                break;
        case 2:
-               fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+               fe_params->guard_interval = GUARD_INTERVAL_1_8;
                break;
        case 3:
-               fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+               fe_params->guard_interval = GUARD_INTERVAL_1_4;
                break;
        }
 
        // hierarchy
        switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) {
        case 0:
-               fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+               fe_params->hierarchy = HIERARCHY_NONE;
                break;
        case 1:
-               fe_params->u.ofdm.hierarchy_information = HIERARCHY_1;
+               fe_params->hierarchy = HIERARCHY_1;
                break;
        case 2:
-               fe_params->u.ofdm.hierarchy_information = HIERARCHY_2;
+               fe_params->hierarchy = HIERARCHY_2;
                break;
        case 3:
-               fe_params->u.ofdm.hierarchy_information = HIERARCHY_4;
+               fe_params->hierarchy = HIERARCHY_4;
                break;
        }
 
@@ -1231,9 +1232,9 @@ static void tda1004x_release(struct dvb_frontend* fe)
 }
 
 static struct dvb_frontend_ops tda10045_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                .name = "Philips TDA10045H DVB-T",
-               .type = FE_OFDM,
                .frequency_min = 51000000,
                .frequency_max = 858000000,
                .frequency_stepsize = 166667,
@@ -1301,9 +1302,9 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
 }
 
 static struct dvb_frontend_ops tda10046_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                .name = "Philips TDA10046H DVB-T",
-               .type = FE_OFDM,
                .frequency_min = 51000000,
                .frequency_max = 858000000,
                .frequency_stepsize = 166667,
index 0c37434d19e20adb34024b3421ce55cf94df34f9..a99205026751c6b77c581e31cbcbe58a70e1e60f 100644 (file)
@@ -636,8 +636,7 @@ error:
        return ret;
 }
 
-static int tda10071_set_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params)
+static int tda10071_set_frontend(struct dvb_frontend *fe)
 {
        struct tda10071_priv *priv = fe->demodulator_priv;
        struct tda10071_cmd cmd;
@@ -777,8 +776,7 @@ error:
        return ret;
 }
 
-static int tda10071_get_frontend(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *p)
+static int tda10071_get_frontend(struct dvb_frontend *fe)
 {
        struct tda10071_priv *priv = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -1217,9 +1215,9 @@ error:
 EXPORT_SYMBOL(tda10071_attach);
 
 static struct dvb_frontend_ops tda10071_ops = {
+       .delsys = { SYS_DVBT, SYS_DVBT2 },
        .info = {
                .name = "NXP TDA10071",
-               .type = FE_QPSK,
                .frequency_min = 950000,
                .frequency_max = 2150000,
                .frequency_tolerance = 5000,
index f2c8faac6f36426e0c7beb3f361e223b3b12cfcd..fcfe2e080cb042a0ea68e8f1ffb8bbe740ce134c 100644 (file)
@@ -267,7 +267,7 @@ static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minic
 }
 
 static int tda10086_set_inversion(struct tda10086_state *state,
-                                 struct dvb_frontend_parameters *fe_params)
+                                 struct dtv_frontend_properties *fe_params)
 {
        u8 invval = 0x80;
 
@@ -292,7 +292,7 @@ static int tda10086_set_inversion(struct tda10086_state *state,
 }
 
 static int tda10086_set_symbol_rate(struct tda10086_state *state,
-                                   struct dvb_frontend_parameters *fe_params)
+                                   struct dtv_frontend_properties *fe_params)
 {
        u8 dfn = 0;
        u8 afs = 0;
@@ -303,7 +303,7 @@ static int tda10086_set_symbol_rate(struct tda10086_state *state,
        u32 tmp;
        u32 bdr;
        u32 bdri;
-       u32 symbol_rate = fe_params->u.qpsk.symbol_rate;
+       u32 symbol_rate = fe_params->symbol_rate;
 
        dprintk ("%s %i\n", __func__, symbol_rate);
 
@@ -367,13 +367,13 @@ static int tda10086_set_symbol_rate(struct tda10086_state *state,
 }
 
 static int tda10086_set_fec(struct tda10086_state *state,
-                           struct dvb_frontend_parameters *fe_params)
+                           struct dtv_frontend_properties *fe_params)
 {
        u8 fecval;
 
-       dprintk ("%s %i\n", __func__, fe_params->u.qpsk.fec_inner);
+       dprintk("%s %i\n", __func__, fe_params->fec_inner);
 
-       switch(fe_params->u.qpsk.fec_inner) {
+       switch (fe_params->fec_inner) {
        case FEC_1_2:
                fecval = 0x00;
                break;
@@ -409,9 +409,9 @@ static int tda10086_set_fec(struct tda10086_state *state,
        return 0;
 }
 
-static int tda10086_set_frontend(struct dvb_frontend* fe,
-                                struct dvb_frontend_parameters *fe_params)
+static int tda10086_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
        struct tda10086_state *state = fe->demodulator_priv;
        int ret;
        u32 freq = 0;
@@ -425,7 +425,7 @@ static int tda10086_set_frontend(struct dvb_frontend* fe,
 
        /* set params */
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, fe_params);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
 
@@ -452,13 +452,14 @@ static int tda10086_set_frontend(struct dvb_frontend* fe,
        tda10086_write_mask(state, 0x10, 0x40, 0x40);
        tda10086_write_mask(state, 0x00, 0x01, 0x00);
 
-       state->symbol_rate = fe_params->u.qpsk.symbol_rate;
+       state->symbol_rate = fe_params->symbol_rate;
        state->frequency = fe_params->frequency;
        return 0;
 }
 
-static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
+static int tda10086_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
        struct tda10086_state* state = fe->demodulator_priv;
        u8 val;
        int tmp;
@@ -467,7 +468,7 @@ static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa
        dprintk ("%s\n", __func__);
 
        /* check for invalid symbol rate */
-       if (fe_params->u.qpsk.symbol_rate < 500000)
+       if (fe_params->symbol_rate < 500000)
                return -EINVAL;
 
        /* calculate the updated frequency (note: we convert from Hz->kHz) */
@@ -516,34 +517,34 @@ static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa
                tmp |= 0xffffff00;
        tmp = (tmp * 480 * (1<<1)) / 128;
        tmp = ((state->symbol_rate/1000) * tmp) / (1000000/1000);
-       fe_params->u.qpsk.symbol_rate = state->symbol_rate + tmp;
+       fe_params->symbol_rate = state->symbol_rate + tmp;
 
        /* the FEC */
        val = (tda10086_read_byte(state, 0x0d) & 0x70) >> 4;
        switch(val) {
        case 0x00:
-               fe_params->u.qpsk.fec_inner = FEC_1_2;
+               fe_params->fec_inner = FEC_1_2;
                break;
        case 0x01:
-               fe_params->u.qpsk.fec_inner = FEC_2_3;
+               fe_params->fec_inner = FEC_2_3;
                break;
        case 0x02:
-               fe_params->u.qpsk.fec_inner = FEC_3_4;
+               fe_params->fec_inner = FEC_3_4;
                break;
        case 0x03:
-               fe_params->u.qpsk.fec_inner = FEC_4_5;
+               fe_params->fec_inner = FEC_4_5;
                break;
        case 0x04:
-               fe_params->u.qpsk.fec_inner = FEC_5_6;
+               fe_params->fec_inner = FEC_5_6;
                break;
        case 0x05:
-               fe_params->u.qpsk.fec_inner = FEC_6_7;
+               fe_params->fec_inner = FEC_6_7;
                break;
        case 0x06:
-               fe_params->u.qpsk.fec_inner = FEC_7_8;
+               fe_params->fec_inner = FEC_7_8;
                break;
        case 0x07:
-               fe_params->u.qpsk.fec_inner = FEC_8_9;
+               fe_params->fec_inner = FEC_8_9;
                break;
        }
 
@@ -664,29 +665,31 @@ static int tda10086_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
 
 static int tda10086_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
 {
-       if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+
+       if (p->symbol_rate > 20000000) {
                fesettings->min_delay_ms = 50;
                fesettings->step_size = 2000;
                fesettings->max_drift = 8000;
-       } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) {
+       } else if (p->symbol_rate > 12000000) {
                fesettings->min_delay_ms = 100;
                fesettings->step_size = 1500;
                fesettings->max_drift = 9000;
-       } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) {
+       } else if (p->symbol_rate > 8000000) {
                fesettings->min_delay_ms = 100;
                fesettings->step_size = 1000;
                fesettings->max_drift = 8000;
-       } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) {
+       } else if (p->symbol_rate > 4000000) {
                fesettings->min_delay_ms = 100;
                fesettings->step_size = 500;
                fesettings->max_drift = 7000;
-       } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) {
+       } else if (p->symbol_rate > 2000000) {
                fesettings->min_delay_ms = 200;
-               fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+               fesettings->step_size = p->symbol_rate / 8000;
                fesettings->max_drift = 14 * fesettings->step_size;
        } else {
                fesettings->min_delay_ms = 200;
-               fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+               fesettings->step_size =  p->symbol_rate / 8000;
                fesettings->max_drift = 18 * fesettings->step_size;
        }
 
@@ -701,10 +704,9 @@ static void tda10086_release(struct dvb_frontend* fe)
 }
 
 static struct dvb_frontend_ops tda10086_ops = {
-
+       .delsys = { SYS_DVBS },
        .info = {
                .name     = "Philips TDA10086 DVB-S",
-               .type     = FE_QPSK,
                .frequency_min    = 950000,
                .frequency_max    = 2150000,
                .frequency_stepsize = 125,     /* kHz for QPSK frontends */
index 1b1bf200c55c4b1c65dea314d5abcffcf89e7027..ad7c72e8f517728539f93adde89f63ddf980d137 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/i2c.h>
-#include <linux/version.h>
 #include <asm/div64.h>
 
 #include "dvb_frontend.h"
@@ -1123,55 +1122,51 @@ static int release(struct dvb_frontend *fe)
        return 0;
 }
 
-/*
- * As defined on EN 300 429 Annex A and on ITU-T J.83 annex A, the DVB-C
- * roll-off factor is 0.15.
- * According with the specs, the amount of the needed bandwith is given by:
- *     Bw = Symbol_rate * (1 + 0.15)
- * As such, the maximum symbol rate supported by 6 MHz is
- *     max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
- *NOTE: For ITU-T J.83 Annex C, the roll-off factor is 0.13. So:
- *     max_symbol_rate = 6 MHz / 1.13 = 5309735 Baud
- *     That means that an adjustment is needed for Japan,
- *     but, as currently DRX-K is hardcoded to Annex A, let's stick
- *     with 0.15 roll-off factor.
- */
-#define MAX_SYMBOL_RATE_6MHz   5217391
 
-static int set_params(struct dvb_frontend *fe,
-                     struct dvb_frontend_parameters *params)
+static int set_params(struct dvb_frontend *fe)
 {
        struct tda_state *state = fe->tuner_priv;
        int status = 0;
        int Standard;
+       u32 bw = fe->dtv_property_cache.bandwidth_hz;
+       u32 delsys  = fe->dtv_property_cache.delivery_system;
 
-       state->m_Frequency = params->frequency;
+       state->m_Frequency = fe->dtv_property_cache.frequency;
 
-       if (fe->ops.info.type == FE_OFDM)
-               switch (params->u.ofdm.bandwidth) {
-               case BANDWIDTH_6_MHZ:
+       switch (delsys) {
+       case  SYS_DVBT:
+       case  SYS_DVBT2:
+               switch (bw) {
+               case 6000000:
                        Standard = HF_DVBT_6MHZ;
                        break;
-               case BANDWIDTH_7_MHZ:
+               case 7000000:
                        Standard = HF_DVBT_7MHZ;
                        break;
-               default:
-               case BANDWIDTH_8_MHZ:
+               case 8000000:
                        Standard = HF_DVBT_8MHZ;
                        break;
+               default:
+                       return -EINVAL;
                }
-       else if (fe->ops.info.type == FE_QAM) {
-               if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz)
+       case SYS_DVBC_ANNEX_A:
+       case SYS_DVBC_ANNEX_C:
+               if (bw <= 6000000)
                        Standard = HF_DVBC_6MHZ;
+               else if (bw <= 7000000)
+                       Standard = HF_DVBC_7MHZ;
                else
                        Standard = HF_DVBC_8MHZ;
-       } else
+               break;
+       default:
                return -EINVAL;
+       }
        do {
-               status = RFTrackingFiltersCorrection(state, params->frequency);
+               status = RFTrackingFiltersCorrection(state, state->m_Frequency);
                if (status < 0)
                        break;
-               status = ChannelConfiguration(state, params->frequency, Standard);
+               status = ChannelConfiguration(state, state->m_Frequency,
+                                             Standard);
                if (status < 0)
                        break;
 
index 9369f7442f273b810c8568873047153d7a1149ba..15912c96926adde19a7fbb7c50663efb146ccdf3 100644 (file)
@@ -315,18 +315,19 @@ static int tda8083_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        return 0;
 }
 
-static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int tda8083_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct tda8083_state* state = fe->demodulator_priv;
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
        tda8083_set_inversion (state, p->inversion);
-       tda8083_set_fec (state, p->u.qpsk.fec_inner);
-       tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate);
+       tda8083_set_fec(state, p->fec_inner);
+       tda8083_set_symbolrate(state, p->symbol_rate);
 
        tda8083_writereg (state, 0x00, 0x3c);
        tda8083_writereg (state, 0x00, 0x04);
@@ -334,16 +335,17 @@ static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        return 0;
 }
 
-static int tda8083_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int tda8083_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct tda8083_state* state = fe->demodulator_priv;
 
        /*  FIXME: get symbolrate & frequency offset...*/
        /*p->frequency = ???;*/
        p->inversion = (tda8083_readreg (state, 0x0e) & 0x80) ?
                        INVERSION_ON : INVERSION_OFF;
-       p->u.qpsk.fec_inner = tda8083_get_fec (state);
-       /*p->u.qpsk.symbol_rate = tda8083_get_symbolrate (state);*/
+       p->fec_inner = tda8083_get_fec(state);
+       /*p->symbol_rate = tda8083_get_symbolrate (state);*/
 
        return 0;
 }
@@ -438,10 +440,9 @@ error:
 }
 
 static struct dvb_frontend_ops tda8083_ops = {
-
+       .delsys = { SYS_DVBS },
        .info = {
                .name                   = "Philips TDA8083 DVB-S",
-               .type                   = FE_QPSK,
                .frequency_min          = 920000,     /* TDA8060 */
                .frequency_max          = 2200000,    /* TDA8060 */
                .frequency_stepsize     = 125,   /* kHz for QPSK frontends */
index 06c94800b9402955ccbf799f8ee66e93c2a4f956..04bbcc24de0a7834c0b6b4d1132157472cd173a5 100644 (file)
@@ -71,8 +71,9 @@ static int tda826x_sleep(struct dvb_frontend *fe)
        return (ret == 1) ? 0 : ret;
 }
 
-static int tda826x_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int tda826x_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct tda826x_priv *priv = fe->tuner_priv;
        int ret;
        u32 div;
@@ -83,11 +84,11 @@ static int tda826x_set_params(struct dvb_frontend *fe, struct dvb_frontend_param
 
        dprintk("%s:\n", __func__);
 
-       div = (params->frequency + (1000-1)) / 1000;
+       div = (p->frequency + (1000-1)) / 1000;
 
        /* BW = ((1 + RO) * SR/2 + 5) * 1.3      [SR in MSPS, BW in MHz] */
        /* with R0 = 0.35 and some transformations: */
-       ksyms = params->u.qpsk.symbol_rate / 1000;
+       ksyms = p->symbol_rate / 1000;
        bandwidth = (878 * ksyms + 6500000) / 1000000 + 1;
        if (bandwidth < 5)
                bandwidth = 5;
index 51f1706786507ad20521a7e109e77a44068d2527..17750985db0cacfc15af5ccec345a8b4ee91dede 100644 (file)
@@ -40,24 +40,25 @@ static struct tda1004x_config alps_tdhd1_204a_config = {
        .request_firmware = alps_tdhd1_204_request_firmware
 };
 
-static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct i2c_adapter *i2c = fe->tuner_priv;
        u8 data[4];
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
        u32 div;
 
-       div = (params->frequency + 36166666) / 166666;
+       div = (p->frequency + 36166666) / 166666;
 
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
        data[2] = 0x85;
 
-       if (params->frequency >= 174000000 && params->frequency <= 230000000)
+       if (p->frequency >= 174000000 && p->frequency <= 230000000)
                data[3] = 0x02;
-       else if (params->frequency >= 470000000 && params->frequency <= 823000000)
+       else if (p->frequency >= 470000000 && p->frequency <= 823000000)
                data[3] = 0x0C;
-       else if (params->frequency > 823000000 && params->frequency <= 862000000)
+       else if (p->frequency > 823000000 && p->frequency <= 862000000)
                data[3] = 0x8C;
        else
                return -EINVAL;
index bcb95c2ef296092dfb50fcc18196cd5204fe97eb..029384d1fdddd0caa08a333b37fb50968df0caa5 100644 (file)
@@ -67,9 +67,9 @@ static int tua6100_sleep(struct dvb_frontend *fe)
        return (ret == 1) ? 0 : ret;
 }
 
-static int tua6100_set_params(struct dvb_frontend *fe,
-                             struct dvb_frontend_parameters *params)
+static int tua6100_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct tua6100_priv *priv = fe->tuner_priv;
        u32 div;
        u32 prediv;
@@ -85,36 +85,37 @@ static int tua6100_set_params(struct dvb_frontend *fe,
 #define _ri 4000000
 
        // setup register 0
-       if (params->frequency < 2000000) {
+       if (c->frequency < 2000000)
                reg0[1] = 0x03;
-       } else {
+       else
                reg0[1] = 0x07;
-       }
 
        // setup register 1
-       if (params->frequency < 1630000) {
+       if (c->frequency < 1630000)
                reg1[1] = 0x2c;
-       } else {
+       else
                reg1[1] = 0x0c;
-       }
+
        if (_P == 64)
                reg1[1] |= 0x40;
-       if (params->frequency >= 1525000)
+       if (c->frequency >= 1525000)
                reg1[1] |= 0x80;
 
        // register 2
        reg2[1] = (_R >> 8) & 0x03;
        reg2[2] = _R;
-       if (params->frequency < 1455000) {
+       if (c->frequency < 1455000)
                reg2[1] |= 0x1c;
-       } else if (params->frequency < 1630000) {
+       else if (c->frequency < 1630000)
                reg2[1] |= 0x0c;
-       } else {
+       else
                reg2[1] |= 0x1c;
-       }
 
-       // The N divisor ratio (note: params->frequency is in kHz, but we need it in Hz)
-       prediv = (params->frequency * _R) / (_ri / 1000);
+       /*
+        * The N divisor ratio (note: c->frequency is in kHz, but we
+        * need it in Hz)
+        */
+       prediv = (c->frequency * _R) / (_ri / 1000);
        div = prediv / _P;
        reg1[1] |= (div >> 9) & 0x03;
        reg1[2] = div >> 1;
index 550a07a8a9975d253b9e39482d5e4cc0b040adb8..bb42b563c42d7761353747f74d682c6ac0999f6b 100644 (file)
@@ -205,25 +205,26 @@ static int ves1820_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int ves1820_set_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct ves1820_state* state = fe->demodulator_priv;
        static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 };
        static const u8 reg0x01[] = { 140, 140, 106, 100, 92 };
        static const u8 reg0x05[] = { 135, 100, 70, 54, 38 };
        static const u8 reg0x08[] = { 162, 116, 67, 52, 35 };
        static const u8 reg0x09[] = { 145, 150, 106, 126, 107 };
-       int real_qam = p->u.qam.modulation - QAM_16;
+       int real_qam = p->modulation - QAM_16;
 
        if (real_qam < 0 || real_qam > 4)
                return -EINVAL;
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
 
-       ves1820_set_symbolrate(state, p->u.qam.symbol_rate);
+       ves1820_set_symbolrate(state, p->symbol_rate);
        ves1820_writereg(state, 0x34, state->pwm);
 
        ves1820_writereg(state, 0x01, reg0x01[real_qam]);
@@ -309,8 +310,9 @@ static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        return 0;
 }
 
-static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int ves1820_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct ves1820_state* state = fe->demodulator_priv;
        int sync;
        s8 afc = 0;
@@ -320,7 +322,7 @@ static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        if (verbose) {
                /* AFC only valid when carrier has been recovered */
                printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" :
-                       "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10);
+                       "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->symbol_rate * afc) >> 10);
        }
 
        if (!state->config->invert) {
@@ -329,13 +331,13 @@ static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
                p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF;
        }
 
-       p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+       p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
 
-       p->u.qam.fec_inner = FEC_NONE;
+       p->fec_inner = FEC_NONE;
 
        p->frequency = ((p->frequency + 31250) / 62500) * 62500;
        if (sync & 2)
-               p->frequency -= ((s32) p->u.qam.symbol_rate * afc) >> 10;
+               p->frequency -= ((s32) p->symbol_rate * afc) >> 10;
 
        return 0;
 }
@@ -405,10 +407,9 @@ error:
 }
 
 static struct dvb_frontend_ops ves1820_ops = {
-
+       .delsys = { SYS_DVBC_ANNEX_A },
        .info = {
                .name = "VLSI VES1820 DVB-C",
-               .type = FE_QAM,
                .frequency_stepsize = 62500,
                .frequency_min = 47000000,
                .frequency_max = 862000000,
index 8d7854c2fb0c142683a2c823a3447af61c637438..9c17eacaec24f738e63028e61cb9d7d3d793c9ba 100644 (file)
@@ -46,6 +46,7 @@ struct ves1x93_state {
        u8 *init_1x93_wtab;
        u8 tab_size;
        u8 demod_type;
+       u32 frequency;
 };
 
 static int debug;
@@ -384,31 +385,34 @@ static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
        return 0;
 }
 
-static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int ves1x93_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct ves1x93_state* state = fe->demodulator_priv;
 
        if (fe->ops.tuner_ops.set_params) {
-               fe->ops.tuner_ops.set_params(fe, p);
+               fe->ops.tuner_ops.set_params(fe);
                if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
        }
        ves1x93_set_inversion (state, p->inversion);
-       ves1x93_set_fec (state, p->u.qpsk.fec_inner);
-       ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate);
+       ves1x93_set_fec(state, p->fec_inner);
+       ves1x93_set_symbolrate(state, p->symbol_rate);
        state->inversion = p->inversion;
+       state->frequency = p->frequency;
 
        return 0;
 }
 
-static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int ves1x93_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct ves1x93_state* state = fe->demodulator_priv;
        int afc;
 
        afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2;
-       afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16;
+       afc = (afc * (int)(p->symbol_rate/1000/8))/16;
 
-       p->frequency -= afc;
+       p->frequency = state->frequency - afc;
 
        /*
         * inversion indicator is only valid
@@ -417,7 +421,7 @@ static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        if (state->inversion == INVERSION_AUTO)
                p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ?
                                INVERSION_OFF : INVERSION_ON;
-       p->u.qpsk.fec_inner = ves1x93_get_fec (state);
+       p->fec_inner = ves1x93_get_fec(state);
        /*  XXX FIXME: timing offset !! */
 
        return 0;
@@ -506,10 +510,9 @@ error:
 }
 
 static struct dvb_frontend_ops ves1x93_ops = {
-
+       .delsys = { SYS_DVBS },
        .info = {
                .name                   = "VLSI VES1x93 DVB-S",
-               .type                   = FE_QPSK,
                .frequency_min          = 950000,
                .frequency_max          = 2150000,
                .frequency_stepsize     = 125,           /* kHz for QPSK frontends */
index 81aa984c551f3516b7179aaab4624d4039252df9..0903d461b8fa769ca5fe2db4a918edfc2388d4bf 100644 (file)
@@ -305,12 +305,12 @@ static int zl10036_set_gain_params(struct zl10036_state *state,
        return zl10036_write(state, buf, sizeof(buf));
 }
 
-static int zl10036_set_params(struct dvb_frontend *fe,
-               struct dvb_frontend_parameters *params)
+static int zl10036_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct zl10036_state *state = fe->tuner_priv;
        int ret = 0;
-       u32 frequency = params->frequency;
+       u32 frequency = p->frequency;
        u32 fbw;
        int i;
        u8 c;
@@ -326,7 +326,7 @@ static int zl10036_set_params(struct dvb_frontend *fe,
         * fBW = (alpha*symbolrate)/(2*0.8)
         * 1.35 / (2*0.8) = 27 / 32
         */
-       fbw = (27 * params->u.qpsk.symbol_rate) / 32;
+       fbw = (27 * p->symbol_rate) / 32;
 
        /* scale to kHz */
        fbw /= 1000;
@@ -353,7 +353,7 @@ static int zl10036_set_params(struct dvb_frontend *fe,
        if (ret < 0)
                goto error;
 
-       ret = zl10036_set_frequency(state, params->frequency);
+       ret = zl10036_set_frequency(state, p->frequency);
        if (ret < 0)
                goto error;
 
index c085e58a94bfe7d64b876a3421d244eb392b473d..eff9c5fde50ad65662948cb9109341a0c25a7e0f 100644 (file)
@@ -176,9 +176,9 @@ static int zl10039_sleep(struct dvb_frontend *fe)
        return 0;
 }
 
-static int zl10039_set_params(struct dvb_frontend *fe,
-                       struct dvb_frontend_parameters *params)
+static int zl10039_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct zl10039_state *state = fe->tuner_priv;
        u8 buf[6];
        u8 bf;
@@ -188,12 +188,12 @@ static int zl10039_set_params(struct dvb_frontend *fe,
 
        dprintk("%s\n", __func__);
        dprintk("Set frequency = %d, symbol rate = %d\n",
-                       params->frequency, params->u.qpsk.symbol_rate);
+                       c->frequency, c->symbol_rate);
 
        /* Assumed 10.111 MHz crystal oscillator */
        /* Cancelled num/den 80 to prevent overflow */
-       div = (params->frequency * 1000) / 126387;
-       fbw = (params->u.qpsk.symbol_rate * 27) / 32000;
+       div = (c->frequency * 1000) / 126387;
+       fbw = (c->symbol_rate * 27) / 32000;
        /* Cancelled num/den 10 to prevent overflow */
        bf = ((fbw * 5088) / 1011100) - 1;
 
index adbbf6d3d044cc4d491032638b7498a2ee422f3e..ac7237891374f68456d3c687c4924b11f04b654b 100644 (file)
@@ -37,9 +37,9 @@ struct zl10353_state {
 
        struct zl10353_config config;
 
-       enum fe_bandwidth bandwidth;
-       u32 ucblocks;
-       u32 frequency;
+       u32 bandwidth;
+       u32 ucblocks;
+       u32 frequency;
 };
 
 static int debug;
@@ -122,30 +122,17 @@ static void zl10353_dump_regs(struct dvb_frontend *fe)
 }
 
 static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
-                                     enum fe_bandwidth bandwidth,
+                                     u32 bandwidth,
                                      u16 *nominal_rate)
 {
        struct zl10353_state *state = fe->demodulator_priv;
        u32 adc_clock = 450560; /* 45.056 MHz */
        u64 value;
-       u8 bw;
+       u8 bw = bandwidth / 1000000;
 
        if (state->config.adc_clock)
                adc_clock = state->config.adc_clock;
 
-       switch (bandwidth) {
-       case BANDWIDTH_6_MHZ:
-               bw = 6;
-               break;
-       case BANDWIDTH_7_MHZ:
-               bw = 7;
-               break;
-       case BANDWIDTH_8_MHZ:
-       default:
-               bw = 8;
-               break;
-       }
-
        value = (u64)10 * (1 << 23) / 7 * 125;
        value = (bw * value) + adc_clock / 2;
        do_div(value, adc_clock);
@@ -192,16 +179,15 @@ static int zl10353_sleep(struct dvb_frontend *fe)
        return 0;
 }
 
-static int zl10353_set_parameters(struct dvb_frontend *fe,
-                                 struct dvb_frontend_parameters *param)
+static int zl10353_set_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct zl10353_state *state = fe->demodulator_priv;
        u16 nominal_rate, input_freq;
        u8 pllbuf[6] = { 0x67 }, acq_ctl = 0;
        u16 tps = 0;
-       struct dvb_ofdm_parameters *op = &param->u.ofdm;
 
-       state->frequency = param->frequency;
+       state->frequency = c->frequency;
 
        zl10353_single_write(fe, RESET, 0x80);
        udelay(200);
@@ -211,42 +197,44 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
 
        zl10353_single_write(fe, AGC_TARGET, 0x28);
 
-       if (op->transmission_mode != TRANSMISSION_MODE_AUTO)
+       if (c->transmission_mode != TRANSMISSION_MODE_AUTO)
                acq_ctl |= (1 << 0);
-       if (op->guard_interval != GUARD_INTERVAL_AUTO)
+       if (c->guard_interval != GUARD_INTERVAL_AUTO)
                acq_ctl |= (1 << 1);
        zl10353_single_write(fe, ACQ_CTL, acq_ctl);
 
-       switch (op->bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       switch (c->bandwidth_hz) {
+       case 6000000:
                /* These are extrapolated from the 7 and 8MHz values */
                zl10353_single_write(fe, MCLK_RATIO, 0x97);
                zl10353_single_write(fe, 0x64, 0x34);
                zl10353_single_write(fe, 0xcc, 0xdd);
                break;
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                zl10353_single_write(fe, MCLK_RATIO, 0x86);
                zl10353_single_write(fe, 0x64, 0x35);
                zl10353_single_write(fe, 0xcc, 0x73);
                break;
-       case BANDWIDTH_8_MHZ:
        default:
+               c->bandwidth_hz = 8000000;
+               /* fall though */
+       case 8000000:
                zl10353_single_write(fe, MCLK_RATIO, 0x75);
                zl10353_single_write(fe, 0x64, 0x36);
                zl10353_single_write(fe, 0xcc, 0x73);
        }
 
-       zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate);
+       zl10353_calc_nominal_rate(fe, c->bandwidth_hz, &nominal_rate);
        zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
        zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
-       state->bandwidth = op->bandwidth;
+       state->bandwidth = c->bandwidth_hz;
 
        zl10353_calc_input_freq(fe, &input_freq);
        zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq));
        zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq));
 
        /* Hint at TPS settings */
-       switch (op->code_rate_HP) {
+       switch (c->code_rate_HP) {
        case FEC_2_3:
                tps |= (1 << 7);
                break;
@@ -266,7 +254,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
                return -EINVAL;
        }
 
-       switch (op->code_rate_LP) {
+       switch (c->code_rate_LP) {
        case FEC_2_3:
                tps |= (1 << 4);
                break;
@@ -283,14 +271,14 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
        case FEC_AUTO:
                break;
        case FEC_NONE:
-               if (op->hierarchy_information == HIERARCHY_AUTO ||
-                   op->hierarchy_information == HIERARCHY_NONE)
+               if (c->hierarchy == HIERARCHY_AUTO ||
+                   c->hierarchy == HIERARCHY_NONE)
                        break;
        default:
                return -EINVAL;
        }
 
-       switch (op->constellation) {
+       switch (c->modulation) {
        case QPSK:
                break;
        case QAM_AUTO:
@@ -304,7 +292,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
                return -EINVAL;
        }
 
-       switch (op->transmission_mode) {
+       switch (c->transmission_mode) {
        case TRANSMISSION_MODE_2K:
        case TRANSMISSION_MODE_AUTO:
                break;
@@ -315,7 +303,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
                return -EINVAL;
        }
 
-       switch (op->guard_interval) {
+       switch (c->guard_interval) {
        case GUARD_INTERVAL_1_32:
        case GUARD_INTERVAL_AUTO:
                break;
@@ -332,7 +320,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
                return -EINVAL;
        }
 
-       switch (op->hierarchy_information) {
+       switch (c->hierarchy) {
        case HIERARCHY_AUTO:
        case HIERARCHY_NONE:
                break;
@@ -362,12 +350,12 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
         */
        if (state->config.no_tuner) {
                if (fe->ops.tuner_ops.set_params) {
-                       fe->ops.tuner_ops.set_params(fe, param);
+                       fe->ops.tuner_ops.set_params(fe);
                        if (fe->ops.i2c_gate_ctrl)
                                fe->ops.i2c_gate_ctrl(fe, 0);
                }
        } else if (fe->ops.tuner_ops.calc_regs) {
-               fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5);
+               fe->ops.tuner_ops.calc_regs(fe, pllbuf + 1, 5);
                pllbuf[1] <<= 1;
                zl10353_write(fe, pllbuf, sizeof(pllbuf));
        }
@@ -383,11 +371,10 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
        return 0;
 }
 
-static int zl10353_get_parameters(struct dvb_frontend *fe,
-                                 struct dvb_frontend_parameters *param)
+static int zl10353_get_parameters(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct zl10353_state *state = fe->demodulator_priv;
-       struct dvb_ofdm_parameters *op = &param->u.ofdm;
        int s6, s9;
        u16 tps;
        static const u8 tps_fec_to_api[8] = {
@@ -411,66 +398,66 @@ static int zl10353_get_parameters(struct dvb_frontend *fe,
        tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 |
              zl10353_read_register(state, TPS_RECEIVED_0);
 
-       op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
-       op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
+       c->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
+       c->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
 
        switch ((tps >> 13) & 3) {
        case 0:
-               op->constellation = QPSK;
+               c->modulation = QPSK;
                break;
        case 1:
-               op->constellation = QAM_16;
+               c->modulation = QAM_16;
                break;
        case 2:
-               op->constellation = QAM_64;
+               c->modulation = QAM_64;
                break;
        default:
-               op->constellation = QAM_AUTO;
+               c->modulation = QAM_AUTO;
                break;
        }
 
-       op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K :
+       c->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K :
                                               TRANSMISSION_MODE_2K;
 
        switch ((tps >> 2) & 3) {
        case 0:
-               op->guard_interval = GUARD_INTERVAL_1_32;
+               c->guard_interval = GUARD_INTERVAL_1_32;
                break;
        case 1:
-               op->guard_interval = GUARD_INTERVAL_1_16;
+               c->guard_interval = GUARD_INTERVAL_1_16;
                break;
        case 2:
-               op->guard_interval = GUARD_INTERVAL_1_8;
+               c->guard_interval = GUARD_INTERVAL_1_8;
                break;
        case 3:
-               op->guard_interval = GUARD_INTERVAL_1_4;
+               c->guard_interval = GUARD_INTERVAL_1_4;
                break;
        default:
-               op->guard_interval = GUARD_INTERVAL_AUTO;
+               c->guard_interval = GUARD_INTERVAL_AUTO;
                break;
        }
 
        switch ((tps >> 10) & 7) {
        case 0:
-               op->hierarchy_information = HIERARCHY_NONE;
+               c->hierarchy = HIERARCHY_NONE;
                break;
        case 1:
-               op->hierarchy_information = HIERARCHY_1;
+               c->hierarchy = HIERARCHY_1;
                break;
        case 2:
-               op->hierarchy_information = HIERARCHY_2;
+               c->hierarchy = HIERARCHY_2;
                break;
        case 3:
-               op->hierarchy_information = HIERARCHY_4;
+               c->hierarchy = HIERARCHY_4;
                break;
        default:
-               op->hierarchy_information = HIERARCHY_AUTO;
+               c->hierarchy = HIERARCHY_AUTO;
                break;
        }
 
-       param->frequency = state->frequency;
-       op->bandwidth = state->bandwidth;
-       param->inversion = INVERSION_AUTO;
+       c->frequency = state->frequency;
+       c->bandwidth_hz = state->bandwidth;
+       c->inversion = INVERSION_AUTO;
 
        return 0;
 }
@@ -651,10 +638,9 @@ error:
 }
 
 static struct dvb_frontend_ops zl10353_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "Zarlink ZL10353 DVB-T",
-               .type                   = FE_OFDM,
                .frequency_min          = 174000000,
                .frequency_max          = 862000000,
                .frequency_stepsize     = 166667,
index 2ae0afa7756be4b27442874a3526ef2d12ddac69..ad013e93ed11d7bd05638ebf7eb5a398c4631244 100644 (file)
@@ -83,9 +83,9 @@ u8 lgtdqcs001f_inittab[] = {
 #define MANTIS_MODEL_NAME      "VP-1033"
 #define MANTIS_DEV_TYPE                "DVB-S/DSS"
 
-int lgtdqcs001f_tuner_set(struct dvb_frontend *fe,
-                         struct dvb_frontend_parameters *params)
+int lgtdqcs001f_tuner_set(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct mantis_pci *mantis       = fe->dvb->priv;
        struct i2c_adapter *adapter     = &mantis->adapter;
 
@@ -95,14 +95,14 @@ int lgtdqcs001f_tuner_set(struct dvb_frontend *fe,
 
        struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)};
 
-       div = params->frequency / 250;
+       div = p->frequency / 250;
 
        buf[0] = (div >> 8) & 0x7f;
        buf[1] =  div & 0xff;
        buf[2] =  0x83;
        buf[3] =  0xc0;
 
-       if (params->frequency < 1531000)
+       if (p->frequency < 1531000)
                buf[3] |= 0x04;
        else
                buf[3] &= ~0x04;
index 06da0ddf05a77b46bcb582a274019499a6cb5f67..1ca6837fbe468a8da8f82fe7818a4240880e5004 100644 (file)
@@ -65,8 +65,9 @@ static u8 read_pwm(struct mantis_pci *mantis)
        return pwm;
 }
 
-static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct mantis_pci *mantis = fe->dvb->priv;
        struct i2c_adapter *adapter = &mantis->adapter;
 
@@ -77,13 +78,13 @@ static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_fronten
 #define CU1216_IF 36125000
 #define TUNER_MUL 62500
 
-       u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+       u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
 
        buf[0] = (div >> 8) & 0x7f;
        buf[1] = div & 0xff;
        buf[2] = 0xce;
-       buf[3] = (params->frequency < 150000000 ? 0x01 :
-                 params->frequency < 445000000 ? 0x02 : 0x04);
+       buf[3] = (p->frequency < 150000000 ? 0x01 :
+                 p->frequency < 445000000 ? 0x02 : 0x04);
        buf[4] = 0xde;
        buf[5] = 0x20;
 
index f72b137b7652b94eded9ddb3351b410c1993de0b..d480741afd786dc3e13420077d43f4567f38e666 100644 (file)
@@ -47,8 +47,9 @@ struct tda10023_config vp2040_tda10023_cu1216_config = {
        .invert         = 1,
 };
 
-static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct mantis_pci *mantis       = fe->dvb->priv;
        struct i2c_adapter *adapter     = &mantis->adapter;
 
@@ -59,13 +60,13 @@ static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_fronten
 #define CU1216_IF 36125000
 #define TUNER_MUL 62500
 
-       u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+       u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
 
        buf[0] = (div >> 8) & 0x7f;
        buf[1] = div & 0xff;
        buf[2] = 0xce;
-       buf[3] = (params->frequency < 150000000 ? 0x01 :
-                 params->frequency < 445000000 ? 0x02 : 0x04);
+       buf[3] = (p->frequency < 150000000 ? 0x01 :
+                 p->frequency < 445000000 ? 0x02 : 0x04);
        buf[4] = 0xde;
        buf[5] = 0x20;
 
index 056419228363f8344eefbab82ef8b05eb24feace..8418c02bcefeb8ec7015d42eb4517f9a8a4cbff6 100644 (file)
@@ -218,7 +218,7 @@ static int demod_attach_drxk(struct ngene_channel *chan,
        memset(&config, 0, sizeof(config));
        config.adr = 0x29 + (chan->number ^ 2);
 
-       chan->fe = dvb_attach(drxk_attach, &config, i2c, &chan->fe2);
+       chan->fe = dvb_attach(drxk_attach, &config, i2c);
        if (!chan->fe) {
                printk(KERN_ERR "No DRXK found!\n");
                return -ENODEV;
index 80fb5100446156e99840f52cbe37a62940063a39..e1f20c236989584161afa2623a52f39b75c68062 100644 (file)
@@ -445,9 +445,9 @@ static inline u32 divide(u32 numerator, u32 denominator)
 }
 
 /* LG Innotek TDTE-E001P (Infineon TUA6034) */
-static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe,
-                                        struct dvb_frontend_parameters *p)
+static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct pluto *pluto = frontend_to_pluto(fe);
        struct i2c_msg msg;
        int ret;
@@ -478,7 +478,7 @@ static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe,
        else
                buf[3] = 0x04;
 
-       if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+       if (p->bandwidth_hz == 8000000)
                buf[3] |= 0x08;
 
        if (sizeof(buf) == 6) {
index 451641c0c1d2d41ec6bf0ad54183c8511157ddb9..d980dfb21e5e1a2e78887ff51a9e2123c313a3dd 100644 (file)
@@ -385,7 +385,7 @@ va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock)
 
 static int
 va1j5jf8007s_tune(struct dvb_frontend *fe,
-                 struct dvb_frontend_parameters *params,
+                 bool re_tune,
                  unsigned int mode_flags,  unsigned int *delay,
                  fe_status_t *status)
 {
@@ -395,7 +395,7 @@ va1j5jf8007s_tune(struct dvb_frontend *fe,
 
        state = fe->demodulator_priv;
 
-       if (params != NULL)
+       if (re_tune)
                state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1;
 
        switch (state->tune_state) {
@@ -579,9 +579,9 @@ static void va1j5jf8007s_release(struct dvb_frontend *fe)
 }
 
 static struct dvb_frontend_ops va1j5jf8007s_ops = {
+       .delsys = { SYS_ISDBS },
        .info = {
                .name = "VA1J5JF8007/VA1J5JF8011 ISDB-S",
-               .type = FE_QPSK,
                .frequency_min = 950000,
                .frequency_max = 2150000,
                .frequency_stepsize = 1000,
index 0f085c3e571b71904fbdc37401bd4d3c63bb724e..2db15159d514daf498791e668a4eab8cd1a91c7d 100644 (file)
@@ -264,7 +264,7 @@ static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state,
 
 static int
 va1j5jf8007t_tune(struct dvb_frontend *fe,
-                 struct dvb_frontend_parameters *params,
+                 bool re_tune,
                  unsigned int mode_flags,  unsigned int *delay,
                  fe_status_t *status)
 {
@@ -274,7 +274,7 @@ va1j5jf8007t_tune(struct dvb_frontend *fe,
 
        state = fe->demodulator_priv;
 
-       if (params != NULL)
+       if (re_tune)
                state->tune_state = VA1J5JF8007T_SET_FREQUENCY;
 
        switch (state->tune_state) {
@@ -428,9 +428,9 @@ static void va1j5jf8007t_release(struct dvb_frontend *fe)
 }
 
 static struct dvb_frontend_ops va1j5jf8007t_ops = {
+       .delsys = { SYS_ISDBT },
        .info = {
                .name = "VA1J5JF8007/VA1J5JF8011 ISDB-T",
-               .type = FE_OFDM,
                .frequency_min = 90000000,
                .frequency_max = 770000000,
                .frequency_stepsize = 142857,
index 37c594f827825af53364797fea1c8b219588af30..654685c9303e58e8eff7edd15c50aae0c6daeaec 100644 (file)
@@ -50,7 +50,7 @@ struct smsdvb_client_t {
        struct completion       tune_done;
 
        /* todo: save freq/band instead whole struct */
-       struct dvb_frontend_parameters fe_params;
+       struct dtv_frontend_properties fe_params;
 
        struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
        int event_fe_state;
@@ -591,8 +591,7 @@ static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
        return 0;
 }
 
-static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe,
-                                   struct dvb_frontend_parameters *p)
+static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
 {
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct smsdvb_client_t *client =
@@ -658,8 +657,7 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe,
                                           &client->tune_done);
 }
 
-static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe,
-                                    struct dvb_frontend_parameters *p)
+static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
 {
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct smsdvb_client_t *client =
@@ -723,8 +721,7 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe,
                                           &client->tune_done);
 }
 
-static int smsdvb_set_frontend(struct dvb_frontend *fe,
-                              struct dvb_frontend_parameters *fep)
+static int smsdvb_set_frontend(struct dvb_frontend *fe)
 {
        struct smsdvb_client_t *client =
                container_of(fe, struct smsdvb_client_t, frontend);
@@ -733,18 +730,18 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
        switch (smscore_get_device_mode(coredev)) {
        case DEVICE_MODE_DVBT:
        case DEVICE_MODE_DVBT_BDA:
-               return smsdvb_dvbt_set_frontend(fe, fep);
+               return smsdvb_dvbt_set_frontend(fe);
        case DEVICE_MODE_ISDBT:
        case DEVICE_MODE_ISDBT_BDA:
-               return smsdvb_isdbt_set_frontend(fe, fep);
+               return smsdvb_isdbt_set_frontend(fe);
        default:
                return -EINVAL;
        }
 }
 
-static int smsdvb_get_frontend(struct dvb_frontend *fe,
-                              struct dvb_frontend_parameters *fep)
+static int smsdvb_get_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct smsdvb_client_t *client =
                container_of(fe, struct smsdvb_client_t, frontend);
 
@@ -752,7 +749,7 @@ static int smsdvb_get_frontend(struct dvb_frontend *fe,
 
        /* todo: */
        memcpy(fep, &client->fe_params,
-              sizeof(struct dvb_frontend_parameters));
+              sizeof(struct dtv_frontend_properties));
 
        return 0;
 }
@@ -789,7 +786,6 @@ static void smsdvb_release(struct dvb_frontend *fe)
 static struct dvb_frontend_ops smsdvb_fe_ops = {
        .info = {
                .name                   = "Siano Mobile Digital MDTV Receiver",
-               .type                   = FE_OFDM,
                .frequency_min          = 44250000,
                .frequency_max          = 867250000,
                .frequency_stepsize     = 250000,
@@ -873,6 +869,17 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
        memcpy(&client->frontend.ops, &smsdvb_fe_ops,
               sizeof(struct dvb_frontend_ops));
 
+       switch (smscore_get_device_mode(coredev)) {
+       case DEVICE_MODE_DVBT:
+       case DEVICE_MODE_DVBT_BDA:
+               smsdvb_fe_ops.delsys[0] = SYS_DVBT;
+               break;
+       case DEVICE_MODE_ISDBT:
+       case DEVICE_MODE_ISDBT_BDA:
+               smsdvb_fe_ops.delsys[0] = SYS_ISDBT;
+               break;
+       }
+
        rc = dvb_register_frontend(&client->adapter, &client->frontend);
        if (rc < 0) {
                sms_err("frontend registration failed %d", rc);
index 3d20719fce1a114d7c630560235ce53b1e022b4b..6ecbcf614878fa186be24be1a39f8a07365b3cc9 100644 (file)
@@ -991,7 +991,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
 
        if (feed->type == DMX_TYPE_TS) {
                if ((feed->ts_type & TS_DECODER) &&
-                   (feed->pes_type < DMX_TS_PES_OTHER)) {
+                   (feed->pes_type <= DMX_TS_PES_PCR)) {
                        switch (demux->dmx.frontend->source) {
                        case DMX_MEMORY_FE:
                                if (feed->ts_type & TS_DECODER)
@@ -1568,20 +1568,27 @@ static int get_firmware(struct av7110* av7110)
        return ret;
 }
 
-static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct av7110* av7110 = fe->dvb->priv;
        u8 pwr = 0;
        u8 buf[4];
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-       u32 div = (params->frequency + 479500) / 125;
+       u32 div = (p->frequency + 479500) / 125;
 
-       if (params->frequency > 2000000) pwr = 3;
-       else if (params->frequency > 1800000) pwr = 2;
-       else if (params->frequency > 1600000) pwr = 1;
-       else if (params->frequency > 1200000) pwr = 0;
-       else if (params->frequency >= 1100000) pwr = 1;
-       else pwr = 2;
+       if (p->frequency > 2000000)
+               pwr = 3;
+       else if (p->frequency > 1800000)
+               pwr = 2;
+       else if (p->frequency > 1600000)
+               pwr = 1;
+       else if (p->frequency > 1200000)
+               pwr = 0;
+       else if (p->frequency >= 1100000)
+               pwr = 1;
+       else
+               pwr = 2;
 
        buf[0] = (div >> 8) & 0x7f;
        buf[1] = div & 0xff;
@@ -1604,19 +1611,20 @@ static struct ves1x93_config alps_bsrv2_config = {
        .invert_pwm = 0,
 };
 
-static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct av7110* av7110 = fe->dvb->priv;
        u32 div;
        u8 data[4];
        struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
 
-       div = (params->frequency + 35937500 + 31250) / 62500;
+       div = (p->frequency + 35937500 + 31250) / 62500;
 
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
        data[2] = 0x85 | ((div >> 10) & 0x60);
-       data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+       data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81);
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
@@ -1635,14 +1643,15 @@ static struct ves1820_config alps_tdbe2_config = {
 
 
 
-static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct av7110* av7110 = fe->dvb->priv;
        u32 div;
        u8 data[4];
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
 
-       div = params->frequency / 125;
+       div = p->frequency / 125;
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
        data[2] = 0x8e;
@@ -1661,11 +1670,12 @@ static struct tda8083_config grundig_29504_451_config = {
 
 
 
-static int philips_cd1516_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int philips_cd1516_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct av7110* av7110 = fe->dvb->priv;
        u32 div;
-       u32 f = params->frequency;
+       u32 f = p->frequency;
        u8 data[4];
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
 
@@ -1692,16 +1702,17 @@ static struct ves1820_config philips_cd1516_config = {
 
 
 
-static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int alps_tdlb7_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct av7110* av7110 = fe->dvb->priv;
        u32 div, pwr;
        u8 data[4];
        struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
 
-       div = (params->frequency + 36200000) / 166666;
+       div = (p->frequency + 36200000) / 166666;
 
-       if (params->frequency <= 782000000)
+       if (p->frequency <= 782000000)
                pwr = 1;
        else
                pwr = 2;
@@ -1829,8 +1840,9 @@ static u8 nexusca_stv0297_inittab[] = {
        0xff, 0xff,
 };
 
-static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int nexusca_stv0297_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct av7110* av7110 = fe->dvb->priv;
        u32 div;
        u8 data[4];
@@ -1838,19 +1850,19 @@ static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_
        struct i2c_msg readmsg = { .addr = 0x63, .flags = I2C_M_RD, .buf = data, .len = 1 };
        int i;
 
-       div = (params->frequency + 36150000 + 31250) / 62500;
+       div = (p->frequency + 36150000 + 31250) / 62500;
 
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
        data[2] = 0xce;
 
-       if (params->frequency < 45000000)
+       if (p->frequency < 45000000)
                return -EINVAL;
-       else if (params->frequency < 137000000)
+       else if (p->frequency < 137000000)
                data[3] = 0x01;
-       else if (params->frequency < 403000000)
+       else if (p->frequency < 403000000)
                data[3] = 0x02;
-       else if (params->frequency < 860000000)
+       else if (p->frequency < 860000000)
                data[3] = 0x04;
        else
                return -EINVAL;
@@ -1884,27 +1896,36 @@ static struct stv0297_config nexusca_stv0297_config = {
 
 
 
-static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct av7110* av7110 = fe->dvb->priv;
        u32 div;
        u8 cfg, cpump, band_select;
        u8 data[4];
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
 
-       div = (36125000 + params->frequency) / 166666;
+       div = (36125000 + p->frequency) / 166666;
 
        cfg = 0x88;
 
-       if (params->frequency < 175000000) cpump = 2;
-       else if (params->frequency < 390000000) cpump = 1;
-       else if (params->frequency < 470000000) cpump = 2;
-       else if (params->frequency < 750000000) cpump = 1;
-       else cpump = 3;
+       if (p->frequency < 175000000)
+               cpump = 2;
+       else if (p->frequency < 390000000)
+               cpump = 1;
+       else if (p->frequency < 470000000)
+               cpump = 2;
+       else if (p->frequency < 750000000)
+               cpump = 1;
+       else
+               cpump = 3;
 
-       if (params->frequency < 175000000) band_select = 0x0e;
-       else if (params->frequency < 470000000) band_select = 0x05;
-       else band_select = 0x03;
+       if (p->frequency < 175000000)
+               band_select = 0x0e;
+       else if (p->frequency < 470000000)
+               band_select = 0x05;
+       else
+               band_select = 0x03;
 
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
@@ -1964,15 +1985,14 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
        return ret;
 }
 
-static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int av7110_fe_set_frontend(struct dvb_frontend *fe)
 {
        struct av7110* av7110 = fe->dvb->priv;
 
        int ret = av7110_fe_lock_fix(av7110, 0);
-       if (!ret) {
-               av7110->saved_fe_params = *params;
-               ret = av7110->fe_set_frontend(fe, params);
-       }
+       if (!ret)
+               ret = av7110->fe_set_frontend(fe);
+
        return ret;
 }
 
@@ -2081,7 +2101,7 @@ static void dvb_s_recover(struct av7110* av7110)
        msleep(20);
        av7110_fe_set_tone(av7110->fe, av7110->saved_tone);
 
-       av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params);
+       av7110_fe_set_frontend(av7110->fe);
 }
 
 static u8 read_pwm(struct av7110* av7110)
index d85b8512ac307cb2bfa59f3d695036a1a6a35515..88b3b2d6cc0e9dbcbf04d50987e40b0576b9c6ae 100644 (file)
@@ -272,7 +272,6 @@ struct av7110 {
 
        /* crash recovery */
        void                            (*recover)(struct av7110* av7110);
-       struct dvb_frontend_parameters  saved_fe_params;
        fe_sec_voltage_t                saved_voltage;
        fe_sec_tone_mode_t              saved_tone;
        struct dvb_diseqc_master_cmd    saved_master_cmd;
@@ -286,7 +285,7 @@ struct av7110 {
        int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
        int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
        int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
-       int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+       int (*fe_set_frontend)(struct dvb_frontend *fe);
 };
 
 
index 78d32f7e49fc569b84d16f68615f998c2c4dfeb4..8b32e282bf5d50d3bae319b6fa1b411e7ff6ada4 100644 (file)
@@ -502,33 +502,33 @@ static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 sra
        return 0;
 }
 
-static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe,
-                                                struct dvb_frontend_parameters *params)
+static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        u32 div;
        u8 buf[4];
        struct budget *budget = (struct budget *) fe->dvb->priv;
        struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
 
-       if ((params->frequency < 950000) || (params->frequency > 2150000))
+       if ((c->frequency < 950000) || (c->frequency > 2150000))
                return -EINVAL;
 
-       div = (params->frequency + (125 - 1)) / 125;    // round correctly
+       div = (c->frequency + (125 - 1)) / 125; /* round correctly */
        buf[0] = (div >> 8) & 0x7f;
        buf[1] = div & 0xff;
        buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
        buf[3] = 0x20;
 
-       if (params->u.qpsk.symbol_rate < 4000000)
+       if (c->symbol_rate < 4000000)
                buf[3] |= 1;
 
-       if (params->frequency < 1250000)
+       if (c->frequency < 1250000)
                buf[3] |= 0;
-       else if (params->frequency < 1550000)
+       else if (c->frequency < 1550000)
                buf[3] |= 0x40;
-       else if (params->frequency < 2050000)
+       else if (c->frequency < 2050000)
                buf[3] |= 0x80;
-       else if (params->frequency < 2150000)
+       else if (c->frequency < 2150000)
                buf[3] |= 0xC0;
 
        if (fe->ops.i2c_gate_ctrl)
@@ -617,8 +617,9 @@ static struct stv0299_config cinergy_1200s_1894_0010_config = {
        .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
 };
 
-static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct budget *budget = (struct budget *) fe->dvb->priv;
        u8 buf[6];
        struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
@@ -627,13 +628,13 @@ static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
 #define CU1216_IF 36125000
 #define TUNER_MUL 62500
 
-       u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+       u32 div = (c->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
 
        buf[0] = (div >> 8) & 0x7f;
        buf[1] = div & 0xff;
        buf[2] = 0xce;
-       buf[3] = (params->frequency < 150000000 ? 0x01 :
-                 params->frequency < 445000000 ? 0x02 : 0x04);
+       buf[3] = (c->frequency < 150000000 ? 0x01 :
+                 c->frequency < 445000000 ? 0x02 : 0x04);
        buf[4] = 0xde;
        buf[5] = 0x20;
 
@@ -697,8 +698,9 @@ static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
        return 0;
 }
 
-static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct budget *budget = (struct budget *) fe->dvb->priv;
        u8 tuner_buf[4];
        struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =
@@ -707,7 +709,7 @@ static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
        u8 band, cp, filter;
 
        // determine charge pump
-       tuner_frequency = params->frequency + 36166000;
+       tuner_frequency = c->frequency + 36166000;
        if (tuner_frequency < 87000000)
                return -EINVAL;
        else if (tuner_frequency < 130000000)
@@ -732,28 +734,28 @@ static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
                return -EINVAL;
 
        // determine band
-       if (params->frequency < 49000000)
+       if (c->frequency < 49000000)
                return -EINVAL;
-       else if (params->frequency < 161000000)
+       else if (c->frequency < 161000000)
                band = 1;
-       else if (params->frequency < 444000000)
+       else if (c->frequency < 444000000)
                band = 2;
-       else if (params->frequency < 861000000)
+       else if (c->frequency < 861000000)
                band = 4;
        else
                return -EINVAL;
 
        // setup PLL filter
-       switch (params->u.ofdm.bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       switch (c->bandwidth_hz) {
+       case 6000000:
                filter = 0;
                break;
 
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                filter = 0;
                break;
 
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
                filter = 1;
                break;
 
@@ -763,7 +765,7 @@ static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
 
        // calculate divisor
        // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
-       tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000;
+       tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000;
 
        // setup tuner buffer
        tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
index ca02e97221721e1f1927ed5b76a9ff29ed523665..98e524178765bb3c1e6094e43fb7edda621fe3ac 100644 (file)
@@ -193,7 +193,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
        dev->input_phys = budget_ci->ir.phys;
        dev->input_id.bustype = BUS_PCI;
        dev->input_id.version = 1;
-       dev->scanmask = 0xff;
        if (saa->pci->subsystem_vendor) {
                dev->input_id.vendor = saa->pci->subsystem_vendor;
                dev->input_id.product = saa->pci->subsystem_device;
@@ -234,6 +233,8 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
                dev->map_name = RC_MAP_BUDGET_CI_OLD;
                break;
        }
+       if (!budget_ci->ir.full_rc5)
+               dev->scanmask = 0xff;
 
        error = rc_register_device(dev);
        if (error) {
@@ -659,33 +660,33 @@ static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
        return 0;
 }
 
-static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
-                                          struct dvb_frontend_parameters *params)
+static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
        u32 div;
        u8 buf[4];
        struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
 
-       if ((params->frequency < 950000) || (params->frequency > 2150000))
+       if ((p->frequency < 950000) || (p->frequency > 2150000))
                return -EINVAL;
 
-       div = (params->frequency + (500 - 1)) / 500;    // round correctly
+       div = (p->frequency + (500 - 1)) / 500; /* round correctly */
        buf[0] = (div >> 8) & 0x7f;
        buf[1] = div & 0xff;
        buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
        buf[3] = 0x20;
 
-       if (params->u.qpsk.symbol_rate < 4000000)
+       if (p->symbol_rate < 4000000)
                buf[3] |= 1;
 
-       if (params->frequency < 1250000)
+       if (p->frequency < 1250000)
                buf[3] |= 0;
-       else if (params->frequency < 1550000)
+       else if (p->frequency < 1550000)
                buf[3] |= 0x40;
-       else if (params->frequency < 2050000)
+       else if (p->frequency < 2050000)
                buf[3] |= 0x80;
-       else if (params->frequency < 2150000)
+       else if (p->frequency < 2150000)
                buf[3] |= 0xC0;
 
        if (fe->ops.i2c_gate_ctrl)
@@ -740,8 +741,9 @@ static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
        return 0;
 }
 
-static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
        u8 tuner_buf[4];
        struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
@@ -749,7 +751,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb
        u8 band, cp, filter;
 
        // determine charge pump
-       tuner_frequency = params->frequency + 36130000;
+       tuner_frequency = p->frequency + 36130000;
        if (tuner_frequency < 87000000)
                return -EINVAL;
        else if (tuner_frequency < 130000000)
@@ -774,30 +776,30 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb
                return -EINVAL;
 
        // determine band
-       if (params->frequency < 49000000)
+       if (p->frequency < 49000000)
                return -EINVAL;
-       else if (params->frequency < 159000000)
+       else if (p->frequency < 159000000)
                band = 1;
-       else if (params->frequency < 444000000)
+       else if (p->frequency < 444000000)
                band = 2;
-       else if (params->frequency < 861000000)
+       else if (p->frequency < 861000000)
                band = 4;
        else
                return -EINVAL;
 
        // setup PLL filter and TDA9889
-       switch (params->u.ofdm.bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       switch (p->bandwidth_hz) {
+       case 6000000:
                tda1004x_writereg(fe, 0x0C, 0x14);
                filter = 0;
                break;
 
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                tda1004x_writereg(fe, 0x0C, 0x80);
                filter = 0;
                break;
 
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
                tda1004x_writereg(fe, 0x0C, 0x14);
                filter = 1;
                break;
@@ -808,7 +810,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb
 
        // calculate divisor
        // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
-       tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
+       tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000;
 
        // setup tuner buffer
        tuner_buf[0] = tuner_frequency >> 8;
@@ -855,8 +857,9 @@ static struct tda1004x_config philips_tdm1316l_config_invert = {
        .request_firmware = philips_tdm1316l_request_firmware,
 };
 
-static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
        u8 tuner_buf[5];
        struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
@@ -867,7 +870,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc
        u8 band, cp, filter;
 
        // determine charge pump
-       tuner_frequency = params->frequency + 36125000;
+       tuner_frequency = p->frequency + 36125000;
        if (tuner_frequency < 87000000)
                return -EINVAL;
        else if (tuner_frequency < 130000000) {
@@ -904,7 +907,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc
        filter = 1;
 
        // calculate divisor
-       tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
+       tuner_frequency = (p->frequency + 36125000 + (62500/2)) / 62500;
 
        // setup tuner buffer
        tuner_buf[0] = tuner_frequency >> 8;
index 3395d1a9051699c64f9a67fe6f173d415aff0d22..2cb35c23d2ac890e212a9c8bee34a91a197f8443 100644 (file)
@@ -261,19 +261,25 @@ static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_c
        return 0;
 }
 
-static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
        u8 pwr = 0;
        u8 buf[4];
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-       u32 div = (params->frequency + 479500) / 125;
-
-       if (params->frequency > 2000000) pwr = 3;
-       else if (params->frequency > 1800000) pwr = 2;
-       else if (params->frequency > 1600000) pwr = 1;
-       else if (params->frequency > 1200000) pwr = 0;
-       else if (params->frequency >= 1100000) pwr = 1;
+       u32 div = (p->frequency + 479500) / 125;
+
+       if (p->frequency > 2000000)
+               pwr = 3;
+       else if (p->frequency > 1800000)
+               pwr = 2;
+       else if (p->frequency > 1600000)
+               pwr = 1;
+       else if (p->frequency > 1200000)
+               pwr = 0;
+       else if (p->frequency >= 1100000)
+               pwr = 1;
        else pwr = 2;
 
        buf[0] = (div >> 8) & 0x7f;
@@ -297,14 +303,15 @@ static struct ves1x93_config alps_bsrv2_config = {
        .invert_pwm = 0,
 };
 
-static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
        u32 div;
        u8 data[4];
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
 
-       div = params->frequency / 125;
+       div = p->frequency / 125;
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
        data[2] = 0x8e;
index d238fb9371a70723e3577f0a3488a7dcf4ea45d7..b21bcce667088a2d0f09cf66cab7d9985a72427b 100644 (file)
@@ -200,19 +200,25 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m
        return 0;
 }
 
-static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct budget* budget = (struct budget*) fe->dvb->priv;
        u8 pwr = 0;
        u8 buf[4];
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-       u32 div = (params->frequency + 479500) / 125;
-
-       if (params->frequency > 2000000) pwr = 3;
-       else if (params->frequency > 1800000) pwr = 2;
-       else if (params->frequency > 1600000) pwr = 1;
-       else if (params->frequency > 1200000) pwr = 0;
-       else if (params->frequency >= 1100000) pwr = 1;
+       u32 div = (c->frequency + 479500) / 125;
+
+       if (c->frequency > 2000000)
+               pwr = 3;
+       else if (c->frequency > 1800000)
+               pwr = 2;
+       else if (c->frequency > 1600000)
+               pwr = 1;
+       else if (c->frequency > 1200000)
+               pwr = 0;
+       else if (c->frequency >= 1100000)
+               pwr = 1;
        else pwr = 2;
 
        buf[0] = (div >> 8) & 0x7f;
@@ -236,19 +242,20 @@ static struct ves1x93_config alps_bsrv2_config =
        .invert_pwm = 0,
 };
 
-static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct budget* budget = (struct budget*) fe->dvb->priv;
        u32 div;
        u8 data[4];
        struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
 
-       div = (params->frequency + 35937500 + 31250) / 62500;
+       div = (c->frequency + 35937500 + 31250) / 62500;
 
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
        data[2] = 0x85 | ((div >> 10) & 0x60);
-       data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+       data[3] = (c->frequency < 174000000 ? 0x88 : c->frequency < 470000000 ? 0x84 : 0x81);
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
@@ -263,8 +270,9 @@ static struct ves1820_config alps_tdbe2_config = {
        .selagc = VES1820_SELAGC_SIGNAMPERR,
 };
 
-static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct budget *budget = fe->dvb->priv;
        u8 *tuner_addr = fe->tuner_priv;
        u32 div;
@@ -277,19 +285,27 @@ static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dv
        else
                msg.addr = 0x61;
 
-       div = (36125000 + params->frequency) / 166666;
+       div = (36125000 + c->frequency) / 166666;
 
        cfg = 0x88;
 
-       if (params->frequency < 175000000) cpump = 2;
-       else if (params->frequency < 390000000) cpump = 1;
-       else if (params->frequency < 470000000) cpump = 2;
-       else if (params->frequency < 750000000) cpump = 1;
-       else cpump = 3;
+       if (c->frequency < 175000000)
+               cpump = 2;
+       else if (c->frequency < 390000000)
+               cpump = 1;
+       else if (c->frequency < 470000000)
+               cpump = 2;
+       else if (c->frequency < 750000000)
+               cpump = 1;
+       else
+               cpump = 3;
 
-       if (params->frequency < 175000000) band_select = 0x0e;
-       else if (params->frequency < 470000000) band_select = 0x05;
-       else band_select = 0x03;
+       if (c->frequency < 175000000)
+               band_select = 0x0e;
+       else if (c->frequency < 470000000)
+               band_select = 0x05;
+       else
+               band_select = 0x03;
 
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
@@ -312,14 +328,15 @@ static struct l64781_config grundig_29504_401_config_activy = {
 
 static u8 tuner_address_grundig_29504_401_activy = 0x60;
 
-static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct budget* budget = (struct budget*) fe->dvb->priv;
        u32 div;
        u8 data[4];
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
 
-       div = params->frequency / 125;
+       div = c->frequency / 125;
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
        data[2] = 0x8e;
@@ -335,14 +352,15 @@ static struct tda8083_config grundig_29504_451_config = {
        .demod_address = 0x68,
 };
 
-static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int s5h1420_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct budget* budget = (struct budget*) fe->dvb->priv;
        u32 div;
        u8 data[4];
        struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
 
-       div = params->frequency / 1000;
+       div = c->frequency / 1000;
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
        data[2] = 0xc2;
index e90192fdde1106447daa654f494e5cad91628f2b..5b682cc4c814e99501c45f82ea17171029301183 100644 (file)
@@ -1017,19 +1017,20 @@ static u32 functionality(struct i2c_adapter *adapter)
 
 
 
-static int alps_tdmb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdmb7_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
        u8 data[4];
        struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) };
        u32 div;
 
-       div = (params->frequency + 36166667) / 166667;
+       div = (p->frequency + 36166667) / 166667;
 
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
        data[2] = ((div >> 10) & 0x60) | 0x85;
-       data[3] = params->frequency < 592000000 ? 0x40 : 0x80;
+       data[3] = p->frequency < 592000000 ? 0x40 : 0x80;
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
@@ -1071,8 +1072,9 @@ static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe)
        return 0;
 }
 
-static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
        u8 tuner_buf[4];
        struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
@@ -1080,7 +1082,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb
        u8 band, cp, filter;
 
        // determine charge pump
-       tuner_frequency = params->frequency + 36130000;
+       tuner_frequency = p->frequency + 36130000;
        if (tuner_frequency < 87000000) return -EINVAL;
        else if (tuner_frequency < 130000000) cp = 3;
        else if (tuner_frequency < 160000000) cp = 5;
@@ -1094,25 +1096,29 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb
        else return -EINVAL;
 
        // determine band
-       if (params->frequency < 49000000) return -EINVAL;
-       else if (params->frequency < 159000000) band = 1;
-       else if (params->frequency < 444000000) band = 2;
-       else if (params->frequency < 861000000) band = 4;
+       if (p->frequency < 49000000)
+               return -EINVAL;
+       else if (p->frequency < 159000000)
+               band = 1;
+       else if (p->frequency < 444000000)
+               band = 2;
+       else if (p->frequency < 861000000)
+               band = 4;
        else return -EINVAL;
 
        // setup PLL filter
-       switch (params->u.ofdm.bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       switch (p->bandwidth_hz) {
+       case 6000000:
                tda1004x_writereg(fe, 0x0C, 0);
                filter = 0;
                break;
 
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                tda1004x_writereg(fe, 0x0C, 0);
                filter = 0;
                break;
 
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
                tda1004x_writereg(fe, 0x0C, 0xFF);
                filter = 1;
                break;
@@ -1123,7 +1129,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb
 
        // calculate divisor
        // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
-       tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
+       tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000;
 
        // setup tuner buffer
        tuner_buf[0] = tuner_frequency >> 8;
@@ -1273,23 +1279,24 @@ static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32
        return 0;
 }
 
-static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
        u8 buf[4];
        u32 div;
        struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
 
-       if ((params->frequency < 950000) || (params->frequency > 2150000))
+       if ((p->frequency < 950000) || (p->frequency > 2150000))
                return -EINVAL;
 
-       div = (params->frequency + (125 - 1)) / 125;    // round correctly
+       div = (p->frequency + (125 - 1)) / 125; /* round correctly */
        buf[0] = (div >> 8) & 0x7f;
        buf[1] = div & 0xff;
        buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
        buf[3] = 0xC4;
 
-       if (params->frequency > 1530000)
+       if (p->frequency > 1530000)
                buf[3] = 0xC0;
 
        /* BSBE1 wants XCE bit set */
@@ -1316,14 +1323,15 @@ static struct stv0299_config alps_stv0299_config = {
        .set_symbol_rate = alps_stv0299_set_symbol_rate,
 };
 
-static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
        u8 buf[4];
        u32 div;
        struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
 
-       div = params->frequency / 125;
+       div = p->frequency / 125;
 
        buf[0] = (div >> 8) & 0x7f;
        buf[1] = div & 0xff;
@@ -1343,19 +1351,20 @@ static struct tda8083_config ttusb_novas_grundig_29504_491_config = {
        .demod_address = 0x68,
 };
 
-static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct ttusb* ttusb = fe->dvb->priv;
        u32 div;
        u8 data[4];
        struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
 
-       div = (params->frequency + 35937500 + 31250) / 62500;
+       div = (p->frequency + 35937500 + 31250) / 62500;
 
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
        data[2] = 0x85 | ((div >> 10) & 0x60);
-       data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+       data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81);
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
@@ -1387,8 +1396,9 @@ static u8 read_pwm(struct ttusb* ttusb)
 }
 
 
-static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv;
        u8 tuner_buf[5];
        struct i2c_msg tuner_msg = {.addr = 0x60,
@@ -1399,7 +1409,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc
        u8 band, cp, filter;
 
        // determine charge pump
-       tuner_frequency = params->frequency;
+       tuner_frequency = p->frequency;
        if      (tuner_frequency <  87000000) {return -EINVAL;}
        else if (tuner_frequency < 130000000) {cp = 3; band = 1;}
        else if (tuner_frequency < 160000000) {cp = 5; band = 1;}
@@ -1417,7 +1427,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc
 
        // calculate divisor
        // (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz
-       tuner_frequency = ((params->frequency + 36125000) / 62500);
+       tuner_frequency = ((p->frequency + 36125000) / 62500);
 
        // setup tuner buffer
        tuner_buf[0] = tuner_frequency >> 8;
@@ -1694,10 +1704,8 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
        ttusb->i2c_adap.dev.parent        = &udev->dev;
 
        result = i2c_add_adapter(&ttusb->i2c_adap);
-       if (result) {
-               dvb_unregister_adapter (&ttusb->adapter);
-               return result;
-       }
+       if (result)
+               goto err_unregister_adapter;
 
        memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux));
 
@@ -1714,33 +1722,29 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
        ttusb->dvb_demux.stop_feed = ttusb_stop_feed;
        ttusb->dvb_demux.write_to_decoder = NULL;
 
-       if ((result = dvb_dmx_init(&ttusb->dvb_demux)) < 0) {
+       result = dvb_dmx_init(&ttusb->dvb_demux);
+       if (result < 0) {
                printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result);
-               i2c_del_adapter(&ttusb->i2c_adap);
-               dvb_unregister_adapter (&ttusb->adapter);
-               return -ENODEV;
+               result = -ENODEV;
+               goto err_i2c_del_adapter;
        }
 //FIXME dmxdev (nur WAS?)
        ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum;
        ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx;
        ttusb->dmxdev.capabilities = 0;
 
-       if ((result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter)) < 0) {
+       result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter);
+       if (result < 0) {
                printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n",
                       result);
-               dvb_dmx_release(&ttusb->dvb_demux);
-               i2c_del_adapter(&ttusb->i2c_adap);
-               dvb_unregister_adapter (&ttusb->adapter);
-               return -ENODEV;
+               result = -ENODEV;
+               goto err_release_dmx;
        }
 
        if (dvb_net_init(&ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) {
                printk("ttusb_dvb: dvb_net_init failed!\n");
-               dvb_dmxdev_release(&ttusb->dmxdev);
-               dvb_dmx_release(&ttusb->dvb_demux);
-               i2c_del_adapter(&ttusb->i2c_adap);
-               dvb_unregister_adapter (&ttusb->adapter);
-               return -ENODEV;
+               result = -ENODEV;
+               goto err_release_dmxdev;
        }
 
        usb_set_intfdata(intf, (void *) ttusb);
@@ -1748,6 +1752,16 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
        frontend_init(ttusb);
 
        return 0;
+
+err_release_dmxdev:
+       dvb_dmxdev_release(&ttusb->dmxdev);
+err_release_dmx:
+       dvb_dmx_release(&ttusb->dvb_demux);
+err_i2c_del_adapter:
+       i2c_del_adapter(&ttusb->i2c_adap);
+err_unregister_adapter:
+       dvb_unregister_adapter (&ttusb->adapter);
+       return result;
 }
 
 static void ttusb_disconnect(struct usb_interface *intf)
index 21260aad1e54684a46c82248dc0bee8681327c21..5c45c9d0712ddf949f0ac571b5649111585046ae 100644 (file)
@@ -87,8 +87,9 @@ static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe,
        return 0;
 }
 
-static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
        u8 b[] = { 0x00, 0x00, 0x00, 0x03,
                   0x00, 0x00, 0x00, 0x00,
@@ -113,8 +114,9 @@ static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe,
                return 0;
 }
 
-static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
 
        u8 b[] = { 0x00, 0x00, 0x00, 0x01,
@@ -135,7 +137,7 @@ static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_fron
        freq = htonl(p->frequency +
               (state->hi_band ? LOF_HI : LOF_LO));
        memcpy(&b[4], &freq, sizeof(u32));
-       sym_rate = htonl(p->u.qam.symbol_rate);
+       sym_rate = htonl(p->symbol_rate);
        memcpy(&b[12], &sym_rate, sizeof(u32));
        band = htonl(state->hi_band ? LOF_HI : LOF_LO);
        memcpy(&b[24], &band, sizeof(u32));
@@ -241,10 +243,9 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf
 }
 
 static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
-
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "TechnoTrend/Hauppauge DEC2000-t Frontend",
-               .type                   = FE_OFDM,
                .frequency_min          = 51000000,
                .frequency_max          = 858000000,
                .frequency_stepsize     = 62500,
@@ -265,10 +266,9 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
 };
 
 static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
-
+       .delsys = { SYS_DVBS },
        .info = {
                .name                   = "TechnoTrend/Hauppauge DEC3000-s Frontend",
-               .type                   = FE_QPSK,
                .frequency_min          = 950000,
                .frequency_max          = 2150000,
                .frequency_stepsize     = 125,
index 6edc9ba81203698e9948c066ddfac2370a142b1d..6f9eb94e85b387f78f144fd74c244e0e0859237a 100644 (file)
@@ -108,8 +108,7 @@ static long media_device_enum_entities(struct media_device *mdev,
        u_ent.group_id = ent->group_id;
        u_ent.pads = ent->num_pads;
        u_ent.links = ent->num_links - ent->num_backlinks;
-       u_ent.v4l.major = ent->v4l.major;
-       u_ent.v4l.minor = ent->v4l.minor;
+       memcpy(&u_ent.raw, &ent->info, sizeof(ent->info));
        if (copy_to_user(uent, &u_ent, sizeof(u_ent)))
                return -EFAULT;
        return 0;
index ccd5f0d8a012113a08b788b9927860079289fa0c..e954781c90bfd920e57bea52d1a1fa2c34f8a151 100644 (file)
@@ -11,6 +11,162 @@ menuconfig RADIO_ADAPTERS
 
 if RADIO_ADAPTERS && VIDEO_V4L2
 
+config RADIO_SI470X
+       bool "Silicon Labs Si470x FM Radio Receiver support"
+       depends on VIDEO_V4L2
+
+source "drivers/media/radio/si470x/Kconfig"
+
+config USB_MR800
+       tristate "AverMedia MR 800 USB FM radio support"
+       depends on USB && VIDEO_V4L2
+       ---help---
+         Say Y here if you want to connect this type of radio to your
+         computer's USB port. Note that the audio is not digital, and
+         you must connect the line out connector to a sound card or a
+         set of speakers.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-mr800.
+
+config USB_DSBR
+       tristate "D-Link/GemTek USB FM radio support"
+       depends on USB && VIDEO_V4L2
+       ---help---
+         Say Y here if you want to connect this type of radio to your
+         computer's USB port. Note that the audio is not digital, and
+         you must connect the line out connector to a sound card or a
+         set of speakers.
+
+         To compile this driver as a module, choose M here: the
+         module will be called dsbr100.
+
+config RADIO_MAXIRADIO
+       tristate "Guillemot MAXI Radio FM 2000 radio"
+       depends on VIDEO_V4L2 && PCI
+       ---help---
+         Choose Y here if you have this radio card.  This card may also be
+         found as Gemtek PCI FM.
+
+         In order to control your radio card, you will need to use programs
+         that are compatible with the Video For Linux API.  Information on
+         this API and pointers to "v4l" programs may be found at
+         <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-maxiradio.
+
+
+config I2C_SI4713
+       tristate "I2C driver for Silicon Labs Si4713 device"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         Say Y here if you want support to Si4713 I2C device.
+         This device driver supports only i2c bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called si4713.
+
+config RADIO_SI4713
+       tristate "Silicon Labs Si4713 FM Radio Transmitter support"
+       depends on I2C && VIDEO_V4L2
+       select I2C_SI4713
+       ---help---
+         Say Y here if you want support to Si4713 FM Radio Transmitter.
+         This device can transmit audio through FM. It can transmit
+         RDS and RBDS signals as well. This module is the v4l2 radio
+         interface for the i2c driver of this device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-si4713.
+
+config RADIO_TEA5764
+       tristate "TEA5764 I2C FM radio support"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         Say Y here if you want to use the TEA5764 FM chip found in
+         EZX phones. This FM chip is present in EZX phones from Motorola,
+         connected to internal pxa I2C bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-tea5764.
+
+config RADIO_TEA5764_XTAL
+       bool "TEA5764 crystal reference"
+       depends on RADIO_TEA5764=y
+       default y
+       help
+         Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N
+         here if TEA5764 reference frequency is connected in FREQIN.
+
+config RADIO_SAA7706H
+       tristate "SAA7706H Car Radio DSP"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         Say Y here if you want to use the SAA7706H Car radio Digital
+         Signal Processor, found for instance on the Russellville development
+         board. On the russellville the device is connected to internal
+         timberdale I2C bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called SAA7706H.
+
+config RADIO_TEF6862
+       tristate "TEF6862 Car Radio Enhanced Selectivity Tuner"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         Say Y here if you want to use the TEF6862 Car Radio Enhanced
+         Selectivity Tuner, found for instance on the Russellville development
+         board. On the russellville the device is connected to internal
+         timberdale I2C bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called TEF6862.
+
+config RADIO_TIMBERDALE
+       tristate "Enable the Timberdale radio driver"
+       depends on MFD_TIMBERDALE && VIDEO_V4L2
+       depends on I2C  # for RADIO_SAA7706H
+       select RADIO_TEF6862
+       select RADIO_SAA7706H
+       ---help---
+         This is a kind of umbrella driver for the Radio Tuner and DSP
+         found behind the Timberdale FPGA on the Russellville board.
+         Enabling this driver will automatically select the DSP and tuner.
+
+config RADIO_WL1273
+       tristate "Texas Instruments WL1273 I2C FM Radio"
+       depends on I2C && VIDEO_V4L2
+       select MFD_CORE
+       select MFD_WL1273_CORE
+       select FW_LOADER
+       ---help---
+         Choose Y here if you have this FM radio chip.
+
+         In order to control your radio card, you will need to use programs
+         that are compatible with the Video For Linux 2 API.  Information on
+         this API and pointers to "v4l2" programs may be found at
+         <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-wl1273.
+
+# TI's ST based wl128x FM radio
+source "drivers/media/radio/wl128x/Kconfig"
+
+#
+# ISA drivers configuration
+#
+
+menuconfig V4L_RADIO_ISA_DRIVERS
+       bool "ISA radio devices"
+       depends on ISA
+       default n
+       ---help---
+         Say Y here to enable support for these ISA drivers.
+
+if V4L_RADIO_ISA_DRIVERS
+
 config RADIO_CADET
        tristate "ADS Cadet AM/FM Tuner"
        depends on ISA && VIDEO_V4L2
@@ -151,21 +307,6 @@ config RADIO_GEMTEK_PROBE
          following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and
          0x28c.
 
-config RADIO_MAXIRADIO
-       tristate "Guillemot MAXI Radio FM 2000 radio"
-       depends on VIDEO_V4L2 && PCI
-       ---help---
-         Choose Y here if you have this radio card.  This card may also be
-         found as Gemtek PCI FM.
-
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux API.  Information on
-         this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called radio-maxiradio.
-
 config RADIO_MIROPCM20
        tristate "miroSOUND PCM20 radio"
        depends on ISA && ISA_DMA_API && VIDEO_V4L2 && SND
@@ -316,130 +457,6 @@ config RADIO_ZOLTRIX_PORT
        help
          Enter the I/O port of your Zoltrix radio card.
 
-config I2C_SI4713
-       tristate "I2C driver for Silicon Labs Si4713 device"
-       depends on I2C && VIDEO_V4L2
-       ---help---
-         Say Y here if you want support to Si4713 I2C device.
-         This device driver supports only i2c bus.
-
-         To compile this driver as a module, choose M here: the
-         module will be called si4713.
-
-config RADIO_SI4713
-       tristate "Silicon Labs Si4713 FM Radio Transmitter support"
-       depends on I2C && VIDEO_V4L2
-       select I2C_SI4713
-       ---help---
-         Say Y here if you want support to Si4713 FM Radio Transmitter.
-         This device can transmit audio through FM. It can transmit
-         RDS and RBDS signals as well. This module is the v4l2 radio
-         interface for the i2c driver of this device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called radio-si4713.
-
-config USB_DSBR
-       tristate "D-Link/GemTek USB FM radio support"
-       depends on USB && VIDEO_V4L2
-       ---help---
-         Say Y here if you want to connect this type of radio to your
-         computer's USB port. Note that the audio is not digital, and
-         you must connect the line out connector to a sound card or a
-         set of speakers.
-
-         To compile this driver as a module, choose M here: the
-         module will be called dsbr100.
-
-config RADIO_SI470X
-       bool "Silicon Labs Si470x FM Radio Receiver support"
-       depends on VIDEO_V4L2
-
-source "drivers/media/radio/si470x/Kconfig"
-
-config USB_MR800
-       tristate "AverMedia MR 800 USB FM radio support"
-       depends on USB && VIDEO_V4L2
-       ---help---
-         Say Y here if you want to connect this type of radio to your
-         computer's USB port. Note that the audio is not digital, and
-         you must connect the line out connector to a sound card or a
-         set of speakers.
-
-         To compile this driver as a module, choose M here: the
-         module will be called radio-mr800.
-
-config RADIO_TEA5764
-       tristate "TEA5764 I2C FM radio support"
-       depends on I2C && VIDEO_V4L2
-       ---help---
-         Say Y here if you want to use the TEA5764 FM chip found in
-         EZX phones. This FM chip is present in EZX phones from Motorola,
-         connected to internal pxa I2C bus.
-
-         To compile this driver as a module, choose M here: the
-         module will be called radio-tea5764.
-
-config RADIO_TEA5764_XTAL
-       bool "TEA5764 crystal reference"
-       depends on RADIO_TEA5764=y
-       default y
-       help
-         Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N
-         here if TEA5764 reference frequency is connected in FREQIN.
-
-config RADIO_SAA7706H
-       tristate "SAA7706H Car Radio DSP"
-       depends on I2C && VIDEO_V4L2
-       ---help---
-         Say Y here if you want to use the SAA7706H Car radio Digital
-         Signal Processor, found for instance on the Russellville development
-         board. On the russellville the device is connected to internal
-         timberdale I2C bus.
-
-         To compile this driver as a module, choose M here: the
-         module will be called SAA7706H.
-
-config RADIO_TEF6862
-       tristate "TEF6862 Car Radio Enhanced Selectivity Tuner"
-       depends on I2C && VIDEO_V4L2
-       ---help---
-         Say Y here if you want to use the TEF6862 Car Radio Enhanced
-         Selectivity Tuner, found for instance on the Russellville development
-         board. On the russellville the device is connected to internal
-         timberdale I2C bus.
-
-         To compile this driver as a module, choose M here: the
-         module will be called TEF6862.
-
-config RADIO_TIMBERDALE
-       tristate "Enable the Timberdale radio driver"
-       depends on MFD_TIMBERDALE && VIDEO_V4L2
-       depends on I2C  # for RADIO_SAA7706H
-       select RADIO_TEF6862
-       select RADIO_SAA7706H
-       ---help---
-         This is a kind of umbrella driver for the Radio Tuner and DSP
-         found behind the Timberdale FPGA on the Russellville board.
-         Enabling this driver will automatically select the DSP and tuner.
-
-config RADIO_WL1273
-       tristate "Texas Instruments WL1273 I2C FM Radio"
-       depends on I2C && VIDEO_V4L2
-       select MFD_WL1273_CORE
-       select FW_LOADER
-       ---help---
-         Choose Y here if you have this FM radio chip.
-
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux 2 API.  Information on
-         this API and pointers to "v4l2" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called radio-wl1273.
-
-# TI's ST based wl128x FM radio
-source "drivers/media/radio/wl128x/Kconfig"
+endif # V4L_RADIO_ISA_DRIVERS
 
 endif # RADIO_ADAPTERS
index edadc8449a3d109ab736afdd24f71058fb07b171..36ce0611c0379824d7d2b792611a2acfb7c20cf8 100644 (file)
@@ -47,11 +47,11 @@ MODULE_VERSION("0.0.4");
 #endif
 
 static int io          = CONFIG_RADIO_GEMTEK_PORT;
-static int probe       = CONFIG_RADIO_GEMTEK_PROBE;
-static int hardmute;
-static int shutdown    = 1;
-static int keepmuted   = 1;
-static int initmute    = 1;
+static bool probe      = CONFIG_RADIO_GEMTEK_PROBE;
+static bool hardmute;
+static bool shutdown   = 1;
+static bool keepmuted  = 1;
+static bool initmute   = 1;
 static int radio_nr    = -1;
 
 module_param(io, int, 0444);
index 3fb76e3834c99da96e8621ab4ecd89458913d259..87c1ee13b058541b0ec9cfa3f0f33c75f173334b 100644 (file)
@@ -23,7 +23,7 @@ static int radio_nr = -1;
 module_param(radio_nr, int, 0);
 MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX).  Default: -1 (autodetect)");
 
-static int mono;
+static bool mono;
 module_param(mono, bool, 0);
 MODULE_PARM_DESC(mono, "Force tuner into mono mode.");
 
index d1fab58850612a333fea3a5f26603bf04c52bc90..c54210c7fef90783200ccec467230fa6a7f3dc69 100644 (file)
@@ -355,17 +355,4 @@ static struct platform_driver radio_si4713_pdriver = {
        .remove         = __exit_p(radio_si4713_pdriver_remove),
 };
 
-/* Module Interface */
-static int __init radio_si4713_module_init(void)
-{
-       return platform_driver_register(&radio_si4713_pdriver);
-}
-
-static void __exit radio_si4713_module_exit(void)
-{
-       platform_driver_unregister(&radio_si4713_pdriver);
-}
-
-module_init(radio_si4713_module_init);
-module_exit(radio_si4713_module_exit);
-
+module_platform_driver(radio_si4713_pdriver);
index 3e9209f84e09bb04f46e75e2e517f10f9d37f608..5d9a90ac3a1c0230b75bffaeff6de7f4cfbb015c 100644 (file)
@@ -226,20 +226,7 @@ static struct platform_driver timbradio_platform_driver = {
        .remove         = timbradio_remove,
 };
 
-/*--------------------------------------------------------------------------*/
-
-static int __init timbradio_init(void)
-{
-       return platform_driver_register(&timbradio_platform_driver);
-}
-
-static void __exit timbradio_exit(void)
-{
-       platform_driver_unregister(&timbradio_platform_driver);
-}
-
-module_init(timbradio_init);
-module_exit(timbradio_exit);
+module_platform_driver(timbradio_platform_driver);
 
 MODULE_DESCRIPTION("Timberdale Radio driver");
 MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
index 8aa4968d57bc6cf3317669fb3a8b9c27daf074b4..f1b607099b6c10361a1305c521b612d7c10ca8ff 100644 (file)
@@ -2148,8 +2148,6 @@ pdata_err:
        return r;
 }
 
-MODULE_ALIAS("platform:wl1273_fm_radio");
-
 static struct platform_driver wl1273_fm_radio_driver = {
        .probe          = wl1273_fm_radio_probe,
        .remove         = __devexit_p(wl1273_fm_radio_remove),
@@ -2159,20 +2157,9 @@ static struct platform_driver wl1273_fm_radio_driver = {
        },
 };
 
-static int __init wl1273_fm_module_init(void)
-{
-       pr_info("%s\n", __func__);
-       return platform_driver_register(&wl1273_fm_radio_driver);
-}
-module_init(wl1273_fm_module_init);
-
-static void __exit wl1273_fm_module_exit(void)
-{
-       platform_driver_unregister(&wl1273_fm_radio_driver);
-       pr_info(DRIVER_DESC ", Exiting.\n");
-}
-module_exit(wl1273_fm_module_exit);
+module_platform_driver(wl1273_fm_radio_driver);
 
 MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wl1273_fm_radio");
index 0991e1973678ce0751c455cb85249264935415fb..3408685b690c74406b690ea101992563028169f1 100644 (file)
@@ -118,9 +118,11 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
        i2cmsg[2] = pll & 0xff;
 
        err = i2c_master_send(client, i2cmsg, sizeof(i2cmsg));
-       if (!err)
-               state->freq = f->frequency;
-       return err;
+       if (err != sizeof(i2cmsg))
+               return err < 0 ? err : -EIO;
+
+       state->freq = f->frequency;
+       return 0;
 }
 
 static int tef6862_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
index 749f67b192e7818340126d5582628ce779d865f3..86b28579f0c745a4e257b00aecb26ce320a3339f 100644 (file)
@@ -5,7 +5,7 @@ menu "Texas Instruments WL128x FM driver (ST based)"
 config RADIO_WL128X
        tristate "Texas Instruments WL128x FM Radio"
        depends on VIDEO_V4L2 && RFKILL
-       select TI_ST
+       select TI_ST if NET && GPIOLIB
        help
        Choose Y here if you have this FM radio chip.
 
index 5991ab60303dcafda387ce7d6d304ef039aa39db..bf867a6b5ea0b5c745bf6684a75183e25b354843 100644 (file)
@@ -387,7 +387,7 @@ static void send_tasklet(unsigned long arg)
  * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for
  * transmission
  */
-static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type,        void *payload,
+static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type,        void *payload,
                int payload_len, struct completion *wait_completion)
 {
        struct sk_buff *skb;
@@ -456,13 +456,13 @@ static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type,   void *payload,
 }
 
 /* Sends FM Channel-8 command to the chip and waits for the response */
-u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
+int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
                unsigned int payload_len, void *response, int *response_len)
 {
        struct sk_buff *skb;
        struct fm_event_msg_hdr *evt_hdr;
        unsigned long flags;
-       u32 ret;
+       int ret;
 
        init_completion(&fmdev->maintask_comp);
        ret = fm_send_cmd(fmdev, fm_op, type, payload, payload_len,
@@ -470,8 +470,8 @@ u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
        if (ret)
                return ret;
 
-       ret = wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT);
-       if (!ret) {
+       if (!wait_for_completion_timeout(&fmdev->maintask_comp,
+                                        FM_DRV_TX_TIMEOUT)) {
                fmerr("Timeout(%d sec),didn't get reg"
                           "completion signal from RX tasklet\n",
                           jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
@@ -508,7 +508,7 @@ u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
 }
 
 /* --- Helper functions used in FM interrupt handlers ---*/
-static inline u32 check_cmdresp_status(struct fmdev *fmdev,
+static inline int check_cmdresp_status(struct fmdev *fmdev,
                struct sk_buff **skb)
 {
        struct fm_event_msg_hdr *fm_evt_hdr;
@@ -1058,7 +1058,7 @@ static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev)
 }
 
 /* Returns availability of RDS data in internel buffer */
-u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file,
+int fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file,
                                struct poll_table_struct *pts)
 {
        poll_wait(file, &fmdev->rx.rds.read_queue, pts);
@@ -1069,7 +1069,7 @@ u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file,
 }
 
 /* Copies RDS data from internal buffer to user buffer */
-u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file,
+int fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file,
                u8 __user *buf, size_t count)
 {
        u32 block_count;
@@ -1113,7 +1113,7 @@ u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file,
        return ret;
 }
 
-u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set)
+int fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set)
 {
        switch (fmdev->curr_fmmode) {
        case FM_MODE_RX:
@@ -1127,7 +1127,7 @@ u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set)
        }
 }
 
-u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq)
+int fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq)
 {
        if (fmdev->rx.freq == FM_UNDEFINED_FREQ) {
                fmerr("RX frequency is not set\n");
@@ -1153,7 +1153,7 @@ u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq)
 
 }
 
-u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set)
+int fmc_set_region(struct fmdev *fmdev, u8 region_to_set)
 {
        switch (fmdev->curr_fmmode) {
        case FM_MODE_RX:
@@ -1167,7 +1167,7 @@ u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set)
        }
 }
 
-u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
+int fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
 {
        switch (fmdev->curr_fmmode) {
        case FM_MODE_RX:
@@ -1181,7 +1181,7 @@ u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
        }
 }
 
-u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode)
+int fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode)
 {
        switch (fmdev->curr_fmmode) {
        case FM_MODE_RX:
@@ -1195,7 +1195,7 @@ u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode)
        }
 }
 
-u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
+int fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
 {
        switch (fmdev->curr_fmmode) {
        case FM_MODE_RX:
@@ -1210,10 +1210,10 @@ u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
 }
 
 /* Sends power off command to the chip */
-static u32 fm_power_down(struct fmdev *fmdev)
+static int fm_power_down(struct fmdev *fmdev)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
                fmerr("FM core is not ready\n");
@@ -1234,7 +1234,7 @@ static u32 fm_power_down(struct fmdev *fmdev)
 }
 
 /* Reads init command from FM firmware file and loads to the chip */
-static u32 fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name)
+static int fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name)
 {
        const struct firmware *fw_entry;
        struct bts_header *fw_header;
@@ -1299,7 +1299,7 @@ rel_fw:
 }
 
 /* Loads default RX configuration to the chip */
-static u32 load_default_rx_configuration(struct fmdev *fmdev)
+static int load_default_rx_configuration(struct fmdev *fmdev)
 {
        int ret;
 
@@ -1311,7 +1311,7 @@ static u32 load_default_rx_configuration(struct fmdev *fmdev)
 }
 
 /* Does FM power on sequence */
-static u32 fm_power_up(struct fmdev *fmdev, u8 mode)
+static int fm_power_up(struct fmdev *fmdev, u8 mode)
 {
        u16 payload, asic_id, asic_ver;
        int resp_len, ret;
@@ -1374,7 +1374,7 @@ rel:
 }
 
 /* Set FM Modes(TX, RX, OFF) */
-u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode)
+int fmc_set_mode(struct fmdev *fmdev, u8 fm_mode)
 {
        int ret = 0;
 
@@ -1427,7 +1427,7 @@ u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode)
 }
 
 /* Returns current FM mode (TX, RX, OFF) */
-u32 fmc_get_mode(struct fmdev *fmdev, u8 *fmmode)
+int fmc_get_mode(struct fmdev *fmdev, u8 *fmmode)
 {
        if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
                fmerr("FM core is not ready\n");
@@ -1483,10 +1483,10 @@ static void fm_st_reg_comp_cb(void *arg, char data)
  * This function will be called from FM V4L2 open function.
  * Register with ST driver and initialize driver data.
  */
-u32 fmc_prepare(struct fmdev *fmdev)
+int fmc_prepare(struct fmdev *fmdev)
 {
        static struct st_proto_s fm_st_proto;
-       u32 ret;
+       int ret;
 
        if (test_bit(FM_CORE_READY, &fmdev->flag)) {
                fmdbg("FM Core is already up\n");
@@ -1512,10 +1512,8 @@ u32 fmc_prepare(struct fmdev *fmdev)
                fmdev->streg_cbdata = -EINPROGRESS;
                fmdbg("%s waiting for ST reg completion signal\n", __func__);
 
-               ret = wait_for_completion_timeout(&wait_for_fmdrv_reg_comp,
-                               FM_ST_REG_TIMEOUT);
-
-               if (!ret) {
+               if (!wait_for_completion_timeout(&wait_for_fmdrv_reg_comp,
+                                                FM_ST_REG_TIMEOUT)) {
                        fmerr("Timeout(%d sec), didn't get reg "
                                        "completion signal from ST\n",
                                        jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000);
@@ -1589,10 +1587,10 @@ u32 fmc_prepare(struct fmdev *fmdev)
  * This function will be called from FM V4L2 release function.
  * Unregister from ST driver.
  */
-u32 fmc_release(struct fmdev *fmdev)
+int fmc_release(struct fmdev *fmdev)
 {
        static struct st_proto_s fm_st_proto;
-       u32 ret;
+       int ret;
 
        if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
                fmdbg("FM Core is already down\n");
@@ -1631,7 +1629,7 @@ u32 fmc_release(struct fmdev *fmdev)
 static int __init fm_drv_init(void)
 {
        struct fmdev *fmdev = NULL;
-       u32 ret = -ENOMEM;
+       int ret = -ENOMEM;
 
        fmdbg("FM driver version %s\n", FM_DRV_VERSION);
 
index aee243bb6630d550e018b3f37e2d6d5a986cba9c..d9b9c6cf83b40fe9f9a973ec3de930b784cd5b4d 100644 (file)
@@ -368,27 +368,27 @@ struct fm_event_msg_hdr {
 #define FM_TX_ANT_IMP_500              2
 
 /* Functions exported by FM common sub-module */
-u32 fmc_prepare(struct fmdev *);
-u32 fmc_release(struct fmdev *);
+int fmc_prepare(struct fmdev *);
+int fmc_release(struct fmdev *);
 
 void fmc_update_region_info(struct fmdev *, u8);
-u32 fmc_send_cmd(struct fmdev *, u8, u16,
+int fmc_send_cmd(struct fmdev *, u8, u16,
                                void *, unsigned int, void *, int *);
-u32 fmc_is_rds_data_available(struct fmdev *, struct file *,
+int fmc_is_rds_data_available(struct fmdev *, struct file *,
                                struct poll_table_struct *);
-u32 fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *,
+int fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *,
                                        u8 __user *, size_t);
 
-u32 fmc_set_freq(struct fmdev *, u32);
-u32 fmc_set_mode(struct fmdev *, u8);
-u32 fmc_set_region(struct fmdev *, u8);
-u32 fmc_set_mute_mode(struct fmdev *, u8);
-u32 fmc_set_stereo_mono(struct fmdev *, u16);
-u32 fmc_set_rds_mode(struct fmdev *, u8);
+int fmc_set_freq(struct fmdev *, u32);
+int fmc_set_mode(struct fmdev *, u8);
+int fmc_set_region(struct fmdev *, u8);
+int fmc_set_mute_mode(struct fmdev *, u8);
+int fmc_set_stereo_mono(struct fmdev *, u16);
+int fmc_set_rds_mode(struct fmdev *, u8);
 
-u32 fmc_get_freq(struct fmdev *, u32 *);
-u32 fmc_get_region(struct fmdev *, u8 *);
-u32 fmc_get_mode(struct fmdev *, u8 *);
+int fmc_get_freq(struct fmdev *, u32 *);
+int fmc_get_region(struct fmdev *, u8 *);
+int fmc_get_mode(struct fmdev *, u8 *);
 
 /*
  * channel spacing
index ec529b55b040db1de737f0901cb13a222f0c9827..43fb72291bea15551f7bf5ca01577d23db879ef9 100644 (file)
@@ -43,12 +43,13 @@ void fm_rx_reset_station_info(struct fmdev *fmdev)
        fmdev->rx.stat_info.af_list_max = 0;
 }
 
-u32 fm_rx_set_freq(struct fmdev *fmdev, u32 freq)
+int fm_rx_set_freq(struct fmdev *fmdev, u32 freq)
 {
        unsigned long timeleft;
        u16 payload, curr_frq, intr_flag;
        u32 curr_frq_in_khz;
-       u32 ret, resp_len;
+       u32 resp_len;
+       int ret;
 
        if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) {
                fmerr("Invalid frequency %d\n", freq);
@@ -141,10 +142,10 @@ exit:
        return ret;
 }
 
-static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing)
+static int fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (spacing > 0 && spacing <= 50000)
                spacing = FM_CHANNEL_SPACING_50KHZ;
@@ -165,7 +166,7 @@ static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing)
        return ret;
 }
 
-u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward,
+int fm_rx_seek(struct fmdev *fmdev, u32 seek_upward,
                u32 wrap_around, u32 spacing)
 {
        u32 resp_len;
@@ -173,7 +174,7 @@ u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward,
        u16 payload, int_reason, intr_flag;
        u16 offset, space_idx;
        unsigned long timeleft;
-       u32 ret;
+       int ret;
 
        /* Set channel spacing */
        ret = fm_rx_set_channel_spacing(fmdev, spacing);
@@ -296,10 +297,10 @@ again:
        return ret;
 }
 
-u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set)
+int fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (fmdev->curr_fmmode != FM_MODE_RX)
                return -EPERM;
@@ -322,7 +323,7 @@ u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set)
 }
 
 /* Get volume */
-u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol)
+int fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol)
 {
        if (fmdev->curr_fmmode != FM_MODE_RX)
                return -EPERM;
@@ -338,7 +339,7 @@ u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol)
 }
 
 /* To get current band's bottom and top frequency */
-u32 fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq)
+int fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq)
 {
        if (bot_freq != NULL)
                *bot_freq = fmdev->rx.region.bot_freq;
@@ -356,11 +357,11 @@ void fm_rx_get_region(struct fmdev *fmdev, u8 *region)
 }
 
 /* Sets band (0-Europe/US; 1-Japan) */
-u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set)
+int fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set)
 {
        u16 payload;
        u32 new_frq = 0;
-       u32 ret;
+       int ret;
 
        if (region_to_set != FM_BAND_EUROPE_US &&
            region_to_set != FM_BAND_JAPAN) {
@@ -399,7 +400,7 @@ u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set)
 }
 
 /* Reads current mute mode (Mute Off/On/Attenuate)*/
-u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode)
+int fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode)
 {
        if (fmdev->curr_fmmode != FM_MODE_RX)
                return -EPERM;
@@ -414,10 +415,10 @@ u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode)
        return 0;
 }
 
-static u32 fm_config_rx_mute_reg(struct fmdev *fmdev)
+static int fm_config_rx_mute_reg(struct fmdev *fmdev)
 {
        u16 payload, muteval;
-       u32 ret;
+       int ret;
 
        muteval = 0;
        switch (fmdev->rx.mute_mode) {
@@ -448,10 +449,10 @@ static u32 fm_config_rx_mute_reg(struct fmdev *fmdev)
 }
 
 /* Configures mute mode (Mute Off/On/Attenuate) */
-u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
+int fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
 {
        u8 org_state;
-       u32 ret;
+       int ret;
 
        if (fmdev->rx.mute_mode == mute_mode_toset)
                return 0;
@@ -469,7 +470,7 @@ u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
 }
 
 /* Gets RF dependent soft mute mode enable/disable status */
-u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode)
+int fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode)
 {
        if (fmdev->curr_fmmode != FM_MODE_RX)
                return -EPERM;
@@ -485,10 +486,10 @@ u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode)
 }
 
 /* Sets RF dependent soft mute mode */
-u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute)
+int fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute)
 {
        u8 org_state;
-       u32 ret;
+       int ret;
 
        if (fmdev->curr_fmmode != FM_MODE_RX)
                return -EPERM;
@@ -514,11 +515,11 @@ u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute)
 }
 
 /* Returns the signal strength level of current channel */
-u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
+int fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
 {
        u16 curr_rssi_lel;
        u32 resp_len;
-       u32 ret;
+       int ret;
 
        if (rssilvl == NULL) {
                fmerr("Invalid memory\n");
@@ -539,10 +540,10 @@ u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
  * Sets the signal strength level that once reached
  * will stop the auto search process
  */
-u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset)
+int fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN ||
                        rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) {
@@ -561,7 +562,7 @@ u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset)
 }
 
 /* Returns current RX RSSI threshold value */
-u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl)
+int fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl)
 {
        if (fmdev->curr_fmmode != FM_MODE_RX)
                return -EPERM;
@@ -577,10 +578,10 @@ u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl)
 }
 
 /* Sets RX stereo/mono modes */
-u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
+int fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) {
                fmerr("Invalid mode\n");
@@ -605,10 +606,11 @@ u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
 }
 
 /* Gets current RX stereo/mono mode */
-u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
+int fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
 {
        u16 curr_mode;
-       u32 ret, resp_len;
+       u32 resp_len;
+       int ret;
 
        if (mode == NULL) {
                fmerr("Invalid memory\n");
@@ -626,10 +628,10 @@ u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
 }
 
 /* Choose RX de-emphasis filter mode (50us/75us) */
-u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode)
+int fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (fmdev->curr_fmmode != FM_MODE_RX)
                return -EPERM;
@@ -652,7 +654,7 @@ u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode)
 }
 
 /* Gets current RX de-emphasis filter mode */
-u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode)
+int fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode)
 {
        if (fmdev->curr_fmmode != FM_MODE_RX)
                return -EPERM;
@@ -668,10 +670,10 @@ u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode)
 }
 
 /* Enable/Disable RX RDS */
-u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
+int fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) {
                fmerr("Invalid rds option\n");
@@ -743,7 +745,7 @@ u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
 }
 
 /* Returns current RX RDS enable/disable status */
-u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis)
+int fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis)
 {
        if (fmdev->curr_fmmode != FM_MODE_RX)
                return -EPERM;
@@ -759,10 +761,10 @@ u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis)
 }
 
 /* Sets RDS operation mode (RDS/RDBS) */
-u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode)
+int fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (fmdev->curr_fmmode != FM_MODE_RX)
                return -EPERM;
@@ -784,7 +786,7 @@ u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode)
 }
 
 /* Returns current RDS operation mode */
-u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode)
+int fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode)
 {
        if (fmdev->curr_fmmode != FM_MODE_RX)
                return -EPERM;
@@ -800,10 +802,10 @@ u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode)
 }
 
 /* Configures Alternate Frequency switch mode */
-u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode)
+int fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (fmdev->curr_fmmode != FM_MODE_RX)
                return -EPERM;
@@ -831,7 +833,7 @@ u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode)
 }
 
 /* Returns Alternate Frequency switch status */
-u32 fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode)
+int fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode)
 {
        if (fmdev->curr_fmmode != FM_MODE_RX)
                return -EPERM;
index 329e62f6be76950ba59b8cccbce6bb55900d39a9..32add81f8d87699fd15eafedefa6b8d9a31264b1 100644 (file)
 #ifndef _FMDRV_RX_H
 #define _FMDRV_RX_H
 
-u32 fm_rx_set_freq(struct fmdev *, u32);
-u32 fm_rx_set_mute_mode(struct fmdev *, u8);
-u32 fm_rx_set_stereo_mono(struct fmdev *, u16);
-u32 fm_rx_set_rds_mode(struct fmdev *, u8);
-u32 fm_rx_set_rds_system(struct fmdev *, u8);
-u32 fm_rx_set_volume(struct fmdev *, u16);
-u32 fm_rx_set_rssi_threshold(struct fmdev *, short);
-u32 fm_rx_set_region(struct fmdev *, u8);
-u32 fm_rx_set_rfdepend_softmute(struct fmdev *, u8);
-u32 fm_rx_set_deemphasis_mode(struct fmdev *, u16);
-u32 fm_rx_set_af_switch(struct fmdev *, u8);
+int fm_rx_set_freq(struct fmdev *, u32);
+int fm_rx_set_mute_mode(struct fmdev *, u8);
+int fm_rx_set_stereo_mono(struct fmdev *, u16);
+int fm_rx_set_rds_mode(struct fmdev *, u8);
+int fm_rx_set_rds_system(struct fmdev *, u8);
+int fm_rx_set_volume(struct fmdev *, u16);
+int fm_rx_set_rssi_threshold(struct fmdev *, short);
+int fm_rx_set_region(struct fmdev *, u8);
+int fm_rx_set_rfdepend_softmute(struct fmdev *, u8);
+int fm_rx_set_deemphasis_mode(struct fmdev *, u16);
+int fm_rx_set_af_switch(struct fmdev *, u8);
 
 void fm_rx_reset_rds_cache(struct fmdev *);
 void fm_rx_reset_station_info(struct fmdev *);
 
-u32 fm_rx_seek(struct fmdev *, u32, u32, u32);
+int fm_rx_seek(struct fmdev *, u32, u32, u32);
 
-u32 fm_rx_get_rds_mode(struct fmdev *, u8 *);
-u32 fm_rx_get_rds_system(struct fmdev *, u8 *);
-u32 fm_rx_get_mute_mode(struct fmdev *, u8 *);
-u32 fm_rx_get_volume(struct fmdev *, u16 *);
-u32 fm_rx_get_band_freq_range(struct fmdev *,
+int fm_rx_get_rds_mode(struct fmdev *, u8 *);
+int fm_rx_get_rds_system(struct fmdev *, u8 *);
+int fm_rx_get_mute_mode(struct fmdev *, u8 *);
+int fm_rx_get_volume(struct fmdev *, u16 *);
+int fm_rx_get_band_freq_range(struct fmdev *,
                                        u32 *, u32 *);
-u32 fm_rx_get_stereo_mono(struct fmdev *, u16 *);
-u32 fm_rx_get_rssi_level(struct fmdev *, u16 *);
-u32 fm_rx_get_rssi_threshold(struct fmdev *, short *);
-u32 fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *);
-u32 fm_rx_get_deemph_mode(struct fmdev *, u16 *);
-u32 fm_rx_get_af_switch(struct fmdev *, u8 *);
+int fm_rx_get_stereo_mono(struct fmdev *, u16 *);
+int fm_rx_get_rssi_level(struct fmdev *, u16 *);
+int fm_rx_get_rssi_threshold(struct fmdev *, short *);
+int fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *);
+int fm_rx_get_deemph_mode(struct fmdev *, u16 *);
+int fm_rx_get_af_switch(struct fmdev *, u8 *);
 void fm_rx_get_region(struct fmdev *, u8 *);
 
-u32 fm_rx_set_chanl_spacing(struct fmdev *, u8);
-u32 fm_rx_get_chanl_spacing(struct fmdev *, u8 *);
+int fm_rx_set_chanl_spacing(struct fmdev *, u8);
+int fm_rx_get_chanl_spacing(struct fmdev *, u8 *);
 #endif
 
index be54068b56a8b0abd3344896e34c9e43cf60a114..6ea33e09d63b23b306979142ace913d6806f561f 100644 (file)
 #include "fmdrv_common.h"
 #include "fmdrv_tx.h"
 
-u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
+int fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (fmdev->tx_data.aud_mode == mode)
                return 0;
@@ -46,10 +46,10 @@ u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
        return ret;
 }
 
-static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text)
+static int set_rds_text(struct fmdev *fmdev, u8 *rds_text)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text,
                        strlen(rds_text), NULL, NULL);
@@ -66,10 +66,10 @@ static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text)
        return 0;
 }
 
-static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode)
+static int set_rds_data_mode(struct fmdev *fmdev, u8 mode)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        /* Setting unique PI TODO: how unique? */
        payload = (u16)0xcafe;
@@ -89,10 +89,10 @@ static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode)
        return 0;
 }
 
-static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len)
+static int set_rds_len(struct fmdev *fmdev, u8 type, u16 len)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        len |= type << 8;
        payload = len;
@@ -105,10 +105,10 @@ static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len)
        return 0;
 }
 
-u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
+int fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
 {
        u16 payload;
-       u32 ret;
+       int ret;
        u8 rds_text[] = "Zoom2\n";
 
        fmdbg("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis,
@@ -148,10 +148,10 @@ u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
        return 0;
 }
 
-u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type)
+int fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (fmdev->curr_fmmode != FM_MODE_TX)
                return -EPERM;
@@ -176,10 +176,10 @@ u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type)
        return 0;
 }
 
-u32 fm_tx_set_af(struct fmdev *fmdev, u32 af)
+int fm_tx_set_af(struct fmdev *fmdev, u32 af)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (fmdev->curr_fmmode != FM_MODE_TX)
                return -EPERM;
@@ -196,10 +196,10 @@ u32 fm_tx_set_af(struct fmdev *fmdev, u32 af)
        return 0;
 }
 
-u32 fm_tx_set_region(struct fmdev *fmdev, u8 region)
+int fm_tx_set_region(struct fmdev *fmdev, u8 region)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (region != FM_BAND_EUROPE_US && region != FM_BAND_JAPAN) {
                fmerr("Invalid band\n");
@@ -216,10 +216,10 @@ u32 fm_tx_set_region(struct fmdev *fmdev, u8 region)
        return 0;
 }
 
-u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
+int fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
 {
        u16 payload;
-       u32 ret;
+       int ret;
 
        fmdbg("tx: mute mode %d\n", mute_mode_toset);
 
@@ -233,11 +233,11 @@ u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
 }
 
 /* Set TX Audio I/O */
-static u32 set_audio_io(struct fmdev *fmdev)
+static int set_audio_io(struct fmdev *fmdev)
 {
        struct fmtx_data *tx = &fmdev->tx_data;
        u16 payload;
-       u32 ret;
+       int ret;
 
        /* Set Audio I/O Enable */
        payload = tx->audio_io;
@@ -251,12 +251,12 @@ static u32 set_audio_io(struct fmdev *fmdev)
 }
 
 /* Start TX Transmission */
-static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state)
+static int enable_xmit(struct fmdev *fmdev, u8 new_xmit_state)
 {
        struct fmtx_data *tx = &fmdev->tx_data;
        unsigned long timeleft;
        u16 payload;
-       u32 ret;
+       int ret;
 
        /* Enable POWER_ENB interrupts */
        payload = FM_POW_ENB_EVENT;
@@ -289,11 +289,11 @@ static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state)
 }
 
 /* Set TX power level */
-u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl)
+int fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl)
 {
        u16 payload;
        struct fmtx_data *tx = &fmdev->tx_data;
-       u32 ret;
+       int ret;
 
        if (fmdev->curr_fmmode != FM_MODE_TX)
                return -EPERM;
@@ -328,11 +328,11 @@ u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl)
  * Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us)
  * Convert V4L2 specified filter values to chip specific filter values.
  */
-u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis)
+int fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis)
 {
        struct fmtx_data *tx = &fmdev->tx_data;
        u16 payload;
-       u32 ret;
+       int ret;
 
        if (fmdev->curr_fmmode != FM_MODE_TX)
                return -EPERM;
@@ -360,10 +360,11 @@ u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis)
 }
 
 /* Get the TX tuning capacitor value.*/
-u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev)
+int fm_tx_get_tune_cap_val(struct fmdev *fmdev)
 {
        u16 curr_val;
-       u32 ret, resp_len;
+       u32 resp_len;
+       int ret;
 
        if (fmdev->curr_fmmode != FM_MODE_TX)
                return -EPERM;
@@ -379,11 +380,11 @@ u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev)
 }
 
 /* Set TX Frequency */
-u32 fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set)
+int fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set)
 {
        struct fmtx_data *tx = &fmdev->tx_data;
        u16 payload, chanl_index;
-       u32 ret;
+       int ret;
 
        if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) {
                enable_xmit(fmdev, 0);
index e393a2bdd49e63fd9ed5d8bb6cbf065d9c134baa..11ae2e4c2d033e586bfcda18db1754aa9462fe8b 100644 (file)
 #ifndef _FMDRV_TX_H
 #define _FMDRV_TX_H
 
-u32 fm_tx_set_freq(struct fmdev *, u32);
-u32 fm_tx_set_pwr_lvl(struct fmdev *, u8);
-u32 fm_tx_set_region(struct fmdev *, u8);
-u32 fm_tx_set_mute_mode(struct fmdev *, u8);
-u32 fm_tx_set_stereo_mono(struct fmdev *, u16);
-u32 fm_tx_set_rds_mode(struct fmdev *, u8);
-u32 fm_tx_set_radio_text(struct fmdev *, u8 *, u8);
-u32 fm_tx_set_af(struct fmdev *, u32);
-u32 fm_tx_set_preemph_filter(struct fmdev *, u32);
-u32 fm_tx_get_tune_cap_val(struct fmdev *);
+int fm_tx_set_freq(struct fmdev *, u32);
+int fm_tx_set_pwr_lvl(struct fmdev *, u8);
+int fm_tx_set_region(struct fmdev *, u8);
+int fm_tx_set_mute_mode(struct fmdev *, u8);
+int fm_tx_set_stereo_mono(struct fmdev *, u16);
+int fm_tx_set_rds_mode(struct fmdev *, u8);
+int fm_tx_set_radio_text(struct fmdev *, u8 *, u8);
+int fm_tx_set_af(struct fmdev *, u32);
+int fm_tx_set_preemph_filter(struct fmdev *, u32);
+int fm_tx_get_tune_cap_val(struct fmdev *);
 
 #endif
 
index 4f5c43d2566c887444a91329b64a3960229e5278..077d369a017318e40849466c92bea074c94b46c1 100644 (file)
@@ -84,6 +84,7 @@ static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf,
        struct fmdev *fmdev;
 
        ret = copy_from_user(&rds, buf, sizeof(rds));
+       rds.text[sizeof(rds.text) - 1] = '\0';
        fmdbg("(%d)type: %d, text %s, af %d\n",
                   ret, rds.text_type, rds.text, rds.af_freq);
        if (ret)
index aeb7f43dfb652790b053192bceeca1f9fdf31758..4df4affeea5f1537d72a8383c970f472b34635b1 100644 (file)
@@ -87,6 +87,16 @@ config IR_RC5_SZ_DECODER
           uses an IR protocol that is almost standard RC-5, but not quite,
           as it uses an additional bit).
 
+config IR_SANYO_DECODER
+       tristate "Enable IR raw decoder for the Sanyo protocol"
+       depends on RC_CORE
+       default y
+
+       ---help---
+          Enable this option if you have an infrared remote control which
+          uses the Sanyo protocol (Sanyo, Aiwa, Chinon remotes),
+          and you need software decoding support.
+
 config IR_MCE_KBD_DECODER
        tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
        depends on RC_CORE
index 2156e786b5571194bbe36b69c4ac1e610cbfc75c..fb3dee2dd84584788c14af2ef0aab4816a0c88bb 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
 obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
 obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
 obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
+obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o
 obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
 obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
 
index 17f8db00435ac70269823ae3f029968cebbbd72a..3c9431a9f62d282d37238ab6089cd63ca73ad77b 100644 (file)
@@ -194,8 +194,8 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
                return 0;
        }
 
-       IR_dprintk(1, "NEC decode failed at state %d (%uus %s)\n",
-                  data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+       IR_dprintk(1, "NEC decode failed at count %d state %d (%uus %s)\n",
+                  data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
        data->state = STATE_INACTIVE;
        return -EINVAL;
 }
index 2e5cd3100b64476da15ef33508cbd39dd42ded50..95e630998aaf42d2e2441514f62713038ab41fdc 100644 (file)
@@ -357,6 +357,7 @@ static void init_decoders(struct work_struct *work)
        load_rc6_decode();
        load_jvc_decode();
        load_sony_decode();
+       load_sanyo_decode();
        load_mce_kbd_decode();
        load_lirc_codec();
 
index 140fb67e2f89d9be9ce79a1b475a2fb24a900140..4cfdd7fa4bbd56b7d04f130b78020f8977ebaec6 100644 (file)
 /*
  * This decoder currently supports:
  * RC6-0-16    (standard toggle bit in header)
+ * RC6-6A-20   (no toggle bit)
  * RC6-6A-24   (no toggle bit)
  * RC6-6A-32   (MCE version with toggle bit in body)
  */
 
-#define RC6_UNIT               444444  /* us */
+#define RC6_UNIT               444444  /* nanosecs */
 #define RC6_HEADER_NBITS       4       /* not including toggle bit */
 #define RC6_0_NBITS            16
-#define RC6_6A_SMALL_NBITS     24
-#define RC6_6A_LARGE_NBITS     32
+#define RC6_6A_32_NBITS                32
+#define RC6_6A_NBITS           128     /* Variable 8..128 */
 #define RC6_PREFIX_PULSE       (6 * RC6_UNIT)
 #define RC6_PREFIX_SPACE       (2 * RC6_UNIT)
 #define RC6_BIT_START          (1 * RC6_UNIT)
 #define RC6_BIT_END            (1 * RC6_UNIT)
 #define RC6_TOGGLE_START       (2 * RC6_UNIT)
 #define RC6_TOGGLE_END         (2 * RC6_UNIT)
+#define RC6_SUFFIX_SPACE       (6 * RC6_UNIT)
 #define RC6_MODE_MASK          0x07    /* for the header bits */
 #define RC6_STARTBIT_MASK      0x08    /* for the header bits */
 #define RC6_6A_MCE_TOGGLE_MASK 0x8000  /* for the body bits */
+#define RC6_6A_LCC_MASK                0xffff0000 /* RC6-6A-32 long customer code mask */
+#define RC6_6A_MCE_CC          0x800f0000 /* MCE customer code */
+#ifndef CHAR_BIT
+#define CHAR_BIT 8     /* Normally in <limits.h> */
+#endif
 
 enum rc6_mode {
        RC6_MODE_0,
@@ -125,6 +132,7 @@ again:
                        break;
 
                data->state = STATE_HEADER_BIT_START;
+               data->header = 0;
                return 0;
 
        case STATE_HEADER_BIT_START:
@@ -171,20 +179,14 @@ again:
                data->state = STATE_BODY_BIT_START;
                decrease_duration(&ev, RC6_TOGGLE_END);
                data->count = 0;
+               data->body = 0;
 
                switch (rc6_mode(data)) {
                case RC6_MODE_0:
                        data->wanted_bits = RC6_0_NBITS;
                        break;
                case RC6_MODE_6A:
-                       /* This might look weird, but we basically
-                          check the value of the first body bit to
-                          determine the number of bits in mode 6A */
-                       if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) ||
-                           geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
-                               data->wanted_bits = RC6_6A_LARGE_NBITS;
-                       else
-                               data->wanted_bits = RC6_6A_SMALL_NBITS;
+                       data->wanted_bits = RC6_6A_NBITS;
                        break;
                default:
                        IR_dprintk(1, "RC6 unknown mode\n");
@@ -193,15 +195,21 @@ again:
                goto again;
 
        case STATE_BODY_BIT_START:
-               if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
-                       break;
-
-               data->body <<= 1;
-               if (ev.pulse)
-                       data->body |= 1;
-               data->count++;
-               data->state = STATE_BODY_BIT_END;
-               return 0;
+               if (eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) {
+                       /* Discard LSB's that won't fit in data->body */
+                       if (data->count++ < CHAR_BIT * sizeof data->body) {
+                               data->body <<= 1;
+                               if (ev.pulse)
+                                       data->body |= 1;
+                       }
+                       data->state = STATE_BODY_BIT_END;
+                       return 0;
+               } else if (RC6_MODE_6A == rc6_mode(data) && !ev.pulse &&
+                               geq_margin(ev.duration, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
+                       data->state = STATE_FINISHED;
+                       goto again;
+               }
+               break;
 
        case STATE_BODY_BIT_END:
                if (!is_transition(&ev, &dev->raw->prev_ev))
@@ -221,20 +229,27 @@ again:
 
                switch (rc6_mode(data)) {
                case RC6_MODE_0:
-                       scancode = data->body & 0xffff;
+                       scancode = data->body;
                        toggle = data->toggle;
                        IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
                                   scancode, toggle);
                        break;
                case RC6_MODE_6A:
-                       if (data->wanted_bits == RC6_6A_LARGE_NBITS) {
-                               toggle = data->body & RC6_6A_MCE_TOGGLE_MASK ? 1 : 0;
-                               scancode = data->body & ~RC6_6A_MCE_TOGGLE_MASK;
+                       if (data->count > CHAR_BIT * sizeof data->body) {
+                               IR_dprintk(1, "RC6 too many (%u) data bits\n",
+                                       data->count);
+                               goto out;
+                       }
+
+                       scancode = data->body;
+                       if (data->count == RC6_6A_32_NBITS &&
+                                       (scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
+                               /* MCE RC */
+                               toggle = (scancode & RC6_6A_MCE_TOGGLE_MASK) ? 1 : 0;
+                               scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
                        } else {
                                toggle = 0;
-                               scancode = data->body & 0xffffff;
                        }
-
                        IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n",
                                   scancode, toggle);
                        break;
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
new file mode 100644 (file)
index 0000000..d38fbdd
--- /dev/null
@@ -0,0 +1,205 @@
+/* ir-sanyo-decoder.c - handle SANYO IR Pulse/Space protocol
+ *
+ * Copyright (C) 2011 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation 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.
+ *
+ * This protocol uses the NEC protocol timings. However, data is formatted as:
+ *     13 bits Custom Code
+ *     13 bits NOT(Custom Code)
+ *     8 bits Key data
+ *     8 bits NOT(Key data)
+ *
+ * According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon
+ * Information for this protocol is available at the Sanyo LC7461 datasheet.
+ */
+
+#include <linux/module.h>
+#include <linux/bitrev.h>
+#include "rc-core-priv.h"
+
+#define SANYO_NBITS            (13+13+8+8)
+#define SANYO_UNIT             562500  /* ns */
+#define SANYO_HEADER_PULSE     (16  * SANYO_UNIT)
+#define SANYO_HEADER_SPACE     (8   * SANYO_UNIT)
+#define SANYO_BIT_PULSE                (1   * SANYO_UNIT)
+#define SANYO_BIT_0_SPACE      (1   * SANYO_UNIT)
+#define SANYO_BIT_1_SPACE      (3   * SANYO_UNIT)
+#define SANYO_REPEAT_SPACE     (150 * SANYO_UNIT)
+#define        SANYO_TRAILER_PULSE     (1   * SANYO_UNIT)
+#define        SANYO_TRAILER_SPACE     (10  * SANYO_UNIT)      /* in fact, 42 */
+
+enum sanyo_state {
+       STATE_INACTIVE,
+       STATE_HEADER_SPACE,
+       STATE_BIT_PULSE,
+       STATE_BIT_SPACE,
+       STATE_TRAILER_PULSE,
+       STATE_TRAILER_SPACE,
+};
+
+/**
+ * ir_sanyo_decode() - Decode one SANYO pulse or space
+ * @dev:       the struct rc_dev descriptor of the device
+ * @duration:  the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
+{
+       struct sanyo_dec *data = &dev->raw->sanyo;
+       u32 scancode;
+       u8 address, not_address, command, not_command;
+
+       if (!(dev->raw->enabled_protocols & RC_TYPE_SANYO))
+               return 0;
+
+       if (!is_timing_event(ev)) {
+               if (ev.reset) {
+                       IR_dprintk(1, "SANYO event reset received. reset to state 0\n");
+                       data->state = STATE_INACTIVE;
+               }
+               return 0;
+       }
+
+       IR_dprintk(2, "SANYO decode started at state %d (%uus %s)\n",
+                  data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+
+       switch (data->state) {
+
+       case STATE_INACTIVE:
+               if (!ev.pulse)
+                       break;
+
+               if (eq_margin(ev.duration, SANYO_HEADER_PULSE, SANYO_UNIT / 2)) {
+                       data->count = 0;
+                       data->state = STATE_HEADER_SPACE;
+                       return 0;
+               }
+               break;
+
+
+       case STATE_HEADER_SPACE:
+               if (ev.pulse)
+                       break;
+
+               if (eq_margin(ev.duration, SANYO_HEADER_SPACE, SANYO_UNIT / 2)) {
+                       data->state = STATE_BIT_PULSE;
+                       return 0;
+               }
+
+               break;
+
+       case STATE_BIT_PULSE:
+               if (!ev.pulse)
+                       break;
+
+               if (!eq_margin(ev.duration, SANYO_BIT_PULSE, SANYO_UNIT / 2))
+                       break;
+
+               data->state = STATE_BIT_SPACE;
+               return 0;
+
+       case STATE_BIT_SPACE:
+               if (ev.pulse)
+                       break;
+
+               if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
+                       if (!dev->keypressed) {
+                               IR_dprintk(1, "SANYO discarding last key repeat: event after key up\n");
+                       } else {
+                               rc_repeat(dev);
+                               IR_dprintk(1, "SANYO repeat last key\n");
+                               data->state = STATE_INACTIVE;
+                       }
+                       return 0;
+               }
+
+               data->bits <<= 1;
+               if (eq_margin(ev.duration, SANYO_BIT_1_SPACE, SANYO_UNIT / 2))
+                       data->bits |= 1;
+               else if (!eq_margin(ev.duration, SANYO_BIT_0_SPACE, SANYO_UNIT / 2))
+                       break;
+               data->count++;
+
+               if (data->count == SANYO_NBITS)
+                       data->state = STATE_TRAILER_PULSE;
+               else
+                       data->state = STATE_BIT_PULSE;
+
+               return 0;
+
+       case STATE_TRAILER_PULSE:
+               if (!ev.pulse)
+                       break;
+
+               if (!eq_margin(ev.duration, SANYO_TRAILER_PULSE, SANYO_UNIT / 2))
+                       break;
+
+               data->state = STATE_TRAILER_SPACE;
+               return 0;
+
+       case STATE_TRAILER_SPACE:
+               if (ev.pulse)
+                       break;
+
+               if (!geq_margin(ev.duration, SANYO_TRAILER_SPACE, SANYO_UNIT / 2))
+                       break;
+
+               address     = bitrev16((data->bits >> 29) & 0x1fff) >> 3;
+               not_address = bitrev16((data->bits >> 16) & 0x1fff) >> 3;
+               command     = bitrev8((data->bits >>  8) & 0xff);
+               not_command = bitrev8((data->bits >>  0) & 0xff);
+
+               if ((command ^ not_command) != 0xff) {
+                       IR_dprintk(1, "SANYO checksum error: received 0x%08Lx\n",
+                                  data->bits);
+                       data->state = STATE_INACTIVE;
+                       return 0;
+               }
+
+               scancode = address << 8 | command;
+               IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode);
+               rc_keydown(dev, scancode, 0);
+               data->state = STATE_INACTIVE;
+               return 0;
+       }
+
+       IR_dprintk(1, "SANYO decode failed at count %d state %d (%uus %s)\n",
+                  data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+       data->state = STATE_INACTIVE;
+       return -EINVAL;
+}
+
+static struct ir_raw_handler sanyo_handler = {
+       .protocols      = RC_TYPE_SANYO,
+       .decode         = ir_sanyo_decode,
+};
+
+static int __init ir_sanyo_decode_init(void)
+{
+       ir_raw_handler_register(&sanyo_handler);
+
+       printk(KERN_INFO "IR SANYO protocol handler initialized\n");
+       return 0;
+}
+
+static void __exit ir_sanyo_decode_exit(void)
+{
+       ir_raw_handler_unregister(&sanyo_handler);
+}
+
+module_init(ir_sanyo_decode_init);
+module_exit(ir_sanyo_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("SANYO IR protocol decoder");
index e51c6163378b5e0bece020e4a615da5b0095640c..929bbbc163931ca9e9883b471d293754d0f75e33 100644 (file)
@@ -182,6 +182,57 @@ static struct rc_map_table rc5_hauppauge_new[] = {
        { 0x1d3d, KEY_POWER },
        { 0x1d3f, KEY_HOME },
 
+       /*
+        * Keycodes for PT# R-005 remote bundled with Haupauge HVR-930C
+        * Keycodes start with address = 0x1c
+        */
+       { 0x1c3b, KEY_GOTO },
+       { 0x1c3d, KEY_POWER },
+
+       { 0x1c14, KEY_UP },
+       { 0x1c15, KEY_DOWN },
+       { 0x1c16, KEY_LEFT },
+       { 0x1c17, KEY_RIGHT },
+       { 0x1c25, KEY_OK },
+
+       { 0x1c00, KEY_0 },
+       { 0x1c01, KEY_1 },
+       { 0x1c02, KEY_2 },
+       { 0x1c03, KEY_3 },
+       { 0x1c04, KEY_4 },
+       { 0x1c05, KEY_5 },
+       { 0x1c06, KEY_6 },
+       { 0x1c07, KEY_7 },
+       { 0x1c08, KEY_8 },
+       { 0x1c09, KEY_9 },
+
+       { 0x1c1f, KEY_EXIT },   /* BACK */
+       { 0x1c0d, KEY_MENU },
+       { 0x1c1c, KEY_TV },
+
+       { 0x1c10, KEY_VOLUMEUP },
+       { 0x1c11, KEY_VOLUMEDOWN },
+
+       { 0x1c20, KEY_CHANNELUP },
+       { 0x1c21, KEY_CHANNELDOWN },
+
+       { 0x1c0f, KEY_MUTE },
+       { 0x1c12, KEY_PREVIOUS }, /* Prev */
+
+       { 0x1c36, KEY_STOP },
+       { 0x1c37, KEY_RECORD },
+
+       { 0x1c24, KEY_LAST },           /* <|             */
+       { 0x1c1e, KEY_NEXT },           /* >|             */
+
+       { 0x1c0a, KEY_TEXT },
+       { 0x1c0e, KEY_SUBTITLE },       /* CC */
+
+       { 0x1c32, KEY_REWIND },
+       { 0x1c30, KEY_PAUSE },
+       { 0x1c35, KEY_PLAY },
+       { 0x1c34, KEY_FASTFORWARD },
+
        /*
         * Keycodes for the old Black Remote Controller
         * This one also uses RC-5 protocol
index 3bd1de1f585c198d54c73ae16b018c6471ce8e35..23ee05e539498ebd6d87e7fc515f2f75fc109ecf 100644 (file)
@@ -1,4 +1,4 @@
-/* videomate-m1f.h - Keytable for videomate_m1f Remote Controller
+/* videomate-k100.h - Keytable for videomate_k100 Remote Controller
  *
  * keymap imported from ir-keymaps.c
  *
@@ -13,7 +13,7 @@
 #include <media/rc-map.h>
 #include <linux/module.h>
 
-static struct rc_map_table videomate_m1f[] = {
+static struct rc_map_table videomate_k100[] = {
        { 0x01, KEY_POWER },
        { 0x31, KEY_TUNER },
        { 0x33, KEY_VIDEO },
@@ -67,27 +67,27 @@ static struct rc_map_table videomate_m1f[] = {
        { 0x18, KEY_TEXT },
 };
 
-static struct rc_map_list videomate_m1f_map = {
+static struct rc_map_list videomate_k100_map = {
        .map = {
-               .scan    = videomate_m1f,
-               .size    = ARRAY_SIZE(videomate_m1f),
+               .scan    = videomate_k100,
+               .size    = ARRAY_SIZE(videomate_k100),
                .rc_type = RC_TYPE_UNKNOWN,     /* Legacy IR type */
-               .name    = RC_MAP_VIDEOMATE_M1F,
+               .name    = RC_MAP_VIDEOMATE_K100,
        }
 };
 
-static int __init init_rc_map_videomate_m1f(void)
+static int __init init_rc_map_videomate_k100(void)
 {
-       return rc_map_register(&videomate_m1f_map);
+       return rc_map_register(&videomate_k100_map);
 }
 
-static void __exit exit_rc_map_videomate_m1f(void)
+static void __exit exit_rc_map_videomate_k100(void)
 {
-       rc_map_unregister(&videomate_m1f_map);
+       rc_map_unregister(&videomate_k100_map);
 }
 
-module_init(init_rc_map_videomate_m1f)
-module_exit(exit_rc_map_videomate_m1f)
+module_init(init_rc_map_videomate_k100)
+module_exit(exit_rc_map_videomate_k100)
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Pavel Osnova <pvosnova@gmail.com>");
index 27997a9ceb0d4552944bbbb6605bfc711ad9d9ea..ca12d3289bfe90a886da3e25ef5c40c9a2a6452f 100644 (file)
@@ -38,7 +38,7 @@
 #include <media/lirc.h>
 #include <media/lirc_dev.h>
 
-static int debug;
+static bool debug;
 
 #define IRCTL_DEV_NAME "BaseRemoteCtl"
 #define NOPLUG         -1
index 20bb12d6fbbea9b48956b8fc31a802db157f0aa0..21105bf9594d37d40842b4874c372c0ecf1bc510 100644 (file)
 
 /* module parameters */
 #ifdef CONFIG_USB_DEBUG
-static int debug = 1;
+static bool debug = 1;
 #else
-static int debug;
+static bool debug;
 #endif
 
 #define mce_dbg(dev, fmt, ...)                                 \
index c6ca870e8b7eb1e2a112b8da1670cd896ed12e1d..b72f8580e3170ba14b629cab0e0ae88d9d83095f 100644 (file)
@@ -84,6 +84,11 @@ struct ir_raw_event_ctrl {
                unsigned count;
                unsigned wanted_bits;
        } rc5_sz;
+       struct sanyo_dec {
+               int state;
+               unsigned count;
+               u64 bits;
+       } sanyo;
        struct mce_kbd_dec {
                struct input_dev *idev;
                struct timer_list rx_timeout;
@@ -193,6 +198,13 @@ static inline void load_jvc_decode(void) { }
 static inline void load_sony_decode(void) { }
 #endif
 
+/* from ir-sanyo-decoder.c */
+#ifdef CONFIG_IR_SANYO_DECODER_MODULE
+#define load_sanyo_decode()    request_module("ir-sanyo-decoder")
+#else
+static inline void load_sanyo_decode(void) { }
+#endif
+
 /* from ir-mce_kbd-decoder.c */
 #ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE
 #define load_mce_kbd_decode()  request_module("ir-mce_kbd-decoder")
index f5db8b949bc3907f0367d7771724190529f81e29..f6a930b70c69586f67d3ac64ec0227c1afa1e623 100644 (file)
@@ -736,6 +736,7 @@ static struct {
        { RC_TYPE_JVC,          "jvc"           },
        { RC_TYPE_SONY,         "sony"          },
        { RC_TYPE_RC5_SZ,       "rc-5-sz"       },
+       { RC_TYPE_SANYO,        "sanyo"         },
        { RC_TYPE_MCE_KBD,      "mce_kbd"       },
        { RC_TYPE_LIRC,         "lirc"          },
        { RC_TYPE_OTHER,        "other"         },
index 07322fb75eff5a42921584dbac8bc0dc8408ae1f..ad95c67a4dbafacbbd227f81cd703372dd9dc3cc 100644 (file)
@@ -286,12 +286,6 @@ static void redrat3_issue_async(struct redrat3_dev *rr3)
 
        rr3_ftr(rr3->dev, "Entering %s\n", __func__);
 
-       if (!rr3->det_enabled) {
-               dev_warn(rr3->dev, "not issuing async read, "
-                        "detector not enabled\n");
-               return;
-       }
-
        memset(rr3->bulk_in_buf, 0, rr3->ep_in->wMaxPacketSize);
        res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC);
        if (res)
@@ -827,6 +821,7 @@ out:
 static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs)
 {
        struct redrat3_dev *rr3;
+       int ret;
 
        if (!urb)
                return;
@@ -840,15 +835,13 @@ static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs)
 
        rr3_ftr(rr3->dev, "Entering %s\n", __func__);
 
-       if (!rr3->det_enabled) {
-               rr3_dbg(rr3->dev, "received a read callback but detector "
-                       "disabled - ignoring\n");
-               return;
-       }
-
        switch (urb->status) {
        case 0:
-               redrat3_get_ir_data(rr3, urb->actual_length);
+               ret = redrat3_get_ir_data(rr3, urb->actual_length);
+               if (!ret) {
+                       /* no error, prepare to read more */
+                       redrat3_issue_async(rr3);
+               }
                break;
 
        case -ECONNRESET:
@@ -865,11 +858,6 @@ static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs)
                rr3->pkttype = 0;
                break;
        }
-
-       if (!rr3->transmitting)
-               redrat3_issue_async(rr3);
-       else
-               rr3_dbg(rr3->dev, "IR transmit in progress\n");
 }
 
 static void redrat3_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
@@ -896,21 +884,24 @@ static u16 mod_freq_to_val(unsigned int mod_freq)
        return (u16)(65536 - (mult / mod_freq));
 }
 
-static int redrat3_set_tx_carrier(struct rc_dev *dev, u32 carrier)
+static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier)
 {
-       struct redrat3_dev *rr3 = dev->priv;
+       struct redrat3_dev *rr3 = rcdev->priv;
+       struct device *dev = rr3->dev;
 
+       rr3_dbg(dev, "Setting modulation frequency to %u", carrier);
        rr3->carrier = carrier;
 
        return carrier;
 }
 
-static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
+static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
+                               unsigned count)
 {
        struct redrat3_dev *rr3 = rcdev->priv;
        struct device *dev = rr3->dev;
        struct redrat3_signal_header header;
-       int i, j, count, ret, ret_len, offset;
+       int i, j, ret, ret_len, offset;
        int lencheck, cur_sample_len, pipe;
        char *buffer = NULL, *sigdata = NULL;
        int *sample_lens = NULL;
@@ -928,20 +919,13 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
                return -EAGAIN;
        }
 
-       count = n / sizeof(int);
        if (count > (RR3_DRIVER_MAXLENS * 2))
                return -EINVAL;
 
+       /* rr3 will disable rc detector on transmit */
+       rr3->det_enabled = false;
        rr3->transmitting = true;
 
-       redrat3_disable_detector(rr3);
-
-       if (rr3->det_enabled) {
-               dev_err(dev, "%s: cannot tx while rx is enabled\n", __func__);
-               ret = -EIO;
-               goto out;
-       }
-
        sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL);
        if (!sample_lens) {
                ret = -ENOMEM;
@@ -1055,7 +1039,7 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
        if (ret < 0)
                dev_err(dev, "Error: control msg send failed, rc %d\n", ret);
        else
-               ret = n;
+               ret = count;
 
 out:
        kfree(sample_lens);
@@ -1063,8 +1047,8 @@ out:
        kfree(sigdata);
 
        rr3->transmitting = false;
-
-       redrat3_enable_detector(rr3);
+       /* rr3 re-enables rc detector because it was enabled before */
+       rr3->det_enabled = true;
 
        return ret;
 }
index b1d29d09eeae77fd2fde0c055fc2ef7b09ff4e4a..d6f4bfe09391e92b68981499d99bb2e076060b98 100644 (file)
@@ -43,9 +43,9 @@
 #define DRIVER_DESC    "Streamzap Remote Control driver"
 
 #ifdef CONFIG_USB_DEBUG
-static int debug = 1;
+static bool debug = 1;
 #else
-static int debug;
+static bool debug;
 #endif
 
 #define USB_STREAMZAP_VENDOR_ID                0x0e9c
index e7f7a57bf6845347e50c3ed2975c67f15c2e05ec..b09c5fae489bd020ea4748cd9c33d67dc12568b0 100644 (file)
@@ -226,11 +226,11 @@ module_param(protocol, uint, 0444);
 MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command "
                 "(0 = RC5, 1 = NEC, 2 = RC6A, default)");
 
-static int invert; /* default = 0 */
+static bool invert; /* default = 0 */
 module_param(invert, bool, 0444);
 MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver");
 
-static int txandrx; /* default = 0 */
+static bool txandrx; /* default = 0 */
 module_param(txandrx, bool, 0444);
 MODULE_PARM_DESC(invert, "Allow simultaneous TX and RX");
 
index b303a3f8a9f8ac776f83511740e52d91e36095e4..9adada0d7447ba60758a7852c2f1b05829e8411e 100644 (file)
@@ -533,6 +533,13 @@ config VIDEO_ADP1653
          This is a driver for the ADP1653 flash controller. It is used for
          example in Nokia N900.
 
+config VIDEO_AS3645A
+       tristate "AS3645A flash driver support"
+       depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER
+       ---help---
+         This is a driver for the AS3645A and LM3555 flash controllers. It has
+         build in control for flash, torch and indicator LEDs.
+
 comment "Video improvement chips"
 
 config VIDEO_UPD64031A
@@ -580,25 +587,6 @@ config VIDEO_M52790
 
 endmenu # encoder / decoder chips
 
-config VIDEO_SH_VOU
-       tristate "SuperH VOU video output driver"
-       depends on VIDEO_DEV && ARCH_SHMOBILE
-       select VIDEOBUF_DMA_CONTIG
-       help
-         Support for the Video Output Unit (VOU) on SuperH SoCs.
-
-config VIDEO_VIU
-       tristate "Freescale VIU Video Driver"
-       depends on VIDEO_V4L2 && PPC_MPC512x
-       select VIDEOBUF_DMA_CONTIG
-       default y
-       ---help---
-         Support for Freescale VIU video driver. This device captures
-         video data, or overlays video on DIU frame buffer.
-
-         Say Y here if you want to enable VIU device on MPC5121e Rev2+.
-         In doubt, say N.
-
 config VIDEO_VIVI
        tristate "Virtual Video Driver"
        depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
@@ -613,66 +601,130 @@ config VIDEO_VIVI
          Say Y here if you want to test video apps or debug V4L devices.
          In doubt, say N.
 
-source "drivers/media/video/davinci/Kconfig"
+#
+# USB Multimedia device configuration
+#
 
-source "drivers/media/video/omap/Kconfig"
+menuconfig V4L_USB_DRIVERS
+       bool "V4L USB devices"
+       depends on USB
+       default y
 
-source "drivers/media/video/bt8xx/Kconfig"
+if V4L_USB_DRIVERS
 
-config VIDEO_PMS
-       tristate "Mediavision Pro Movie Studio Video For Linux"
-       depends on ISA && VIDEO_V4L2
-       help
-         Say Y if you have such a thing.
+source "drivers/media/video/uvc/Kconfig"
+
+source "drivers/media/video/gspca/Kconfig"
+
+source "drivers/media/video/pvrusb2/Kconfig"
+
+source "drivers/media/video/hdpvr/Kconfig"
+
+source "drivers/media/video/em28xx/Kconfig"
+
+source "drivers/media/video/tlg2300/Kconfig"
+
+source "drivers/media/video/cx231xx/Kconfig"
+
+source "drivers/media/video/tm6000/Kconfig"
+
+source "drivers/media/video/usbvision/Kconfig"
+
+source "drivers/media/video/et61x251/Kconfig"
+
+source "drivers/media/video/sn9c102/Kconfig"
+
+source "drivers/media/video/pwc/Kconfig"
+
+source "drivers/media/video/cpia2/Kconfig"
+
+config USB_ZR364XX
+       tristate "USB ZR364XX Camera support"
+       depends on VIDEO_V4L2
+       select VIDEOBUF_GEN
+       select VIDEOBUF_VMALLOC
+       ---help---
+         Say Y here if you want to connect this type of camera to your
+         computer's USB port.
+         See <file:Documentation/video4linux/zr364xx.txt> for more info
+         and list of supported cameras.
 
          To compile this driver as a module, choose M here: the
-         module will be called pms.
+         module will be called zr364xx.
 
-config VIDEO_BWQCAM
-       tristate "Quickcam BW Video For Linux"
-       depends on PARPORT && VIDEO_V4L2
-       help
-         Say Y have if you the black and white version of the QuickCam
-         camera. See the next option for the color version.
+config USB_STKWEBCAM
+       tristate "USB Syntek DC1125 Camera support"
+       depends on VIDEO_V4L2 && EXPERIMENTAL
+       ---help---
+         Say Y here if you want to use this type of camera.
+         Supported devices are typically found in some Asus laptops,
+         with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
+         may be supported by the stk11xx driver, from which this is
+         derived, see <http://sourceforge.net/projects/syntekdriver/>
 
          To compile this driver as a module, choose M here: the
-         module will be called bw-qcam.
+         module will be called stkwebcam.
 
-config VIDEO_CQCAM
-       tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && PARPORT && VIDEO_V4L2
+config USB_S2255
+       tristate "USB Sensoray 2255 video capture device"
+       depends on VIDEO_V4L2
+       select VIDEOBUF_VMALLOC
+       default n
        help
-         This is the video4linux driver for the colour version of the
-         Connectix QuickCam.  If you have one of these cameras, say Y here,
-         otherwise say N.  This driver does not work with the original
-         monochrome QuickCam, QuickCam VC or QuickClip.  It is also available
-         as a module (c-qcam).
-         Read <file:Documentation/video4linux/CQcam.txt> for more information.
+         Say Y here if you want support for the Sensoray 2255 USB device.
+         This driver can be compiled as a module, called s2255drv.
 
-config VIDEO_W9966
-       tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux"
-       depends on PARPORT_1284 && PARPORT && VIDEO_V4L2
-       help
-         Video4linux driver for Winbond's w9966 based Webcams.
-         Currently tested with the LifeView FlyCam Supra.
-         If you have one of these cameras, say Y here
-         otherwise say N.
-         This driver is also available as a module (w9966).
+endif # V4L_USB_DRIVERS
 
-         Check out <file:Documentation/video4linux/w9966.txt> for more
-         information.
+#
+# PCI drivers configuration
+#
 
-source "drivers/media/video/cpia2/Kconfig"
+menuconfig V4L_PCI_DRIVERS
+       bool "V4L PCI(e) devices"
+       depends on PCI
+       default y
+       ---help---
+         Say Y here to enable support for these PCI(e) drivers.
 
-config VIDEO_VINO
-       tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
-       depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
-       select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO
-       help
-         Say Y here to build in support for the Vino video input system found
-         on SGI Indy machines.
+if V4L_PCI_DRIVERS
 
-source "drivers/media/video/zoran/Kconfig"
+source "drivers/media/video/au0828/Kconfig"
+
+source "drivers/media/video/bt8xx/Kconfig"
+
+source "drivers/media/video/cx18/Kconfig"
+
+source "drivers/media/video/cx23885/Kconfig"
+
+source "drivers/media/video/cx25821/Kconfig"
+
+source "drivers/media/video/cx88/Kconfig"
+
+config VIDEO_HEXIUM_GEMINI
+       tristate "Hexium Gemini frame grabber"
+       depends on PCI && VIDEO_V4L2 && I2C
+       select VIDEO_SAA7146_VV
+       ---help---
+         This is a video4linux driver for the Hexium Gemini frame
+         grabber card by Hexium. Please note that the Gemini Dual
+         card is *not* fully supported.
+
+         To compile this driver as a module, choose M here: the
+         module will be called hexium_gemini.
+
+config VIDEO_HEXIUM_ORION
+       tristate "Hexium HV-PCI6 and Orion frame grabber"
+       depends on PCI && VIDEO_V4L2 && I2C
+       select VIDEO_SAA7146_VV
+       ---help---
+         This is a video4linux driver for the Hexium HV-PCI6 and
+         Orion frame grabber cards by Hexium.
+
+         To compile this driver as a module, choose M here: the
+         module will be called hexium_orion.
+
+source "drivers/media/video/ivtv/Kconfig"
 
 config VIDEO_MEYE
        tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
@@ -688,8 +740,6 @@ config VIDEO_MEYE
          To compile this driver as a module, choose M here: the
          module will be called meye.
 
-source "drivers/media/video/saa7134/Kconfig"
-
 config VIDEO_MXB
        tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
        depends on PCI && VIDEO_V4L2 && I2C
@@ -706,28 +756,119 @@ config VIDEO_MXB
          To compile this driver as a module, choose M here: the
          module will be called mxb.
 
-config VIDEO_HEXIUM_ORION
-       tristate "Hexium HV-PCI6 and Orion frame grabber"
-       depends on PCI && VIDEO_V4L2 && I2C
-       select VIDEO_SAA7146_VV
+source "drivers/media/video/saa7134/Kconfig"
+
+source "drivers/media/video/saa7164/Kconfig"
+
+source "drivers/media/video/zoran/Kconfig"
+
+endif # V4L_PCI_DRIVERS
+
+#
+# ISA & parallel port drivers configuration
+#
+
+menuconfig V4L_ISA_PARPORT_DRIVERS
+       bool "V4L ISA and parallel port devices"
+       depends on ISA || PARPORT
+       default n
        ---help---
-         This is a video4linux driver for the Hexium HV-PCI6 and
-         Orion frame grabber cards by Hexium.
+         Say Y here to enable support for these ISA and parallel port drivers.
+
+if V4L_ISA_PARPORT_DRIVERS
+
+config VIDEO_BWQCAM
+       tristate "Quickcam BW Video For Linux"
+       depends on PARPORT && VIDEO_V4L2
+       help
+         Say Y have if you the black and white version of the QuickCam
+         camera. See the next option for the color version.
 
          To compile this driver as a module, choose M here: the
-         module will be called hexium_orion.
+         module will be called bw-qcam.
 
-config VIDEO_HEXIUM_GEMINI
-       tristate "Hexium Gemini frame grabber"
-       depends on PCI && VIDEO_V4L2 && I2C
-       select VIDEO_SAA7146_VV
-       ---help---
-         This is a video4linux driver for the Hexium Gemini frame
-         grabber card by Hexium. Please note that the Gemini Dual
-         card is *not* fully supported.
+config VIDEO_CQCAM
+       tristate "QuickCam Colour Video For Linux"
+       depends on PARPORT && VIDEO_V4L2
+       help
+         This is the video4linux driver for the colour version of the
+         Connectix QuickCam.  If you have one of these cameras, say Y here,
+         otherwise say N.  This driver does not work with the original
+         monochrome QuickCam, QuickCam VC or QuickClip.  It is also available
+         as a module (c-qcam).
+         Read <file:Documentation/video4linux/CQcam.txt> for more information.
+
+config VIDEO_PMS
+       tristate "Mediavision Pro Movie Studio Video For Linux"
+       depends on ISA && VIDEO_V4L2
+       help
+         Say Y if you have the ISA Mediavision Pro Movie Studio
+         capture card.
 
          To compile this driver as a module, choose M here: the
-         module will be called hexium_gemini.
+         module will be called pms.
+
+config VIDEO_W9966
+       tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux"
+       depends on PARPORT_1284 && PARPORT && VIDEO_V4L2
+       help
+         Video4linux driver for Winbond's w9966 based Webcams.
+         Currently tested with the LifeView FlyCam Supra.
+         If you have one of these cameras, say Y here
+         otherwise say N.
+         This driver is also available as a module (w9966).
+
+         Check out <file:Documentation/video4linux/w9966.txt> for more
+         information.
+
+endif # V4L_ISA_PARPORT_DRIVERS
+
+menuconfig V4L_PLATFORM_DRIVERS
+       bool "V4L platform devices"
+       default n
+       ---help---
+         Say Y here to enable support for platform-specific V4L drivers.
+
+if V4L_PLATFORM_DRIVERS
+
+source "drivers/media/video/marvell-ccic/Kconfig"
+
+config VIDEO_VIA_CAMERA
+       tristate "VIAFB camera controller support"
+       depends on FB_VIA
+       select VIDEOBUF_DMA_SG
+       select VIDEO_OV7670
+       help
+          Driver support for the integrated camera controller in VIA
+          Chrome9 chipsets.  Currently only tested on OLPC xo-1.5 systems
+          with ov7670 sensors.
+
+#
+# Platform multimedia device configuration
+#
+
+source "drivers/media/video/davinci/Kconfig"
+
+source "drivers/media/video/omap/Kconfig"
+
+config VIDEO_SH_VOU
+       tristate "SuperH VOU video output driver"
+       depends on VIDEO_DEV && ARCH_SHMOBILE
+       select VIDEOBUF_DMA_CONTIG
+       help
+         Support for the Video Output Unit (VOU) on SuperH SoCs.
+
+config VIDEO_VIU
+       tristate "Freescale VIU Video Driver"
+       depends on VIDEO_V4L2 && PPC_MPC512x
+       select VIDEOBUF_DMA_CONTIG
+       default y
+       ---help---
+         Support for Freescale VIU video driver. This device captures
+         video data, or overlays video on DIU frame buffer.
+
+         Say Y here if you want to enable VIU device on MPC5121e Rev2+.
+         In doubt, say N.
 
 config VIDEO_TIMBERDALE
        tristate "Support for timberdale Video In/LogiWIN"
@@ -739,21 +880,13 @@ config VIDEO_TIMBERDALE
        ---help---
          Add support for the Video In peripherial of the timberdale FPGA.
 
-source "drivers/media/video/cx88/Kconfig"
-
-source "drivers/media/video/cx23885/Kconfig"
-
-source "drivers/media/video/cx25821/Kconfig"
-
-source "drivers/media/video/au0828/Kconfig"
-
-source "drivers/media/video/ivtv/Kconfig"
-
-source "drivers/media/video/cx18/Kconfig"
-
-source "drivers/media/video/saa7164/Kconfig"
-
-source "drivers/media/video/marvell-ccic/Kconfig"
+config VIDEO_VINO
+       tristate "SGI Vino Video For Linux"
+       depends on I2C && SGI_IP22 && VIDEO_V4L2
+       select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO
+       help
+         Say Y here to build in support for the Vino video input system found
+         on SGI Indy machines.
 
 config VIDEO_M32R_AR
        tristate "AR devices"
@@ -774,16 +907,6 @@ config VIDEO_M32R_AR_M64278
          To compile this driver as a module, choose M here: the
          module will be called arv.
 
-config VIDEO_VIA_CAMERA
-       tristate "VIAFB camera controller support"
-       depends on FB_VIA
-       select VIDEOBUF_DMA_SG
-       select VIDEO_OV7670
-       help
-          Driver support for the integrated camera controller in VIA
-          Chrome9 chipsets.  Currently only tested on OLPC xo-1.5 systems
-          with ov7670 sensors.
-
 config VIDEO_OMAP3
        tristate "OMAP 3 Camera support (EXPERIMENTAL)"
        depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL
@@ -1002,78 +1125,7 @@ config VIDEO_S5P_MIPI_CSIS
 
 source "drivers/media/video/s5p-tv/Kconfig"
 
-#
-# USB Multimedia device configuration
-#
-
-menuconfig V4L_USB_DRIVERS
-       bool "V4L USB devices"
-       depends on USB
-       default y
-
-if V4L_USB_DRIVERS && USB
-
-source "drivers/media/video/uvc/Kconfig"
-
-source "drivers/media/video/gspca/Kconfig"
-
-source "drivers/media/video/pvrusb2/Kconfig"
-
-source "drivers/media/video/hdpvr/Kconfig"
-
-source "drivers/media/video/em28xx/Kconfig"
-
-source "drivers/media/video/tlg2300/Kconfig"
-
-source "drivers/media/video/cx231xx/Kconfig"
-
-source "drivers/media/video/tm6000/Kconfig"
-
-source "drivers/media/video/usbvision/Kconfig"
-
-source "drivers/media/video/et61x251/Kconfig"
-
-source "drivers/media/video/sn9c102/Kconfig"
-
-source "drivers/media/video/pwc/Kconfig"
-
-config USB_ZR364XX
-       tristate "USB ZR364XX Camera support"
-       depends on VIDEO_V4L2
-       select VIDEOBUF_GEN
-       select VIDEOBUF_VMALLOC
-       ---help---
-         Say Y here if you want to connect this type of camera to your
-         computer's USB port.
-         See <file:Documentation/video4linux/zr364xx.txt> for more info
-         and list of supported cameras.
-
-         To compile this driver as a module, choose M here: the
-         module will be called zr364xx.
-
-config USB_STKWEBCAM
-       tristate "USB Syntek DC1125 Camera support"
-       depends on VIDEO_V4L2 && EXPERIMENTAL
-       ---help---
-         Say Y here if you want to use this type of camera.
-         Supported devices are typically found in some Asus laptops,
-         with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
-         may be supported by the stk11xx driver, from which this is
-         derived, see <http://sourceforge.net/projects/syntekdriver/>
-
-         To compile this driver as a module, choose M here: the
-         module will be called stkwebcam.
-
-config USB_S2255
-       tristate "USB Sensoray 2255 video capture device"
-       depends on VIDEO_V4L2
-       select VIDEOBUF_VMALLOC
-       default n
-       help
-         Say Y here if you want support for the Sensoray 2255 USB device.
-         This driver can be compiled as a module, called s2255drv.
-
-endif # V4L_USB_DRIVERS
+endif # V4L_PLATFORM_DRIVERS
 endif # VIDEO_CAPTURE_DRIVERS
 
 menuconfig V4L_MEM2MEM_DRIVERS
@@ -1098,6 +1150,23 @@ config VIDEO_MEM2MEM_TESTDEV
          This is a virtual test device for the memory-to-memory driver
          framework.
 
+config VIDEO_SAMSUNG_S5P_G2D
+       tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver"
+       depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
+       select VIDEOBUF2_DMA_CONTIG
+       select V4L2_MEM2MEM_DEV
+       default n
+       ---help---
+         This is a v4l2 driver for Samsung S5P and EXYNOS4 G2D
+         2d graphics accelerator.
+
+config VIDEO_SAMSUNG_S5P_JPEG
+       tristate "Samsung S5P/Exynos4 JPEG codec driver (EXPERIMENTAL)"
+       depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P && EXPERIMENTAL
+       select VIDEOBUF2_DMA_CONTIG
+       select V4L2_MEM2MEM_DEV
+       ---help---
+         This is a v4l2 driver for Samsung S5P and EXYNOS4 JPEG codec
 
 config VIDEO_SAMSUNG_S5P_MFC
        tristate "Samsung S5P MFC 5.1 Video Codec"
index 117f9c4b4cb9a9d804f96f7d80c2a125d857fb44..354138804cdad917e9b858f9724e5fe57f39b4f1 100644 (file)
@@ -74,6 +74,7 @@ obj-$(CONFIG_VIDEO_NOON010PC30)       += noon010pc30.o
 obj-$(CONFIG_VIDEO_M5MOLS)     += m5mols/
 obj-$(CONFIG_VIDEO_S5K6AA)     += s5k6aa.o
 obj-$(CONFIG_VIDEO_ADP1653)    += adp1653.o
+obj-$(CONFIG_VIDEO_AS3645A)    += as3645a.o
 
 obj-$(CONFIG_SOC_CAMERA_IMX074)                += imx074.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
@@ -177,9 +178,12 @@ obj-$(CONFIG_VIDEO_OMAP1)          += omap1_camera.o
 obj-$(CONFIG_VIDEO_ATMEL_ISI)          += atmel-isi.o
 
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC)   += s5p-fimc/
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG)   += s5p-jpeg/
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC)    += s5p-mfc/
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV)     += s5p-tv/
 
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D)    += s5p-g2d/
+
 obj-$(CONFIG_ARCH_DAVINCI)             += davinci/
 
 obj-$(CONFIG_VIDEO_SH_VOU)             += sh_vou.o
index 23ba5c37c3e4d493bd243ddf444404fd43cd01e3..879f1d839760a5588376358c81128ededa8cee81 100644 (file)
@@ -64,6 +64,11 @@ static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd)
 
 static char *inputs[] = { "pass_through", "play_back" };
 
+static enum v4l2_mbus_pixelcode adv7170_codes[] = {
+       V4L2_MBUS_FMT_UYVY8_2X8,
+       V4L2_MBUS_FMT_UYVY8_1X16,
+};
+
 /* ----------------------------------------------------------------------- */
 
 static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value)
@@ -258,6 +263,60 @@ static int adv7170_s_routing(struct v4l2_subdev *sd,
        return 0;
 }
 
+static int adv7170_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+                               enum v4l2_mbus_pixelcode *code)
+{
+       if (index >= ARRAY_SIZE(adv7170_codes))
+               return -EINVAL;
+
+       *code = adv7170_codes[index];
+       return 0;
+}
+
+static int adv7170_g_fmt(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_framefmt *mf)
+{
+       u8 val = adv7170_read(sd, 0x7);
+
+       if ((val & 0x40) == (1 << 6))
+               mf->code = V4L2_MBUS_FMT_UYVY8_1X16;
+       else
+               mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+
+       mf->colorspace  = V4L2_COLORSPACE_SMPTE170M;
+       mf->width       = 0;
+       mf->height      = 0;
+       mf->field       = V4L2_FIELD_ANY;
+
+       return 0;
+}
+
+static int adv7170_s_fmt(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_framefmt *mf)
+{
+       u8 val = adv7170_read(sd, 0x7);
+       int ret;
+
+       switch (mf->code) {
+       case V4L2_MBUS_FMT_UYVY8_2X8:
+               val &= ~0x40;
+               break;
+
+       case V4L2_MBUS_FMT_UYVY8_1X16:
+               val |= 0x40;
+               break;
+
+       default:
+               v4l2_dbg(1, debug, sd,
+                       "illegal v4l2_mbus_framefmt code: %d\n", mf->code);
+               return -EINVAL;
+       }
+
+       ret = adv7170_write(sd, 0x7, val);
+
+       return ret;
+}
+
 static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -274,6 +333,9 @@ static const struct v4l2_subdev_core_ops adv7170_core_ops = {
 static const struct v4l2_subdev_video_ops adv7170_video_ops = {
        .s_std_output = adv7170_s_std_output,
        .s_routing = adv7170_s_routing,
+       .s_mbus_fmt = adv7170_s_fmt,
+       .g_mbus_fmt = adv7170_g_fmt,
+       .enum_mbus_fmt  = adv7170_enum_fmt,
 };
 
 static const struct v4l2_subdev_ops adv7170_ops = {
diff --git a/drivers/media/video/as3645a.c b/drivers/media/video/as3645a.c
new file mode 100644 (file)
index 0000000..f241702
--- /dev/null
@@ -0,0 +1,905 @@
+/*
+ * drivers/media/video/as3645a.c - AS3645A and LM3555 flash controllers driver
+ *
+ * Copyright (C) 2008-2011 Nokia Corporation
+ * Copyright (c) 2011, Intel Corporation.
+ *
+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * TODO:
+ * - Check hardware FSTROBE control when sensor driver add support for this
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <media/as3645a.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+#define AS_TIMER_MS_TO_CODE(t)                 (((t) - 100) / 50)
+#define AS_TIMER_CODE_TO_MS(c)                 (50 * (c) + 100)
+
+/* Register definitions */
+
+/* Read-only Design info register: Reset state: xxxx 0001 */
+#define AS_DESIGN_INFO_REG                     0x00
+#define AS_DESIGN_INFO_FACTORY(x)              (((x) >> 4))
+#define AS_DESIGN_INFO_MODEL(x)                        ((x) & 0x0f)
+
+/* Read-only Version control register: Reset state: 0000 0000
+ * for first engineering samples
+ */
+#define AS_VERSION_CONTROL_REG                 0x01
+#define AS_VERSION_CONTROL_RFU(x)              (((x) >> 4))
+#define AS_VERSION_CONTROL_VERSION(x)          ((x) & 0x0f)
+
+/* Read / Write        (Indicator and timer register): Reset state: 0000 1111 */
+#define AS_INDICATOR_AND_TIMER_REG             0x02
+#define AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT   0
+#define AS_INDICATOR_AND_TIMER_VREF_SHIFT      4
+#define AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT 6
+
+/* Read / Write        (Current set register): Reset state: 0110 1001 */
+#define AS_CURRENT_SET_REG                     0x03
+#define AS_CURRENT_ASSIST_LIGHT_SHIFT          0
+#define AS_CURRENT_LED_DET_ON                  (1 << 3)
+#define AS_CURRENT_FLASH_CURRENT_SHIFT         4
+
+/* Read / Write        (Control register): Reset state: 1011 0100 */
+#define AS_CONTROL_REG                         0x04
+#define AS_CONTROL_MODE_SETTING_SHIFT          0
+#define AS_CONTROL_STROBE_ON                   (1 << 2)
+#define AS_CONTROL_OUT_ON                      (1 << 3)
+#define AS_CONTROL_EXT_TORCH_ON                        (1 << 4)
+#define AS_CONTROL_STROBE_TYPE_EDGE            (0 << 5)
+#define AS_CONTROL_STROBE_TYPE_LEVEL           (1 << 5)
+#define AS_CONTROL_COIL_PEAK_SHIFT             6
+
+/* Read only (D3 is read / write) (Fault and info): Reset state: 0000 x000 */
+#define AS_FAULT_INFO_REG                      0x05
+#define AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT      (1 << 1)
+#define AS_FAULT_INFO_INDICATOR_LED            (1 << 2)
+#define AS_FAULT_INFO_LED_AMOUNT               (1 << 3)
+#define AS_FAULT_INFO_TIMEOUT                  (1 << 4)
+#define AS_FAULT_INFO_OVER_TEMPERATURE         (1 << 5)
+#define AS_FAULT_INFO_SHORT_CIRCUIT            (1 << 6)
+#define AS_FAULT_INFO_OVER_VOLTAGE             (1 << 7)
+
+/* Boost register */
+#define AS_BOOST_REG                           0x0d
+#define AS_BOOST_CURRENT_DISABLE               (0 << 0)
+#define AS_BOOST_CURRENT_ENABLE                        (1 << 0)
+
+/* Password register is used to unlock boost register writing */
+#define AS_PASSWORD_REG                                0x0f
+#define AS_PASSWORD_UNLOCK_VALUE               0x55
+
+enum as_mode {
+       AS_MODE_EXT_TORCH = 0 << AS_CONTROL_MODE_SETTING_SHIFT,
+       AS_MODE_INDICATOR = 1 << AS_CONTROL_MODE_SETTING_SHIFT,
+       AS_MODE_ASSIST = 2 << AS_CONTROL_MODE_SETTING_SHIFT,
+       AS_MODE_FLASH = 3 << AS_CONTROL_MODE_SETTING_SHIFT,
+};
+
+/*
+ * struct as3645a
+ *
+ * @subdev:            V4L2 subdev
+ * @pdata:             Flash platform data
+ * @power_lock:                Protects power_count
+ * @power_count:       Power reference count
+ * @led_mode:          V4L2 flash LED mode
+ * @timeout:           Flash timeout in microseconds
+ * @flash_current:     Flash current (0=200mA ... 15=500mA). Maximum
+ *                     values are 400mA for two LEDs and 500mA for one LED.
+ * @assist_current:    Torch/Assist light current (0=20mA, 1=40mA ... 7=160mA)
+ * @indicator_current: Indicator LED current (0=0mA, 1=2.5mA ... 4=10mA)
+ * @strobe_source:     Flash strobe source (software or external)
+ */
+struct as3645a {
+       struct v4l2_subdev subdev;
+       const struct as3645a_platform_data *pdata;
+
+       struct mutex power_lock;
+       int power_count;
+
+       /* Controls */
+       struct v4l2_ctrl_handler ctrls;
+
+       enum v4l2_flash_led_mode led_mode;
+       unsigned int timeout;
+       u8 flash_current;
+       u8 assist_current;
+       u8 indicator_current;
+       enum v4l2_flash_strobe_source strobe_source;
+};
+
+#define to_as3645a(sd) container_of(sd, struct as3645a, subdev)
+
+/* Return negative errno else zero on success */
+static int as3645a_write(struct as3645a *flash, u8 addr, u8 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       int rval;
+
+       rval = i2c_smbus_write_byte_data(client, addr, val);
+
+       dev_dbg(&client->dev, "Write Addr:%02X Val:%02X %s\n", addr, val,
+               rval < 0 ? "fail" : "ok");
+
+       return rval;
+}
+
+/* Return negative errno else a data byte received from the device. */
+static int as3645a_read(struct as3645a *flash, u8 addr)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       int rval;
+
+       rval = i2c_smbus_read_byte_data(client, addr);
+
+       dev_dbg(&client->dev, "Read Addr:%02X Val:%02X %s\n", addr, rval,
+               rval < 0 ? "fail" : "ok");
+
+       return rval;
+}
+
+/* -----------------------------------------------------------------------------
+ * Hardware configuration and trigger
+ */
+
+/*
+ * as3645a_set_config - Set flash configuration registers
+ * @flash: The flash
+ *
+ * Configure the hardware with flash, assist and indicator currents, as well as
+ * flash timeout.
+ *
+ * Return 0 on success, or a negative error code if an I2C communication error
+ * occurred.
+ */
+static int as3645a_set_config(struct as3645a *flash)
+{
+       int ret;
+       u8 val;
+
+       val = (flash->flash_current << AS_CURRENT_FLASH_CURRENT_SHIFT)
+           | (flash->assist_current << AS_CURRENT_ASSIST_LIGHT_SHIFT)
+           | AS_CURRENT_LED_DET_ON;
+
+       ret = as3645a_write(flash, AS_CURRENT_SET_REG, val);
+       if (ret < 0)
+               return ret;
+
+       val = AS_TIMER_MS_TO_CODE(flash->timeout / 1000)
+                   << AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT;
+
+       val |= (flash->pdata->vref << AS_INDICATOR_AND_TIMER_VREF_SHIFT)
+           |  ((flash->indicator_current ? flash->indicator_current - 1 : 0)
+                << AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT);
+
+       return as3645a_write(flash, AS_INDICATOR_AND_TIMER_REG, val);
+}
+
+/*
+ * as3645a_set_control - Set flash control register
+ * @flash: The flash
+ * @mode: Desired output mode
+ * @on: Desired output state
+ *
+ * Configure the hardware with output mode and state.
+ *
+ * Return 0 on success, or a negative error code if an I2C communication error
+ * occurred.
+ */
+static int
+as3645a_set_control(struct as3645a *flash, enum as_mode mode, bool on)
+{
+       u8 reg;
+
+       /* Configure output parameters and operation mode. */
+       reg = (flash->pdata->peak << AS_CONTROL_COIL_PEAK_SHIFT)
+           | (on ? AS_CONTROL_OUT_ON : 0)
+           | mode;
+
+       if (flash->led_mode == V4L2_FLASH_LED_MODE_FLASH &&
+           flash->strobe_source == V4L2_FLASH_STROBE_SOURCE_EXTERNAL) {
+               reg |= AS_CONTROL_STROBE_TYPE_LEVEL
+                   |  AS_CONTROL_STROBE_ON;
+       }
+
+       return as3645a_write(flash, AS_CONTROL_REG, reg);
+}
+
+/*
+ * as3645a_set_output - Configure output and operation mode
+ * @flash: Flash controller
+ * @strobe: Strobe the flash (only valid in flash mode)
+ *
+ * Turn the LEDs output on/off and set the operation mode based on the current
+ * parameters.
+ *
+ * The AS3645A can't control the indicator LED independently of the flash/torch
+ * LED. If the flash controller is in V4L2_FLASH_LED_MODE_NONE mode, set the
+ * chip to indicator mode. Otherwise set it to assist light (torch) or flash
+ * mode.
+ *
+ * In indicator and assist modes, turn the output on/off based on the indicator
+ * and torch currents. In software strobe flash mode, turn the output on/off
+ * based on the strobe parameter.
+ */
+static int as3645a_set_output(struct as3645a *flash, bool strobe)
+{
+       enum as_mode mode;
+       bool on;
+
+       switch (flash->led_mode) {
+       case V4L2_FLASH_LED_MODE_NONE:
+               on = flash->indicator_current != 0;
+               mode = AS_MODE_INDICATOR;
+               break;
+       case V4L2_FLASH_LED_MODE_TORCH:
+               on = true;
+               mode = AS_MODE_ASSIST;
+               break;
+       case V4L2_FLASH_LED_MODE_FLASH:
+               on = strobe;
+               mode = AS_MODE_FLASH;
+               break;
+       default:
+               BUG();
+       }
+
+       /* Configure output parameters and operation mode. */
+       return as3645a_set_control(flash, mode, on);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 controls
+ */
+
+static int as3645a_is_active(struct as3645a *flash)
+{
+       int ret;
+
+       ret = as3645a_read(flash, AS_CONTROL_REG);
+       return ret < 0 ? ret : !!(ret & AS_CONTROL_OUT_ON);
+}
+
+static int as3645a_read_fault(struct as3645a *flash)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       int rval;
+
+       /* NOTE: reading register clear fault status */
+       rval = as3645a_read(flash, AS_FAULT_INFO_REG);
+       if (rval < 0)
+               return rval;
+
+       if (rval & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT)
+               dev_dbg(&client->dev, "Inductor Peak limit fault\n");
+
+       if (rval & AS_FAULT_INFO_INDICATOR_LED)
+               dev_dbg(&client->dev, "Indicator LED fault: "
+                       "Short circuit or open loop\n");
+
+       dev_dbg(&client->dev, "%u connected LEDs\n",
+               rval & AS_FAULT_INFO_LED_AMOUNT ? 2 : 1);
+
+       if (rval & AS_FAULT_INFO_TIMEOUT)
+               dev_dbg(&client->dev, "Timeout fault\n");
+
+       if (rval & AS_FAULT_INFO_OVER_TEMPERATURE)
+               dev_dbg(&client->dev, "Over temperature fault\n");
+
+       if (rval & AS_FAULT_INFO_SHORT_CIRCUIT)
+               dev_dbg(&client->dev, "Short circuit fault\n");
+
+       if (rval & AS_FAULT_INFO_OVER_VOLTAGE)
+               dev_dbg(&client->dev, "Over voltage fault: "
+                       "Indicates missing capacitor or open connection\n");
+
+       return rval;
+}
+
+static int as3645a_get_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct as3645a *flash =
+               container_of(ctrl->handler, struct as3645a, ctrls);
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       int value;
+
+       switch (ctrl->id) {
+       case V4L2_CID_FLASH_FAULT:
+               value = as3645a_read_fault(flash);
+               if (value < 0)
+                       return value;
+
+               ctrl->cur.val = 0;
+               if (value & AS_FAULT_INFO_SHORT_CIRCUIT)
+                       ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
+               if (value & AS_FAULT_INFO_OVER_TEMPERATURE)
+                       ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
+               if (value & AS_FAULT_INFO_TIMEOUT)
+                       ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT;
+               if (value & AS_FAULT_INFO_OVER_VOLTAGE)
+                       ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
+               if (value & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT)
+                       ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_CURRENT;
+               if (value & AS_FAULT_INFO_INDICATOR_LED)
+                       ctrl->cur.val |= V4L2_FLASH_FAULT_INDICATOR;
+               break;
+
+       case V4L2_CID_FLASH_STROBE_STATUS:
+               if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) {
+                       ctrl->cur.val = 0;
+                       break;
+               }
+
+               value = as3645a_is_active(flash);
+               if (value < 0)
+                       return value;
+
+               ctrl->cur.val = value;
+               break;
+       }
+
+       dev_dbg(&client->dev, "G_CTRL %08x:%d\n", ctrl->id, ctrl->cur.val);
+
+       return 0;
+}
+
+static int as3645a_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct as3645a *flash =
+               container_of(ctrl->handler, struct as3645a, ctrls);
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       int ret;
+
+       dev_dbg(&client->dev, "S_CTRL %08x:%d\n", ctrl->id, ctrl->val);
+
+       /* If a control that doesn't apply to the current mode is modified,
+        * we store the value and return immediately. The setting will be
+        * applied when the LED mode is changed. Otherwise we apply the setting
+        * immediately.
+        */
+
+       switch (ctrl->id) {
+       case V4L2_CID_FLASH_LED_MODE:
+               if (flash->indicator_current)
+                       return -EBUSY;
+
+               ret = as3645a_set_config(flash);
+               if (ret < 0)
+                       return ret;
+
+               flash->led_mode = ctrl->val;
+               return as3645a_set_output(flash, false);
+
+       case V4L2_CID_FLASH_STROBE_SOURCE:
+               flash->strobe_source = ctrl->val;
+
+               /* Applies to flash mode only. */
+               if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+                       break;
+
+               return as3645a_set_output(flash, false);
+
+       case V4L2_CID_FLASH_STROBE:
+               if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+                       return -EBUSY;
+
+               return as3645a_set_output(flash, true);
+
+       case V4L2_CID_FLASH_STROBE_STOP:
+               if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+                       return -EBUSY;
+
+               return as3645a_set_output(flash, false);
+
+       case V4L2_CID_FLASH_TIMEOUT:
+               flash->timeout = ctrl->val;
+
+               /* Applies to flash mode only. */
+               if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+                       break;
+
+               return as3645a_set_config(flash);
+
+       case V4L2_CID_FLASH_INTENSITY:
+               flash->flash_current = (ctrl->val - AS3645A_FLASH_INTENSITY_MIN)
+                                    / AS3645A_FLASH_INTENSITY_STEP;
+
+               /* Applies to flash mode only. */
+               if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
+                       break;
+
+               return as3645a_set_config(flash);
+
+       case V4L2_CID_FLASH_TORCH_INTENSITY:
+               flash->assist_current =
+                       (ctrl->val - AS3645A_TORCH_INTENSITY_MIN)
+                       / AS3645A_TORCH_INTENSITY_STEP;
+
+               /* Applies to torch mode only. */
+               if (flash->led_mode != V4L2_FLASH_LED_MODE_TORCH)
+                       break;
+
+               return as3645a_set_config(flash);
+
+       case V4L2_CID_FLASH_INDICATOR_INTENSITY:
+               if (flash->led_mode != V4L2_FLASH_LED_MODE_NONE)
+                       return -EBUSY;
+
+               flash->indicator_current =
+                       (ctrl->val - AS3645A_INDICATOR_INTENSITY_MIN)
+                       / AS3645A_INDICATOR_INTENSITY_STEP;
+
+               ret = as3645a_set_config(flash);
+               if (ret < 0)
+                       return ret;
+
+               if ((ctrl->val == 0) == (ctrl->cur.val == 0))
+                       break;
+
+               return as3645a_set_output(flash, false);
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops as3645a_ctrl_ops = {
+       .g_volatile_ctrl = as3645a_get_ctrl,
+       .s_ctrl = as3645a_set_ctrl,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+/* Put device into know state. */
+static int as3645a_setup(struct as3645a *flash)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       int ret;
+
+       /* clear errors */
+       ret = as3645a_read(flash, AS_FAULT_INFO_REG);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(&client->dev, "Fault info: %02x\n", ret);
+
+       ret = as3645a_set_config(flash);
+       if (ret < 0)
+               return ret;
+
+       ret = as3645a_set_output(flash, false);
+       if (ret < 0)
+               return ret;
+
+       /* read status */
+       ret = as3645a_read_fault(flash);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(&client->dev, "AS_INDICATOR_AND_TIMER_REG: %02x\n",
+               as3645a_read(flash, AS_INDICATOR_AND_TIMER_REG));
+       dev_dbg(&client->dev, "AS_CURRENT_SET_REG: %02x\n",
+               as3645a_read(flash, AS_CURRENT_SET_REG));
+       dev_dbg(&client->dev, "AS_CONTROL_REG: %02x\n",
+               as3645a_read(flash, AS_CONTROL_REG));
+
+       return ret & ~AS_FAULT_INFO_LED_AMOUNT ? -EIO : 0;
+}
+
+static int __as3645a_set_power(struct as3645a *flash, int on)
+{
+       int ret;
+
+       if (!on)
+               as3645a_set_control(flash, AS_MODE_EXT_TORCH, false);
+
+       if (flash->pdata->set_power) {
+               ret = flash->pdata->set_power(&flash->subdev, on);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (!on)
+               return 0;
+
+       ret = as3645a_setup(flash);
+       if (ret < 0) {
+               if (flash->pdata->set_power)
+                       flash->pdata->set_power(&flash->subdev, 0);
+       }
+
+       return ret;
+}
+
+static int as3645a_set_power(struct v4l2_subdev *sd, int on)
+{
+       struct as3645a *flash = to_as3645a(sd);
+       int ret = 0;
+
+       mutex_lock(&flash->power_lock);
+
+       if (flash->power_count == !on) {
+               ret = __as3645a_set_power(flash, !!on);
+               if (ret < 0)
+                       goto done;
+       }
+
+       flash->power_count += on ? 1 : -1;
+       WARN_ON(flash->power_count < 0);
+
+done:
+       mutex_unlock(&flash->power_lock);
+       return ret;
+}
+
+static int as3645a_registered(struct v4l2_subdev *sd)
+{
+       struct as3645a *flash = to_as3645a(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int rval, man, model, rfu, version;
+       const char *vendor;
+
+       /* Power up the flash driver and read manufacturer ID, model ID, RFU
+        * and version.
+        */
+       rval = as3645a_set_power(&flash->subdev, 1);
+       if (rval < 0)
+               return rval;
+
+       rval = as3645a_read(flash, AS_DESIGN_INFO_REG);
+       if (rval < 0)
+               goto power_off;
+
+       man = AS_DESIGN_INFO_FACTORY(rval);
+       model = AS_DESIGN_INFO_MODEL(rval);
+
+       rval = as3645a_read(flash, AS_VERSION_CONTROL_REG);
+       if (rval < 0)
+               goto power_off;
+
+       rfu = AS_VERSION_CONTROL_RFU(rval);
+       version = AS_VERSION_CONTROL_VERSION(rval);
+
+       /* Verify the chip model and version. */
+       if (model != 0x01 || rfu != 0x00) {
+               dev_err(&client->dev, "AS3645A not detected "
+                       "(model %d rfu %d)\n", model, rfu);
+               rval = -ENODEV;
+               goto power_off;
+       }
+
+       switch (man) {
+       case 1:
+               vendor = "AMS, Austria Micro Systems";
+               break;
+       case 2:
+               vendor = "ADI, Analog Devices Inc.";
+               break;
+       case 3:
+               vendor = "NSC, National Semiconductor";
+               break;
+       case 4:
+               vendor = "NXP";
+               break;
+       case 5:
+               vendor = "TI, Texas Instrument";
+               break;
+       default:
+               vendor = "Unknown";
+       }
+
+       dev_info(&client->dev, "Chip vendor: %s (%d) Version: %d\n", vendor,
+                man, version);
+
+       rval = as3645a_write(flash, AS_PASSWORD_REG, AS_PASSWORD_UNLOCK_VALUE);
+       if (rval < 0)
+               goto power_off;
+
+       rval = as3645a_write(flash, AS_BOOST_REG, AS_BOOST_CURRENT_DISABLE);
+       if (rval < 0)
+               goto power_off;
+
+       /* Setup default values. This makes sure that the chip is in a known
+        * state, in case the power rail can't be controlled.
+        */
+       rval = as3645a_setup(flash);
+
+power_off:
+       as3645a_set_power(&flash->subdev, 0);
+
+       return rval;
+}
+
+static int as3645a_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       return as3645a_set_power(sd, 1);
+}
+
+static int as3645a_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       return as3645a_set_power(sd, 0);
+}
+
+static const struct v4l2_subdev_core_ops as3645a_core_ops = {
+       .s_power                = as3645a_set_power,
+};
+
+static const struct v4l2_subdev_ops as3645a_ops = {
+       .core = &as3645a_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops as3645a_internal_ops = {
+       .registered = as3645a_registered,
+       .open = as3645a_open,
+       .close = as3645a_close,
+};
+
+/* -----------------------------------------------------------------------------
+ *  I2C driver
+ */
+#ifdef CONFIG_PM
+
+static int as3645a_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct as3645a *flash = to_as3645a(subdev);
+       int rval;
+
+       if (flash->power_count == 0)
+               return 0;
+
+       rval = __as3645a_set_power(flash, 0);
+
+       dev_dbg(&client->dev, "Suspend %s\n", rval < 0 ? "failed" : "ok");
+
+       return rval;
+}
+
+static int as3645a_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct as3645a *flash = to_as3645a(subdev);
+       int rval;
+
+       if (flash->power_count == 0)
+               return 0;
+
+       rval = __as3645a_set_power(flash, 1);
+
+       dev_dbg(&client->dev, "Resume %s\n", rval < 0 ? "fail" : "ok");
+
+       return rval;
+}
+
+#else
+
+#define as3645a_suspend        NULL
+#define as3645a_resume NULL
+
+#endif /* CONFIG_PM */
+
+/*
+ * as3645a_init_controls - Create controls
+ * @flash: The flash
+ *
+ * The number of LEDs reported in platform data is used to compute default
+ * limits. Parameters passed through platform data can override those limits.
+ */
+static int as3645a_init_controls(struct as3645a *flash)
+{
+       const struct as3645a_platform_data *pdata = flash->pdata;
+       struct v4l2_ctrl *ctrl;
+       int maximum;
+
+       v4l2_ctrl_handler_init(&flash->ctrls, 10);
+
+       /* V4L2_CID_FLASH_LED_MODE */
+       v4l2_ctrl_new_std_menu(&flash->ctrls, &as3645a_ctrl_ops,
+                              V4L2_CID_FLASH_LED_MODE, 2, ~7,
+                              V4L2_FLASH_LED_MODE_NONE);
+
+       /* V4L2_CID_FLASH_STROBE_SOURCE */
+       v4l2_ctrl_new_std_menu(&flash->ctrls, &as3645a_ctrl_ops,
+                              V4L2_CID_FLASH_STROBE_SOURCE,
+                              pdata->ext_strobe ? 1 : 0,
+                              pdata->ext_strobe ? ~3 : ~1,
+                              V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
+
+       flash->strobe_source = V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
+
+       /* V4L2_CID_FLASH_STROBE */
+       v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+                         V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
+
+       /* V4L2_CID_FLASH_STROBE_STOP */
+       v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+                         V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
+
+       /* V4L2_CID_FLASH_STROBE_STATUS */
+       ctrl = v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+                                V4L2_CID_FLASH_STROBE_STATUS, 0, 1, 1, 1);
+       if (ctrl != NULL)
+               ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+       /* V4L2_CID_FLASH_TIMEOUT */
+       maximum = pdata->timeout_max;
+
+       v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+                         V4L2_CID_FLASH_TIMEOUT, AS3645A_FLASH_TIMEOUT_MIN,
+                         maximum, AS3645A_FLASH_TIMEOUT_STEP, maximum);
+
+       flash->timeout = maximum;
+
+       /* V4L2_CID_FLASH_INTENSITY */
+       maximum = pdata->flash_max_current;
+
+       v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+                         V4L2_CID_FLASH_INTENSITY, AS3645A_FLASH_INTENSITY_MIN,
+                         maximum, AS3645A_FLASH_INTENSITY_STEP, maximum);
+
+       flash->flash_current = (maximum - AS3645A_FLASH_INTENSITY_MIN)
+                            / AS3645A_FLASH_INTENSITY_STEP;
+
+       /* V4L2_CID_FLASH_TORCH_INTENSITY */
+       maximum = pdata->torch_max_current;
+
+       v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+                         V4L2_CID_FLASH_TORCH_INTENSITY,
+                         AS3645A_TORCH_INTENSITY_MIN, maximum,
+                         AS3645A_TORCH_INTENSITY_STEP,
+                         AS3645A_TORCH_INTENSITY_MIN);
+
+       flash->assist_current = 0;
+
+       /* V4L2_CID_FLASH_INDICATOR_INTENSITY */
+       v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+                         V4L2_CID_FLASH_INDICATOR_INTENSITY,
+                         AS3645A_INDICATOR_INTENSITY_MIN,
+                         AS3645A_INDICATOR_INTENSITY_MAX,
+                         AS3645A_INDICATOR_INTENSITY_STEP,
+                         AS3645A_INDICATOR_INTENSITY_MIN);
+
+       flash->indicator_current = 0;
+
+       /* V4L2_CID_FLASH_FAULT */
+       ctrl = v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops,
+                                V4L2_CID_FLASH_FAULT, 0,
+                                V4L2_FLASH_FAULT_OVER_VOLTAGE |
+                                V4L2_FLASH_FAULT_TIMEOUT |
+                                V4L2_FLASH_FAULT_OVER_TEMPERATURE |
+                                V4L2_FLASH_FAULT_SHORT_CIRCUIT, 0, 0);
+       if (ctrl != NULL)
+               ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+       flash->subdev.ctrl_handler = &flash->ctrls;
+
+       return flash->ctrls.error;
+}
+
+static int as3645a_probe(struct i2c_client *client,
+                        const struct i2c_device_id *devid)
+{
+       struct as3645a *flash;
+       int ret;
+
+       if (client->dev.platform_data == NULL)
+               return -ENODEV;
+
+       flash = kzalloc(sizeof(*flash), GFP_KERNEL);
+       if (flash == NULL)
+               return -ENOMEM;
+
+       flash->pdata = client->dev.platform_data;
+
+       v4l2_i2c_subdev_init(&flash->subdev, client, &as3645a_ops);
+       flash->subdev.internal_ops = &as3645a_internal_ops;
+       flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       ret = as3645a_init_controls(flash);
+       if (ret < 0)
+               goto done;
+
+       ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0);
+       if (ret < 0)
+               goto done;
+
+       flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH;
+
+       mutex_init(&flash->power_lock);
+
+       flash->led_mode = V4L2_FLASH_LED_MODE_NONE;
+
+done:
+       if (ret < 0) {
+               v4l2_ctrl_handler_free(&flash->ctrls);
+               kfree(flash);
+       }
+
+       return ret;
+}
+
+static int __exit as3645a_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct as3645a *flash = to_as3645a(subdev);
+
+       v4l2_device_unregister_subdev(subdev);
+       v4l2_ctrl_handler_free(&flash->ctrls);
+       media_entity_cleanup(&flash->subdev.entity);
+       mutex_destroy(&flash->power_lock);
+       kfree(flash);
+
+       return 0;
+}
+
+static const struct i2c_device_id as3645a_id_table[] = {
+       { AS3645A_NAME, 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, as3645a_id_table);
+
+static const struct dev_pm_ops as3645a_pm_ops = {
+       .suspend = as3645a_suspend,
+       .resume = as3645a_resume,
+};
+
+static struct i2c_driver as3645a_i2c_driver = {
+       .driver = {
+               .name = AS3645A_NAME,
+               .pm   = &as3645a_pm_ops,
+       },
+       .probe  = as3645a_probe,
+       .remove = __exit_p(as3645a_remove),
+       .id_table = as3645a_id_table,
+};
+
+static int __init as3645a_init(void)
+{
+       int rval;
+
+       rval = i2c_add_driver(&as3645a_i2c_driver);
+       if (rval)
+               pr_err("%s: Failed to register the driver\n", AS3645A_NAME);
+
+       return rval;
+}
+
+static void __exit as3645a_exit(void)
+{
+       i2c_del_driver(&as3645a_i2c_driver);
+}
+
+module_init(as3645a_init);
+module_exit(as3645a_exit);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("LED flash driver for AS3645A, LM3555 and their clones");
+MODULE_LICENSE("GPL");
index 8c775c59e120f30589d520c49d75b18fd9a397fa..9fe4519176a4850ceecda1d29fb961eeb7b03fb2 100644 (file)
@@ -90,7 +90,10 @@ struct atmel_isi {
        struct isi_dma_desc             dma_desc[MAX_BUFFER_NUM];
 
        struct completion               complete;
+       /* ISI peripherial clock */
        struct clk                      *pclk;
+       /* ISI_MCK, feed to camera sensor to generate pixel clock */
+       struct clk                      *mck;
        unsigned int                    irq;
 
        struct isi_platform_data        *pdata;
@@ -766,6 +769,12 @@ static int isi_camera_add_device(struct soc_camera_device *icd)
        if (ret)
                return ret;
 
+       ret = clk_enable(isi->mck);
+       if (ret) {
+               clk_disable(isi->pclk);
+               return ret;
+       }
+
        isi->icd = icd;
        dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n",
                 icd->devnum);
@@ -779,6 +788,7 @@ static void isi_camera_remove_device(struct soc_camera_device *icd)
 
        BUG_ON(icd != isi->icd);
 
+       clk_disable(isi->mck);
        clk_disable(isi->pclk);
        isi->icd = NULL;
 
@@ -803,7 +813,7 @@ static int isi_camera_querycap(struct soc_camera_host *ici,
        return 0;
 }
 
-static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt)
+static int isi_camera_set_bus_param(struct soc_camera_device *icd)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -874,7 +884,7 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt)
 
        if (isi->pdata->has_emb_sync)
                cfg1 |= ISI_CFG1_EMB_SYNC;
-       if (isi->pdata->isi_full_mode)
+       if (isi->pdata->full_mode)
                cfg1 |= ISI_CFG1_FULL_MODE;
 
        isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
@@ -912,6 +922,7 @@ static int __devexit atmel_isi_remove(struct platform_device *pdev)
                        isi->fb_descriptors_phys);
 
        iounmap(isi->regs);
+       clk_put(isi->mck);
        clk_put(isi->pclk);
        kfree(isi);
 
@@ -930,7 +941,7 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev)
        struct isi_platform_data *pdata;
 
        pdata = dev->platform_data;
-       if (!pdata || !pdata->data_width_flags) {
+       if (!pdata || !pdata->data_width_flags || !pdata->mck_hz) {
                dev_err(&pdev->dev,
                        "No config available for Atmel ISI\n");
                return -EINVAL;
@@ -959,6 +970,19 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&isi->video_buffer_list);
        INIT_LIST_HEAD(&isi->dma_desc_head);
 
+       /* Get ISI_MCK, provided by programmable clock or external clock */
+       isi->mck = clk_get(dev, "isi_mck");
+       if (IS_ERR(isi->mck)) {
+               dev_err(dev, "Failed to get isi_mck\n");
+               ret = PTR_ERR(isi->mck);
+               goto err_clk_get;
+       }
+
+       /* Set ISI_MCK's frequency, it should be faster than pixel clock */
+       ret = clk_set_rate(isi->mck, pdata->mck_hz);
+       if (ret < 0)
+               goto err_set_mck_rate;
+
        isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev,
                                sizeof(struct fbd) * MAX_BUFFER_NUM,
                                &isi->fb_descriptors_phys,
@@ -1034,9 +1058,12 @@ err_alloc_ctx:
                        isi->p_fb_descriptors,
                        isi->fb_descriptors_phys);
 err_alloc_descriptors:
+err_set_mck_rate:
+       clk_put(isi->mck);
+err_clk_get:
        kfree(isi);
 err_alloc_isi:
-       clk_put(isi->pclk);
+       clk_put(pclk);
 
        return ret;
 }
index 0c3a5ba0e857d85b8a657c476e2f36aaf509eb01..81ba9d9d1b52c2024d1777e0ff4e730393063124 100644 (file)
@@ -2,6 +2,7 @@
 config VIDEO_AU0828
        tristate "Auvitek AU0828 support"
        depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2
+       depends on DVB_CAPTURE_DRIVERS
        select I2C_ALGOBIT
        select VIDEO_TVEEPROM
        select VIDEOBUF_VMALLOC
index cbdb65c34f219081387fce62731b1f74e0b05f41..05c299fa5d79f5c90de3da3eca758ad45f7f2933 100644 (file)
@@ -348,7 +348,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
        }
 }
 
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
 int au0828_i2c_register(struct au0828_dev *dev)
 {
        dprintk(1, "%s()\n", __func__);
index 0bcd95303bb0c2ace9c55d21e95eb530cbdfe000..c37e6acffdedef6ea698f73da153a3f9ec47f3d7 100644 (file)
 #ifndef PCI_DEVICE_ID_BT849
 #define PCI_DEVICE_ID_BT849     0x351
 #endif
+#ifndef PCI_DEVICE_ID_FUSION879
+#define PCI_DEVICE_ID_FUSION879        0x36c
+#endif
+
 #ifndef PCI_DEVICE_ID_BT878
 #define PCI_DEVICE_ID_BT878     0x36e
 #endif
@@ -37,7 +41,6 @@
 #define PCI_DEVICE_ID_BT879     0x36f
 #endif
 
-
 /* Brooktree 848 registers */
 
 #define BT848_DSTATUS          0x000
index 5939021d8eba4782cc983e99b658d0f370c93c0a..ff2933ab705ff2608dd38827dcab12ff0b0ca2ee 100644 (file)
@@ -80,6 +80,8 @@ static void phytec_muxsel(struct bttv *btv, unsigned int input);
 static void gv800s_muxsel(struct bttv *btv, unsigned int input);
 static void gv800s_init(struct bttv *btv);
 
+static void td3116_muxsel(struct bttv *btv, unsigned int input);
+
 static int terratec_active_radio_upgrade(struct bttv *btv);
 static int tea5757_read(struct bttv *btv);
 static int tea5757_write(struct bttv *btv, int value);
@@ -284,7 +286,8 @@ static struct CARD {
        { 0x10b42636, BTTV_BOARD_HAUPPAUGE878,  "STB ???" },
        { 0x217d6606, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
        { 0xfff6f6ff, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
-       { 0x03116000, BTTV_BOARD_SENSORAY311,   "Sensoray 311" },
+       { 0x03116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 311" },
+       { 0x06116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 611" },
        { 0x00790e11, BTTV_BOARD_WINDVR,        "Canopus WinDVR PCI" },
        { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX,       "Face to Face Tvmax" },
        { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" },
@@ -341,6 +344,7 @@ static struct CARD {
        { 0x15401835, BTTV_BOARD_PV183,         "Provideo PV183-6" },
        { 0x15401836, BTTV_BOARD_PV183,         "Provideo PV183-7" },
        { 0x15401837, BTTV_BOARD_PV183,         "Provideo PV183-8" },
+       { 0x3116f200, BTTV_BOARD_TVT_TD3116,    "Tongwei Video Technology TD-3116" },
 
        { 0, -1, NULL }
 };
@@ -1526,10 +1530,10 @@ struct tvcard bttv_tvcards[] = {
                        GPIO20,22,23: R30,R29,R28
                */
        },
-       [BTTV_BOARD_SENSORAY311] = {
+       [BTTV_BOARD_SENSORAY311_611] = {
                /* Clay Kunz <ckunz@mail.arc.nasa.gov> */
-               /* you must jumper JP5 for the card to work */
-               .name           = "Sensoray 311",
+               /* you must jumper JP5 for the 311 card (PC/104+) to work */
+               .name           = "Sensoray 311/611",
                .video_inputs   = 5,
                /* .audio_inputs= 0, */
                .svhs           = 4,
@@ -2879,6 +2883,16 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = TUNER_ABSENT,
                .tuner_addr     = ADDR_UNSET,
        },
+       [BTTV_BOARD_TVT_TD3116] = {
+               .name           = "Tongwei Video Technology TD-3116",
+               .video_inputs   = 16,
+               .gpiomask       = 0xc00ff,
+               .muxsel         = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),
+               .muxsel_hook    = td3116_muxsel,
+               .svhs           = NO_SVHS,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_ABSENT,
+       },
 };
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3228,6 +3242,42 @@ static void geovision_muxsel(struct bttv *btv, unsigned int input)
        gpio_bits(0xf, inmux);
 }
 
+/*
+ * The TD3116 has 2 74HC4051 muxes wired to the MUX0 input of a bt878.
+ * The first 74HC4051 has the lower 8 inputs, the second one the higher 8.
+ * The muxes are controlled via a 74HC373 latch which is connected to
+ * GPIOs 0-7. GPIO 18 is connected to the LE signal of the latch.
+ * Q0 of the latch is connected to the Enable (~E) input of the first
+ * 74HC4051. Q1 - Q3 are connected to S0 - S2 of the same 74HC4051.
+ * Q4 - Q7 are connected to the second 74HC4051 in the same way.
+ */
+
+static void td3116_latch_value(struct bttv *btv, u32 value)
+{
+       gpio_bits((1<<18) | 0xff, value);
+       gpio_bits((1<<18) | 0xff, (1<<18) | value);
+       udelay(1);
+       gpio_bits((1<<18) | 0xff, value);
+}
+
+static void td3116_muxsel(struct bttv *btv, unsigned int input)
+{
+       u32 value;
+       u32 highbit;
+
+       highbit = (input & 0x8) >> 3 ;
+
+       /* Disable outputs and set value in the mux */
+       value = 0x11; /* Disable outputs */
+       value |= ((input & 0x7) << 1)  << (4 * highbit);
+       td3116_latch_value(btv, value);
+
+       /* Enable the correct output */
+       value &= ~0x11;
+       value |= ((highbit ^ 0x1) << 4) | highbit;
+       td3116_latch_value(btv, value);
+}
+
 /* ----------------------------------------------------------------------- */
 
 static void bttv_reset_audio(struct bttv *btv)
index 3dd06607aec2a0457ec4b75a36463162ab15b6e4..76c301f05095375ec21d6956d00a9d69f8b33da6 100644 (file)
@@ -4572,6 +4572,7 @@ static struct pci_device_id bttv_pci_tbl[] = {
        {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0},
        {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0},
        {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0},
+       {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_FUSION879), 0},
        {0,}
 };
 
index e3952af7e56e2df0f28c6be896add69e2fa37b0f..580c8e682392c4c5524c789c8b21a75fbbe23314 100644 (file)
@@ -346,7 +346,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
        }
 }
 
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
 int __devinit init_bttv_i2c(struct bttv *btv)
 {
        strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE);
index c6333595c6b90a3749fabfa8e3f90de1751fa2c3..c5171619ac7998369511c515da9046beda33d315 100644 (file)
@@ -96,7 +96,7 @@
 #define BTTV_BOARD_PV_BT878P_PLUS          0x46
 #define BTTV_BOARD_FLYVIDEO98EZ            0x47
 #define BTTV_BOARD_PV_BT878P_9B            0x48
-#define BTTV_BOARD_SENSORAY311             0x49
+#define BTTV_BOARD_SENSORAY311_611         0x49
 #define BTTV_BOARD_RV605                   0x4a
 #define BTTV_BOARD_POWERCLR_MTV878         0x4b
 #define BTTV_BOARD_WINDVR                  0x4c
 #define BTTV_BOARD_GEOVISION_GV800S       0x9d
 #define BTTV_BOARD_GEOVISION_GV800S_SL    0x9e
 #define BTTV_BOARD_PV183                   0x9f
+#define BTTV_BOARD_TVT_TD3116             0xa0
 
 
 /* more card-specific defines */
index cd8ff0473184ea06a14bf38f0b97bfc82db91917..fda32f52554a75d63cb34652b4b7bd61b49c3890 100644 (file)
@@ -72,7 +72,7 @@ struct qcam {
 
 static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
 static int probe = 2;
-static int force_rgb;
+static bool force_rgb;
 static int video_nr = -1;
 
 /* FIXME: parport=auto would never have worked, surely? --RR */
index 5909f2557ab4fbadbaec0a58d7635a37f0d86db7..1d64af9adf719c5eb995a8f5170be94a221afbb9 100644 (file)
@@ -31,7 +31,7 @@ MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
 MODULE_AUTHOR("Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static int debug;
+static bool debug;
 
 module_param(debug, bool, 0644);
 
index d93e5ab45fd31baadc8a325265f30911ef7dcbe8..51c5b9ad67d8ba4a0b441e5f8c1aa54427b46645 100644 (file)
@@ -35,7 +35,7 @@ MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
 MODULE_AUTHOR("Martin Vaughan");
 MODULE_LICENSE("GPL");
 
-static int debug;
+static bool debug;
 
 module_param(debug, bool, 0644);
 
index c6ff32a6137c61a22c6b0774c09a18d5fd0158d0..349bd9c2aff546ae3afd2a06411d0f0ceb24f285 100644 (file)
@@ -75,7 +75,7 @@ static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1 };
 static unsigned cardtype_c = 1;
 static unsigned tuner_c = 1;
-static unsigned radio_c = 1;
+static bool radio_c = 1;
 static char pal[] = "--";
 static char secam[] = "--";
 static char ntsc[] = "-";
index 14cb961c22bdba5ef506ba56ad55e59d2dc1ade5..4bfd865a4106069538b893720622e424b0097915 100644 (file)
@@ -751,20 +751,10 @@ int cx18_v4l2_close(struct file *filp)
 
        CX18_DEBUG_IOCTL("close() of %s\n", s->name);
 
-       v4l2_fh_del(fh);
-       v4l2_fh_exit(fh);
-
-       /* Easy case first: this stream was never claimed by us */
-       if (s->id != id->open_id) {
-               kfree(id);
-               return 0;
-       }
-
-       /* 'Unclaim' this stream */
-
-       /* Stop radio */
        mutex_lock(&cx->serialize_lock);
-       if (id->type == CX18_ENC_STREAM_TYPE_RAD) {
+       /* Stop radio */
+       if (id->type == CX18_ENC_STREAM_TYPE_RAD &&
+                       v4l2_fh_is_singular_file(filp)) {
                /* Closing radio device, return to TV mode */
                cx18_mute(cx);
                /* Mark that the radio is no longer in use */
@@ -781,10 +771,14 @@ int cx18_v4l2_close(struct file *filp)
                }
                /* Done! Unmute and continue. */
                cx18_unmute(cx);
-               cx18_release_stream(s);
-       } else {
-               cx18_stop_capture(id, 0);
        }
+
+       v4l2_fh_del(fh);
+       v4l2_fh_exit(fh);
+
+       /* 'Unclaim' this stream */
+       if (s->id == id->open_id)
+               cx18_stop_capture(id, 0);
        kfree(id);
        mutex_unlock(&cx->serialize_lock);
        return 0;
@@ -810,21 +804,15 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
 
        item->open_id = cx->open_id++;
        filp->private_data = &item->fh;
+       v4l2_fh_add(&item->fh);
 
-       if (item->type == CX18_ENC_STREAM_TYPE_RAD) {
-               /* Try to claim this stream */
-               if (cx18_claim_stream(item, item->type)) {
-                       /* No, it's already in use */
-                       v4l2_fh_exit(&item->fh);
-                       kfree(item);
-                       return -EBUSY;
-               }
-
+       if (item->type == CX18_ENC_STREAM_TYPE_RAD &&
+                       v4l2_fh_is_singular_file(filp)) {
                if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
                        if (atomic_read(&cx->ana_capturing) > 0) {
                                /* switching to radio while capture is
                                   in progress is not polite */
-                               cx18_release_stream(s);
+                               v4l2_fh_del(&item->fh);
                                v4l2_fh_exit(&item->fh);
                                kfree(item);
                                return -EBUSY;
@@ -842,7 +830,6 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
                /* Done! Unmute and continue. */
                cx18_unmute(cx);
        }
-       v4l2_fh_add(&item->fh);
        return 0;
 }
 
index 040aaa87579ddf0c21f4a9d786a8d636ac5ebfe0..51609d5c88ce7962d765f0e5a3ea66e74bd69946 100644 (file)
@@ -232,7 +232,7 @@ static struct i2c_algo_bit_data cx18_i2c_algo_template = {
        .timeout        = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */
 };
 
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
 int init_cx18_i2c(struct cx18 *cx)
 {
        int i, err;
index bdfd1921e30021062f8c1ddcd50f476f3bf8d513..1180fdc8d983b1b861edc635a7e9ed53463d56ee 100644 (file)
@@ -24,6 +24,6 @@
 int cx18_i2c_register(struct cx18 *cx, unsigned idx);
 struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw);
 
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
 int init_cx18_i2c(struct cx18 *cx);
 void exit_cx18_i2c(struct cx18 *cx);
index ae85a7a7bd73814c81b578761b522e7ddda9c8bf..446f692aabb740e175326f4017b925517f2ab52c 100644 (file)
@@ -40,10 +40,10 @@ config VIDEO_CX231XX_ALSA
 
 config VIDEO_CX231XX_DVB
        tristate "DVB/ATSC Support for Cx231xx based TV cards"
-       depends on VIDEO_CX231XX && DVB_CORE
+       depends on VIDEO_CX231XX && DVB_CORE && DVB_CAPTURE_DRIVERS
        select VIDEOBUF_DVB
-       select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_NXP18271 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
        select DVB_MB86A20S if !DVB_FE_CUSTOMISE
 
        ---help---
index 30d13c15739a7d32a3a66636f90cb9aa4edde2df..a2c2b7d343ec6c05d7bee2f1e1015c9a25a649f6 100644 (file)
@@ -111,6 +111,9 @@ static void cx231xx_audio_isocirq(struct urb *urb)
        struct snd_pcm_substream *substream;
        struct snd_pcm_runtime *runtime;
 
+       if (dev->state & DEV_DISCONNECTED)
+               return;
+
        switch (urb->status) {
        case 0:         /* success */
        case -ETIMEDOUT:        /* NAK */
@@ -196,6 +199,9 @@ static void cx231xx_audio_bulkirq(struct urb *urb)
        struct snd_pcm_substream *substream;
        struct snd_pcm_runtime *runtime;
 
+       if (dev->state & DEV_DISCONNECTED)
+               return;
+
        switch (urb->status) {
        case 0:         /* success */
        case -ETIMEDOUT:        /* NAK */
@@ -273,6 +279,9 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
 
        cx231xx_info("%s: Starting ISO AUDIO transfers\n", __func__);
 
+       if (dev->state & DEV_DISCONNECTED)
+               return -ENODEV;
+
        sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
 
        for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
@@ -298,7 +307,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
                urb->context = dev;
                urb->pipe = usb_rcvisocpipe(dev->udev,
                                                dev->adev.end_point_addr);
-               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
                urb->transfer_buffer = dev->adev.transfer_buffer[i];
                urb->interval = 1;
                urb->complete = cx231xx_audio_isocirq;
@@ -331,6 +340,9 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev)
 
        cx231xx_info("%s: Starting BULK AUDIO transfers\n", __func__);
 
+       if (dev->state & DEV_DISCONNECTED)
+               return -ENODEV;
+
        sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
 
        for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
@@ -356,7 +368,7 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev)
                urb->context = dev;
                urb->pipe = usb_rcvbulkpipe(dev->udev,
                                                dev->adev.end_point_addr);
-               urb->transfer_flags = 0;
+               urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
                urb->transfer_buffer = dev->adev.transfer_buffer[i];
                urb->complete = cx231xx_audio_bulkirq;
                urb->transfer_buffer_length = sb_size;
@@ -432,6 +444,11 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
                return -ENODEV;
        }
 
+       if (dev->state & DEV_DISCONNECTED) {
+               cx231xx_errdev("Can't open. the device was removed.\n");
+               return -ENODEV;
+       }
+
        /* Sets volume, mute, etc */
        dev->mute = 0;
 
@@ -571,6 +588,9 @@ static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream,
        struct cx231xx *dev = snd_pcm_substream_chip(substream);
        int retval;
 
+       if (dev->state & DEV_DISCONNECTED)
+               return -ENODEV;
+
        spin_lock(&dev->adev.slock);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
index 60b021e7986473e4187a6326f0ba2f91d62f317b..875a7ce947361ffb720ced4e811dd909cb03b15b 100644 (file)
@@ -843,25 +843,34 @@ void cx231xx_release_resources(struct cx231xx *dev)
 
        cx231xx_remove_from_devlist(dev);
 
+       cx231xx_ir_exit(dev);
+
        /* Release I2C buses */
        cx231xx_dev_uninit(dev);
 
-       cx231xx_ir_exit(dev);
+       /* delete v4l2 device */
+       v4l2_device_unregister(&dev->v4l2_dev);
 
        usb_put_dev(dev->udev);
 
        /* Mark device as unused */
-       cx231xx_devused &= ~(1 << dev->devno);
+       clear_bit(dev->devno, &cx231xx_devused);
+
+       kfree(dev->video_mode.alt_max_pkt_size);
+       kfree(dev->vbi_mode.alt_max_pkt_size);
+       kfree(dev->sliced_cc_mode.alt_max_pkt_size);
+       kfree(dev->ts1_mode.alt_max_pkt_size);
+       kfree(dev);
+       dev = NULL;
 }
 
 /*
  * cx231xx_init_dev()
  * allocates and inits the device structs, registers i2c bus and v4l device
  */
-static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
+static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
                            int minor)
 {
-       struct cx231xx *dev = *devhandle;
        int retval = -ENOMEM;
        int errCode;
        unsigned int maxh, maxw;
@@ -1016,7 +1025,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        int i, isoc_pipe = 0;
        char *speed;
        char descr[255] = "";
-       struct usb_interface *lif = NULL;
        struct usb_interface_assoc_descriptor *assoc_desc;
 
        udev = usb_get_dev(interface_to_usbdev(interface));
@@ -1030,21 +1038,21 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                return -ENODEV;
 
        /* Check to see next free device and mark as used */
-       nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS);
-       cx231xx_devused |= 1 << nr;
-
-       if (nr >= CX231XX_MAXBOARDS) {
-               cx231xx_err(DRIVER_NAME
-                ": Supports only %i cx231xx boards.\n", CX231XX_MAXBOARDS);
-               cx231xx_devused &= ~(1 << nr);
-               return -ENOMEM;
-       }
+       do {
+               nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS);
+               if (nr >= CX231XX_MAXBOARDS) {
+                       /* No free device slots */
+                       cx231xx_err(DRIVER_NAME ": Supports only %i devices.\n",
+                                       CX231XX_MAXBOARDS);
+                       return -ENOMEM;
+               }
+       } while (test_and_set_bit(nr, &cx231xx_devused));
 
        /* allocate memory for our device state and initialize it */
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL) {
                cx231xx_err(DRIVER_NAME ": out of memory!\n");
-               cx231xx_devused &= ~(1 << nr);
+               clear_bit(nr, &cx231xx_devused);
                return -ENOMEM;
        }
 
@@ -1071,9 +1079,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
 
        /* init CIR module TBD */
 
-       /* store the current interface */
-       lif = interface;
-
        /*mode_tv: digital=1 or analog=0*/
        dev->mode_tv = 0;
 
@@ -1113,9 +1118,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
             le16_to_cpu(udev->descriptor.idProduct),
             dev->max_iad_interface_count);
 
-       /* store the interface 0 back */
-       lif = udev->actconfig->interface[0];
-
        /* increment interface count */
        dev->interface_count++;
 
@@ -1126,7 +1128,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        if (assoc_desc->bFirstInterface != ifnum) {
                cx231xx_err(DRIVER_NAME ": Not found "
                            "matching IAD interface\n");
-               cx231xx_devused &= ~(1 << nr);
+               clear_bit(dev->devno, &cx231xx_devused);
                kfree(dev);
                dev = NULL;
                return -ENODEV;
@@ -1135,7 +1137,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        cx231xx_info("registering interface %d\n", ifnum);
 
        /* save our data pointer in this interface device */
-       usb_set_intfdata(lif, dev);
+       usb_set_intfdata(interface, dev);
 
        /*
         * AV device initialization - only done at the last interface
@@ -1145,19 +1147,19 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
        if (retval) {
                cx231xx_errdev("v4l2_device_register failed\n");
-               cx231xx_devused &= ~(1 << nr);
+               clear_bit(dev->devno, &cx231xx_devused);
                kfree(dev);
                dev = NULL;
                return -EIO;
        }
        /* allocate device struct */
-       retval = cx231xx_init_dev(&dev, udev, nr);
+       retval = cx231xx_init_dev(dev, udev, nr);
        if (retval) {
-               cx231xx_devused &= ~(1 << dev->devno);
+               clear_bit(dev->devno, &cx231xx_devused);
                v4l2_device_unregister(&dev->v4l2_dev);
                kfree(dev);
                dev = NULL;
-               usb_set_intfdata(lif, NULL);
+               usb_set_intfdata(interface, NULL);
 
                return retval;
        }
@@ -1178,7 +1180,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
 
        if (dev->video_mode.alt_max_pkt_size == NULL) {
                cx231xx_errdev("out of memory!\n");
-               cx231xx_devused &= ~(1 << nr);
+               clear_bit(dev->devno, &cx231xx_devused);
                v4l2_device_unregister(&dev->v4l2_dev);
                kfree(dev);
                dev = NULL;
@@ -1212,7 +1214,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
 
        if (dev->vbi_mode.alt_max_pkt_size == NULL) {
                cx231xx_errdev("out of memory!\n");
-               cx231xx_devused &= ~(1 << nr);
+               clear_bit(dev->devno, &cx231xx_devused);
                v4l2_device_unregister(&dev->v4l2_dev);
                kfree(dev);
                dev = NULL;
@@ -1247,7 +1249,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
 
        if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) {
                cx231xx_errdev("out of memory!\n");
-               cx231xx_devused &= ~(1 << nr);
+               clear_bit(dev->devno, &cx231xx_devused);
                v4l2_device_unregister(&dev->v4l2_dev);
                kfree(dev);
                dev = NULL;
@@ -1283,7 +1285,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
 
                if (dev->ts1_mode.alt_max_pkt_size == NULL) {
                        cx231xx_errdev("out of memory!\n");
-                       cx231xx_devused &= ~(1 << nr);
+                       clear_bit(dev->devno, &cx231xx_devused);
                        v4l2_device_unregister(&dev->v4l2_dev);
                        kfree(dev);
                        dev = NULL;
@@ -1334,10 +1336,9 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
        if (!dev->udev)
                return;
 
-       flush_request_modules(dev);
+       dev->state |= DEV_DISCONNECTED;
 
-       /* delete v4l2 device */
-       v4l2_device_unregister(&dev->v4l2_dev);
+       flush_request_modules(dev);
 
        /* wait until all current v4l2 io is finished then deallocate
           resources */
@@ -1351,31 +1352,24 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
                     "deallocation are deferred on close.\n",
                     video_device_node_name(dev->vdev));
 
-               dev->state |= DEV_MISCONFIGURED;
+               /* Even having users, it is safe to remove the RC i2c driver */
+               cx231xx_ir_exit(dev);
+
                if (dev->USE_ISO)
                        cx231xx_uninit_isoc(dev);
                else
                        cx231xx_uninit_bulk(dev);
-               dev->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&dev->wait_frame);
                wake_up_interruptible(&dev->wait_stream);
        } else {
-               dev->state |= DEV_DISCONNECTED;
-               cx231xx_release_resources(dev);
        }
 
        cx231xx_close_extension(dev);
 
        mutex_unlock(&dev->lock);
 
-       if (!dev->users) {
-               kfree(dev->video_mode.alt_max_pkt_size);
-               kfree(dev->vbi_mode.alt_max_pkt_size);
-               kfree(dev->sliced_cc_mode.alt_max_pkt_size);
-               kfree(dev->ts1_mode.alt_max_pkt_size);
-               kfree(dev);
-               dev = NULL;
-       }
+       if (!dev->users)
+               cx231xx_release_resources(dev);
 }
 
 static struct usb_driver cx231xx_usb_driver = {
index d4457f9488eee6c6e06feb1dd7c7ef727d6b91b8..08dd930f882a60bf566774480f2bb7950f8df4a6 100644 (file)
@@ -166,6 +166,9 @@ int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus,
        u8 _i2c_nostop = 0;
        u8 _i2c_reserve = 0;
 
+       if (dev->state & DEV_DISCONNECTED)
+               return -ENODEV;
+
        /* Get the I2C period, nostop and reserve parameters */
        _i2c_period = i2c_bus->i2c_period;
        _i2c_nostop = i2c_bus->i2c_nostop;
@@ -1071,7 +1074,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
                                 sb_size, cx231xx_isoc_irq_callback, dma_q, 1);
 
                urb->number_of_packets = max_packets;
-               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
 
                k = 0;
                for (j = 0; j < max_packets; j++) {
@@ -1182,7 +1185,7 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
                        return -ENOMEM;
                }
                dev->video_mode.bulk_ctl.urb[i] = urb;
-               urb->transfer_flags = 0;
+               urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 
                dev->video_mode.bulk_ctl.transfer_buffer[i] =
                    usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL,
index da9a4a0aab7923c96086e7bfc68115911da7e40d..7c4e360ba9bcba325177a881e7d0f9ee052c4fce 100644 (file)
@@ -196,7 +196,7 @@ static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb)
        if (!dev)
                return 0;
 
-       if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+       if (dev->state & DEV_DISCONNECTED)
                return 0;
 
        if (urb->status < 0) {
@@ -228,7 +228,7 @@ static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb)
        if (!dev)
                return 0;
 
-       if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+       if (dev->state & DEV_DISCONNECTED)
                return 0;
 
        if (urb->status < 0) {
index 45e14cac4622ba03108bd3b4845f6f77a1beab18..96176e9db5a28faa01086e1aca1c364b401efe15 100644 (file)
 static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key,
                         u32 *ir_raw)
 {
+       int     rc;
        u8      cmd, scancode;
 
        dev_dbg(&ir->rc->input_dev->dev, "%s\n", __func__);
 
                /* poll IR chip */
-       if (1 != i2c_master_recv(ir->c, &cmd, 1))
+       rc = i2c_master_recv(ir->c, &cmd, 1);
+       if (rc < 0)
+               return rc;
+       if (rc != 1)
                return -EIO;
 
        /* it seems that 0xFE indicates that a button is still hold
@@ -102,11 +106,14 @@ int cx231xx_ir_init(struct cx231xx *dev)
        ir_i2c_bus = cx231xx_boards[dev->model].ir_i2c_master;
        dev_dbg(&dev->udev->dev, "Trying to bind ir at bus %d, addr 0x%02x\n",
                ir_i2c_bus, info.addr);
-       i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info);
+       dev->ir_i2c_client = i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info);
 
        return 0;
 }
 
 void cx231xx_ir_exit(struct cx231xx *dev)
 {
+       if (dev->ir_i2c_client)
+               i2c_unregister_device(dev->ir_i2c_client);
+       dev->ir_i2c_client = NULL;
 }
index 1c7a4daafecf56f2dc382ebc60b291f197dbbb45..8cdee5f78f131a516918cb9525e0ab23fa31b0f8 100644 (file)
@@ -93,7 +93,7 @@ static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb)
        if (!dev)
                return 0;
 
-       if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+       if (dev->state & DEV_DISCONNECTED)
                return 0;
 
        if (urb->status < 0) {
@@ -452,7 +452,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
                        return -ENOMEM;
                }
                dev->vbi_mode.bulk_ctl.urb[i] = urb;
-               urb->transfer_flags = 0;
+               urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 
                dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
                    kzalloc(sb_size, GFP_KERNEL);
index 6e81f970dc7d8e35d48975e141c5e75fbfdf878f..829a41b0c9ef5c77edc7095164debac2120f284c 100644 (file)
@@ -337,7 +337,7 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
        if (!dev)
                return 0;
 
-       if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+       if (dev->state & DEV_DISCONNECTED)
                return 0;
 
        if (urb->status < 0) {
@@ -440,7 +440,7 @@ static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
        if (!dev)
                return 0;
 
-       if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+       if (dev->state & DEV_DISCONNECTED)
                return 0;
 
        if (urb->status < 0) {
@@ -1000,12 +1000,6 @@ static int check_dev(struct cx231xx *dev)
                cx231xx_errdev("v4l2 ioctl: device not present\n");
                return -ENODEV;
        }
-
-       if (dev->state & DEV_MISCONFIGURED) {
-               cx231xx_errdev("v4l2 ioctl: device is misconfigured; "
-                              "close and open it again\n");
-               return -EIO;
-       }
        return 0;
 }
 
@@ -2347,7 +2341,8 @@ static int cx231xx_v4l2_close(struct file *filp)
                        return 0;
                }
 
-       if (dev->users == 1) {
+       dev->users--;
+       if (!dev->users) {
                videobuf_stop(&fh->vb_vidq);
                videobuf_mmap_free(&fh->vb_vidq);
 
@@ -2374,7 +2369,6 @@ static int cx231xx_v4l2_close(struct file *filp)
                cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0);
        }
        kfree(fh);
-       dev->users--;
        wake_up_interruptible_nr(&dev->open, 1);
        return 0;
 }
index 2000bc64c49784af168855f9dfab150b078a6d48..e17447554a0d6eed2de8deb94360019e20114cea 100644 (file)
@@ -377,7 +377,6 @@ struct cx231xx_board {
 enum cx231xx_dev_state {
        DEV_INITIALIZED = 0x01,
        DEV_DISCONNECTED = 0x02,
-       DEV_MISCONFIGURED = 0x04,
 };
 
 enum AFE_MODE {
@@ -621,6 +620,7 @@ struct cx231xx {
 
        /* For I2C IR support */
        struct IR_i2c_init_data    init_data;
+       struct i2c_client          *ir_i2c_client;
 
        unsigned int stream_on:1;       /* Locks streams */
        unsigned int vbi_stream_on:1;   /* Locks streams for VBI */
index 67c4a59bd8825800cda0bd1e657c92673ab4c944..f5c79e53e5a145bce2fc8a0f898ca7482d2ab0e6 100644 (file)
@@ -900,6 +900,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
        int i, retval = 0;
        u32 value = 0;
        u32 gpio_output = 0;
+       u32 gpio_value;
        u32 checksum = 0;
        u32 *dataptr;
 
@@ -907,7 +908,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
 
        /* Save GPIO settings before reset of APU */
        retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
-       retval |= mc417_memory_read(dev, 0x900C, &value);
+       retval |= mc417_memory_read(dev, 0x900C, &gpio_value);
 
        retval  = mc417_register_write(dev,
                IVTV_REG_VPU, 0xFFFFFFED);
@@ -991,11 +992,18 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
 
        /* F/W power up disturbs the GPIOs, restore state */
        retval |= mc417_register_write(dev, 0x9020, gpio_output);
-       retval |= mc417_register_write(dev, 0x900C, value);
+       retval |= mc417_register_write(dev, 0x900C, gpio_value);
 
        retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
        retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
 
+       /* Hardcoded GPIO's here */
+       retval |= mc417_register_write(dev, 0x9020, 0x4000);
+       retval |= mc417_register_write(dev, 0x900C, 0x4000);
+
+       mc417_register_read(dev, 0x9020, &gpio_output);
+       mc417_register_read(dev, 0x900C, &gpio_value);
+
        if (retval < 0)
                printk(KERN_ERR "%s: Error with mc417_register_write\n",
                        __func__);
@@ -1015,6 +1023,12 @@ static void cx23885_codec_settings(struct cx23885_dev *dev)
 {
        dprintk(1, "%s()\n", __func__);
 
+       /* Dynamically change the height based on video standard */
+       if (dev->encodernorm.id & V4L2_STD_525_60)
+               dev->ts1.height = 480;
+       else
+               dev->ts1.height = 576;
+
        /* assign frame size */
        cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
                                dev->ts1.height, dev->ts1.width);
@@ -1030,7 +1044,7 @@ static void cx23885_codec_settings(struct cx23885_dev *dev)
        cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
 }
 
-static int cx23885_initialize_codec(struct cx23885_dev *dev)
+static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder)
 {
        int version;
        int retval;
@@ -1112,9 +1126,11 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev)
        mc417_memory_write(dev, 2120, 0x00000080);
 
        /* start capturing to the host interface */
-       cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
-               CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE);
-       msleep(10);
+       if (startencoder) {
+               cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
+                       CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE);
+               msleep(10);
+       }
 
        return 0;
 }
@@ -1196,6 +1212,16 @@ static int cx23885_querymenu(struct cx23885_dev *dev,
                cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
 }
 
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct cx23885_fh  *fh  = file->private_data;
+       struct cx23885_dev *dev = fh->dev;
+
+       call_all(dev, core, g_std, id);
+
+       return 0;
+}
+
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
 {
        struct cx23885_fh  *fh  = file->private_data;
@@ -1208,55 +1234,31 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
        if (i == ARRAY_SIZE(cx23885_tvnorms))
                return -EINVAL;
        dev->encodernorm = cx23885_tvnorms[i];
+
+       /* Have the drier core notify the subdevices */
+       mutex_lock(&dev->lock);
+       cx23885_set_tvnorm(dev, *id);
+       mutex_unlock(&dev->lock);
+
        return 0;
 }
 
 static int vidioc_enum_input(struct file *file, void *priv,
-                               struct v4l2_input *i)
+       struct v4l2_input *i)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
-       struct cx23885_input *input;
-       int n;
-
-       if (i->index >= 4)
-               return -EINVAL;
-
-       input = &cx23885_boards[dev->board].input[i->index];
-
-       if (input->type == 0)
-               return -EINVAL;
-
-       /* FIXME
-        * strcpy(i->name, input->name); */
-       strcpy(i->name, "unset");
-
-       if (input->type == CX23885_VMUX_TELEVISION ||
-           input->type == CX23885_VMUX_CABLE)
-               i->type = V4L2_INPUT_TYPE_TUNER;
-       else
-               i->type  = V4L2_INPUT_TYPE_CAMERA;
-
-       for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++)
-               i->std |= cx23885_tvnorms[n].id;
-       return 0;
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       dprintk(1, "%s()\n", __func__);
+       return cx23885_enum_input(dev, i);
 }
 
 static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
-
-       *i = dev->input;
-       return 0;
+       return cx23885_get_input(file, priv, i);
 }
 
 static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 {
-       if (i >= 4)
-               return -EINVAL;
-
-       return 0;
+       return cx23885_set_input(file, priv, i);
 }
 
 static int vidioc_g_tuner(struct file *file, void *priv,
@@ -1309,43 +1311,25 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
-                               struct v4l2_frequency *f)
+       struct v4l2_frequency *f)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
-
-       cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
-               CX23885_END_NOW, CX23885_MPEG_CAPTURE,
-               CX23885_RAW_BITS_NONE);
-
-       dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n",
-               dev->tuner_type);
-       dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n",
-               f->tuner, f->type);
-       if (UNSET == dev->tuner_type)
-               return -EINVAL;
-       if (f->tuner != 0)
-               return -EINVAL;
-       if (f->type != V4L2_TUNER_ANALOG_TV)
-               return -EINVAL;
-       dev->freq = f->frequency;
-
-       call_all(dev, tuner, s_frequency, f);
+       return cx23885_set_frequency(file, priv, f);
+}
 
-       cx23885_initialize_codec(dev);
+static int vidioc_g_ctrl(struct file *file, void *priv,
+       struct v4l2_control *ctl)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
 
-       return 0;
+       return cx23885_get_control(dev, ctl);
 }
 
 static int vidioc_s_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctl)
+       struct v4l2_control *ctl)
 {
-       struct cx23885_fh  *fh  = file->private_data;
-       struct cx23885_dev *dev = fh->dev;
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
 
-       /* Update the A/V core */
-       call_all(dev, core, s_ctrl, ctl);
-       return 0;
+       return cx23885_set_control(dev, ctl);
 }
 
 static int vidioc_querycap(struct file *file, void  *priv,
@@ -1636,7 +1620,7 @@ static ssize_t mpeg_read(struct file *file, char __user *data,
        /* Start mpeg encoder on first read. */
        if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
                if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
-                       if (cx23885_initialize_codec(dev) < 0)
+                       if (cx23885_initialize_codec(dev, 1) < 0)
                                return -EINVAL;
                }
        }
@@ -1677,6 +1661,8 @@ static struct v4l2_file_operations mpeg_fops = {
 };
 
 static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
+       .vidioc_querystd         = vidioc_g_std,
+       .vidioc_g_std            = vidioc_g_std,
        .vidioc_s_std            = vidioc_s_std,
        .vidioc_enum_input       = vidioc_enum_input,
        .vidioc_g_input          = vidioc_g_input,
@@ -1686,6 +1672,7 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
        .vidioc_g_frequency      = vidioc_g_frequency,
        .vidioc_s_frequency      = vidioc_s_frequency,
        .vidioc_s_ctrl           = vidioc_s_ctrl,
+       .vidioc_g_ctrl           = vidioc_g_ctrl,
        .vidioc_querycap         = vidioc_querycap,
        .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
        .vidioc_g_fmt_vid_cap    = vidioc_g_fmt_vid_cap,
@@ -1746,8 +1733,8 @@ static struct video_device *cx23885_video_dev_alloc(
        if (NULL == vfd)
                return NULL;
        *vfd = *template;
-       snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
-               type, cx23885_boards[tsport->dev->board].name);
+       snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
+               cx23885_boards[tsport->dev->board].name, type);
        vfd->parent  = &pci->dev;
        vfd->release = video_device_release;
        return vfd;
@@ -1791,5 +1778,11 @@ int cx23885_417_register(struct cx23885_dev *dev)
        printk(KERN_INFO "%s: registered device %s [mpeg]\n",
               dev->name, video_device_node_name(dev->v4l_device));
 
+       /* ST: Configure the encoder paramaters, but don't begin
+        * encoding, this resolves an issue where the first time the
+        * encoder is started video can be choppy.
+        */
+       cx23885_initialize_codec(dev, 0);
+
        return 0;
 }
index c3cf08945e4cf853f2acb959b64ab7eaac8291f7..19b5499d2624cc9b130e8340062222fd12a465e3 100644 (file)
@@ -213,8 +213,8 @@ struct cx23885_board cx23885_boards[] = {
                .portc          = CX23885_MPEG_DVB,
                .tuner_type     = TUNER_XC4000,
                .tuner_addr     = 0x61,
-               .radio_type     = TUNER_XC4000,
-               .radio_addr     = 0x61,
+               .radio_type     = UNSET,
+               .radio_addr     = ADDR_UNSET,
                .input          = {{
                        .type   = CX23885_VMUX_TELEVISION,
                        .vmux   = CX25840_VIN2_CH1 |
@@ -335,8 +335,33 @@ struct cx23885_board cx23885_boards[] = {
        },
        [CX23885_BOARD_HAUPPAUGE_HVR1850] = {
                .name           = "Hauppauge WinTV-HVR1850",
+               .porta          = CX23885_ANALOG_VIDEO,
                .portb          = CX23885_MPEG_ENCODER,
                .portc          = CX23885_MPEG_DVB,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = 0x42, /* 0x84 >> 1 */
+               .force_bff      = 1,
+               .input          = {{
+                       .type   = CX23885_VMUX_TELEVISION,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN5_CH2 |
+                                       CX25840_VIN2_CH1 |
+                                       CX25840_DIF_ON,
+                       .amux   = CX25840_AUDIO8,
+               }, {
+                       .type   = CX23885_VMUX_COMPOSITE1,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN4_CH2 |
+                                       CX25840_VIN6_CH1,
+                       .amux   = CX25840_AUDIO7,
+               }, {
+                       .type   = CX23885_VMUX_SVIDEO,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN4_CH2 |
+                                       CX25840_VIN8_CH1 |
+                                       CX25840_SVIDEO_ON,
+                       .amux   = CX25840_AUDIO7,
+               } },
        },
        [CX23885_BOARD_COMPRO_VIDEOMATE_E800] = {
                .name           = "Compro VideoMate E800",
@@ -438,6 +463,41 @@ struct cx23885_board cx23885_boards[] = {
                        .gpio0  = 0,
                } },
        },
+       [CX23885_BOARD_MYGICA_X8507] = {
+               .name           = "Mygica X8507",
+               .tuner_type = TUNER_XC5000,
+               .tuner_addr = 0x61,
+               .tuner_bus      = 1,
+               .porta          = CX23885_ANALOG_VIDEO,
+               .input          = {
+                       {
+                               .type   = CX23885_VMUX_TELEVISION,
+                               .vmux   = CX25840_COMPOSITE2,
+                               .amux   = CX25840_AUDIO8,
+                       },
+                       {
+                               .type   = CX23885_VMUX_COMPOSITE1,
+                               .vmux   = CX25840_COMPOSITE8,
+                       },
+                       {
+                               .type   = CX23885_VMUX_SVIDEO,
+                               .vmux   = CX25840_SVIDEO_LUMA3 |
+                                               CX25840_SVIDEO_CHROMA4,
+                       },
+                       {
+                               .type   = CX23885_VMUX_COMPONENT,
+                               .vmux   = CX25840_COMPONENT_ON |
+                                       CX25840_VIN1_CH1 |
+                                       CX25840_VIN6_CH2 |
+                                       CX25840_VIN7_CH3,
+                       },
+               },
+       },
+       [CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL] = {
+               .name           = "TerraTec Cinergy T PCIe Dual",
+               .portb          = CX23885_MPEG_DVB,
+               .portc          = CX23885_MPEG_DVB,
+       }
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -637,6 +697,14 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x1b55,
                .subdevice = 0xe2e4,
                .card      = CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF,
+       }, {
+               .subvendor = 0x14f1,
+               .subdevice = 0x8502,
+               .card      = CX23885_BOARD_MYGICA_X8507,
+       }, {
+               .subvendor = 0x153b,
+               .subdevice = 0x117e,
+               .card      = CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL,
        },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1068,6 +1136,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                break;
        case CX23885_BOARD_MYGICA_X8506:
        case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+       case CX23885_BOARD_MYGICA_X8507:
                /* GPIO-0 (0)Analog / (1)Digital TV */
                /* GPIO-1 reset XC5000 */
                /* GPIO-2 reset LGS8GL5 / LGS8G75 */
@@ -1367,6 +1436,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
                break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
                /* Defaults for VID B - Analog encoder */
                /* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */
@@ -1377,6 +1447,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                /* APB_TSVALERR_POL (active low)*/
                ts1->vld_misc_val    = 0x2000;
                ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc);
+               cx_write(0x130184, 0xc);
 
                /* Defaults for VID C */
                ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
@@ -1396,6 +1467,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                break;
        case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
        case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+       case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
                ts1->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
                ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
@@ -1431,7 +1503,6 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1275:
        case CX23885_BOARD_HAUPPAUGE_HVR1255:
        case CX23885_BOARD_HAUPPAUGE_HVR1210:
-       case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
        case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
@@ -1468,6 +1539,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_MPX885:
+       case CX23885_BOARD_MYGICA_X8507:
+       case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
                dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
                                &dev->i2c_bus[2].i2c_adap,
                                "cx25840", 0x88 >> 1, NULL);
index 40e68b22015eea4c54ce28babecd2701feb03d1c..6ad227029a0f2b497f9b7853891fb107b85c192e 100644 (file)
@@ -206,12 +206,12 @@ static struct sram_channel cx23887_sram_channels[] = {
                .cnt2_reg       = DMA1_CNT2,
        },
        [SRAM_CH02] = {
-               .name           = "ch2",
-               .cmds_start     = 0x0,
-               .ctrl_start     = 0x0,
-               .cdt            = 0x0,
-               .fifo_start     = 0x0,
-               .fifo_size      = 0x0,
+               .name           = "VID A (VBI)",
+               .cmds_start     = 0x10050,
+               .ctrl_start     = 0x105F0,
+               .cdt            = 0x10810,
+               .fifo_start     = 0x3000,
+               .fifo_size      = 0x1000,
                .ptr1_reg       = DMA2_PTR1,
                .ptr2_reg       = DMA2_PTR2,
                .cnt1_reg       = DMA2_CNT1,
@@ -266,12 +266,12 @@ static struct sram_channel cx23887_sram_channels[] = {
                .cnt2_reg       = DMA5_CNT2,
        },
        [SRAM_CH07] = {
-               .name           = "ch7",
-               .cmds_start     = 0x0,
-               .ctrl_start     = 0x0,
-               .cdt            = 0x0,
-               .fifo_start     = 0x0,
-               .fifo_size      = 0x0,
+               .name           = "TV Audio",
+               .cmds_start     = 0x10190,
+               .ctrl_start     = 0x106B0,
+               .cdt            = 0x10930,
+               .fifo_start     = 0x7000,
+               .fifo_size      = 0x1000,
                .ptr1_reg       = DMA6_PTR1,
                .ptr2_reg       = DMA6_PTR2,
                .cnt1_reg       = DMA6_CNT1,
index bcb45be44bb279a2085bd20f1491a58eee962d6e..6835eb1fc09319cb52c006f6af6e299f7fc76833 100644 (file)
@@ -61,6 +61,8 @@
 #include "cx23885-f300.h"
 #include "altera-ci.h"
 #include "stv0367.h"
+#include "drxk.h"
+#include "mt2063.h"
 
 static unsigned int debug;
 
@@ -111,6 +113,8 @@ static void dvb_buf_release(struct videobuf_queue *q,
        cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
 }
 
+static int cx23885_dvb_set_frontend(struct dvb_frontend *fe);
+
 static void cx23885_dvb_gate_ctrl(struct cx23885_tsport  *port, int open)
 {
        struct videobuf_dvb_frontends *f;
@@ -125,6 +129,12 @@ static void cx23885_dvb_gate_ctrl(struct cx23885_tsport  *port, int open)
 
        if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
                fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
+
+       /*
+        * FIXME: Improve this path to avoid calling the
+        * cx23885_dvb_set_frontend() every time it passes here.
+        */
+       cx23885_dvb_set_frontend(fe->dvb.frontend);
 }
 
 static struct videobuf_queue_ops dvb_qops = {
@@ -479,15 +489,15 @@ static struct xc5000_config mygica_x8506_xc5000_config = {
        .if_khz = 5380,
 };
 
-static int cx23885_dvb_set_frontend(struct dvb_frontend *fe,
-                                   struct dvb_frontend_parameters *param)
+static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        struct cx23885_tsport *port = fe->dvb->priv;
        struct cx23885_dev *dev = port->dev;
 
        switch (dev->board) {
        case CX23885_BOARD_HAUPPAUGE_HVR1275:
-               switch (param->u.vsb.modulation) {
+               switch (p->modulation) {
                case VSB_8:
                        cx23885_gpio_clear(dev, GPIO_5);
                        break;
@@ -507,31 +517,6 @@ static int cx23885_dvb_set_frontend(struct dvb_frontend *fe,
        return 0;
 }
 
-static int cx23885_dvb_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_SET_FRONTEND:
-                       err = cx23885_dvb_set_frontend(fe,
-                               (struct dvb_frontend_parameters *) parg);
-                       break;
-               }
-               break;
-
-       case DVB_FE_IOCTL_POST:
-               /* no post-ioctl handling required */
-               break;
-       }
-       return err;
-};
-
-
 static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = {
        .prod = LGS8GXX_PROD_LGS8G75,
        .demod_address = 0x19,
@@ -617,6 +602,24 @@ static struct xc5000_config netup_xc5000_config[] = {
        },
 };
 
+static struct drxk_config terratec_drxk_config[] = {
+       {
+               .adr = 0x29,
+               .no_i2c_bridge = 1,
+       }, {
+               .adr = 0x2a,
+               .no_i2c_bridge = 1,
+       },
+};
+
+static struct mt2063_config terratec_mt2063_config[] = {
+       {
+               .tuner_address = 0x60,
+       }, {
+               .tuner_address = 0x67,
+       },
+};
+
 int netup_altera_fpga_rw(void *device, int flag, int data, int read)
 {
        struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -940,6 +943,11 @@ static int dvb_register(struct cx23885_tsport *port)
 
                        fe = dvb_attach(xc4000_attach, fe0->dvb.frontend,
                                        &dev->i2c_bus[1].i2c_adap, &cfg);
+                       if (!fe) {
+                               printk(KERN_ERR "%s/2: xc4000 attach failed\n",
+                                      dev->name);
+                               goto frontend_detach;
+                       }
                }
                break;
        case CX23885_BOARD_TBS_6920:
@@ -1043,6 +1051,20 @@ static int dvb_register(struct cx23885_tsport *port)
                }
                break;
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
+               i2c_bus = &dev->i2c_bus[0];
+               fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+                       &hcw_s5h1411_config,
+                       &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL)
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
+                               0x60, &dev->i2c_bus[0].i2c_adap,
+                               &hauppauge_tda18271_config);
+
+               tda18271_attach(&dev->ts1.analog_fe,
+                       0x60, &dev->i2c_bus[1].i2c_adap,
+                       &hauppauge_tda18271_config);
+
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
                i2c_bus = &dev->i2c_bus[0];
                fe0->dvb.frontend = dvb_attach(s5h1411_attach,
@@ -1118,6 +1140,39 @@ static int dvb_register(struct cx23885_tsport *port)
                                goto frontend_detach;
                }
                break;
+       case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+               i2c_bus = &dev->i2c_bus[0];
+               i2c_bus2 = &dev->i2c_bus[1];
+
+               switch (port->nr) {
+               /* port b */
+               case 1:
+                       fe0->dvb.frontend = dvb_attach(drxk_attach,
+                                       &terratec_drxk_config[0],
+                                       &i2c_bus->i2c_adap);
+                       if (fe0->dvb.frontend != NULL) {
+                               if (!dvb_attach(mt2063_attach,
+                                               fe0->dvb.frontend,
+                                               &terratec_mt2063_config[0],
+                                               &i2c_bus2->i2c_adap))
+                                       goto frontend_detach;
+                       }
+                       break;
+               /* port c */
+               case 2:
+                       fe0->dvb.frontend = dvb_attach(drxk_attach,
+                                       &terratec_drxk_config[1],
+                                       &i2c_bus->i2c_adap);
+                       if (fe0->dvb.frontend != NULL) {
+                               if (!dvb_attach(mt2063_attach,
+                                               fe0->dvb.frontend,
+                                               &terratec_mt2063_config[1],
+                                               &i2c_bus2->i2c_adap))
+                                       goto frontend_detach;
+                       }
+                       break;
+               }
+               break;
        default:
                printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
                        " isn't supported yet\n",
@@ -1151,7 +1206,7 @@ static int dvb_register(struct cx23885_tsport *port)
        /* register everything */
        ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
                                        &dev->pci->dev, adapter_nr, mfe_shared,
-                                       cx23885_dvb_fe_ioctl_override);
+                                       NULL);
        if (ret)
                goto frontend_detach;
 
index 0ff7a9e98f3e637c6a9ef6d258c08e80de2e8c6c..be1e21d8295c8b382c0289d3265d7038abb2f73a 100644 (file)
@@ -309,7 +309,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
        }
 }
 
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
 int cx23885_i2c_register(struct cx23885_i2c *bus)
 {
        struct cx23885_dev *dev = bus->dev;
index e730b92630161b58b5d4c8278e48d394910b95b3..c654bdc7ccb201dd4e285c0b7ddfe703ab89cb61 100644 (file)
@@ -253,9 +253,9 @@ static struct cx23885_ctrl cx23885_ctls[] = {
                        .id            = V4L2_CID_AUDIO_VOLUME,
                        .name          = "Volume",
                        .minimum       = 0,
-                       .maximum       = 0x3f,
-                       .step          = 1,
-                       .default_value = 0x3f,
+                       .maximum       = 65535,
+                       .step          = 65535 / 100,
+                       .default_value = 65535,
                        .type          = V4L2_CTRL_TYPE_INTEGER,
                },
                .reg                   = PATH1_VOL_CTL,
@@ -316,7 +316,7 @@ void cx23885_video_wakeup(struct cx23885_dev *dev,
                        __func__, bc);
 }
 
-static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
+int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
 {
        dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
                __func__,
@@ -344,8 +344,8 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
        *vfd = *template;
        vfd->v4l2_dev = &dev->v4l2_dev;
        vfd->release = video_device_release;
-       snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
-                dev->name, type, cx23885_boards[dev->board].name);
+       snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
+                cx23885_boards[dev->board].name, type);
        video_set_drvdata(vfd, dev);
        return vfd;
 }
@@ -492,7 +492,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
        dev->input = input;
 
        if (dev->board == CX23885_BOARD_MYGICA_X8506 ||
-               dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2) {
+               dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2 ||
+               dev->board == CX23885_BOARD_MYGICA_X8507) {
                /* Select Analog TV */
                if (INPUT(input)->type == CX23885_VMUX_TELEVISION)
                        cx23885_gpio_clear(dev, GPIO_0);
@@ -503,7 +504,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
                        INPUT(input)->vmux, 0, 0);
 
        if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) ||
-               (dev->board == CX23885_BOARD_MPX885)) {
+               (dev->board == CX23885_BOARD_MPX885) ||
+               (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)) {
                /* Configure audio routing */
                v4l2_subdev_call(dev->sd_cx25840, audio, s_routing,
                        INPUT(input)->amux, 0, 0);
@@ -649,6 +651,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        int rc, init_buffer = 0;
        u32 line0_offset, line1_offset;
        struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+       int field_tff;
 
        BUG_ON(NULL == fh->fmt);
        if (fh->width  < 48 || fh->width  > norm_maxw(dev->tvnorm) ||
@@ -690,15 +693,25 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                                         buf->bpl, 0, buf->vb.height);
                        break;
                case V4L2_FIELD_INTERLACED:
-                       if (dev->tvnorm & V4L2_STD_NTSC) {
+                       if (dev->tvnorm & V4L2_STD_NTSC)
+                               /* NTSC or  */
+                               field_tff = 1;
+                       else
+                               field_tff = 0;
+
+                       if (cx23885_boards[dev->board].force_bff)
+                               /* PAL / SECAM OR 888 in NTSC MODE */
+                               field_tff = 0;
+
+                       if (field_tff) {
                                /* cx25840 transmits NTSC bottom field first */
-                               dprintk(1, "%s() Creating NTSC risc\n",
+                               dprintk(1, "%s() Creating TFF/NTSC risc\n",
                                        __func__);
                                line0_offset = buf->bpl;
                                line1_offset = 0;
                        } else {
                                /* All other formats are top field first */
-                               dprintk(1, "%s() Creating PAL/SECAM risc\n",
+                               dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n",
                                        __func__);
                                line0_offset = 0;
                                line1_offset = buf->bpl;
@@ -981,6 +994,8 @@ static int video_release(struct file *file)
        }
 
        videobuf_mmap_free(&fh->vidq);
+       videobuf_mmap_free(&fh->vbiq);
+
        file->private_data = NULL;
        kfree(fh);
 
@@ -1002,7 +1017,7 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma)
 /* ------------------------------------------------------------------ */
 /* VIDEO CTRL IOCTLS                                                  */
 
-static int cx23885_get_control(struct cx23885_dev *dev,
+int cx23885_get_control(struct cx23885_dev *dev,
        struct v4l2_control *ctl)
 {
        dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
@@ -1010,7 +1025,7 @@ static int cx23885_get_control(struct cx23885_dev *dev,
        return 0;
 }
 
-static int cx23885_set_control(struct cx23885_dev *dev,
+int cx23885_set_control(struct cx23885_dev *dev,
        struct v4l2_control *ctl)
 {
        dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__);
@@ -1229,6 +1244,16 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
        return 0;
 }
 
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+       struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+       dprintk(1, "%s()\n", __func__);
+
+       call_all(dev, core, g_std, id);
+
+       return 0;
+}
+
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
 {
        struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
@@ -1241,7 +1266,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
        return 0;
 }
 
-static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
+int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
 {
        static const char *iname[] = {
                [CX23885_VMUX_COMPOSITE1] = "Composite1",
@@ -1278,6 +1303,15 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
        if (INPUT(n)->type != CX23885_VMUX_TELEVISION)
                i->audioset = 0x3;
 
+       if (dev->input == n) {
+               /* enum'd input matches our configured input.
+                * Ask the video decoder to process the call
+                * and give it an oppertunity to update the
+                * status field.
+                */
+               call_all(dev, video, g_input_status, &i->status);
+       }
+
        return 0;
 }
 
@@ -1289,7 +1323,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
        return cx23885_enum_input(dev, i);
 }
 
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+int cx23885_get_input(struct file *file, void *priv, unsigned int *i)
 {
        struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
 
@@ -1298,7 +1332,12 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
        return 0;
 }
 
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       return cx23885_get_input(file, priv, i);
+}
+
+int cx23885_set_input(struct file *file, void *priv, unsigned int i)
 {
        struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
 
@@ -1322,6 +1361,11 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
        return 0;
 }
 
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+       return cx23885_set_input(file, priv, i);
+}
+
 static int vidioc_log_status(struct file *file, void *priv)
 {
        struct cx23885_fh  *fh  = priv;
@@ -1329,11 +1373,11 @@ static int vidioc_log_status(struct file *file, void *priv)
 
        printk(KERN_INFO
                "%s/0: ============  START LOG STATUS  ============\n",
-              dev->name);
+               dev->name);
        call_all(dev, core, log_status);
        printk(KERN_INFO
                "%s/0: =============  END LOG STATUS  =============\n",
-              dev->name);
+               dev->name);
        return 0;
 }
 
@@ -1471,6 +1515,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 
 static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
 {
+       struct v4l2_control ctrl;
+
        if (unlikely(UNSET == dev->tuner_type))
                return -EINVAL;
        if (unlikely(f->tuner != 0))
@@ -1479,29 +1525,103 @@ static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
        mutex_lock(&dev->lock);
        dev->freq = f->frequency;
 
+       /* I need to mute audio here */
+       ctrl.id = V4L2_CID_AUDIO_MUTE;
+       ctrl.value = 1;
+       cx23885_set_control(dev, &ctrl);
+
        call_all(dev, tuner, s_frequency, f);
 
        /* When changing channels it is required to reset TVAUDIO */
-       msleep(10);
+       msleep(100);
+
+       /* I need to unmute audio here */
+       ctrl.value = 0;
+       cx23885_set_control(dev, &ctrl);
 
        mutex_unlock(&dev->lock);
 
        return 0;
 }
 
-static int vidioc_s_frequency(struct file *file, void *priv,
-                               struct v4l2_frequency *f)
+static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
+       struct v4l2_frequency *f)
+{
+       struct v4l2_control ctrl;
+       struct videobuf_dvb_frontend *vfe;
+       struct dvb_frontend *fe;
+
+       struct analog_parameters params = {
+               .mode      = V4L2_TUNER_ANALOG_TV,
+               .audmode   = V4L2_TUNER_MODE_STEREO,
+               .std       = dev->tvnorm,
+               .frequency = f->frequency
+       };
+
+       mutex_lock(&dev->lock);
+       dev->freq = f->frequency;
+
+       /* I need to mute audio here */
+       ctrl.id = V4L2_CID_AUDIO_MUTE;
+       ctrl.value = 1;
+       cx23885_set_control(dev, &ctrl);
+
+       /* If HVR1850 */
+       dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__,
+               params.frequency, f->tuner, params.std);
+
+       vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1);
+       if (!vfe) {
+               mutex_unlock(&dev->lock);
+               return -EINVAL;
+       }
+
+       fe = vfe->dvb.frontend;
+
+       if (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)
+               fe = &dev->ts1.analog_fe;
+
+       if (fe && fe->ops.tuner_ops.set_analog_params) {
+               call_all(dev, core, s_std, dev->tvnorm);
+               fe->ops.tuner_ops.set_analog_params(fe, &params);
+       }
+       else
+               printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__);
+
+       /* When changing channels it is required to reset TVAUDIO */
+       msleep(100);
+
+       /* I need to unmute audio here */
+       ctrl.value = 0;
+       cx23885_set_control(dev, &ctrl);
+
+       mutex_unlock(&dev->lock);
+
+       return 0;
+}
+
+int cx23885_set_frequency(struct file *file, void *priv,
+       struct v4l2_frequency *f)
 {
        struct cx23885_fh *fh = priv;
        struct cx23885_dev *dev = fh->dev;
+       int ret;
 
-       if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
-               return -EINVAL;
-       if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
-               return -EINVAL;
+       switch (dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1850:
+               ret = cx23885_set_freq_via_ops(dev, f);
+               break;
+       default:
+               ret = cx23885_set_freq(dev, f);
+       }
 
-       return
-               cx23885_set_freq(dev, f);
+       return ret;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+       struct v4l2_frequency *f)
+{
+       return cx23885_set_frequency(file, priv, f);
 }
 
 /* ----------------------------------------------------------- */
@@ -1613,6 +1733,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_qbuf          = vidioc_qbuf,
        .vidioc_dqbuf         = vidioc_dqbuf,
        .vidioc_s_std         = vidioc_s_std,
+       .vidioc_g_std         = vidioc_g_std,
+       .vidioc_querystd      = vidioc_g_std,
        .vidioc_enum_input    = vidioc_enum_input,
        .vidioc_g_input       = vidioc_g_input,
        .vidioc_s_input       = vidioc_s_input,
index b49036fe3ffdc52fcea1bf946a423594e4a5f242..f020f0568df4a8c8c15d098c1c4d6ad9f39367f5 100644 (file)
@@ -87,6 +87,8 @@
 #define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30
 #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31
 #define CX23885_BOARD_MPX885                   32
+#define CX23885_BOARD_MYGICA_X8507             33
+#define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
@@ -226,6 +228,8 @@ struct cx23885_board {
        u32                     clk_freq;
        struct cx23885_input    input[MAX_CX23885_INPUT];
        int                     ci_type; /* for NetUP */
+       /* Force bottom field first during DMA (888 workaround) */
+       u32                     force_bff;
 };
 
 struct cx23885_subid {
@@ -310,6 +314,9 @@ struct cx23885_tsport {
        u32                        num_frontends;
        void                (*gate_ctrl)(struct cx23885_tsport *port, int open);
        void                       *port_priv;
+
+       /* Workaround for a temp dvb_frontend that the tuner can attached to */
+       struct dvb_frontend analog_fe;
 };
 
 struct cx23885_kernel_ir {
@@ -574,6 +581,13 @@ extern void cx23885_video_unregister(struct cx23885_dev *dev);
 extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status);
 extern void cx23885_video_wakeup(struct cx23885_dev *dev,
        struct cx23885_dmaqueue *q, u32 count);
+int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i);
+int cx23885_set_input(struct file *file, void *priv, unsigned int i);
+int cx23885_get_input(struct file *file, void *priv, unsigned int *i);
+int cx23885_set_frequency(struct file *file, void *priv, struct v4l2_frequency *f);
+int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
+int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
+int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm);
 
 /* ----------------------------------------------------------- */
 /* cx23885-vbi.c                                               */
index 09e99de5fd21823194358cd8ca8a9f8f30cb30c7..03cfac476b032b547297c2a38e1d97d764c6a486 100644 (file)
@@ -102,7 +102,7 @@ struct cx25821_audio_dev {
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
-static int enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 };
+static bool enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 };
 
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable cx25821 soundcard. default enabled.");
@@ -176,8 +176,7 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip)
 
        /* Set the input mode to 16-bit */
        tmp = cx_read(AUD_A_CFG);
-       cx_write(AUD_A_CFG,
-                tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE |
+       cx_write(AUD_A_CFG, tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE |
                 FLD_AUD_CLK_ENABLE);
 
        /*
@@ -188,9 +187,8 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip)
        */
 
        /* Enables corresponding bits at AUD_INT_STAT */
-       cx_write(AUD_A_INT_MSK,
-                FLD_AUD_DST_RISCI1 | FLD_AUD_DST_OF | FLD_AUD_DST_SYNC |
-                FLD_AUD_DST_OPC_ERR);
+       cx_write(AUD_A_INT_MSK, FLD_AUD_DST_RISCI1 | FLD_AUD_DST_OF |
+                FLD_AUD_DST_SYNC | FLD_AUD_DST_OPC_ERR);
 
        /* Clean any pending interrupt bits already set */
        cx_write(AUD_A_INT_STAT, ~0);
@@ -200,8 +198,8 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip)
 
        /* Turn on audio downstream fifo and risc enable 0x101 */
        tmp = cx_read(AUD_INT_DMA_CTL);
-       cx_set(AUD_INT_DMA_CTL,
-              tmp | (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN));
+       cx_set(AUD_INT_DMA_CTL, tmp |
+              (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN));
 
        mdelay(100);
        return 0;
@@ -220,9 +218,8 @@ static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip)
 
        /* disable irqs */
        cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT);
-       cx_clear(AUD_A_INT_MSK,
-                AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | AUD_INT_DN_RISCI2 |
-                AUD_INT_DN_RISCI1);
+       cx_clear(AUD_A_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+                AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
 
        return 0;
 }
@@ -234,15 +231,15 @@ static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip)
  */
 static char *cx25821_aud_irqs[32] = {
        "dn_risci1", "up_risci1", "rds_dn_risc1",       /* 0-2 */
-       NULL,                   /* reserved */
+       NULL,                                           /* reserved */
        "dn_risci2", "up_risci2", "rds_dn_risc2",       /* 4-6 */
-       NULL,                   /* reserved */
-       "dnf_of", "upf_uf", "rds_dnf_uf",       /* 8-10 */
-       NULL,                   /* reserved */
-       "dn_sync", "up_sync", "rds_dn_sync",    /* 12-14 */
-       NULL,                   /* reserved */
-       "opc_err", "par_err", "rip_err",        /* 16-18 */
-       "pci_abort", "ber_irq", "mchg_irq"      /* 19-21 */
+       NULL,                                           /* reserved */
+       "dnf_of", "upf_uf", "rds_dnf_uf",               /* 8-10 */
+       NULL,                                           /* reserved */
+       "dn_sync", "up_sync", "rds_dn_sync",            /* 12-14 */
+       NULL,                                           /* reserved */
+       "opc_err", "par_err", "rip_err",                /* 16-18 */
+       "pci_abort", "ber_irq", "mchg_irq"              /* 19-21 */
 };
 
 /*
@@ -258,10 +255,8 @@ static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status,
 
        cx_write(AUD_A_INT_STAT, status);
        if (debug > 1 || (status & mask & ~0xff))
-               cx25821_print_irqbits(dev->name, "irq aud",
-                                     cx25821_aud_irqs,
-                                     ARRAY_SIZE(cx25821_aud_irqs), status,
-                                     mask);
+               cx25821_print_irqbits(dev->name, "irq aud", cx25821_aud_irqs,
+                               ARRAY_SIZE(cx25821_aud_irqs), status, mask);
 
        /* risc op code error */
        if (status & AUD_INT_OPC_ERR) {
@@ -270,8 +265,7 @@ static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status,
                cx_clear(AUD_INT_DMA_CTL,
                         FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN);
                cx25821_sram_channel_dump_audio(dev,
-                                               &cx25821_sram_channels
-                                               [AUDIO_SRAM_CHANNEL]);
+                               &cx25821_sram_channels[AUDIO_SRAM_CHANNEL]);
        }
        if (status & AUD_INT_DN_SYNC) {
                pr_warn("WARNING %s: Downstream sync error!\n", dev->name);
@@ -317,8 +311,9 @@ static irqreturn_t cx25821_irq(int irq, void *dev_id)
                                cx25821_aud_irq(chip, audint_status,
                                                audint_mask);
                                break;
-                       } else
+                       } else {
                                goto out;
+                       }
                }
 
                handled = 1;
@@ -361,9 +356,8 @@ static int dsp_buffer_free(struct cx25821_audio_dev *chip)
  */
 #define DEFAULT_FIFO_SIZE      384
 static struct snd_pcm_hardware snd_cx25821_digital_hw = {
-       .info = SNDRV_PCM_INFO_MMAP |
-           SNDRV_PCM_INFO_INTERLEAVED |
-           SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID,
+       .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID,
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
 
        .rates = SNDRV_PCM_RATE_48000,
@@ -396,8 +390,8 @@ static int snd_cx25821_pcm_open(struct snd_pcm_substream *substream)
                return -ENODEV;
        }
 
-       err =
-           snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS);
+       err = snd_pcm_hw_constraint_pow2(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_PERIODS);
        if (err < 0)
                goto _error;
 
@@ -468,8 +462,7 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
        dma = &buf->dma;
        videobuf_dma_init(dma);
        ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
-                                      (PAGE_ALIGN(chip->dma_size) >>
-                                       PAGE_SHIFT));
+                       (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
        if (ret < 0)
                goto error;
 
@@ -477,10 +470,8 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                goto error;
 
-       ret =
-           cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist,
-                                         chip->period_size, chip->num_periods,
-                                         1);
+       ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist,
+                       chip->period_size, chip->num_periods, 1);
        if (ret < 0) {
                pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n");
                goto error;
@@ -686,7 +677,7 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
        }
 
        err = snd_card_create(index[devno], id[devno], THIS_MODULE,
-                        sizeof(struct cx25821_audio_dev), &card);
+                       sizeof(struct cx25821_audio_dev), &card);
        if (err < 0) {
                pr_info("DEBUG ERROR: cannot create snd_card_new in %s\n",
                        __func__);
@@ -711,8 +702,8 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
                          IRQF_SHARED, chip->dev->name, chip);
 
        if (err < 0) {
-               pr_err("ERROR %s: can't get IRQ %d for ALSA\n",
-                      chip->dev->name, dev->pci->irq);
+               pr_err("ERROR %s: can't get IRQ %d for ALSA\n", chip->dev->name,
+                       dev->pci->irq);
                goto error;
        }
 
@@ -730,8 +721,8 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
                chip->iobase, chip->irq);
        strcpy(card->mixername, "CX25821");
 
-       pr_info("%s/%i: ALSA support for cx25821 boards\n",
-               card->driver, devno);
+       pr_info("%s/%i: ALSA support for cx25821 boards\n", card->driver,
+               devno);
 
        err = snd_card_register(card);
        if (err < 0) {
index c20d6dece154ee66066c1456b1284f314b89a1ee..20c7ca3351a8df7399d05af0a850867e32140662 100644 (file)
@@ -107,7 +107,7 @@ static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev,
 {
        unsigned int line;
        struct sram_channel *sram_ch =
-          dev->channels[dev->_audio_upstream_channel].sram_channels;
+               dev->channels[dev->_audio_upstream_channel].sram_channels;
        int offset = 0;
 
        /* scan lines */
@@ -175,10 +175,8 @@ int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev,
                }
 
                rp = cx25821_risc_field_upstream_audio(dev, rp,
-                                                      dev->
-                                                      _audiodata_buf_phys_addr
-                                                      + databuf_offset, bpl,
-                                                      fifo_enable);
+                               dev->_audiodata_buf_phys_addr + databuf_offset,
+                               bpl, fifo_enable);
 
                if (USE_RISC_NOOP_AUDIO) {
                        for (i = 0; i < NUM_NO_OPS; i++)
@@ -193,7 +191,7 @@ int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev,
 
                /* Recalculate virtual address based on frame index */
                rp = dev->_risc_virt_addr + RISC_SYNC_INSTRUCTION_SIZE / 4 +
-                   (AUDIO_RISC_DMA_BUF_SIZE * (frame + 1) / 4);
+                       (AUDIO_RISC_DMA_BUF_SIZE * (frame + 1) / 4);
        }
 
        return 0;
@@ -218,7 +216,7 @@ void cx25821_free_memory_audio(struct cx25821_dev *dev)
 void cx25821_stop_upstream_audio(struct cx25821_dev *dev)
 {
        struct sram_channel *sram_ch =
-          dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels;
+               dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels;
        u32 tmp = 0;
 
        if (!dev->_audio_is_running) {
@@ -286,14 +284,14 @@ int cx25821_get_audio_data(struct cx25821_dev *dev,
        } else {
                if (!(myfile->f_op)) {
                        pr_err("%s(): File has no file operations registered!\n",
-                              __func__);
+                               __func__);
                        filp_close(myfile, NULL);
                        return -EIO;
                }
 
                if (!myfile->f_op->read) {
                        pr_err("%s(): File has no READ operations registered!\n",
-                              __func__);
+                               __func__);
                        filp_close(myfile, NULL);
                        return -EIO;
                }
@@ -305,14 +303,14 @@ int cx25821_get_audio_data(struct cx25821_dev *dev,
                for (i = 0; i < dev->_audio_lines_count; i++) {
                        pos = file_offset;
 
-                       vfs_read_retval =
-                           vfs_read(myfile, mybuf, line_size, &pos);
+                       vfs_read_retval = vfs_read(myfile, mybuf, line_size,
+                                                                       &pos);
 
                        if (vfs_read_retval > 0 && vfs_read_retval == line_size
                            && dev->_audiodata_buf_virt_addr != NULL) {
                                memcpy((void *)(dev->_audiodata_buf_virt_addr +
                                                frame_offset / 4), mybuf,
-                                      vfs_read_retval);
+                                       vfs_read_retval);
                        }
 
                        file_offset += vfs_read_retval;
@@ -328,8 +326,8 @@ int cx25821_get_audio_data(struct cx25821_dev *dev,
                if (i > 0)
                        dev->_audioframe_count++;
 
-               dev->_audiofile_status =
-                   (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE;
+               dev->_audiofile_status = (vfs_read_retval == line_size) ?
+                                               IN_PROGRESS : END_OF_FILE;
 
                set_fs(old_fs);
                filp_close(myfile, NULL);
@@ -340,12 +338,12 @@ int cx25821_get_audio_data(struct cx25821_dev *dev,
 
 static void cx25821_audioups_handler(struct work_struct *work)
 {
-       struct cx25821_dev *dev =
-           container_of(work, struct cx25821_dev, _audio_work_entry);
+       struct cx25821_dev *dev = container_of(work, struct cx25821_dev,
+                       _audio_work_entry);
 
        if (!dev) {
                pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
-                      __func__);
+                       __func__);
                return;
        }
 
@@ -370,19 +368,19 @@ int cx25821_openfile_audio(struct cx25821_dev *dev,
        if (IS_ERR(myfile)) {
                const int open_errno = -PTR_ERR(myfile);
                pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
-                      __func__, dev->_audiofilename, open_errno);
+                       __func__, dev->_audiofilename, open_errno);
                return PTR_ERR(myfile);
        } else {
                if (!(myfile->f_op)) {
                        pr_err("%s(): File has no file operations registered!\n",
-                              __func__);
+                               __func__);
                        filp_close(myfile, NULL);
                        return -EIO;
                }
 
                if (!myfile->f_op->read) {
                        pr_err("%s(): File has no READ operations registered!\n",
-                              __func__);
+                               __func__);
                        filp_close(myfile, NULL);
                        return -EIO;
                }
@@ -395,12 +393,12 @@ int cx25821_openfile_audio(struct cx25821_dev *dev,
                        for (i = 0; i < dev->_audio_lines_count; i++) {
                                pos = offset;
 
-                               vfs_read_retval =
-                                   vfs_read(myfile, mybuf, line_size, &pos);
+                               vfs_read_retval = vfs_read(myfile, mybuf,
+                                               line_size, &pos);
 
-                               if (vfs_read_retval > 0
-                                   && vfs_read_retval == line_size
-                                   && dev->_audiodata_buf_virt_addr != NULL) {
+                               if (vfs_read_retval > 0 &&
+                                   vfs_read_retval == line_size &&
+                                   dev->_audiodata_buf_virt_addr != NULL) {
                                        memcpy((void *)(dev->
                                                        _audiodata_buf_virt_addr
                                                        + offset / 4), mybuf,
@@ -423,8 +421,8 @@ int cx25821_openfile_audio(struct cx25821_dev *dev,
                                break;
                }
 
-               dev->_audiofile_status =
-                   (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE;
+               dev->_audiofile_status = (vfs_read_retval == line_size) ?
+                                               IN_PROGRESS : END_OF_FILE;
 
                set_fs(old_fs);
                myfile->f_pos = 0;
@@ -444,9 +442,8 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev,
 
        cx25821_free_memory_audio(dev);
 
-       dev->_risc_virt_addr =
-           pci_alloc_consistent(dev->pci, dev->audio_upstream_riscbuf_size,
-                                &dma_addr);
+       dev->_risc_virt_addr = pci_alloc_consistent(dev->pci,
+                       dev->audio_upstream_riscbuf_size, &dma_addr);
        dev->_risc_virt_start_addr = dev->_risc_virt_addr;
        dev->_risc_phys_start_addr = dma_addr;
        dev->_risc_phys_addr = dma_addr;
@@ -454,22 +451,21 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev,
 
        if (!dev->_risc_virt_addr) {
                printk(KERN_DEBUG
-                      pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning\n"));
+                       pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning\n"));
                return -ENOMEM;
        }
        /* Clear out memory at address */
        memset(dev->_risc_virt_addr, 0, dev->_audiorisc_size);
 
        /* For Audio Data buffer allocation */
-       dev->_audiodata_buf_virt_addr =
-           pci_alloc_consistent(dev->pci, dev->audio_upstream_databuf_size,
-                                &data_dma_addr);
+       dev->_audiodata_buf_virt_addr = pci_alloc_consistent(dev->pci,
+                       dev->audio_upstream_databuf_size, &data_dma_addr);
        dev->_audiodata_buf_phys_addr = data_dma_addr;
        dev->_audiodata_buf_size = dev->audio_upstream_databuf_size;
 
        if (!dev->_audiodata_buf_virt_addr) {
                printk(KERN_DEBUG
-                      pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning\n"));
+                       pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning\n"));
                return -ENOMEM;
        }
        /* Clear out memory at address */
@@ -480,12 +476,11 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev,
                return ret;
 
        /* Creating RISC programs */
-       ret =
-           cx25821_risc_buffer_upstream_audio(dev, dev->pci, bpl,
-                                              dev->_audio_lines_count);
+       ret = cx25821_risc_buffer_upstream_audio(dev, dev->pci, bpl,
+                                               dev->_audio_lines_count);
        if (ret < 0) {
                printk(KERN_DEBUG
-                      pr_fmt("ERROR creating audio upstream RISC programs!\n"));
+                       pr_fmt("ERROR creating audio upstream RISC programs!\n"));
                goto error;
        }
 
@@ -533,9 +528,9 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
 
                        if (dev->_risc_virt_start_addr != NULL) {
                                risc_phys_jump_addr =
-                                   dev->_risc_phys_start_addr +
-                                   RISC_SYNC_INSTRUCTION_SIZE +
-                                   AUDIO_RISC_DMA_BUF_SIZE;
+                                       dev->_risc_phys_start_addr +
+                                       RISC_SYNC_INSTRUCTION_SIZE +
+                                       AUDIO_RISC_DMA_BUF_SIZE;
 
                                rp = cx25821_risc_field_upstream_audio(dev,
                                                dev->_risc_virt_start_addr + 1,
@@ -632,7 +627,7 @@ static void cx25821_wait_fifo_enable(struct cx25821_dev *dev,
                /* 10 millisecond timeout */
                if (count++ > 1000) {
                        pr_err("ERROR: %s() fifo is NOT turned on. Timeout!\n",
-                              __func__);
+                               __func__);
                        return;
                }
 
@@ -661,9 +656,9 @@ int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev,
 
        /* Set the input mode to 16-bit */
        tmp = cx_read(sram_ch->aud_cfg);
-       tmp |=
-           FLD_AUD_SRC_ENABLE | FLD_AUD_DST_PK_MODE | FLD_AUD_CLK_ENABLE |
-           FLD_AUD_MASTER_MODE | FLD_AUD_CLK_SELECT_PLL_D | FLD_AUD_SONY_MODE;
+       tmp |= FLD_AUD_SRC_ENABLE | FLD_AUD_DST_PK_MODE | FLD_AUD_CLK_ENABLE |
+               FLD_AUD_MASTER_MODE | FLD_AUD_CLK_SELECT_PLL_D |
+               FLD_AUD_SONY_MODE;
        cx_write(sram_ch->aud_cfg, tmp);
 
        /* Read and write back the interrupt status register to clear it */
@@ -678,12 +673,11 @@ int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev,
        tmp = cx_read(sram_ch->int_msk);
        cx_write(sram_ch->int_msk, tmp |= _intr_msk);
 
-       err =
-           request_irq(dev->pci->irq, cx25821_upstream_irq_audio,
+       err = request_irq(dev->pci->irq, cx25821_upstream_irq_audio,
                        IRQF_SHARED, dev->name, dev);
        if (err < 0) {
-               pr_err("%s: can't get upstream IRQ %d\n",
-                      dev->name, dev->pci->irq);
+               pr_err("%s: can't get upstream IRQ %d\n", dev->name,
+                               dev->pci->irq);
                goto fail_irq;
        }
 
@@ -726,7 +720,7 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
 
        if (!dev->_irq_audio_queues) {
                printk(KERN_DEBUG
-                      pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n"));
+                       pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n"));
                return -ENOMEM;
        }
 
@@ -739,33 +733,30 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
 
        if (dev->input_audiofilename) {
                str_length = strlen(dev->input_audiofilename);
-               dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL);
+               dev->_audiofilename = kmemdup(dev->input_audiofilename,
+                                             str_length + 1, GFP_KERNEL);
 
                if (!dev->_audiofilename)
                        goto error;
 
-               memcpy(dev->_audiofilename, dev->input_audiofilename,
-                      str_length + 1);
-
                /* Default if filename is empty string */
                if (strcmp(dev->input_audiofilename, "") == 0)
                        dev->_audiofilename = "/root/audioGOOD.wav";
        } else {
                str_length = strlen(_defaultAudioName);
-               dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL);
+               dev->_audiofilename = kmemdup(_defaultAudioName,
+                                             str_length + 1, GFP_KERNEL);
 
                if (!dev->_audiofilename)
                        goto error;
-
-               memcpy(dev->_audiofilename, _defaultAudioName, str_length + 1);
        }
 
        retval = cx25821_sram_channel_setup_upstream_audio(dev, sram_ch,
                                                        _line_size, 0);
 
        dev->audio_upstream_riscbuf_size =
-           AUDIO_RISC_DMA_BUF_SIZE * NUM_AUDIO_PROGS +
-           RISC_SYNC_INSTRUCTION_SIZE;
+               AUDIO_RISC_DMA_BUF_SIZE * NUM_AUDIO_PROGS +
+               RISC_SYNC_INSTRUCTION_SIZE;
        dev->audio_upstream_databuf_size = AUDIO_DATA_BUF_SZ * NUM_AUDIO_PROGS;
 
        /* Allocating buffers and prepare RISC program */
@@ -773,7 +764,7 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
                                                        _line_size);
        if (retval < 0) {
                pr_err("%s: Failed to set up Audio upstream buffers!\n",
-                      dev->name);
+                       dev->name);
                goto error;
        }
        /* Start RISC engine */
index 8eb55b7b88cbd19f010b390521587807edffaa0a..1fc2d24f5110ac400e80f94ec5112ba4f0bc42c7 100644 (file)
 #ifndef __CX25821_AUDIO_H__
 #define __CX25821_AUDIO_H__
 
-#define USE_RISC_NOOP               1
-#define LINES_PER_BUFFER            15
-#define AUDIO_LINE_SIZE             128
+#define USE_RISC_NOOP          1
+#define LINES_PER_BUFFER       15
+#define AUDIO_LINE_SIZE                128
 
 /* Number of buffer programs to use at once. */
-#define NUMBER_OF_PROGRAMS  8
+#define NUMBER_OF_PROGRAMS     8
 
 /*
  * Max size of the RISC program for a buffer. - worst case is 2 writes per line
  * Space is also added for the 4 no-op instructions added on the end.
  */
 #ifndef USE_RISC_NOOP
-#define MAX_BUFFER_PROGRAM_SIZE     \
-       (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \
-       RISC_WRITECR_INSTRUCTION_SIZE * 4)
+#define MAX_BUFFER_PROGRAM_SIZE                                                \
+       (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE +           \
+        RISC_WRITECR_INSTRUCTION_SIZE * 4)
 #endif
 
 /* MAE 12 July 2005 Try to use NOOP RISC instruction instead */
 #ifdef USE_RISC_NOOP
-#define MAX_BUFFER_PROGRAM_SIZE     \
-       (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \
-       RISC_NOOP_INSTRUCTION_SIZE * 4)
+#define MAX_BUFFER_PROGRAM_SIZE                                                \
+       (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE +           \
+        RISC_NOOP_INSTRUCTION_SIZE * 4)
 #endif
 
 /* Sizes of various instructions in bytes.  Used when adding instructions. */
-#define RISC_WRITE_INSTRUCTION_SIZE 12
-#define RISC_JUMP_INSTRUCTION_SIZE  12
-#define RISC_SKIP_INSTRUCTION_SIZE  4
-#define RISC_SYNC_INSTRUCTION_SIZE  4
-#define RISC_WRITECR_INSTRUCTION_SIZE  16
-#define RISC_NOOP_INSTRUCTION_SIZE 4
-
-#define MAX_AUDIO_DMA_BUFFER_SIZE      \
-(MAX_BUFFER_PROGRAM_SIZE * NUMBER_OF_PROGRAMS + RISC_SYNC_INSTRUCTION_SIZE)
+#define RISC_WRITE_INSTRUCTION_SIZE    12
+#define RISC_JUMP_INSTRUCTION_SIZE     12
+#define RISC_SKIP_INSTRUCTION_SIZE     4
+#define RISC_SYNC_INSTRUCTION_SIZE     4
+#define RISC_WRITECR_INSTRUCTION_SIZE  16
+#define RISC_NOOP_INSTRUCTION_SIZE     4
+
+#define MAX_AUDIO_DMA_BUFFER_SIZE                                      \
+       (MAX_BUFFER_PROGRAM_SIZE * NUMBER_OF_PROGRAMS +                 \
+        RISC_SYNC_INSTRUCTION_SIZE)
 
 #endif
index 6ace60313b4907a1f090086d4579bd88d3caf185..99988c988095d0259bf6963a4971b81b376c17f9 100644 (file)
@@ -67,6 +67,6 @@ void cx25821_card_setup(struct cx25821_dev *dev)
        if (dev->i2c_bus[0].i2c_rc == 0) {
                dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
                tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
-                             sizeof(eeprom));
+                               sizeof(eeprom));
        }
 }
index a7fa38f9594e8356a4a180af2d2b5c85fbaa6474..f617474f907317eb39c8071e46660a8c48d23554 100644 (file)
@@ -804,8 +804,8 @@ void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select,
                              u32 format)
 {
        if (channel_select <= 7 && channel_select >= 0) {
-               cx_write(dev->channels[channel_select].
-                       sram_channels->pix_frmt, format);
+               cx_write(dev->channels[channel_select].sram_channels->pix_frmt,
+                               format);
                dev->channels[channel_select].pixel_formats = format;
        }
 }
@@ -855,21 +855,19 @@ static void cx25821_initialize(struct cx25821_dev *dev)
        }
 
        cx25821_sram_channel_setup_audio(dev,
-                               dev->channels[SRAM_CH08].sram_channels,
-                               128, 0);
+                       dev->channels[SRAM_CH08].sram_channels, 128, 0);
 
        cx25821_gpio_init(dev);
 }
 
 static int cx25821_get_resources(struct cx25821_dev *dev)
 {
-       if (request_mem_region
-           (pci_resource_start(dev->pci, 0), pci_resource_len(dev->pci, 0),
-            dev->name))
+       if (request_mem_region(pci_resource_start(dev->pci, 0),
+                               pci_resource_len(dev->pci, 0), dev->name))
                return 0;
 
        pr_err("%s: can't get MMIO memory @ 0x%llx\n",
-              dev->name, (unsigned long long)pci_resource_start(dev->pci, 0));
+               dev->name, (unsigned long long)pci_resource_start(dev->pci, 0));
 
        return -EBUSY;
 }
@@ -972,8 +970,7 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
        dev->lmmio = ioremap(dev->base_io_addr, pci_resource_len(dev->pci, 0));
 
        if (!dev->lmmio) {
-               CX25821_ERR
-                   ("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n");
+               CX25821_ERR("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n");
                cx25821_iounmap(dev);
                return -ENOMEM;
        }
@@ -994,7 +991,7 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
  *  cx25821_i2c_register(&dev->i2c_bus[2]); */
 
        CX25821_INFO("i2c register! bus->i2c_rc = %d\n",
-                    dev->i2c_bus[0].i2c_rc);
+                       dev->i2c_bus[0].i2c_rc);
 
        cx25821_card_setup(dev);
 
@@ -1004,9 +1001,8 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
        cx25821_video_register(dev);
 
        /* register IOCTL device */
-       dev->ioctl_dev =
-          cx25821_vdev_init(dev, dev->pci, &cx25821_videoioctl_template,
-                             "video");
+       dev->ioctl_dev = cx25821_vdev_init(dev, dev->pci,
+                       &cx25821_videoioctl_template, "video");
 
        if (video_register_device
            (dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) {
@@ -1103,16 +1099,15 @@ static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist,
                }
                if (bpl <= sg_dma_len(sg) - offset) {
                        /* fits into current chunk */
-                       *(rp++) =
-                           cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL | bpl);
+                       *(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL |
+                                       bpl);
                        *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
                        *(rp++) = cpu_to_le32(0);       /* bits 63-32 */
                        offset += bpl;
                } else {
                        /* scanline needs to be split */
                        todo = bpl;
-                       *(rp++) =
-                           cpu_to_le32(RISC_WRITE | RISC_SOL |
+                       *(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL |
                                        (sg_dma_len(sg) - offset));
                        *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
                        *(rp++) = cpu_to_le32(0);       /* bits 63-32 */
@@ -1120,8 +1115,8 @@ static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist,
                        offset = 0;
                        sg++;
                        while (todo > sg_dma_len(sg)) {
-                               *(rp++) =
-                                   cpu_to_le32(RISC_WRITE | sg_dma_len(sg));
+                               *(rp++) = cpu_to_le32(RISC_WRITE |
+                                               sg_dma_len(sg));
                                *(rp++) = cpu_to_le32(sg_dma_address(sg));
                                *(rp++) = cpu_to_le32(0);       /* bits 63-32 */
                                todo -= sg_dma_len(sg);
@@ -1160,8 +1155,8 @@ int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
           can cause next bpl to start close to a page border.  First DMA
           region may be smaller than PAGE_SIZE */
        /* write and jump need and extra dword */
-       instructions =
-           fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
+       instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE +
+                       lines);
        instructions += 2;
        rc = btcx_riscmem_alloc(pci, risc, instructions * 12);
 
@@ -1215,8 +1210,8 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist,
 
                if (bpl <= sg_dma_len(sg) - offset) {
                        /* fits into current chunk */
-                       *(rp++) =
-                           cpu_to_le32(RISC_WRITE | sol | RISC_EOL | bpl);
+                       *(rp++) = cpu_to_le32(RISC_WRITE | sol | RISC_EOL |
+                                       bpl);
                        *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
                        *(rp++) = cpu_to_le32(0);       /* bits 63-32 */
                        offset += bpl;
@@ -1224,7 +1219,7 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist,
                        /* scanline needs to be split */
                        todo = bpl;
                        *(rp++) = cpu_to_le32(RISC_WRITE | sol |
-                                             (sg_dma_len(sg) - offset));
+                                       (sg_dma_len(sg) - offset));
                        *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
                        *(rp++) = cpu_to_le32(0);       /* bits 63-32 */
                        todo -= (sg_dma_len(sg) - offset);
@@ -1232,7 +1227,7 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist,
                        sg++;
                        while (todo > sg_dma_len(sg)) {
                                *(rp++) = cpu_to_le32(RISC_WRITE |
-                                                     sg_dma_len(sg));
+                                               sg_dma_len(sg));
                                *(rp++) = cpu_to_le32(sg_dma_address(sg));
                                *(rp++) = cpu_to_le32(0);       /* bits 63-32 */
                                todo -= sg_dma_len(sg);
@@ -1339,8 +1334,8 @@ static irqreturn_t cx25821_irq(int irq, void *dev_id)
                                sram_channels->int_stat);
 
                        if (vid_status)
-                               handled +=
-                               cx25821_video_irq(dev, i, vid_status);
+                               handled += cx25821_video_irq(dev, i,
+                                               vid_status);
 
                        cx_write(PCI_INT_STAT, mask[i]);
                }
@@ -1427,9 +1422,8 @@ static int __devinit cx25821_initdev(struct pci_dev *pci_dev,
                goto fail_irq;
        }
 
-       err =
-           request_irq(pci_dev->irq, cx25821_irq, IRQF_SHARED,
-                       dev->name, dev);
+       err = request_irq(pci_dev->irq, cx25821_irq,
+                       IRQF_SHARED, dev->name, dev);
 
        if (err < 0) {
                pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq);
@@ -1512,6 +1506,5 @@ static void __exit cx25821_fini(void)
        pci_unregister_driver(&cx25821_pci_driver);
 }
 
-
 module_init(cx25821_init);
 module_exit(cx25821_fini);
index 4d3d0ce407856ba5753580e0a81835b0e24ab8bb..12d7300fa1e9e9f8563f065025c088099a707e58 100644 (file)
@@ -252,8 +252,8 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
                } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
                           msgs[i].addr == msgs[i + 1].addr) {
                        /* write then read from same address */
-                       retval =
-                           i2c_sendbytes(i2c_adap, &msgs[i], msgs[i + 1].len);
+                       retval = i2c_sendbytes(i2c_adap, &msgs[i],
+                                       msgs[i + 1].len);
 
                        if (retval < 0)
                                goto err;
@@ -276,10 +276,8 @@ err:
 
 static u32 cx25821_functionality(struct i2c_adapter *adap)
 {
-       return I2C_FUNC_SMBUS_EMUL |
-           I2C_FUNC_I2C |
-           I2C_FUNC_SMBUS_WORD_DATA |
-           I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA;
+       return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_WORD_DATA |
+               I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA;
 }
 
 static struct i2c_algorithm cx25821_i2c_algo_template = {
@@ -300,7 +298,7 @@ static struct i2c_client cx25821_i2c_client_template = {
        .name = "cx25821 internal",
 };
 
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
 int cx25821_i2c_register(struct cx25821_i2c *bus)
 {
        struct cx25821_dev *dev = bus->dev;
index 60d197f575560ab69ea79e49635b47019094b6c0..7a9e6470ba227db92d2a26fc89c83388fa6c3d89 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef _MEDUSA_DEF_H_
 #define _MEDUSA_DEF_H_
 
-/* Video deocder that we supported */
+/* Video decoder that we supported */
 #define VDEC_A         0
 #define VDEC_B         1
 #define VDEC_C         2
@@ -34,9 +34,9 @@
 #define VDEC_H         7
 
 /* end of display sequence */
-#define END_OF_SEQ                                     0xF;
+#define END_OF_SEQ     0xF;
 
 /* registry string size */
-#define MAX_REGISTRY_SZ                                        40;
+#define MAX_REGISTRY_SZ        40;
 
 #endif
index 1c1c228352d10cb85e96436a9520c2fbf7185d58..c98ac946b277d9e33a4f8d86c29a3c7ada7fe4ff 100644 (file)
 #define        HOST_REGISTER2                          0x0001
 
 /* Chip Configuration Registers */
-#define        CHIP_CTRL                                       0x0100
-#define        AFE_AB_CTRL                                     0x0104
-#define        AFE_CD_CTRL                                     0x0108
-#define        AFE_EF_CTRL                                     0x010C
-#define        AFE_GH_CTRL                                     0x0110
+#define        CHIP_CTRL                               0x0100
+#define        AFE_AB_CTRL                             0x0104
+#define        AFE_CD_CTRL                             0x0108
+#define        AFE_EF_CTRL                             0x010C
+#define        AFE_GH_CTRL                             0x0110
 #define        DENC_AB_CTRL                            0x0114
-#define        BYP_AB_CTRL                                     0x0118
-#define        MON_A_CTRL                                      0x011C
-#define        DISP_SEQ_A                                      0x0120
-#define        DISP_SEQ_B                                      0x0124
-#define        DISP_AB_CNT                                     0x0128
-#define        DISP_CD_CNT                                     0x012C
-#define        DISP_EF_CNT                                     0x0130
-#define        DISP_GH_CNT                                     0x0134
-#define        DISP_IJ_CNT                                     0x0138
-#define        PIN_OE_CTRL                                     0x013C
+#define        BYP_AB_CTRL                             0x0118
+#define        MON_A_CTRL                              0x011C
+#define        DISP_SEQ_A                              0x0120
+#define        DISP_SEQ_B                              0x0124
+#define        DISP_AB_CNT                             0x0128
+#define        DISP_CD_CNT                             0x012C
+#define        DISP_EF_CNT                             0x0130
+#define        DISP_GH_CNT                             0x0134
+#define        DISP_IJ_CNT                             0x0138
+#define        PIN_OE_CTRL                             0x013C
 #define        PIN_SPD_CTRL                            0x0140
 #define        PIN_SPD_CTRL2                           0x0144
 #define        IRQ_STAT_CTRL                           0x0148
@@ -51,8 +51,8 @@
 #define        POWER_CTRL_CD                           0x0150
 #define        POWER_CTRL_EF                           0x0154
 #define        POWER_CTRL_GH                           0x0158
-#define        TUNE_CTRL                                       0x015C
-#define        BIAS_CTRL                                       0x0160
+#define        TUNE_CTRL                               0x015C
+#define        BIAS_CTRL                               0x0160
 #define        AFE_AB_DIAG_CTRL                        0x0164
 #define        AFE_CD_DIAG_CTRL                        0x0168
 #define        AFE_EF_DIAG_CTRL                        0x016C
 #define        PLL_CD_DIAG_CTRL                        0x0178
 #define        PLL_EF_DIAG_CTRL                        0x017C
 #define        PLL_GH_DIAG_CTRL                        0x0180
-#define        TEST_CTRL                                       0x0184
-#define        BIST_STAT                                       0x0188
-#define        BIST_STAT2                                      0x018C
-#define        BIST_VID_PLL_AB_STAT            0x0190
-#define        BIST_VID_PLL_CD_STAT            0x0194
-#define        BIST_VID_PLL_EF_STAT            0x0198
-#define        BIST_VID_PLL_GH_STAT            0x019C
+#define        TEST_CTRL                               0x0184
+#define        BIST_STAT                               0x0188
+#define        BIST_STAT2                              0x018C
+#define        BIST_VID_PLL_AB_STAT                    0x0190
+#define        BIST_VID_PLL_CD_STAT                    0x0194
+#define        BIST_VID_PLL_EF_STAT                    0x0198
+#define        BIST_VID_PLL_GH_STAT                    0x019C
 #define        DLL_DIAG_CTRL                           0x01A0
 #define        DEV_CH_ID_CTRL                          0x01A4
 #define        ABIST_CTRL_STATUS                       0x01A8
-#define        ABIST_FREQ                                      0x01AC
+#define        ABIST_FREQ                              0x01AC
 #define        ABIST_GOERT_SHIFT                       0x01B0
 #define        ABIST_COEF12                            0x01B4
 #define        ABIST_COEF34                            0x01B8
 #define        ABIST_CLAMP_E                           0x01F4
 #define        ABIST_CLAMP_F                           0x01F8
 
-/*              Digital Video Encoder A Registers */
-#define        DENC_A_REG_1                                    0x0200
-#define        DENC_A_REG_2                                    0x0204
-#define        DENC_A_REG_3                                    0x0208
-#define        DENC_A_REG_4                                    0x020C
-#define        DENC_A_REG_5                                    0x0210
-#define        DENC_A_REG_6                                    0x0214
-#define        DENC_A_REG_7                                    0x0218
-#define        DENC_A_REG_8                                    0x021C
+/* Digital Video Encoder A Registers */
+#define        DENC_A_REG_1                            0x0200
+#define        DENC_A_REG_2                            0x0204
+#define        DENC_A_REG_3                            0x0208
+#define        DENC_A_REG_4                            0x020C
+#define        DENC_A_REG_5                            0x0210
+#define        DENC_A_REG_6                            0x0214
+#define        DENC_A_REG_7                            0x0218
+#define        DENC_A_REG_8                            0x021C
 
-/*      Digital Video Encoder B Registers */
-#define        DENC_B_REG_1                                    0x0300
-#define        DENC_B_REG_2                                    0x0304
-#define        DENC_B_REG_3                                    0x0308
-#define        DENC_B_REG_4                                    0x030C
-#define        DENC_B_REG_5                                    0x0310
-#define        DENC_B_REG_6                                    0x0314
-#define        DENC_B_REG_7                                    0x0318
-#define        DENC_B_REG_8                                    0x031C
+/* Digital Video Encoder B Registers */
+#define        DENC_B_REG_1                            0x0300
+#define        DENC_B_REG_2                            0x0304
+#define        DENC_B_REG_3                            0x0308
+#define        DENC_B_REG_4                            0x030C
+#define        DENC_B_REG_5                            0x0310
+#define        DENC_B_REG_6                            0x0314
+#define        DENC_B_REG_7                            0x0318
+#define        DENC_B_REG_8                            0x031C
 
-/*              Video Decoder A Registers */
-#define        MODE_CTRL                                               0x1000
-#define        OUT_CTRL1                                               0x1004
-#define        OUT_CTRL_NS                                             0x1008
-#define        GEN_STAT                                                0x100C
-#define        INT_STAT_MASK                                   0x1010
-#define        LUMA_CTRL                                               0x1014
-#define        CHROMA_CTRL                                             0x1018
-#define        CRUSH_CTRL                                              0x101C
-#define        HORIZ_TIM_CTRL                                  0x1020
-#define        VERT_TIM_CTRL                                   0x1024
-#define        MISC_TIM_CTRL                                   0x1028
-#define        FIELD_COUNT                                             0x102C
-#define        HSCALE_CTRL                                             0x1030
-#define        VSCALE_CTRL                                             0x1034
-#define        MAN_VGA_CTRL                                    0x1038
-#define        MAN_AGC_CTRL                                    0x103C
-#define        DFE_CTRL1                                               0x1040
-#define        DFE_CTRL2                                               0x1044
-#define        DFE_CTRL3                                               0x1048
-#define        PLL_CTRL                                                0x104C
-#define        PLL_CTRL_FAST                                   0x1050
-#define        HTL_CTRL                                                0x1054
-#define        SRC_CFG                                                 0x1058
-#define        SC_STEP_SIZE                                    0x105C
-#define        SC_CONVERGE_CTRL                                0x1060
-#define        SC_LOOP_CTRL                                    0x1064
-#define        COMB_2D_HFS_CFG                                 0x1068
-#define        COMB_2D_HFD_CFG                                 0x106C
-#define        COMB_2D_LF_CFG                                  0x1070
-#define        COMB_2D_BLEND                                   0x1074
-#define        COMB_MISC_CTRL                                  0x1078
+/* Video Decoder A Registers */
+#define        MODE_CTRL                               0x1000
+#define        OUT_CTRL1                               0x1004
+#define        OUT_CTRL_NS                             0x1008
+#define        GEN_STAT                                0x100C
+#define        INT_STAT_MASK                           0x1010
+#define        LUMA_CTRL                               0x1014
+#define        CHROMA_CTRL                             0x1018
+#define        CRUSH_CTRL                              0x101C
+#define        HORIZ_TIM_CTRL                          0x1020
+#define        VERT_TIM_CTRL                           0x1024
+#define        MISC_TIM_CTRL                           0x1028
+#define        FIELD_COUNT                             0x102C
+#define        HSCALE_CTRL                             0x1030
+#define        VSCALE_CTRL                             0x1034
+#define        MAN_VGA_CTRL                            0x1038
+#define        MAN_AGC_CTRL                            0x103C
+#define        DFE_CTRL1                               0x1040
+#define        DFE_CTRL2                               0x1044
+#define        DFE_CTRL3                               0x1048
+#define        PLL_CTRL                                0x104C
+#define        PLL_CTRL_FAST                           0x1050
+#define        HTL_CTRL                                0x1054
+#define        SRC_CFG                                 0x1058
+#define        SC_STEP_SIZE                            0x105C
+#define        SC_CONVERGE_CTRL                        0x1060
+#define        SC_LOOP_CTRL                            0x1064
+#define        COMB_2D_HFS_CFG                         0x1068
+#define        COMB_2D_HFD_CFG                         0x106C
+#define        COMB_2D_LF_CFG                          0x1070
+#define        COMB_2D_BLEND                           0x1074
+#define        COMB_MISC_CTRL                          0x1078
 #define        COMB_FLAT_THRESH_CTRL                   0x107C
-#define        COMB_TEST                                               0x1080
-#define        BP_MISC_CTRL                                    0x1084
-#define        VCR_DET_CTRL                                    0x1088
-#define        NOISE_DET_CTRL                                  0x108C
+#define        COMB_TEST                               0x1080
+#define        BP_MISC_CTRL                            0x1084
+#define        VCR_DET_CTRL                            0x1088
+#define        NOISE_DET_CTRL                          0x108C
 #define        COMB_FLAT_NOISE_CTRL                    0x1090
-#define        VERSION                                                 0x11F8
-#define        SOFT_RST_CTRL                                   0x11FC
+#define        VERSION                                 0x11F8
+#define        SOFT_RST_CTRL                           0x11FC
 
-/*      Video Decoder B Registers */
-#define        VDEC_B_MODE_CTRL                                0x1200
-#define        VDEC_B_OUT_CTRL1                                0x1204
-#define        VDEC_B_OUT_CTRL_NS                              0x1208
-#define        VDEC_B_GEN_STAT                                 0x120C
+/* Video Decoder B Registers */
+#define        VDEC_B_MODE_CTRL                        0x1200
+#define        VDEC_B_OUT_CTRL1                        0x1204
+#define        VDEC_B_OUT_CTRL_NS                      0x1208
+#define        VDEC_B_GEN_STAT                         0x120C
 #define        VDEC_B_INT_STAT_MASK                    0x1210
-#define        VDEC_B_LUMA_CTRL                                0x1214
-#define        VDEC_B_CHROMA_CTRL                              0x1218
-#define        VDEC_B_CRUSH_CTRL                               0x121C
+#define        VDEC_B_LUMA_CTRL                        0x1214
+#define        VDEC_B_CHROMA_CTRL                      0x1218
+#define        VDEC_B_CRUSH_CTRL                       0x121C
 #define        VDEC_B_HORIZ_TIM_CTRL                   0x1220
 #define        VDEC_B_VERT_TIM_CTRL                    0x1224
 #define        VDEC_B_MISC_TIM_CTRL                    0x1228
-#define        VDEC_B_FIELD_COUNT                              0x122C
-#define        VDEC_B_HSCALE_CTRL                              0x1230
-#define        VDEC_B_VSCALE_CTRL                              0x1234
-#define        VDEC_B_MAN_VGA_CTRL                             0x1238
-#define        VDEC_B_MAN_AGC_CTRL                             0x123C
-#define        VDEC_B_DFE_CTRL1                                0x1240
-#define        VDEC_B_DFE_CTRL2                                0x1244
-#define        VDEC_B_DFE_CTRL3                                0x1248
-#define        VDEC_B_PLL_CTRL                                 0x124C
+#define        VDEC_B_FIELD_COUNT                      0x122C
+#define        VDEC_B_HSCALE_CTRL                      0x1230
+#define        VDEC_B_VSCALE_CTRL                      0x1234
+#define        VDEC_B_MAN_VGA_CTRL                     0x1238
+#define        VDEC_B_MAN_AGC_CTRL                     0x123C
+#define        VDEC_B_DFE_CTRL1                        0x1240
+#define        VDEC_B_DFE_CTRL2                        0x1244
+#define        VDEC_B_DFE_CTRL3                        0x1248
+#define        VDEC_B_PLL_CTRL                         0x124C
 #define        VDEC_B_PLL_CTRL_FAST                    0x1250
-#define        VDEC_B_HTL_CTRL                                 0x1254
-#define        VDEC_B_SRC_CFG                                  0x1258
-#define        VDEC_B_SC_STEP_SIZE                             0x125C
+#define        VDEC_B_HTL_CTRL                         0x1254
+#define        VDEC_B_SRC_CFG                          0x1258
+#define        VDEC_B_SC_STEP_SIZE                     0x125C
 #define        VDEC_B_SC_CONVERGE_CTRL                 0x1260
-#define        VDEC_B_SC_LOOP_CTRL                             0x1264
+#define        VDEC_B_SC_LOOP_CTRL                     0x1264
 #define        VDEC_B_COMB_2D_HFS_CFG                  0x1268
 #define        VDEC_B_COMB_2D_HFD_CFG                  0x126C
 #define        VDEC_B_COMB_2D_LF_CFG                   0x1270
 #define        VDEC_B_COMB_2D_BLEND                    0x1274
 #define        VDEC_B_COMB_MISC_CTRL                   0x1278
-#define        VDEC_B_COMB_FLAT_THRESH_CTRL    0x127C
-#define        VDEC_B_COMB_TEST                                0x1280
-#define        VDEC_B_BP_MISC_CTRL                             0x1284
-#define        VDEC_B_VCR_DET_CTRL                             0x1288
+#define        VDEC_B_COMB_FLAT_THRESH_CTRL            0x127C
+#define        VDEC_B_COMB_TEST                        0x1280
+#define        VDEC_B_BP_MISC_CTRL                     0x1284
+#define        VDEC_B_VCR_DET_CTRL                     0x1288
 #define        VDEC_B_NOISE_DET_CTRL                   0x128C
 #define        VDEC_B_COMB_FLAT_NOISE_CTRL             0x1290
-#define        VDEC_B_VERSION                                  0x13F8
+#define        VDEC_B_VERSION                          0x13F8
 #define        VDEC_B_SOFT_RST_CTRL                    0x13FC
 
 /* Video Decoder C Registers */
-#define        VDEC_C_MODE_CTRL                                0x1400
-#define        VDEC_C_OUT_CTRL1                                0x1404
-#define        VDEC_C_OUT_CTRL_NS                              0x1408
-#define        VDEC_C_GEN_STAT                                 0x140C
+#define        VDEC_C_MODE_CTRL                        0x1400
+#define        VDEC_C_OUT_CTRL1                        0x1404
+#define        VDEC_C_OUT_CTRL_NS                      0x1408
+#define        VDEC_C_GEN_STAT                         0x140C
 #define        VDEC_C_INT_STAT_MASK                    0x1410
-#define VDEC_C_LUMA_CTRL                               0x1414
-#define VDEC_C_CHROMA_CTRL                             0x1418
-#define        VDEC_C_CRUSH_CTRL                               0x141C
+#define VDEC_C_LUMA_CTRL                       0x1414
+#define VDEC_C_CHROMA_CTRL                     0x1418
+#define        VDEC_C_CRUSH_CTRL                       0x141C
 #define        VDEC_C_HORIZ_TIM_CTRL                   0x1420
 #define        VDEC_C_VERT_TIM_CTRL                    0x1424
 #define        VDEC_C_MISC_TIM_CTRL                    0x1428
-#define        VDEC_C_FIELD_COUNT                              0x142C
-#define        VDEC_C_HSCALE_CTRL                              0x1430
-#define        VDEC_C_VSCALE_CTRL                              0x1434
-#define        VDEC_C_MAN_VGA_CTRL                             0x1438
-#define        VDEC_C_MAN_AGC_CTRL                             0x143C
-#define        VDEC_C_DFE_CTRL1                                0x1440
-#define        VDEC_C_DFE_CTRL2                                0x1444
-#define        VDEC_C_DFE_CTRL3                                0x1448
-#define        VDEC_C_PLL_CTRL                                 0x144C
+#define        VDEC_C_FIELD_COUNT                      0x142C
+#define        VDEC_C_HSCALE_CTRL                      0x1430
+#define        VDEC_C_VSCALE_CTRL                      0x1434
+#define        VDEC_C_MAN_VGA_CTRL                     0x1438
+#define        VDEC_C_MAN_AGC_CTRL                     0x143C
+#define        VDEC_C_DFE_CTRL1                        0x1440
+#define        VDEC_C_DFE_CTRL2                        0x1444
+#define        VDEC_C_DFE_CTRL3                        0x1448
+#define        VDEC_C_PLL_CTRL                         0x144C
 #define        VDEC_C_PLL_CTRL_FAST                    0x1450
-#define        VDEC_C_HTL_CTRL                                 0x1454
-#define        VDEC_C_SRC_CFG                                  0x1458
-#define        VDEC_C_SC_STEP_SIZE                             0x145C
+#define        VDEC_C_HTL_CTRL                         0x1454
+#define        VDEC_C_SRC_CFG                          0x1458
+#define        VDEC_C_SC_STEP_SIZE                     0x145C
 #define        VDEC_C_SC_CONVERGE_CTRL                 0x1460
-#define        VDEC_C_SC_LOOP_CTRL                             0x1464
+#define        VDEC_C_SC_LOOP_CTRL                     0x1464
 #define        VDEC_C_COMB_2D_HFS_CFG                  0x1468
 #define        VDEC_C_COMB_2D_HFD_CFG                  0x146C
 #define        VDEC_C_COMB_2D_LF_CFG                   0x1470
 #define        VDEC_C_COMB_2D_BLEND                    0x1474
 #define        VDEC_C_COMB_MISC_CTRL                   0x1478
-#define        VDEC_C_COMB_FLAT_THRESH_CTRL    0x147C
-#define        VDEC_C_COMB_TEST                                0x1480
-#define        VDEC_C_BP_MISC_CTRL                             0x1484
-#define        VDEC_C_VCR_DET_CTRL                             0x1488
+#define        VDEC_C_COMB_FLAT_THRESH_CTRL            0x147C
+#define        VDEC_C_COMB_TEST                        0x1480
+#define        VDEC_C_BP_MISC_CTRL                     0x1484
+#define        VDEC_C_VCR_DET_CTRL                     0x1488
 #define        VDEC_C_NOISE_DET_CTRL                   0x148C
 #define        VDEC_C_COMB_FLAT_NOISE_CTRL             0x1490
-#define        VDEC_C_VERSION                                  0x15F8
+#define        VDEC_C_VERSION                          0x15F8
 #define        VDEC_C_SOFT_RST_CTRL                    0x15FC
 
 /* Video Decoder D Registers */
-#define VDEC_D_MODE_CTRL                               0x1600
-#define VDEC_D_OUT_CTRL1                               0x1604
-#define VDEC_D_OUT_CTRL_NS                             0x1608
-#define VDEC_D_GEN_STAT                                        0x160C
+#define VDEC_D_MODE_CTRL                       0x1600
+#define VDEC_D_OUT_CTRL1                       0x1604
+#define VDEC_D_OUT_CTRL_NS                     0x1608
+#define VDEC_D_GEN_STAT                                0x160C
 #define VDEC_D_INT_STAT_MASK                   0x1610
-#define VDEC_D_LUMA_CTRL                               0x1614
-#define VDEC_D_CHROMA_CTRL                             0x1618
-#define VDEC_D_CRUSH_CTRL                              0x161C
+#define VDEC_D_LUMA_CTRL                       0x1614
+#define VDEC_D_CHROMA_CTRL                     0x1618
+#define VDEC_D_CRUSH_CTRL                      0x161C
 #define VDEC_D_HORIZ_TIM_CTRL                  0x1620
 #define VDEC_D_VERT_TIM_CTRL                   0x1624
 #define VDEC_D_MISC_TIM_CTRL                   0x1628
-#define VDEC_D_FIELD_COUNT                             0x162C
-#define VDEC_D_HSCALE_CTRL                             0x1630
-#define VDEC_D_VSCALE_CTRL                             0x1634
-#define VDEC_D_MAN_VGA_CTRL                            0x1638
-#define VDEC_D_MAN_AGC_CTRL                            0x163C
-#define VDEC_D_DFE_CTRL1                               0x1640
-#define VDEC_D_DFE_CTRL2                               0x1644
-#define VDEC_D_DFE_CTRL3                               0x1648
-#define VDEC_D_PLL_CTRL                                        0x164C
+#define VDEC_D_FIELD_COUNT                     0x162C
+#define VDEC_D_HSCALE_CTRL                     0x1630
+#define VDEC_D_VSCALE_CTRL                     0x1634
+#define VDEC_D_MAN_VGA_CTRL                    0x1638
+#define VDEC_D_MAN_AGC_CTRL                    0x163C
+#define VDEC_D_DFE_CTRL1                       0x1640
+#define VDEC_D_DFE_CTRL2                       0x1644
+#define VDEC_D_DFE_CTRL3                       0x1648
+#define VDEC_D_PLL_CTRL                                0x164C
 #define VDEC_D_PLL_CTRL_FAST                   0x1650
-#define VDEC_D_HTL_CTRL                                        0x1654
-#define VDEC_D_SRC_CFG                                 0x1658
-#define VDEC_D_SC_STEP_SIZE                            0x165C
+#define VDEC_D_HTL_CTRL                                0x1654
+#define VDEC_D_SRC_CFG                         0x1658
+#define VDEC_D_SC_STEP_SIZE                    0x165C
 #define VDEC_D_SC_CONVERGE_CTRL                        0x1660
-#define VDEC_D_SC_LOOP_CTRL                            0x1664
+#define VDEC_D_SC_LOOP_CTRL                    0x1664
 #define VDEC_D_COMB_2D_HFS_CFG                 0x1668
 #define VDEC_D_COMB_2D_HFD_CFG                 0x166C
 #define VDEC_D_COMB_2D_LF_CFG                  0x1670
 #define VDEC_D_COMB_2D_BLEND                   0x1674
 #define VDEC_D_COMB_MISC_CTRL                  0x1678
-#define VDEC_D_COMB_FLAT_THRESH_CTRL   0x167C
-#define VDEC_D_COMB_TEST                               0x1680
-#define VDEC_D_BP_MISC_CTRL                            0x1684
-#define VDEC_D_VCR_DET_CTRL                            0x1688
+#define VDEC_D_COMB_FLAT_THRESH_CTRL           0x167C
+#define VDEC_D_COMB_TEST                       0x1680
+#define VDEC_D_BP_MISC_CTRL                    0x1684
+#define VDEC_D_VCR_DET_CTRL                    0x1688
 #define VDEC_D_NOISE_DET_CTRL                  0x168C
 #define VDEC_D_COMB_FLAT_NOISE_CTRL            0x1690
-#define VDEC_D_VERSION                                 0x17F8
+#define VDEC_D_VERSION                         0x17F8
 #define VDEC_D_SOFT_RST_CTRL                   0x17FC
 
 /* Video Decoder E Registers */
-#define        VDEC_E_MODE_CTRL                                0x1800
-#define        VDEC_E_OUT_CTRL1                                0x1804
-#define        VDEC_E_OUT_CTRL_NS                              0x1808
-#define        VDEC_E_GEN_STAT                                 0x180C
+#define        VDEC_E_MODE_CTRL                        0x1800
+#define        VDEC_E_OUT_CTRL1                        0x1804
+#define        VDEC_E_OUT_CTRL_NS                      0x1808
+#define        VDEC_E_GEN_STAT                         0x180C
 #define        VDEC_E_INT_STAT_MASK                    0x1810
-#define        VDEC_E_LUMA_CTRL                                0x1814
-#define        VDEC_E_CHROMA_CTRL                              0x1818
-#define        VDEC_E_CRUSH_CTRL                               0x181C
+#define        VDEC_E_LUMA_CTRL                        0x1814
+#define        VDEC_E_CHROMA_CTRL                      0x1818
+#define        VDEC_E_CRUSH_CTRL                       0x181C
 #define        VDEC_E_HORIZ_TIM_CTRL                   0x1820
 #define        VDEC_E_VERT_TIM_CTRL                    0x1824
 #define        VDEC_E_MISC_TIM_CTRL                    0x1828
-#define        VDEC_E_FIELD_COUNT                              0x182C
-#define        VDEC_E_HSCALE_CTRL                              0x1830
-#define        VDEC_E_VSCALE_CTRL                              0x1834
-#define        VDEC_E_MAN_VGA_CTRL                             0x1838
-#define        VDEC_E_MAN_AGC_CTRL                             0x183C
-#define        VDEC_E_DFE_CTRL1                                0x1840
-#define        VDEC_E_DFE_CTRL2                                0x1844
-#define        VDEC_E_DFE_CTRL3                                0x1848
-#define        VDEC_E_PLL_CTRL                                 0x184C
+#define        VDEC_E_FIELD_COUNT                      0x182C
+#define        VDEC_E_HSCALE_CTRL                      0x1830
+#define        VDEC_E_VSCALE_CTRL                      0x1834
+#define        VDEC_E_MAN_VGA_CTRL                     0x1838
+#define        VDEC_E_MAN_AGC_CTRL                     0x183C
+#define        VDEC_E_DFE_CTRL1                        0x1840
+#define        VDEC_E_DFE_CTRL2                        0x1844
+#define        VDEC_E_DFE_CTRL3                        0x1848
+#define        VDEC_E_PLL_CTRL                         0x184C
 #define        VDEC_E_PLL_CTRL_FAST                    0x1850
-#define        VDEC_E_HTL_CTRL                                 0x1854
-#define        VDEC_E_SRC_CFG                                  0x1858
-#define        VDEC_E_SC_STEP_SIZE                             0x185C
+#define        VDEC_E_HTL_CTRL                         0x1854
+#define        VDEC_E_SRC_CFG                          0x1858
+#define        VDEC_E_SC_STEP_SIZE                     0x185C
 #define        VDEC_E_SC_CONVERGE_CTRL                 0x1860
-#define        VDEC_E_SC_LOOP_CTRL                             0x1864
+#define        VDEC_E_SC_LOOP_CTRL                     0x1864
 #define        VDEC_E_COMB_2D_HFS_CFG                  0x1868
 #define        VDEC_E_COMB_2D_HFD_CFG                  0x186C
 #define        VDEC_E_COMB_2D_LF_CFG                   0x1870
 #define        VDEC_E_COMB_2D_BLEND                    0x1874
 #define        VDEC_E_COMB_MISC_CTRL                   0x1878
-#define        VDEC_E_COMB_FLAT_THRESH_CTRL    0x187C
-#define        VDEC_E_COMB_TEST                                0x1880
-#define        VDEC_E_BP_MISC_CTRL                             0x1884
-#define        VDEC_E_VCR_DET_CTRL                             0x1888
+#define        VDEC_E_COMB_FLAT_THRESH_CTRL            0x187C
+#define        VDEC_E_COMB_TEST                        0x1880
+#define        VDEC_E_BP_MISC_CTRL                     0x1884
+#define        VDEC_E_VCR_DET_CTRL                     0x1888
 #define        VDEC_E_NOISE_DET_CTRL                   0x188C
 #define        VDEC_E_COMB_FLAT_NOISE_CTRL             0x1890
-#define        VDEC_E_VERSION                                  0x19F8
+#define        VDEC_E_VERSION                          0x19F8
 #define        VDEC_E_SOFT_RST_CTRL                    0x19FC
 
 /* Video Decoder F Registers */
-#define        VDEC_F_MODE_CTRL                                0x1A00
-#define        VDEC_F_OUT_CTRL1                                0x1A04
-#define        VDEC_F_OUT_CTRL_NS                              0x1A08
-#define        VDEC_F_GEN_STAT                                 0x1A0C
+#define        VDEC_F_MODE_CTRL                        0x1A00
+#define        VDEC_F_OUT_CTRL1                        0x1A04
+#define        VDEC_F_OUT_CTRL_NS                      0x1A08
+#define        VDEC_F_GEN_STAT                         0x1A0C
 #define        VDEC_F_INT_STAT_MASK                    0x1A10
-#define        VDEC_F_LUMA_CTRL                                0x1A14
-#define        VDEC_F_CHROMA_CTRL                              0x1A18
-#define        VDEC_F_CRUSH_CTRL                               0x1A1C
+#define        VDEC_F_LUMA_CTRL                        0x1A14
+#define        VDEC_F_CHROMA_CTRL                      0x1A18
+#define        VDEC_F_CRUSH_CTRL                       0x1A1C
 #define        VDEC_F_HORIZ_TIM_CTRL                   0x1A20
 #define        VDEC_F_VERT_TIM_CTRL                    0x1A24
 #define        VDEC_F_MISC_TIM_CTRL                    0x1A28
-#define        VDEC_F_FIELD_COUNT                              0x1A2C
-#define        VDEC_F_HSCALE_CTRL                              0x1A30
-#define        VDEC_F_VSCALE_CTRL                              0x1A34
-#define        VDEC_F_MAN_VGA_CTRL                             0x1A38
-#define        VDEC_F_MAN_AGC_CTRL                             0x1A3C
-#define        VDEC_F_DFE_CTRL1                                0x1A40
-#define        VDEC_F_DFE_CTRL2                                0x1A44
-#define        VDEC_F_DFE_CTRL3                                0x1A48
-#define        VDEC_F_PLL_CTRL                                 0x1A4C
+#define        VDEC_F_FIELD_COUNT                      0x1A2C
+#define        VDEC_F_HSCALE_CTRL                      0x1A30
+#define        VDEC_F_VSCALE_CTRL                      0x1A34
+#define        VDEC_F_MAN_VGA_CTRL                     0x1A38
+#define        VDEC_F_MAN_AGC_CTRL                     0x1A3C
+#define        VDEC_F_DFE_CTRL1                        0x1A40
+#define        VDEC_F_DFE_CTRL2                        0x1A44
+#define        VDEC_F_DFE_CTRL3                        0x1A48
+#define        VDEC_F_PLL_CTRL                         0x1A4C
 #define        VDEC_F_PLL_CTRL_FAST                    0x1A50
-#define        VDEC_F_HTL_CTRL                                 0x1A54
-#define        VDEC_F_SRC_CFG                                  0x1A58
-#define        VDEC_F_SC_STEP_SIZE                             0x1A5C
+#define        VDEC_F_HTL_CTRL                         0x1A54
+#define        VDEC_F_SRC_CFG                          0x1A58
+#define        VDEC_F_SC_STEP_SIZE                     0x1A5C
 #define        VDEC_F_SC_CONVERGE_CTRL                 0x1A60
-#define        VDEC_F_SC_LOOP_CTRL                             0x1A64
+#define        VDEC_F_SC_LOOP_CTRL                     0x1A64
 #define        VDEC_F_COMB_2D_HFS_CFG                  0x1A68
 #define        VDEC_F_COMB_2D_HFD_CFG                  0x1A6C
 #define        VDEC_F_COMB_2D_LF_CFG                   0x1A70
 #define        VDEC_F_COMB_2D_BLEND                    0x1A74
 #define        VDEC_F_COMB_MISC_CTRL                   0x1A78
-#define        VDEC_F_COMB_FLAT_THRESH_CTRL    0x1A7C
-#define        VDEC_F_COMB_TEST                                0x1A80
-#define        VDEC_F_BP_MISC_CTRL                             0x1A84
-#define        VDEC_F_VCR_DET_CTRL                             0x1A88
+#define        VDEC_F_COMB_FLAT_THRESH_CTRL            0x1A7C
+#define        VDEC_F_COMB_TEST                        0x1A80
+#define        VDEC_F_BP_MISC_CTRL                     0x1A84
+#define        VDEC_F_VCR_DET_CTRL                     0x1A88
 #define        VDEC_F_NOISE_DET_CTRL                   0x1A8C
 #define        VDEC_F_COMB_FLAT_NOISE_CTRL             0x1A90
-#define        VDEC_F_VERSION                                  0x1BF8
+#define        VDEC_F_VERSION                          0x1BF8
 #define        VDEC_F_SOFT_RST_CTRL                    0x1BFC
 
 /* Video Decoder G Registers */
-#define        VDEC_G_MODE_CTRL                                0x1C00
-#define        VDEC_G_OUT_CTRL1                                0x1C04
-#define        VDEC_G_OUT_CTRL_NS                              0x1C08
-#define        VDEC_G_GEN_STAT                                 0x1C0C
+#define        VDEC_G_MODE_CTRL                        0x1C00
+#define        VDEC_G_OUT_CTRL1                        0x1C04
+#define        VDEC_G_OUT_CTRL_NS                      0x1C08
+#define        VDEC_G_GEN_STAT                         0x1C0C
 #define        VDEC_G_INT_STAT_MASK                    0x1C10
-#define        VDEC_G_LUMA_CTRL                                0x1C14
-#define        VDEC_G_CHROMA_CTRL                              0x1C18
-#define        VDEC_G_CRUSH_CTRL                               0x1C1C
+#define        VDEC_G_LUMA_CTRL                        0x1C14
+#define        VDEC_G_CHROMA_CTRL                      0x1C18
+#define        VDEC_G_CRUSH_CTRL                       0x1C1C
 #define        VDEC_G_HORIZ_TIM_CTRL                   0x1C20
 #define        VDEC_G_VERT_TIM_CTRL                    0x1C24
 #define        VDEC_G_MISC_TIM_CTRL                    0x1C28
-#define        VDEC_G_FIELD_COUNT                              0x1C2C
-#define        VDEC_G_HSCALE_CTRL                              0x1C30
-#define        VDEC_G_VSCALE_CTRL                              0x1C34
-#define        VDEC_G_MAN_VGA_CTRL                             0x1C38
-#define        VDEC_G_MAN_AGC_CTRL                             0x1C3C
-#define        VDEC_G_DFE_CTRL1                                0x1C40
-#define        VDEC_G_DFE_CTRL2                                0x1C44
-#define        VDEC_G_DFE_CTRL3                                0x1C48
-#define        VDEC_G_PLL_CTRL                                 0x1C4C
+#define        VDEC_G_FIELD_COUNT                      0x1C2C
+#define        VDEC_G_HSCALE_CTRL                      0x1C30
+#define        VDEC_G_VSCALE_CTRL                      0x1C34
+#define        VDEC_G_MAN_VGA_CTRL                     0x1C38
+#define        VDEC_G_MAN_AGC_CTRL                     0x1C3C
+#define        VDEC_G_DFE_CTRL1                        0x1C40
+#define        VDEC_G_DFE_CTRL2                        0x1C44
+#define        VDEC_G_DFE_CTRL3                        0x1C48
+#define        VDEC_G_PLL_CTRL                         0x1C4C
 #define        VDEC_G_PLL_CTRL_FAST                    0x1C50
-#define        VDEC_G_HTL_CTRL                                 0x1C54
-#define        VDEC_G_SRC_CFG                                  0x1C58
-#define        VDEC_G_SC_STEP_SIZE                             0x1C5C
+#define        VDEC_G_HTL_CTRL                         0x1C54
+#define        VDEC_G_SRC_CFG                          0x1C58
+#define        VDEC_G_SC_STEP_SIZE                     0x1C5C
 #define        VDEC_G_SC_CONVERGE_CTRL                 0x1C60
-#define        VDEC_G_SC_LOOP_CTRL                             0x1C64
+#define        VDEC_G_SC_LOOP_CTRL                     0x1C64
 #define        VDEC_G_COMB_2D_HFS_CFG                  0x1C68
 #define        VDEC_G_COMB_2D_HFD_CFG                  0x1C6C
 #define        VDEC_G_COMB_2D_LF_CFG                   0x1C70
 #define        VDEC_G_COMB_2D_BLEND                    0x1C74
 #define        VDEC_G_COMB_MISC_CTRL                   0x1C78
-#define        VDEC_G_COMB_FLAT_THRESH_CTRL    0x1C7C
-#define        VDEC_G_COMB_TEST                                0x1C80
-#define        VDEC_G_BP_MISC_CTRL                             0x1C84
-#define        VDEC_G_VCR_DET_CTRL                             0x1C88
+#define        VDEC_G_COMB_FLAT_THRESH_CTRL            0x1C7C
+#define        VDEC_G_COMB_TEST                        0x1C80
+#define        VDEC_G_BP_MISC_CTRL                     0x1C84
+#define        VDEC_G_VCR_DET_CTRL                     0x1C88
 #define        VDEC_G_NOISE_DET_CTRL                   0x1C8C
 #define        VDEC_G_COMB_FLAT_NOISE_CTRL             0x1C90
-#define        VDEC_G_VERSION                                  0x1DF8
+#define        VDEC_G_VERSION                          0x1DF8
 #define        VDEC_G_SOFT_RST_CTRL                    0x1DFC
 
-/*              Video Decoder H Registers  */
-#define        VDEC_H_MODE_CTRL                                0x1E00
-#define        VDEC_H_OUT_CTRL1                                0x1E04
-#define        VDEC_H_OUT_CTRL_NS                              0x1E08
-#define        VDEC_H_GEN_STAT                                 0x1E0C
+/* Video Decoder H Registers  */
+#define        VDEC_H_MODE_CTRL                        0x1E00
+#define        VDEC_H_OUT_CTRL1                        0x1E04
+#define        VDEC_H_OUT_CTRL_NS                      0x1E08
+#define        VDEC_H_GEN_STAT                         0x1E0C
 #define        VDEC_H_INT_STAT_MASK                    0x1E1E
-#define        VDEC_H_LUMA_CTRL                                0x1E14
-#define        VDEC_H_CHROMA_CTRL                              0x1E18
-#define        VDEC_H_CRUSH_CTRL                               0x1E1C
+#define        VDEC_H_LUMA_CTRL                        0x1E14
+#define        VDEC_H_CHROMA_CTRL                      0x1E18
+#define        VDEC_H_CRUSH_CTRL                       0x1E1C
 #define        VDEC_H_HORIZ_TIM_CTRL                   0x1E20
 #define        VDEC_H_VERT_TIM_CTRL                    0x1E24
 #define        VDEC_H_MISC_TIM_CTRL                    0x1E28
-#define        VDEC_H_FIELD_COUNT                              0x1E2C
-#define        VDEC_H_HSCALE_CTRL                              0x1E30
-#define        VDEC_H_VSCALE_CTRL                              0x1E34
-#define        VDEC_H_MAN_VGA_CTRL                             0x1E38
-#define        VDEC_H_MAN_AGC_CTRL                             0x1E3C
-#define        VDEC_H_DFE_CTRL1                                0x1E40
-#define        VDEC_H_DFE_CTRL2                                0x1E44
-#define        VDEC_H_DFE_CTRL3                                0x1E48
-#define        VDEC_H_PLL_CTRL                                 0x1E4C
+#define        VDEC_H_FIELD_COUNT                      0x1E2C
+#define        VDEC_H_HSCALE_CTRL                      0x1E30
+#define        VDEC_H_VSCALE_CTRL                      0x1E34
+#define        VDEC_H_MAN_VGA_CTRL                     0x1E38
+#define        VDEC_H_MAN_AGC_CTRL                     0x1E3C
+#define        VDEC_H_DFE_CTRL1                        0x1E40
+#define        VDEC_H_DFE_CTRL2                        0x1E44
+#define        VDEC_H_DFE_CTRL3                        0x1E48
+#define        VDEC_H_PLL_CTRL                         0x1E4C
 #define        VDEC_H_PLL_CTRL_FAST                    0x1E50
-#define        VDEC_H_HTL_CTRL                                 0x1E54
-#define        VDEC_H_SRC_CFG                                  0x1E58
-#define        VDEC_H_SC_STEP_SIZE                             0x1E5C
+#define        VDEC_H_HTL_CTRL                         0x1E54
+#define        VDEC_H_SRC_CFG                          0x1E58
+#define        VDEC_H_SC_STEP_SIZE                     0x1E5C
 #define        VDEC_H_SC_CONVERGE_CTRL                 0x1E60
-#define        VDEC_H_SC_LOOP_CTRL                             0x1E64
+#define        VDEC_H_SC_LOOP_CTRL                     0x1E64
 #define        VDEC_H_COMB_2D_HFS_CFG                  0x1E68
 #define        VDEC_H_COMB_2D_HFD_CFG                  0x1E6C
 #define        VDEC_H_COMB_2D_LF_CFG                   0x1E70
 #define        VDEC_H_COMB_2D_BLEND                    0x1E74
 #define        VDEC_H_COMB_MISC_CTRL                   0x1E78
-#define        VDEC_H_COMB_FLAT_THRESH_CTRL    0x1E7C
-#define        VDEC_H_COMB_TEST                                0x1E80
-#define        VDEC_H_BP_MISC_CTRL                             0x1E84
-#define        VDEC_H_VCR_DET_CTRL                             0x1E88
+#define        VDEC_H_COMB_FLAT_THRESH_CTRL            0x1E7C
+#define        VDEC_H_COMB_TEST                        0x1E80
+#define        VDEC_H_BP_MISC_CTRL                     0x1E84
+#define        VDEC_H_VCR_DET_CTRL                     0x1E88
 #define        VDEC_H_NOISE_DET_CTRL                   0x1E8C
 #define        VDEC_H_COMB_FLAT_NOISE_CTRL             0x1E90
-#define        VDEC_H_VERSION                                  0x1FF8
+#define        VDEC_H_VERSION                          0x1FF8
 #define        VDEC_H_SOFT_RST_CTRL                    0x1FFC
 
 /*****************************************************************************/
 /* LUMA_CTRL register fields */
-#define VDEC_A_BRITE_CTRL                              0x1014
+#define VDEC_A_BRITE_CTRL                      0x1014
 #define VDEC_A_CNTRST_CTRL                     0x1015
 #define VDEC_A_PEAK_SEL                                0x1016
 
index fc780d0908dc61e54f255f7f7ca6c290df598274..298a68d98c2f3ac4bab0846715f440410f85d185 100644 (file)
@@ -99,82 +99,67 @@ static int medusa_initialize_ntsc(struct cx25821_dev *dev)
 
        for (i = 0; i < MAX_DECODERS; i++) {
                /* set video format NTSC-M */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i),
-                                    &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               MODE_CTRL + (0x200 * i), &tmp);
                value &= 0xFFFFFFF0;
                /* enable the fast locking mode bit[16] */
                value |= 0x10001;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i),
-                                     value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               MODE_CTRL + (0x200 * i), value);
 
                /* resolution NTSC 720x480 */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    HORIZ_TIM_CTRL + (0x200 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               HORIZ_TIM_CTRL + (0x200 * i), &tmp);
                value &= 0x00C00C00;
                value |= 0x612D0074;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     HORIZ_TIM_CTRL + (0x200 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               HORIZ_TIM_CTRL + (0x200 * i), value);
 
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    VERT_TIM_CTRL + (0x200 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               VERT_TIM_CTRL + (0x200 * i), &tmp);
                value &= 0x00C00C00;
                value |= 0x1C1E001A;    /* vblank_cnt + 2 to get camera ID */
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     VERT_TIM_CTRL + (0x200 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               VERT_TIM_CTRL + (0x200 * i), value);
 
                /* chroma subcarrier step size */
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     SC_STEP_SIZE + (0x200 * i), 0x43E00000);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               SC_STEP_SIZE + (0x200 * i), 0x43E00000);
 
                /* enable VIP optional active */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    OUT_CTRL_NS + (0x200 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               OUT_CTRL_NS + (0x200 * i), &tmp);
                value &= 0xFFFBFFFF;
                value |= 0x00040000;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     OUT_CTRL_NS + (0x200 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               OUT_CTRL_NS + (0x200 * i), value);
 
                /* enable VIP optional active (VIP_OPT_AL) for direct output. */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i),
-                                    &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               OUT_CTRL1 + (0x200 * i), &tmp);
                value &= 0xFFFBFFFF;
                value |= 0x00040000;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i),
-                                     value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               OUT_CTRL1 + (0x200 * i), value);
 
                /*
                 * clear VPRES_VERT_EN bit, fixes the chroma run away problem
                 * when the input switching rate < 16 fields
                */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    MISC_TIM_CTRL + (0x200 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               MISC_TIM_CTRL + (0x200 * i), &tmp);
                /* disable special play detection */
                value = setBitAtPos(value, 14);
                value = clearBitAtPos(value, 15);
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     MISC_TIM_CTRL + (0x200 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               MISC_TIM_CTRL + (0x200 * i), value);
 
                /* set vbi_gate_en to 0 */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i),
-                                    &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               DFE_CTRL1 + (0x200 * i), &tmp);
                value = clearBitAtPos(value, 29);
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i),
-                                     value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DFE_CTRL1 + (0x200 * i), value);
 
                /* Enable the generation of blue field output if no video */
                medusa_enable_bluefield_output(dev, i, 1);
@@ -182,61 +167,49 @@ static int medusa_initialize_ntsc(struct cx25821_dev *dev)
 
        for (i = 0; i < MAX_ENCODERS; i++) {
                /* NTSC hclock */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    DENC_A_REG_1 + (0x100 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               DENC_A_REG_1 + (0x100 * i), &tmp);
                value &= 0xF000FC00;
                value |= 0x06B402D0;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_1 + (0x100 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_1 + (0x100 * i), value);
 
                /* burst begin and burst end */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    DENC_A_REG_2 + (0x100 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               DENC_A_REG_2 + (0x100 * i), &tmp);
                value &= 0xFF000000;
                value |= 0x007E9054;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_2 + (0x100 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_2 + (0x100 * i), value);
 
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    DENC_A_REG_3 + (0x100 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               DENC_A_REG_3 + (0x100 * i), &tmp);
                value &= 0xFC00FE00;
                value |= 0x00EC00F0;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_3 + (0x100 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_3 + (0x100 * i), value);
 
                /* set NTSC vblank, no phase alternation, 7.5 IRE pedestal */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    DENC_A_REG_4 + (0x100 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               DENC_A_REG_4 + (0x100 * i), &tmp);
                value &= 0x00FCFFFF;
                value |= 0x13020000;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_4 + (0x100 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_4 + (0x100 * i), value);
 
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    DENC_A_REG_5 + (0x100 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               DENC_A_REG_5 + (0x100 * i), &tmp);
                value &= 0xFFFF0000;
                value |= 0x0000E575;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_5 + (0x100 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_5 + (0x100 * i), value);
 
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_6 + (0x100 * i), 0x009A89C1);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_6 + (0x100 * i), 0x009A89C1);
 
                /* Subcarrier Increment */
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_7 + (0x100 * i), 0x21F07C1F);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_7 + (0x100 * i), 0x21F07C1F);
        }
 
        /* set picture resolutions */
@@ -261,34 +234,27 @@ static int medusa_PALCombInit(struct cx25821_dev *dev, int dec)
        u32 value = 0, tmp = 0;
 
        /* Setup for 2D threshold */
-       ret_val =
-           cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_HFS_CFG + (0x200 * dec),
-                             0x20002861);
-       ret_val =
-           cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_HFD_CFG + (0x200 * dec),
-                             0x20002861);
-       ret_val =
-           cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_LF_CFG + (0x200 * dec),
-                             0x200A1023);
+       ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                       COMB_2D_HFS_CFG + (0x200 * dec), 0x20002861);
+       ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                       COMB_2D_HFD_CFG + (0x200 * dec), 0x20002861);
+       ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                       COMB_2D_LF_CFG + (0x200 * dec), 0x200A1023);
 
        /* Setup flat chroma and luma thresholds */
-       value =
-           cx25821_i2c_read(&dev->i2c_bus[0],
-                            COMB_FLAT_THRESH_CTRL + (0x200 * dec), &tmp);
+       value = cx25821_i2c_read(&dev->i2c_bus[0],
+                       COMB_FLAT_THRESH_CTRL + (0x200 * dec), &tmp);
        value &= 0x06230000;
-       ret_val =
-           cx25821_i2c_write(&dev->i2c_bus[0],
-                             COMB_FLAT_THRESH_CTRL + (0x200 * dec), value);
+       ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                       COMB_FLAT_THRESH_CTRL + (0x200 * dec), value);
 
        /* set comb 2D blend */
-       ret_val =
-           cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_BLEND + (0x200 * dec),
-                             0x210F0F0F);
+       ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                       COMB_2D_BLEND + (0x200 * dec), 0x210F0F0F);
 
        /* COMB MISC CONTROL */
-       ret_val =
-           cx25821_i2c_write(&dev->i2c_bus[0], COMB_MISC_CTRL + (0x200 * dec),
-                             0x41120A7F);
+       ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                       COMB_MISC_CTRL + (0x200 * dec), 0x41120A7F);
 
        return ret_val;
 }
@@ -304,83 +270,68 @@ static int medusa_initialize_pal(struct cx25821_dev *dev)
 
        for (i = 0; i < MAX_DECODERS; i++) {
                /* set video format PAL-BDGHI */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i),
-                                    &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               MODE_CTRL + (0x200 * i), &tmp);
                value &= 0xFFFFFFF0;
                /* enable the fast locking mode bit[16] */
                value |= 0x10004;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i),
-                                     value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               MODE_CTRL + (0x200 * i), value);
 
                /* resolution PAL 720x576 */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    HORIZ_TIM_CTRL + (0x200 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               HORIZ_TIM_CTRL + (0x200 * i), &tmp);
                value &= 0x00C00C00;
                value |= 0x632D007D;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     HORIZ_TIM_CTRL + (0x200 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               HORIZ_TIM_CTRL + (0x200 * i), value);
 
                /* vblank656_cnt=x26, vactive_cnt=240h, vblank_cnt=x24 */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    VERT_TIM_CTRL + (0x200 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               VERT_TIM_CTRL + (0x200 * i), &tmp);
                value &= 0x00C00C00;
                value |= 0x28240026;    /* vblank_cnt + 2 to get camera ID */
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     VERT_TIM_CTRL + (0x200 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               VERT_TIM_CTRL + (0x200 * i), value);
 
                /* chroma subcarrier step size */
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     SC_STEP_SIZE + (0x200 * i), 0x5411E2D0);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               SC_STEP_SIZE + (0x200 * i), 0x5411E2D0);
 
                /* enable VIP optional active */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    OUT_CTRL_NS + (0x200 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               OUT_CTRL_NS + (0x200 * i), &tmp);
                value &= 0xFFFBFFFF;
                value |= 0x00040000;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     OUT_CTRL_NS + (0x200 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               OUT_CTRL_NS + (0x200 * i), value);
 
                /* enable VIP optional active (VIP_OPT_AL) for direct output. */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i),
-                                    &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               OUT_CTRL1 + (0x200 * i), &tmp);
                value &= 0xFFFBFFFF;
                value |= 0x00040000;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i),
-                                     value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               OUT_CTRL1 + (0x200 * i), value);
 
                /*
                 * clear VPRES_VERT_EN bit, fixes the chroma run away problem
                 * when the input switching rate < 16 fields
                 */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    MISC_TIM_CTRL + (0x200 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               MISC_TIM_CTRL + (0x200 * i), &tmp);
                /* disable special play detection */
                value = setBitAtPos(value, 14);
                value = clearBitAtPos(value, 15);
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     MISC_TIM_CTRL + (0x200 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               MISC_TIM_CTRL + (0x200 * i), value);
 
                /* set vbi_gate_en to 0 */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i),
-                                    &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               DFE_CTRL1 + (0x200 * i), &tmp);
                value = clearBitAtPos(value, 29);
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i),
-                                     value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DFE_CTRL1 + (0x200 * i), value);
 
                medusa_PALCombInit(dev, i);
 
@@ -390,62 +341,50 @@ static int medusa_initialize_pal(struct cx25821_dev *dev)
 
        for (i = 0; i < MAX_ENCODERS; i++) {
                /* PAL hclock */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    DENC_A_REG_1 + (0x100 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               DENC_A_REG_1 + (0x100 * i), &tmp);
                value &= 0xF000FC00;
                value |= 0x06C002D0;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_1 + (0x100 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_1 + (0x100 * i), value);
 
                /* burst begin and burst end */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    DENC_A_REG_2 + (0x100 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               DENC_A_REG_2 + (0x100 * i), &tmp);
                value &= 0xFF000000;
                value |= 0x007E9754;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_2 + (0x100 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_2 + (0x100 * i), value);
 
                /* hblank and vactive */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    DENC_A_REG_3 + (0x100 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               DENC_A_REG_3 + (0x100 * i), &tmp);
                value &= 0xFC00FE00;
                value |= 0x00FC0120;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_3 + (0x100 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_3 + (0x100 * i), value);
 
                /* set PAL vblank, phase alternation, 0 IRE pedestal */
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    DENC_A_REG_4 + (0x100 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               DENC_A_REG_4 + (0x100 * i), &tmp);
                value &= 0x00FCFFFF;
                value |= 0x14010000;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_4 + (0x100 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_4 + (0x100 * i), value);
 
-               value =
-                   cx25821_i2c_read(&dev->i2c_bus[0],
-                                    DENC_A_REG_5 + (0x100 * i), &tmp);
+               value = cx25821_i2c_read(&dev->i2c_bus[0],
+                               DENC_A_REG_5 + (0x100 * i), &tmp);
                value &= 0xFFFF0000;
                value |= 0x0000F078;
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_5 + (0x100 * i), value);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_5 + (0x100 * i), value);
 
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_6 + (0x100 * i), 0x00A493CF);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_6 + (0x100 * i), 0x00A493CF);
 
                /* Subcarrier Increment */
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     DENC_A_REG_7 + (0x100 * i), 0x2A098ACB);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               DENC_A_REG_7 + (0x100 * i), 0x2A098ACB);
        }
 
        /* set picture resolutions */
@@ -499,7 +438,7 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width,
 
        mutex_lock(&dev->lock);
 
-       /* validate the width - cannot be negative */
+       /* validate the width */
        if (width > MAX_WIDTH) {
                pr_info("%s(): width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH\n",
                        __func__, width, MAX_WIDTH);
@@ -543,12 +482,10 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width,
 
        for (; decoder < decoder_count; decoder++) {
                /* write scaling values for each decoder */
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     HSCALE_CTRL + (0x200 * decoder), hscale);
-               ret_val =
-                   cx25821_i2c_write(&dev->i2c_bus[0],
-                                     VSCALE_CTRL + (0x200 * decoder), vscale);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               HSCALE_CTRL + (0x200 * decoder), hscale);
+               ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+                               VSCALE_CTRL + (0x200 * decoder), vscale);
        }
 
        mutex_unlock(&dev->lock);
@@ -606,8 +543,8 @@ static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder,
 }
 
 /* Map to Medusa register setting */
-static int mapM(int srcMin,
-               int srcMax, int srcVal, int dstMin, int dstMax, int *dstVal)
+static int mapM(int srcMin, int srcMax, int srcVal, int dstMin, int dstMax,
+               int *dstVal)
 {
        int numerator;
        int denominator;
@@ -654,23 +591,19 @@ int medusa_set_brightness(struct cx25821_dev *dev, int brightness, int decoder)
        u32 val = 0, tmp = 0;
 
        mutex_lock(&dev->lock);
-       if ((brightness > VIDEO_PROCAMP_MAX)
-           || (brightness < VIDEO_PROCAMP_MIN)) {
+       if ((brightness > VIDEO_PROCAMP_MAX) ||
+           (brightness < VIDEO_PROCAMP_MIN)) {
                mutex_unlock(&dev->lock);
                return -1;
        }
-       ret_val =
-           mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness,
-                SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value);
+       ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness,
+                       SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value);
        value = convert_to_twos(value, 8);
-       val =
-           cx25821_i2c_read(&dev->i2c_bus[0],
-                            VDEC_A_BRITE_CTRL + (0x200 * decoder), &tmp);
+       val = cx25821_i2c_read(&dev->i2c_bus[0],
+                       VDEC_A_BRITE_CTRL + (0x200 * decoder), &tmp);
        val &= 0xFFFFFF00;
-       ret_val |=
-           cx25821_i2c_write(&dev->i2c_bus[0],
-                             VDEC_A_BRITE_CTRL + (0x200 * decoder),
-                             val | value);
+       ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+                       VDEC_A_BRITE_CTRL + (0x200 * decoder), val | value);
        mutex_unlock(&dev->lock);
        return ret_val;
 }
@@ -688,17 +621,13 @@ int medusa_set_contrast(struct cx25821_dev *dev, int contrast, int decoder)
                return -1;
        }
 
-       ret_val =
-           mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, contrast,
-                UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value);
-       val =
-           cx25821_i2c_read(&dev->i2c_bus[0],
-                            VDEC_A_CNTRST_CTRL + (0x200 * decoder), &tmp);
+       ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, contrast,
+                       UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value);
+       val = cx25821_i2c_read(&dev->i2c_bus[0],
+                       VDEC_A_CNTRST_CTRL + (0x200 * decoder), &tmp);
        val &= 0xFFFFFF00;
-       ret_val |=
-           cx25821_i2c_write(&dev->i2c_bus[0],
-                             VDEC_A_CNTRST_CTRL + (0x200 * decoder),
-                             val | value);
+       ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+                       VDEC_A_CNTRST_CTRL + (0x200 * decoder), val | value);
 
        mutex_unlock(&dev->lock);
        return ret_val;
@@ -717,19 +646,16 @@ int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder)
                return -1;
        }
 
-       ret_val =
-           mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, hue, SIGNED_BYTE_MIN,
-                SIGNED_BYTE_MAX, &value);
+       ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, hue,
+                       SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value);
 
        value = convert_to_twos(value, 8);
-       val =
-           cx25821_i2c_read(&dev->i2c_bus[0],
-                            VDEC_A_HUE_CTRL + (0x200 * decoder), &tmp);
+       val = cx25821_i2c_read(&dev->i2c_bus[0],
+                       VDEC_A_HUE_CTRL + (0x200 * decoder), &tmp);
        val &= 0xFFFFFF00;
 
-       ret_val |=
-           cx25821_i2c_write(&dev->i2c_bus[0],
-                             VDEC_A_HUE_CTRL + (0x200 * decoder), val | value);
+       ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+                       VDEC_A_HUE_CTRL + (0x200 * decoder), val | value);
 
        mutex_unlock(&dev->lock);
        return ret_val;
@@ -743,33 +669,26 @@ int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder)
 
        mutex_lock(&dev->lock);
 
-       if ((saturation > VIDEO_PROCAMP_MAX)
-           || (saturation < VIDEO_PROCAMP_MIN)) {
+       if ((saturation > VIDEO_PROCAMP_MAX) ||
+           (saturation < VIDEO_PROCAMP_MIN)) {
                mutex_unlock(&dev->lock);
                return -1;
        }
 
-       ret_val =
-           mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, saturation,
-                UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value);
+       ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, saturation,
+                       UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value);
 
-       val =
-           cx25821_i2c_read(&dev->i2c_bus[0],
-                            VDEC_A_USAT_CTRL + (0x200 * decoder), &tmp);
+       val = cx25821_i2c_read(&dev->i2c_bus[0],
+                       VDEC_A_USAT_CTRL + (0x200 * decoder), &tmp);
        val &= 0xFFFFFF00;
-       ret_val |=
-           cx25821_i2c_write(&dev->i2c_bus[0],
-                             VDEC_A_USAT_CTRL + (0x200 * decoder),
-                             val | value);
-
-       val =
-           cx25821_i2c_read(&dev->i2c_bus[0],
-                            VDEC_A_VSAT_CTRL + (0x200 * decoder), &tmp);
+       ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+                       VDEC_A_USAT_CTRL + (0x200 * decoder), val | value);
+
+       val = cx25821_i2c_read(&dev->i2c_bus[0],
+                       VDEC_A_VSAT_CTRL + (0x200 * decoder), &tmp);
        val &= 0xFFFFFF00;
-       ret_val |=
-           cx25821_i2c_write(&dev->i2c_bus[0],
-                             VDEC_A_VSAT_CTRL + (0x200 * decoder),
-                             val | value);
+       ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
+                       VDEC_A_VSAT_CTRL + (0x200 * decoder), val | value);
 
        mutex_unlock(&dev->lock);
        return ret_val;
@@ -830,9 +749,8 @@ int medusa_video_init(struct cx25821_dev *dev)
        /* select AFE clock to output mode */
        value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp);
        value &= 0x83FFFFFF;
-       ret_val =
-          cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
-                            value | 0x10000000);
+       ret_val = cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL,
+                       value | 0x10000000);
 
        if (ret_val < 0)
                goto error;
index 2a724ddfa53f1cfa226f8569a7d98dd68647391c..5a157cf4a95e38ca8b8f7800f01267ad85d14569 100644 (file)
@@ -65,9 +65,8 @@ static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev,
                *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr_ch2 + offset);
                *(rp++) = cpu_to_le32(0);       /* bits 63-32 */
 
-               if ((lines <= NTSC_FIELD_HEIGHT)
-                   || (line < (NTSC_FIELD_HEIGHT - 1))
-                   || !(dev->_isNTSC_ch2)) {
+               if ((lines <= NTSC_FIELD_HEIGHT) ||
+                   (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) {
                        offset += dist_betwn_starts;
                }
        }
@@ -85,7 +84,7 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
 {
        unsigned int line, i;
        struct sram_channel *sram_ch =
-          dev->channels[dev->_channel2_upstream_select].sram_channels;
+               dev->channels[dev->_channel2_upstream_select].sram_channels;
        int dist_betwn_starts = bpl * 2;
 
        /* sync instruction */
@@ -103,9 +102,8 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
                *(rp++) = cpu_to_le32(databuf_phys_addr + offset);
                *(rp++) = cpu_to_le32(0);       /* bits 63-32 */
 
-               if ((lines <= NTSC_FIELD_HEIGHT)
-                   || (line < (NTSC_FIELD_HEIGHT - 1))
-                   || !(dev->_isNTSC_ch2)) {
+               if ((lines <= NTSC_FIELD_HEIGHT) ||
+                   (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) {
                        offset += dist_betwn_starts;
                }
 
@@ -173,7 +171,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
 
                fifo_enable = FIFO_DISABLE;
 
-              /* Even field */
+               /* Even field */
                rp = cx25821_risc_field_upstream_ch2(dev, rp,
                                dev->_data_buf_phys_addr_ch2 + databuf_offset,
                                bottom_offset, 0x200, bpl, singlefield_lines,
@@ -189,9 +187,9 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
                }
 
               /*
-                 Loop to 2ndFrameRISC or to Start of
-                 Risc program & generate IRQ
-              */
+               * Loop to 2ndFrameRISC or to Start of
+               * Risc program & generate IRQ
+               */
                *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag);
                *(rp++) = cpu_to_le32(risc_phys_jump_addr);
                *(rp++) = cpu_to_le32(0);
@@ -203,7 +201,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
 void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev)
 {
        struct sram_channel *sram_ch =
-          dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels;
+               dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels;
        u32 tmp = 0;
 
        if (!dev->_is_running_ch2) {
@@ -262,9 +260,8 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
        struct file *myfile;
        int frame_index_temp = dev->_frame_index_ch2;
        int i = 0;
-       int line_size =
-           (dev->_pixel_format_ch2 ==
-            PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ;
+       int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ?
+               Y411_LINE_SZ : Y422_LINE_SZ;
        int frame_size = 0;
        int frame_offset = 0;
        ssize_t vfs_read_retval = 0;
@@ -277,14 +274,11 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
                return 0;
 
        if (dev->_isNTSC_ch2) {
-               frame_size =
-                   (line_size ==
-                    Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 :
-                   FRAME_SIZE_NTSC_Y422;
+               frame_size = (line_size == Y411_LINE_SZ) ?
+                       FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422;
        } else {
-               frame_size =
-                   (line_size ==
-                    Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
+               frame_size = (line_size == Y411_LINE_SZ) ?
+                       FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
        }
 
        frame_offset = (frame_index_temp > 0) ? frame_size : 0;
@@ -318,14 +312,14 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
                for (i = 0; i < dev->_lines_count_ch2; i++) {
                        pos = file_offset;
 
-                       vfs_read_retval =
-                           vfs_read(myfile, mybuf, line_size, &pos);
+                       vfs_read_retval = vfs_read(myfile, mybuf, line_size,
+                                       &pos);
 
                        if (vfs_read_retval > 0 && vfs_read_retval == line_size
                            && dev->_data_buf_virt_addr_ch2 != NULL) {
                                memcpy((void *)(dev->_data_buf_virt_addr_ch2 +
                                                frame_offset / 4), mybuf,
-                                      vfs_read_retval);
+                                               vfs_read_retval);
                        }
 
                        file_offset += vfs_read_retval;
@@ -341,8 +335,8 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
                if (i > 0)
                        dev->_frame_count_ch2++;
 
-               dev->_file_status_ch2 =
-                   (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE;
+               dev->_file_status_ch2 = (vfs_read_retval == line_size) ?
+                       IN_PROGRESS : END_OF_FILE;
 
                set_fs(old_fs);
                filp_close(myfile, NULL);
@@ -353,8 +347,8 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
 
 static void cx25821_vidups_handler_ch2(struct work_struct *work)
 {
-       struct cx25821_dev *dev =
-           container_of(work, struct cx25821_dev, _irq_work_entry_ch2);
+       struct cx25821_dev *dev = container_of(work, struct cx25821_dev,
+                       _irq_work_entry_ch2);
 
        if (!dev) {
                pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
@@ -362,18 +356,16 @@ static void cx25821_vidups_handler_ch2(struct work_struct *work)
                return;
        }
 
-       cx25821_get_frame_ch2(dev,
-                            dev->channels[dev->
-                              _channel2_upstream_select].sram_channels);
+       cx25821_get_frame_ch2(dev, dev->channels[dev->
+                       _channel2_upstream_select].sram_channels);
 }
 
 int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
 {
        struct file *myfile;
        int i = 0, j = 0;
-       int line_size =
-           (dev->_pixel_format_ch2 ==
-            PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ;
+       int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ?
+               Y411_LINE_SZ : Y422_LINE_SZ;
        ssize_t vfs_read_retval = 0;
        char mybuf[line_size];
        loff_t pos;
@@ -410,16 +402,16 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
                        for (i = 0; i < dev->_lines_count_ch2; i++) {
                                pos = offset;
 
-                               vfs_read_retval =
-                                   vfs_read(myfile, mybuf, line_size, &pos);
+                               vfs_read_retval = vfs_read(myfile, mybuf,
+                                               line_size, &pos);
 
-                               if (vfs_read_retval > 0
-                                   && vfs_read_retval == line_size
-                                   && dev->_data_buf_virt_addr_ch2 != NULL) {
+                               if (vfs_read_retval > 0 &&
+                                   vfs_read_retval == line_size &&
+                                   dev->_data_buf_virt_addr_ch2 != NULL) {
                                        memcpy((void *)(dev->
                                                        _data_buf_virt_addr_ch2
                                                        + offset / 4), mybuf,
-                                              vfs_read_retval);
+                                                       vfs_read_retval);
                                }
 
                                offset += vfs_read_retval;
@@ -438,8 +430,8 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch)
                                break;
                }
 
-               dev->_file_status_ch2 =
-                   (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE;
+               dev->_file_status_ch2 = (vfs_read_retval == line_size) ?
+                       IN_PROGRESS : END_OF_FILE;
 
                set_fs(old_fs);
                myfile->f_pos = 0;
@@ -463,9 +455,8 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
                                    dev->_dma_phys_addr_ch2);
        }
 
-       dev->_dma_virt_addr_ch2 =
-           pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size_ch2,
-                                &dma_addr);
+       dev->_dma_virt_addr_ch2 = pci_alloc_consistent(dev->pci,
+                       dev->upstream_riscbuf_size_ch2, &dma_addr);
        dev->_dma_virt_start_addr_ch2 = dev->_dma_virt_addr_ch2;
        dev->_dma_phys_start_addr_ch2 = dma_addr;
        dev->_dma_phys_addr_ch2 = dma_addr;
@@ -485,9 +476,8 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
                                    dev->_data_buf_phys_addr_ch2);
        }
        /* For Video Data buffer allocation */
-       dev->_data_buf_virt_addr_ch2 =
-           pci_alloc_consistent(dev->pci, dev->upstream_databuf_size_ch2,
-                                &data_dma_addr);
+       dev->_data_buf_virt_addr_ch2 = pci_alloc_consistent(dev->pci,
+                       dev->upstream_databuf_size_ch2, &data_dma_addr);
        dev->_data_buf_phys_addr_ch2 = data_dma_addr;
        dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2;
 
@@ -563,8 +553,8 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
                                else
                                        line_size_in_bytes = Y422_LINE_SZ;
                                risc_phys_jump_addr =
-                                   dev->_dma_phys_start_addr_ch2 +
-                                   odd_risc_prog_size;
+                                       dev->_dma_phys_start_addr_ch2 +
+                                       odd_risc_prog_size;
 
                                rp = cx25821_update_riscprogram_ch2(dev,
                                                dev->_dma_virt_start_addr_ch2,
@@ -612,11 +602,9 @@ static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id)
        vid_status = cx_read(sram_ch->int_stat);
 
        /* Only deal with our interrupt */
-       if (vid_status) {
-               handled =
-                   cx25821_video_upstream_irq_ch2(dev, channel_num,
-                                                  vid_status);
-       }
+       if (vid_status)
+               handled = cx25821_video_upstream_irq_ch2(dev, channel_num,
+                               vid_status);
 
        if (handled < 0)
                cx25821_stop_upstream_video_ch2(dev);
@@ -691,8 +679,7 @@ int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev,
        tmp = cx_read(sram_ch->int_msk);
        cx_write(sram_ch->int_msk, tmp |= _intr_msk);
 
-       err =
-           request_irq(dev->pci->irq, cx25821_upstream_irq_ch2,
+       err = request_irq(dev->pci->irq, cx25821_upstream_irq_ch2,
                        IRQF_SHARED, dev->name, dev);
        if (err < 0) {
                pr_err("%s: can't get upstream IRQ %d\n",
@@ -752,45 +739,38 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
        dev->_file_status_ch2 = RESET_STATUS;
        dev->_lines_count_ch2 = dev->_isNTSC_ch2 ? 480 : 576;
        dev->_pixel_format_ch2 = pixel_format;
-       dev->_line_size_ch2 =
-           (dev->_pixel_format_ch2 ==
-            PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
+       dev->_line_size_ch2 = (dev->_pixel_format_ch2 == PIXEL_FRMT_422) ?
+               (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
        data_frame_size = dev->_isNTSC_ch2 ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ;
-       risc_buffer_size =
-           dev->_isNTSC_ch2 ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE;
+       risc_buffer_size = dev->_isNTSC_ch2 ?
+               NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE;
 
        if (dev->input_filename_ch2) {
                str_length = strlen(dev->input_filename_ch2);
-               dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL);
+               dev->_filename_ch2 = kmemdup(dev->input_filename_ch2,
+                                            str_length + 1, GFP_KERNEL);
 
                if (!dev->_filename_ch2)
                        goto error;
-
-               memcpy(dev->_filename_ch2, dev->input_filename_ch2,
-                      str_length + 1);
        } else {
                str_length = strlen(dev->_defaultname_ch2);
-               dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL);
+               dev->_filename_ch2 = kmemdup(dev->_defaultname_ch2,
+                                            str_length + 1, GFP_KERNEL);
 
                if (!dev->_filename_ch2)
                        goto error;
-
-               memcpy(dev->_filename_ch2, dev->_defaultname_ch2,
-                      str_length + 1);
        }
 
        /* Default if filename is empty string */
        if (strcmp(dev->input_filename_ch2, "") == 0) {
                if (dev->_isNTSC_ch2) {
-                       dev->_filename_ch2 =
-                           (dev->_pixel_format_ch2 ==
-                            PIXEL_FRMT_411) ? "/root/vid411.yuv" :
-                           "/root/vidtest.yuv";
+                       dev->_filename_ch2 = (dev->_pixel_format_ch2 ==
+                               PIXEL_FRMT_411) ? "/root/vid411.yuv" :
+                               "/root/vidtest.yuv";
                } else {
-                       dev->_filename_ch2 =
-                           (dev->_pixel_format_ch2 ==
-                            PIXEL_FRMT_411) ? "/root/pal411.yuv" :
-                           "/root/pal422.yuv";
+                       dev->_filename_ch2 = (dev->_pixel_format_ch2 ==
+                               PIXEL_FRMT_411) ? "/root/pal411.yuv" :
+                               "/root/pal422.yuv";
                }
        }
 
index c0b80068f468b9d62e9d967f92dc96b261491791..21e7d657f049b21daa20d7ab6ef620304946dd4b 100644 (file)
@@ -136,7 +136,7 @@ static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp,
 {
        unsigned int line, i;
        struct sram_channel *sram_ch =
-          dev->channels[dev->_channel_upstream_select].sram_channels;
+               dev->channels[dev->_channel_upstream_select].sram_channels;
        int dist_betwn_starts = bpl * 2;
 
        /* sync instruction */
@@ -194,15 +194,12 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
        if (dev->_isNTSC) {
                odd_num_lines = singlefield_lines + 1;
                risc_program_size = FRAME1_VID_PROG_SIZE;
-               frame_size =
-                   (bpl ==
-                    Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 :
-                   FRAME_SIZE_NTSC_Y422;
+               frame_size = (bpl == Y411_LINE_SZ) ?
+                       FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422;
        } else {
                risc_program_size = PAL_VID_PROG_SIZE;
-               frame_size =
-                   (bpl ==
-                    Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
+               frame_size = (bpl == Y411_LINE_SZ) ?
+                       FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
        }
 
        /* Virtual address of Risc buffer program */
@@ -214,13 +211,9 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
                if (UNSET != top_offset) {
                        fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE;
                        rp = cx25821_risc_field_upstream(dev, rp,
-                                                        dev->
-                                                        _data_buf_phys_addr +
-                                                        databuf_offset,
-                                                        top_offset, 0, bpl,
-                                                        odd_num_lines,
-                                                        fifo_enable,
-                                                        ODD_FIELD);
+                                       dev->_data_buf_phys_addr +
+                                       databuf_offset, top_offset, 0, bpl,
+                                       odd_num_lines, fifo_enable, ODD_FIELD);
                }
 
                fifo_enable = FIFO_DISABLE;
@@ -234,8 +227,8 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
 
                if (frame == 0) {
                        risc_flag = RISC_CNT_RESET;
-                       risc_phys_jump_addr =
-                           dev->_dma_phys_start_addr + risc_program_size;
+                       risc_phys_jump_addr = dev->_dma_phys_start_addr +
+                               risc_program_size;
                } else {
                        risc_phys_jump_addr = dev->_dma_phys_start_addr;
                        risc_flag = RISC_CNT_INC;
@@ -255,7 +248,7 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
 void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev)
 {
        struct sram_channel *sram_ch =
-          dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels;
+               dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels;
        u32 tmp = 0;
 
        if (!dev->_is_running) {
@@ -312,9 +305,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
        struct file *myfile;
        int frame_index_temp = dev->_frame_index;
        int i = 0;
-       int line_size =
-           (dev->_pixel_format ==
-            PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ;
+       int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ?
+               Y411_LINE_SZ : Y422_LINE_SZ;
        int frame_size = 0;
        int frame_offset = 0;
        ssize_t vfs_read_retval = 0;
@@ -326,16 +318,12 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
        if (dev->_file_status == END_OF_FILE)
                return 0;
 
-       if (dev->_isNTSC) {
-               frame_size =
-                   (line_size ==
-                    Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 :
-                   FRAME_SIZE_NTSC_Y422;
-       } else {
-               frame_size =
-                   (line_size ==
-                    Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
-       }
+       if (dev->_isNTSC)
+               frame_size = (line_size == Y411_LINE_SZ) ?
+                       FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422;
+       else
+               frame_size = (line_size == Y411_LINE_SZ) ?
+                       FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
 
        frame_offset = (frame_index_temp > 0) ? frame_size : 0;
        file_offset = dev->_frame_count * frame_size;
@@ -369,8 +357,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
                for (i = 0; i < dev->_lines_count; i++) {
                        pos = file_offset;
 
-                       vfs_read_retval =
-                           vfs_read(myfile, mybuf, line_size, &pos);
+                       vfs_read_retval = vfs_read(myfile, mybuf, line_size,
+                                       &pos);
 
                        if (vfs_read_retval > 0 && vfs_read_retval == line_size
                            && dev->_data_buf_virt_addr != NULL) {
@@ -392,8 +380,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
                if (i > 0)
                        dev->_frame_count++;
 
-               dev->_file_status =
-                   (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE;
+               dev->_file_status = (vfs_read_retval == line_size) ?
+                       IN_PROGRESS : END_OF_FILE;
 
                set_fs(old_fs);
                filp_close(myfile, NULL);
@@ -404,8 +392,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch)
 
 static void cx25821_vidups_handler(struct work_struct *work)
 {
-       struct cx25821_dev *dev =
-           container_of(work, struct cx25821_dev, _irq_work_entry);
+       struct cx25821_dev *dev = container_of(work, struct cx25821_dev,
+                       _irq_work_entry);
 
        if (!dev) {
                pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
@@ -413,18 +401,16 @@ static void cx25821_vidups_handler(struct work_struct *work)
                return;
        }
 
-       cx25821_get_frame(dev,
-                        dev->channels[dev->_channel_upstream_select].
-                                              sram_channels);
+       cx25821_get_frame(dev, dev->channels[dev->_channel_upstream_select].
+                       sram_channels);
 }
 
 int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
 {
        struct file *myfile;
        int i = 0, j = 0;
-       int line_size =
-           (dev->_pixel_format ==
-            PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ;
+       int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ?
+               Y411_LINE_SZ : Y422_LINE_SZ;
        ssize_t vfs_read_retval = 0;
        char mybuf[line_size];
        loff_t pos;
@@ -461,8 +447,8 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
                        for (i = 0; i < dev->_lines_count; i++) {
                                pos = offset;
 
-                               vfs_read_retval =
-                                   vfs_read(myfile, mybuf, line_size, &pos);
+                               vfs_read_retval = vfs_read(myfile, mybuf,
+                                               line_size, &pos);
 
                                if (vfs_read_retval > 0
                                    && vfs_read_retval == line_size
@@ -489,8 +475,8 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch)
                                break;
                }
 
-               dev->_file_status =
-                   (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE;
+               dev->_file_status = (vfs_read_retval == line_size) ?
+                       IN_PROGRESS : END_OF_FILE;
 
                set_fs(old_fs);
                myfile->f_pos = 0;
@@ -507,14 +493,12 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
        dma_addr_t dma_addr;
        dma_addr_t data_dma_addr;
 
-       if (dev->_dma_virt_addr != NULL) {
+       if (dev->_dma_virt_addr != NULL)
                pci_free_consistent(dev->pci, dev->upstream_riscbuf_size,
-                                   dev->_dma_virt_addr, dev->_dma_phys_addr);
-       }
+                               dev->_dma_virt_addr, dev->_dma_phys_addr);
 
-       dev->_dma_virt_addr =
-           pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size,
-                                &dma_addr);
+       dev->_dma_virt_addr = pci_alloc_consistent(dev->pci,
+                       dev->upstream_riscbuf_size, &dma_addr);
        dev->_dma_virt_start_addr = dev->_dma_virt_addr;
        dev->_dma_phys_start_addr = dma_addr;
        dev->_dma_phys_addr = dma_addr;
@@ -528,15 +512,13 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
        /* Clear memory at address */
        memset(dev->_dma_virt_addr, 0, dev->_risc_size);
 
-       if (dev->_data_buf_virt_addr != NULL) {
+       if (dev->_data_buf_virt_addr != NULL)
                pci_free_consistent(dev->pci, dev->upstream_databuf_size,
-                                   dev->_data_buf_virt_addr,
-                                   dev->_data_buf_phys_addr);
-       }
+                               dev->_data_buf_virt_addr,
+                               dev->_data_buf_phys_addr);
        /* For Video Data buffer allocation */
-       dev->_data_buf_virt_addr =
-           pci_alloc_consistent(dev->pci, dev->upstream_databuf_size,
-                                &data_dma_addr);
+       dev->_data_buf_virt_addr = pci_alloc_consistent(dev->pci,
+                       dev->upstream_databuf_size, &data_dma_addr);
        dev->_data_buf_phys_addr = data_dma_addr;
        dev->_data_buf_size = dev->upstream_databuf_size;
 
@@ -553,9 +535,8 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
                return ret;
 
        /* Create RISC programs */
-       ret =
-           cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl,
-                                        dev->_lines_count);
+       ret = cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl,
+                       dev->_lines_count);
        if (ret < 0) {
                pr_info("Failed creating Video Upstream Risc programs!\n");
                goto error;
@@ -672,10 +653,9 @@ static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id)
        vid_status = cx_read(sram_ch->int_stat);
 
        /* Only deal with our interrupt */
-       if (vid_status) {
-               handled =
-                   cx25821_video_upstream_irq(dev, channel_num, vid_status);
-       }
+       if (vid_status)
+               handled = cx25821_video_upstream_irq(dev, channel_num,
+                               vid_status);
 
        if (handled < 0)
                cx25821_stop_upstream_video_ch1(dev);
@@ -747,8 +727,7 @@ int cx25821_start_video_dma_upstream(struct cx25821_dev *dev,
        tmp = cx_read(sram_ch->int_msk);
        cx_write(sram_ch->int_msk, tmp |= _intr_msk);
 
-       err =
-           request_irq(dev->pci->irq, cx25821_upstream_irq,
+       err = request_irq(dev->pci->irq, cx25821_upstream_irq,
                        IRQF_SHARED, dev->name, dev);
        if (err < 0) {
                pr_err("%s: can't get upstream IRQ %d\n",
@@ -807,43 +786,38 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select,
        dev->_file_status = RESET_STATUS;
        dev->_lines_count = dev->_isNTSC ? 480 : 576;
        dev->_pixel_format = pixel_format;
-       dev->_line_size =
-           (dev->_pixel_format ==
-            PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
+       dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ?
+               (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
        data_frame_size = dev->_isNTSC ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ;
-       risc_buffer_size =
-           dev->_isNTSC ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE;
+       risc_buffer_size = dev->_isNTSC ?
+               NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE;
 
        if (dev->input_filename) {
                str_length = strlen(dev->input_filename);
-               dev->_filename = kmalloc(str_length + 1, GFP_KERNEL);
+               dev->_filename = kmemdup(dev->input_filename, str_length + 1,
+                                        GFP_KERNEL);
 
                if (!dev->_filename)
                        goto error;
-
-               memcpy(dev->_filename, dev->input_filename, str_length + 1);
        } else {
                str_length = strlen(dev->_defaultname);
-               dev->_filename = kmalloc(str_length + 1, GFP_KERNEL);
+               dev->_filename = kmemdup(dev->_defaultname, str_length + 1,
+                                        GFP_KERNEL);
 
                if (!dev->_filename)
                        goto error;
-
-               memcpy(dev->_filename, dev->_defaultname, str_length + 1);
        }
 
        /* Default if filename is empty string */
        if (strcmp(dev->input_filename, "") == 0) {
                if (dev->_isNTSC) {
                        dev->_filename =
-                           (dev->_pixel_format ==
-                            PIXEL_FRMT_411) ? "/root/vid411.yuv" :
-                           "/root/vidtest.yuv";
+                               (dev->_pixel_format == PIXEL_FRMT_411) ?
+                               "/root/vid411.yuv" : "/root/vidtest.yuv";
                } else {
                        dev->_filename =
-                           (dev->_pixel_format ==
-                            PIXEL_FRMT_411) ? "/root/pal411.yuv" :
-                           "/root/pal422.yuv";
+                               (dev->_pixel_format == PIXEL_FRMT_411) ?
+                               "/root/pal411.yuv" : "/root/pal422.yuv";
                }
        }
 
@@ -852,13 +826,11 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select,
        dev->_file_status = RESET_STATUS;
        dev->_lines_count = dev->_isNTSC ? 480 : 576;
        dev->_pixel_format = pixel_format;
-       dev->_line_size =
-           (dev->_pixel_format ==
-            PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
+       dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ?
+               (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
 
-       retval =
-           cx25821_sram_channel_setup_upstream(dev, sram_ch, dev->_line_size,
-                                               0);
+       retval = cx25821_sram_channel_setup_upstream(dev, sram_ch,
+                       dev->_line_size, 0);
 
        /* setup fifo + format */
        cx25821_set_pixelengine(dev, sram_ch, dev->_pixel_format);
index 4d6907cda75b8a0c2405e88bb569ba6953b64d81..ffd8bc79c02e61358a48d89eab07f2d35cad450c 100644 (file)
@@ -118,12 +118,12 @@ void cx25821_dump_video_queue(struct cx25821_dev *dev,
 
        if (!list_empty(&q->active)) {
                list_for_each(item, &q->active)
-                   buf = list_entry(item, struct cx25821_buffer, vb.queue);
+                       buf = list_entry(item, struct cx25821_buffer, vb.queue);
        }
 
        if (!list_empty(&q->queued)) {
                list_for_each(item, &q->queued)
-                   buf = list_entry(item, struct cx25821_buffer, vb.queue);
+                       buf = list_entry(item, struct cx25821_buffer, vb.queue);
        }
 
 }
@@ -140,8 +140,8 @@ void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q,
                        break;
                }
 
-               buf =
-                   list_entry(q->active.next, struct cx25821_buffer, vb.queue);
+               buf = list_entry(q->active.next, struct cx25821_buffer,
+                               vb.queue);
 
                /* count comes from the hw and it is 16bit wide --
                 * this trick handles wrap-arounds correctly for
@@ -318,8 +318,8 @@ int cx25821_restart_video_queue(struct cx25821_dev *dev,
        struct list_head *item;
 
        if (!list_empty(&q->active)) {
-               buf =
-                   list_entry(q->active.next, struct cx25821_buffer, vb.queue);
+               buf = list_entry(q->active.next, struct cx25821_buffer,
+                               vb.queue);
 
                cx25821_start_video_dma(dev, q, buf, channel);
 
@@ -337,8 +337,8 @@ int cx25821_restart_video_queue(struct cx25821_dev *dev,
                if (list_empty(&q->queued))
                        return 0;
 
-               buf =
-                   list_entry(q->queued.next, struct cx25821_buffer, vb.queue);
+               buf = list_entry(q->queued.next, struct cx25821_buffer,
+                               vb.queue);
 
                if (NULL == prev) {
                        list_move_tail(&buf->vb.queue, &q->active);
@@ -375,8 +375,8 @@ void cx25821_vid_timeout(unsigned long data)
 
        spin_lock_irqsave(&dev->slock, flags);
        while (!list_empty(&q->active)) {
-               buf =
-                   list_entry(q->active.next, struct cx25821_buffer, vb.queue);
+               buf = list_entry(q->active.next, struct cx25821_buffer,
+                               vb.queue);
                list_del(&buf->vb.queue);
 
                buf->vb.state = VIDEOBUF_ERROR;
@@ -484,8 +484,7 @@ int cx25821_video_register(struct cx25821_dev *dev)
                cx25821_init_controls(dev, i);
 
                cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper,
-                               dev->channels[i].sram_channels->dma_ctl,
-                               0x11, 0);
+                       dev->channels[i].sram_channels->dma_ctl, 0x11, 0);
 
                dev->channels[i].sram_channels = &cx25821_sram_channels[i];
                dev->channels[i].video_dev = NULL;
@@ -499,15 +498,14 @@ int cx25821_video_register(struct cx25821_dev *dev)
                dev->channels[i].timeout_data.dev = dev;
                dev->channels[i].timeout_data.channel =
                        &cx25821_sram_channels[i];
-               dev->channels[i].vidq.timeout.function =
-                       cx25821_vid_timeout;
+               dev->channels[i].vidq.timeout.function = cx25821_vid_timeout;
                dev->channels[i].vidq.timeout.data =
                        (unsigned long)&dev->channels[i].timeout_data;
                init_timer(&dev->channels[i].vidq.timeout);
 
                /* register v4l devices */
-               dev->channels[i].video_dev = cx25821_vdev_init(dev,
-                               dev->pci, &cx25821_video_device, "video");
+               dev->channels[i].video_dev = cx25821_vdev_init(dev, dev->pci,
+                               &cx25821_video_device, "video");
 
                err = video_register_device(dev->channels[i].video_dev,
                                VFL_TYPE_GRABBER, video_nr[dev->nr]);
@@ -528,7 +526,6 @@ int cx25821_video_register(struct cx25821_dev *dev)
 #endif
        mutex_unlock(&dev->lock);
 
-
        return 0;
 
 fail_unreg:
@@ -558,7 +555,7 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        struct cx25821_fh *fh = q->priv_data;
        struct cx25821_dev *dev = fh->dev;
        struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
+               container_of(vb, struct cx25821_buffer, vb);
        int rc, init_buffer = 0;
        u32 line0_offset, line1_offset;
        struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
@@ -617,14 +614,13 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                        if (channel_opened >= 0 && channel_opened <= 7) {
                                if (dev->channels[channel_opened]
                                                .use_cif_resolution) {
-                                       if (dev->tvnorm & V4L2_STD_PAL_BG
-                                           || dev->tvnorm & V4L2_STD_PAL_DK)
+                                       if (dev->tvnorm & V4L2_STD_PAL_BG ||
+                                           dev->tvnorm & V4L2_STD_PAL_DK)
                                                bpl_local = 352 << 1;
                                        else
-                                               bpl_local =
-                                                dev->channels[channel_opened].
-                                                cif_width <<
-                                                1;
+                                               bpl_local = dev->channels[
+                                                       channel_opened].
+                                                       cif_width << 1;
                                }
                        }
                }
@@ -685,7 +681,7 @@ void cx25821_buffer_release(struct videobuf_queue *q,
                            struct videobuf_buffer *vb)
 {
        struct cx25821_buffer *buf =
-           container_of(vb, struct cx25821_buffer, vb);
+               container_of(vb, struct cx25821_buffer, vb);
 
        cx25821_free_buffer(q, buf);
 }
@@ -723,7 +719,7 @@ int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
 static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 {
        struct cx25821_buffer *buf =
-          container_of(vb, struct cx25821_buffer, vb);
+               container_of(vb, struct cx25821_buffer, vb);
        struct cx25821_buffer *prev;
        struct cx25821_fh *fh = vq->priv_data;
        struct cx25821_dev *dev = fh->dev;
@@ -814,7 +810,7 @@ static int video_open(struct file *file)
 
                for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) {
                        if (h->channels[i].video_dev &&
-                          h->channels[i].video_dev->minor == minor) {
+                           h->channels[i].video_dev->minor == minor) {
                                dev = h;
                                ch_id = i;
                                type  = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -848,11 +844,10 @@ static int video_open(struct file *file)
 
        v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio);
 
-       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops,
-                             &dev->pci->dev, &dev->slock,
-                             V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                             V4L2_FIELD_INTERLACED,
-                             sizeof(struct cx25821_buffer), fh, NULL);
+       videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, &dev->pci->dev,
+                       &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                       V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
+                       fh, NULL);
 
        dprintk(1, "post videobuf_queue_init()\n");
        mutex_unlock(&cx25821_devlist_mutex);
@@ -1168,8 +1163,8 @@ int cx25821_vidioc_querycap(struct file *file, void *priv,
        strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
        sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
        cap->version = CX25821_VERSION_CODE;
-       cap->capabilities =
-           V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+               V4L2_CAP_STREAMING;
        if (UNSET != dev->tuner_type)
                cap->capabilities |= V4L2_CAP_TUNER;
        return 0;
@@ -1454,38 +1449,38 @@ static const struct v4l2_queryctrl no_ctl = {
 static struct v4l2_queryctrl cx25821_ctls[] = {
        /* --- video --- */
        {
-        .id = V4L2_CID_BRIGHTNESS,
-        .name = "Brightness",
-        .minimum = 0,
-        .maximum = 10000,
-        .step = 1,
-        .default_value = 6200,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        }, {
-            .id = V4L2_CID_CONTRAST,
-            .name = "Contrast",
-            .minimum = 0,
-            .maximum = 10000,
-            .step = 1,
-            .default_value = 5000,
-            .type = V4L2_CTRL_TYPE_INTEGER,
-            }, {
-                .id = V4L2_CID_SATURATION,
-                .name = "Saturation",
-                .minimum = 0,
-                .maximum = 10000,
-                .step = 1,
-                .default_value = 5000,
-                .type = V4L2_CTRL_TYPE_INTEGER,
-                }, {
-                    .id = V4L2_CID_HUE,
-                    .name = "Hue",
-                    .minimum = 0,
-                    .maximum = 10000,
-                    .step = 1,
-                    .default_value = 5000,
-                    .type = V4L2_CTRL_TYPE_INTEGER,
-                    }
+               .id = V4L2_CID_BRIGHTNESS,
+               .name = "Brightness",
+               .minimum = 0,
+               .maximum = 10000,
+               .step = 1,
+               .default_value = 6200,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+       }, {
+               .id = V4L2_CID_CONTRAST,
+               .name = "Contrast",
+               .minimum = 0,
+               .maximum = 10000,
+               .step = 1,
+               .default_value = 5000,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+       }, {
+               .id = V4L2_CID_SATURATION,
+               .name = "Saturation",
+               .minimum = 0,
+               .maximum = 10000,
+               .step = 1,
+               .default_value = 5000,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+       }, {
+               .id = V4L2_CID_HUE,
+               .name = "Hue",
+               .minimum = 0,
+               .maximum = 10000,
+               .step = 1,
+               .default_value = 5000,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+       }
 };
 static const int CX25821_CTLS = ARRAY_SIZE(cx25821_ctls);
 
@@ -1623,7 +1618,8 @@ int cx25821_vidioc_cropcap(struct file *file, void *priv,
 
        if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
-       cropcap->bounds.top = cropcap->bounds.left = 0;
+       cropcap->bounds.top = 0;
+       cropcap->bounds.left = 0;
        cropcap->bounds.width = 720;
        cropcap->bounds.height = dev->tvnorm == V4L2_STD_PAL_BG ? 576 : 480;
        cropcap->pixelaspect.numerator =
@@ -1829,8 +1825,11 @@ static long video_ioctl_set(struct file *file, unsigned int cmd,
        struct downstream_user_struct *data_from_user;
        int command;
        int width = 720;
-       int selected_channel = 0, pix_format = 0, i = 0;
-       int cif_enable = 0, cif_width = 0;
+       int selected_channel = 0;
+       int pix_format = 0;
+       int i = 0;
+       int cif_enable = 0;
+       int cif_width = 0;
        u32 value = 0;
 
        data_from_user = (struct downstream_user_struct *)arg;
@@ -1895,8 +1894,8 @@ static long video_ioctl_set(struct file *file, unsigned int cmd,
                }
 
                if (selected_channel <= 7 && selected_channel >= 0) {
-                       dev->channels[selected_channel].
-                               use_cif_resolution = cif_enable;
+                       dev->channels[selected_channel].use_cif_resolution =
+                               cif_enable;
                        dev->channels[selected_channel].cif_width = width;
                } else {
                        for (i = 0; i < VID_CHANNEL_NUM; i++) {
@@ -1932,9 +1931,9 @@ static long video_ioctl_set(struct file *file, unsigned int cmd,
 static long cx25821_video_ioctl(struct file *file,
                                unsigned int cmd, unsigned long arg)
 {
-       int  ret = 0;
+       int ret = 0;
 
-       struct cx25821_fh  *fh  = file->private_data;
+       struct cx25821_fh *fh = file->private_data;
 
        /* check to see if it's the video upstream */
        if (fh->channel_id == SRAM_CH09) {
index 2d2d00932823a09dae7cb07595d1cb42b4613e28..b9aa801b00a7b29c01c45334dd14d6c7c61bb978 100644 (file)
@@ -67,7 +67,7 @@
 #define MAX_CAMERAS             16
 
 /* Max number of inputs by card */
-#define MAX_CX25821_INPUT 8
+#define MAX_CX25821_INPUT     8
 #define INPUT(nr) (&cx25821_boards[dev->board].input[nr])
 #define RESOURCE_VIDEO0       1
 #define RESOURCE_VIDEO1       2
@@ -85,7 +85,7 @@
 
 #define BUFFER_TIMEOUT     (HZ)        /* 0.5 seconds */
 
-#define UNKNOWN_BOARD       0
+#define UNKNOWN_BOARD        0
 #define CX25821_BOARD        1
 
 /* Currently supported by the driver */
index 005f11093642711cc854dce2decb70760ee08fdd..34b96c7cfd620007b88a7082166413c284ac7a0e 100644 (file)
@@ -480,7 +480,6 @@ void cx25840_audio_set_path(struct i2c_client *client)
 
 static void set_volume(struct i2c_client *client, int volume)
 {
-       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        int vol;
 
        /* Convert the volume to msp3400 values (0-127) */
@@ -496,14 +495,7 @@ static void set_volume(struct i2c_client *client, int volume)
        }
 
        /* PATH1_VOLUME */
-       if (is_cx2388x(state)) {
-               /* for cx23885 volume doesn't work,
-                * the calculation always results in
-                * e4 regardless.
-                */
-               cx25840_write(client, 0x8d4, volume);
-       } else
-               cx25840_write(client, 0x8d4, 228 - (vol * 2));
+       cx25840_write(client, 0x8d4, 228 - (vol * 2));
 }
 
 static void set_balance(struct i2c_client *client, int balance)
index cd9976408ab33050498633ee5c8c3e87a8d2f24c..05247d4c340a6c7f74e9a19f21f931571fc675d7 100644 (file)
@@ -18,6 +18,9 @@
  * CX2388[578] IRQ handling, IO Pin mux configuration and other small fixes are
  * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
  *
+ * CX23888 DIF support for the HVR1850
+ * Copyright (C) 2011 Steven Toth <stoth@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; either version 2
@@ -40,6 +43,7 @@
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
+#include <linux/math64.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/cx25840.h>
@@ -80,6 +84,7 @@ MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
 
 
 /* ----------------------------------------------------------------------- */
+static void cx23885_std_setup(struct i2c_client *client);
 
 int cx25840_write(struct i2c_client *client, u16 addr, u8 value)
 {
@@ -498,8 +503,13 @@ static void cx23885_initialize(struct i2c_client *client)
                 * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz
                 * 572.73 MHz before post divide
                 */
-               cx25840_write4(client, 0x11c, 0x00e8ba26);
-               cx25840_write4(client, 0x118, 0x0000040b);
+               /* HVR1850 or 50MHz xtal */
+               cx25840_write(client, 0x2, 0x71);
+               cx25840_write4(client, 0x11c, 0x01d1744c);
+               cx25840_write4(client, 0x118, 0x00000416);
+               cx25840_write4(client, 0x404, 0x0010253e);
+               cx25840_write4(client, 0x42c, 0x42600000);
+               cx25840_write4(client, 0x44c, 0x161f1000);
                break;
        case V4L2_IDENT_CX23887_AV:
                /*
@@ -533,8 +543,18 @@ static void cx23885_initialize(struct i2c_client *client)
         * 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz
         * 432.0 MHz before post divide
         */
-       cx25840_write4(client, 0x10c, 0x002be2c9);
-       cx25840_write4(client, 0x108, 0x0000040f);
+
+       /* HVR1850 */
+       switch (state->id) {
+       case V4L2_IDENT_CX23888_AV:
+               /* 888/HVR1250 specific */
+               cx25840_write4(client, 0x10c, 0x13333333);
+               cx25840_write4(client, 0x108, 0x00000515);
+               break;
+       default:
+               cx25840_write4(client, 0x10c, 0x002be2c9);
+               cx25840_write4(client, 0x108, 0x0000040f);
+       }
 
        /* Luma */
        cx25840_write4(client, 0x414, 0x00107d12);
@@ -556,8 +576,9 @@ static void cx23885_initialize(struct i2c_client *client)
                 * 368.64 MHz before post divide
                 * 122.88 MHz / 0xa = 12.288 MHz
                 */
-               cx25840_write4(client, 0x114, 0x00bedfa4);
-               cx25840_write4(client, 0x110, 0x000a0307);
+               /* HVR1850  or 50MHz xtal */
+               cx25840_write4(client, 0x114, 0x017dbf48);
+               cx25840_write4(client, 0x110, 0x000a030e);
                break;
        case V4L2_IDENT_CX23887_AV:
                /*
@@ -617,7 +638,10 @@ static void cx23885_initialize(struct i2c_client *client)
        finish_wait(&state->fw_wait, &wait);
        destroy_workqueue(q);
 
-       cx25840_std_setup(client);
+       /* Call the cx23885 specific std setup func, we no longer rely on
+        * the generic cx24840 func.
+        */
+       cx23885_std_setup(client);
 
        /* (re)set input */
        set_input(client, state->vid_input, state->aud_input);
@@ -631,6 +655,37 @@ static void cx23885_initialize(struct i2c_client *client)
        /* Disable and clear audio interrupts - we don't use them */
        cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0xff);
        cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff);
+
+       /* CC raw enable */
+       /*  - VIP 1.1 control codes - 10bit, blue field enable.
+        *  - enable raw data during vertical blanking.
+        *  - enable ancillary Data insertion for 656 or VIP.
+        */
+       cx25840_write4(client, 0x404, 0x0010253e);
+
+       /* CC on  - Undocumented Register */
+       cx25840_write(client, 0x42f, 0x66);
+
+       /* HVR-1250 / HVR1850 DIF related */
+       /* Power everything up */
+       cx25840_write4(client, 0x130, 0x0);
+
+       /* Undocumented */
+       cx25840_write4(client, 0x478, 0x6628021F);
+
+       /* AFE_CLK_OUT_CTRL - Select the clock output source as output */
+       cx25840_write4(client, 0x144, 0x5);
+
+       /* I2C_OUT_CTL - I2S output configuration as
+        * Master, Sony, Left justified, left sample on WS=1
+        */
+       cx25840_write4(client, 0x918, 0x1a0);
+
+       /* AFE_DIAG_CTRL1 */
+       cx25840_write4(client, 0x134, 0x000a1800);
+
+       /* AFE_DIAG_CTRL3 - Inverted Polarity for Audio and Video */
+       cx25840_write4(client, 0x13c, 0x00310000);
 }
 
 /* ----------------------------------------------------------------------- */
@@ -945,9 +1000,14 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
                           vid_input <= CX25840_COMPOSITE8);
        u8 is_component = (vid_input & CX25840_COMPONENT_ON) ==
                        CX25840_COMPONENT_ON;
+       u8 is_dif = (vid_input & CX25840_DIF_ON) ==
+                       CX25840_DIF_ON;
+       u8 is_svideo = (vid_input & CX25840_SVIDEO_ON) ==
+                       CX25840_SVIDEO_ON;
        int luma = vid_input & 0xf0;
        int chroma = vid_input & 0xf00;
        u8 reg;
+       u32 val;
 
        v4l_dbg(1, cx25840_debug, client,
                "decoder set video input %d, audio input %d\n",
@@ -1012,6 +1072,66 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
        else
                cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
 
+       if (is_cx2388x(state)) {
+
+               /* Enable or disable the DIF for tuner use */
+               if (is_dif) {
+                       cx25840_and_or(client, 0x102, ~0x80, 0x80);
+
+                       /* Set of defaults for NTSC and PAL */
+                       cx25840_write4(client, 0x31c, 0xc2262600);
+                       cx25840_write4(client, 0x320, 0xc2262600);
+
+                       /* 18271 IF - Nobody else yet uses a different
+                        * tuner with the DIF, so these are reasonable
+                        * assumptions (HVR1250 and HVR1850 specific).
+                        */
+                       cx25840_write4(client, 0x318, 0xda262600);
+                       cx25840_write4(client, 0x33c, 0x2a24c800);
+                       cx25840_write4(client, 0x104, 0x0704dd00);
+               } else {
+                       cx25840_write4(client, 0x300, 0x015c28f5);
+
+                       cx25840_and_or(client, 0x102, ~0x80, 0);
+                       cx25840_write4(client, 0x340, 0xdf7df83);
+                       cx25840_write4(client, 0x104, 0x0704dd80);
+                       cx25840_write4(client, 0x314, 0x22400600);
+                       cx25840_write4(client, 0x318, 0x40002600);
+                       cx25840_write4(client, 0x324, 0x40002600);
+                       cx25840_write4(client, 0x32c, 0x0250e620);
+                       cx25840_write4(client, 0x39c, 0x01FF0B00);
+
+                       cx25840_write4(client, 0x410, 0xffff0dbf);
+                       cx25840_write4(client, 0x414, 0x00137d03);
+                       cx25840_write4(client, 0x418, 0x01008080);
+                       cx25840_write4(client, 0x41c, 0x00000000);
+                       cx25840_write4(client, 0x420, 0x001c3e0f);
+                       cx25840_write4(client, 0x42c, 0x42600000);
+                       cx25840_write4(client, 0x430, 0x0000039b);
+                       cx25840_write4(client, 0x438, 0x00000000);
+
+                       cx25840_write4(client, 0x440, 0xF8E3E824);
+                       cx25840_write4(client, 0x444, 0x401040dc);
+                       cx25840_write4(client, 0x448, 0xcd3f02a0);
+                       cx25840_write4(client, 0x44c, 0x161f1000);
+                       cx25840_write4(client, 0x450, 0x00000802);
+
+                       cx25840_write4(client, 0x91c, 0x01000000);
+                       cx25840_write4(client, 0x8e0, 0x03063870);
+                       cx25840_write4(client, 0x8d4, 0x7FFF0024);
+                       cx25840_write4(client, 0x8d0, 0x00063073);
+
+                       cx25840_write4(client, 0x8c8, 0x00010000);
+                       cx25840_write4(client, 0x8cc, 0x00080023);
+
+                       /* DIF BYPASS */
+                       cx25840_write4(client, 0x33c, 0x2a04c800);
+               }
+
+               /* Reset the DIF */
+               cx25840_write4(client, 0x398, 0);
+       }
+
        if (!is_cx2388x(state) && !is_cx231xx(state)) {
                /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
                cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
@@ -1036,6 +1156,33 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
                                cx25840_and_or(client, 0x102, ~0x2, 0);
                        }
                }
+
+               /* cx23885 / SVIDEO */
+               if (is_cx2388x(state) && is_svideo) {
+#define AFE_CTRL  (0x104)
+#define MODE_CTRL (0x400)
+                       cx25840_and_or(client, 0x102, ~0x2, 0x2);
+
+                       val = cx25840_read4(client, MODE_CTRL);
+                       val &= 0xFFFFF9FF;
+
+                       /* YC */
+                       val |= 0x00000200;
+                       val &= ~0x2000;
+                       cx25840_write4(client, MODE_CTRL, val);
+
+                       val = cx25840_read4(client, AFE_CTRL);
+
+                       /* Chroma in select */
+                       val |= 0x00001000;
+                       val &= 0xfffffe7f;
+                       /* Clear VGA_SEL_CH2 and VGA_SEL_CH3 (bits 7 and 8).
+                        * This sets them to use video rather than audio.
+                        * Only one of the two will be in use.
+                        */
+                       cx25840_write4(client, AFE_CTRL, val);
+               } else
+                       cx25840_and_or(client, 0x102, ~0x2, 0);
        }
 
        state->vid_input = vid_input;
@@ -1086,6 +1233,23 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
                cx25840_write4(client, 0x8d0, 0x1f063870);
        }
 
+       if (is_cx2388x(state)) {
+               /* HVR1850 */
+               /* AUD_IO_CTRL - I2S Input, Parallel1*/
+               /*  - Channel 1 src - Parallel1 (Merlin out) */
+               /*  - Channel 2 src - Parallel2 (Merlin out) */
+               /*  - Channel 3 src - Parallel3 (Merlin AC97 out) */
+               /*  - I2S source and dir - Merlin, output */
+               cx25840_write4(client, 0x124, 0x100);
+
+               if (!is_dif) {
+                       /* Stop microcontroller if we don't need it
+                        * to avoid audio popping on svideo/composite use.
+                        */
+                       cx25840_and_or(client, 0x803, ~0x10, 0x00);
+               }
+       }
+
        return 0;
 }
 
@@ -1134,7 +1298,10 @@ static int set_v4lstd(struct i2c_client *client)
        }
        cx25840_and_or(client, 0x400, ~0xf, fmt);
        cx25840_and_or(client, 0x403, ~0x3, pal_m);
-       cx25840_std_setup(client);
+       if (is_cx2388x(state))
+               cx23885_std_setup(client);
+       else
+               cx25840_std_setup(client);
        if (!is_cx2583x(state))
                input_change(client);
        return 0;
@@ -1539,6 +1706,56 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
        return 0;
 }
 
+/* Query the current detected video format */
+static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       v4l2_std_id stds[] = {
+               /* 0000 */ V4L2_STD_UNKNOWN,
+
+               /* 0001 */ V4L2_STD_NTSC_M,
+               /* 0010 */ V4L2_STD_NTSC_M_JP,
+               /* 0011 */ V4L2_STD_NTSC_443,
+               /* 0100 */ V4L2_STD_PAL,
+               /* 0101 */ V4L2_STD_PAL_M,
+               /* 0110 */ V4L2_STD_PAL_N,
+               /* 0111 */ V4L2_STD_PAL_Nc,
+               /* 1000 */ V4L2_STD_PAL_60,
+
+               /* 1001 */ V4L2_STD_UNKNOWN,
+               /* 1010 */ V4L2_STD_UNKNOWN,
+               /* 1001 */ V4L2_STD_UNKNOWN,
+               /* 1010 */ V4L2_STD_UNKNOWN,
+               /* 1011 */ V4L2_STD_UNKNOWN,
+               /* 1110 */ V4L2_STD_UNKNOWN,
+               /* 1111 */ V4L2_STD_UNKNOWN
+       };
+
+       u32 fmt = (cx25840_read4(client, 0x40c) >> 8) & 0xf;
+       *std = stds[ fmt ];
+
+       v4l_dbg(1, cx25840_debug, client, "g_std fmt = %x, v4l2_std_id = 0x%x\n",
+               fmt, (unsigned int)stds[ fmt ]);
+
+       return 0;
+}
+
+static int cx25840_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       /* A limited function that checks for signal status and returns
+        * the state.
+        */
+
+       /* Check for status of Horizontal lock (SRC lock isn't reliable) */
+       if ((cx25840_read4(client, 0x40c) & 0x00010000) == 0)
+               *status |= V4L2_IN_ST_NO_SIGNAL;
+
+       return 0;
+}
+
 static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 {
        struct cx25840_state *state = to_state(sd);
@@ -1565,6 +1782,9 @@ static int cx25840_s_video_routing(struct v4l2_subdev *sd,
        struct cx25840_state *state = to_state(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
+       if (is_cx2388x(state))
+               cx23885_std_setup(client);
+
        return set_input(client, input, state->aud_input);
 }
 
@@ -1574,6 +1794,8 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd,
        struct cx25840_state *state = to_state(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
+       if (is_cx2388x(state))
+               cx23885_std_setup(client);
        return set_input(client, state->vid_input, input);
 }
 
@@ -1786,6 +2008,3007 @@ static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status,
 
 /* ----------------------------------------------------------------------- */
 
+#define DIF_PLL_FREQ_WORD      (0x300)
+#define DIF_BPF_COEFF01                (0x348)
+#define DIF_BPF_COEFF23                (0x34c)
+#define DIF_BPF_COEFF45                (0x350)
+#define DIF_BPF_COEFF67                (0x354)
+#define DIF_BPF_COEFF89                (0x358)
+#define DIF_BPF_COEFF1011      (0x35c)
+#define DIF_BPF_COEFF1213      (0x360)
+#define DIF_BPF_COEFF1415      (0x364)
+#define DIF_BPF_COEFF1617      (0x368)
+#define DIF_BPF_COEFF1819      (0x36c)
+#define DIF_BPF_COEFF2021      (0x370)
+#define DIF_BPF_COEFF2223      (0x374)
+#define DIF_BPF_COEFF2425      (0x378)
+#define DIF_BPF_COEFF2627      (0x37c)
+#define DIF_BPF_COEFF2829      (0x380)
+#define DIF_BPF_COEFF3031      (0x384)
+#define DIF_BPF_COEFF3233      (0x388)
+#define DIF_BPF_COEFF3435      (0x38c)
+#define DIF_BPF_COEFF36                (0x390)
+
+void cx23885_dif_setup(struct i2c_client *client, u32 ifHz)
+{
+       u64 pll_freq;
+       u32 pll_freq_word;
+
+       v4l_dbg(1, cx25840_debug, client, "%s(%d)\n", __func__, ifHz);
+
+       /* Assuming TV */
+       /* Calculate the PLL frequency word based on the adjusted ifHz */
+        pll_freq = div_u64((u64)ifHz * 268435456, 50000000);
+        pll_freq_word = (u32)pll_freq;
+
+        cx25840_write4(client, DIF_PLL_FREQ_WORD,  pll_freq_word);
+
+       /* Round down to the nearest 100KHz */
+       ifHz = (ifHz / 100000) * 100000;
+
+       if (ifHz < 3000000)
+               ifHz = 3000000;
+
+       if (ifHz > 16000000)
+               ifHz = 16000000;
+
+       v4l_dbg(1, cx25840_debug, client, "%s(%d) again\n", __func__, ifHz);
+
+       switch (ifHz) {
+       case 3000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0024);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x001bfff8);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff50);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed8fe68);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe34);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfebaffc7);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d031f);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x04f0065d);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x07010688);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x04c901d6);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f9d3);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f342);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f337);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf64efb22);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105070f);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x0c460fce);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 3100000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00220032);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00370026);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff91);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0efe7c);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fdcc);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe0afedb);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440224);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0434060c);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738074e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x06090361);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99fb39);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef3b6);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21af2a5);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf573fa33);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034067d);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bfb0fb9);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 3200000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000e);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00200038);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x004c004f);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x002fffdf);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff5cfeb6);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dfd92);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7ffe03);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36010a);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x03410575);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x072607d2);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x071804d5);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134fcb7);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff451);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223f22e);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4a7f94b);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xff6405e8);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bae0fa4);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 3300000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00000008);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0036);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0056006d);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00670030);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xffbdff10);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46fd8d);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd25fd4f);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35ffe0);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0224049f);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9080e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x07ef0627);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9fe45);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f513);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250f1d2);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3ecf869);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930552);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b5f0f8f);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 3400000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0001);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x000f002c);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0054007d);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0093007c);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0024ff82);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6fdbb);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd03fcca);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51feb9);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x00eb0392);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270802);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x08880750);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x044dffdb);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf5f8);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0f193);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf342f78f);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc404b9);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b0e0f78);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 3500000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff9);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0002001b);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0046007d);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad00ba);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00870000);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe1a);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1bfc7e);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fda4);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xffa5025c);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x054507ad);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x08dd0847);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80172);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef6ff);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313f170);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2abf6bd);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6041f);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x0abc0f61);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 3600000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff3);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfff50006);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x002f006c);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00b200e3);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00dc007e);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9fea0);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd6bfc71);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fcb1);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe65010b);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x042d0713);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ec0906);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020302);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff823);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7f16a);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf228f5f5);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2a0384);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a670f4a);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 3700000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7ffef);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9fff1);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0010004d);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00a100f2);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x011a00f0);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053ff44);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdedfca2);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fbef);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd39ffae);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x02ea0638);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x08b50987);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230483);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f960);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45bf180);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1b8f537);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb6102e7);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a110f32);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 3800000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffdd);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00024);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x007c00e5);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x013a014a);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e6fff8);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe98fd0f);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fb67);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc32fe54);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x01880525);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x083909c7);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x091505ee);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7fab3);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52df1b4);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf15df484);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9b0249);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x09ba0f19);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 3900000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff0);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffcf);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1fff6);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x004800be);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x01390184);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x016300ac);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xff5efdb1);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb23);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb5cfd0d);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x001703e4);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x077b09c4);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d2073c);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251fc18);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61cf203);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf118f3dc);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d801aa);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x09600eff);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 4000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffefff4);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffc8);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffca);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x000b0082);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x01170198);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10152);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0030fe7b);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb24);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfac3fbe9);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5027f);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x0683097f);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a560867);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2fd89);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723f26f);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0e8f341);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919010a);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x09060ee5);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 4100000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fffb);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8ffca);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffa4);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffcd0036);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d70184);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f601dc);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ffff60);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb6d);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6efaf5);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd410103);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x055708f9);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e0969);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543ff02);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842f2f5);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cef2b2);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85e006b);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x08aa0ecb);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 4200000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00050003);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfff3ffd3);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaff8b);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ffe5);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0080014a);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe023f);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ba0050);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fbf8);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa62fa3b);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9ff7e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x04010836);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa90a3d);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f007f);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf975f395);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cbf231);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ffcb);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x084c0eaf);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 4300000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000a);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0000ffe4);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff81);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff96);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x001c00f0);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70271);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0254013b);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fcbd);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa9ff9c5);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbfdfe);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x028c073b);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a750adf);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e101fa);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab8f44e);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0ddf1be);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ff2b);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x07ed0e94);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 4400000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000f);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x000efff8);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff87);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff54);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xffb5007e);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01860270);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c00210);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fdb2);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb22f997);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2fc90);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x0102060f);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a050b4c);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902036e);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0af51e);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf106f15a);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64efe8b);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x078d0e77);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 4500000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0019000e);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff9e);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff25);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff560000);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112023b);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f702c0);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfec8);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbe5f9b3);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947fb41);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xff7004b9);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a0b81);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a0004d8);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd65f603);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf144f104);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aafdec);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x072b0e5a);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 4600000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00060012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00200022);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ffc1);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ff10);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff09ff82);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x008601d7);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f50340);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fff0);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcddfa19);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa1e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfde30343);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x08790b7f);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50631);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec7f6fc);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf198f0bd);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50dfd4e);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x06c90e3d);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 4700000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00220030);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffed);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff87ff15);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed6ff10);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xffed014c);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b90386);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110119);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfdfefac4);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6f92f);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc6701b7);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x07670b44);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0776);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x002df807);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf200f086);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477fcb1);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x06650e1e);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 4800000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0009);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0038);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x003f001b);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffbcff36);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec2feb6);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xff5600a5);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0248038d);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00232);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xff39fbab);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4f87f);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb060020);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x062a0ad2);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf908a3);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0192f922);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf27df05e);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8fc14);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x06000e00);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 4900000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0002);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00160037);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00510046);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xfff9ff6d);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed0fe7c);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefff0);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x01aa0356);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413032b);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x007ffcc5);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cf812);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9cefe87);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c90a2c);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4309b4);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f3fa4a);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf30ef046);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361fb7a);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x059b0de0);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 5000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x000a002d);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00570067);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0037ffb5);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfefffe68);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62ff3d);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ec02e3);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x043503f6);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x01befe05);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa27f7ee);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8c6fcf8);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x034c0954);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0aa4);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x044cfb7e);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3b1f03f);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2fae1);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x05340dc0);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 5100000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff4);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfffd001e);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0051007b);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x006e0006);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff48fe7c);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfe9a);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x001d023e);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130488);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x02e6ff5b);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1ef812);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7f7fb7f);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bc084e);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430b72);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x059afcba);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf467f046);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cfa4a);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x04cd0da0);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 5200000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffef);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfff00009);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x003f007f);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00980056);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xffa5feb6);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe15);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xff4b0170);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b004d7);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x03e800b9);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc48f87f);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf768fa23);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022071f);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90c1b);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x06dafdfd);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf52df05e);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef9b5);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x04640d7f);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 5300000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6fff3);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00250072);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00af009c);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x000cff10);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13fdb8);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe870089);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104e1);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x04b8020f);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd98f92f);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf71df8f0);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe8805ce);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0c9c);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0808ff44);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf603f086);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af922);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x03fb0d5e);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 5400000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffef);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe0);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00050056);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00b000d1);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0071ff82);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53fd8c);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfddfff99);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104a3);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x054a034d);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xff01fa1e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf717f7ed);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf50461);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50cf4);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0921008d);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf6e7f0bd);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff891);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x03920d3b);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 5500000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffffff3);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffd1);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5002f);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x009c00ed);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00cb0000);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfebafd94);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd61feb0);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d0422);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x05970464);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0074fb41);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf759f721);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb7502de);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000d21);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a2201d4);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7d9f104);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf804);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x03280d19);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 5600000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fffa);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3ffc9);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffc90002);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x007500ef);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x010e007e);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3dfdcf);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd16fddd);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440365);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x059b0548);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3fc90);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7dff691);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0f014d);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020d23);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0318);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8d7f15a);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f779);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x02bd0cf6);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 5700000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00060001);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffecffc9);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffd4);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x004000d5);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x013600f0);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd3fe39);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd04fd31);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xff360277);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x055605ef);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x033efdfe);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8a5f642);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbffb6);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10cfb);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50456);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9dff1be);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f6f2);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x02520cd2);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 5800000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00080009);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfff8ffd2);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffac);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x000200a3);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x013c014a);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x006dfec9);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2bfcb7);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe350165);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x04cb0651);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477ff7e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9a5f635);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1fe20);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0ca8);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c81058b);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xfaf0f231);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f66d);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x01e60cae);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 5900000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000e);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0005ffe1);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffacff90);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5005f);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x01210184);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fcff72);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd8afc77);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51003f);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x04020669);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830103);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfad7f66b);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8fc93);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430c2b);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d06b5);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xfc08f2b2);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af5ec);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x017b0c89);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 6000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0012fff5);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaff82);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff8e000f);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e80198);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750028);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe18fc75);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99ff15);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x03050636);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0656027f);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc32f6e2);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614fb17);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20b87);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d7707d2);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xfd26f341);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf56f);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x010f0c64);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 6100000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00050012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001c000b);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff84);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ffbe);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00960184);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd00da);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeccfcb2);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fdf9);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x01e005bc);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e703e4);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfdabf798);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f9b3);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510abd);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf08df);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xfe48f3dc);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f4f6);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x00a20c3e);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 6200000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0002000f);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0021001f);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff97);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff74);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0034014a);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa0179);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xff97fd2a);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fcfa);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x00a304fe);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310525);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xff37f886);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf86e);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c709d0);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de209db);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xff6df484);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf481);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0x00360c18);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 6300000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe000a);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0021002f);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ffb8);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff3b);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xffcc00f0);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa01fa);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0069fdd4);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fc26);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xff5d0407);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310638);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x00c9f9a8);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf74e);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xff3908c3);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de20ac3);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0093f537);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf410);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xffca0bf2);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 6400000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb0003);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001c0037);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x002fffe2);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ff17);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff6a007e);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd0251);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0134fea5);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb8b);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe2002e0);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e70713);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x0255faf5);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f658);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0799);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf0b96);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x01b8f5f5);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f3a3);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xff5e0bca);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 6500000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00120037);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00460010);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff8eff0f);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff180000);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750276);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x01e8ff8d);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb31);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcfb0198);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x065607ad);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x03cefc64);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614f592);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0656);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d770c52);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x02daf6bd);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf33b);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xfef10ba3);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 6600000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff5);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0005002f);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0054003c);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5ff22);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedfff82);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fc0267);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0276007e);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb1c);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbfe003e);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830802);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x0529fdec);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8f4fe);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd04ff);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d0cf6);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x03f8f78f);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af2d7);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe850b7b);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 6700000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfff80020);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00560060);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0002ff4e);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec4ff10);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x006d0225);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02d50166);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb4e);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb35fee1);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477080e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x065bff82);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1f4a0);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610397);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c810d80);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0510f869);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f278);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe1a0b52);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 6800000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffaffee);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffec000c);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0078);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0040ff8e);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecafeb6);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd301b6);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fc0235);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fbc5);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaaafd90);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x033e07d2);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x075b011b);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbf47a);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f0224);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50def);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0621f94b);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f21e);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xfdae0b29);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 6900000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffef);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3fff6);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0037007f);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0075ffdc);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef2fe7c);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3d0122);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02ea02dd);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fc79);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa65fc5d);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3074e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x082102ad);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0ff48c);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe00a9);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0e43);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0729fa33);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f1c9);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xfd430b00);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 7000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0001fff3);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe2);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x001b0076);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x009c002d);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff35fe68);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfeba0076);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x029f0352);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfd60);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa69fb53);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x00740688);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x08a7042d);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb75f4d6);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600ff2d);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a220e7a);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0827fb22);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf17a);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xfcd80ad6);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 7100000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff9);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffd2);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb005e);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00b0007a);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8ffe7c);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53ffc1);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0221038c);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fe6e);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfab6fa80);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xff010587);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e90590);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf5f556);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfdb3);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x09210e95);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0919fc15);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff12f);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc6e0aab);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 7200000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00070000);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6ffc9);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0039);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00af00b8);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfff4feb6);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13ff10);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x01790388);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311ff92);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb48f9ed);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd980453);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e306cd);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe88f60a);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fc40);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x08080e93);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x09fdfd0c);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af0ea);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc050a81);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 7300000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00080008);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfff0ffc9);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1000d);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x009800e2);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x005bff10);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe74);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x00b50345);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000bc);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc18f9a1);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc4802f9);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x089807dc);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022f6f0);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fada);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x06da0e74);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ad3fe06);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef0ab);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb9c0a55);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 7400000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000e);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfffdffd0);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffdf);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x006e00f2);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00b8ff82);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfdf8);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xffe302c8);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x041301dc);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd1af99e);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1e0183);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x080908b5);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bcf801);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf985);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x059a0e38);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b99ff03);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cf071);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb330a2a);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 7500000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00070011);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x000affdf);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffa9ffb5);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x003700e6);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x01010000);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62fda8);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xff140219);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x043502e1);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe42f9e6);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa270000);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x073a0953);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x034cf939);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a4f845);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x044c0de1);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c4f0000);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2f03c);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xfacc09fe);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 7600000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00040012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0016fff3);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffafff95);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xfff900c0);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0130007e);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefd89);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe560146);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x041303bc);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xff81fa76);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cfe7d);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x063209b1);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c9fa93);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf71e);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f30d6e);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cf200fd);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361f00e);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa6509d1);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 7700000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00010010);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0008);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ff84);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffbc0084);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x013e00f0);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xff56fd9f);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdb8005c);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00460);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x00c7fb45);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4fd07);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x04fa09ce);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x062afc07);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407f614);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x01920ce0);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d8301fa);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8efe5);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa0009a4);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 7800000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd000b);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001d);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff82);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff870039);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x012a014a);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xffedfde7);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd47ff6b);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104c6);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0202fc4c);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6fbad);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x039909a7);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0767fd8e);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482f52b);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x002d0c39);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e0002f4);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477efc2);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf99b0977);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 7900000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa0004);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0020002d);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff91);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ffe8);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f70184);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x0086fe5c);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0bfe85);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104e5);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0323fd7d);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa79);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x021d093f);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0879ff22);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bf465);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec70b79);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e6803eb);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50defa5);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf937094a);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 8000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffd);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00190036);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x001bffaf);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff99);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00aa0198);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112fef3);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd09fdb9);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04be);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x041bfecc);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947f978);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x00900897);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a00b9);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f3c5);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd650aa3);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ebc04de);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aaef8e);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf8d5091c);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 8100000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff6);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x000e0038);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ffd7);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff56);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x004b0184);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x0186ffa1);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd40fd16);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440452);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x04de0029);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2f8b2);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfefe07b5);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a05024d);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef34d);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0a09b8);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0efa05cd);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64eef7d);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf87308ed);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 8200000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00000031);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0005);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff27);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xffe4014a);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70057);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdacfca6);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3603a7);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x05610184);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbf82e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd74069f);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a7503d6);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff2ff);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab808b9);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f2306b5);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ef72);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf81308bf);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 8300000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbffee);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfff30022);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00560032);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ff10);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8000f0);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe0106);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe46fc71);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3502c7);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x059e02ce);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9f7f2);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfbff055b);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa9054c);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f2db);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf97507aa);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f350797);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ef6d);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7b40890);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 8400000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffee);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8000f);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00540058);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffcdff14);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff29007e);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f6019e);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xff01fc7c);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5101bf);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x059203f6);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd41f7fe);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfaa903f3);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e06a9);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf2e2);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842068b);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f320871);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85eef6e);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7560860);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 8500000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fff2);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1fff9);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00460073);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x000bff34);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee90000);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10215);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xffd0fcc5);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99009d);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x053d04f1);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5f853);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf97d0270);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a5607e4);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef314);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723055f);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f180943);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919ef75);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6fa0830);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 8600000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff8);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe4);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x002f007f);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0048ff6b);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec7ff82);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x0163025f);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x00a2fd47);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff73);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x04a405b2);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0017f8ed);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf88500dc);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d208f9);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff370);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61c0429);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ee80a0b);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d8ef82);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6a00800);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 8700000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0007ffff);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffd4);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0010007a);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x007cffb2);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec6ff10);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e60277);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0168fdf9);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fe50);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x03ce0631);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0188f9c8);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7c7ff43);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x091509e3);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f3f6);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52d02ea);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ea30ac9);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9bef95);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf64607d0);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 8800000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00090007);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9ffca);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00065);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00a10003);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee6feb6);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053025b);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0213fed0);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fd46);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x02c70668);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x02eafadb);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf74bfdae);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230a9c);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f4a3);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45b01a6);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e480b7c);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb61efae);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf5ef079f);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 8900000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000d);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfff5ffc8);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10043);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00b20053);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff24fe7c);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9020c);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0295ffbb);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fc64);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x019b0654);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x042dfc1c);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf714fc2a);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020b21);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f575);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7005e);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0dd80c24);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2aefcd);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf599076e);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 9000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00060011);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0002ffcf);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffba0018);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad009a);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff79fe68);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xff260192);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e500ab);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fbb6);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x005b05f7);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545fd81);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf723fabf);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80b70);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f669);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313ff15);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d550cbf);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6eff2);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544073d);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 9100000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00030012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x000fffdd);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffea);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x009300cf);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdcfe7c);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea600f7);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fd0190);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb46);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xff150554);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0627fefd);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf778f978);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x044d0b87);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f77d);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0fdcf);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbe0d4e);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc4f01d);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2070b);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 9200000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00000010);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001afff0);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffbf);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x006700ed);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043feb6);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe460047);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02db0258);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb1b);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddc0473);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c90082);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf811f85e);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c90b66);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff8ad);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250fc8d);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c140dcf);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe93f04d);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a106d9);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 9300000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc000c);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00200006);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff9c);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x002f00ef);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a4ff10);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dff92);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x028102f7);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb37);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbf035e);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x07260202);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e8f778);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x01340b0d);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f9f4);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223fb51);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b590e42);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xff64f083);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf45206a7);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 9400000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90005);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001a);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff86);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xfff000d7);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2ff82);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fee5);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f60362);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb99);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbcc0222);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x07380370);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f7f6cc);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xff990a7e);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902fb50);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21afa1f);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8d0ea6);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034f0bf);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4050675);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 9500000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffe);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001e002b);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff81);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffb400a5);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe50);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x01460390);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfc3a);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb1000ce);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x070104bf);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb37f65f);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe0009bc);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00fcbb);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f8f8);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b20efc);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105f101);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3ba0642);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 9600000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff7);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00150036);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff8c);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff810061);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x013d007e);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe71fddf);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x007c0380);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fd13);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa94ff70);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x068005e2);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9bf633);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc7308ca);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5fe30);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf274f7e0);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c90f43);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d4f147);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371060f);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 9700000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fff1);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00090038);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffa7);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff5e0012);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x013200f0);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee3fd9b);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaa0331);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fe15);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa60fe18);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bd06d1);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1bf64a);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafa07ae);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7effab);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d5f6d7);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d30f7a);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a3f194);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf32905dc);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 9800000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffee);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfffb0032);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x003fffcd);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effc1);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106014a);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6efd8a);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfedd02aa);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0ff34);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa74fcd7);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bf0781);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaaf6a3);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99e066b);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90128);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf359f5e1);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d20fa2);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0370f1e5);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e405a8);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 9900000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffee);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffef0024);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0051fffa);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff54ff77);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00be0184);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x0006fdad);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe2701f3);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413005e);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad1fbba);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x039007ee);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x013bf73d);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868050a);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4302a1);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fdf4fe);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c70fba);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x043bf23c);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a10575);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 10000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fff1);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe50011);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00570027);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff70ff3c);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00620198);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x009efe01);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95011a);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350183);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb71fad0);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x023c0812);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c3f811);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75e0390);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0411);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c1f432);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b30fc1);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0503f297);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2610541);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 10100000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0006fff7);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffdffffc);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00510050);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff9dff18);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffc0184);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x0128fe80);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32002e);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130292);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4dfa21);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d107ee);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x0435f91c);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6850205);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430573);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a1f37d);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x03990fba);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c7f2f8);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222050d);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 10200000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffe);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffdfffe7);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x003f006e);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffd6ff0f);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96014a);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x0197ff1f);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd05ff3e);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0037c);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd59f9b7);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5d0781);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x0585fa56);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4006f);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf906c4);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69df2e0);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x02790fa2);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0688f35d);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e604d8);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 10300000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00090005);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4ffd6);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0025007e);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0014ff20);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3c00f0);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e1ffd0);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd12fe5c);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110433);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88f996);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf106d1);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aafbb7);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57efed8);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e07ff);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b0f25e);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x01560f7a);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0745f3c7);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1ac04a4);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 10400000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000c);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffedffcb);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0005007d);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0050ff4c);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6007e);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ff0086);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd58fd97);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104ad);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xffcaf9c0);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc9905e2);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x079afd35);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf555fd46);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50920);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d9f1f6);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x00310f43);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fdf435);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174046f);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 10500000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00050011);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfffaffc8);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5006b);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0082ff8c);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f00130);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd2fcfc);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04e3);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x010efa32);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb6404bf);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x084efec5);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569fbc2);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000a23);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa15f1ab);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0b0efc);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b0f4a7);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13f043a);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 10600000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00020012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0007ffcd);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9004c);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00a4ffd9);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3ff82);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b401c1);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe76fc97);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404d2);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0245fae8);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5f0370);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1005f);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bcfa52);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020b04);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb60f17b);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde70ea6);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x095df51e);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10c0405);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 10700000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0011);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0014ffdb);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40023);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2002a);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedbff10);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150022d);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xff38fc6f);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36047b);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x035efbda);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9940202);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ee01f5);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf649f8fe);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10bc2);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb6f169);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc60e42);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a04f599);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0db03d0);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 10800000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb000d);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001dffed);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffaafff5);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00aa0077);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13feb6);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x00ce026b);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x000afc85);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3503e3);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x044cfcfb);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90c0082);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5037f);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf710f7cc);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0c59);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe16f173);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaa0dcf);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa5f617);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0ad039b);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 10900000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90006);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00210003);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffc8);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x008e00b6);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff63fe7c);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x003a0275);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x00dafcda);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd510313);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0501fe40);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cbfefd);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x087604f0);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80af6c2);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430cc8);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7af19a);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa940d4e);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3ff699);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0810365);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 11000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffff);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00210018);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffa3);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x006000e1);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc4fe68);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0024b);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x019afd66);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc990216);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0575ff99);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4fd81);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d40640);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf932f5e6);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20d0d);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x00dff1de);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9860cbf);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd1f71e);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058032f);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 11100000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff8);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001b0029);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff8a);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x002600f2);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x002cfe7c);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0f01f0);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x023bfe20);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc1700fa);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a200f7);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf927fc1c);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f40765);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa82f53b);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510d27);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0243f23d);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8810c24);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5cf7a7);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf03102fa);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 11200000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00110035);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff81);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffe700e7);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x008ffeb6);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94016d);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b0fefb);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3ffd1);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x05850249);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c1fadb);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x05de0858);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf2f4c4);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c70d17);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a0f2b8);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7870b7c);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdff833);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00d02c4);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 11300000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffee);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00040038);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ff88);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffac00c2);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e2ff10);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe3900cb);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f1ffe9);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3feaa);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x05210381);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9cf9c8);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x04990912);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7af484);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xff390cdb);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f4f34d);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69a0ac9);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5af8c1);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xefec028e);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 11400000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0000ffee);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfff60033);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x002fff9f);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff7b0087);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x011eff82);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe080018);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f900d8);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fd96);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x04790490);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbadf8ed);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x032f098e);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xff10f47d);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0c75);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x063cf3fc);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5ba0a0b);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dccf952);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcd0258);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 11500000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff1);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffea0026);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0046ffc3);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff5a003c);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04ff63);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c801b8);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fca6);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397056a);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcecf853);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x01ad09c9);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x00acf4ad);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0be7);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0773f4c2);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e90943);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35f9e6);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb10221);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 11600000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff6);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe20014);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0054ffee);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effeb);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137007e);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2efebb);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260027a);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fbe6);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x02870605);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4af7fe);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x001d09c1);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0243f515);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd0b32);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0897f59e);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4280871);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e95fa7c);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef9701eb);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 11700000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffd);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffff);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0056001d);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff57ff9c);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x011300f0);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe82fe2e);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ca0310);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb62);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155065a);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xffbaf7f2);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8c0977);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x03cef5b2);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610a58);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a5f68f);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3790797);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eebfb14);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef8001b5);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 11800000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00080004);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe9);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0047);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff75ff58);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1014a);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef9fdc8);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111036f);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb21);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x00120665);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x012df82e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd0708ec);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542f682);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f095c);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9af792);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2db06b5);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f38fbad);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6c017e);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 11900000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000b);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe7ffd8);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00370068);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffa4ff28);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00790184);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87fd91);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x00430392);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb26);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfece0626);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294f8b2);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb990825);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0698f77f);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe0842);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b73f8a7);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf25105cd);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7bfc48);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5a0148);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 12000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00050010);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfff2ffcc);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x001b007b);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffdfff10);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00140198);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x0020fd8e);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xff710375);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb73);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9a059f);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e0f978);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4e0726);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c8f8a7);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600070c);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2ff9c9);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1db04de);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4fce5);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4b0111);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 12100000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00010012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffffffc8);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb007e);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x001dff14);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xffad0184);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b7fdbe);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9031b);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fc01);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc8504d6);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0504fa79);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf93005f6);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x08caf9f2);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52b05c0);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccbfaf9);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf17903eb);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3fd83);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3f00db);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 12200000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe0011);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x000cffcc);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0071);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0058ff32);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4f014a);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x013cfe1f);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfb028a);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fcc9);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9d03d6);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f4fbad);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848049d);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0999fb5b);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf4820461);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d46fc32);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12d02f4);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x1007fe21);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3600a4);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 12300000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0017ffd9);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffc10055);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0088ff68);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0400f0);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a6fea7);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7501cc);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fdc0);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaef02a8);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a7fd07);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79d0326);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a31fcda);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf40702f3);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9ffd72);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f601fa);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x1021fec0);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2f006d);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 12400000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80007);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001fffeb);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffaf002d);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00a8ffb0);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3007e);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e9ff4c);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2000ee);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fed8);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82015c);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0715fe7d);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7340198);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8dfe69);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bd017c);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd5feb8);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d500fd);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x1031ff60);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2b0037);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 12500000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff70000);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00220000);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffa90000);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00b30000);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec20000);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x02000000);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd030000);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350000);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa5e0000);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x073b0000);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7110000);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aac0000);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a40000);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de70000);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0c90000);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x10360000);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef290000);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 12600000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff9);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001f0015);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffd3);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00a80050);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3ff82);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e900b4);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd20ff12);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130128);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82fea4);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x07150183);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf734fe68);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8d0197);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdfe84);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd50148);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d5ff03);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x103100a0);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2bffc9);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 12700000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00170027);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ffab);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00880098);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff04ff10);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a60159);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd75fe34);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00240);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaeffd58);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a702f9);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79dfcda);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a310326);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fd0d);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9f028e);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f6fe06);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x10210140);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2fff93);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 12800000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffef);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x000c0034);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff8f);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x005800ce);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4ffeb6);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x013c01e1);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfbfd76);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110337);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9dfc2a);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f40453);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848fb63);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x099904a5);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fb9f);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d4603ce);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12dfd0c);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x100701df);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef36ff5c);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 12900000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0001ffee);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffff0038);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff82);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x001d00ec);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xffadfe7c);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b70242);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9fce5);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x024103ff);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc85fb2a);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x05040587);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf930fa0a);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x08ca060e);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfa40);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccb0507);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf179fc15);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3027d);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3fff25);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 13000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff0);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfff20034);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x001bff85);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffdf00f0);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0014fe68);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x00200272);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xff71fc8b);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d048d);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9afa61);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e00688);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4ef8da);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c80759);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f8f4);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2f0637);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1dbfb22);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4031b);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4bfeef);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 13100000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff5);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe70028);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ff98);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffa400d8);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0079fe7c);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87026f);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0043fc6e);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404da);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfecef9da);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294074e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb99f7db);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x06980881);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef7be);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b730759);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf251fa33);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7b03b8);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5afeb8);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 13200000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffc);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe00017);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x004cffb9);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff7500a8);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1feb6);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef90238);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111fc91);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604df);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0012f99b);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x012d07d2);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd07f714);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542097e);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff6a4);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9a086e);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2dbf94b);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f380453);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6cfe82);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 13300000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00080003);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffde0001);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0056ffe3);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff570064);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0113ff10);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe8201d2);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x01cafcf0);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35049e);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155f9a6);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xffba080e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8cf689);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x03ce0a4e);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f5a8);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a50971);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf379f869);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eeb04ec);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef80fe4b);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 13400000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000a);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe2ffec);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00540012);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e0015);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137ff82);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2e0145);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260fd86);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51041a);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0287f9fb);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4a0802);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x001df63f);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x02430aeb);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf4ce);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x08970a62);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf428f78f);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e950584);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xef97fe15);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 13500000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000f);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffeaffda);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0046003d);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff5affc4);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04009d);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c8fe48);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99035a);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397fa96);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcec07ad);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x01adf637);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x00ac0b53);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef419);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x07730b3e);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e9f6bd);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35061a);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb1fddf);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 13600000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00000012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfff6ffcd);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x002f0061);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff7bff79);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x011e007e);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe08ffe8);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f9ff28);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17026a);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0479fb70);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbad0713);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x032ff672);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xff100b83);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff38b);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x063c0c04);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5baf5f5);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dcc06ae);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcdfda8);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 13700000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0004ffc8);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00100078);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffacff3e);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e200f0);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe39ff35);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f10017);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd30156);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0521fc7f);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9c0638);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x0499f6ee);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7a0b7c);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f325);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f40cb3);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69af537);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5a073f);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xefecfd72);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 13800000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0011ffcb);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0007f);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffe7ff19);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x008f014a);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94fe93);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b00105);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3002f);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x0585fdb7);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c10525);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x05def7a8);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf20b3c);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f2e9);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a00d48);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf787f484);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdf07cd);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00dfd3c);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 13900000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80008);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001bffd7);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10076);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0026ff0e);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x002c0184);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0ffe10);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x023b01e0);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff06);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a2ff09);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf92703e4);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f4f89b);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa820ac5);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f2d9);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x02430dc3);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf881f3dc);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5c0859);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf031fd06);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 14000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80001);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0021ffe8);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffba005d);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0060ff1f);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc40198);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0fdb5);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x019a029a);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fdea);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x05750067);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4027f);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d4f9c0);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf9320a1a);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f2f3);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0x00df0e22);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xf986f341);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd108e2);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058fcd1);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 14100000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0021fffd);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0038);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x008eff4a);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff630184);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x003afd8b);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x00da0326);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fced);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x050101c0);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cb0103);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x0876fb10);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80a093e);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f338);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7a0e66);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa94f2b2);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3f0967);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf081fc9b);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 14200000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff3);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001d0013);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa000b);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00aaff89);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13014a);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x00cefd95);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x000a037b);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fc1d);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x044c0305);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90cff7e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5fc81);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7100834);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff3a7);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe160e8d);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaaf231);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa509e9);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0adfc65);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 14300000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffef);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00140025);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffdd);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2ffd6);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedb00f0);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150fdd3);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xff380391);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb85);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x035e0426);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xf994fdfe);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x08eefe0b);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6490702);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f43e);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb60e97);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc6f1be);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a040a67);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0dbfc30);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 14400000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0002ffee);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00070033);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ffb4);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00a40027);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3007e);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b4fe3f);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe760369);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb2e);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x02450518);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5ffc90);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1ffa1);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bc05ae);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902f4fc);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb600e85);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde7f15a);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x095d0ae2);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10cfbfb);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 14500000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0005ffef);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfffa0038);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff95);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00820074);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f0fed0);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd20304);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb1d);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x010e05ce);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb64fb41);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x084e013b);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569043e);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00f5dd);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa150e55);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0bf104);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b00b59);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13ffbc6);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 14600000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fff4);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffed0035);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff83);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x005000b4);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6ff82);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ffff7a);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd580269);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fb53);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xffca0640);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc99fa1e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x079a02cb);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55502ba);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5f6e0);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d90e0a);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0031f0bd);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fd0bcb);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174fb91);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 14700000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0009fffb);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4002a);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ff82);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x001400e0);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3cff10);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e10030);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1201a4);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fbcd);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88066a);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf1f92f);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aa0449);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57e0128);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7ef801);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b00da2);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0156f086);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x07450c39);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1acfb5c);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 14800000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00080002);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0019);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x003fff92);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffd600f1);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96feb6);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x019700e1);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0500c2);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fc84);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd590649);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5df87f);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x058505aa);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4ff91);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9f93c);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69d0d20);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0279f05e);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x06880ca3);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e6fb28);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 14900000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x00060009);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0004);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0051ffb0);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff9d00e8);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffcfe7c);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x01280180);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32ffd2);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fd6e);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4d05df);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d1f812);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x043506e4);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf685fdfb);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fa8d);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a10c83);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0399f046);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c70d08);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222faf3);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 15000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffe5ffef);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x0057ffd9);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff7000c4);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0062fe68);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x009e01ff);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95fee6);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0435fe7d);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb710530);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x023cf7ee);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c307ef);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75efc70);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5cfbef);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c10bce);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b3f03f);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x05030d69);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf261fabf);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 15100000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xffefffdc);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00510006);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff540089);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00befe7c);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0x00060253);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe27fe0d);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413ffa2);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad10446);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0390f812);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0x013b08c3);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868faf6);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fd5f);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fd0b02);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c7f046);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x043b0dc4);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a1fa8b);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 15200000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0012);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0xfffbffce);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x003f0033);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e003f);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106feb6);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6e0276);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeddfd56);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000cc);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa740329);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bff87f);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaa095d);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99ef995);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9fed8);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3590a1f);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d2f05e);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x03700e1b);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e4fa58);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 15300000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9000f);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0009ffc8);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00250059);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff5effee);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0132ff10);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee30265);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaafccf);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x031101eb);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6001e8);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bdf92f);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1b09b6);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafaf852);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0055);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d50929);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d3f086);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a30e6c);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf329fa24);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 15400000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80009);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0015ffca);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0x00050074);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xff81ff9f);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x013dff82);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe710221);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x007cfc80);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x024102ed);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa940090);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0680fa1e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9b09cd);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc73f736);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad501d0);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2740820);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c9f0bd);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d40eb9);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371f9f1);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 15500000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80002);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001effd5);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5007f);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff5b);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2401b0);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0146fc70);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d03c6);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb10ff32);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0701fb41);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb3709a1);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f644);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000345);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2350708);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b2f104);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x01050eff);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3baf9be);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 15600000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0022ffe6);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9007a);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff29);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2007e);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01011b);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f6fc9e);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440467);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbccfdde);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738fc90);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f70934);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99f582);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x090204b0);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21a05e1);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8df15a);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0x00340f41);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf405f98b);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 15700000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcfff4);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x0020fffa);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40064);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x002fff11);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a400f0);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0d006e);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x0281fd09);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604c9);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbffca2);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0726fdfe);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e80888);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134f4f3);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1060c);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf22304af);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b59f1be);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xff640f7d);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf452f959);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 15800000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0000fff0);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0010);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa0041);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0067ff13);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043014a);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46ffb9);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02dbfda8);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3504e5);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddcfb8d);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9ff7e);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf81107a2);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9f49a);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0753);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2500373);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c14f231);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930fb3);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a1f927);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 15900000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0003ffee);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x000f0023);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0016);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x0093ff31);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdc0184);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6ff09);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fdfe70);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5104ba);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0xff15faac);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270103);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7780688);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x044df479);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430883);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a00231);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbef2b2);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc40fe3);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2f8f5);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+
+       case 16000000:
+               cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001);
+               cx25840_write4(client, DIF_BPF_COEFF23, 0x0006ffef);
+               cx25840_write4(client, DIF_BPF_COEFF45, 0x00020031);
+               cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffe8);
+               cx25840_write4(client, DIF_BPF_COEFF89, 0x00adff66);
+               cx25840_write4(client, DIF_BPF_COEFF1011, 0xff790198);
+               cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe6e);
+               cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e5ff55);
+               cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99044a);
+               cx25840_write4(client, DIF_BPF_COEFF1819, 0x005bfa09);
+               cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545027f);
+               cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7230541);
+               cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b8f490);
+               cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20997);
+               cx25840_write4(client, DIF_BPF_COEFF2829, 0xf31300eb);
+               cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d55f341);
+               cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6100e);
+               cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544f8c3);
+               cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000);
+               break;
+       }
+}
+
+static void cx23885_std_setup(struct i2c_client *client)
+{
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+       v4l2_std_id std = state->std;
+       u32 ifHz;
+
+       cx25840_write4(client, 0x478, 0x6628021F);
+       cx25840_write4(client, 0x400, 0x0);
+       cx25840_write4(client, 0x4b4, 0x20524030);
+       cx25840_write4(client, 0x47c, 0x010a8263);
+
+       if (std & V4L2_STD_NTSC) {
+               v4l_dbg(1, cx25840_debug, client, "%s() Selecting NTSC",
+                       __func__);
+
+               /* Horiz / vert timing */
+               cx25840_write4(client, 0x428, 0x1e1e601a);
+               cx25840_write4(client, 0x424, 0x5b2d007a);
+
+               /* DIF NTSC */
+               cx25840_write4(client, 0x304, 0x6503bc0c);
+               cx25840_write4(client, 0x308, 0xbd038c85);
+               cx25840_write4(client, 0x30c, 0x1db4640a);
+               cx25840_write4(client, 0x310, 0x00008800);
+               cx25840_write4(client, 0x314, 0x44400400);
+               cx25840_write4(client, 0x32c, 0x0c800800);
+               cx25840_write4(client, 0x330, 0x27000100);
+               cx25840_write4(client, 0x334, 0x1f296e1f);
+               cx25840_write4(client, 0x338, 0x009f50c1);
+               cx25840_write4(client, 0x340, 0x1befbf06);
+               cx25840_write4(client, 0x344, 0x000035e8);
+
+               /* DIF I/F */
+               ifHz = 5400000;
+
+       } else {
+               v4l_dbg(1, cx25840_debug, client, "%s() Selecting PAL-BG",
+                       __func__);
+
+               /* Horiz / vert timing */
+               cx25840_write4(client, 0x428, 0x28244024);
+               cx25840_write4(client, 0x424, 0x5d2d0084);
+
+               /* DIF */
+               cx25840_write4(client, 0x304, 0x6503bc0c);
+               cx25840_write4(client, 0x308, 0xbd038c85);
+               cx25840_write4(client, 0x30c, 0x1db4640a);
+               cx25840_write4(client, 0x310, 0x00008800);
+               cx25840_write4(client, 0x314, 0x44400600);
+               cx25840_write4(client, 0x32c, 0x0c800800);
+               cx25840_write4(client, 0x330, 0x27000100);
+               cx25840_write4(client, 0x334, 0x213530ec);
+               cx25840_write4(client, 0x338, 0x00a65ba8);
+               cx25840_write4(client, 0x340, 0x1befbf06);
+               cx25840_write4(client, 0x344, 0x000035e8);
+
+               /* DIF I/F */
+               ifHz = 6000000;
+       }
+
+       cx23885_dif_setup(client, ifHz);
+
+       /* Explicitly ensure the inputs are reconfigured after
+        * a standard change.
+        */
+       set_input(client, state->vid_input, state->aud_input);
+}
+
+/* ----------------------------------------------------------------------- */
+
 static const struct v4l2_ctrl_ops cx25840_ctrl_ops = {
        .s_ctrl = cx25840_s_ctrl,
 };
@@ -1801,6 +5024,7 @@ static const struct v4l2_subdev_core_ops cx25840_core_ops = {
        .queryctrl = v4l2_subdev_queryctrl,
        .querymenu = v4l2_subdev_querymenu,
        .s_std = cx25840_s_std,
+       .g_std = cx25840_g_std,
        .reset = cx25840_reset,
        .load_fw = cx25840_load_fw,
        .s_io_pin_config = common_s_io_pin_config,
@@ -1828,6 +5052,7 @@ static const struct v4l2_subdev_video_ops cx25840_video_ops = {
        .s_routing = cx25840_s_video_routing,
        .s_mbus_fmt = cx25840_s_mbus_fmt,
        .s_stream = cx25840_s_stream,
+       .g_input_status = cx25840_g_input_status,
 };
 
 static const struct v4l2_subdev_vbi_ops cx25840_vbi_ops = {
index 5c42abdf422f35fe47a77c711f47adea3e8c26fa..3598dc087b0880fd5214f8f96b36b377678b1a00 100644 (file)
@@ -70,11 +70,6 @@ config VIDEO_CX88_DVB
          To compile this driver as a module, choose M here: the
          module will be called cx88-dvb.
 
-config VIDEO_CX88_MPEG
-       tristate
-       depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD
-       default y
-
 config VIDEO_CX88_VP3054
        tristate "VP-3054 Secondary I2C Bus Support"
        default m
@@ -84,3 +79,8 @@ config VIDEO_CX88_VP3054
          Conexant 2388x chip and the MT352 demodulator,
          which also require support for the VP-3054
          Secondary I2C bus, such at DNTV Live! DVB-T Pro.
+
+config VIDEO_CX88_MPEG
+       tristate
+       depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD
+       default y
index 68d1240f493c98f9327858dd9170d75ee232c802..04bf6627d3629c824e174e4679de2525ff16ee38 100644 (file)
@@ -96,7 +96,7 @@ typedef struct cx88_audio_dev snd_cx88_card_t;
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static const char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;        /* ID for this card */
-static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
+static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
 
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
index 0d719faafd8aeb32e0a260d080622355d8fafa68..cbd5d119a2c660ebd7f8e9aba9b4206795d290e9 100644 (file)
@@ -1306,7 +1306,7 @@ static const struct cx88_board cx88_boards[] = {
        },
        [CX88_BOARD_WINFAST_DTV2000H_J] = {
                .name           = "WinFast DTV2000 H rev. J",
-               .tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+               .tuner_type     = TUNER_PHILIPS_FMD1216MEX_MK3,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
@@ -1573,8 +1573,8 @@ static const struct cx88_board cx88_boards[] = {
                .name           = "Pinnacle Hybrid PCTV",
                .tuner_type     = TUNER_XC2028,
                .tuner_addr     = 0x61,
-               .radio_type     = TUNER_XC2028,
-               .radio_addr     = 0x61,
+               .radio_type     = UNSET,
+               .radio_addr     = ADDR_UNSET,
                .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
@@ -1611,8 +1611,8 @@ static const struct cx88_board cx88_boards[] = {
                .name           = "Leadtek TV2000 XP Global",
                .tuner_type     = TUNER_XC2028,
                .tuner_addr     = 0x61,
-               .radio_type     = TUNER_XC2028,
-               .radio_addr     = 0x61,
+               .radio_type     = UNSET,
+               .radio_addr     = ADDR_UNSET,
                .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
@@ -1643,6 +1643,78 @@ static const struct cx88_board cx88_boards[] = {
                        .gpio3  = 0x0000,
                },
        },
+       [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36] = {
+               .name           = "Leadtek TV2000 XP Global (SC4100)",
+               .tuner_type     = TUNER_XC4000,
+               .tuner_addr     = 0x61,
+               .radio_type     = UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = { {
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x0000,
+                       .gpio2  = 0x0C04,       /* pin 18 = 1, pin 19 = 0 */
+                       .gpio3  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x0000,
+                       .gpio2  = 0x0C0C,       /* pin 18 = 1, pin 19 = 1 */
+                       .gpio3  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x0000,
+                       .gpio2  = 0x0C0C,       /* pin 18 = 1, pin 19 = 1 */
+                       .gpio3  = 0x0000,
+               } },
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0x0400,        /* pin 2 = 0 */
+                       .gpio1  = 0x0000,
+                       .gpio2  = 0x0C00,       /* pin 18 = 0, pin 19 = 0 */
+                       .gpio3  = 0x0000,
+               },
+       },
+       [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43] = {
+               .name           = "Leadtek TV2000 XP Global (XC4100)",
+               .tuner_type     = TUNER_XC4000,
+               .tuner_addr     = 0x61,
+               .radio_type     = UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = { {
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6040,       /* pin 14 = 1, pin 13 = 0 */
+                       .gpio2  = 0x0000,
+                       .gpio3  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6060,       /* pin 14 = 1, pin 13 = 1 */
+                       .gpio2  = 0x0000,
+                       .gpio3  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6060,       /* pin 14 = 1, pin 13 = 1 */
+                       .gpio2  = 0x0000,
+                       .gpio3  = 0x0000,
+               } },
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0x0400,        /* pin 2 = 0 */
+                       .gpio1  = 0x6000,        /* pin 14 = 1, pin 13 = 0 */
+                       .gpio2  = 0x0000,
+                       .gpio3  = 0x0000,
+               },
+       },
        [CX88_BOARD_POWERCOLOR_REAL_ANGEL] = {
                .name           = "PowerColor RA330",   /* Long names may confuse LIRC. */
                .tuner_type     = TUNER_XC2028,
@@ -2043,8 +2115,8 @@ static const struct cx88_board cx88_boards[] = {
                .name           = "Terratec Cinergy HT PCI MKII",
                .tuner_type     = TUNER_XC2028,
                .tuner_addr     = 0x61,
-               .radio_type     = TUNER_XC2028,
-               .radio_addr     = 0x61,
+               .radio_type     = UNSET,
+               .radio_addr     = ADDR_UNSET,
                .input          = { {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
@@ -2082,9 +2154,9 @@ static const struct cx88_board cx88_boards[] = {
        [CX88_BOARD_WINFAST_DTV1800H] = {
                .name           = "Leadtek WinFast DTV1800 Hybrid",
                .tuner_type     = TUNER_XC2028,
-               .radio_type     = TUNER_XC2028,
+               .radio_type     = UNSET,
                .tuner_addr     = 0x61,
-               .radio_addr     = 0x61,
+               .radio_addr     = ADDR_UNSET,
                /*
                 * GPIO setting
                 *
@@ -2123,9 +2195,9 @@ static const struct cx88_board cx88_boards[] = {
        [CX88_BOARD_WINFAST_DTV1800H_XC4000] = {
                .name           = "Leadtek WinFast DTV1800 H (XC4000)",
                .tuner_type     = TUNER_XC4000,
-               .radio_type     = TUNER_XC4000,
+               .radio_type     = UNSET,
                .tuner_addr     = 0x61,
-               .radio_addr     = 0x61,
+               .radio_addr     = ADDR_UNSET,
                /*
                 * GPIO setting
                 *
@@ -2164,9 +2236,9 @@ static const struct cx88_board cx88_boards[] = {
        [CX88_BOARD_WINFAST_DTV2000H_PLUS] = {
                .name           = "Leadtek WinFast DTV2000 H PLUS",
                .tuner_type     = TUNER_XC4000,
-               .radio_type     = TUNER_XC4000,
+               .radio_type     = UNSET,
                .tuner_addr     = 0x61,
-               .radio_addr     = 0x61,
+               .radio_addr     = ADDR_UNSET,
                /*
                 * GPIO
                 *   2: 1: mute audio
@@ -2718,6 +2790,21 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x107d,
                .subdevice = 0x6618,
                .card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL,
+       }, {
+               /* TV2000 XP Global [107d:6618] */
+               .subvendor = 0x107d,
+               .subdevice = 0x6619,
+               .card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL,
+       }, {
+               /* WinFast TV2000 XP Global with XC4000 tuner */
+               .subvendor = 0x107d,
+               .subdevice = 0x6f36,
+               .card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36,
+       }, {
+               /* WinFast TV2000 XP Global with XC4000 tuner and different GPIOs */
+               .subvendor = 0x107d,
+               .subdevice = 0x6f43,
+               .card      = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43,
        }, {
                .subvendor = 0xb034,
                .subdevice = 0x3034,
@@ -3075,6 +3162,8 @@ static int cx88_xc4000_tuner_callback(struct cx88_core *core,
        switch (core->boardnr) {
        case CX88_BOARD_WINFAST_DTV1800H_XC4000:
        case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
                return cx88_xc4000_winfast2000h_plus_callback(core,
                                                              command, arg);
        }
@@ -3232,6 +3321,7 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
                cx_set(MO_GP0_IO, 0x00001010);
                break;
 
+       case CX88_BOARD_WINFAST_DTV2000H_J:
        case CX88_BOARD_HAUPPAUGE_HVR3000:
        case CX88_BOARD_HAUPPAUGE_HVR4000:
                /* Init GPIO */
@@ -3250,6 +3340,8 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
 
        case CX88_BOARD_WINFAST_DTV1800H_XC4000:
        case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
                cx88_xc4000_winfast2000h_plus_callback(core,
                                                       XC4000_TUNER_RESET, 0);
                break;
index cf3d33ab541b8ee190dcd7fbdaefc6130895a002..003937cd72f553e80bceecdcb9a0befe8986630a 100644 (file)
@@ -815,9 +815,9 @@ static const u8 samsung_smt_7020_inittab[] = {
 };
 
 
-static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params)
+static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct cx8802_dev *dev = fe->dvb->priv;
        u8 buf[4];
        u32 div;
@@ -827,14 +827,14 @@ static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe,
                .buf = buf,
                .len = sizeof(buf) };
 
-       div = params->frequency / 125;
+       div = c->frequency / 125;
 
        buf[0] = (div >> 8) & 0x7f;
        buf[1] = div & 0xff;
        buf[2] = 0x84;  /* 0xC4 */
        buf[3] = 0x00;
 
-       if (params->frequency < 1500000)
+       if (c->frequency < 1500000)
                buf[3] |= 0x10;
 
        if (fe->ops.i2c_gate_ctrl)
@@ -954,6 +954,7 @@ static int dvb_register(struct cx8802_dev *dev)
        struct cx88_core *core = dev->core;
        struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
        int mfe_shared = 0; /* bus not shared by default */
+       int res = -EINVAL;
 
        if (0 != core->i2c_rc) {
                printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name);
@@ -999,7 +1000,6 @@ static int dvb_register(struct cx8802_dev *dev)
                }
                break;
        case CX88_BOARD_WINFAST_DTV2000H:
-       case CX88_BOARD_WINFAST_DTV2000H_J:
        case CX88_BOARD_HAUPPAUGE_HVR1100:
        case CX88_BOARD_HAUPPAUGE_HVR1100LP:
        case CX88_BOARD_HAUPPAUGE_HVR1300:
@@ -1013,6 +1013,17 @@ static int dvb_register(struct cx8802_dev *dev)
                                goto frontend_detach;
                }
                break;
+       case CX88_BOARD_WINFAST_DTV2000H_J:
+               fe0->dvb.frontend = dvb_attach(cx22702_attach,
+                                              &hauppauge_hvr_config,
+                                              &core->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+                                  &core->i2c_adap, 0x61,
+                                  TUNER_PHILIPS_FMD1216MEX_MK3))
+                               goto frontend_detach;
+               }
+               break;
        case CX88_BOARD_HAUPPAUGE_HVR3000:
                /* MFE frontend 1 */
                mfe_shared = 1;
@@ -1566,13 +1577,16 @@ static int dvb_register(struct cx8802_dev *dev)
        call_all(core, core, s_power, 0);
 
        /* register everything */
-       return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
-                                        &dev->pci->dev, adapter_nr, mfe_shared, NULL);
+       res = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+               &dev->pci->dev, adapter_nr, mfe_shared, NULL);
+       if (res)
+               goto frontend_detach;
+       return res;
 
 frontend_detach:
        core->gate_ctrl = NULL;
        videobuf_dvb_dealloc_frontends(&dev->frontends);
-       return -EINVAL;
+       return res;
 }
 
 /* ----------------------------------------------------------- */
index a1fe0abb6e43051c49d36b964e5a3069809219c7..de0f1af74e415bc516cd9b12fd97b4b34a8cc45e 100644 (file)
@@ -132,7 +132,7 @@ static void do_i2c_scan(const char *name, struct i2c_client *c)
        }
 }
 
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
 int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
 {
        /* Prevents usage of invalid delay values */
index e614201b5ed33b5994ec4528ece3574e7f90919d..ebf448c48ca3335ce6cdb0a0091270fcdb96bd57 100644 (file)
@@ -103,6 +103,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
        case CX88_BOARD_WINFAST_DTV1800H_XC4000:
        case CX88_BOARD_WINFAST_DTV2000H_PLUS:
        case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
                gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
                auxgpio = gpio;
                break;
@@ -302,6 +304,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_WINFAST2000XP_EXPERT:
        case CX88_BOARD_WINFAST_DTV1000:
        case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
                ir_codes = RC_MAP_WINFAST;
                ir->gpio_addr = MO_GP0_IO;
                ir->mask_keycode = 0x8f8;
index fa8d307e1a3d2299618bdf5266aea118b68f7670..c9659def2a787d79ecfa97c5cc56ff62b4521e47 100644 (file)
@@ -244,6 +244,8 @@ extern const struct sram_channel const cx88_sram_channels[];
 #define CX88_BOARD_TEVII_S464              86
 #define CX88_BOARD_WINFAST_DTV2000H_PLUS   87
 #define CX88_BOARD_WINFAST_DTV1800H_XC4000 88
+#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36 89
+#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43 90
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
index bd443ee76fff2a342b5c7633969affdbadfa480e..f83baf3a52b0b7ae40f0e05091b2cb90147e2d4a 100644 (file)
@@ -1069,15 +1069,4 @@ static struct platform_driver dm355_ccdc_driver = {
        .probe = dm355_ccdc_probe,
 };
 
-static int __init dm355_ccdc_init(void)
-{
-       return platform_driver_register(&dm355_ccdc_driver);
-}
-
-static void __exit dm355_ccdc_exit(void)
-{
-       platform_driver_unregister(&dm355_ccdc_driver);
-}
-
-module_init(dm355_ccdc_init);
-module_exit(dm355_ccdc_exit);
+module_platform_driver(dm355_ccdc_driver);
index 8051c2956478d9ff826839874b34338ca675dcc8..9303fe553b075899e09e529173373de77af5a871 100644 (file)
@@ -1078,15 +1078,4 @@ static struct platform_driver dm644x_ccdc_driver = {
        .probe = dm644x_ccdc_probe,
 };
 
-static int __init dm644x_ccdc_init(void)
-{
-       return platform_driver_register(&dm644x_ccdc_driver);
-}
-
-static void __exit dm644x_ccdc_exit(void)
-{
-       platform_driver_unregister(&dm644x_ccdc_driver);
-}
-
-module_init(dm644x_ccdc_init);
-module_exit(dm644x_ccdc_exit);
+module_platform_driver(dm644x_ccdc_driver);
index 29c29c668596276c8c4ebeb366cd482439209d3c..1e63852374bed0641e443c9c0237dc7868c90598 100644 (file)
@@ -1156,17 +1156,6 @@ static struct platform_driver isif_driver = {
        .probe = isif_probe,
 };
 
-static int __init isif_init(void)
-{
-       return platform_driver_register(&isif_driver);
-}
-
-static void isif_exit(void)
-{
-       platform_driver_unregister(&isif_driver);
-}
-
-module_init(isif_init);
-module_exit(isif_exit);
+module_platform_driver(isif_driver);
 
 MODULE_LICENSE("GPL");
index d773d30de221f0bc7d5fd04e6ea660ff9b2f3940..c4a82a1a8a977f42431e47e5fba269173c48c272 100644 (file)
@@ -141,11 +141,12 @@ static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev,
        return 0;
 }
 
-static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode)
+static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode,
+                             int output_index)
 {
        struct vpbe_config *cfg = vpbe_dev->cfg;
        struct vpbe_enc_mode_info var;
-       int curr_output = vpbe_dev->current_out_index;
+       int curr_output = output_index;
        int i;
 
        if (NULL == mode)
@@ -245,6 +246,8 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index)
        struct encoder_config_info *curr_enc_info =
                        vpbe_current_encoder_info(vpbe_dev);
        struct vpbe_config *cfg = vpbe_dev->cfg;
+       struct venc_platform_data *venc_device = vpbe_dev->venc_device;
+       enum v4l2_mbus_pixelcode if_params;
        int enc_out_index;
        int sd_index;
        int ret = 0;
@@ -274,6 +277,8 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index)
                        goto out;
                }
 
+               if_params = cfg->outputs[index].if_params;
+               venc_device->setup_if_config(if_params);
                if (ret)
                        goto out;
        }
@@ -293,7 +298,7 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index)
         * encoder.
         */
        ret = vpbe_get_mode_info(vpbe_dev,
-                                cfg->outputs[index].default_mode);
+                                cfg->outputs[index].default_mode, index);
        if (!ret) {
                struct osd_state *osd_device = vpbe_dev->osd_device;
 
@@ -367,6 +372,11 @@ static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev,
 
        ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
                                        s_dv_preset, dv_preset);
+       if (!ret && (vpbe_dev->amp != NULL)) {
+               /* Call amplifier subdevice */
+               ret = v4l2_subdev_call(vpbe_dev->amp, video,
+                               s_dv_preset, dv_preset);
+       }
        /* set the lcd controller output for the given mode */
        if (!ret) {
                struct osd_state *osd_device = vpbe_dev->osd_device;
@@ -566,6 +576,8 @@ static int platform_device_get(struct device *dev, void *data)
 
        if (strcmp("vpbe-osd", pdev->name) == 0)
                vpbe_dev->osd_device = platform_get_drvdata(pdev);
+       if (strcmp("vpbe-venc", pdev->name) == 0)
+               vpbe_dev->venc_device = dev_get_platdata(&pdev->dev);
 
        return 0;
 }
@@ -584,6 +596,7 @@ static int platform_device_get(struct device *dev, void *data)
 static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
 {
        struct encoder_config_info *enc_info;
+       struct amp_config_info *amp_info;
        struct v4l2_subdev **enc_subdev;
        struct osd_state *osd_device;
        struct i2c_adapter *i2c_adap;
@@ -704,6 +717,32 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
                        v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders"
                                 " currently not supported");
        }
+       /* Add amplifier subdevice for dm365 */
+       if ((strcmp(vpbe_dev->cfg->module_name, "dm365-vpbe-display") == 0) &&
+                       vpbe_dev->cfg->amp != NULL) {
+               amp_info = vpbe_dev->cfg->amp;
+               if (amp_info->is_i2c) {
+                       vpbe_dev->amp = v4l2_i2c_new_subdev_board(
+                       &vpbe_dev->v4l2_dev, i2c_adap,
+                       &amp_info->board_info, NULL);
+                       if (!vpbe_dev->amp) {
+                               v4l2_err(&vpbe_dev->v4l2_dev,
+                                        "amplifier %s failed to register",
+                                        amp_info->module_name);
+                               ret = -ENODEV;
+                               goto vpbe_fail_amp_register;
+                       }
+                       v4l2_info(&vpbe_dev->v4l2_dev,
+                                         "v4l2 sub device %s registered\n",
+                                         amp_info->module_name);
+               } else {
+                           vpbe_dev->amp = NULL;
+                           v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c amplifiers"
+                           " currently not supported");
+               }
+       } else {
+           vpbe_dev->amp = NULL;
+       }
 
        /* set the current encoder and output to that of venc by default */
        vpbe_dev->current_sd_index = 0;
@@ -731,6 +770,8 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
        /* TBD handling of bootargs for default output and mode */
        return 0;
 
+vpbe_fail_amp_register:
+       kfree(vpbe_dev->amp);
 vpbe_fail_sd_register:
        kfree(vpbe_dev->encoders);
 vpbe_fail_v4l2_device:
@@ -757,6 +798,7 @@ static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev)
        if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0)
                clk_put(vpbe_dev->dac_clk);
 
+       kfree(vpbe_dev->amp);
        kfree(vpbe_dev->encoders);
        vpbe_dev->initialized = 0;
        /* disable vpss clocks */
@@ -811,8 +853,10 @@ static __devinit int vpbe_probe(struct platform_device *pdev)
 
        if (cfg->outputs->num_modes > 0)
                vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0];
-       else
+       else {
+               kfree(vpbe_dev);
                return -ENODEV;
+       }
 
        /* set the driver data in platform device */
        platform_set_drvdata(pdev, vpbe_dev);
@@ -839,26 +883,4 @@ static struct platform_driver vpbe_driver = {
        .remove = vpbe_remove,
 };
 
-/**
- * vpbe_init: initialize the vpbe driver
- *
- * This function registers device and driver to the kernel
- */
-static __init int vpbe_init(void)
-{
-       return platform_driver_register(&vpbe_driver);
-}
-
-/**
- * vpbe_cleanup : cleanup function for vpbe driver
- *
- * This will un-registers the device and driver to the kernel
- */
-static void vpbe_cleanup(void)
-{
-       platform_driver_unregister(&vpbe_driver);
-}
-
-/* Function for module initialization and cleanup */
-module_init(vpbe_init);
-module_exit(vpbe_cleanup);
+module_platform_driver(vpbe_driver);
index 8588a86d9b45ecb31335924b5259499fd310d69c..1f3b1c72925297efd8cb549dc206b18b77eab497 100644 (file)
@@ -1746,15 +1746,16 @@ static __devinit int vpbe_display_probe(struct platform_device *pdev)
        for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
                if (register_device(disp_dev->dev[i], disp_dev, pdev)) {
                        err = -ENODEV;
-                       goto probe_out;
+                       goto probe_out_irq;
                }
        }
 
        printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n");
        return 0;
 
-probe_out:
+probe_out_irq:
        free_irq(res->start, disp_dev);
+probe_out:
        for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) {
                /* Get the pointer to the layer object */
                vpbe_display_layer = disp_dev->dev[k];
@@ -1816,43 +1817,7 @@ static struct platform_driver vpbe_display_driver = {
        .remove = __devexit_p(vpbe_display_remove),
 };
 
-/*
- * vpbe_display_init()
- * This function registers device and driver to the kernel, requests irq
- * handler and allocates memory for layer objects
- */
-static __devinit int vpbe_display_init(void)
-{
-       int err;
-
-       printk(KERN_DEBUG "vpbe_display_init\n");
-
-       /* Register driver to the kernel */
-       err = platform_driver_register(&vpbe_display_driver);
-       if (0 != err)
-               return err;
-
-       printk(KERN_DEBUG "vpbe_display_init:"
-                       "VPBE V4L2 Display Driver V1.0 loaded\n");
-       return 0;
-}
-
-/*
- * vpbe_display_cleanup()
- * This function un-registers device and driver to the kernel, frees requested
- * irq handler and de-allocates memory allocated for layer objects.
- */
-static void vpbe_display_cleanup(void)
-{
-       printk(KERN_DEBUG "vpbe_display_cleanup\n");
-
-       /* platform driver unregister */
-       platform_driver_unregister(&vpbe_display_driver);
-}
-
-/* Function for module initialization and cleanup */
-module_init(vpbe_display_init);
-module_exit(vpbe_display_cleanup);
+module_platform_driver(vpbe_display_driver);
 
 MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller");
 MODULE_LICENSE("GPL");
index ceccf43025189743960ac711bae3cf8c01b4cda6..d6488b79ae3b54602e09170372b03bbbe8f3929a 100644 (file)
@@ -248,11 +248,29 @@ static void _osd_set_rec601_attenuation(struct osd_state *sd,
                osd_modify(sd, OSD_OSDWIN0MD_ATN0E,
                          enable ? OSD_OSDWIN0MD_ATN0E : 0,
                          OSD_OSDWIN0MD);
+               if (sd->vpbe_type == VPBE_VERSION_1)
+                       osd_modify(sd, OSD_OSDWIN0MD_ATN0E,
+                                 enable ? OSD_OSDWIN0MD_ATN0E : 0,
+                                 OSD_OSDWIN0MD);
+               else if ((sd->vpbe_type == VPBE_VERSION_3) ||
+                          (sd->vpbe_type == VPBE_VERSION_2))
+                       osd_modify(sd, OSD_EXTMODE_ATNOSD0EN,
+                                 enable ? OSD_EXTMODE_ATNOSD0EN : 0,
+                                 OSD_EXTMODE);
                break;
        case OSDWIN_OSD1:
                osd_modify(sd, OSD_OSDWIN1MD_ATN1E,
                          enable ? OSD_OSDWIN1MD_ATN1E : 0,
                          OSD_OSDWIN1MD);
+               if (sd->vpbe_type == VPBE_VERSION_1)
+                       osd_modify(sd, OSD_OSDWIN1MD_ATN1E,
+                                 enable ? OSD_OSDWIN1MD_ATN1E : 0,
+                                 OSD_OSDWIN1MD);
+               else if ((sd->vpbe_type == VPBE_VERSION_3) ||
+                          (sd->vpbe_type == VPBE_VERSION_2))
+                       osd_modify(sd, OSD_EXTMODE_ATNOSD1EN,
+                                 enable ? OSD_EXTMODE_ATNOSD1EN : 0,
+                                 OSD_EXTMODE);
                break;
        }
 }
@@ -273,15 +291,71 @@ static void _osd_set_blending_factor(struct osd_state *sd,
        }
 }
 
+static void _osd_enable_rgb888_pixblend(struct osd_state *sd,
+                                       enum osd_win_layer osdwin)
+{
+
+       osd_modify(sd, OSD_MISCCTL_BLDSEL, 0, OSD_MISCCTL);
+       switch (osdwin) {
+       case OSDWIN_OSD0:
+               osd_modify(sd, OSD_EXTMODE_OSD0BLDCHR,
+                         OSD_EXTMODE_OSD0BLDCHR, OSD_EXTMODE);
+               break;
+       case OSDWIN_OSD1:
+               osd_modify(sd, OSD_EXTMODE_OSD1BLDCHR,
+                         OSD_EXTMODE_OSD1BLDCHR, OSD_EXTMODE);
+               break;
+       }
+}
+
 static void _osd_enable_color_key(struct osd_state *sd,
                                  enum osd_win_layer osdwin,
                                  unsigned colorkey,
                                  enum osd_pix_format pixfmt)
 {
        switch (pixfmt) {
+       case PIXFMT_1BPP:
+       case PIXFMT_2BPP:
+       case PIXFMT_4BPP:
+       case PIXFMT_8BPP:
+               if (sd->vpbe_type == VPBE_VERSION_3) {
+                       switch (osdwin) {
+                       case OSDWIN_OSD0:
+                               osd_modify(sd, OSD_TRANSPBMPIDX_BMP0,
+                                         colorkey <<
+                                         OSD_TRANSPBMPIDX_BMP0_SHIFT,
+                                         OSD_TRANSPBMPIDX);
+                               break;
+                       case OSDWIN_OSD1:
+                               osd_modify(sd, OSD_TRANSPBMPIDX_BMP1,
+                                         colorkey <<
+                                         OSD_TRANSPBMPIDX_BMP1_SHIFT,
+                                         OSD_TRANSPBMPIDX);
+                               break;
+                       }
+               }
+               break;
        case PIXFMT_RGB565:
-               osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS,
-                         OSD_TRANSPVAL);
+               if (sd->vpbe_type == VPBE_VERSION_1)
+                       osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS,
+                                 OSD_TRANSPVAL);
+               else if (sd->vpbe_type == VPBE_VERSION_3)
+                       osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL,
+                                 OSD_TRANSPVALL);
+               break;
+       case PIXFMT_YCbCrI:
+       case PIXFMT_YCrCbI:
+               if (sd->vpbe_type == VPBE_VERSION_3)
+                       osd_modify(sd, OSD_TRANSPVALU_Y, colorkey,
+                                  OSD_TRANSPVALU);
+               break;
+       case PIXFMT_RGB888:
+               if (sd->vpbe_type == VPBE_VERSION_3) {
+                       osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL,
+                                 OSD_TRANSPVALL);
+                       osd_modify(sd, OSD_TRANSPVALU_RGBU, colorkey >> 16,
+                                 OSD_TRANSPVALU);
+               }
                break;
        default:
                break;
@@ -470,23 +544,188 @@ static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer,
        return 0;
 }
 
+#define OSD_SRC_ADDR_HIGH4     0x7800000
+#define OSD_SRC_ADDR_HIGH7     0x7F0000
+#define OSD_SRCADD_OFSET_SFT   23
+#define OSD_SRCADD_ADD_SFT     16
+#define OSD_WINADL_MASK                0xFFFF
+#define OSD_WINOFST_MASK       0x1000
+#define VPBE_REG_BASE          0x80000000
+
 static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer,
                             unsigned long fb_base_phys,
                             unsigned long cbcr_ofst)
 {
-       switch (layer) {
-       case WIN_OSD0:
-               osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR);
-               break;
-       case WIN_VID0:
-               osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR);
-               break;
-       case WIN_OSD1:
-               osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR);
-               break;
-       case WIN_VID1:
-               osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR);
-               break;
+
+       if (sd->vpbe_type == VPBE_VERSION_1) {
+               switch (layer) {
+               case WIN_OSD0:
+                       osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR);
+                       break;
+               case WIN_VID0:
+                       osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR);
+                       break;
+               case WIN_OSD1:
+                       osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR);
+                       break;
+               case WIN_VID1:
+                       osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR);
+                       break;
+             }
+       } else if (sd->vpbe_type == VPBE_VERSION_3) {
+               unsigned long fb_offset_32 =
+                   (fb_base_phys - VPBE_REG_BASE) >> 5;
+
+               switch (layer) {
+               case WIN_OSD0:
+                       osd_modify(sd, OSD_OSDWINADH_O0AH,
+                                 fb_offset_32 >> (OSD_SRCADD_ADD_SFT -
+                                                  OSD_OSDWINADH_O0AH_SHIFT),
+                                 OSD_OSDWINADH);
+                       osd_write(sd, fb_offset_32 & OSD_OSDWIN0ADL_O0AL,
+                                 OSD_OSDWIN0ADL);
+                       break;
+               case WIN_VID0:
+                       osd_modify(sd, OSD_VIDWINADH_V0AH,
+                                 fb_offset_32 >> (OSD_SRCADD_ADD_SFT -
+                                                  OSD_VIDWINADH_V0AH_SHIFT),
+                                 OSD_VIDWINADH);
+                       osd_write(sd, fb_offset_32 & OSD_VIDWIN0ADL_V0AL,
+                                 OSD_VIDWIN0ADL);
+                       break;
+               case WIN_OSD1:
+                       osd_modify(sd, OSD_OSDWINADH_O1AH,
+                                 fb_offset_32 >> (OSD_SRCADD_ADD_SFT -
+                                                  OSD_OSDWINADH_O1AH_SHIFT),
+                                 OSD_OSDWINADH);
+                       osd_write(sd, fb_offset_32 & OSD_OSDWIN1ADL_O1AL,
+                                 OSD_OSDWIN1ADL);
+                       break;
+               case WIN_VID1:
+                       osd_modify(sd, OSD_VIDWINADH_V1AH,
+                                 fb_offset_32 >> (OSD_SRCADD_ADD_SFT -
+                                                  OSD_VIDWINADH_V1AH_SHIFT),
+                                 OSD_VIDWINADH);
+                       osd_write(sd, fb_offset_32 & OSD_VIDWIN1ADL_V1AL,
+                                 OSD_VIDWIN1ADL);
+                       break;
+               }
+       } else if (sd->vpbe_type == VPBE_VERSION_2) {
+               struct osd_window_state *win = &sd->win[layer];
+               unsigned long fb_offset_32, cbcr_offset_32;
+
+               fb_offset_32 = fb_base_phys - VPBE_REG_BASE;
+               if (cbcr_ofst)
+                       cbcr_offset_32 = cbcr_ofst;
+               else
+                       cbcr_offset_32 = win->lconfig.line_length *
+                                        win->lconfig.ysize;
+               cbcr_offset_32 += fb_offset_32;
+               fb_offset_32 = fb_offset_32 >> 5;
+               cbcr_offset_32 = cbcr_offset_32 >> 5;
+               /*
+                * DM365: start address is 27-bit long address b26 - b23 are
+                * in offset register b12 - b9, and * bit 26 has to be '1'
+                */
+               if (win->lconfig.pixfmt == PIXFMT_NV12) {
+                       switch (layer) {
+                       case WIN_VID0:
+                       case WIN_VID1:
+                               /* Y is in VID0 */
+                               osd_modify(sd, OSD_VIDWIN0OFST_V0AH,
+                                        ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+                                        (OSD_SRCADD_OFSET_SFT -
+                                        OSD_WINOFST_AH_SHIFT)) |
+                                        OSD_WINOFST_MASK, OSD_VIDWIN0OFST);
+                               osd_modify(sd, OSD_VIDWINADH_V0AH,
+                                         (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+                                         (OSD_SRCADD_ADD_SFT -
+                                         OSD_VIDWINADH_V0AH_SHIFT),
+                                          OSD_VIDWINADH);
+                               osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+                                         OSD_VIDWIN0ADL);
+                               /* CbCr is in VID1 */
+                               osd_modify(sd, OSD_VIDWIN1OFST_V1AH,
+                                        ((cbcr_offset_32 &
+                                        OSD_SRC_ADDR_HIGH4) >>
+                                        (OSD_SRCADD_OFSET_SFT -
+                                        OSD_WINOFST_AH_SHIFT)) |
+                                        OSD_WINOFST_MASK, OSD_VIDWIN1OFST);
+                               osd_modify(sd, OSD_VIDWINADH_V1AH,
+                                         (cbcr_offset_32 &
+                                         OSD_SRC_ADDR_HIGH7) >>
+                                         (OSD_SRCADD_ADD_SFT -
+                                         OSD_VIDWINADH_V1AH_SHIFT),
+                                         OSD_VIDWINADH);
+                               osd_write(sd, cbcr_offset_32 & OSD_WINADL_MASK,
+                                         OSD_VIDWIN1ADL);
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+               switch (layer) {
+               case WIN_OSD0:
+                       osd_modify(sd, OSD_OSDWIN0OFST_O0AH,
+                                ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+                                (OSD_SRCADD_OFSET_SFT -
+                                OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK,
+                                 OSD_OSDWIN0OFST);
+                       osd_modify(sd, OSD_OSDWINADH_O0AH,
+                                (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+                                (OSD_SRCADD_ADD_SFT -
+                                OSD_OSDWINADH_O0AH_SHIFT), OSD_OSDWINADH);
+                       osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+                                       OSD_OSDWIN0ADL);
+                       break;
+               case WIN_VID0:
+                       if (win->lconfig.pixfmt != PIXFMT_NV12) {
+                               osd_modify(sd, OSD_VIDWIN0OFST_V0AH,
+                                        ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+                                        (OSD_SRCADD_OFSET_SFT -
+                                        OSD_WINOFST_AH_SHIFT)) |
+                                        OSD_WINOFST_MASK, OSD_VIDWIN0OFST);
+                               osd_modify(sd, OSD_VIDWINADH_V0AH,
+                                         (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+                                         (OSD_SRCADD_ADD_SFT -
+                                         OSD_VIDWINADH_V0AH_SHIFT),
+                                         OSD_VIDWINADH);
+                               osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+                                         OSD_VIDWIN0ADL);
+                       }
+                       break;
+               case WIN_OSD1:
+                       osd_modify(sd, OSD_OSDWIN1OFST_O1AH,
+                                ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+                                (OSD_SRCADD_OFSET_SFT -
+                                OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK,
+                                 OSD_OSDWIN1OFST);
+                       osd_modify(sd, OSD_OSDWINADH_O1AH,
+                                 (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+                                 (OSD_SRCADD_ADD_SFT -
+                                 OSD_OSDWINADH_O1AH_SHIFT),
+                                 OSD_OSDWINADH);
+                       osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+                                       OSD_OSDWIN1ADL);
+                       break;
+               case WIN_VID1:
+                       if (win->lconfig.pixfmt != PIXFMT_NV12) {
+                               osd_modify(sd, OSD_VIDWIN1OFST_V1AH,
+                                        ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >>
+                                        (OSD_SRCADD_OFSET_SFT -
+                                        OSD_WINOFST_AH_SHIFT)) |
+                                        OSD_WINOFST_MASK, OSD_VIDWIN1OFST);
+                               osd_modify(sd, OSD_VIDWINADH_V1AH,
+                                         (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >>
+                                         (OSD_SRCADD_ADD_SFT -
+                                         OSD_VIDWINADH_V1AH_SHIFT),
+                                         OSD_VIDWINADH);
+                               osd_write(sd, fb_offset_32 & OSD_WINADL_MASK,
+                                         OSD_VIDWIN1ADL);
+                       }
+                       break;
+               }
        }
 }
 
@@ -545,7 +784,7 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
 {
        struct osd_state *osd = sd;
        struct osd_window_state *win = &osd->win[layer];
-       int bad_config;
+       int bad_config = 0;
 
        /* verify that the pixel format is compatible with the layer */
        switch (lconfig->pixfmt) {
@@ -554,17 +793,25 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
        case PIXFMT_4BPP:
        case PIXFMT_8BPP:
        case PIXFMT_RGB565:
-               bad_config = !is_osd_win(layer);
+               if (osd->vpbe_type == VPBE_VERSION_1)
+                       bad_config = !is_vid_win(layer);
                break;
        case PIXFMT_YCbCrI:
        case PIXFMT_YCrCbI:
                bad_config = !is_vid_win(layer);
                break;
        case PIXFMT_RGB888:
-               bad_config = !is_vid_win(layer);
+               if (osd->vpbe_type == VPBE_VERSION_1)
+                       bad_config = !is_vid_win(layer);
+               else if ((osd->vpbe_type == VPBE_VERSION_3) ||
+                        (osd->vpbe_type == VPBE_VERSION_2))
+                       bad_config = !is_osd_win(layer);
                break;
        case PIXFMT_NV12:
-               bad_config = 1;
+               if (osd->vpbe_type != VPBE_VERSION_2)
+                       bad_config = 1;
+               else
+                       bad_config = is_osd_win(layer);
                break;
        case PIXFMT_OSD_ATTR:
                bad_config = (layer != WIN_OSD1);
@@ -584,7 +831,8 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
 
        /* DM6446: */
        /* only one OSD window at a time can use RGB pixel formats */
-       if (is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) {
+         if ((osd->vpbe_type == VPBE_VERSION_1) &&
+                 is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) {
                enum osd_pix_format pixfmt;
                if (layer == WIN_OSD0)
                        pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt;
@@ -602,7 +850,8 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
        }
 
        /* DM6446: only one video window at a time can use RGB888 */
-       if (is_vid_win(layer) && lconfig->pixfmt == PIXFMT_RGB888) {
+       if ((osd->vpbe_type == VPBE_VERSION_1) && is_vid_win(layer) &&
+               lconfig->pixfmt == PIXFMT_RGB888) {
                enum osd_pix_format pixfmt;
 
                if (layer == WIN_VID0)
@@ -652,7 +901,8 @@ static void _osd_disable_vid_rgb888(struct osd_state *sd)
         * The caller must ensure that neither video window is currently
         * configured for RGB888 pixel format.
         */
-       osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL);
+       if (sd->vpbe_type == VPBE_VERSION_1)
+               osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL);
 }
 
 static void _osd_enable_vid_rgb888(struct osd_state *sd,
@@ -665,13 +915,14 @@ static void _osd_enable_vid_rgb888(struct osd_state *sd,
         * currently configured for RGB888 pixel format, as this routine will
         * disable RGB888 pixel format for the other window.
         */
-       if (layer == WIN_VID0) {
-               osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
-                         OSD_MISCCTL_RGBEN, OSD_MISCCTL);
-       } else if (layer == WIN_VID1) {
-               osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
-                         OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
-                         OSD_MISCCTL);
+       if (sd->vpbe_type == VPBE_VERSION_1) {
+               if (layer == WIN_VID0)
+                       osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+                                 OSD_MISCCTL_RGBEN, OSD_MISCCTL);
+               else if (layer == WIN_VID1)
+                       osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+                                 OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+                                 OSD_MISCCTL);
        }
 }
 
@@ -697,9 +948,30 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
 
        switch (layer) {
        case WIN_OSD0:
-               winmd_mask |= OSD_OSDWIN0MD_RGB0E;
-               if (lconfig->pixfmt == PIXFMT_RGB565)
-                       winmd |= OSD_OSDWIN0MD_RGB0E;
+               if (sd->vpbe_type == VPBE_VERSION_1) {
+                       winmd_mask |= OSD_OSDWIN0MD_RGB0E;
+                       if (lconfig->pixfmt == PIXFMT_RGB565)
+                               winmd |= OSD_OSDWIN0MD_RGB0E;
+               } else if ((sd->vpbe_type == VPBE_VERSION_3) ||
+                 (sd->vpbe_type == VPBE_VERSION_2)) {
+                       winmd_mask |= OSD_OSDWIN0MD_BMP0MD;
+                       switch (lconfig->pixfmt) {
+                       case PIXFMT_RGB565:
+                                       winmd |= (1 <<
+                                       OSD_OSDWIN0MD_BMP0MD_SHIFT);
+                                       break;
+                       case PIXFMT_RGB888:
+                               winmd |= (2 << OSD_OSDWIN0MD_BMP0MD_SHIFT);
+                               _osd_enable_rgb888_pixblend(sd, OSDWIN_OSD0);
+                               break;
+                       case PIXFMT_YCbCrI:
+                       case PIXFMT_YCrCbI:
+                               winmd |= (3 << OSD_OSDWIN0MD_BMP0MD_SHIFT);
+                               break;
+                       default:
+                               break;
+                       }
+               }
 
                winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0;
 
@@ -749,12 +1021,59 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
                 * For YUV420P format the register contents are
                 * duplicated in both VID registers
                 */
+               if ((sd->vpbe_type == VPBE_VERSION_2) &&
+                               (lconfig->pixfmt == PIXFMT_NV12)) {
+                       /* other window also */
+                       if (lconfig->interlaced) {
+                               winmd_mask |= OSD_VIDWINMD_VFF1;
+                               winmd |= OSD_VIDWINMD_VFF1;
+                               osd_modify(sd, winmd_mask, winmd,
+                                         OSD_VIDWINMD);
+                       }
+
+                       osd_modify(sd, OSD_MISCCTL_S420D,
+                                   OSD_MISCCTL_S420D, OSD_MISCCTL);
+                       osd_write(sd, lconfig->line_length >> 5,
+                                 OSD_VIDWIN1OFST);
+                       osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP);
+                       osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL);
+                       /*
+                         * if NV21 pixfmt and line length not 32B
+                         * aligned (e.g. NTSC), Need to set window
+                         * X pixel size to be 32B aligned as well
+                         */
+                       if (lconfig->xsize % 32) {
+                               osd_write(sd,
+                                         ((lconfig->xsize + 31) & ~31),
+                                         OSD_VIDWIN1XL);
+                               osd_write(sd,
+                                         ((lconfig->xsize + 31) & ~31),
+                                         OSD_VIDWIN0XL);
+                       }
+               } else if ((sd->vpbe_type == VPBE_VERSION_2) &&
+                               (lconfig->pixfmt != PIXFMT_NV12)) {
+                       osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D,
+                                               OSD_MISCCTL);
+               }
+
                if (lconfig->interlaced) {
                        osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP);
                        osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL);
+                       if ((sd->vpbe_type == VPBE_VERSION_2) &&
+                               lconfig->pixfmt == PIXFMT_NV12) {
+                               osd_write(sd, lconfig->ypos >> 1,
+                                         OSD_VIDWIN1YP);
+                               osd_write(sd, lconfig->ysize >> 1,
+                                         OSD_VIDWIN1YL);
+                       }
                } else {
                        osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP);
                        osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL);
+                       if ((sd->vpbe_type == VPBE_VERSION_2) &&
+                               lconfig->pixfmt == PIXFMT_NV12) {
+                               osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP);
+                               osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL);
+                       }
                }
                break;
        case WIN_OSD1:
@@ -764,14 +1083,43 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
                 * attribute mode to a normal mode.
                 */
                if (lconfig->pixfmt == PIXFMT_OSD_ATTR) {
-                       winmd_mask |=
-                           OSD_OSDWIN1MD_ATN1E | OSD_OSDWIN1MD_RGB1E |
-                           OSD_OSDWIN1MD_CLUTS1 |
-                           OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1;
+                       if (sd->vpbe_type == VPBE_VERSION_1) {
+                               winmd_mask |= OSD_OSDWIN1MD_ATN1E |
+                               OSD_OSDWIN1MD_RGB1E | OSD_OSDWIN1MD_CLUTS1 |
+                               OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1;
+                       } else {
+                               winmd_mask |= OSD_OSDWIN1MD_BMP1MD |
+                               OSD_OSDWIN1MD_CLUTS1 | OSD_OSDWIN1MD_BLND1 |
+                               OSD_OSDWIN1MD_TE1;
+                       }
                } else {
-                       winmd_mask |= OSD_OSDWIN1MD_RGB1E;
-                       if (lconfig->pixfmt == PIXFMT_RGB565)
-                               winmd |= OSD_OSDWIN1MD_RGB1E;
+                       if (sd->vpbe_type == VPBE_VERSION_1) {
+                               winmd_mask |= OSD_OSDWIN1MD_RGB1E;
+                               if (lconfig->pixfmt == PIXFMT_RGB565)
+                                       winmd |= OSD_OSDWIN1MD_RGB1E;
+                       } else if ((sd->vpbe_type == VPBE_VERSION_3)
+                                  || (sd->vpbe_type == VPBE_VERSION_2)) {
+                               winmd_mask |= OSD_OSDWIN1MD_BMP1MD;
+                               switch (lconfig->pixfmt) {
+                               case PIXFMT_RGB565:
+                                       winmd |=
+                                           (1 << OSD_OSDWIN1MD_BMP1MD_SHIFT);
+                                       break;
+                               case PIXFMT_RGB888:
+                                       winmd |=
+                                           (2 << OSD_OSDWIN1MD_BMP1MD_SHIFT);
+                                       _osd_enable_rgb888_pixblend(sd,
+                                                       OSDWIN_OSD1);
+                                       break;
+                               case PIXFMT_YCbCrI:
+                               case PIXFMT_YCrCbI:
+                                       winmd |=
+                                           (3 << OSD_OSDWIN1MD_BMP1MD_SHIFT);
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
 
                        winmd_mask |= OSD_OSDWIN1MD_BMW1;
                        switch (lconfig->pixfmt) {
@@ -822,15 +1170,45 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
                 * For YUV420P format the register contents are
                 * duplicated in both VID registers
                 */
-               osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D,
-                          OSD_MISCCTL);
+               if (sd->vpbe_type == VPBE_VERSION_2) {
+                       if (lconfig->pixfmt == PIXFMT_NV12) {
+                               /* other window also */
+                               if (lconfig->interlaced) {
+                                       winmd_mask |= OSD_VIDWINMD_VFF0;
+                                       winmd |= OSD_VIDWINMD_VFF0;
+                                       osd_modify(sd, winmd_mask, winmd,
+                                                 OSD_VIDWINMD);
+                               }
+                               osd_modify(sd, OSD_MISCCTL_S420D,
+                                          OSD_MISCCTL_S420D, OSD_MISCCTL);
+                               osd_write(sd, lconfig->line_length >> 5,
+                                         OSD_VIDWIN0OFST);
+                               osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP);
+                               osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL);
+                       } else {
+                               osd_modify(sd, OSD_MISCCTL_S420D,
+                                          ~OSD_MISCCTL_S420D, OSD_MISCCTL);
+                       }
+               }
 
                if (lconfig->interlaced) {
                        osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP);
                        osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL);
+                       if ((sd->vpbe_type == VPBE_VERSION_2) &&
+                               lconfig->pixfmt == PIXFMT_NV12) {
+                               osd_write(sd, lconfig->ypos >> 1,
+                                         OSD_VIDWIN0YP);
+                               osd_write(sd, lconfig->ysize >> 1,
+                                         OSD_VIDWIN0YL);
+                       }
                } else {
                        osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP);
                        osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL);
+                       if ((sd->vpbe_type == VPBE_VERSION_2) &&
+                               lconfig->pixfmt == PIXFMT_NV12) {
+                               osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP);
+                               osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL);
+                       }
                }
                break;
        }
@@ -1089,6 +1467,11 @@ static void _osd_init(struct osd_state *sd)
        osd_write(sd, 0, OSD_OSDWIN1MD);
        osd_write(sd, 0, OSD_RECTCUR);
        osd_write(sd, 0, OSD_MISCCTL);
+       if (sd->vpbe_type == VPBE_VERSION_3) {
+               osd_write(sd, 0, OSD_VBNDRY);
+               osd_write(sd, 0, OSD_EXTMODE);
+               osd_write(sd, OSD_MISCCTL_DMANG, OSD_MISCCTL);
+       }
 }
 
 static void osd_set_left_margin(struct osd_state *sd, u32 val)
@@ -1110,6 +1493,14 @@ static int osd_initialize(struct osd_state *osd)
        /* set default Cb/Cr order */
        osd->yc_pixfmt = PIXFMT_YCbCrI;
 
+       if (osd->vpbe_type == VPBE_VERSION_3) {
+               /*
+                * ROM CLUT1 on the DM355 is similar (identical?) to ROM CLUT0
+                * on the DM6446, so make ROM_CLUT1 the default on the DM355.
+                */
+               osd->rom_clut = ROM_CLUT1;
+       }
+
        _osd_set_field_inversion(osd, osd->field_inversion);
        _osd_set_rom_clut(osd, osd->rom_clut);
 
@@ -1208,23 +1599,7 @@ static struct platform_driver osd_driver = {
        },
 };
 
-static int osd_init(void)
-{
-       if (platform_driver_register(&osd_driver)) {
-               printk(KERN_ERR "Unable to register davinci osd driver\n");
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static void osd_exit(void)
-{
-       platform_driver_unregister(&osd_driver);
-}
-
-module_init(osd_init);
-module_exit(osd_exit);
+module_platform_driver(osd_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("DaVinci OSD Manager Driver");
index 03a3e5c65ee78c53c017096ca55cf35d81ec0402..00e80f59d5d5339c6f0e835e9f82103d328be7f5 100644 (file)
@@ -99,6 +99,8 @@ static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val)
        return val;
 }
 
+#define VDAC_COMPONENT 0x543
+#define VDAC_S_VIDEO   0x210
 /* This function sets the dac of the VPBE for various outputs
  */
 static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index)
@@ -109,11 +111,12 @@ static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index)
                venc_write(sd, VENC_DACSEL, 0);
                break;
        case 1:
-               v4l2_dbg(debug, 1, sd, "Setting output to S-Video\n");
-               venc_write(sd, VENC_DACSEL, 0x210);
+               v4l2_dbg(debug, 1, sd, "Setting output to Component\n");
+               venc_write(sd, VENC_DACSEL, VDAC_COMPONENT);
                break;
-       case  2:
-               venc_write(sd, VENC_DACSEL, 0x543);
+       case 2:
+               v4l2_dbg(debug, 1, sd, "Setting output to S-video\n");
+               venc_write(sd, VENC_DACSEL, VDAC_S_VIDEO);
                break;
        default:
                return -EINVAL;
@@ -124,6 +127,8 @@ static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index)
 
 static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable)
 {
+       struct venc_state *venc = to_state(sd);
+       struct venc_platform_data *pdata = venc->pdata;
        v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n");
 
        if (benable) {
@@ -155,7 +160,8 @@ static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable)
 
                /* Disable LCD output control (accepting default polarity) */
                venc_write(sd, VENC_LCDOUT, 0);
-               venc_write(sd, VENC_CMPNT, 0x100);
+               if (pdata->venc_type != VPBE_VERSION_3)
+                       venc_write(sd, VENC_CMPNT, 0x100);
                venc_write(sd, VENC_HSPLS, 0);
                venc_write(sd, VENC_HINT, 0);
                venc_write(sd, VENC_HSTART, 0);
@@ -178,11 +184,14 @@ static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable)
        }
 }
 
+#define VDAC_CONFIG_SD_V3      0x0E21A6B6
+#define VDAC_CONFIG_SD_V2      0x081141CF
 /*
  * setting NTSC mode
  */
 static int venc_set_ntsc(struct v4l2_subdev *sd)
 {
+       u32 val;
        struct venc_state *venc = to_state(sd);
        struct venc_platform_data *pdata = venc->pdata;
 
@@ -195,12 +204,22 @@ static int venc_set_ntsc(struct v4l2_subdev *sd)
 
        venc_enabledigitaloutput(sd, 0);
 
-       /* to set VENC CLK DIV to 1 - final clock is 54 MHz */
-       venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
-       /* Set REC656 Mode */
-       venc_write(sd, VENC_YCCCTL, 0x1);
-       venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ);
-       venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS);
+       if (pdata->venc_type == VPBE_VERSION_3) {
+               venc_write(sd, VENC_CLKCTL, 0x01);
+               venc_write(sd, VENC_VIDCTL, 0);
+               val = vdaccfg_write(sd, VDAC_CONFIG_SD_V3);
+       } else if (pdata->venc_type == VPBE_VERSION_2) {
+               venc_write(sd, VENC_CLKCTL, 0x01);
+               venc_write(sd, VENC_VIDCTL, 0);
+               vdaccfg_write(sd, VDAC_CONFIG_SD_V2);
+       } else {
+               /* to set VENC CLK DIV to 1 - final clock is 54 MHz */
+               venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
+               /* Set REC656 Mode */
+               venc_write(sd, VENC_YCCCTL, 0x1);
+               venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ);
+               venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS);
+       }
 
        venc_write(sd, VENC_VMOD, 0);
        venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
@@ -220,6 +239,7 @@ static int venc_set_ntsc(struct v4l2_subdev *sd)
 static int venc_set_pal(struct v4l2_subdev *sd)
 {
        struct venc_state *venc = to_state(sd);
+       struct venc_platform_data *pdata = venc->pdata;
 
        v4l2_dbg(debug, 2, sd, "venc_set_pal\n");
 
@@ -230,10 +250,20 @@ static int venc_set_pal(struct v4l2_subdev *sd)
 
        venc_enabledigitaloutput(sd, 0);
 
-       /* to set VENC CLK DIV to 1 - final clock is 54 MHz */
-       venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
-       /* Set REC656 Mode */
-       venc_write(sd, VENC_YCCCTL, 0x1);
+       if (pdata->venc_type == VPBE_VERSION_3) {
+               venc_write(sd, VENC_CLKCTL, 0x1);
+               venc_write(sd, VENC_VIDCTL, 0);
+               vdaccfg_write(sd, VDAC_CONFIG_SD_V3);
+       } else if (pdata->venc_type == VPBE_VERSION_2) {
+               venc_write(sd, VENC_CLKCTL, 0x1);
+               venc_write(sd, VENC_VIDCTL, 0);
+               vdaccfg_write(sd, VDAC_CONFIG_SD_V2);
+       } else {
+               /* to set VENC CLK DIV to 1 - final clock is 54 MHz */
+               venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
+               /* Set REC656 Mode */
+               venc_write(sd, VENC_YCCCTL, 0x1);
+       }
 
        venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT,
                        VENC_SYNCCTL_OVD);
@@ -252,6 +282,7 @@ static int venc_set_pal(struct v4l2_subdev *sd)
        return 0;
 }
 
+#define VDAC_CONFIG_HD_V2      0x081141EF
 /*
  * venc_set_480p59_94
  *
@@ -263,6 +294,9 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd)
        struct venc_platform_data *pdata = venc->pdata;
 
        v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n");
+       if ((pdata->venc_type != VPBE_VERSION_1) &&
+           (pdata->venc_type != VPBE_VERSION_2))
+               return -EINVAL;
 
        /* Setup clock at VPSS & VENC for SD */
        if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0)
@@ -270,12 +304,18 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd)
 
        venc_enabledigitaloutput(sd, 0);
 
+       if (pdata->venc_type == VPBE_VERSION_2)
+               vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
        venc_write(sd, VENC_OSDCLK0, 0);
        venc_write(sd, VENC_OSDCLK1, 1);
-       venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
-                   VENC_VDPRO_DAFRQ);
-       venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
-                   VENC_VDPRO_DAUPS);
+
+       if (pdata->venc_type == VPBE_VERSION_1) {
+               venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
+                           VENC_VDPRO_DAFRQ);
+               venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
+                           VENC_VDPRO_DAUPS);
+       }
+
        venc_write(sd, VENC_VMOD, 0);
        venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
                    VENC_VMOD_VIE);
@@ -302,19 +342,27 @@ static int venc_set_576p50(struct v4l2_subdev *sd)
 
        v4l2_dbg(debug, 2, sd, "venc_set_576p50\n");
 
+       if ((pdata->venc_type != VPBE_VERSION_1) &&
+         (pdata->venc_type != VPBE_VERSION_2))
+               return -EINVAL;
        /* Setup clock at VPSS & VENC for SD */
        if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0)
                return -EINVAL;
 
        venc_enabledigitaloutput(sd, 0);
 
+       if (pdata->venc_type == VPBE_VERSION_2)
+               vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
+
        venc_write(sd, VENC_OSDCLK0, 0);
        venc_write(sd, VENC_OSDCLK1, 1);
 
-       venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
-                   VENC_VDPRO_DAFRQ);
-       venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
-                   VENC_VDPRO_DAUPS);
+       if (pdata->venc_type == VPBE_VERSION_1) {
+               venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
+                           VENC_VDPRO_DAFRQ);
+               venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
+                           VENC_VDPRO_DAUPS);
+       }
 
        venc_write(sd, VENC_VMOD, 0);
        venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
@@ -330,6 +378,63 @@ static int venc_set_576p50(struct v4l2_subdev *sd)
        return 0;
 }
 
+/*
+ * venc_set_720p60_internal - Setup 720p60 in venc for dm365 only
+ */
+static int venc_set_720p60_internal(struct v4l2_subdev *sd)
+{
+       struct venc_state *venc = to_state(sd);
+       struct venc_platform_data *pdata = venc->pdata;
+
+       if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_720P60) < 0)
+               return -EINVAL;
+
+       venc_enabledigitaloutput(sd, 0);
+
+       venc_write(sd, VENC_OSDCLK0, 0);
+       venc_write(sd, VENC_OSDCLK1, 1);
+
+       venc_write(sd, VENC_VMOD, 0);
+       /* DM365 component HD mode */
+       venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+           VENC_VMOD_VIE);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
+       venc_modify(sd, VENC_VMOD, (HDTV_720P << VENC_VMOD_TVTYP_SHIFT),
+                   VENC_VMOD_TVTYP);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+       venc_write(sd, VENC_XHINTVL, 0);
+       return 0;
+}
+
+/*
+ * venc_set_1080i30_internal - Setup 1080i30 in venc for dm365 only
+ */
+static int venc_set_1080i30_internal(struct v4l2_subdev *sd)
+{
+       struct venc_state *venc = to_state(sd);
+       struct venc_platform_data *pdata = venc->pdata;
+
+       if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_1080P30) < 0)
+               return -EINVAL;
+
+       venc_enabledigitaloutput(sd, 0);
+
+       venc_write(sd, VENC_OSDCLK0, 0);
+       venc_write(sd, VENC_OSDCLK1, 1);
+
+
+       venc_write(sd, VENC_VMOD, 0);
+       /* DM365 component HD mode */
+       venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+                   VENC_VMOD_VIE);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
+       venc_modify(sd, VENC_VMOD, (HDTV_1080I << VENC_VMOD_TVTYP_SHIFT),
+                   VENC_VMOD_TVTYP);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+       venc_write(sd, VENC_XHINTVL, 0);
+       return 0;
+}
+
 static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
 {
        v4l2_dbg(debug, 1, sd, "venc_s_std_output\n");
@@ -345,13 +450,30 @@ static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
 static int venc_s_dv_preset(struct v4l2_subdev *sd,
                            struct v4l2_dv_preset *dv_preset)
 {
+       struct venc_state *venc = to_state(sd);
+       int ret;
+
        v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n");
 
        if (dv_preset->preset == V4L2_DV_576P50)
                return venc_set_576p50(sd);
        else if (dv_preset->preset == V4L2_DV_480P59_94)
                return venc_set_480p59_94(sd);
-
+       else if ((dv_preset->preset == V4L2_DV_720P60) &&
+                       (venc->pdata->venc_type == VPBE_VERSION_2)) {
+               /* TBD setup internal 720p mode here */
+               ret = venc_set_720p60_internal(sd);
+               /* for DM365 VPBE, there is DAC inside */
+               vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
+               return ret;
+       } else if ((dv_preset->preset == V4L2_DV_1080I30) &&
+               (venc->pdata->venc_type == VPBE_VERSION_2)) {
+               /* TBD setup internal 1080i mode here */
+               ret = venc_set_1080i30_internal(sd);
+               /* for DM365 VPBE, there is DAC inside */
+               vdaccfg_write(sd, VDAC_CONFIG_HD_V2);
+               return ret;
+       }
        return -EINVAL;
 }
 
@@ -508,11 +630,41 @@ static int venc_probe(struct platform_device *pdev)
                goto release_venc_mem_region;
        }
 
+       if (venc->pdata->venc_type != VPBE_VERSION_1) {
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               if (!res) {
+                       dev_err(venc->pdev,
+                               "Unable to get VDAC_CONFIG address map\n");
+                       ret = -ENODEV;
+                       goto unmap_venc_io;
+               }
+
+               if (!request_mem_region(res->start,
+                                       resource_size(res), "venc")) {
+                       dev_err(venc->pdev,
+                               "Unable to reserve VDAC_CONFIG  MMIO region\n");
+                       ret = -ENODEV;
+                       goto unmap_venc_io;
+               }
+
+               venc->vdaccfg_reg = ioremap_nocache(res->start,
+                                                   resource_size(res));
+               if (!venc->vdaccfg_reg) {
+                       dev_err(venc->pdev,
+                               "Unable to map VDAC_CONFIG IO space\n");
+                       ret = -ENODEV;
+                       goto release_vdaccfg_mem_region;
+               }
+       }
        spin_lock_init(&venc->lock);
        platform_set_drvdata(pdev, venc);
        dev_notice(venc->pdev, "VENC sub device probe success\n");
        return 0;
 
+release_vdaccfg_mem_region:
+       release_mem_region(res->start, resource_size(res));
+unmap_venc_io:
+       iounmap(venc->venc_base);
 release_venc_mem_region:
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(res->start, resource_size(res));
@@ -529,6 +681,11 @@ static int venc_remove(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        iounmap((void *)venc->venc_base);
        release_mem_region(res->start, resource_size(res));
+       if (venc->pdata->venc_type != VPBE_VERSION_1) {
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               iounmap((void *)venc->vdaccfg_reg);
+               release_mem_region(res->start, resource_size(res));
+       }
        kfree(venc);
 
        return 0;
@@ -543,23 +700,7 @@ static struct platform_driver venc_driver = {
        },
 };
 
-static int venc_init(void)
-{
-       if (platform_driver_register(&venc_driver)) {
-               printk(KERN_ERR "Unable to register venc driver\n");
-               return -ENODEV;
-       }
-       return 0;
-}
-
-static void venc_exit(void)
-{
-       platform_driver_unregister(&venc_driver);
-       return;
-}
-
-module_init(venc_init);
-module_exit(venc_exit);
+module_platform_driver(venc_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("VPBE VENC Driver");
index 5b38fc93ff280c7fe8fa3e22f386ccaa31c9d824..20cf271a774b81b6c3d9b32b963287f30130f3f7 100644 (file)
@@ -2076,20 +2076,4 @@ static struct platform_driver vpfe_driver = {
        .remove = __devexit_p(vpfe_remove),
 };
 
-static __init int vpfe_init(void)
-{
-       printk(KERN_NOTICE "vpfe_init\n");
-       /* Register driver to the kernel */
-       return platform_driver_register(&vpfe_driver);
-}
-
-/*
- * vpfe_cleanup : This function un-registers device driver
- */
-static void vpfe_cleanup(void)
-{
-       platform_driver_unregister(&vpfe_driver);
-}
-
-module_init(vpfe_init);
-module_exit(vpfe_cleanup);
+module_platform_driver(vpfe_driver);
index 49e4deb500430faf3be60475b5062cf7e5141921..6504e40a31dd2fb27277253ae7166ff3da64decb 100644 (file)
@@ -2177,6 +2177,12 @@ static __init int vpif_probe(struct platform_device *pdev)
                return err;
        }
 
+       err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);
+       if (err) {
+               v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n");
+               return err;
+       }
+
        k = 0;
        while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) {
                for (i = res->start; i <= res->end; i++) {
@@ -2246,12 +2252,6 @@ static __init int vpif_probe(struct platform_device *pdev)
                goto probe_out;
        }
 
-       err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev);
-       if (err) {
-               v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n");
-               goto probe_subdev_out;
-       }
-
        for (i = 0; i < subdev_count; i++) {
                subdevdata = &config->subdev_info[i];
                vpif_obj.sd[i] =
@@ -2281,7 +2281,6 @@ probe_subdev_out:
 
        j = VPIF_CAPTURE_MAX_DEVICES;
 probe_out:
-       v4l2_device_unregister(&vpif_obj.v4l2_dev);
        for (k = 0; k < j; k++) {
                /* Get the pointer to the channel object */
                ch = vpif_obj.dev[k];
@@ -2303,6 +2302,7 @@ vpif_int_err:
                if (res)
                        i = res->end;
        }
+       v4l2_device_unregister(&vpif_obj.v4l2_dev);
        return err;
 }
 
index cff0768afbf514183b50ba0e35e3bfdcbde43a6f..e2a7b77c39c79a21fbef86892cd66f2a322a95c6 100644 (file)
@@ -193,7 +193,7 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
 
                urb->dev = dev->udev;
                urb->context = dev;
-               urb->pipe = usb_rcvisocpipe(dev->udev, 0x83);
+               urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
                urb->transfer_flags = URB_ISO_ASAP;
                urb->transfer_buffer = dev->adev.transfer_buffer[i];
                urb->interval = 1;
index 93807dcf944e4be4d9a4ed4604d358fa0c2e0b90..4561cd89938de422ff268b64d5a2734d27873daa 100644 (file)
@@ -336,6 +336,23 @@ static struct em28xx_reg_seq pctv_460e[] = {
        {             -1,   -1,   -1,  -1},
 };
 
+#if 0
+static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
+       {EM2874_R80_GPIO,       0x6f,   0xff,   10},
+       {EM2874_R80_GPIO,       0x4f,   0xff,   10}, /* xc5000 reset */
+       {EM2874_R80_GPIO,       0x6f,   0xff,   10},
+       {EM2874_R80_GPIO,       0x4f,   0xff,   10},
+       { -1,                   -1,     -1,     -1},
+};
+
+static struct em28xx_reg_seq hauppauge_930c_digital[] = {
+       {EM2874_R80_GPIO,       0xf6,   0xff,   10},
+       {EM2874_R80_GPIO,       0xe6,   0xff,   100},
+       {EM2874_R80_GPIO,       0xa6,   0xff,   10},
+       { -1,                   -1,     -1,     -1},
+};
+#endif
+
 /*
  *  Board definitions
  */
@@ -839,6 +856,10 @@ struct em28xx_board em28xx_boards[] = {
        [EM2870_BOARD_KWORLD_355U] = {
                .name         = "Kworld 355 U DVB-T",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
+               .tuner_type   = TUNER_ABSENT,
+               .tuner_gpio   = default_tuner_gpio,
+               .has_dvb      = 1,
+               .dvb_gpio     = default_digital,
        },
        [EM2870_BOARD_PINNACLE_PCTV_DVB] = {
                .name         = "Pinnacle PCTV DVB-T",
@@ -887,6 +908,37 @@ struct em28xx_board em28xx_boards[] = {
                .tuner_addr   = 0x41,
                .dvb_gpio     = terratec_h5_digital, /* FIXME: probably wrong */
                .tuner_gpio   = terratec_h5_gpio,
+#else
+               .tuner_type   = TUNER_ABSENT,
+#endif
+               .i2c_speed    = EM2874_I2C_SECONDARY_BUS_SELECT |
+                               EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_400_KHZ,
+       },
+       [EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C] = {
+               .name         = "Hauppauge WinTV HVR 930C",
+               .has_dvb      = 1,
+#if 0 /* FIXME: Add analog support */
+               .tuner_type   = TUNER_XC5000,
+               .tuner_addr   = 0x41,
+               .dvb_gpio     = hauppauge_930c_digital,
+               .tuner_gpio   = hauppauge_930c_gpio,
+#else
+               .tuner_type   = TUNER_ABSENT,
+#endif
+               .ir_codes     = RC_MAP_HAUPPAUGE,
+               .i2c_speed    = EM2874_I2C_SECONDARY_BUS_SELECT |
+                               EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_400_KHZ,
+       },
+       [EM2884_BOARD_CINERGY_HTC_STICK] = {
+               .name         = "Terratec Cinergy HTC Stick",
+               .has_dvb      = 1,
+#if 0
+               .tuner_type   = TUNER_PHILIPS_TDA8290,
+               .tuner_addr   = 0x41,
+               .dvb_gpio     = terratec_h5_digital, /* FIXME: probably wrong */
+               .tuner_gpio   = terratec_h5_gpio,
 #endif
                .i2c_speed    = EM2874_I2C_SECONDARY_BUS_SELECT |
                                EM28XX_I2C_CLK_WAIT_ENABLE |
@@ -1127,7 +1179,7 @@ struct em28xx_board em28xx_boards[] = {
                .name         = "Terratec Cinergy 200 USB",
                .is_em2800    = 1,
                .has_ir_i2c   = 1,
-               .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+               .tuner_type   = TUNER_LG_TALN,
                .tda9887_conf = TDA9887_PRESENT,
                .decoder      = EM28XX_SAA711X,
                .input        = { {
@@ -1218,7 +1270,7 @@ struct em28xx_board em28xx_boards[] = {
        },
        [EM2820_BOARD_PINNACLE_DVC_90] = {
                .name         = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker "
-                               "/ Kworld DVD Maker 2",
+                              "/ Kworld DVD Maker 2 / Plextor ConvertX PX-AV100U",
                .tuner_type   = TUNER_ABSENT, /* capture only board */
                .decoder      = EM28XX_SAA711X,
                .input        = { {
@@ -1840,6 +1892,22 @@ struct em28xx_board em28xx_boards[] = {
                .has_dvb       = 1,
                .ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
        },
+       /* eb1a:5006 Honestech VIDBOX NW03
+        * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner */
+       [EM2860_BOARD_HT_VIDBOX_NW03] = {
+               .name                = "Honestech Vidbox NW03",
+               .tuner_type          = TUNER_ABSENT,
+               .decoder             = EM28XX_SAA711X,
+               .input               = { {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = SAA7115_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = SAA7115_SVIDEO3,  /* S-VIDEO needs confirming */
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               } },
+       },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -1899,6 +1967,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2800_BOARD_GRABBEEX_USB2800 },
        { USB_DEVICE(0xeb1a, 0xe357),
                        .driver_info = EM2870_BOARD_KWORLD_355U },
+       { USB_DEVICE(0xeb1a, 0xe359),
+                       .driver_info = EM2870_BOARD_KWORLD_355U },
        { USB_DEVICE(0x1b80, 0xe302),
                        .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */
        { USB_DEVICE(0x1b80, 0xe304),
@@ -1914,17 +1984,23 @@ struct usb_device_id em28xx_id_table[] = {
        { USB_DEVICE(0x0ccd, 0x0042),
                        .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS },
        { USB_DEVICE(0x0ccd, 0x0043),
+                       .driver_info = EM2870_BOARD_TERRATEC_XS },
+       { USB_DEVICE(0x0ccd, 0x008e),   /* Cinergy HTC USB XS Rev. 1 */
+                       .driver_info = EM2884_BOARD_TERRATEC_H5 },
+       { USB_DEVICE(0x0ccd, 0x00ac),   /* Cinergy HTC USB XS Rev. 2 */
+                       .driver_info = EM2884_BOARD_TERRATEC_H5 },
+       { USB_DEVICE(0x0ccd, 0x10a2),   /* H5 Rev. 1 */
                        .driver_info = EM2884_BOARD_TERRATEC_H5 },
-       { USB_DEVICE(0x0ccd, 0x10a2),   /* Rev. 1 */
+       { USB_DEVICE(0x0ccd, 0x10ad),   /* H5 Rev. 2 */
                        .driver_info = EM2884_BOARD_TERRATEC_H5 },
-       { USB_DEVICE(0x0ccd, 0x10ad),   /* Rev. 2 */
-                       .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
        { USB_DEVICE(0x0ccd, 0x0084),
                        .driver_info = EM2860_BOARD_TERRATEC_AV350 },
        { USB_DEVICE(0x0ccd, 0x0096),
                        .driver_info = EM2860_BOARD_TERRATEC_GRABBY },
        { USB_DEVICE(0x0ccd, 0x10AF),
                        .driver_info = EM2860_BOARD_TERRATEC_GRABBY },
+       { USB_DEVICE(0x0ccd, 0x00b2),
+                       .driver_info = EM2884_BOARD_CINERGY_HTC_STICK },
        { USB_DEVICE(0x0fd9, 0x0033),
                        .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE},
        { USB_DEVICE(0x185b, 0x2870),
@@ -1963,6 +2039,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
        { USB_DEVICE(0x0413, 0x6023),
                        .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII },
+       { USB_DEVICE(0x093b, 0xa003),
+                      .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
        { USB_DEVICE(0x093b, 0xa005),
                        .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U },
        { USB_DEVICE(0x04bb, 0x0515),
@@ -1975,6 +2053,12 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM28174_BOARD_PCTV_290E },
        { USB_DEVICE(0x2013, 0x024c),
                        .driver_info = EM28174_BOARD_PCTV_460E },
+       { USB_DEVICE(0x2040, 0x1605),
+                       .driver_info = EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C },
+       { USB_DEVICE(0xeb1a, 0x5006),
+                       .driver_info = EM2860_BOARD_HT_VIDBOX_NW03 },
+       { USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */
+                       .driver_info = EM2860_BOARD_EASYCAP },
        { },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2028,10 +2112,10 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
        int rc = 0;
        struct em28xx *dev = ptr;
 
-       if (dev->tuner_type != TUNER_XC2028)
+       if (dev->tuner_type != TUNER_XC2028 && dev->tuner_type != TUNER_XC5000)
                return 0;
 
-       if (command != XC2028_TUNER_RESET)
+       if (command != XC2028_TUNER_RESET && command != XC5000_TUNER_RESET)
                return 0;
 
        rc = em28xx_gpio_set(dev, dev->board.tuner_gpio);
@@ -2203,7 +2287,8 @@ void em28xx_pre_card_setup(struct em28xx *dev)
        /* Set the initial XCLK and I2C clock values based on the board
           definition */
        em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f);
-       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
+       if (!dev->board.is_em2800)
+               em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
        msleep(50);
 
        /* request some modules */
@@ -2832,11 +2917,10 @@ void em28xx_release_resources(struct em28xx *dev)
  * em28xx_init_dev()
  * allocates and inits the device structs, registers i2c bus and v4l device
  */
-static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
+static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
                           struct usb_interface *interface,
                           int minor)
 {
-       struct em28xx *dev = *devhandle;
        int retval;
 
        dev->udev = udev;
@@ -2931,7 +3015,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
 
        if (!dev->board.is_em2800) {
                /* Resets I2C speed */
-               em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
+               retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
                if (retval < 0) {
                        em28xx_errdev("%s: em28xx_write_reg failed!"
                                      " retval [%d]\n",
@@ -3031,12 +3115,11 @@ unregister_dev:
 static int em28xx_usb_probe(struct usb_interface *interface,
                            const struct usb_device_id *id)
 {
-       const struct usb_endpoint_descriptor *endpoint;
        struct usb_device *udev;
        struct em28xx *dev = NULL;
        int retval;
-       bool is_audio_only = false, has_audio = false;
-       int i, nr, isoc_pipe;
+       bool has_audio = false, has_video = false, has_dvb = false;
+       int i, nr;
        const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
        char *speed;
        char descr[255] = "";
@@ -3068,54 +3151,65 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                goto err;
        }
 
+       /* allocate memory for our device state and initialize it */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
+               em28xx_err(DRIVER_NAME ": out of memory!\n");
+               retval = -ENOMEM;
+               goto err;
+       }
+
+       /* compute alternate max packet sizes */
+       dev->alt_max_pkt_size = kmalloc(sizeof(dev->alt_max_pkt_size[0]) *
+                                       interface->num_altsetting, GFP_KERNEL);
+       if (dev->alt_max_pkt_size == NULL) {
+               em28xx_errdev("out of memory!\n");
+               kfree(dev);
+               retval = -ENOMEM;
+               goto err;
+       }
+
        /* Get endpoints */
        for (i = 0; i < interface->num_altsetting; i++) {
                int ep;
 
                for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
-                       struct usb_host_endpoint        *e;
-                       e = &interface->altsetting[i].endpoint[ep];
-
-                       if (e->desc.bEndpointAddress == 0x83)
-                               has_audio = true;
+                       const struct usb_endpoint_descriptor *e;
+                       int sizedescr, size;
+
+                       e = &interface->altsetting[i].endpoint[ep].desc;
+
+                       sizedescr = le16_to_cpu(e->wMaxPacketSize);
+                       size = sizedescr & 0x7ff;
+
+                       if (udev->speed == USB_SPEED_HIGH)
+                               size = size * hb_mult(sizedescr);
+
+                       if (usb_endpoint_xfer_isoc(e) &&
+                           usb_endpoint_dir_in(e)) {
+                               switch (e->bEndpointAddress) {
+                               case EM28XX_EP_AUDIO:
+                                       has_audio = true;
+                                       break;
+                               case EM28XX_EP_ANALOG:
+                                       has_video = true;
+                                       dev->alt_max_pkt_size[i] = size;
+                                       break;
+                               case EM28XX_EP_DIGITAL:
+                                       has_dvb = true;
+                                       if (size > dev->dvb_max_pkt_size) {
+                                               dev->dvb_max_pkt_size = size;
+                                               dev->dvb_alt = i;
+                                       }
+                                       break;
+                               }
+                       }
                }
        }
 
-       endpoint = &interface->cur_altsetting->endpoint[0].desc;
-
-       /* check if the device has the iso in endpoint at the correct place */
-       if (usb_endpoint_xfer_isoc(endpoint)
-           &&
-           (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) {
-               /* It's a newer em2874/em2875 device */
-               isoc_pipe = 0;
-       } else {
-               int check_interface = 1;
-               isoc_pipe = 1;
-               endpoint = &interface->cur_altsetting->endpoint[1].desc;
-               if (!usb_endpoint_xfer_isoc(endpoint))
-                       check_interface = 0;
-
-               if (usb_endpoint_dir_out(endpoint))
-                       check_interface = 0;
-
-               if (!check_interface) {
-                       if (has_audio) {
-                               is_audio_only = true;
-                       } else {
-                               em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
-                                       "interface %i, class %i found.\n",
-                                       le16_to_cpu(udev->descriptor.idVendor),
-                                       le16_to_cpu(udev->descriptor.idProduct),
-                                       ifnum,
-                                       interface->altsetting[0].desc.bInterfaceClass);
-                               em28xx_err(DRIVER_NAME " This is an anciliary "
-                                       "interface not used by the driver\n");
-
-                               retval = -ENODEV;
-                               goto err;
-                       }
-               }
+       if (!(has_audio || has_video || has_dvb)) {
+               retval = -ENODEV;
+               goto err_free;
        }
 
        switch (udev->speed) {
@@ -3141,6 +3235,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                        strlcat(descr, " ", sizeof(descr));
                strlcat(descr, udev->product, sizeof(descr));
        }
+
        if (*descr)
                strlcat(descr, " ", sizeof(descr));
 
@@ -3157,6 +3252,14 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                printk(KERN_INFO DRIVER_NAME
                       ": Audio Vendor Class interface %i found\n",
                       ifnum);
+       if (has_video)
+               printk(KERN_INFO DRIVER_NAME
+                      ": Video interface %i found\n",
+                      ifnum);
+       if (has_dvb)
+               printk(KERN_INFO DRIVER_NAME
+                      ": DVB interface %i found\n",
+                      ifnum);
 
        /*
         * Make sure we have 480 Mbps of bandwidth, otherwise things like
@@ -3168,22 +3271,14 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                printk(DRIVER_NAME ": Device must be connected to a high-speed"
                       " USB 2.0 port.\n");
                retval = -ENODEV;
-               goto err;
-       }
-
-       /* allocate memory for our device state and initialize it */
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (dev == NULL) {
-               em28xx_err(DRIVER_NAME ": out of memory!\n");
-               retval = -ENOMEM;
-               goto err;
+               goto err_free;
        }
 
        snprintf(dev->name, sizeof(dev->name), "em28xx #%d", nr);
        dev->devno = nr;
        dev->model = id->driver_info;
        dev->alt   = -1;
-       dev->is_audio_only = is_audio_only;
+       dev->is_audio_only = has_audio && !(has_video || has_dvb);
        dev->has_alsa_audio = has_audio;
        dev->audio_ifnum = ifnum;
 
@@ -3196,26 +3291,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                }
        }
 
-       /* compute alternate max packet sizes */
        dev->num_alt = interface->num_altsetting;
-       dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
-
-       if (dev->alt_max_pkt_size == NULL) {
-               em28xx_errdev("out of memory!\n");
-               kfree(dev);
-               retval = -ENOMEM;
-               goto err;
-       }
-
-       for (i = 0; i < dev->num_alt ; i++) {
-               u16 tmp = le16_to_cpu(interface->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
-               unsigned int size = tmp & 0x7ff;
-
-               if (udev->speed == USB_SPEED_HIGH)
-                       size = size * hb_mult(tmp);
-
-               dev->alt_max_pkt_size[i] = size;
-       }
 
        if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
                dev->model = card[nr];
@@ -3226,12 +3302,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        /* allocate device struct */
        mutex_init(&dev->lock);
        mutex_lock(&dev->lock);
-       retval = em28xx_init_dev(&dev, udev, interface, nr);
+       retval = em28xx_init_dev(dev, udev, interface, nr);
        if (retval) {
-               mutex_unlock(&dev->lock);
-               kfree(dev->alt_max_pkt_size);
-               kfree(dev);
-               goto err;
+               goto unlock_and_free;
        }
 
        request_modules(dev);
@@ -3250,6 +3323,13 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 
        return 0;
 
+unlock_and_free:
+       mutex_unlock(&dev->lock);
+
+err_free:
+       kfree(dev->alt_max_pkt_size);
+       kfree(dev);
+
 err:
        clear_bit(nr, &em28xx_devused);
 
index 804a4ab47ac636405579d4d6a8003dcffafa04f0..0aacc96f9a232416928e8a07346620f223ef0cbc 100644 (file)
@@ -568,7 +568,7 @@ int em28xx_audio_setup(struct em28xx *dev)
        em28xx_warn("AC97 features = 0x%04x\n", feat);
 
        /* Try to identify what audio processor we have */
-       if ((vid == 0xffffffff) && (feat == 0x6a90))
+       if (((vid == 0xffffffff) || (vid == 0x83847650)) && (feat == 0x6a90))
                dev->audio_mode.ac97 = EM28XX_AC97_EM202;
        else if ((vid >> 8) == 0x838476)
                dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL;
@@ -1070,7 +1070,8 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
                        should also be using 'desc.bInterval'
                 */
                pipe = usb_rcvisocpipe(dev->udev,
-                       dev->mode == EM28XX_ANALOG_MODE ? 0x82 : 0x84);
+                                      dev->mode == EM28XX_ANALOG_MODE ?
+                                      EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL);
 
                usb_fill_int_urb(urb, dev->udev, pipe,
                                 dev->isoc_ctl.transfer_buffer[i], sb_size,
@@ -1108,62 +1109,6 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
 }
 EXPORT_SYMBOL_GPL(em28xx_init_isoc);
 
-/* Determine the packet size for the DVB stream for the given device
-   (underlying value programmed into the eeprom) */
-int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev)
-{
-       unsigned int chip_cfg2;
-       unsigned int packet_size;
-
-       switch (dev->chip_id) {
-       case CHIP_ID_EM2710:
-       case CHIP_ID_EM2750:
-       case CHIP_ID_EM2800:
-       case CHIP_ID_EM2820:
-       case CHIP_ID_EM2840:
-       case CHIP_ID_EM2860:
-               /* No DVB support */
-               return -EINVAL;
-       case CHIP_ID_EM2870:
-       case CHIP_ID_EM2883:
-               /* TS max packet size stored in bits 1-0 of R01 */
-               chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2);
-               switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) {
-               case EM28XX_CHIPCFG2_TS_PACKETSIZE_188:
-                       packet_size = 188;
-                       break;
-               case EM28XX_CHIPCFG2_TS_PACKETSIZE_376:
-                       packet_size = 376;
-                       break;
-               case EM28XX_CHIPCFG2_TS_PACKETSIZE_564:
-                       packet_size = 564;
-                       break;
-               case EM28XX_CHIPCFG2_TS_PACKETSIZE_752:
-                       packet_size = 752;
-                       break;
-               }
-               break;
-       case CHIP_ID_EM2874:
-               /*
-                * FIXME: for now assumes 564 like it was before, but the
-                * em2874 code should be added to return the proper value
-                */
-               packet_size = 564;
-               break;
-       case CHIP_ID_EM2884:
-       case CHIP_ID_EM28174:
-       default:
-               /*
-                * FIXME: same as em2874. 564 was enough for 22 Mbit DVB-T
-                * but not enough for 44 Mbit DVB-C.
-                */
-               packet_size = 752;
-       }
-
-       return packet_size;
-}
-EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize);
-
 /*
  * em28xx_wake_i2c()
  * configure i2c attached devices
index cef7a2d409cbc27c53c2aabe805528d62f40b894..9449423098e0d4163eabe8d7a0b0c57cdb484cc2 100644 (file)
@@ -44,6 +44,7 @@
 #include "drxk.h"
 #include "tda10071.h"
 #include "a8293.h"
+#include "qt1010.h"
 
 MODULE_DESCRIPTION("driver for em28xx based DVB cards");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -163,12 +164,12 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
        struct em28xx *dev = dvb->adapter.priv;
        int max_dvb_packet_size;
 
-       usb_set_interface(dev->udev, 0, 1);
+       usb_set_interface(dev->udev, 0, dev->dvb_alt);
        rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
        if (rc < 0)
                return rc;
 
-       max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev);
+       max_dvb_packet_size = dev->dvb_max_pkt_size;
        if (max_dvb_packet_size < 0)
                return max_dvb_packet_size;
        dprintk(1, "Using %d buffers each with %d bytes\n",
@@ -302,10 +303,12 @@ static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
 };
 
 static struct drxd_config em28xx_drxd = {
-       .index = 0, .demod_address = 0x70, .demod_revision = 0xa2,
-       .demoda_address = 0x00, .pll_address = 0x00,
-       .pll_type = DRXD_PLL_NONE, .clock = 12000, .insert_rs_byte = 1,
-       .pll_set = NULL, .osc_deviation = NULL, .IF = 42800000,
+       .demod_address = 0x70,
+       .demod_revision = 0xa2,
+       .pll_type = DRXD_PLL_NONE,
+       .clock = 12000,
+       .insert_rs_byte = 1,
+       .IF = 42800000,
        .disable_i2c_gate_ctrl = 1,
 };
 
@@ -316,6 +319,14 @@ struct drxk_config terratec_h5_drxk = {
        .microcode_name = "dvb-usb-terratec-h5-drxk.fw",
 };
 
+struct drxk_config hauppauge_930c_drxk = {
+       .adr = 0x29,
+       .single_master = 1,
+       .no_i2c_bridge = 1,
+       .microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw",
+       .chunk_size = 56,
+};
+
 static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
        struct em28xx_dvb *dvb = fe->sec_priv;
@@ -334,6 +345,73 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
        return status;
 }
 
+static void hauppauge_hvr930c_init(struct em28xx *dev)
+{
+       int i;
+
+       struct em28xx_reg_seq hauppauge_hvr930c_init[] = {
+               {EM2874_R80_GPIO,       0xff,   0xff,   0x65},
+               {EM2874_R80_GPIO,       0xfb,   0xff,   0x32},
+               {EM2874_R80_GPIO,       0xff,   0xff,   0xb8},
+               { -1,                   -1,     -1,     -1},
+       };
+       struct em28xx_reg_seq hauppauge_hvr930c_end[] = {
+               {EM2874_R80_GPIO,       0xef,   0xff,   0x01},
+               {EM2874_R80_GPIO,       0xaf,   0xff,   0x65},
+               {EM2874_R80_GPIO,       0xef,   0xff,   0x76},
+               {EM2874_R80_GPIO,       0xef,   0xff,   0x01},
+               {EM2874_R80_GPIO,       0xcf,   0xff,   0x0b},
+               {EM2874_R80_GPIO,       0xef,   0xff,   0x40},
+
+               {EM2874_R80_GPIO,       0xcf,   0xff,   0x65},
+               {EM2874_R80_GPIO,       0xef,   0xff,   0x65},
+               {EM2874_R80_GPIO,       0xcf,   0xff,   0x0b},
+               {EM2874_R80_GPIO,       0xef,   0xff,   0x65},
+
+               { -1,                   -1,     -1,     -1},
+       };
+
+       struct {
+               unsigned char r[4];
+               int len;
+       } regs[] = {
+               {{ 0x06, 0x02, 0x00, 0x31 }, 4},
+               {{ 0x01, 0x02 }, 2},
+               {{ 0x01, 0x02, 0x00, 0xc6 }, 4},
+               {{ 0x01, 0x00 }, 2},
+               {{ 0x01, 0x00, 0xff, 0xaf }, 4},
+               {{ 0x01, 0x00, 0x03, 0xa0 }, 4},
+               {{ 0x01, 0x00 }, 2},
+               {{ 0x01, 0x00, 0x73, 0xaf }, 4},
+               {{ 0x04, 0x00 }, 2},
+               {{ 0x00, 0x04 }, 2},
+               {{ 0x00, 0x04, 0x00, 0x0a }, 4},
+               {{ 0x04, 0x14 }, 2},
+               {{ 0x04, 0x14, 0x00, 0x00 }, 4},
+       };
+
+       em28xx_gpio_set(dev, hauppauge_hvr930c_init);
+       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
+       msleep(10);
+       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
+       msleep(10);
+
+       dev->i2c_client.addr = 0x82 >> 1;
+
+       for (i = 0; i < ARRAY_SIZE(regs); i++)
+               i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+       em28xx_gpio_set(dev, hauppauge_hvr930c_end);
+
+       msleep(100);
+
+       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
+       msleep(30);
+
+       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45);
+       msleep(10);
+
+}
+
 static void terratec_h5_init(struct em28xx *dev)
 {
        int i;
@@ -425,13 +503,6 @@ static struct tda10023_config em28xx_tda10023_config = {
 static struct cxd2820r_config em28xx_cxd2820r_config = {
        .i2c_address = (0xd8 >> 1),
        .ts_mode = CXD2820R_TS_SERIAL,
-       .if_dvbt_6  = 3300,
-       .if_dvbt_7  = 3500,
-       .if_dvbt_8  = 4000,
-       .if_dvbt2_6 = 3300,
-       .if_dvbt2_7 = 3500,
-       .if_dvbt2_8 = 4000,
-       .if_dvbc    = 5000,
 
        /* enable LNA for DVB-T2 and DVB-C */
        .gpio_dvbt2[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
@@ -456,6 +527,17 @@ static const struct a8293_config em28xx_a8293_config = {
        .i2c_addr = 0x08, /* (0x10 >> 1) */
 };
 
+static struct zl10353_config em28xx_zl10353_no_i2c_gate_dev = {
+       .demod_address = (0x1e >> 1),
+       .disable_i2c_gate_ctrl = 1,
+       .no_tuner = 1,
+       .parallel_ts = 1,
+};
+static struct qt1010_config em28xx_qt1010_config = {
+       .i2c_address = 0x62
+
+};
+
 /* ------------------------------------------------------------------ */
 
 static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
@@ -708,6 +790,14 @@ static int em28xx_dvb_init(struct em28xx *dev)
                        goto out_free;
                }
                break;
+       case EM2870_BOARD_KWORLD_355U:
+               dvb->fe[0] = dvb_attach(zl10353_attach,
+                                          &em28xx_zl10353_no_i2c_gate_dev,
+                                          &dev->i2c_adap);
+               if (dvb->fe[0] != NULL)
+                       dvb_attach(qt1010_attach, dvb->fe[0],
+                                  &dev->i2c_adap, &em28xx_qt1010_config);
+               break;
        case EM2883_BOARD_KWORLD_HYBRID_330U:
        case EM2882_BOARD_EVGA_INDTUBE:
                dvb->fe[0] = dvb_attach(s5h1409_attach,
@@ -761,50 +851,72 @@ static int em28xx_dvb_init(struct em28xx *dev)
                                   &dev->i2c_adap, &kworld_a340_config);
                break;
        case EM28174_BOARD_PCTV_290E:
-               /* MFE
-                * FE 0 = DVB-T/T2 + FE 1 = DVB-C, both sharing same tuner. */
-               /* FE 0 */
                dvb->fe[0] = dvb_attach(cxd2820r_attach,
-                       &em28xx_cxd2820r_config, &dev->i2c_adap, NULL);
+                                       &em28xx_cxd2820r_config,
+                                       &dev->i2c_adap,
+                                       NULL);
                if (dvb->fe[0]) {
                        /* FE 0 attach tuner */
-                       if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
-                               &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) {
+                       if (!dvb_attach(tda18271_attach,
+                                       dvb->fe[0],
+                                       0x60,
+                                       &dev->i2c_adap,
+                                       &em28xx_cxd2820r_tda18271_config)) {
+
                                dvb_frontend_detach(dvb->fe[0]);
                                result = -EINVAL;
                                goto out_free;
                        }
-                       /* FE 1. This dvb_attach() cannot fail. */
-                       dvb->fe[1] = dvb_attach(cxd2820r_attach, NULL, NULL,
-                               dvb->fe[0]);
-                       dvb->fe[1]->id = 1;
-                       /* FE 1 attach tuner */
-                       if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60,
-                               &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) {
-                               dvb_frontend_detach(dvb->fe[1]);
-                               /* leave FE 0 still active */
-                       }
+               }
+               break;
+       case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C:
+       {
+               struct xc5000_config cfg;
+               hauppauge_hvr930c_init(dev);
+
+               dvb->fe[0] = dvb_attach(drxk_attach,
+                                       &hauppauge_930c_drxk, &dev->i2c_adap);
+               if (!dvb->fe[0]) {
+                       result = -EINVAL;
+                       goto out_free;
+               }
+               /* FIXME: do we need a pll semaphore? */
+               dvb->fe[0]->sec_priv = dvb;
+               sema_init(&dvb->pll_mutex, 1);
+               dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
+               dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
 
-                       mfe_shared = 1;
+               /* Attach xc5000 */
+               memset(&cfg, 0, sizeof(cfg));
+               cfg.i2c_address  = 0x61;
+               cfg.if_khz = 4000;
+
+               if (dvb->fe[0]->ops.i2c_gate_ctrl)
+                       dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
+               if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap,
+                               &cfg)) {
+                       result = -EINVAL;
+                       goto out_free;
                }
+               if (dvb->fe[0]->ops.i2c_gate_ctrl)
+                       dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
+
                break;
+       }
        case EM2884_BOARD_TERRATEC_H5:
+       case EM2884_BOARD_CINERGY_HTC_STICK:
                terratec_h5_init(dev);
 
-               dvb->dont_attach_fe1 = 1;
-
-               dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap, &dvb->fe[1]);
+               dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap);
                if (!dvb->fe[0]) {
                        result = -EINVAL;
                        goto out_free;
                }
-
                /* FIXME: do we need a pll semaphore? */
                dvb->fe[0]->sec_priv = dvb;
                sema_init(&dvb->pll_mutex, 1);
                dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
                dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
-               dvb->fe[1]->id = 1;
 
                /* Attach tda18271 to DVB-C frontend */
                if (dvb->fe[0]->ops.i2c_gate_ctrl)
@@ -816,12 +928,6 @@ static int em28xx_dvb_init(struct em28xx *dev)
                if (dvb->fe[0]->ops.i2c_gate_ctrl)
                        dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
 
-               /* Hack - needed by drxk/tda18271c2dd */
-               dvb->fe[1]->tuner_priv = dvb->fe[0]->tuner_priv;
-               memcpy(&dvb->fe[1]->ops.tuner_ops,
-                      &dvb->fe[0]->ops.tuner_ops,
-                      sizeof(dvb->fe[0]->ops.tuner_ops));
-
                break;
        case EM28174_BOARD_PCTV_460E:
                /* attach demod */
@@ -845,6 +951,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
        }
        /* define general-purpose callback pointer */
        dvb->fe[0]->callback = em28xx_tuner_callback;
+       if (dvb->fe[1])
+               dvb->fe[1]->callback = em28xx_tuner_callback;
 
        /* register everything */
        result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
index 679da480428113ec8d7da347e722bf36bde6e590..2630b265b0e813c5c6f450927367d3899933c013 100644 (file)
@@ -306,7 +306,8 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
                                   poll_result.rc_data[0],
                                   poll_result.toggle_bit);
 
-               if (ir->dev->chip_id == CHIP_ID_EM2874)
+               if (ir->dev->chip_id == CHIP_ID_EM2874 ||
+                   ir->dev->chip_id == CHIP_ID_EM2884)
                        /* The em2874 clears the readcount field every time the
                           register is read.  The em2860/2880 datasheet says that it
                           is supposed to clear the readcount, but it doesn't.  So with
@@ -371,13 +372,15 @@ int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
        case CHIP_ID_EM2883:
                ir->get_key = default_polling_getkey;
                break;
+       case CHIP_ID_EM2884:
        case CHIP_ID_EM2874:
        case CHIP_ID_EM28174:
                ir->get_key = em2874_polling_getkey;
                em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1);
                break;
        default:
-               printk("Unrecognized em28xx chip id: IR not supported\n");
+               printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n",
+                       dev->chip_id);
                rc = -EINVAL;
        }
 
index 66f792361b97dee12d7b91c9839c12f71600f8a2..2f626850572643a18e6f5c79d41468f893fade2e 100644 (file)
 #define EM_GPO_2   (1 << 2)
 #define EM_GPO_3   (1 << 3)
 
+/* em28xx endpoints */
+#define EM28XX_EP_ANALOG       0x82
+#define EM28XX_EP_AUDIO                0x83
+#define EM28XX_EP_DIGITAL      0x84
+
 /* em2800 registers */
 #define EM2800_R08_AUDIOSRC 0x08
 
index 9b4557a2f6d02858cb0c6a29a4295fac966cd317..613300b51a9e82012f17c664ad7ae2d90ca70a03 100644 (file)
@@ -1070,6 +1070,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                /* the em2800 can only scale down to 50% */
                height = height > (3 * maxh / 4) ? maxh : maxh / 2;
                width = width > (3 * maxw / 4) ? maxw : maxw / 2;
+                /* MaxPacketSize for em2800 is too small to capture at full resolution
+                 * use half of maxw as the scaler can only scale to 50% */
+               if (width == maxw && height == maxh)
+                       width /= 2;
        } else {
                /* width must even because of the YUYV format
                   height must be even because of interlacing */
@@ -2503,6 +2507,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 {
       u8 val;
        int ret;
+       unsigned int maxw;
 
        printk(KERN_INFO "%s: v4l2 driver version %s\n",
                dev->name, EM28XX_VERSION);
@@ -2515,8 +2520,15 @@ int em28xx_register_analog_devices(struct em28xx *dev)
 
        /* Analog specific initialization */
        dev->format = &format[0];
+
+       maxw = norm_maxw(dev);
+        /* MaxPacketSize for em2800 is too small to capture at full resolution
+         * use half of maxw as the scaler can only scale to 50% */
+        if (dev->board.is_em2800)
+            maxw /= 2;
+
        em28xx_set_video_format(dev, format[0].fourcc,
-                               norm_maxw(dev), norm_maxh(dev));
+                               maxw, norm_maxh(dev));
 
        video_mux(dev, dev->ctl_input);
 
index 2a2cb7ed0014fcda319a31c60066c3ebbfa12f9f..22e252bcc41e2fffc0ad5ef9bcd08fca24b82175 100644 (file)
@@ -38,6 +38,7 @@
 #include <media/videobuf-dvb.h>
 #endif
 #include "tuner-xc2028.h"
+#include "xc5000.h"
 #include "em28xx-reg.h"
 
 /* Boards supported by driver */
 #define EM28174_BOARD_PCTV_290E                   78
 #define EM2884_BOARD_TERRATEC_H5                 79
 #define EM28174_BOARD_PCTV_460E                   80
+#define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C    81
+#define EM2884_BOARD_CINERGY_HTC_STICK           82
+#define EM2860_BOARD_HT_VIDBOX_NW03              83
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -594,6 +598,8 @@ struct em28xx {
        int max_pkt_size;       /* max packet size of isoc transaction */
        int num_alt;            /* Number of alternative settings */
        unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
+       int dvb_alt;                            /* alternate for DVB */
+       unsigned int dvb_max_pkt_size;          /* wMaxPacketSize for DVB */
        struct urb *urb[EM28XX_NUM_BUFS];       /* urb for isoc transfers */
        char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc
                                                   transfer */
@@ -825,7 +831,7 @@ static inline unsigned int norm_maxw(struct em28xx *dev)
        if (dev->board.is_webcam)
                return dev->sensor_xres;
 
-       if (dev->board.max_range_640_480 || dev->board.is_em2800)
+       if (dev->board.max_range_640_480)
                return 640;
 
        return 720;
index 40f214ab924f718f68146dbf150ff119cb40c2ca..5539f09440ac7eae5ae1ce8c67ef9509b85ef73b 100644 (file)
@@ -76,8 +76,8 @@ MODULE_PARM_DESC(video_nr,
                 "\none and for every other camera."
                 "\n");
 
-static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] =
-                              ET61X251_FORCE_MUNMAP};
+static bool force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] =
+                             ET61X251_FORCE_MUNMAP};
 module_param_array(force_munmap, bool, NULL, 0444);
 MODULE_PARM_DESC(force_munmap,
                 "\n<0|1[,...]> Force the application to unmap previously"
index 27cb197d0bd6e911696750e988a85e5af0a5994f..27e3e0c0b219138a689909203d9ebf3fa354ea12 100644 (file)
@@ -1661,18 +1661,7 @@ static struct platform_driver viu_of_platform_driver = {
        },
 };
 
-static int __init viu_init(void)
-{
-       return platform_driver_register(&viu_of_platform_driver);
-}
-
-static void __exit viu_exit(void)
-{
-       platform_driver_unregister(&viu_of_platform_driver);
-}
-
-module_init(viu_init);
-module_exit(viu_exit);
+module_platform_driver(viu_of_platform_driver);
 
 MODULE_DESCRIPTION("Freescale Video-In(VIU)");
 MODULE_AUTHOR("Hongjun Chen");
index 103af3fe5aa07b8aabd5cbd1acb3c8fa08ca6c82..dfe268bfa4f8f55a1e18139515546cd45365eb93 100644 (file)
@@ -77,6 +77,16 @@ config USB_GSPCA_JEILINJ
          To compile this driver as a module, choose M here: the
          module will be called gspca_jeilinj.
 
+config USB_GSPCA_JL2005BCD
+       tristate "JL2005B/C/D USB V4L2 driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for cameras based the
+         JL2005B, JL2005C, or JL2005D chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_jl2005bcd.
+
 config USB_GSPCA_KINECT
        tristate "Kinect sensor device USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
index f345f494d0f3121e16302ee20d61daea8d813deb..79ebe46e1ad792b80d3a013aa9efba786ea82d9f 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_USB_GSPCA_CPIA1)    += gspca_cpia1.o
 obj-$(CONFIG_USB_GSPCA_ETOMS)    += gspca_etoms.o
 obj-$(CONFIG_USB_GSPCA_FINEPIX)  += gspca_finepix.o
 obj-$(CONFIG_USB_GSPCA_JEILINJ)  += gspca_jeilinj.o
+obj-$(CONFIG_USB_GSPCA_JL2005BCD) += gspca_jl2005bcd.o
 obj-$(CONFIG_USB_GSPCA_KINECT)   += gspca_kinect.o
 obj-$(CONFIG_USB_GSPCA_KONICA)   += gspca_konica.o
 obj-$(CONFIG_USB_GSPCA_MARS)     += gspca_mars.o
@@ -49,6 +50,7 @@ gspca_cpia1-objs    := cpia1.o
 gspca_etoms-objs    := etoms.o
 gspca_finepix-objs  := finepix.o
 gspca_jeilinj-objs  := jeilinj.o
+gspca_jl2005bcd-objs  := jl2005bcd.o
 gspca_kinect-objs   := kinect.o
 gspca_konica-objs   := konica.o
 gspca_mars-objs     := mars.o
index 636627b57dc933ff447c1f2485ae031e173bdb74..9769f17915c0546c41391025addcaa942b12a68d 100644 (file)
@@ -76,7 +76,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        gspca_dev->cam.cam_mode = vga_mode;
        gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
        gspca_dev->cam.no_urb_create = 1;
-       gspca_dev->cam.reverse_alts = 1;
        return 0;
 }
 
@@ -135,13 +134,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
+       struct usb_interface *intf;
+
        reg_w(gspca_dev, 0x003c, 0x0003);
        reg_w(gspca_dev, 0x003c, 0x0004);
        reg_w(gspca_dev, 0x003c, 0x0005);
        reg_w(gspca_dev, 0x003c, 0x0006);
        reg_w(gspca_dev, 0x003c, 0x0007);
+
+       intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
        usb_set_interface(gspca_dev->dev, gspca_dev->iface,
-                                       gspca_dev->nbalt - 1);
+                                       intf->num_altsetting - 1);
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
index a8f54c20e58550d0426b5a712b9d10ff1c0f38b5..c84e26006fc386afef472a7a09fa52e4a6b572d5 100644 (file)
@@ -337,7 +337,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
                return -1;
 
        cam = &gspca_dev->cam;
-       gspca_dev->nbalt = 4;
 
        switch (sd->sensor) {
        case ID_MI1320:
index 2ca10dfec91fd2347532d35e22ea44fd4ee01298..ca5a2b139d0b739f8d5aa149785d95c60d674a4a 100644 (file)
@@ -633,23 +633,32 @@ static u32 which_bandwidth(struct gspca_dev *gspca_dev)
        u32 bandwidth;
        int i;
 
+       /* get the (max) image size */
        i = gspca_dev->curr_mode;
        bandwidth = gspca_dev->cam.cam_mode[i].sizeimage;
 
-       /* if the image is compressed, estimate the mean image size */
-       if (bandwidth < gspca_dev->cam.cam_mode[i].width *
+       /* if the image is compressed, estimate its mean size */
+       if (!gspca_dev->cam.needs_full_bandwidth &&
+           bandwidth < gspca_dev->cam.cam_mode[i].width *
                                gspca_dev->cam.cam_mode[i].height)
-               bandwidth /= 3;
+               bandwidth = bandwidth * 3 / 8;  /* 0.375 */
 
        /* estimate the frame rate */
        if (gspca_dev->sd_desc->get_streamparm) {
                struct v4l2_streamparm parm;
 
-               parm.parm.capture.timeperframe.denominator = 15;
                gspca_dev->sd_desc->get_streamparm(gspca_dev, &parm);
                bandwidth *= parm.parm.capture.timeperframe.denominator;
+               bandwidth /= parm.parm.capture.timeperframe.numerator;
        } else {
-               bandwidth *= 15;                /* 15 fps */
+
+               /* don't hope more than 15 fps with USB 1.1 and
+                * image resolution >= 640x480 */
+               if (gspca_dev->width >= 640
+                && gspca_dev->dev->speed == USB_SPEED_FULL)
+                       bandwidth *= 15;                /* 15 fps */
+               else
+                       bandwidth *= 30;                /* 30 fps */
        }
 
        PDEBUG(D_STREAM, "min bandwidth: %d", bandwidth);
@@ -667,9 +676,8 @@ struct ep_tb_s {
  * build the table of the endpoints
  * and compute the minimum bandwidth for the image transfer
  */
-static int build_ep_tb(struct gspca_dev *gspca_dev,
+static int build_isoc_ep_tb(struct gspca_dev *gspca_dev,
                        struct usb_interface *intf,
-                       int xfer,
                        struct ep_tb_s *ep_tb)
 {
        struct usb_host_endpoint *ep;
@@ -687,17 +695,21 @@ static int build_ep_tb(struct gspca_dev *gspca_dev,
                ep_tb->bandwidth = 2000 * 2000 * 120;
                found = 0;
                for (j = 0; j < nbalt; j++) {
-                       ep = alt_xfer(&intf->altsetting[j], xfer);
+                       ep = alt_xfer(&intf->altsetting[j],
+                                     USB_ENDPOINT_XFER_ISOC);
                        if (ep == NULL)
                                continue;
+                       if (ep->desc.bInterval == 0) {
+                               pr_err("alt %d iso endp with 0 interval\n", j);
+                               continue;
+                       }
                        psize = le16_to_cpu(ep->desc.wMaxPacketSize);
-                       if (!gspca_dev->cam.bulk)               /* isoc */
-                               psize = (psize & 0x07ff) *
-                                               (1 + ((psize >> 11) & 3));
-                       bandwidth = psize * ep->desc.bInterval * 1000;
+                       psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+                       bandwidth = psize * 1000;
                        if (gspca_dev->dev->speed == USB_SPEED_HIGH
                         || gspca_dev->dev->speed == USB_SPEED_SUPER)
                                bandwidth *= 8;
+                       bandwidth /= 1 << (ep->desc.bInterval - 1);
                        if (bandwidth <= last_bw)
                                continue;
                        if (bandwidth < ep_tb->bandwidth) {
@@ -715,6 +727,23 @@ static int build_ep_tb(struct gspca_dev *gspca_dev,
                ep_tb++;
        }
 
+       /*
+        * If the camera:
+        * has a usb audio class interface (a built in usb mic); and
+        * is a usb 1 full speed device; and
+        * uses the max full speed iso bandwidth; and
+        * and has more than 1 alt setting
+        * then skip the highest alt setting to spare bandwidth for the mic
+        */
+       if (gspca_dev->audio &&
+                       gspca_dev->dev->speed == USB_SPEED_FULL &&
+                       last_bw >= 1000000 &&
+                       i > 1) {
+               PDEBUG(D_STREAM, "dev has usb audio, skipping highest alt");
+               i--;
+               ep_tb--;
+       }
+
        /* get the requested bandwidth and start at the highest atlsetting */
        bandwidth = which_bandwidth(gspca_dev);
        ep_tb--;
@@ -790,10 +819,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
                                                    ep->desc.bEndpointAddress);
                        urb->transfer_flags = URB_ISO_ASAP
                                        | URB_NO_TRANSFER_DMA_MAP;
-                       if (gspca_dev->dev->speed == USB_SPEED_LOW)
-                               urb->interval = ep->desc.bInterval;
-                       else
-                               urb->interval = 1 << (ep->desc.bInterval - 1);
+                       urb->interval = 1 << (ep->desc.bInterval - 1);
                        urb->complete = isoc_irq;
                        urb->number_of_packets = npkt;
                        for (i = 0; i < npkt; i++) {
@@ -848,7 +874,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
        xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
                                   : USB_ENDPOINT_XFER_ISOC;
 
-       /* if the subdriver forced an altsetting, get the endpoint */
+       /* if bulk or the subdriver forced an altsetting, get the endpoint */
        if (gspca_dev->alt != 0) {
                gspca_dev->alt--;       /* (previous version compatibility) */
                ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer);
@@ -863,7 +889,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
 
        /* else, compute the minimum bandwidth
         * and build the endpoint table */
-               alt_idx = build_ep_tb(gspca_dev, intf, xfer, ep_tb);
+               alt_idx = build_isoc_ep_tb(gspca_dev, intf, ep_tb);
                if (alt_idx <= 0) {
                        pr_err("no transfer endpoint found\n");
                        ret = -EIO;
@@ -880,7 +906,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
        for (;;) {
                if (alt != gspca_dev->alt) {
                        alt = gspca_dev->alt;
-                       if (gspca_dev->nbalt > 1) {
+                       if (intf->num_altsetting > 1) {
                                ret = usb_set_interface(gspca_dev->dev,
                                                        gspca_dev->iface,
                                                        alt);
@@ -2300,15 +2326,14 @@ int gspca_dev_probe2(struct usb_interface *intf,
        }
        gspca_dev->dev = dev;
        gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber;
-       gspca_dev->nbalt = intf->num_altsetting;
 
        /* check if any audio device */
-       if (dev->config->desc.bNumInterfaces != 1) {
+       if (dev->actconfig->desc.bNumInterfaces != 1) {
                int i;
                struct usb_interface *intf2;
 
-               for (i = 0; i < dev->config->desc.bNumInterfaces; i++) {
-                       intf2 = dev->config->interface[i];
+               for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
+                       intf2 = dev->actconfig->interface[i];
                        if (intf2 != NULL
                         && intf2->altsetting != NULL
                         && intf2->altsetting->desc.bInterfaceClass ==
@@ -2389,7 +2414,7 @@ int gspca_dev_probe(struct usb_interface *intf,
        }
 
        /* the USB video interface must be the first one */
-       if (dev->config->desc.bNumInterfaces != 1
+       if (dev->actconfig->desc.bNumInterfaces != 1
         && intf->cur_altsetting->desc.bInterfaceNumber != 0)
                return -ENODEV;
 
index e444f16e14971c97d02d63e13d74fe57c4fc32ee..589009f4496fcfc2599bed9709f214cc082780f3 100644 (file)
@@ -69,7 +69,9 @@ struct cam {
        u8 bulk;                /* image transfer by 0:isoc / 1:bulk */
        u8 npkt;                /* number of packets in an ISOC message
                                 * 0 is the default value: 32 packets */
-       u8 reverse_alts;        /* Alt settings are in high to low order */
+       u8 needs_full_bandwidth;/* Set this flag to notify the bandwidth calc.
+                                * code that the cam fills all image buffers to
+                                * the max, even when using compression. */
 };
 
 struct gspca_dev;
@@ -208,7 +210,6 @@ struct gspca_dev {
        char memory;                    /* memory type (V4L2_MEMORY_xxx) */
        __u8 iface;                     /* USB interface number */
        __u8 alt;                       /* USB alternate setting */
-       __u8 nbalt;                     /* number of USB alternate settings */
        u8 audio;                       /* presence of audio device */
 };
 
diff --git a/drivers/media/video/gspca/jl2005bcd.c b/drivers/media/video/gspca/jl2005bcd.c
new file mode 100644 (file)
index 0000000..53f58ef
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+ * Jeilin JL2005B/C/D library
+ *
+ * Copyright (C) 2011 Theodore Kilgore <kilgota@auburn.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; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define MODULE_NAME "jl2005bcd"
+
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include "gspca.h"
+
+
+MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
+MODULE_DESCRIPTION("JL2005B/C/D USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeouts, in ms */
+#define JL2005C_CMD_TIMEOUT 500
+#define JL2005C_DATA_TIMEOUT 1000
+
+/* Maximum transfer size to use. */
+#define JL2005C_MAX_TRANSFER 0x200
+#define FRAME_HEADER_LEN 16
+
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;  /* !! must be the first item */
+       unsigned char firmware_id[6];
+       const struct v4l2_pix_format *cap_mode;
+       /* Driver stuff */
+       struct work_struct work_struct;
+       struct workqueue_struct *work_thread;
+       u8 frame_brightness;
+       int block_size; /* block size of camera */
+       int vga;        /* 1 if vga cam, 0 if cif cam */
+};
+
+
+/* Camera has two resolution settings. What they are depends on model. */
+static const struct v4l2_pix_format cif_mode[] = {
+       {176, 144, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
+               .bytesperline = 176,
+               .sizeimage = 176 * 144,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
+       {352, 288, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
+               .bytesperline = 352,
+               .sizeimage = 352 * 288,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+       {320, 240, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
+       {640, 480, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0},
+};
+
+/*
+ * cam uses endpoint 0x03 to send commands, 0x84 for read commands,
+ * and 0x82 for bulk data transfer.
+ */
+
+/* All commands are two bytes only */
+static int jl2005c_write2(struct gspca_dev *gspca_dev, unsigned char *command)
+{
+       int retval;
+
+       memcpy(gspca_dev->usb_buf, command, 2);
+       retval = usb_bulk_msg(gspca_dev->dev,
+                       usb_sndbulkpipe(gspca_dev->dev, 3),
+                       gspca_dev->usb_buf, 2, NULL, 500);
+       if (retval < 0)
+               pr_err("command write [%02x] error %d\n",
+                      gspca_dev->usb_buf[0], retval);
+       return retval;
+}
+
+/* Response to a command is one byte in usb_buf[0], only if requested. */
+static int jl2005c_read1(struct gspca_dev *gspca_dev)
+{
+       int retval;
+
+       retval = usb_bulk_msg(gspca_dev->dev,
+                               usb_rcvbulkpipe(gspca_dev->dev, 0x84),
+                               gspca_dev->usb_buf, 1, NULL, 500);
+       if (retval < 0)
+               pr_err("read command [0x%02x] error %d\n",
+                      gspca_dev->usb_buf[0], retval);
+       return retval;
+}
+
+/* Response appears in gspca_dev->usb_buf[0] */
+static int jl2005c_read_reg(struct gspca_dev *gspca_dev, unsigned char reg)
+{
+       int retval;
+
+       static u8 instruction[2] = {0x95, 0x00};
+       /* put register to read in byte 1 */
+       instruction[1] = reg;
+       /* Send the read request */
+       retval = jl2005c_write2(gspca_dev, instruction);
+       if (retval < 0)
+               return retval;
+       retval = jl2005c_read1(gspca_dev);
+
+       return retval;
+}
+
+static int jl2005c_start_new_frame(struct gspca_dev *gspca_dev)
+{
+       int i;
+       int retval;
+       int frame_brightness = 0;
+
+       static u8 instruction[2] = {0x7f, 0x01};
+
+       retval = jl2005c_write2(gspca_dev, instruction);
+       if (retval < 0)
+               return retval;
+
+       i = 0;
+       while (i < 20 && !frame_brightness) {
+               /* If we tried 20 times, give up. */
+               retval = jl2005c_read_reg(gspca_dev, 0x7e);
+               if (retval < 0)
+                       return retval;
+               frame_brightness = gspca_dev->usb_buf[0];
+               retval = jl2005c_read_reg(gspca_dev, 0x7d);
+               if (retval < 0)
+                       return retval;
+               i++;
+       }
+       PDEBUG(D_FRAM, "frame_brightness is 0x%02x", gspca_dev->usb_buf[0]);
+       return retval;
+}
+
+static int jl2005c_write_reg(struct gspca_dev *gspca_dev, unsigned char reg,
+                                                   unsigned char value)
+{
+       int retval;
+       u8 instruction[2];
+
+       instruction[0] = reg;
+       instruction[1] = value;
+
+       retval = jl2005c_write2(gspca_dev, instruction);
+       if (retval < 0)
+                       return retval;
+
+       return retval;
+}
+
+static int jl2005c_get_firmware_id(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+       int i = 0;
+       int retval = -1;
+       unsigned char regs_to_read[] = {0x57, 0x02, 0x03, 0x5d, 0x5e, 0x5f};
+
+       PDEBUG(D_PROBE, "Running jl2005c_get_firmware_id");
+       /* Read the first ID byte once for warmup */
+       retval = jl2005c_read_reg(gspca_dev, regs_to_read[0]);
+       PDEBUG(D_PROBE, "response is %02x", gspca_dev->usb_buf[0]);
+       if (retval < 0)
+               return retval;
+       /* Now actually get the ID string */
+       for (i = 0; i < 6; i++) {
+               retval = jl2005c_read_reg(gspca_dev, regs_to_read[i]);
+               if (retval < 0)
+                       return retval;
+               sd->firmware_id[i] = gspca_dev->usb_buf[0];
+       }
+       PDEBUG(D_PROBE, "firmware ID is %02x%02x%02x%02x%02x%02x",
+                                               sd->firmware_id[0],
+                                               sd->firmware_id[1],
+                                               sd->firmware_id[2],
+                                               sd->firmware_id[3],
+                                               sd->firmware_id[4],
+                                               sd->firmware_id[5]);
+       return 0;
+}
+
+static int jl2005c_stream_start_vga_lg
+                   (struct gspca_dev *gspca_dev)
+{
+       int i;
+       int retval = -1;
+       static u8 instruction[][2] = {
+               {0x05, 0x00},
+               {0x7c, 0x00},
+               {0x7d, 0x18},
+               {0x02, 0x00},
+               {0x01, 0x00},
+               {0x04, 0x52},
+       };
+
+       for (i = 0; i < ARRAY_SIZE(instruction); i++) {
+               msleep(60);
+               retval = jl2005c_write2(gspca_dev, instruction[i]);
+               if (retval < 0)
+                       return retval;
+       }
+       msleep(60);
+       return retval;
+}
+
+static int jl2005c_stream_start_vga_small(struct gspca_dev *gspca_dev)
+{
+       int i;
+       int retval = -1;
+       static u8 instruction[][2] = {
+               {0x06, 0x00},
+               {0x7c, 0x00},
+               {0x7d, 0x1a},
+               {0x02, 0x00},
+               {0x01, 0x00},
+               {0x04, 0x52},
+       };
+
+       for (i = 0; i < ARRAY_SIZE(instruction); i++) {
+               msleep(60);
+               retval = jl2005c_write2(gspca_dev, instruction[i]);
+               if (retval < 0)
+                       return retval;
+       }
+       msleep(60);
+       return retval;
+}
+
+static int jl2005c_stream_start_cif_lg(struct gspca_dev *gspca_dev)
+{
+       int i;
+       int retval = -1;
+       static u8 instruction[][2] = {
+               {0x05, 0x00},
+               {0x7c, 0x00},
+               {0x7d, 0x30},
+               {0x02, 0x00},
+               {0x01, 0x00},
+               {0x04, 0x42},
+       };
+
+       for (i = 0; i < ARRAY_SIZE(instruction); i++) {
+               msleep(60);
+               retval = jl2005c_write2(gspca_dev, instruction[i]);
+               if (retval < 0)
+                       return retval;
+       }
+       msleep(60);
+       return retval;
+}
+
+static int jl2005c_stream_start_cif_small(struct gspca_dev *gspca_dev)
+{
+       int i;
+       int retval = -1;
+       static u8 instruction[][2] = {
+               {0x06, 0x00},
+               {0x7c, 0x00},
+               {0x7d, 0x32},
+               {0x02, 0x00},
+               {0x01, 0x00},
+               {0x04, 0x42},
+       };
+
+       for (i = 0; i < ARRAY_SIZE(instruction); i++) {
+               msleep(60);
+               retval = jl2005c_write2(gspca_dev, instruction[i]);
+               if (retval < 0)
+                       return retval;
+       }
+       msleep(60);
+       return retval;
+}
+
+
+static int jl2005c_stop(struct gspca_dev *gspca_dev)
+{
+       int retval;
+
+       retval = jl2005c_write_reg(gspca_dev, 0x07, 0x00);
+       return retval;
+}
+
+/* This function is called as a workqueue function and runs whenever the camera
+ * is streaming data. Because it is a workqueue function it is allowed to sleep
+ * so we can use synchronous USB calls. To avoid possible collisions with other
+ * threads attempting to use the camera's USB interface the gspca usb_lock is
+ * used when performing the one USB control operation inside the workqueue,
+ * which tells the camera to close the stream. In practice the only thing
+ * which needs to be protected against is the usb_set_interface call that
+ * gspca makes during stream_off. Otherwise the camera doesn't provide any
+ * controls that the user could try to change.
+ */
+static void jl2005c_dostream(struct work_struct *work)
+{
+       struct sd *dev = container_of(work, struct sd, work_struct);
+       struct gspca_dev *gspca_dev = &dev->gspca_dev;
+       int bytes_left = 0; /* bytes remaining in current frame. */
+       int data_len;   /* size to use for the next read. */
+       int header_read = 0;
+       unsigned char header_sig[2] = {0x4a, 0x4c};
+       int act_len;
+       int packet_type;
+       int ret;
+       u8 *buffer;
+
+       buffer = kmalloc(JL2005C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
+       if (!buffer) {
+               pr_err("Couldn't allocate USB buffer\n");
+               goto quit_stream;
+       }
+
+       while (gspca_dev->present && gspca_dev->streaming) {
+               /* Check if this is a new frame. If so, start the frame first */
+               if (!header_read) {
+                       mutex_lock(&gspca_dev->usb_lock);
+                       ret = jl2005c_start_new_frame(gspca_dev);
+                       mutex_unlock(&gspca_dev->usb_lock);
+                       if (ret < 0)
+                               goto quit_stream;
+                       ret = usb_bulk_msg(gspca_dev->dev,
+                               usb_rcvbulkpipe(gspca_dev->dev, 0x82),
+                               buffer, JL2005C_MAX_TRANSFER, &act_len,
+                               JL2005C_DATA_TIMEOUT);
+                       PDEBUG(D_PACK,
+                               "Got %d bytes out of %d for header",
+                                       act_len, JL2005C_MAX_TRANSFER);
+                       if (ret < 0 || act_len < JL2005C_MAX_TRANSFER)
+                               goto quit_stream;
+                       /* Check whether we actually got the first blodk */
+                       if (memcmp(header_sig, buffer, 2) != 0) {
+                               pr_err("First block is not the first block\n");
+                               goto quit_stream;
+                       }
+                       /* total size to fetch is byte 7, times blocksize
+                        * of which we already got act_len */
+                       bytes_left = buffer[0x07] * dev->block_size - act_len;
+                       PDEBUG(D_PACK, "bytes_left = 0x%x", bytes_left);
+                       /* We keep the header. It has other information, too.*/
+                       packet_type = FIRST_PACKET;
+                       gspca_frame_add(gspca_dev, packet_type,
+                                       buffer, act_len);
+                       header_read = 1;
+               }
+               while (bytes_left > 0 && gspca_dev->present) {
+                       data_len = bytes_left > JL2005C_MAX_TRANSFER ?
+                               JL2005C_MAX_TRANSFER : bytes_left;
+                       ret = usb_bulk_msg(gspca_dev->dev,
+                               usb_rcvbulkpipe(gspca_dev->dev, 0x82),
+                               buffer, data_len, &act_len,
+                               JL2005C_DATA_TIMEOUT);
+                       if (ret < 0 || act_len < data_len)
+                               goto quit_stream;
+                       PDEBUG(D_PACK,
+                               "Got %d bytes out of %d for frame",
+                                               data_len, bytes_left);
+                       bytes_left -= data_len;
+                       if (bytes_left == 0) {
+                               packet_type = LAST_PACKET;
+                               header_read = 0;
+                       } else
+                               packet_type = INTER_PACKET;
+                       gspca_frame_add(gspca_dev, packet_type,
+                                       buffer, data_len);
+               }
+       }
+quit_stream:
+       if (gspca_dev->present) {
+               mutex_lock(&gspca_dev->usb_lock);
+               jl2005c_stop(gspca_dev);
+               mutex_unlock(&gspca_dev->usb_lock);
+       }
+       kfree(buffer);
+}
+
+
+
+
+/* This function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct cam *cam;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       cam = &gspca_dev->cam;
+       /* We don't use the buffer gspca allocates so make it small. */
+       cam->bulk_size = 64;
+       cam->bulk = 1;
+       /* For the rest, the camera needs to be detected */
+       jl2005c_get_firmware_id(gspca_dev);
+       /* Here are some known firmware IDs
+        * First some JL2005B cameras
+        * {0x41, 0x07, 0x04, 0x2c, 0xe8, 0xf2} Sakar KidzCam
+        * {0x45, 0x02, 0x08, 0xb9, 0x00, 0xd2} No-name JL2005B
+        * JL2005C cameras
+        * {0x01, 0x0c, 0x16, 0x10, 0xf8, 0xc8} Argus DC-1512
+        * {0x12, 0x04, 0x03, 0xc0, 0x00, 0xd8} ICarly
+        * {0x86, 0x08, 0x05, 0x02, 0x00, 0xd4} Jazz
+        *
+        * Based upon this scanty evidence, we can detect a CIF camera by
+        * testing byte 0 for 0x4x.
+        */
+       if ((sd->firmware_id[0] & 0xf0) == 0x40) {
+               cam->cam_mode   = cif_mode;
+               cam->nmodes     = ARRAY_SIZE(cif_mode);
+               sd->block_size  = 0x80;
+       } else {
+               cam->cam_mode   = vga_mode;
+               cam->nmodes     = ARRAY_SIZE(vga_mode);
+               sd->block_size  = 0x200;
+       }
+
+       INIT_WORK(&sd->work_struct, jl2005c_dostream);
+
+       return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+
+       struct sd *sd = (struct sd *) gspca_dev;
+       sd->cap_mode = gspca_dev->cam.cam_mode;
+
+       switch (gspca_dev->width) {
+       case 640:
+               PDEBUG(D_STREAM, "Start streaming at vga resolution");
+               jl2005c_stream_start_vga_lg(gspca_dev);
+               break;
+       case 320:
+               PDEBUG(D_STREAM, "Start streaming at qvga resolution");
+               jl2005c_stream_start_vga_small(gspca_dev);
+               break;
+       case 352:
+               PDEBUG(D_STREAM, "Start streaming at cif resolution");
+               jl2005c_stream_start_cif_lg(gspca_dev);
+               break;
+       case 176:
+               PDEBUG(D_STREAM, "Start streaming at qcif resolution");
+               jl2005c_stream_start_cif_small(gspca_dev);
+               break;
+       default:
+               pr_err("Unknown resolution specified\n");
+               return -1;
+       }
+
+       /* Start the workqueue function to do the streaming */
+       sd->work_thread = create_singlethread_workqueue(MODULE_NAME);
+       queue_work(sd->work_thread, &sd->work_struct);
+
+       return 0;
+}
+
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *dev = (struct sd *) gspca_dev;
+
+       /* wait for the work queue to terminate */
+       mutex_unlock(&gspca_dev->usb_lock);
+       /* This waits for sq905c_dostream to finish */
+       destroy_workqueue(dev->work_thread);
+       dev->work_thread = NULL;
+       mutex_lock(&gspca_dev->usb_lock);
+}
+
+
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       /* .ctrls = none have been detected */
+       /* .nctrls = ARRAY_SIZE(sd_ctrls),  */
+       .config = sd_config,
+       .init = sd_init,
+       .start = sd_start,
+       .stop0 = sd_stop0,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x0979, 0x0227)},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                               const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       int ret;
+
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index b1da7f4096c8b31dfb469d9b4bdd513beea7fadc..f0c0d74dfe928b781aeb486b7ea1d19ed27d138f 100644 (file)
@@ -247,9 +247,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        gspca_dev->cam.cam_mode = vga_mode;
        gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
        gspca_dev->cam.no_urb_create = 1;
-       /* The highest alt setting has an isoc packetsize of 0, so we
-          don't want to use it */
-       gspca_dev->nbalt--;
 
        sd->brightness  = BRIGHTNESS_DEFAULT;
        sd->contrast    = CONTRAST_DEFAULT;
index 9fe3816b2aa04f8c1e9b69e2118bd08c908bf8bb..0c4493675438ee1e0cabd3b6bb87a85153713de7 100644 (file)
@@ -27,8 +27,8 @@
 
 /* Kernel module parameters */
 int force_sensor;
-static int dump_bridge;
-int dump_sensor;
+static bool dump_bridge;
+bool dump_sensor;
 
 static const struct usb_device_id m5602_table[] = {
        {USB_DEVICE(0x0402, 0x5602)},
index b1f0c492036abd257379c9a71bc050928076c874..8c672b5c8c6a2797d659c29a0c644c5cced39a40 100644 (file)
 
 /* Kernel module parameters */
 extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
 
 int mt9m111_probe(struct sd *sd);
 int mt9m111_init(struct sd *sd);
index 2efd607987ec2ecaee9339360eec6cecf6d2d445..2b6a13b508f7331518acb30099fa2f885ab426d1 100644 (file)
@@ -86,7 +86,7 @@
 
 /* Kernel module parameters */
 extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
 
 int ov7660_probe(struct sd *sd);
 int ov7660_init(struct sd *sd);
index da9a129b739d2e9cb5b4465e338a8575f79e4b1b..f7aa5bf68983d3d4245b6fc914a433adc9b6d161 100644 (file)
 
 /* Kernel module parameters */
 extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
 
 int ov9650_probe(struct sd *sd);
 int ov9650_init(struct sd *sd);
index 3383595963987c9dc560ae9806132959b3bc154b..81a2bcb88fe3c3ac61e2e3b8d442346d9acc5a32 100644 (file)
 
 /* Kernel module parameters */
 extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
 
 int po1030_probe(struct sd *sd);
 int po1030_init(struct sd *sd);
index 8cc7a3f6da725fbbe4d70dcd7135f90b24ee3a93..8e0035e731c777c95b15b15971b61722e7915090 100644 (file)
@@ -65,7 +65,7 @@
 
 /* Kernel module parameters */
 extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
 
 int s5k4aa_probe(struct sd *sd);
 int s5k4aa_init(struct sd *sd);
index 80a63a236e240e83783b0b7078c91eff6a61ec7c..79952247b534e029569a8d6c8eab4f7afe4590d9 100644 (file)
@@ -41,7 +41,7 @@
 
 /* Kernel module parameters */
 extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
 
 int s5k83a_probe(struct sd *sd);
 int s5k83a_init(struct sd *sd);
index 5c2ea05c46b49783aee1b7647950eca3baf29ac3..b0231465afae8b058702a7f56a78f563f996df8b 100644 (file)
@@ -263,7 +263,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        cam->nmodes = ARRAY_SIZE(vga_mode);
        cam->ctrls = sd->ctrls;
        sd->quality = QUALITY_DEF;
-       gspca_dev->nbalt = 9;           /* use the altsetting 08 */
        return 0;
 }
 
index d4bec9321771a41c49925e64d4844412d3628365..7167cac7359c565730cfd22cb3075be6fc27812b 100644 (file)
@@ -1763,8 +1763,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
        if ((unsigned) webcam >= NWEBCAMS)
                webcam = 0;
        sd->webcam = webcam;
-       gspca_dev->cam.reverse_alts = 1;
        gspca_dev->cam.ctrls = sd->ctrls;
+       gspca_dev->cam.needs_full_bandwidth = 1;
        sd->ag_cnt = -1;
 
        /*
index 08b8ce1dee184a99d388520d4dba27b2afa617c3..739e8a2a2d308ea31268de9f625617d3dce27b0b 100644 (file)
@@ -3348,7 +3348,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        case BRIDGE_W9968CF:
                cam->cam_mode = w9968cf_vga_mode;
                cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode);
-               cam->reverse_alts = 1;
                break;
        }
 
@@ -3684,8 +3683,8 @@ static void ov511_mode_init_regs(struct sd *sd)
        /* Check if we have enough bandwidth to disable compression */
        fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1;
        needed = fps * sd->gspca_dev.width * sd->gspca_dev.height * 3 / 2;
-       /* 1400 is a conservative estimate of the max nr of isoc packets/sec */
-       if (needed > 1400 * packet_size) {
+       /* 1000 isoc packets/sec */
+       if (needed > 1000 * packet_size) {
                /* Enable Y and UV quantization and compression */
                reg_w(sd, R511_COMP_EN, 0x07);
                reg_w(sd, R511_COMP_LUT_EN, 0x03);
index f30060d5063325d8277f7889d8bbb3f9f9716b30..fbfa02affa132908d02feceebac5b06ab44c9292 100644 (file)
@@ -71,6 +71,7 @@ struct sd {
 enum sensors {
        SENSOR_OV965x,          /* ov9657 */
        SENSOR_OV971x,          /* ov9712 */
+       SENSOR_OV562x,          /* ov5621 */
        NSENSORS
 };
 
@@ -207,6 +208,14 @@ static const struct v4l2_pix_format ov971x_mode[] = {
        }
 };
 
+static const struct v4l2_pix_format ov562x_mode[] = {
+       {2592, 1680, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 2592,
+               .sizeimage = 2592 * 1680,
+               .colorspace = V4L2_COLORSPACE_SRGB
+       }
+};
+
 static const u8 bridge_init[][2] = {
        {0x88, 0xf8},
        {0x89, 0xff},
@@ -830,6 +839,124 @@ static const u8 ov965x_start_2_sxga[][2] = {
        {0xa3, 0x41},   /* bd60 */
 };
 
+static const u8 ov562x_init[][2] = {
+       {0x88, 0x20},
+       {0x89, 0x0a},
+       {0x8a, 0x90},
+       {0x8b, 0x06},
+       {0x8c, 0x01},
+       {0x8d, 0x10},
+       {0x1c, 0x00},
+       {0x1d, 0x48},
+       {0x1d, 0x00},
+       {0x1d, 0xff},
+       {0x1c, 0x0a},
+       {0x1d, 0x2e},
+       {0x1d, 0x1e},
+};
+
+static const u8 ov562x_init_2[][2] = {
+       {0x12, 0x80},
+       {0x11, 0x41},
+       {0x13, 0x00},
+       {0x10, 0x1e},
+       {0x3b, 0x07},
+       {0x5b, 0x40},
+       {0x39, 0x07},
+       {0x53, 0x02},
+       {0x54, 0x60},
+       {0x04, 0x20},
+       {0x27, 0x04},
+       {0x3d, 0x40},
+       {0x36, 0x00},
+       {0xc5, 0x04},
+       {0x4e, 0x00},
+       {0x4f, 0x93},
+       {0x50, 0x7b},
+       {0xca, 0x0c},
+       {0xcb, 0x0f},
+       {0x39, 0x07},
+       {0x4a, 0x10},
+       {0x3e, 0x0a},
+       {0x3d, 0x00},
+       {0x0c, 0x38},
+       {0x38, 0x90},
+       {0x46, 0x30},
+       {0x4f, 0x93},
+       {0x50, 0x7b},
+       {0xab, 0x00},
+       {0xca, 0x0c},
+       {0xcb, 0x0f},
+       {0x37, 0x02},
+       {0x44, 0x48},
+       {0x8d, 0x44},
+       {0x2a, 0x00},
+       {0x2b, 0x00},
+       {0x32, 0x00},
+       {0x38, 0x90},
+       {0x53, 0x02},
+       {0x54, 0x60},
+       {0x12, 0x00},
+       {0x17, 0x12},
+       {0x18, 0xb4},
+       {0x19, 0x0c},
+       {0x1a, 0xf4},
+       {0x03, 0x4a},
+       {0x89, 0x20},
+       {0x83, 0x80},
+       {0xb7, 0x9d},
+       {0xb6, 0x11},
+       {0xb5, 0x55},
+       {0xb4, 0x00},
+       {0xa9, 0xf0},
+       {0xa8, 0x0a},
+       {0xb8, 0xf0},
+       {0xb9, 0xf0},
+       {0xba, 0xf0},
+       {0x81, 0x07},
+       {0x63, 0x44},
+       {0x13, 0xc7},
+       {0x14, 0x60},
+       {0x33, 0x75},
+       {0x2c, 0x00},
+       {0x09, 0x00},
+       {0x35, 0x30},
+       {0x27, 0x04},
+       {0x3c, 0x07},
+       {0x3a, 0x0a},
+       {0x3b, 0x07},
+       {0x01, 0x40},
+       {0x02, 0x40},
+       {0x16, 0x40},
+       {0x52, 0xb0},
+       {0x51, 0x83},
+       {0x21, 0xbb},
+       {0x22, 0x10},
+       {0x23, 0x03},
+       {0x35, 0x38},
+       {0x20, 0x90},
+       {0x28, 0x30},
+       {0x73, 0xe1},
+       {0x6c, 0x00},
+       {0x6d, 0x80},
+       {0x6e, 0x00},
+       {0x70, 0x04},
+       {0x71, 0x00},
+       {0x8d, 0x04},
+       {0x64, 0x00},
+       {0x65, 0x00},
+       {0x66, 0x00},
+       {0x67, 0x00},
+       {0x68, 0x00},
+       {0x69, 0x00},
+       {0x6a, 0x00},
+       {0x6b, 0x00},
+       {0x71, 0x94},
+       {0x74, 0x20},
+       {0x80, 0x09},
+       {0x85, 0xc0},
+};
+
 static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val)
 {
        struct usb_device *udev = gspca_dev->dev;
@@ -1210,6 +1337,17 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        reg_w(gspca_dev, 0x56, 0x1f);
                else
                        reg_w(gspca_dev, 0x56, 0x17);
+       } else if ((sensor_id & 0xfff0) == 0x5620) {
+               sd->sensor = SENSOR_OV562x;
+
+               gspca_dev->cam.cam_mode = ov562x_mode;
+               gspca_dev->cam.nmodes = ARRAY_SIZE(ov562x_mode);
+
+               reg_w_array(gspca_dev, ov562x_init,
+                               ARRAY_SIZE(ov562x_init));
+               sccb_w_array(gspca_dev, ov562x_init_2,
+                               ARRAY_SIZE(ov562x_init_2));
+               reg_w(gspca_dev, 0xe0, 0x00);
        } else {
                err("Unknown sensor %04x", sensor_id);
                return -EINVAL;
@@ -1222,7 +1360,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       if (sd->sensor == SENSOR_OV971x)
+       if (sd->sensor == SENSOR_OV971x || sd->sensor == SENSOR_OV562x)
                return gspca_dev->usb_err;
        switch (gspca_dev->curr_mode) {
        case QVGA_MODE:                 /* 320x240 */
@@ -1409,6 +1547,7 @@ static const struct sd_desc sd_desc = {
 static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x05a9, 0x8065)},
        {USB_DEVICE(0x06f8, 0x3003)},
+       {USB_DEVICE(0x05a9, 0x1550)},
        {}
 };
 
index ece8b1e82a13c6f4c8a876cddc3360d92690a27d..3844c49f269c4f06d1059ef65948ebfbdbdb1dc4 100644 (file)
@@ -41,14 +41,14 @@ MODULE_LICENSE("GPL");
 #define PAC207_BRIGHTNESS_DEFAULT      46
 
 #define PAC207_EXPOSURE_MIN            3
-#define PAC207_EXPOSURE_MAX            26
+#define PAC207_EXPOSURE_MAX            90 /* 1 sec expo time / 1 fps */
 #define PAC207_EXPOSURE_DEFAULT                5 /* power on default: 3 */
-#define PAC207_EXPOSURE_KNEE           8 /* 4 = 30 fps, 11 = 8, 15 = 6 */
+#define PAC207_EXPOSURE_KNEE           9 /* fps: 90 / exposure -> 9: 10 fps */
 
 #define PAC207_GAIN_MIN                        0
 #define PAC207_GAIN_MAX                        31
-#define PAC207_GAIN_DEFAULT            9 /* power on default: 9 */
-#define PAC207_GAIN_KNEE               31
+#define PAC207_GAIN_DEFAULT            7 /* power on default: 9 */
+#define PAC207_GAIN_KNEE               15
 
 #define PAC207_AUTOGAIN_DEADZONE       30
 
@@ -332,7 +332,7 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
        if (sd->autogain_ignore_frames > 0)
                sd->autogain_ignore_frames--;
        else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
-                       100, PAC207_AUTOGAIN_DEADZONE,
+                       90, PAC207_AUTOGAIN_DEADZONE,
                        PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
                sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 }
index 2811195258c48f816df23f370c8d264f2b6d232a..9db2b34d172cd9a6cab23bbb37847c3018ac3a90 100644 (file)
@@ -1197,6 +1197,7 @@ static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
        {USB_DEVICE(0x093a, 0x262a)},
        {USB_DEVICE(0x093a, 0x262c)},
+       {USB_DEVICE(0x145f, 0x013c)},
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
index 1494e1829d368a080eb9e6d5ec6fa3ec9606e983..bb70092c2229f3eca85d3795058595a4f981fd9e 100644 (file)
@@ -376,7 +376,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        cam->bulk_size = BULK_SIZE;
        cam->bulk_nurbs = 4;
        cam->ctrls = sd->ctrls;
-       gspca_dev->nbalt = 1;  /* Ignore the bogus isoc alt settings */
        sd->resetlevel = 0x2d; /* Set initial resetlevel */
 
        /* See if the camera supports brightness */
@@ -395,6 +394,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
+/* function called at start time before URB creation */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+       gspca_dev->alt = 1;     /* Ignore the bogus isoc alt settings */
+
+       return gspca_dev->usb_err;
+}
+
 /* -- start the camera -- */
 static int sd_start(struct gspca_dev *gspca_dev)
 {
@@ -714,6 +721,7 @@ static const struct sd_desc sd_desc = {
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
        .init = sd_init,
+       .isoc_init = sd_isoc_init,
        .start = sd_start,
        .stopN = sd_stopN,
        .dq_callback = sd_dq_callback,
index 33cabc342dcfcdf5ce24fa284e38f097eb18f119..9e198b45c3c804e11471ccff215c69471fa825ed 100644 (file)
@@ -2048,6 +2048,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
 
        cam = &gspca_dev->cam;
+       cam->needs_full_bandwidth = 1;
 
        sd->sensor = (id->driver_info >> 8) & 0xff;
        sd->i2c_addr = id->driver_info & 0xff;
@@ -2233,6 +2234,42 @@ static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
        }
 }
 
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+       struct usb_interface *intf;
+       u32 flags = gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv;
+
+       /*
+        * When using the SN9C20X_I420 fmt the sn9c20x needs more bandwidth
+        * than our regular bandwidth calculations reserve, so we force the
+        * use of a specific altsetting when using the SN9C20X_I420 fmt.
+        */
+       if (!(flags & (MODE_RAW | MODE_JPEG))) {
+               intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+
+               if (intf->num_altsetting != 9) {
+                       pr_warn("sn9c20x camera with unknown number of alt "
+                               "settings (%d), please report!\n",
+                               intf->num_altsetting);
+                       gspca_dev->alt = intf->num_altsetting;
+                       return 0;
+               }
+
+               switch (gspca_dev->width) {
+               case 160: /* 160x120 */
+                       gspca_dev->alt = 2;
+                       break;
+               case 320: /* 320x240 */
+                       gspca_dev->alt = 6;
+                       break;
+               default:  /* >= 640x480 */
+                       gspca_dev->alt = 9;
+               }
+       }
+
+       return 0;
+}
+
 #define HW_WIN(mode, hstart, vstart) \
 ((const u8 []){hstart, 0, vstart, 0, \
 (mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
@@ -2473,6 +2510,7 @@ static const struct sd_desc sd_desc = {
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
        .init = sd_init,
+       .isoc_init = sd_isoc_init,
        .start = sd_start,
        .stopN = sd_stopN,
        .pkt_scan = sd_pkt_scan,
index ddb392dc4f2dbd7b52efd0fffb52311b7e4f42f3..6a1148d7fe926772a245482ba16dca48947467f8 100644 (file)
@@ -1079,20 +1079,23 @@ static int sd_config(struct gspca_dev *gspca_dev,
        }
        cam->npkt = 36;                 /* 36 packets per ISOC message */
 
-       if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) {
-               sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN;
-               sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX;
-               sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF;
-       }
-
        return 0;
 }
 
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        const __u8 stop = 0x09; /* Disable stream turn of LED */
 
+       if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) {
+               sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN;
+               sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX;
+               sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF;
+               if (sd->ctrls[EXPOSURE].val > COARSE_EXPOSURE_MAX)
+                       sd->ctrls[EXPOSURE].val = COARSE_EXPOSURE_DEF;
+       }
+
        reg_w(gspca_dev, 0x01, &stop, 1);
 
        return 0;
index afa3186b803860a5b36e03e7187b5271d56d5d6c..0c9e6ddabd2cc9a43d94dcbc5c1591b280031244 100644 (file)
@@ -1235,7 +1235,7 @@ static const u8 po2030n_sensor_param1[][8] = {
        {DELAY, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 8ms */
        {0xa1, 0x6e, 0x1b, 0xf4, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10},
-       {0xd1, 0x6e, 0x16, 0x50, 0x40, 0x49, 0x40, 0x10},
+       {0xd1, 0x6e, 0x16, 0x40, 0x40, 0x40, 0x40, 0x10}, /* RGBG gains */
 /*param2*/
        {0xa1, 0x6e, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x6e, 0x04, 0x03, 0x00, 0x00, 0x00, 0x10},
@@ -1779,10 +1779,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->ag_cnt = -1;
        sd->quality = QUALITY_DEF;
 
-       /* if USB 1.1, let some bandwidth for the audio device */
-       if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH)
-               gspca_dev->nbalt--;
-
        INIT_WORK(&sd->work, qual_upd);
 
        return 0;
@@ -2063,6 +2059,16 @@ static void setredblue(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
+       if (sd->sensor == SENSOR_PO2030N) {
+               u8 rg1b[] =             /* red  green1 blue (no g2) */
+                       {0xc1, 0x6e, 0x16, 0x00, 0x40, 0x00, 0x00, 0x10};
+
+               /* 0x40 = normal value = gain x 1 */
+               rg1b[3] = sd->ctrls[RED].val * 2;
+               rg1b[5] = sd->ctrls[BLUE].val * 2;
+               i2c_w8(gspca_dev, rg1b);
+               return;
+       }
        reg_w1(gspca_dev, 0x05, sd->ctrls[RED].val);
 /*     reg_w1(gspca_dev, 0x07, 32); */
        reg_w1(gspca_dev, 0x06, sd->ctrls[BLUE].val);
@@ -2397,7 +2403,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0x17, reg17);
        reg01 &= ~S_PWR_DN;             /* sensor power on */
        reg_w1(gspca_dev, 0x01, reg01);
-       reg01 &= ~SYS_SEL_48M;
+       reg01 &= ~SCL_SEL_OD;           /* remove open-drain mode */
        reg_w1(gspca_dev, 0x01, reg01);
 
        switch (sd->sensor) {
index 259a0c73c664b9c02966ba3253d41981b8eeae83..4a5f209ce719aa878ae082d30ca82f9faa9586f3 100644 (file)
@@ -451,7 +451,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        }
 
        cam = &gspca_dev->cam;
-       gspca_dev->nbalt = 7 + 1;       /* choose alternate 7 first */
+       cam->needs_full_bandwidth = 1;
 
        sd->chip_revision = id->driver_info;
        if (sd->chip_revision == Rev012A) {
index 0ab425fbea9ab32cada5e22973986631c8b8bde3..91d99b4cc57bf69afca371e70e0b5527abd1625d 100644 (file)
@@ -36,8 +36,8 @@ MODULE_AUTHOR("Erik Andrén");
 MODULE_DESCRIPTION("STV06XX USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-static int dump_bridge;
-static int dump_sensor;
+static bool dump_bridge;
+static bool dump_sensor;
 
 int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data)
 {
@@ -304,7 +304,7 @@ static int stv06xx_isoc_init(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        /* Start isoc bandwidth "negotiation" at max isoc bandwidth */
-       alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+       alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
        alt->endpoint[0].desc.wMaxPacketSize =
                cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]);
 
@@ -317,7 +317,7 @@ static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev)
        struct usb_host_interface *alt;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+       alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
        packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
        min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode];
        if (packet_size <= min_packet_size)
index ea44deb66af4bbf9b9f7f871f70394804afd621d..9b9f85a8e60e750f9d2fba5cb4a0deab8e4f3b63 100644 (file)
@@ -30,6 +30,7 @@
 
 #define MODULE_NAME "t613"
 
+#include <linux/input.h>
 #include <linux/slab.h>
 #include "gspca.h"
 
@@ -57,6 +58,7 @@ struct sd {
        u8 effect;
 
        u8 sensor;
+       u8 button_pressed;
 };
 enum sensors {
        SENSOR_OM6802,
@@ -1095,15 +1097,35 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
                msleep(20);
                reg_w(gspca_dev, 0x0309);
        }
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+       /* If the last button state is pressed, release it now! */
+       if (sd->button_pressed) {
+               input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+               input_sync(gspca_dev->input_dev);
+               sd->button_pressed = 0;
+       }
+#endif
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        int pkt_type;
 
        if (data[0] == 0x5a) {
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+               if (len > 20) {
+                       u8 state = (data[20] & 0x80) ? 1 : 0;
+                       if (sd->button_pressed != state) {
+                               input_report_key(gspca_dev->input_dev,
+                                                KEY_CAMERA, state);
+                               input_sync(gspca_dev->input_dev);
+                               sd->button_pressed = state;
+                       }
+               }
+#endif
                /* Control Packet, after this came the header again,
                 * but extra bytes came in the packet before this,
                 * sometimes an EOF arrives, sometimes not... */
@@ -1410,6 +1432,9 @@ static const struct sd_desc sd_desc = {
        .stopN = sd_stopN,
        .pkt_scan = sd_pkt_scan,
        .querymenu = sd_querymenu,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+       .other_input = 1,
+#endif
 };
 
 /* -- module initialisation -- */
index b2695b1dc6032a28312d411aa244db1979882759..444d3c5b90795db1c4c127d696c2a08fef7dd5fb 100644 (file)
@@ -3946,7 +3946,7 @@ static int get_fr_idx(struct gspca_dev *gspca_dev)
                /* 640x480 * 30 fps does not work */
                if (i == 6                      /* if 30 fps */
                 && gspca_dev->width == 640)
-                       i = 0x86;               /* 15 fps */
+                       i = 0x05;               /* 15 fps */
        } else {
                for (i = 0; i < ARRAY_SIZE(rates_6810) - 1; i++) {
                        if (sd->framerate >= rates_6810[i])
index d12ea1518ace7df6351ccda64de3b3d7a7cd8994..911152e169d6d43c4a42dd47fffa0542dd1e96f9 100644 (file)
@@ -324,7 +324,8 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
        dev->work_thread = NULL;
        mutex_lock(&gspca_dev->usb_lock);
 
-       vicam_set_camera_power(gspca_dev, 0);
+       if (gspca_dev->present)
+               vicam_set_camera_power(gspca_dev, 0);
 }
 
 /* Table of supported USB devices */
index fbb6ed25ec313a007086f933a0f6bb7efcbc697a..ecada178bceb9b27bc0c3d6d0a2d505100ccb3b4 100644 (file)
@@ -995,14 +995,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
        case CIT_MODEL0:
                cam->cam_mode = model0_mode;
                cam->nmodes = ARRAY_SIZE(model0_mode);
-               cam->reverse_alts = 1;
                gspca_dev->ctrl_dis = ~((1 << SD_CONTRAST) | (1 << SD_HFLIP));
                sd->sof_len = 4;
                break;
        case CIT_MODEL1:
                cam->cam_mode = cif_yuv_mode;
                cam->nmodes = ARRAY_SIZE(cif_yuv_mode);
-               cam->reverse_alts = 1;
                gspca_dev->ctrl_dis = (1 << SD_HUE) | (1 << SD_HFLIP);
                sd->sof_len = 4;
                break;
@@ -2791,7 +2789,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
        }
 
        /* Start isoc bandwidth "negotiation" at max isoc bandwidth */
-       alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+       alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
        alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size);
 
        return 0;
@@ -2814,7 +2812,7 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev)
                break;
        }
 
-       alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+       alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
        packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
        if (packet_size <= min_packet_size)
                return -EIO;
index 0202fead6b9746e4330b6666db2ee09cea545ea0..b9e15bb0328bef03dab33169c3d14fbebee44cbc 100644 (file)
@@ -5381,12 +5381,12 @@ static const struct usb_action tas5130c_NoFlikerScale[] = {
        {}
 };
 
-static const struct usb_action gc0303_InitialScale[] = {
+/* from usbvm305.inf 0ac8:305b 07/06/15 (3 - tas5130c) */
+static const struct usb_action gc0303_Initial[] = {
        {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},         /* 00,00,01,cc, */
        {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING},          /* 00,08,02,cc, */
        {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc, */
-       {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},           /* 00,02,00,cc,
-                                                        * 0<->10 */
+       {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
        {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},        /* 00,03,02,cc, */
        {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},         /* 00,04,80,cc, */
        {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},       /* 00,05,01,cc, */
@@ -5405,29 +5405,22 @@ static const struct usb_action gc0303_InitialScale[] = {
                                                         * 6<->8 */
        {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},            /* 00,87,10,cc, */
        {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR},         /* 00,8b,98,cc, */
-       {0xaa, 0x1b, 0x0024},           /* 00,1b,24,aa, */
-       {0xdd, 0x00, 0x0080},           /* 00,00,80,dd, */
-       {0xaa, 0x1b, 0x0000},           /* 00,1b,00,aa, */
-       {0xaa, 0x13, 0x0002},           /* 00,13,02,aa, */
-       {0xaa, 0x15, 0x0004},           /* 00,15,04,aa */
-/*??   {0xaa, 0x01, 0x0000}, */
        {0xaa, 0x01, 0x0000},
        {0xaa, 0x1a, 0x0000},           /* 00,1a,00,aa, */
        {0xaa, 0x1c, 0x0017},           /* 00,1c,17,aa, */
+       {0xaa, 0x1b, 0x0000},
        {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH},           /* 00,86,82,cc, */
        {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID},            /* 00,87,83,cc, */
        {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW},            /* 00,88,84,cc, */
        {0xaa, 0x05, 0x0010},           /* 00,05,10,aa, */
-       {0xaa, 0x0a, 0x0000},           /* 00,0a,00,aa, */
-       {0xaa, 0x0b, 0x00a0},           /* 00,0b,a0,aa, */
-       {0xaa, 0x0c, 0x0000},           /* 00,0c,00,aa, */
-       {0xaa, 0x0d, 0x00a0},           /* 00,0d,a0,aa, */
-       {0xaa, 0x0e, 0x0000},           /* 00,0e,00,aa, */
-       {0xaa, 0x0f, 0x00a0},           /* 00,0f,a0,aa, */
-       {0xaa, 0x10, 0x0000},           /* 00,10,00,aa, */
-       {0xaa, 0x11, 0x00a0},           /* 00,11,a0,aa, */
-/*??   {0xa0, 0x00, 0x0039},
-       {0xa1, 0x01, 0x0037}, */
+       {0xaa, 0x0a, 0x0002},
+       {0xaa, 0x0b, 0x0000},
+       {0xaa, 0x0c, 0x0002},
+       {0xaa, 0x0d, 0x0000},
+       {0xaa, 0x0e, 0x0002},
+       {0xaa, 0x0f, 0x0000},
+       {0xaa, 0x10, 0x0002},
+       {0xaa, 0x11, 0x0000},
        {0xaa, 0x16, 0x0001},           /* 00,16,01,aa, */
        {0xaa, 0x17, 0x00e8},           /* 00,17,e6,aa, (e6 -> e8) */
        {0xaa, 0x18, 0x0002},           /* 00,18,02,aa, */
@@ -5442,17 +5435,18 @@ static const struct usb_action gc0303_InitialScale[] = {
        {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},           /* 01,cb,13,cc, */
        {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},        /* 02,50,08,cc, */
        {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},          /* 03,01,08,cc, */
-       {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},           /* 01,a8,60,cc, */
+       {0xa0, 0x58, ZC3XX_R1A8_DIGITALGAIN},
        {0xa0, 0x61, ZC3XX_R116_RGAIN},                 /* 01,16,61,cc, */
        {0xa0, 0x65, ZC3XX_R118_BGAIN},                 /* 01,18,65,cc */
+       {0xaa, 0x1b, 0x0000},
        {}
 };
 
-static const struct usb_action gc0303_Initial[] = {
+static const struct usb_action gc0303_InitialScale[] = {
        {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},         /* 00,00,01,cc, */
        {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING},          /* 00,08,02,cc, */
        {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,01,cc, */
-       {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},           /* 00,02,10,cc, */
+       {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
        {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},        /* 00,03,02,cc, */
        {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},         /* 00,04,80,cc, */
        {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},       /* 00,05,01,cc, */
@@ -5471,34 +5465,26 @@ static const struct usb_action gc0303_Initial[] = {
                                                         * 8<->6 */
        {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},            /* 00,87,10,cc, */
        {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR},         /* 00,8b,98,cc, */
-       {0xaa, 0x1b, 0x0024},           /* 00,1b,24,aa, */
-       {0xdd, 0x00, 0x0080},           /* 00,00,80,dd, */
-       {0xaa, 0x1b, 0x0000},           /* 00,1b,00,aa, */
-       {0xaa, 0x13, 0x0002},           /* 00,13,02,aa, */
-       {0xaa, 0x15, 0x0004},           /* 00,15,04,aa */
-/*??   {0xaa, 0x01, 0x0000}, */
        {0xaa, 0x01, 0x0000},
        {0xaa, 0x1a, 0x0000},           /* 00,1a,00,aa, */
        {0xaa, 0x1c, 0x0017},           /* 00,1c,17,aa, */
+       {0xaa, 0x1b, 0x0000},
        {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH},   /* 00,86,82,cc, */
        {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID},    /* 00,87,83,cc, */
        {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW},    /* 00,88,84,cc, */
        {0xaa, 0x05, 0x0010},           /* 00,05,10,aa, */
-       {0xaa, 0x0a, 0x0000},           /* 00,0a,00,aa, */
-       {0xaa, 0x0b, 0x00a0},           /* 00,0b,a0,aa, */
-       {0xaa, 0x0c, 0x0000},           /* 00,0c,00,aa, */
-       {0xaa, 0x0d, 0x00a0},           /* 00,0d,a0,aa, */
-       {0xaa, 0x0e, 0x0000},           /* 00,0e,00,aa, */
-       {0xaa, 0x0f, 0x00a0},           /* 00,0f,a0,aa, */
-       {0xaa, 0x10, 0x0000},           /* 00,10,00,aa, */
-       {0xaa, 0x11, 0x00a0},           /* 00,11,a0,aa, */
-/*??   {0xa0, 0x00, 0x0039},
-       {0xa1, 0x01, 0x0037}, */
+       {0xaa, 0x0a, 0x0001},
+       {0xaa, 0x0b, 0x0000},
+       {0xaa, 0x0c, 0x0001},
+       {0xaa, 0x0d, 0x0000},
+       {0xaa, 0x0e, 0x0001},
+       {0xaa, 0x0f, 0x0000},
+       {0xaa, 0x10, 0x0001},
+       {0xaa, 0x11, 0x0000},
        {0xaa, 0x16, 0x0001},           /* 00,16,01,aa, */
        {0xaa, 0x17, 0x00e8},           /* 00,17,e6,aa (e6 -> e8) */
        {0xaa, 0x18, 0x0002},           /* 00,18,02,aa, */
        {0xaa, 0x19, 0x0088},           /* 00,19,88,aa, */
-       {0xaa, 0x20, 0x0020},           /* 00,20,20,aa, */
        {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},      /* 01,01,b7,cc, */
        {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},      /* 00,12,05,cc, */
        {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},         /* 01,00,0d,cc, */
@@ -5508,36 +5494,37 @@ static const struct usb_action gc0303_Initial[] = {
        {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},           /* 01,cb,13,cc, */
        {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},        /* 02,50,08,cc, */
        {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},          /* 03,01,08,cc, */
-       {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},           /* 01,a8,60,cc, */
+       {0xa0, 0x58, ZC3XX_R1A8_DIGITALGAIN},
        {0xa0, 0x61, ZC3XX_R116_RGAIN},         /* 01,16,61,cc, */
        {0xa0, 0x65, ZC3XX_R118_BGAIN},         /* 01,18,65,cc */
+       {0xaa, 0x1b, 0x0000},
        {}
 };
-static const struct usb_action gc0303_50HZScale[] = {
+static const struct usb_action gc0303_50HZ[] = {
        {0xaa, 0x82, 0x0000},           /* 00,82,00,aa */
        {0xaa, 0x83, 0x0001},           /* 00,83,01,aa */
-       {0xaa, 0x84, 0x00aa},           /* 00,84,aa,aa */
+       {0xaa, 0x84, 0x0063},
        {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,00,cc, */
        {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,0d,cc, */
        {0xa0, 0xa8, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,50,cc, */
        {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,00,cc, */
        {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,00,cc, */
-       {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,47,cc, */
+       {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,47,cc, */
        {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},              /* 01,8c,0e,cc, */
        {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE},            /* 01,8f,15,cc, */
        {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,10,cc, */
-       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,24,cc, */
+       {0xa0, 0x48, ZC3XX_R1AA_DIGITALGAINSTEP},
        {0xa0, 0x62, ZC3XX_R01D_HSYNC_0},               /* 00,1d,62,cc, */
        {0xa0, 0x90, ZC3XX_R01E_HSYNC_1},               /* 00,1e,90,cc, */
        {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},               /* 00,1f,c8,cc, */
        {0xa0, 0xff, ZC3XX_R020_HSYNC_3},               /* 00,20,ff,cc, */
        {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN},            /* 01,1d,58,cc, */
        {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},     /* 01,80,42,cc, */
-       {0xa0, 0x78, ZC3XX_R18D_YTARGET},               /* 01,8d,78,cc */
+       {0xa0, 0x7f, ZC3XX_R18D_YTARGET},
        {}
 };
 
-static const struct usb_action gc0303_50HZ[] = {
+static const struct usb_action gc0303_50HZScale[] = {
        {0xaa, 0x82, 0x0000},           /* 00,82,00,aa */
        {0xaa, 0x83, 0x0003},           /* 00,83,03,aa */
        {0xaa, 0x84, 0x0054},           /* 00,84,54,aa */
@@ -5550,21 +5537,21 @@ static const struct usb_action gc0303_50HZ[] = {
        {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},              /* 01,8c,0e,cc, */
        {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE},            /* 01,8f,15,cc, */
        {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,10,cc, */
-       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,24,cc, */
+       {0xa0, 0x48, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,24,cc, */
        {0xa0, 0x62, ZC3XX_R01D_HSYNC_0},               /* 00,1d,62,cc, */
        {0xa0, 0x90, ZC3XX_R01E_HSYNC_1},               /* 00,1e,90,cc, */
        {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},               /* 00,1f,c8,cc, */
        {0xa0, 0xff, ZC3XX_R020_HSYNC_3},               /* 00,20,ff,cc, */
        {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN},            /* 01,1d,58,cc, */
        {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},     /* 01,80,42,cc, */
-       {0xa0, 0x78, ZC3XX_R18D_YTARGET},               /* 01,8d,78,cc */
+       {0xa0, 0x7f, ZC3XX_R18D_YTARGET},
        {}
 };
 
-static const struct usb_action gc0303_60HZScale[] = {
+static const struct usb_action gc0303_60HZ[] = {
        {0xaa, 0x82, 0x0000},           /* 00,82,00,aa */
-       {0xaa, 0x83, 0x0001},           /* 00,83,01,aa */
-       {0xaa, 0x84, 0x0062},           /* 00,84,62,aa */
+       {0xaa, 0x83, 0x0000},
+       {0xaa, 0x84, 0x003b},
        {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,00,cc, */
        {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,05,cc, */
        {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,88,cc, */
@@ -5581,14 +5568,14 @@ static const struct usb_action gc0303_60HZScale[] = {
        {0xa0, 0xff, ZC3XX_R020_HSYNC_3},               /* 00,20,ff,cc, */
        {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN},            /* 01,1d,58,cc, */
        {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},     /* 01,80,42,cc, */
-       {0xa0, 0x78, ZC3XX_R18D_YTARGET},               /* 01,8d,78,cc */
+       {0xa0, 0x80, ZC3XX_R18D_YTARGET},
        {}
 };
 
-static const struct usb_action gc0303_60HZ[] = {
+static const struct usb_action gc0303_60HZScale[] = {
        {0xaa, 0x82, 0x0000},           /* 00,82,00,aa */
-       {0xaa, 0x83, 0x0002},           /* 00,83,02,aa */
-       {0xaa, 0x84, 0x00c4},           /* 00,84,c4,aa */
+       {0xaa, 0x83, 0x0000},
+       {0xaa, 0x84, 0x0076},
        {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,00,cc, */
        {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,1,0b,cc, */
        {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,2,10,cc, */
@@ -5605,18 +5592,18 @@ static const struct usb_action gc0303_60HZ[] = {
        {0xa0, 0xff, ZC3XX_R020_HSYNC_3},               /* 00,0,ff,cc, */
        {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN},            /* 01,d,58,cc, */
        {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},     /* 01,80,42,cc, */
-       {0xa0, 0x78, ZC3XX_R18D_YTARGET},               /* 01,d,78,cc */
+       {0xa0, 0x80, ZC3XX_R18D_YTARGET},
        {}
 };
 
-static const struct usb_action gc0303_NoFlikerScale[] = {
+static const struct usb_action gc0303_NoFliker[] = {
        {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE},         /* 01,00,0c,cc, */
        {0xaa, 0x82, 0x0000},           /* 00,82,00,aa */
        {0xaa, 0x83, 0x0000},           /* 00,83,00,aa */
        {0xaa, 0x84, 0x0020},           /* 00,84,20,aa */
        {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,0,00,cc, */
-       {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,05,cc, */
-       {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,88,cc, */
+       {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID},
+       {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW},
        {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,00,cc, */
        {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,00,cc, */
        {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,10,cc, */
@@ -5631,14 +5618,14 @@ static const struct usb_action gc0303_NoFlikerScale[] = {
        {}
 };
 
-static const struct usb_action gc0303_NoFliker[] = {
+static const struct usb_action gc0303_NoFlikerScale[] = {
        {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE},         /* 01,00,0c,cc, */
        {0xaa, 0x82, 0x0000},           /* 00,82,00,aa */
        {0xaa, 0x83, 0x0000},           /* 00,83,00,aa */
        {0xaa, 0x84, 0x0020},           /* 00,84,20,aa */
        {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,00,cc, */
-       {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,0b,cc, */
-       {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,10,cc, */
+       {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID},
+       {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW},
        {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,00,cc, */
        {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,00,cc, */
        {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,10,cc, */
@@ -5809,7 +5796,7 @@ static void setmatrix(struct gspca_dev *gspca_dev)
        static const u8 tas5130c_matrix[9] =
                {0x68, 0xec, 0xec, 0xec, 0x68, 0xec, 0xec, 0xec, 0x68};
        static const u8 gc0303_matrix[9] =
-               {0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b};
+               {0x6c, 0xea, 0xea, 0xea, 0x6c, 0xea, 0xea, 0xea, 0x6c};
        static const u8 *matrix_tb[SENSOR_MAX] = {
                [SENSOR_ADCM2700] =     adcm2700_matrix,
                [SENSOR_CS2102] =       ov7620_matrix,
@@ -6426,10 +6413,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        gspca_dev->cam.ctrls = sd->ctrls;
        sd->quality = QUALITY_DEF;
 
-       /* if USB 1.1, let some bandwidth for the audio device */
-       if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH)
-               gspca_dev->nbalt--;
-
        return 0;
 }
 
index 3f1a5b1beeba63f7336f96d9a3d3310c2530d77b..e5eb56a5b6180cd80e43d25812cc406bdda06921 100644 (file)
@@ -49,7 +49,7 @@ module_param(default_audio_input, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(default_audio_input, "default audio input: 0=RCA back / "
                 "1=RCA front / 2=S/PDIF");
 
-static int boost_audio;
+static bool boost_audio;
 module_param(boost_audio, bool, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(boost_audio, "boost the audio signal");
 
index 3ab875d036e10cdc1a530cffb75246a76bdc3d2f..a7c41d32f4140b02e03350d2e4222b2a0fd38430 100644 (file)
@@ -244,7 +244,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
 
 /* ----------------------------------------------------------------------- */
 
-static void ir_key_poll(struct IR_i2c *ir)
+static int ir_key_poll(struct IR_i2c *ir)
 {
        static u32 ir_key, ir_raw;
        int rc;
@@ -253,20 +253,28 @@ static void ir_key_poll(struct IR_i2c *ir)
        rc = ir->get_key(ir, &ir_key, &ir_raw);
        if (rc < 0) {
                dprintk(2,"error\n");
-               return;
+               return rc;
        }
 
        if (rc) {
                dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key);
                rc_keydown(ir->rc, ir_key, 0);
        }
+       return 0;
 }
 
 static void ir_work(struct work_struct *work)
 {
+       int rc;
        struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work);
 
-       ir_key_poll(ir);
+       rc = ir_key_poll(ir);
+       if (rc == -ENODEV) {
+               rc_unregister_device(ir->rc);
+               ir->rc = NULL;
+               return;
+       }
+
        schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval));
 }
 
@@ -446,7 +454,8 @@ static int ir_remove(struct i2c_client *client)
        cancel_delayed_work_sync(&ir->work);
 
        /* unregister device */
-       rc_unregister_device(ir->rc);
+       if (ir->rc)
+               rc_unregister_device(ir->rc);
 
        /* free memory */
        kfree(ir);
@@ -489,11 +498,3 @@ static void __exit ir_fini(void)
 
 module_init(ir_init);
 module_exit(ir_fini);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 41108a9a195ecb5b07fd6ad4697f978fc7cd0c9a..3949b7dc2368370ebe6d28f15b3b83bc2999babe 100644 (file)
@@ -99,7 +99,7 @@ static int i2c_clock_period[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
 
 static unsigned int cardtype_c = 1;
 static unsigned int tuner_c = 1;
-static unsigned int radio_c = 1;
+static bool radio_c = 1;
 static unsigned int i2c_clock_period_c = 1;
 static char pal[] = "---";
 static char secam[] = "--";
@@ -731,9 +731,6 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
 
        init_kthread_work(&itv->irq_work, ivtv_irq_work_handler);
 
-       /* start counting open_id at 1 */
-       itv->open_id = 1;
-
        /* Initial settings */
        itv->cxhdl.port = CX2341X_PORT_MEMORY;
        itv->cxhdl.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
index 8f9cc17b518eaaf6320e092d0a667d8d4876e586..06f3d78389bfbb250f89d655a9d6e57ebe359d24 100644 (file)
@@ -332,7 +332,7 @@ struct ivtv_stream {
        const char *name;               /* name of the stream */
        int type;                       /* stream type */
 
-       u32 id;
+       struct v4l2_fh *fh;             /* pointer to the streaming filehandle */
        spinlock_t qlock;               /* locks access to the queues */
        unsigned long s_flags;          /* status flags, see above */
        int dma;                        /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */
@@ -379,7 +379,6 @@ struct ivtv_stream {
 
 struct ivtv_open_id {
        struct v4l2_fh fh;
-       u32 open_id;                    /* unique ID for this file descriptor */
        int type;                       /* stream type */
        int yuv_frames;                 /* 1: started OUT_UDMA_YUV output mode */
        struct ivtv *itv;
index 38f052257f4620498d6b23e0bf3b7cfb88aa5ba9..2cd6c89b7d917d618de7791bf919bb1015c899b9 100644 (file)
@@ -50,16 +50,16 @@ static int ivtv_claim_stream(struct ivtv_open_id *id, int type)
 
        if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
                /* someone already claimed this stream */
-               if (s->id == id->open_id) {
+               if (s->fh == &id->fh) {
                        /* yes, this file descriptor did. So that's OK. */
                        return 0;
                }
-               if (s->id == -1 && (type == IVTV_DEC_STREAM_TYPE_VBI ||
+               if (s->fh == NULL && (type == IVTV_DEC_STREAM_TYPE_VBI ||
                                         type == IVTV_ENC_STREAM_TYPE_VBI)) {
                        /* VBI is handled already internally, now also assign
                           the file descriptor to this stream for external
                           reading of the stream. */
-                       s->id = id->open_id;
+                       s->fh = &id->fh;
                        IVTV_DEBUG_INFO("Start Read VBI\n");
                        return 0;
                }
@@ -67,7 +67,7 @@ static int ivtv_claim_stream(struct ivtv_open_id *id, int type)
                IVTV_DEBUG_INFO("Stream %d is busy\n", type);
                return -EBUSY;
        }
-       s->id = id->open_id;
+       s->fh = &id->fh;
        if (type == IVTV_DEC_STREAM_TYPE_VBI) {
                /* Enable reinsertion interrupt */
                ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
@@ -104,7 +104,7 @@ void ivtv_release_stream(struct ivtv_stream *s)
        struct ivtv *itv = s->itv;
        struct ivtv_stream *s_vbi;
 
-       s->id = -1;
+       s->fh = NULL;
        if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) &&
                test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) {
                /* this stream is still in use internally */
@@ -136,7 +136,7 @@ void ivtv_release_stream(struct ivtv_stream *s)
                /* was already cleared */
                return;
        }
-       if (s_vbi->id != -1) {
+       if (s_vbi->fh) {
                /* VBI stream still claimed by a file descriptor */
                return;
        }
@@ -268,11 +268,13 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
                }
 
                /* wait for more data to arrive */
+               mutex_unlock(&itv->serialize_lock);
                prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
                /* New buffers might have become available before we were added to the waitqueue */
                if (!s->q_full.buffers)
                        schedule();
                finish_wait(&s->waitq, &wait);
+               mutex_lock(&itv->serialize_lock);
                if (signal_pending(current)) {
                        /* return if a signal was received */
                        IVTV_DEBUG_INFO("User stopped %s\n", s->name);
@@ -357,7 +359,7 @@ static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_co
        size_t tot_written = 0;
        int single_frame = 0;
 
-       if (atomic_read(&itv->capturing) == 0 && s->id == -1) {
+       if (atomic_read(&itv->capturing) == 0 && s->fh == NULL) {
                /* shouldn't happen */
                IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name);
                return -EIO;
@@ -507,9 +509,7 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_
 
        IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
 
-       mutex_lock(&itv->serialize_lock);
        rc = ivtv_start_capture(id);
-       mutex_unlock(&itv->serialize_lock);
        if (rc)
                return rc;
        return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
@@ -584,9 +584,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
        set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
 
        /* Start decoder (returns 0 if already started) */
-       mutex_lock(&itv->serialize_lock);
        rc = ivtv_start_decoding(id, itv->speed);
-       mutex_unlock(&itv->serialize_lock);
        if (rc) {
                IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
 
@@ -627,11 +625,13 @@ retry:
                        break;
                if (filp->f_flags & O_NONBLOCK)
                        return -EAGAIN;
+               mutex_unlock(&itv->serialize_lock);
                prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
                /* New buffers might have become free before we were added to the waitqueue */
                if (!s->q_free.buffers)
                        schedule();
                finish_wait(&s->waitq, &wait);
+               mutex_lock(&itv->serialize_lock);
                if (signal_pending(current)) {
                        IVTV_DEBUG_INFO("User stopped %s\n", s->name);
                        return -EINTR;
@@ -686,12 +686,14 @@ retry:
                        if (mode == OUT_YUV)
                                ivtv_yuv_setup_stream_frame(itv);
 
+                       mutex_unlock(&itv->serialize_lock);
                        prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
                        while (!(got_sig = signal_pending(current)) &&
                                        test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) {
                                schedule();
                        }
                        finish_wait(&itv->dma_waitq, &wait);
+                       mutex_lock(&itv->serialize_lock);
                        if (got_sig) {
                                IVTV_DEBUG_INFO("User interrupted %s\n", s->name);
                                return -EINTR;
@@ -756,9 +758,7 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
        if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
                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);
@@ -808,7 +808,7 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end)
                     id->type == IVTV_ENC_STREAM_TYPE_VBI) &&
                    test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) {
                        /* Also used internally, don't stop capturing */
-                       s->id = -1;
+                       s->fh = NULL;
                }
                else {
                        ivtv_stop_v4l2_encode_stream(s, gop_end);
@@ -861,20 +861,9 @@ int ivtv_v4l2_close(struct file *filp)
 
        IVTV_DEBUG_FILE("close %s\n", s->name);
 
-       v4l2_fh_del(fh);
-       v4l2_fh_exit(fh);
-
-       /* Easy case first: this stream was never claimed by us */
-       if (s->id != id->open_id) {
-               kfree(id);
-               return 0;
-       }
-
-       /* 'Unclaim' this stream */
-
        /* Stop radio */
-       mutex_lock(&itv->serialize_lock);
-       if (id->type == IVTV_ENC_STREAM_TYPE_RAD) {
+       if (id->type == IVTV_ENC_STREAM_TYPE_RAD &&
+                       v4l2_fh_is_singular_file(filp)) {
                /* Closing radio device, return to TV mode */
                ivtv_mute(itv);
                /* Mark that the radio is no longer in use */
@@ -890,13 +879,25 @@ int ivtv_v4l2_close(struct file *filp)
                if (atomic_read(&itv->capturing) > 0) {
                        /* Undo video mute */
                        ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,
-                               v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute) |
-                               (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8));
+                                       v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute) |
+                                       (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8));
                }
                /* Done! Unmute and continue. */
                ivtv_unmute(itv);
-               ivtv_release_stream(s);
-       } else if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
+       }
+
+       v4l2_fh_del(fh);
+       v4l2_fh_exit(fh);
+
+       /* Easy case first: this stream was never claimed by us */
+       if (s->fh != &id->fh) {
+               kfree(id);
+               return 0;
+       }
+
+       /* 'Unclaim' this stream */
+
+       if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
                struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT];
 
                ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
@@ -911,21 +912,25 @@ int ivtv_v4l2_close(struct file *filp)
                ivtv_stop_capture(id, 0);
        }
        kfree(id);
-       mutex_unlock(&itv->serialize_lock);
        return 0;
 }
 
-static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
+int ivtv_v4l2_open(struct file *filp)
 {
-#ifdef CONFIG_VIDEO_ADV_DEBUG
        struct video_device *vdev = video_devdata(filp);
-#endif
+       struct ivtv_stream *s = video_get_drvdata(vdev);
        struct ivtv *itv = s->itv;
        struct ivtv_open_id *item;
        int res = 0;
 
        IVTV_DEBUG_FILE("open %s\n", s->name);
 
+       if (ivtv_init_on_first_open(itv)) {
+               IVTV_ERR("Failed to initialize on device %s\n",
+                        video_device_node_name(vdev));
+               return -ENXIO;
+       }
+
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        /* Unless ivtv_fw_debug is set, error out if firmware dead. */
        if (ivtv_fw_debug) {
@@ -966,31 +971,19 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
                return -ENOMEM;
        }
        v4l2_fh_init(&item->fh, s->vdev);
-       if (res < 0) {
-               v4l2_fh_exit(&item->fh);
-               kfree(item);
-               return res;
-       }
        item->itv = itv;
        item->type = s->type;
 
-       item->open_id = itv->open_id++;
        filp->private_data = &item->fh;
+       v4l2_fh_add(&item->fh);
 
-       if (item->type == IVTV_ENC_STREAM_TYPE_RAD) {
-               /* Try to claim this stream */
-               if (ivtv_claim_stream(item, item->type)) {
-                       /* No, it's already in use */
-                       v4l2_fh_exit(&item->fh);
-                       kfree(item);
-                       return -EBUSY;
-               }
-
+       if (item->type == IVTV_ENC_STREAM_TYPE_RAD &&
+                       v4l2_fh_is_singular_file(filp)) {
                if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
                        if (atomic_read(&itv->capturing) > 0) {
                                /* switching to radio while capture is
                                   in progress is not polite */
-                               ivtv_release_stream(s);
+                               v4l2_fh_del(&item->fh);
                                v4l2_fh_exit(&item->fh);
                                kfree(item);
                                return -EBUSY;
@@ -1022,32 +1015,9 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
                                1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
                itv->yuv_info.stream_size = 0;
        }
-       v4l2_fh_add(&item->fh);
        return 0;
 }
 
-int ivtv_v4l2_open(struct file *filp)
-{
-       int res;
-       struct ivtv *itv = NULL;
-       struct ivtv_stream *s = NULL;
-       struct video_device *vdev = video_devdata(filp);
-
-       s = video_get_drvdata(vdev);
-       itv = s->itv;
-
-       mutex_lock(&itv->serialize_lock);
-       if (ivtv_init_on_first_open(itv)) {
-               IVTV_ERR("Failed to initialize on device %s\n",
-                        video_device_node_name(vdev));
-               mutex_unlock(&itv->serialize_lock);
-               return -ENXIO;
-       }
-       res = ivtv_serialized_open(s, filp);
-       mutex_unlock(&itv->serialize_lock);
-       return res;
-}
-
 void ivtv_mute(struct ivtv *itv)
 {
        if (atomic_read(&itv->capturing))
index 9332920ca4ff9ff672fa486473a7a7042049f0bf..7b9ec1cfeb80f69bb16a6a476e7b125c44e71bc7 100644 (file)
@@ -25,7 +25,7 @@ struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv);
 int ivtv_i2c_register(struct ivtv *itv, unsigned idx);
 struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw);
 
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter */
 int init_ivtv_i2c(struct ivtv *itv);
 void exit_ivtv_i2c(struct ivtv *itv);
 
index ecafa697326e302803ab85604c0a7ab8aec697f6..c4bc481430985c6405580a461e2cc8e518ae2d73 100644 (file)
@@ -179,6 +179,7 @@ int ivtv_set_speed(struct ivtv *itv, int speed)
                ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0);
 
                /* Wait for any DMA to finish */
+               mutex_unlock(&itv->serialize_lock);
                prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
                while (test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
                        got_sig = signal_pending(current);
@@ -188,6 +189,7 @@ int ivtv_set_speed(struct ivtv *itv, int speed)
                        schedule();
                }
                finish_wait(&itv->dma_waitq, &wait);
+               mutex_lock(&itv->serialize_lock);
                if (got_sig)
                        return -EINTR;
 
@@ -1107,6 +1109,7 @@ void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std)
         * happens within the first 100 lines of the top field.
         * Make 4 attempts to sync to the decoder before giving up.
         */
+       mutex_unlock(&itv->serialize_lock);
        for (f = 0; f < 4; f++) {
                prepare_to_wait(&itv->vsync_waitq, &wait,
                                TASK_UNINTERRUPTIBLE);
@@ -1115,6 +1118,7 @@ void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std)
                schedule_timeout(msecs_to_jiffies(25));
        }
        finish_wait(&itv->vsync_waitq, &wait);
+       mutex_lock(&itv->serialize_lock);
 
        if (f == 4)
                IVTV_WARN("Mode change failed to sync to decoder\n");
@@ -1842,8 +1846,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
        return 0;
 }
 
-static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp,
-               unsigned int cmd, unsigned long arg)
+long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct video_device *vfd = video_devdata(filp);
        long ret;
@@ -1855,21 +1858,6 @@ static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp,
        return ret;
 }
 
-long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
-       struct ivtv_open_id *id = fh2id(filp->private_data);
-       struct ivtv *itv = id->itv;
-       long res;
-
-       /* DQEVENT can block, so this should not run with the serialize lock */
-       if (cmd == VIDIOC_DQEVENT)
-               return ivtv_serialized_ioctl(itv, filp, cmd, arg);
-       mutex_lock(&itv->serialize_lock);
-       res = ivtv_serialized_ioctl(itv, filp, cmd, arg);
-       mutex_unlock(&itv->serialize_lock);
-       return res;
-}
-
 static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
        .vidioc_querycap                    = ivtv_querycap,
        .vidioc_s_audio                     = ivtv_s_audio,
index 9c29e964d400b955d36074487c17c22e1195bbcd..1b3b9578bf47657915b464e9b9513f48b481aa0e 100644 (file)
@@ -288,13 +288,13 @@ static void dma_post(struct ivtv_stream *s)
                        ivtv_process_vbi_data(itv, buf, 0, s->type);
                        s->q_dma.bytesused += buf->bytesused;
                }
-               if (s->id == -1) {
+               if (s->fh == NULL) {
                        ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
                        return;
                }
        }
        ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused);
-       if (s->id != -1)
+       if (s->fh)
                wake_up(&s->waitq);
 }
 
index e7794dc1330e50348a5e358714abf9f54702e56d..c6e28b4ebbed6dfe3e821e443dcff04d8e4694e3 100644 (file)
@@ -159,7 +159,6 @@ static void ivtv_stream_init(struct ivtv *itv, int type)
                s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size;
        spin_lock_init(&s->qlock);
        init_waitqueue_head(&s->waitq);
-       s->id = -1;
        s->sg_handle = IVTV_DMA_UNMAPPED;
        ivtv_queue_init(&s->q_free);
        ivtv_queue_init(&s->q_full);
@@ -214,6 +213,7 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
        s->vdev->fops = ivtv_stream_info[type].fops;
        s->vdev->release = video_device_release;
        s->vdev->tvnorms = V4L2_STD_ALL;
+       s->vdev->lock = &itv->serialize_lock;
        set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev->flags);
        ivtv_set_funcs(s->vdev);
        return 0;
index dcbab6ad4c26ee8843336f673aeb1f9f7fe7ef80..2ad65eb29832754b54a5d190257cadd5d6a09031 100644 (file)
@@ -1149,23 +1149,37 @@ int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)
 {
        struct yuv_playback_info *yi = &itv->yuv_info;
        struct ivtv_dma_frame dma_args;
+       int res;
 
        ivtv_yuv_setup_stream_frame(itv);
 
        /* We only need to supply source addresses for this */
        dma_args.y_source = src;
        dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
-       return ivtv_yuv_udma_frame(itv, &dma_args);
+       /* Wait for frame DMA. Note that serialize_lock is locked,
+          so to allow other processes to access the driver while
+          we are waiting unlock first and later lock again. */
+       mutex_unlock(&itv->serialize_lock);
+       res = ivtv_yuv_udma_frame(itv, &dma_args);
+       mutex_lock(&itv->serialize_lock);
+       return res;
 }
 
 /* IVTV_IOC_DMA_FRAME ioctl handler */
 int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
 {
-/*     IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
+       int res;
 
+/*     IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
        ivtv_yuv_next_free(itv);
        ivtv_yuv_setup_frame(itv, args);
-       return ivtv_yuv_udma_frame(itv, args);
+       /* Wait for frame DMA. Note that serialize_lock is locked,
+          so to allow other processes to access the driver while
+          we are waiting unlock first and later lock again. */
+       mutex_unlock(&itv->serialize_lock);
+       res = ivtv_yuv_udma_frame(itv, args);
+       mutex_lock(&itv->serialize_lock);
+       return res;
 }
 
 void ivtv_yuv_close(struct ivtv *itv)
@@ -1174,7 +1188,9 @@ void ivtv_yuv_close(struct ivtv *itv)
        int h_filter, v_filter_1, v_filter_2;
 
        IVTV_DEBUG_YUV("ivtv_yuv_close\n");
+       mutex_unlock(&itv->serialize_lock);
        ivtv_waitq(&itv->vsync_waitq);
+       mutex_lock(&itv->serialize_lock);
 
        yi->running = 0;
        atomic_set(&yi->next_dma_frame, -1);
index 6b7c9c8233309975726e42a65f97296df84cff54..d0fbfcf7133da88cfabf2caf52c26e685aae35b1 100644 (file)
@@ -58,7 +58,7 @@
 /* card parameters */
 static int ivtvfb_card_id = -1;
 static int ivtvfb_debug = 0;
-static int osd_laced;
+static bool osd_laced;
 static int osd_depth;
 static int osd_upper;
 static int osd_left;
index 82c8817bd32dcddcc74a98593919bd64502de237..4b021e1ee5f26f7e6a3407fcebdc2b74bf706786 100644 (file)
@@ -163,7 +163,6 @@ struct m5mols_version {
  * @ffmt: current fmt according to resolution type
  * @res_type: current resolution type
  * @irq_waitq: waitqueue for the capture
- * @work_irq: workqueue for the IRQ
  * @flags: state variable for the interrupt handler
  * @handle: control handler
  * @autoexposure: Auto Exposure control
@@ -175,14 +174,12 @@ struct m5mols_version {
  * @ver: information of the version
  * @cap: the capture mode attributes
  * @power: current sensor's power status
- * @ctrl_sync: true means all controls of the sensor are initialized
- * @int_capture: true means the capture interrupt is issued once
+ * @isp_ready: 1 when the ISP controller has completed booting
+ * @ctrl_sync: 1 when the control handler state is restored in H/W
  * @lock_ae: true means the Auto Exposure is locked
  * @lock_awb: true means the Aut WhiteBalance is locked
  * @resolution:        register value for current resolution
- * @interrupt: register value for current interrupt status
  * @mode: register value for current operation mode
- * @mode_save: register value for current operation mode for saving
  * @set_power: optional power callback to the board code
  */
 struct m5mols_info {
@@ -191,16 +188,16 @@ struct m5mols_info {
        struct media_pad pad;
        struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
        int res_type;
+
        wait_queue_head_t irq_waitq;
-       struct work_struct work_irq;
-       unsigned long flags;
+       atomic_t irq_done;
 
        struct v4l2_ctrl_handler handle;
+
        /* Autoexposure/exposure control cluster */
-       struct {
-               struct v4l2_ctrl *autoexposure;
-               struct v4l2_ctrl *exposure;
-       };
+       struct v4l2_ctrl *autoexposure;
+       struct v4l2_ctrl *exposure;
+
        struct v4l2_ctrl *autowb;
        struct v4l2_ctrl *colorfx;
        struct v4l2_ctrl *saturation;
@@ -208,21 +205,19 @@ struct m5mols_info {
 
        struct m5mols_version ver;
        struct m5mols_capture cap;
-       bool power;
-       bool ctrl_sync;
+
+       unsigned int isp_ready:1;
+       unsigned int power:1;
+       unsigned int ctrl_sync:1;
+
        bool lock_ae;
        bool lock_awb;
        u8 resolution;
-       u8 interrupt;
        u8 mode;
-       u8 mode_save;
+
        int (*set_power)(struct device *dev, int on);
 };
 
-#define ST_CAPT_IRQ 0
-
-#define is_powered(__info) (__info->power)
-#define is_ctrl_synced(__info) (__info->ctrl_sync)
 #define is_available_af(__info)        (__info->ver.af)
 #define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code)
 #define is_manufacturer(__info, __manufacturer)        \
@@ -257,7 +252,15 @@ int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val);
 int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val);
 int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val);
 int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val);
-int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 value);
+
+int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
+                    int timeout);
+
+/* Mask value for busy waiting until M-5MOLS I2C interface is initialized */
+#define M5MOLS_I2C_RDY_WAIT_FL         (1 << 16)
+/* ISP state transition timeout, in ms */
+#define M5MOLS_MODE_CHANGE_TIMEOUT     200
+#define M5MOLS_BUSY_WAIT_DEF_TIMEOUT   250
 
 /*
  * Mode operation of the M-5MOLS
@@ -282,7 +285,8 @@ int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 value);
 int m5mols_mode(struct m5mols_info *info, u8 mode);
 
 int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
-int m5mols_sync_controls(struct m5mols_info *info);
+int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout);
+int m5mols_restore_controls(struct m5mols_info *info);
 int m5mols_start_capture(struct m5mols_info *info);
 int m5mols_do_scenemode(struct m5mols_info *info, u8 mode);
 int m5mols_lock_3a(struct m5mols_info *info, bool lock);
index 3248ac8057119dcabbe0c726206f9fa60e2ca612..ba25e8e2ba4c789ba391800e88602cfba6a3aecd 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * The Capture code for Fujitsu M-5MOLS ISP
  *
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
 #include <media/m5mols.h>
+#include <media/s5p_fimc.h>
 
 #include "m5mols.h"
 #include "m5mols_reg.h"
 
-static int m5mols_capture_error_handler(struct m5mols_info *info,
-                                       int timeout)
-{
-       int ret;
-
-       /* Disable all interrupts and clear relevant interrupt staus bits */
-       ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE,
-                          info->interrupt & ~(REG_INT_CAPTURE));
-       if (ret)
-               return ret;
-
-       if (timeout == 0)
-               return -ETIMEDOUT;
-
-       return 0;
-}
 /**
  * m5mols_read_rational - I2C read of a rational number
  *
@@ -121,69 +107,54 @@ int m5mols_start_capture(struct m5mols_info *info)
 {
        struct v4l2_subdev *sd = &info->sd;
        u8 resolution = info->resolution;
-       int timeout;
        int ret;
 
        /*
-        * Preparing capture. Setting control & interrupt before entering
-        * capture mode
-        *
-        * 1) change to MONITOR mode for operating control & interrupt
-        * 2) set controls (considering v4l2_control value & lock 3A)
-        * 3) set interrupt
-        * 4) change to CAPTURE mode
+        * Synchronize the controls, set the capture frame resolution and color
+        * format. The frame capture is initiated during switching from Monitor
+        * to Capture mode.
         */
        ret = m5mols_mode(info, REG_MONITOR);
        if (!ret)
-               ret = m5mols_sync_controls(info);
+               ret = m5mols_restore_controls(info);
        if (!ret)
-               ret = m5mols_lock_3a(info, true);
+               ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG);
+       if (!ret)
+               ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution);
        if (!ret)
-               ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
+               ret = m5mols_lock_3a(info, true);
        if (!ret)
                ret = m5mols_mode(info, REG_CAPTURE);
-       if (!ret) {
-               /* Wait for capture interrupt, after changing capture mode */
-               timeout = wait_event_interruptible_timeout(info->irq_waitq,
-                                          test_bit(ST_CAPT_IRQ, &info->flags),
-                                          msecs_to_jiffies(2000));
-               if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags))
-                       ret = m5mols_capture_error_handler(info, timeout);
-       }
+       if (!ret)
+               /* Wait until a frame is captured to ISP internal memory */
+               ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
        if (!ret)
                ret = m5mols_lock_3a(info, false);
        if (ret)
                return ret;
+
        /*
-        * Starting capture. Setting capture frame count and resolution and
-        * the format(available format: JPEG, Bayer RAW, YUV).
-        *
-        * 1) select single or multi(enable to 25), format, size
-        * 2) set interrupt
-        * 3) start capture(for main image, now)
-        * 4) get information
-        * 5) notify file size to v4l2 device(e.g, to s5p-fimc v4l2 device)
+        * Initiate the captured data transfer to a MIPI-CSI receiver.
         */
        ret = m5mols_write(sd, CAPC_SEL_FRAME, 1);
-       if (!ret)
-               ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG);
-       if (!ret)
-               ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution);
-       if (!ret)
-               ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
        if (!ret)
                ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN);
        if (!ret) {
+               bool captured = false;
+               unsigned int size;
+
                /* Wait for the capture completion interrupt */
-               timeout = wait_event_interruptible_timeout(info->irq_waitq,
-                                          test_bit(ST_CAPT_IRQ, &info->flags),
-                                          msecs_to_jiffies(2000));
-               if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) {
+               ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
+               if (!ret) {
+                       captured = true;
                        ret = m5mols_capture_info(info);
-                       if (!ret)
-                               v4l2_subdev_notify(sd, 0, &info->cap.total);
                }
+               size = captured ? info->cap.main : 0;
+               v4l2_dbg(1, m5mols_debug, sd, "%s: size: %d, thumb.: %d B\n",
+                        __func__, size, info->cap.thumb);
+
+               v4l2_subdev_notify(sd, S5P_FIMC_TX_END_NOTIFY, &size);
        }
 
-       return m5mols_capture_error_handler(info, timeout);
+       return ret;
 }
index e0f09e531800d193c1cb0250cb89d820d7fa1236..93d768db9f3328b152bf8f1a98329fc475c11d2d 100644 (file)
@@ -135,10 +135,13 @@ static u32 m5mols_swap_byte(u8 *data, u8 length)
  * @reg: combination of size, category and command for the I2C packet
  * @size: desired size of I2C packet
  * @val: read value
+ *
+ * Returns 0 on success, or else negative errno.
  */
 static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct m5mols_info *info = to_m5mols(sd);
        u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1];
        u8 category = I2C_CATEGORY(reg);
        u8 cmd = I2C_COMMAND(reg);
@@ -168,15 +171,17 @@ static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val)
        usleep_range(200, 200);
 
        ret = i2c_transfer(client->adapter, msg, 2);
-       if (ret < 0) {
-               v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n",
-                        size, category, cmd, ret);
-               return ret;
+
+       if (ret == 2) {
+               *val = m5mols_swap_byte(&rbuf[1], size);
+               return 0;
        }
 
-       *val = m5mols_swap_byte(&rbuf[1], size);
+       if (info->isp_ready)
+               v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n",
+                        size, category, cmd, ret);
 
-       return 0;
+       return ret < 0 ? ret : -EIO;
 }
 
 int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val)
@@ -229,10 +234,13 @@ int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val)
  * m5mols_write - I2C command write function
  * @reg: combination of size, category and command for the I2C packet
  * @val: value to write
+ *
+ * Returns 0 on success, or else negative errno.
  */
 int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct m5mols_info *info = to_m5mols(sd);
        u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4];
        u8 category = I2C_CATEGORY(reg);
        u8 cmd = I2C_COMMAND(reg);
@@ -263,28 +271,45 @@ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
        usleep_range(200, 200);
 
        ret = i2c_transfer(client->adapter, msg, 1);
-       if (ret < 0) {
-               v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n",
-                       size, category, cmd, ret);
-               return ret;
-       }
+       if (ret == 1)
+               return 0;
 
-       return 0;
+       if (info->isp_ready)
+               v4l2_err(sd, "write failed: cat:%02x cmd:%02x ret:%d\n",
+                        category, cmd, ret);
+
+       return ret < 0 ? ret : -EIO;
 }
 
-int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 mask)
+/**
+ * m5mols_busy_wait - Busy waiting with I2C register polling
+ * @reg: the I2C_REG() address of an 8-bit status register to check
+ * @value: expected status register value
+ * @mask: bit mask for the read status register value
+ * @timeout: timeout in miliseconds, or -1 for default timeout
+ *
+ * The @reg register value is ORed with @mask before comparing with @value.
+ *
+ * Return: 0 if the requested condition became true within less than
+ *         @timeout ms, or else negative errno.
+ */
+int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
+                    int timeout)
 {
-       u8 busy;
-       int i;
-       int ret;
+       int ms = timeout < 0 ? M5MOLS_BUSY_WAIT_DEF_TIMEOUT : timeout;
+       unsigned long end = jiffies + msecs_to_jiffies(ms);
+       u8 status;
 
-       for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) {
-               ret = m5mols_read_u8(sd, I2C_REG(category, cmd, 1), &busy);
-               if (ret < 0)
+       do {
+               int ret = m5mols_read_u8(sd, reg, &status);
+
+               if (ret < 0 && !(mask & M5MOLS_I2C_RDY_WAIT_FL))
                        return ret;
-               if ((busy & mask) == mask)
+               if (!ret && (status & mask & 0xff) == (value & 0xff))
                        return 0;
-       }
+               usleep_range(100, 250);
+       } while (ms > 0 && time_is_after_jiffies(end));
+
        return -EBUSY;
 }
 
@@ -307,6 +332,20 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg)
        return ret;
 }
 
+int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 irq_mask, u32 timeout)
+{
+       struct m5mols_info *info = to_m5mols(sd);
+
+       int ret = wait_event_interruptible_timeout(info->irq_waitq,
+                               atomic_add_unless(&info->irq_done, -1, 0),
+                               msecs_to_jiffies(timeout));
+       if (ret <= 0)
+               return ret ? ret : -ETIMEDOUT;
+
+       return m5mols_busy_wait(sd, SYSTEM_INT_FACTOR, irq_mask,
+                               M5MOLS_I2C_RDY_WAIT_FL | irq_mask, -1);
+}
+
 /**
  * m5mols_reg_mode - Write the mode and check busy status
  *
@@ -316,8 +355,10 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg)
 static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode)
 {
        int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode);
-
-       return ret ? ret : m5mols_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode);
+       if (ret < 0)
+               return ret;
+       return m5mols_busy_wait(sd, SYSTEM_SYSMODE, mode, 0xff,
+                               M5MOLS_MODE_CHANGE_TIMEOUT);
 }
 
 /**
@@ -338,13 +379,13 @@ int m5mols_mode(struct m5mols_info *info, u8 mode)
                return ret;
 
        ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, &reg);
-       if ((!ret && reg == mode) || ret)
+       if (ret || reg == mode)
                return ret;
 
        switch (reg) {
        case REG_PARAMETER:
                ret = m5mols_reg_mode(sd, REG_MONITOR);
-               if (!ret && mode == REG_MONITOR)
+               if (mode == REG_MONITOR)
                        break;
                if (!ret)
                        ret = m5mols_reg_mode(sd, REG_CAPTURE);
@@ -361,7 +402,7 @@ int m5mols_mode(struct m5mols_info *info, u8 mode)
 
        case REG_CAPTURE:
                ret = m5mols_reg_mode(sd, REG_MONITOR);
-               if (!ret && mode == REG_MONITOR)
+               if (mode == REG_MONITOR)
                        break;
                if (!ret)
                        ret = m5mols_reg_mode(sd, REG_PARAMETER);
@@ -570,26 +611,25 @@ static struct v4l2_subdev_pad_ops m5mols_pad_ops = {
 };
 
 /**
- * m5mols_sync_controls - Apply default scene mode and the current controls
+ * m5mols_restore_controls - Apply current control values to the registers
  *
- * This is used only streaming for syncing between v4l2_ctrl framework and
- * m5mols's controls. First, do the scenemode to the sensor, then call
- * v4l2_ctrl_handler_setup. It can be same between some commands and
- * the scenemode's in the default v4l2_ctrls. But, such commands of control
- * should be prior to the scenemode's one.
+ * m5mols_do_scenemode() handles all parameters for which there is yet no
+ * individual control. It should be replaced at some point by setting each
+ * control individually, in required register set up order.
  */
-int m5mols_sync_controls(struct m5mols_info *info)
+int m5mols_restore_controls(struct m5mols_info *info)
 {
-       int ret = -EINVAL;
+       int ret;
 
-       if (!is_ctrl_synced(info)) {
-               ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL);
-               if (ret)
-                       return ret;
+       if (info->ctrl_sync)
+               return 0;
 
-               v4l2_ctrl_handler_setup(&info->handle);
-               info->ctrl_sync = true;
-       }
+       ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL);
+       if (ret)
+               return ret;
+
+       ret = v4l2_ctrl_handler_setup(&info->handle);
+       info->ctrl_sync = !ret;
 
        return ret;
 }
@@ -613,7 +653,7 @@ static int m5mols_start_monitor(struct m5mols_info *info)
        if (!ret)
                ret = m5mols_mode(info, REG_MONITOR);
        if (!ret)
-               ret = m5mols_sync_controls(info);
+               ret = m5mols_restore_controls(info);
 
        return ret;
 }
@@ -645,17 +685,25 @@ static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct v4l2_subdev *sd = to_sd(ctrl);
        struct m5mols_info *info = to_m5mols(sd);
+       int ispstate = info->mode;
        int ret;
 
-       info->mode_save = info->mode;
+       /*
+        * If needed, defer restoring the controls until
+        * the device is fully initialized.
+        */
+       if (!info->isp_ready) {
+               info->ctrl_sync = 0;
+               return 0;
+       }
 
        ret = m5mols_mode(info, REG_PARAMETER);
-       if (!ret)
-               ret = m5mols_set_ctrl(ctrl);
-       if (!ret)
-               ret = m5mols_mode(info, info->mode_save);
-
-       return ret;
+       if (ret < 0)
+               return ret;
+       ret = m5mols_set_ctrl(ctrl);
+       if (ret < 0)
+               return ret;
+       return m5mols_mode(info, ispstate);
 }
 
 static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
@@ -669,10 +717,10 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
        const struct m5mols_platform_data *pdata = info->pdata;
        int ret;
 
-       if (enable) {
-               if (is_powered(info))
-                       return 0;
+       if (info->power == enable)
+               return 0;
 
+       if (enable) {
                if (info->set_power) {
                        ret = info->set_power(&client->dev, 1);
                        if (ret)
@@ -686,15 +734,11 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
                }
 
                gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity);
-               usleep_range(1000, 1000);
-               info->power = true;
+               info->power = 1;
 
                return ret;
        }
 
-       if (!is_powered(info))
-               return 0;
-
        ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
        if (ret)
                return ret;
@@ -703,8 +747,9 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
                info->set_power(&client->dev, 0);
 
        gpio_set_value(pdata->gpio_reset, pdata->reset_polarity);
-       usleep_range(1000, 1000);
-       info->power = false;
+
+       info->isp_ready = 0;
+       info->power = 0;
 
        return ret;
 }
@@ -717,21 +762,29 @@ int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd,
 }
 
 /**
- * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core.
+ * m5mols_fw_start - M-5MOLS internal ARM controller initialization
  *
- * Booting internal ARM core makes the M-5MOLS is ready for getting commands
- * with I2C. It's the first thing to be done after it powered up. It must wait
- * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting.
+ * Execute the M-5MOLS internal ARM controller initialization sequence.
+ * This function should be called after the supply voltage has been
+ * applied and before any requests to the device are made.
  */
-static int m5mols_sensor_armboot(struct v4l2_subdev *sd)
+static int m5mols_fw_start(struct v4l2_subdev *sd)
 {
+       struct m5mols_info *info = to_m5mols(sd);
        int ret;
 
-       ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT);
+       atomic_set(&info->irq_done, 0);
+       /* Wait until I2C slave is initialized in Flash Writer mode */
+       ret = m5mols_busy_wait(sd, FLASH_CAM_START, REG_IN_FLASH_MODE,
+                              M5MOLS_I2C_RDY_WAIT_FL | 0xff, -1);
+       if (!ret)
+               ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT);
+       if (!ret)
+               ret = m5mols_wait_interrupt(sd, REG_INT_MODE, 2000);
        if (ret < 0)
                return ret;
 
-       msleep(520);
+       info->isp_ready = 1;
 
        ret = m5mols_get_version(sd);
        if (!ret)
@@ -743,7 +796,8 @@ static int m5mols_sensor_armboot(struct v4l2_subdev *sd)
 
        ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI);
        if (!ret)
-               ret = m5mols_enable_interrupt(sd, REG_INT_AF);
+               ret = m5mols_enable_interrupt(sd,
+                               REG_INT_AF | REG_INT_CAPTURE);
 
        return ret;
 }
@@ -780,7 +834,7 @@ static int m5mols_init_controls(struct m5mols_info *info)
                        4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE);
        info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle,
                        &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
-                       1, 0, V4L2_EXPOSURE_MANUAL);
+                       1, 0, V4L2_EXPOSURE_AUTO);
 
        sd->ctrl_handler = &info->handle;
        if (info->handle.error) {
@@ -809,16 +863,7 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on)
        if (on) {
                ret = m5mols_sensor_power(info, true);
                if (!ret)
-                       ret = m5mols_sensor_armboot(sd);
-               if (!ret)
-                       ret = m5mols_init_controls(info);
-               if (ret)
-                       return ret;
-
-               info->ffmt[M5MOLS_RESTYPE_MONITOR] =
-                       m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR];
-               info->ffmt[M5MOLS_RESTYPE_CAPTURE] =
-                       m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE];
+                       ret = m5mols_fw_start(sd);
                return ret;
        }
 
@@ -829,17 +874,14 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on)
                if (!ret)
                        ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF);
                if (!ret)
-                       ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS,
-                                       REG_AF_IDLE);
-               if (!ret)
-                       v4l2_info(sd, "Success soft-landing lens\n");
+                       ret = m5mols_busy_wait(sd, SYSTEM_STATUS, REG_AF_IDLE,
+                                              0xff, -1);
+               if (ret < 0)
+                       v4l2_warn(sd, "Soft landing lens failed\n");
        }
 
        ret = m5mols_sensor_power(info, false);
-       if (!ret) {
-               v4l2_ctrl_handler_free(&info->handle);
-               info->ctrl_sync = false;
-       }
+       info->ctrl_sync = 0;
 
        return ret;
 }
@@ -865,52 +907,33 @@ static const struct v4l2_subdev_core_ops m5mols_core_ops = {
        .log_status     = m5mols_log_status,
 };
 
+/*
+ * V4L2 subdev internal operations
+ */
+static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+
+       *format = m5mols_default_ffmt[0];
+       return 0;
+}
+
+static const struct v4l2_subdev_internal_ops m5mols_subdev_internal_ops = {
+       .open           = m5mols_open,
+};
+
 static const struct v4l2_subdev_ops m5mols_ops = {
        .core           = &m5mols_core_ops,
        .pad            = &m5mols_pad_ops,
        .video          = &m5mols_video_ops,
 };
 
-static void m5mols_irq_work(struct work_struct *work)
-{
-       struct m5mols_info *info =
-               container_of(work, struct m5mols_info, work_irq);
-       struct v4l2_subdev *sd = &info->sd;
-       u8 reg;
-       int ret;
-
-       if (!is_powered(info) ||
-                       m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt))
-               return;
-
-       switch (info->interrupt & REG_INT_MASK) {
-       case REG_INT_AF:
-               if (!is_available_af(info))
-                       break;
-               ret = m5mols_read_u8(sd, AF_STATUS, &reg);
-               v4l2_dbg(2, m5mols_debug, sd, "AF %s\n",
-                        reg == REG_AF_FAIL ? "Failed" :
-                        reg == REG_AF_SUCCESS ? "Success" :
-                        reg == REG_AF_IDLE ? "Idle" : "Busy");
-               break;
-       case REG_INT_CAPTURE:
-               if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags))
-                       wake_up_interruptible(&info->irq_waitq);
-
-               v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n");
-               break;
-       default:
-               v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg);
-               break;
-       };
-}
-
 static irqreturn_t m5mols_irq_handler(int irq, void *data)
 {
-       struct v4l2_subdev *sd = data;
-       struct m5mols_info *info = to_m5mols(sd);
+       struct m5mols_info *info = to_m5mols(data);
 
-       schedule_work(&info->work_irq);
+       atomic_set(&info->irq_done, 1);
+       wake_up_interruptible(&info->irq_waitq);
 
        return IRQ_HANDLED;
 }
@@ -961,7 +984,9 @@ static int __devinit m5mols_probe(struct i2c_client *client,
        sd = &info->sd;
        strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
        v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
+       sd->internal_ops = &m5mols_subdev_internal_ops;
        info->pad.flags = MEDIA_PAD_FL_SOURCE;
        ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
        if (ret < 0)
@@ -969,7 +994,6 @@ static int __devinit m5mols_probe(struct i2c_client *client,
        sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
 
        init_waitqueue_head(&info->irq_waitq);
-       INIT_WORK(&info->work_irq, m5mols_irq_work);
        ret = request_irq(client->irq, m5mols_irq_handler,
                          IRQF_TRIGGER_RISING, MODULE_NAME, sd);
        if (ret) {
@@ -977,7 +1001,20 @@ static int __devinit m5mols_probe(struct i2c_client *client,
                goto out_me;
        }
        info->res_type = M5MOLS_RESTYPE_MONITOR;
-       return 0;
+       info->ffmt[0] = m5mols_default_ffmt[0];
+       info->ffmt[1] = m5mols_default_ffmt[1];
+
+       ret = m5mols_sensor_power(info, true);
+       if (ret)
+               goto out_me;
+
+       ret = m5mols_fw_start(sd);
+       if (!ret)
+               ret = m5mols_init_controls(info);
+
+       m5mols_sensor_power(info, false);
+       if (!ret)
+               return 0;
 out_me:
        media_entity_cleanup(&sd->entity);
 out_reg:
@@ -995,6 +1032,7 @@ static int __devexit m5mols_remove(struct i2c_client *client)
        struct m5mols_info *info = to_m5mols(sd);
 
        v4l2_device_unregister_subdev(sd);
+       v4l2_ctrl_handler_free(sd->ctrl_handler);
        free_irq(client->irq, sd);
 
        regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
index c755bd6edfe9b0a485731e641766d39396356ee0..ae4aced0f9b23b0789c69647f2810c9cf98426a7 100644 (file)
  * There is many registers between customer version address and awb one. For
  * more specific contents, see definition if file m5mols.h.
  */
-#define CAT0_VER_CUSTOMER      0x00    /* customer version */
-#define CAT0_VER_PROJECT       0x01    /* project version */
-#define CAT0_VER_FIRMWARE      0x02    /* Firmware version */
-#define CAT0_VER_HARDWARE      0x04    /* Hardware version */
-#define CAT0_VER_PARAMETER     0x06    /* Parameter version */
-#define CAT0_VER_AWB           0x08    /* Auto WB version */
-#define CAT0_VER_STRING                0x0a    /* string including M-5MOLS */
-#define CAT0_SYSMODE           0x0b    /* SYSTEM mode register */
-#define CAT0_STATUS            0x0c    /* SYSTEM mode status register */
-#define CAT0_INT_FACTOR                0x10    /* interrupt pending register */
-#define CAT0_INT_ENABLE                0x11    /* interrupt enable register */
-
-#define SYSTEM_VER_CUSTOMER    I2C_REG(CAT_SYSTEM, CAT0_VER_CUSTOMER, 1)
-#define SYSTEM_VER_PROJECT     I2C_REG(CAT_SYSTEM, CAT0_VER_PROJECT, 1)
-#define SYSTEM_VER_FIRMWARE    I2C_REG(CAT_SYSTEM, CAT0_VER_FIRMWARE, 2)
-#define SYSTEM_VER_HARDWARE    I2C_REG(CAT_SYSTEM, CAT0_VER_HARDWARE, 2)
-#define SYSTEM_VER_PARAMETER   I2C_REG(CAT_SYSTEM, CAT0_VER_PARAMETER, 2)
-#define SYSTEM_VER_AWB         I2C_REG(CAT_SYSTEM, CAT0_VER_AWB, 2)
-
-#define SYSTEM_SYSMODE         I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1)
+#define SYSTEM_VER_CUSTOMER    I2C_REG(CAT_SYSTEM, 0x00, 1)
+#define SYSTEM_VER_PROJECT     I2C_REG(CAT_SYSTEM, 0x01, 1)
+#define SYSTEM_VER_FIRMWARE    I2C_REG(CAT_SYSTEM, 0x02, 2)
+#define SYSTEM_VER_HARDWARE    I2C_REG(CAT_SYSTEM, 0x04, 2)
+#define SYSTEM_VER_PARAMETER   I2C_REG(CAT_SYSTEM, 0x06, 2)
+#define SYSTEM_VER_AWB         I2C_REG(CAT_SYSTEM, 0x08, 2)
+
+#define SYSTEM_SYSMODE         I2C_REG(CAT_SYSTEM, 0x0b, 1)
 #define REG_SYSINIT            0x00    /* SYSTEM mode */
 #define REG_PARAMETER          0x01    /* PARAMETER mode */
 #define REG_MONITOR            0x02    /* MONITOR mode */
 #define REG_CAPTURE            0x03    /* CAPTURE mode */
 
 #define SYSTEM_CMD(__cmd)      I2C_REG(CAT_SYSTEM, cmd, 1)
-#define SYSTEM_VER_STRING      I2C_REG(CAT_SYSTEM, CAT0_VER_STRING, 1)
+#define SYSTEM_VER_STRING      I2C_REG(CAT_SYSTEM, 0x0a, 1)
 #define REG_SAMSUNG_ELECTRO    "SE"    /* Samsung Electro-Mechanics */
 #define REG_SAMSUNG_OPTICS     "OP"    /* Samsung Fiber-Optics */
 #define REG_SAMSUNG_TECHWIN    "TB"    /* Samsung Techwin */
+/* SYSTEM mode status */
+#define SYSTEM_STATUS  I2C_REG(CAT_SYSTEM, 0x0c, 1)
 
-#define SYSTEM_INT_FACTOR      I2C_REG(CAT_SYSTEM, CAT0_INT_FACTOR, 1)
-#define SYSTEM_INT_ENABLE      I2C_REG(CAT_SYSTEM, CAT0_INT_ENABLE, 1)
+/* Interrupt pending register */
+#define SYSTEM_INT_FACTOR      I2C_REG(CAT_SYSTEM, 0x10, 1)
+/* interrupt enable register */
+#define SYSTEM_INT_ENABLE      I2C_REG(CAT_SYSTEM, 0x11, 1)
 #define REG_INT_MODE           (1 << 0)
 #define REG_INT_AF             (1 << 1)
 #define REG_INT_ZOOM           (1 << 2)
  * can handle with preview(MONITOR) resolution size/frame per second/interface
  * between the sensor and the Application Processor/even the image effect.
  */
-#define CAT1_DATA_INTERFACE    0x00    /* interface between sensor and AP */
-#define CAT1_MONITOR_SIZE      0x01    /* resolution at the MONITOR mode */
-#define CAT1_MONITOR_FPS       0x02    /* frame per second at this mode */
-#define CAT1_EFFECT            0x0b    /* image effects */
 
-#define PARM_MON_SIZE          I2C_REG(CAT_PARAM, CAT1_MONITOR_SIZE, 1)
+/* Resolution in the MONITOR mode */
+#define PARM_MON_SIZE          I2C_REG(CAT_PARAM, 0x01, 1)
 
-#define PARM_MON_FPS           I2C_REG(CAT_PARAM, CAT1_MONITOR_FPS, 1)
+/* Frame rate */
+#define PARM_MON_FPS           I2C_REG(CAT_PARAM, 0x02, 1)
 #define REG_FPS_30             0x02
 
-#define PARM_INTERFACE         I2C_REG(CAT_PARAM, CAT1_DATA_INTERFACE, 1)
+/* Video bus between the sensor and a host processor */
+#define PARM_INTERFACE         I2C_REG(CAT_PARAM, 0x00, 1)
 #define REG_INTERFACE_MIPI     0x02
 
-#define PARM_EFFECT            I2C_REG(CAT_PARAM, CAT1_EFFECT, 1)
+/* Image effects */
+#define PARM_EFFECT            I2C_REG(CAT_PARAM, 0x0b, 1)
 #define REG_EFFECT_OFF         0x00
 #define REG_EFFECT_NEGA                0x01
 #define REG_EFFECT_EMBOSS      0x06
  * another options like zoom/color effect(different with effect in PARAMETER
  * mode)/anti hand shaking algorithm.
  */
-#define CAT2_ZOOM              0x01    /* set the zoom position & execute */
-#define CAT2_ZOOM_STEP         0x03    /* set the zoom step */
-#define CAT2_CFIXB             0x09    /* CB value for color effect */
-#define CAT2_CFIXR             0x0a    /* CR value for color effect */
-#define CAT2_COLOR_EFFECT      0x0b    /* set on/off of color effect */
-#define CAT2_CHROMA_LVL                0x0f    /* set chroma level */
-#define CAT2_CHROMA_EN         0x10    /* set on/off of choroma */
-#define CAT2_EDGE_LVL          0x11    /* set sharpness level */
-#define CAT2_EDGE_EN           0x12    /* set on/off sharpness */
-#define CAT2_TONE_CTL          0x25    /* set tone color(contrast) */
-
-#define MON_ZOOM               I2C_REG(CAT_MONITOR, CAT2_ZOOM, 1)
-
-#define MON_CFIXR              I2C_REG(CAT_MONITOR, CAT2_CFIXR, 1)
-#define MON_CFIXB              I2C_REG(CAT_MONITOR, CAT2_CFIXB, 1)
+
+/* Target digital zoom position */
+#define MON_ZOOM               I2C_REG(CAT_MONITOR, 0x01, 1)
+
+/* CR value for color effect */
+#define MON_CFIXR              I2C_REG(CAT_MONITOR, 0x0a, 1)
+/* CB value for color effect */
+#define MON_CFIXB              I2C_REG(CAT_MONITOR, 0x09, 1)
 #define REG_CFIXB_SEPIA                0xd8
 #define REG_CFIXR_SEPIA                0x18
 
-#define MON_EFFECT             I2C_REG(CAT_MONITOR, CAT2_COLOR_EFFECT, 1)
+#define MON_EFFECT             I2C_REG(CAT_MONITOR, 0x0b, 1)
 #define REG_COLOR_EFFECT_OFF   0x00
 #define REG_COLOR_EFFECT_ON    0x01
 
-#define MON_CHROMA_EN          I2C_REG(CAT_MONITOR, CAT2_CHROMA_EN, 1)
-#define MON_CHROMA_LVL         I2C_REG(CAT_MONITOR, CAT2_CHROMA_LVL, 1)
+/* Chroma enable */
+#define MON_CHROMA_EN          I2C_REG(CAT_MONITOR, 0x10, 1)
+/* Chroma level */
+#define MON_CHROMA_LVL         I2C_REG(CAT_MONITOR, 0x0f, 1)
 #define REG_CHROMA_OFF         0x00
 #define REG_CHROMA_ON          0x01
 
-#define MON_EDGE_EN            I2C_REG(CAT_MONITOR, CAT2_EDGE_EN, 1)
-#define MON_EDGE_LVL           I2C_REG(CAT_MONITOR, CAT2_EDGE_LVL, 1)
+/* Sharpness on/off */
+#define MON_EDGE_EN            I2C_REG(CAT_MONITOR, 0x12, 1)
+/* Sharpness level */
+#define MON_EDGE_LVL           I2C_REG(CAT_MONITOR, 0x11, 1)
 #define REG_EDGE_OFF           0x00
 #define REG_EDGE_ON            0x01
 
-#define MON_TONE_CTL           I2C_REG(CAT_MONITOR, CAT2_TONE_CTL, 1)
+/* Set color tone (contrast) */
+#define MON_TONE_CTL           I2C_REG(CAT_MONITOR, 0x25, 1)
 
 /*
  * Category 3 - Auto Exposure
  * different. So, this category also provide getting the max/min values. And,
  * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values.
  */
-#define CAT3_AE_LOCK           0x00    /* locking Auto exposure */
-#define CAT3_AE_MODE           0x01    /* set AE mode, mode means range */
-#define CAT3_ISO               0x05    /* set ISO */
-#define CAT3_EV_PRESET_MONITOR 0x0a    /* EV(scenemode) preset for MONITOR */
-#define CAT3_EV_PRESET_CAPTURE 0x0b    /* EV(scenemode) preset for CAPTURE */
-#define CAT3_MANUAL_GAIN_MON   0x12    /* meteoring value for the MONITOR */
-#define CAT3_MAX_GAIN_MON      0x1a    /* max gain value for the MONITOR */
-#define CAT3_MANUAL_GAIN_CAP   0x26    /* meteoring value for the CAPTURE */
-#define CAT3_AE_INDEX          0x38    /* AE index */
-
-#define AE_LOCK                        I2C_REG(CAT_AE, CAT3_AE_LOCK, 1)
+
+/* Auto Exposure locking */
+#define AE_LOCK                        I2C_REG(CAT_AE, 0x00, 1)
 #define REG_AE_UNLOCK          0x00
 #define REG_AE_LOCK            0x01
 
-#define AE_MODE                        I2C_REG(CAT_AE, CAT3_AE_MODE, 1)
+/* Auto Exposure algorithm mode */
+#define AE_MODE                        I2C_REG(CAT_AE, 0x01, 1)
 #define REG_AE_OFF             0x00    /* AE off */
 #define REG_AE_ALL             0x01    /* calc AE in all block integral */
 #define REG_AE_CENTER          0x03    /* calc AE in center weighted */
 #define REG_AE_SPOT            0x06    /* calc AE in specific spot */
 
-#define AE_ISO                 I2C_REG(CAT_AE, CAT3_ISO, 1)
+#define AE_ISO                 I2C_REG(CAT_AE, 0x05, 1)
 #define REG_ISO_AUTO           0x00
 #define REG_ISO_50             0x01
 #define REG_ISO_100            0x02
 #define REG_ISO_400            0x04
 #define REG_ISO_800            0x05
 
-#define AE_EV_PRESET_MONITOR   I2C_REG(CAT_AE, CAT3_EV_PRESET_MONITOR, 1)
-#define AE_EV_PRESET_CAPTURE   I2C_REG(CAT_AE, CAT3_EV_PRESET_CAPTURE, 1)
+/* EV (scenemode) preset for MONITOR */
+#define AE_EV_PRESET_MONITOR   I2C_REG(CAT_AE, 0x0a, 1)
+/* EV (scenemode) preset for CAPTURE */
+#define AE_EV_PRESET_CAPTURE   I2C_REG(CAT_AE, 0x0b, 1)
 #define REG_SCENE_NORMAL       0x00
 #define REG_SCENE_PORTRAIT     0x01
 #define REG_SCENE_LANDSCAPE    0x02
 #define REG_SCENE_TEXT         0x0c
 #define REG_SCENE_CANDLE       0x0d
 
-#define AE_MAN_GAIN_MON                I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_MON, 2)
-#define AE_MAX_GAIN_MON                I2C_REG(CAT_AE, CAT3_MAX_GAIN_MON, 2)
-#define AE_MAN_GAIN_CAP                I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_CAP, 2)
+/* Manual gain in MONITOR mode */
+#define AE_MAN_GAIN_MON                I2C_REG(CAT_AE, 0x12, 2)
+/* Maximum gain in MONITOR mode */
+#define AE_MAX_GAIN_MON                I2C_REG(CAT_AE, 0x1a, 2)
+/* Manual gain in CAPTURE mode */
+#define AE_MAN_GAIN_CAP                I2C_REG(CAT_AE, 0x26, 2)
 
-#define AE_INDEX               I2C_REG(CAT_AE, CAT3_AE_INDEX, 1)
+#define AE_INDEX               I2C_REG(CAT_AE, 0x38, 1)
 #define REG_AE_INDEX_20_NEG    0x00
 #define REG_AE_INDEX_15_NEG    0x01
 #define REG_AE_INDEX_10_NEG    0x02
 
 /*
  * Category 6 - White Balance
- *
- * This category provide AWB locking/mode/preset/speed/gain bias, etc.
  */
-#define CAT6_AWB_LOCK          0x00    /* locking Auto Whitebalance */
-#define CAT6_AWB_MODE          0x02    /* set Auto or Manual */
-#define CAT6_AWB_MANUAL                0x03    /* set Manual(preset) value */
 
-#define AWB_LOCK               I2C_REG(CAT_WB, CAT6_AWB_LOCK, 1)
+/* Auto Whitebalance locking */
+#define AWB_LOCK               I2C_REG(CAT_WB, 0x00, 1)
 #define REG_AWB_UNLOCK         0x00
 #define REG_AWB_LOCK           0x01
 
-#define AWB_MODE               I2C_REG(CAT_WB, CAT6_AWB_MODE, 1)
+#define AWB_MODE               I2C_REG(CAT_WB, 0x02, 1)
 #define REG_AWB_AUTO           0x01    /* AWB off */
 #define REG_AWB_PRESET         0x02    /* AWB preset */
 
-#define AWB_MANUAL             I2C_REG(CAT_WB, CAT6_AWB_MANUAL, 1)
+/* Manual WB (preset) */
+#define AWB_MANUAL             I2C_REG(CAT_WB, 0x03, 1)
 #define REG_AWB_INCANDESCENT   0x01
 #define REG_AWB_FLUORESCENT_1  0x02
 #define REG_AWB_FLUORESCENT_2  0x03
 /*
  * Category 7 - EXIF information
  */
-#define CAT7_INFO_EXPTIME_NU   0x00
-#define CAT7_INFO_EXPTIME_DE   0x04
-#define CAT7_INFO_TV_NU                0x08
-#define CAT7_INFO_TV_DE                0x0c
-#define CAT7_INFO_AV_NU                0x10
-#define CAT7_INFO_AV_DE                0x14
-#define CAT7_INFO_BV_NU                0x18
-#define CAT7_INFO_BV_DE                0x1c
-#define CAT7_INFO_EBV_NU       0x20
-#define CAT7_INFO_EBV_DE       0x24
-#define CAT7_INFO_ISO          0x28
-#define CAT7_INFO_FLASH                0x2a
-#define CAT7_INFO_SDR          0x2c
-#define CAT7_INFO_QVAL         0x2e
-
-#define EXIF_INFO_EXPTIME_NU   I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_NU, 4)
-#define EXIF_INFO_EXPTIME_DE   I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_DE, 4)
-#define EXIF_INFO_TV_NU                I2C_REG(CAT_EXIF, CAT7_INFO_TV_NU, 4)
-#define EXIF_INFO_TV_DE                I2C_REG(CAT_EXIF, CAT7_INFO_TV_DE, 4)
-#define EXIF_INFO_AV_NU                I2C_REG(CAT_EXIF, CAT7_INFO_AV_NU, 4)
-#define EXIF_INFO_AV_DE                I2C_REG(CAT_EXIF, CAT7_INFO_AV_DE, 4)
-#define EXIF_INFO_BV_NU                I2C_REG(CAT_EXIF, CAT7_INFO_BV_NU, 4)
-#define EXIF_INFO_BV_DE                I2C_REG(CAT_EXIF, CAT7_INFO_BV_DE, 4)
-#define EXIF_INFO_EBV_NU       I2C_REG(CAT_EXIF, CAT7_INFO_EBV_NU, 4)
-#define EXIF_INFO_EBV_DE       I2C_REG(CAT_EXIF, CAT7_INFO_EBV_DE, 4)
-#define EXIF_INFO_ISO          I2C_REG(CAT_EXIF, CAT7_INFO_ISO, 2)
-#define EXIF_INFO_FLASH                I2C_REG(CAT_EXIF, CAT7_INFO_FLASH, 2)
-#define EXIF_INFO_SDR          I2C_REG(CAT_EXIF, CAT7_INFO_SDR, 2)
-#define EXIF_INFO_QVAL         I2C_REG(CAT_EXIF, CAT7_INFO_QVAL, 2)
+#define EXIF_INFO_EXPTIME_NU   I2C_REG(CAT_EXIF, 0x00, 4)
+#define EXIF_INFO_EXPTIME_DE   I2C_REG(CAT_EXIF, 0x04, 4)
+#define EXIF_INFO_TV_NU                I2C_REG(CAT_EXIF, 0x08, 4)
+#define EXIF_INFO_TV_DE                I2C_REG(CAT_EXIF, 0x0c, 4)
+#define EXIF_INFO_AV_NU                I2C_REG(CAT_EXIF, 0x10, 4)
+#define EXIF_INFO_AV_DE                I2C_REG(CAT_EXIF, 0x14, 4)
+#define EXIF_INFO_BV_NU                I2C_REG(CAT_EXIF, 0x18, 4)
+#define EXIF_INFO_BV_DE                I2C_REG(CAT_EXIF, 0x1c, 4)
+#define EXIF_INFO_EBV_NU       I2C_REG(CAT_EXIF, 0x20, 4)
+#define EXIF_INFO_EBV_DE       I2C_REG(CAT_EXIF, 0x24, 4)
+#define EXIF_INFO_ISO          I2C_REG(CAT_EXIF, 0x28, 2)
+#define EXIF_INFO_FLASH                I2C_REG(CAT_EXIF, 0x2a, 2)
+#define EXIF_INFO_SDR          I2C_REG(CAT_EXIF, 0x2c, 2)
+#define EXIF_INFO_QVAL         I2C_REG(CAT_EXIF, 0x2e, 2)
 
 /*
  * Category 9 - Face Detection
  */
-#define CAT9_FD_CTL            0x00
-
-#define FD_CTL                 I2C_REG(CAT_FD, CAT9_FD_CTL, 1)
+#define FD_CTL                 I2C_REG(CAT_FD, 0x00, 1)
 #define BIT_FD_EN              0
 #define BIT_FD_DRAW_FACE_FRAME 4
 #define BIT_FD_DRAW_SMILE_LVL  6
 /*
  * Category A - Lens Parameter
  */
-#define CATA_AF_MODE           0x01
-#define CATA_AF_EXECUTE                0x02
-#define CATA_AF_STATUS         0x03
-#define CATA_AF_VERSION                0x0a
-
-#define AF_MODE                        I2C_REG(CAT_LENS, CATA_AF_MODE, 1)
+#define AF_MODE                        I2C_REG(CAT_LENS, 0x01, 1)
 #define REG_AF_NORMAL          0x00    /* Normal AF, one time */
 #define REG_AF_MACRO           0x01    /* Macro AF, one time */
 #define REG_AF_POWEROFF                0x07
 
-#define AF_EXECUTE             I2C_REG(CAT_LENS, CATA_AF_EXECUTE, 1)
+#define AF_EXECUTE             I2C_REG(CAT_LENS, 0x02, 1)
 #define REG_AF_STOP            0x00
 #define REG_AF_EXE_AUTO                0x01
 #define REG_AF_EXE_CAF         0x02
 
-#define AF_STATUS              I2C_REG(CAT_LENS, CATA_AF_STATUS, 1)
+#define AF_STATUS              I2C_REG(CAT_LENS, 0x03, 1)
 #define REG_AF_FAIL            0x00
 #define REG_AF_SUCCESS         0x02
 #define REG_AF_IDLE            0x04
 #define REG_AF_BUSY            0x05
 
-#define AF_VERSION             I2C_REG(CAT_LENS, CATA_AF_VERSION, 1)
+#define AF_VERSION             I2C_REG(CAT_LENS, 0x0a, 1)
 
 /*
  * Category B - CAPTURE Parameter
  */
-#define CATB_YUVOUT_MAIN       0x00
-#define CATB_MAIN_IMAGE_SIZE   0x01
-#define CATB_MCC_MODE          0x1d
-#define CATB_WDR_EN            0x2c
-#define CATB_LIGHT_CTRL                0x40
-#define CATB_FLASH_CTRL                0x41
-
-#define CAPP_YUVOUT_MAIN       I2C_REG(CAT_CAPT_PARM, CATB_YUVOUT_MAIN, 1)
+#define CAPP_YUVOUT_MAIN       I2C_REG(CAT_CAPT_PARM, 0x00, 1)
 #define REG_YUV422             0x00
 #define REG_BAYER10            0x05
 #define REG_BAYER8             0x06
 #define REG_JPEG               0x10
 
-#define CAPP_MAIN_IMAGE_SIZE   I2C_REG(CAT_CAPT_PARM, CATB_MAIN_IMAGE_SIZE, 1)
+#define CAPP_MAIN_IMAGE_SIZE   I2C_REG(CAT_CAPT_PARM, 0x01, 1)
 
-#define CAPP_MCC_MODE          I2C_REG(CAT_CAPT_PARM, CATB_MCC_MODE, 1)
+#define CAPP_MCC_MODE          I2C_REG(CAT_CAPT_PARM, 0x1d, 1)
 #define REG_MCC_OFF            0x00
 #define REG_MCC_NORMAL         0x01
 
-#define CAPP_WDR_EN            I2C_REG(CAT_CAPT_PARM, CATB_WDR_EN, 1)
+#define CAPP_WDR_EN            I2C_REG(CAT_CAPT_PARM, 0x2c, 1)
 #define REG_WDR_OFF            0x00
 #define REG_WDR_ON             0x01
 #define REG_WDR_AUTO           0x02
 
-#define CAPP_LIGHT_CTRL                I2C_REG(CAT_CAPT_PARM, CATB_LIGHT_CTRL, 1)
+#define CAPP_LIGHT_CTRL                I2C_REG(CAT_CAPT_PARM, 0x40, 1)
 #define REG_LIGHT_OFF          0x00
 #define REG_LIGHT_ON           0x01
 #define REG_LIGHT_AUTO         0x02
 
-#define CAPP_FLASH_CTRL                I2C_REG(CAT_CAPT_PARM, CATB_FLASH_CTRL, 1)
+#define CAPP_FLASH_CTRL                I2C_REG(CAT_CAPT_PARM, 0x41, 1)
 #define REG_FLASH_OFF          0x00
 #define REG_FLASH_ON           0x01
 #define REG_FLASH_AUTO         0x02
 /*
  * Category C - CAPTURE Control
  */
-#define CATC_CAP_MODE          0x00
-#define CATC_CAP_SEL_FRAME     0x06    /* It determines Single or Multi */
-#define CATC_CAP_START         0x09
-#define CATC_CAP_IMAGE_SIZE    0x0d
-#define CATC_CAP_THUMB_SIZE    0x11
-
-#define CAPC_MODE              I2C_REG(CAT_CAPT_CTRL, CATC_CAP_MODE, 1)
+#define CAPC_MODE              I2C_REG(CAT_CAPT_CTRL, 0x00, 1)
 #define REG_CAP_NONE           0x00
 #define REG_CAP_ANTI_SHAKE     0x02
 
-#define CAPC_SEL_FRAME         I2C_REG(CAT_CAPT_CTRL, CATC_CAP_SEL_FRAME, 1)
+/* Select single- or multi-shot capture */
+#define CAPC_SEL_FRAME         I2C_REG(CAT_CAPT_CTRL, 0x06, 1)
 
-#define CAPC_START             I2C_REG(CAT_CAPT_CTRL, CATC_CAP_START, 1)
+#define CAPC_START             I2C_REG(CAT_CAPT_CTRL, 0x09, 1)
 #define REG_CAP_START_MAIN     0x01
 #define REG_CAP_START_THUMB    0x03
 
-#define CAPC_IMAGE_SIZE                I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 4)
-#define CAPC_THUMB_SIZE                I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 4)
+#define CAPC_IMAGE_SIZE                I2C_REG(CAT_CAPT_CTRL, 0x0d, 4)
+#define CAPC_THUMB_SIZE                I2C_REG(CAT_CAPT_CTRL, 0x11, 4)
 
 /*
  * Category F - Flash
  *
  * This mode provides functions about internal flash stuff and system startup.
  */
-#define CATF_CAM_START         0x12    /* It starts internal ARM core booting
-                                        * after power-up */
 
-#define FLASH_CAM_START                I2C_REG(CAT_FLASH, CATF_CAM_START, 1)
-#define REG_START_ARM_BOOT     0x01
+/* Starts internal ARM core booting after power-up */
+#define FLASH_CAM_START                I2C_REG(CAT_FLASH, 0x12, 1)
+#define REG_START_ARM_BOOT     0x01    /* write value */
+#define REG_IN_FLASH_MODE      0x00    /* read value */
 
 #endif /* M5MOLS_REG_H */
index 80ec64d2d6d87f8e8fc4dcf4d6da81d67400fbc6..37d20e73908a24402a933740b68d4463532e64eb 100644 (file)
@@ -51,7 +51,7 @@ static int delivered;
  * sense.
  */
 
-static int alloc_bufs_at_read;
+static bool alloc_bufs_at_read;
 module_param(alloc_bufs_at_read, bool, 0444);
 MODULE_PARM_DESC(alloc_bufs_at_read,
                "Non-zero value causes DMA buffers to be allocated when the "
@@ -73,11 +73,11 @@ MODULE_PARM_DESC(dma_buf_size,
                "parameters require larger buffers, an attempt to reallocate "
                "will be made.");
 #else /* MCAM_MODE_VMALLOC */
-static const int alloc_bufs_at_read = 0;
+static const bool alloc_bufs_at_read = 0;
 static const int n_dma_bufs = 3;  /* Used by S/G_PARM */
 #endif /* MCAM_MODE_VMALLOC */
 
-static int flip;
+static bool flip;
 module_param(flip, bool, 0444);
 MODULE_PARM_DESC(flip,
                "If set, the sensor will be instructed to flip the image "
@@ -522,6 +522,15 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam)
  */
 static void mcam_ctlr_dma_sg(struct mcam_camera *cam)
 {
+       /*
+        * The list-empty condition can hit us at resume time
+        * if the buffer list was empty when the system was suspended.
+        */
+       if (list_empty(&cam->buffers)) {
+               set_bit(CF_SG_RESTART, &cam->flags);
+               return;
+       }
+
        mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD);
        mcam_sg_next_buffer(cam);
        mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
@@ -566,6 +575,7 @@ static void mcam_dma_sg_done(struct mcam_camera *cam, int frame)
        } else {
                set_bit(CF_SG_RESTART, &cam->flags);
                singles++;
+               cam->vb_bufs[0] = NULL;
        }
        /*
         * Now we can give the completed frame back to user space.
@@ -661,10 +671,10 @@ static int mcam_ctlr_configure(struct mcam_camera *cam)
        unsigned long flags;
 
        spin_lock_irqsave(&cam->dev_lock, flags);
+       clear_bit(CF_SG_RESTART, &cam->flags);
        cam->dma_setup(cam);
        mcam_ctlr_image(cam);
        mcam_set_config_needed(cam, 0);
-       clear_bit(CF_SG_RESTART, &cam->flags);
        spin_unlock_irqrestore(&cam->dev_lock, flags);
        return 0;
 }
@@ -873,7 +883,8 @@ static int mcam_read_setup(struct mcam_camera *cam)
        mcam_reset_buffers(cam);
        mcam_ctlr_irq_enable(cam);
        cam->state = S_STREAMING;
-       mcam_ctlr_start(cam);
+       if (!test_bit(CF_SG_RESTART, &cam->flags))
+               mcam_ctlr_start(cam);
        spin_unlock_irqrestore(&cam->dev_lock, flags);
        return 0;
 }
@@ -1818,11 +1829,15 @@ void mccic_shutdown(struct mcam_camera *cam)
 
 void mccic_suspend(struct mcam_camera *cam)
 {
-       enum mcam_state cstate = cam->state;
+       mutex_lock(&cam->s_mutex);
+       if (cam->users > 0) {
+               enum mcam_state cstate = cam->state;
 
-       mcam_ctlr_stop_dma(cam);
-       mcam_ctlr_power_down(cam);
-       cam->state = cstate;
+               mcam_ctlr_stop_dma(cam);
+               mcam_ctlr_power_down(cam);
+               cam->state = cstate;
+       }
+       mutex_unlock(&cam->s_mutex);
 }
 
 int mccic_resume(struct mcam_camera *cam)
@@ -1839,8 +1854,15 @@ int mccic_resume(struct mcam_camera *cam)
        mutex_unlock(&cam->s_mutex);
 
        set_bit(CF_CONFIG_NEEDED, &cam->flags);
-       if (cam->state == S_STREAMING)
+       if (cam->state == S_STREAMING) {
+               /*
+                * If there was a buffer in the DMA engine at suspend
+                * time, put it back on the queue or we'll forget about it.
+                */
+               if (cam->buffer_mode == B_DMA_sg && cam->vb_bufs[0])
+                       list_add(&cam->vb_bufs[0]->queue, &cam->buffers);
                ret = mcam_read_setup(cam);
+       }
        return ret;
 }
 #endif /* CONFIG_PM */
index fb0b124b35f302529eadcc9f3eef85db3820a10a..0d64e2d7474a52eebc06bf1dd84314ba7d32d288 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/list.h>
+#include <linux/pm.h>
 
 #include "mcam-core.h"
 
@@ -310,10 +311,44 @@ static int mmpcam_platform_remove(struct platform_device *pdev)
        return mmpcam_remove(cam);
 }
 
+/*
+ * Suspend/resume support.
+ */
+#ifdef CONFIG_PM
+
+static int mmpcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct mmp_camera *cam = mmpcam_find_device(pdev);
+
+       if (state.event != PM_EVENT_SUSPEND)
+               return 0;
+       mccic_suspend(&cam->mcam);
+       return 0;
+}
+
+static int mmpcam_resume(struct platform_device *pdev)
+{
+       struct mmp_camera *cam = mmpcam_find_device(pdev);
+
+       /*
+        * Power up unconditionally just in case the core tries to
+        * touch a register even if nothing was active before; trust
+        * me, it's better this way.
+        */
+       mmpcam_power_up(&cam->mcam);
+       return mccic_resume(&cam->mcam);
+}
+
+#endif
+
 
 static struct platform_driver mmpcam_driver = {
        .probe          = mmpcam_probe,
        .remove         = mmpcam_platform_remove,
+#ifdef CONFIG_PM
+       .suspend        = mmpcam_suspend,
+       .resume         = mmpcam_resume,
+#endif
        .driver = {
                .name   = "mmp-camera",
                .owner  = THIS_MODULE
index d0f5388572855d8fed885a1ed54d1a37db3d7ec1..d7cd0f633f63905c77095b959efa724b7b5ffebc 100644 (file)
@@ -69,12 +69,12 @@ MODULE_LICENSE("GPL");
 /* module parameters */
 static int opmode   = OPMODE_AUTO;
 int msp_debug;          /* msp_debug output */
-int msp_once;           /* no continuous stereo monitoring */
-int msp_amsound;        /* hard-wire AM sound at 6.5 Hz (france),
+bool msp_once;          /* no continuous stereo monitoring */
+bool msp_amsound;       /* hard-wire AM sound at 6.5 Hz (france),
                            the autoscan seems work well only with FM... */
 int msp_standard = 1;    /* Override auto detect of audio msp_standard,
                            if needed. */
-int msp_dolby;
+bool msp_dolby;
 
 int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual
                                        (msp34xxg only) 0x00a0-0x03c0 */
index 831e8db4368c06e23915518b82abb56dde84fcd1..fbe5e0715f9309d0c76fce2ed61fb16d5614a512 100644 (file)
 
 /* module parameters */
 extern int msp_debug;
-extern int msp_once;
-extern int msp_amsound;
+extern bool msp_once;
+extern bool msp_amsound;
 extern int msp_standard;
-extern int msp_dolby;
+extern bool msp_dolby;
 extern int msp_stereo_thresh;
 
 struct msp_state {
index e2b1029b16cdd24552123d67dfc4a44ef51a6359..097c9d3d04a8c581236a928d9eceeaed765d4d72 100644 (file)
@@ -109,14 +109,13 @@ static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
 
 static int reg_read(struct i2c_client *client, const u8 reg)
 {
-       s32 data = i2c_smbus_read_word_data(client, reg);
-       return data < 0 ? data : swab16(data);
+       return i2c_smbus_read_word_swapped(client, reg);
 }
 
 static int reg_write(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
-       return i2c_smbus_write_word_data(client, reg, swab16(data));
+       return i2c_smbus_write_word_swapped(client, reg, data);
 }
 
 static int reg_set(struct i2c_client *client, const u8 reg,
index 398f96ffd35e88d212a8d39c8585decfc1d426d0..bee65bff46e8d5e25e94f49253d8b41484da3438 100644 (file)
 #define MT9M111_MAX_HEIGHT     1024
 #define MT9M111_MAX_WIDTH      1280
 
+struct mt9m111_context {
+       u16 read_mode;
+       u16 blanking_h;
+       u16 blanking_v;
+       u16 reducer_xzoom;
+       u16 reducer_yzoom;
+       u16 reducer_xsize;
+       u16 reducer_ysize;
+       u16 output_fmt_ctrl2;
+       u16 control;
+};
+
+static struct mt9m111_context context_a = {
+       .read_mode              = MT9M111_READ_MODE_A,
+       .blanking_h             = MT9M111_HORIZONTAL_BLANKING_A,
+       .blanking_v             = MT9M111_VERTICAL_BLANKING_A,
+       .reducer_xzoom          = MT9M111_REDUCER_XZOOM_A,
+       .reducer_yzoom          = MT9M111_REDUCER_YZOOM_A,
+       .reducer_xsize          = MT9M111_REDUCER_XSIZE_A,
+       .reducer_ysize          = MT9M111_REDUCER_YSIZE_A,
+       .output_fmt_ctrl2       = MT9M111_OUTPUT_FORMAT_CTRL2_A,
+       .control                = MT9M111_CTXT_CTRL_RESTART,
+};
+
+static struct mt9m111_context context_b = {
+       .read_mode              = MT9M111_READ_MODE_B,
+       .blanking_h             = MT9M111_HORIZONTAL_BLANKING_B,
+       .blanking_v             = MT9M111_VERTICAL_BLANKING_B,
+       .reducer_xzoom          = MT9M111_REDUCER_XZOOM_B,
+       .reducer_yzoom          = MT9M111_REDUCER_YZOOM_B,
+       .reducer_xsize          = MT9M111_REDUCER_XSIZE_B,
+       .reducer_ysize          = MT9M111_REDUCER_YSIZE_B,
+       .output_fmt_ctrl2       = MT9M111_OUTPUT_FORMAT_CTRL2_B,
+       .control                = MT9M111_CTXT_CTRL_RESTART |
+               MT9M111_CTXT_CTRL_DEFECTCOR_B | MT9M111_CTXT_CTRL_RESIZE_B |
+               MT9M111_CTXT_CTRL_CTRL2_B | MT9M111_CTXT_CTRL_GAMMA_B |
+               MT9M111_CTXT_CTRL_READ_MODE_B | MT9M111_CTXT_CTRL_VBLANK_SEL_B |
+               MT9M111_CTXT_CTRL_HBLANK_SEL_B,
+};
+
 /* MT9M111 has only one fixed colorspace per pixelcode */
 struct mt9m111_datafmt {
        enum v4l2_mbus_pixelcode        code;
        enum v4l2_colorspace            colorspace;
 };
 
-/* Find a data format by a pixel code in an array */
-static const struct mt9m111_datafmt *mt9m111_find_datafmt(
-       enum v4l2_mbus_pixelcode code, const struct mt9m111_datafmt *fmt,
-       int n)
-{
-       int i;
-       for (i = 0; i < n; i++)
-               if (fmt[i].code == code)
-                       return fmt + i;
-
-       return NULL;
-}
-
 static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
        {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
        {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
@@ -173,27 +200,35 @@ static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
        {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
 };
 
-enum mt9m111_context {
-       HIGHPOWER = 0,
-       LOWPOWER,
-};
-
 struct mt9m111 {
        struct v4l2_subdev subdev;
        struct v4l2_ctrl_handler hdl;
        struct v4l2_ctrl *gain;
        int model;      /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code
                         * from v4l2-chip-ident.h */
-       enum mt9m111_context context;
-       struct v4l2_rect rect;
+       struct mt9m111_context *ctx;
+       struct v4l2_rect rect;  /* cropping rectangle */
+       int width;              /* output */
+       int height;             /* sizes */
        struct mutex power_lock; /* lock to protect power_count */
        int power_count;
        const struct mt9m111_datafmt *fmt;
        int lastpage;   /* PageMap cache value */
        unsigned char datawidth;
-       unsigned int powered:1;
 };
 
+/* Find a data format by a pixel code */
+static const struct mt9m111_datafmt *mt9m111_find_datafmt(struct mt9m111 *mt9m111,
+                                               enum v4l2_mbus_pixelcode code)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(mt9m111_colour_fmts); i++)
+               if (mt9m111_colour_fmts[i].code == code)
+                       return mt9m111_colour_fmts + i;
+
+       return mt9m111->fmt;
+}
+
 static struct mt9m111 *to_mt9m111(const struct i2c_client *client)
 {
        return container_of(i2c_get_clientdata(client), struct mt9m111, subdev);
@@ -211,7 +246,7 @@ static int reg_page_map_set(struct i2c_client *client, const u16 reg)
        if (page > 2)
                return -EINVAL;
 
-       ret = i2c_smbus_write_word_data(client, MT9M111_PAGE_MAP, swab16(page));
+       ret = i2c_smbus_write_word_swapped(client, MT9M111_PAGE_MAP, page);
        if (!ret)
                mt9m111->lastpage = page;
        return ret;
@@ -223,7 +258,7 @@ static int mt9m111_reg_read(struct i2c_client *client, const u16 reg)
 
        ret = reg_page_map_set(client, reg);
        if (!ret)
-               ret = swab16(i2c_smbus_read_word_data(client, reg & 0xff));
+               ret = i2c_smbus_read_word_swapped(client, reg & 0xff);
 
        dev_dbg(&client->dev, "read  reg.%03x -> %04x\n", reg, ret);
        return ret;
@@ -236,8 +271,7 @@ static int mt9m111_reg_write(struct i2c_client *client, const u16 reg,
 
        ret = reg_page_map_set(client, reg);
        if (!ret)
-               ret = i2c_smbus_write_word_data(client, reg & 0xff,
-                                               swab16(data));
+               ret = i2c_smbus_write_word_swapped(client, reg & 0xff, data);
        dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
        return ret;
 }
@@ -276,76 +310,63 @@ static int mt9m111_reg_mask(struct i2c_client *client, const u16 reg,
 }
 
 static int mt9m111_set_context(struct mt9m111 *mt9m111,
-                              enum mt9m111_context ctxt)
+                              struct mt9m111_context *ctx)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
-       int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
-               | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
-               | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
-               | MT9M111_CTXT_CTRL_VBLANK_SEL_B
-               | MT9M111_CTXT_CTRL_HBLANK_SEL_B;
-       int valA = MT9M111_CTXT_CTRL_RESTART;
-
-       if (ctxt == HIGHPOWER)
-               return reg_write(CONTEXT_CONTROL, valB);
-       else
-               return reg_write(CONTEXT_CONTROL, valA);
+       return reg_write(CONTEXT_CONTROL, ctx->control);
 }
 
-static int mt9m111_setup_rect(struct mt9m111 *mt9m111,
-                             struct v4l2_rect *rect)
+static int mt9m111_setup_rect_ctx(struct mt9m111 *mt9m111,
+                       struct mt9m111_context *ctx, struct v4l2_rect *rect,
+                       unsigned int width, unsigned int height)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
-       int ret, is_raw_format;
-       int width = rect->width;
-       int height = rect->height;
+       int ret = mt9m111_reg_write(client, ctx->reducer_xzoom, rect->width);
+       if (!ret)
+               ret = mt9m111_reg_write(client, ctx->reducer_yzoom, rect->height);
+       if (!ret)
+               ret = mt9m111_reg_write(client, ctx->reducer_xsize, width);
+       if (!ret)
+               ret = mt9m111_reg_write(client, ctx->reducer_ysize, height);
+       return ret;
+}
 
-       if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
-           mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE)
-               is_raw_format = 1;
-       else
-               is_raw_format = 0;
+static int mt9m111_setup_geometry(struct mt9m111 *mt9m111, struct v4l2_rect *rect,
+                       int width, int height, enum v4l2_mbus_pixelcode code)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+       int ret;
 
        ret = reg_write(COLUMN_START, rect->left);
        if (!ret)
                ret = reg_write(ROW_START, rect->top);
 
-       if (is_raw_format) {
-               if (!ret)
-                       ret = reg_write(WINDOW_WIDTH, width);
-               if (!ret)
-                       ret = reg_write(WINDOW_HEIGHT, height);
-       } else {
-               if (!ret)
-                       ret = reg_write(REDUCER_XZOOM_B, MT9M111_MAX_WIDTH);
-               if (!ret)
-                       ret = reg_write(REDUCER_YZOOM_B, MT9M111_MAX_HEIGHT);
-               if (!ret)
-                       ret = reg_write(REDUCER_XSIZE_B, width);
-               if (!ret)
-                       ret = reg_write(REDUCER_YSIZE_B, height);
-               if (!ret)
-                       ret = reg_write(REDUCER_XZOOM_A, MT9M111_MAX_WIDTH);
-               if (!ret)
-                       ret = reg_write(REDUCER_YZOOM_A, MT9M111_MAX_HEIGHT);
+       if (!ret)
+               ret = reg_write(WINDOW_WIDTH, rect->width);
+       if (!ret)
+               ret = reg_write(WINDOW_HEIGHT, rect->height);
+
+       if (code != V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
+               /* IFP in use, down-scaling possible */
                if (!ret)
-                       ret = reg_write(REDUCER_XSIZE_A, width);
+                       ret = mt9m111_setup_rect_ctx(mt9m111, &context_b,
+                                                    rect, width, height);
                if (!ret)
-                       ret = reg_write(REDUCER_YSIZE_A, height);
+                       ret = mt9m111_setup_rect_ctx(mt9m111, &context_a,
+                                                    rect, width, height);
        }
 
+       dev_dbg(&client->dev, "%s(%x): %ux%u@%u:%u -> %ux%u = %d\n",
+               __func__, code, rect->width, rect->height, rect->left, rect->top,
+               width, height, ret);
+
        return ret;
 }
 
 static int mt9m111_enable(struct mt9m111 *mt9m111)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
-       int ret;
-
-       ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE);
-       if (!ret)
-               mt9m111->powered = 1;
-       return ret;
+       return reg_write(RESET, MT9M111_RESET_CHIP_ENABLE);
 }
 
 static int mt9m111_reset(struct mt9m111 *mt9m111)
@@ -363,43 +384,41 @@ static int mt9m111_reset(struct mt9m111 *mt9m111)
        return ret;
 }
 
-static int mt9m111_make_rect(struct mt9m111 *mt9m111,
-                            struct v4l2_rect *rect)
+static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
+       struct v4l2_rect rect = a->c;
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+       int width, height;
+       int ret;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
        if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
            mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
                /* Bayer format - even size lengths */
-               rect->width     = ALIGN(rect->width, 2);
-               rect->height    = ALIGN(rect->height, 2);
+               rect.width      = ALIGN(rect.width, 2);
+               rect.height     = ALIGN(rect.height, 2);
                /* Let the user play with the starting pixel */
        }
 
        /* FIXME: the datasheet doesn't specify minimum sizes */
-       soc_camera_limit_side(&rect->left, &rect->width,
+       soc_camera_limit_side(&rect.left, &rect.width,
                     MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH);
 
-       soc_camera_limit_side(&rect->top, &rect->height,
+       soc_camera_limit_side(&rect.top, &rect.height,
                     MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT);
 
-       return mt9m111_setup_rect(mt9m111, rect);
-}
-
-static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
-       struct v4l2_rect rect = a->c;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
-       int ret;
-
-       dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
-               __func__, rect.left, rect.top, rect.width, rect.height);
+       width = min(mt9m111->width, rect.width);
+       height = min(mt9m111->height, rect.height);
 
-       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       ret = mt9m111_make_rect(mt9m111, &rect);
-       if (!ret)
+       ret = mt9m111_setup_geometry(mt9m111, &rect, width, height, mt9m111->fmt->code);
+       if (!ret) {
                mt9m111->rect = rect;
+               mt9m111->width = width;
+               mt9m111->height = height;
+       }
+
        return ret;
 }
 
@@ -434,8 +453,8 @@ static int mt9m111_g_fmt(struct v4l2_subdev *sd,
 {
        struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
 
-       mf->width       = mt9m111->rect.width;
-       mf->height      = mt9m111->rect.height;
+       mf->width       = mt9m111->width;
+       mf->height      = mt9m111->height;
        mf->code        = mt9m111->fmt->code;
        mf->colorspace  = mt9m111->fmt->colorspace;
        mf->field       = V4L2_FIELD_NONE;
@@ -504,46 +523,11 @@ static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
                return -EINVAL;
        }
 
-       ret = reg_mask(OUTPUT_FORMAT_CTRL2_A, data_outfmt2,
-                      mask_outfmt2);
+       ret = mt9m111_reg_mask(client, context_a.output_fmt_ctrl2,
+                              data_outfmt2, mask_outfmt2);
        if (!ret)
-               ret = reg_mask(OUTPUT_FORMAT_CTRL2_B, data_outfmt2,
-                              mask_outfmt2);
-
-       return ret;
-}
-
-static int mt9m111_s_fmt(struct v4l2_subdev *sd,
-                        struct v4l2_mbus_framefmt *mf)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       const struct mt9m111_datafmt *fmt;
-       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
-       struct v4l2_rect rect = {
-               .left   = mt9m111->rect.left,
-               .top    = mt9m111->rect.top,
-               .width  = mf->width,
-               .height = mf->height,
-       };
-       int ret;
-
-       fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts,
-                                  ARRAY_SIZE(mt9m111_colour_fmts));
-       if (!fmt)
-               return -EINVAL;
-
-       dev_dbg(&client->dev,
-               "%s code=%x left=%d, top=%d, width=%d, height=%d\n", __func__,
-               mf->code, rect.left, rect.top, rect.width, rect.height);
-
-       ret = mt9m111_make_rect(mt9m111, &rect);
-       if (!ret)
-               ret = mt9m111_set_pixfmt(mt9m111, mf->code);
-       if (!ret) {
-               mt9m111->rect   = rect;
-               mt9m111->fmt    = fmt;
-               mf->colorspace  = fmt->colorspace;
-       }
+               ret = mt9m111_reg_mask(client, context_b.output_fmt_ctrl2,
+                                      data_outfmt2, mask_outfmt2);
 
        return ret;
 }
@@ -551,42 +535,71 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
 static int mt9m111_try_fmt(struct v4l2_subdev *sd,
                           struct v4l2_mbus_framefmt *mf)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
        const struct mt9m111_datafmt *fmt;
-       bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
-               mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE;
-
-       fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts,
-                                  ARRAY_SIZE(mt9m111_colour_fmts));
-       if (!fmt) {
-               fmt = mt9m111->fmt;
-               mf->code = fmt->code;
-       }
+       struct v4l2_rect *rect = &mt9m111->rect;
+       bool bayer;
+
+       fmt = mt9m111_find_datafmt(mt9m111, mf->code);
+
+       bayer = fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
+               fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE;
 
        /*
         * With Bayer format enforce even side lengths, but let the user play
         * with the starting pixel
         */
+       if (bayer) {
+               rect->width = ALIGN(rect->width, 2);
+               rect->height = ALIGN(rect->height, 2);
+       }
 
-       if (mf->height > MT9M111_MAX_HEIGHT)
-               mf->height = MT9M111_MAX_HEIGHT;
-       else if (mf->height < 2)
-               mf->height = 2;
-       else if (bayer)
-               mf->height = ALIGN(mf->height, 2);
+       if (fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
+               /* IFP bypass mode, no scaling */
+               mf->width = rect->width;
+               mf->height = rect->height;
+       } else {
+               /* No upscaling */
+               if (mf->width > rect->width)
+                       mf->width = rect->width;
+               if (mf->height > rect->height)
+                       mf->height = rect->height;
+       }
 
-       if (mf->width > MT9M111_MAX_WIDTH)
-               mf->width = MT9M111_MAX_WIDTH;
-       else if (mf->width < 2)
-               mf->width = 2;
-       else if (bayer)
-               mf->width = ALIGN(mf->width, 2);
+       dev_dbg(&client->dev, "%s(): %ux%u, code=%x\n", __func__,
+               mf->width, mf->height, fmt->code);
 
+       mf->code = fmt->code;
        mf->colorspace = fmt->colorspace;
 
        return 0;
 }
 
+static int mt9m111_s_fmt(struct v4l2_subdev *sd,
+                        struct v4l2_mbus_framefmt *mf)
+{
+       const struct mt9m111_datafmt *fmt;
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+       struct v4l2_rect *rect = &mt9m111->rect;
+       int ret;
+
+       mt9m111_try_fmt(sd, mf);
+       fmt = mt9m111_find_datafmt(mt9m111, mf->code);
+       /* try_fmt() guarantees fmt != NULL && fmt->code == mf->code */
+
+       ret = mt9m111_setup_geometry(mt9m111, rect, mf->width, mf->height, mf->code);
+       if (!ret)
+               ret = mt9m111_set_pixfmt(mt9m111, mf->code);
+       if (!ret) {
+               mt9m111->width  = mf->width;
+               mt9m111->height = mf->height;
+               mt9m111->fmt    = fmt;
+       }
+
+       return ret;
+}
+
 static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
                                struct v4l2_dbg_chip_ident *id)
 {
@@ -650,17 +663,10 @@ static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask)
        struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
-       if (mt9m111->context == HIGHPOWER) {
-               if (flip)
-                       ret = reg_set(READ_MODE_B, mask);
-               else
-                       ret = reg_clear(READ_MODE_B, mask);
-       } else {
-               if (flip)
-                       ret = reg_set(READ_MODE_A, mask);
-               else
-                       ret = reg_clear(READ_MODE_A, mask);
-       }
+       if (flip)
+               ret = mt9m111_reg_set(client, mt9m111->ctx->read_mode, mask);
+       else
+               ret = mt9m111_reg_clear(client, mt9m111->ctx->read_mode, mask);
 
        return ret;
 }
@@ -738,30 +744,39 @@ static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
 
 static int mt9m111_suspend(struct mt9m111 *mt9m111)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+       int ret;
+
        v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111));
 
-       return 0;
+       ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
+       if (!ret)
+               ret = reg_set(RESET, MT9M111_RESET_RESET_SOC |
+                             MT9M111_RESET_OUTPUT_DISABLE |
+                             MT9M111_RESET_ANALOG_STANDBY);
+       if (!ret)
+               ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
+
+       return ret;
 }
 
 static void mt9m111_restore_state(struct mt9m111 *mt9m111)
 {
-       mt9m111_set_context(mt9m111, mt9m111->context);
+       mt9m111_set_context(mt9m111, mt9m111->ctx);
        mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
-       mt9m111_setup_rect(mt9m111, &mt9m111->rect);
+       mt9m111_setup_geometry(mt9m111, &mt9m111->rect,
+                       mt9m111->width, mt9m111->height, mt9m111->fmt->code);
        v4l2_ctrl_handler_setup(&mt9m111->hdl);
 }
 
 static int mt9m111_resume(struct mt9m111 *mt9m111)
 {
-       int ret = 0;
+       int ret = mt9m111_enable(mt9m111);
+       if (!ret)
+               ret = mt9m111_reset(mt9m111);
+       if (!ret)
+               mt9m111_restore_state(mt9m111);
 
-       if (mt9m111->powered) {
-               ret = mt9m111_enable(mt9m111);
-               if (!ret)
-                       ret = mt9m111_reset(mt9m111);
-               if (!ret)
-                       mt9m111_restore_state(mt9m111);
-       }
        return ret;
 }
 
@@ -770,12 +785,13 @@ static int mt9m111_init(struct mt9m111 *mt9m111)
        struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
-       mt9m111->context = HIGHPOWER;
+       /* Default HIGHPOWER context */
+       mt9m111->ctx = &context_b;
        ret = mt9m111_enable(mt9m111);
        if (!ret)
                ret = mt9m111_reset(mt9m111);
        if (!ret)
-               ret = mt9m111_set_context(mt9m111, mt9m111->context);
+               ret = mt9m111_set_context(mt9m111, mt9m111->ctx);
        if (ret)
                dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
        return ret;
index 73c068993f050cce24eb408d2cbf7e745791c667..93c3ec7426e85ce14b83d8380c7c008abeb5505c 100644 (file)
@@ -132,13 +132,12 @@ static struct mt9p031 *to_mt9p031(struct v4l2_subdev *sd)
 
 static int mt9p031_read(struct i2c_client *client, u8 reg)
 {
-       s32 data = i2c_smbus_read_word_data(client, reg);
-       return data < 0 ? data : be16_to_cpu(data);
+       return i2c_smbus_read_word_swapped(client, reg);
 }
 
 static int mt9p031_write(struct i2c_client *client, u8 reg, u16 data)
 {
-       return i2c_smbus_write_word_data(client, reg, cpu_to_be16(data));
+       return i2c_smbus_write_word_swapped(client, reg, data);
 }
 
 static int mt9p031_set_output_control(struct mt9p031 *mt9p031, u16 clear,
index 08074b8a2736ca75a8bcdd6a26512536e584cf36..cd81d04a529e2ec9eb1d10fd9eb2c80f502830c4 100644 (file)
@@ -133,13 +133,12 @@ static inline struct mt9t001 *to_mt9t001(struct v4l2_subdev *sd)
 
 static int mt9t001_read(struct i2c_client *client, u8 reg)
 {
-       s32 data = i2c_smbus_read_word_data(client, reg);
-       return data < 0 ? data : be16_to_cpu(data);
+       return i2c_smbus_read_word_swapped(client, reg);
 }
 
 static int mt9t001_write(struct i2c_client *client, u8 reg, u16 data)
 {
-       return i2c_smbus_write_word_data(client, reg, cpu_to_be16(data));
+       return i2c_smbus_write_word_swapped(client, reg, data);
 }
 
 static int mt9t001_set_output_control(struct mt9t001 *mt9t001, u16 clear,
index 0e78477452ffb81bf5a09a781d9b68326b61e345..84add1aef13955941a1969d7dabec019148d7a51 100644 (file)
@@ -90,14 +90,13 @@ static struct mt9t031 *to_mt9t031(const struct i2c_client *client)
 
 static int reg_read(struct i2c_client *client, const u8 reg)
 {
-       s32 data = i2c_smbus_read_word_data(client, reg);
-       return data < 0 ? data : swab16(data);
+       return i2c_smbus_read_word_swapped(client, reg);
 }
 
 static int reg_write(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
-       return i2c_smbus_write_word_data(client, reg, swab16(data));
+       return i2c_smbus_write_word_swapped(client, reg, data);
 }
 
 static int reg_set(struct i2c_client *client, const u8 reg,
index 690ee0d42eebbcbb8aaf7374ca49a7302716180f..944940758fa3094d6ec0d5213342fc533d97a240 100644 (file)
@@ -130,14 +130,13 @@ static struct mt9v022 *to_mt9v022(const struct i2c_client *client)
 
 static int reg_read(struct i2c_client *client, const u8 reg)
 {
-       s32 data = i2c_smbus_read_word_data(client, reg);
-       return data < 0 ? data : swab16(data);
+       return i2c_smbus_read_word_swapped(client, reg);
 }
 
 static int reg_write(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
-       return i2c_smbus_write_word_data(client, reg, swab16(data));
+       return i2c_smbus_write_word_swapped(client, reg, data);
 }
 
 static int reg_set(struct i2c_client *client, const u8 reg,
index f080c162123f3ee0de1d0b532fc74a96d760b846..d90b982cc218d4adf5874494f2a3203fbd8bc43d 100644 (file)
@@ -139,10 +139,10 @@ static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd)
 
 static int mt9v032_read(struct i2c_client *client, const u8 reg)
 {
-       s32 data = i2c_smbus_read_word_data(client, reg);
+       s32 data = i2c_smbus_read_word_swapped(client, reg);
        dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__,
-               swab16(data), reg);
-       return data < 0 ? data : swab16(data);
+               data, reg);
+       return data;
 }
 
 static int mt9v032_write(struct i2c_client *client, const u8 reg,
@@ -150,7 +150,7 @@ static int mt9v032_write(struct i2c_client *client, const u8 reg,
 {
        dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__,
                data, reg);
-       return i2c_smbus_write_word_data(client, reg, swab16(data));
+       return i2c_smbus_write_word_swapped(client, reg, data);
 }
 
 static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set)
index 18e94c7d2be83e1668bdf6c6664ed50907761d40..055d11ddb0388aa6f3f1b2bb7244427d730c849e 100644 (file)
@@ -487,7 +487,7 @@ static int mx1_camera_set_crop(struct soc_camera_device *icd,
        return v4l2_subdev_call(sd, video, s_crop, a);
 }
 
-static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+static int mx1_camera_set_bus_param(struct soc_camera_device *icd)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
index a803d9ea8fd61df40b2061a1423222435573e564..04aab0c538aa75c3e22da8338080ebe0a1890b57 100644 (file)
 
 #define MAX_VIDEO_MEM  16
 
+struct mx2_prp_cfg {
+       int channel;
+       u32 in_fmt;
+       u32 out_fmt;
+       u32 src_pixel;
+       u32 ch1_pixel;
+       u32 irq_flags;
+};
+
+/* prp configuration for a client-host fmt pair */
+struct mx2_fmt_cfg {
+       enum v4l2_mbus_pixelcode        in_fmt;
+       u32                             out_fmt;
+       struct mx2_prp_cfg              cfg;
+};
+
 struct mx2_camera_dev {
        struct device           *dev;
        struct soc_camera_host  soc_host;
@@ -241,6 +257,8 @@ struct mx2_camera_dev {
        void                    *discard_buffer;
        dma_addr_t              discard_buffer_dma;
        size_t                  discard_size;
+       struct mx2_fmt_cfg      *emma_prp;
+       u32                     frame_count;
 };
 
 /* buffer for one video frame */
@@ -253,6 +271,59 @@ struct mx2_buffer {
        int bufnum;
 };
 
+static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
+       /*
+        * This is a generic configuration which is valid for most
+        * prp input-output format combinations.
+        * We set the incomming and outgoing pixelformat to a
+        * 16 Bit wide format and adjust the bytesperline
+        * accordingly. With this configuration the inputdata
+        * will not be changed by the emma and could be any type
+        * of 16 Bit Pixelformat.
+        */
+       {
+               .in_fmt         = 0,
+               .out_fmt        = 0,
+               .cfg            = {
+                       .channel        = 1,
+                       .in_fmt         = PRP_CNTL_DATA_IN_RGB16,
+                       .out_fmt        = PRP_CNTL_CH1_OUT_RGB16,
+                       .src_pixel      = 0x2ca00565, /* RGB565 */
+                       .ch1_pixel      = 0x2ca00565, /* RGB565 */
+                       .irq_flags      = PRP_INTR_RDERR | PRP_INTR_CH1WERR |
+                                               PRP_INTR_CH1FC | PRP_INTR_LBOVF,
+               }
+       },
+       {
+               .in_fmt         = V4L2_MBUS_FMT_YUYV8_2X8,
+               .out_fmt        = V4L2_PIX_FMT_YUV420,
+               .cfg            = {
+                       .channel        = 2,
+                       .in_fmt         = PRP_CNTL_DATA_IN_YUV422,
+                       .out_fmt        = PRP_CNTL_CH2_OUT_YUV420,
+                       .src_pixel      = 0x22000888, /* YUV422 (YUYV) */
+                       .irq_flags      = PRP_INTR_RDERR | PRP_INTR_CH2WERR |
+                                       PRP_INTR_CH2FC | PRP_INTR_LBOVF |
+                                       PRP_INTR_CH2OVF,
+               }
+       },
+};
+
+static struct mx2_fmt_cfg *mx27_emma_prp_get_format(
+                                       enum v4l2_mbus_pixelcode in_fmt,
+                                       u32 out_fmt)
+{
+       int i;
+
+       for (i = 1; i < ARRAY_SIZE(mx27_emma_prp_table); i++)
+               if ((mx27_emma_prp_table[i].in_fmt == in_fmt) &&
+                               (mx27_emma_prp_table[i].out_fmt == out_fmt)) {
+                       return &mx27_emma_prp_table[i];
+               }
+       /* If no match return the most generic configuration */
+       return &mx27_emma_prp_table[0];
+};
+
 static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
 {
        unsigned long flags;
@@ -301,6 +372,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
        writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
 
        pcdev->icd = icd;
+       pcdev->frame_count = 0;
 
        dev_info(icd->parent, "Camera driver attached to camera %d\n",
                 icd->devnum);
@@ -719,55 +791,77 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
        struct soc_camera_host *ici =
                to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
+       struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+       u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width;
+
+       if (prp->cfg.channel == 1) {
+               writel(pcdev->discard_buffer_dma,
+                               pcdev->base_emma + PRP_DEST_RGB1_PTR);
+               writel(pcdev->discard_buffer_dma,
+                               pcdev->base_emma + PRP_DEST_RGB2_PTR);
+
+               writel(PRP_CNTL_CH1EN |
+                               PRP_CNTL_CSIEN |
+                               prp->cfg.in_fmt |
+                               prp->cfg.out_fmt |
+                               PRP_CNTL_CH1_LEN |
+                               PRP_CNTL_CH1BYP |
+                               PRP_CNTL_CH1_TSKIP(0) |
+                               PRP_CNTL_IN_TSKIP(0),
+                               pcdev->base_emma + PRP_CNTL);
+
+               writel((icd->user_width << 16) | icd->user_height,
+                       pcdev->base_emma + PRP_SRC_FRAME_SIZE);
+               writel((icd->user_width << 16) | icd->user_height,
+                       pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
+               writel(bytesperline,
+                       pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
+               writel(prp->cfg.src_pixel,
+                       pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
+               writel(prp->cfg.ch1_pixel,
+                       pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
+       } else { /* channel 2 */
+               writel(pcdev->discard_buffer_dma,
+                       pcdev->base_emma + PRP_DEST_Y_PTR);
+               writel(pcdev->discard_buffer_dma,
+                       pcdev->base_emma + PRP_SOURCE_Y_PTR);
+
+               if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) {
+                       writel(pcdev->discard_buffer_dma + imgsize,
+                               pcdev->base_emma + PRP_DEST_CB_PTR);
+                       writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4),
+                               pcdev->base_emma + PRP_DEST_CR_PTR);
+                       writel(pcdev->discard_buffer_dma + imgsize,
+                               pcdev->base_emma + PRP_SOURCE_CB_PTR);
+                       writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4),
+                               pcdev->base_emma + PRP_SOURCE_CR_PTR);
+               }
 
-       writel(pcdev->discard_buffer_dma,
-                       pcdev->base_emma + PRP_DEST_RGB1_PTR);
-       writel(pcdev->discard_buffer_dma,
-                       pcdev->base_emma + PRP_DEST_RGB2_PTR);
-
-       /*
-        * We only use the EMMA engine to get rid of the broken
-        * DMA Engine. No color space consversion at the moment.
-        * We set the incomming and outgoing pixelformat to an
-        * 16 Bit wide format and adjust the bytesperline
-        * accordingly. With this configuration the inputdata
-        * will not be changed by the emma and could be any type
-        * of 16 Bit Pixelformat.
-        */
-       writel(PRP_CNTL_CH1EN |
+               writel(PRP_CNTL_CH2EN |
                        PRP_CNTL_CSIEN |
-                       PRP_CNTL_DATA_IN_RGB16 |
-                       PRP_CNTL_CH1_OUT_RGB16 |
-                       PRP_CNTL_CH1_LEN |
-                       PRP_CNTL_CH1BYP |
-                       PRP_CNTL_CH1_TSKIP(0) |
+                       prp->cfg.in_fmt |
+                       prp->cfg.out_fmt |
+                       PRP_CNTL_CH2_LEN |
+                       PRP_CNTL_CH2_TSKIP(0) |
                        PRP_CNTL_IN_TSKIP(0),
                        pcdev->base_emma + PRP_CNTL);
 
-       writel(((bytesperline >> 1) << 16) | icd->user_height,
+               writel((icd->user_width << 16) | icd->user_height,
                        pcdev->base_emma + PRP_SRC_FRAME_SIZE);
-       writel(((bytesperline >> 1) << 16) | icd->user_height,
-                       pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
-       writel(bytesperline,
-                       pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
-       writel(0x2ca00565, /* RGB565 */
+
+               writel((icd->user_width << 16) | icd->user_height,
+                       pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
+
+               writel(prp->cfg.src_pixel,
                        pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
-       writel(0x2ca00565, /* RGB565 */
-                       pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
+
+       }
 
        /* Enable interrupts */
-       writel(PRP_INTR_RDERR |
-                       PRP_INTR_CH1WERR |
-                       PRP_INTR_CH2WERR |
-                       PRP_INTR_CH1FC |
-                       PRP_INTR_CH2FC |
-                       PRP_INTR_LBOVF |
-                       PRP_INTR_CH2OVF,
-                       pcdev->base_emma + PRP_INTR_CNTL);
+       writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL);
 }
 
-static int mx2_camera_set_bus_param(struct soc_camera_device *icd,
-               __u32 pixfmt)
+static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -911,9 +1005,58 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd,
        return ret;
 }
 
+static int mx2_camera_get_formats(struct soc_camera_device *icd,
+                                 unsigned int idx,
+                                 struct soc_camera_format_xlate *xlate)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       const struct soc_mbus_pixelfmt *fmt;
+       struct device *dev = icd->parent;
+       enum v4l2_mbus_pixelcode code;
+       int ret, formats = 0;
+
+       ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+       if (ret < 0)
+               /* no more formats */
+               return 0;
+
+       fmt = soc_mbus_get_fmtdesc(code);
+       if (!fmt) {
+               dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
+               return 0;
+       }
+
+       if (code == V4L2_MBUS_FMT_YUYV8_2X8) {
+               formats++;
+               if (xlate) {
+                       /*
+                        * CH2 can output YUV420 which is a standard format in
+                        * soc_mediabus.c
+                        */
+                       xlate->host_fmt =
+                               soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_1_5X8);
+                       xlate->code     = code;
+                       dev_dbg(dev, "Providing host format %s for sensor code %d\n",
+                              xlate->host_fmt->name, code);
+                       xlate++;
+               }
+       }
+
+       /* Generic pass-trough */
+       formats++;
+       if (xlate) {
+               xlate->host_fmt = fmt;
+               xlate->code     = code;
+               xlate++;
+       }
+       return formats;
+}
+
 static int mx2_camera_set_fmt(struct soc_camera_device *icd,
                               struct v4l2_format *f)
 {
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct mx2_camera_dev *pcdev = ici->priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        const struct soc_camera_format_xlate *xlate;
        struct v4l2_pix_format *pix = &f->fmt.pix;
@@ -946,6 +1089,10 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
        pix->colorspace         = mf.colorspace;
        icd->current_fmt        = xlate;
 
+       if (mx27_camera_emma(pcdev))
+               pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
+                                               xlate->host_fmt->fourcc);
+
        return 0;
 }
 
@@ -1011,7 +1158,12 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
 
        if (mf.field == V4L2_FIELD_ANY)
                mf.field = V4L2_FIELD_NONE;
-       if (mf.field != V4L2_FIELD_NONE) {
+       /*
+        * Driver supports interlaced images provided they have
+        * both fields so that they can be processed as if they
+        * were progressive.
+        */
+       if (mf.field != V4L2_FIELD_NONE && !V4L2_FIELD_HAS_BOTH(mf.field)) {
                dev_err(icd->parent, "Field type %d unsupported.\n",
                                mf.field);
                return -EINVAL;
@@ -1173,6 +1325,7 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
        .remove         = mx2_camera_remove_device,
        .set_fmt        = mx2_camera_set_fmt,
        .set_crop       = mx2_camera_set_crop,
+       .get_formats    = mx2_camera_get_formats,
        .try_fmt        = mx2_camera_try_fmt,
        .init_videobuf  = mx2_camera_init_videobuf,
        .reqbufs        = mx2_camera_reqbufs,
@@ -1184,6 +1337,8 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
 static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
                int bufnum, int state)
 {
+       u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width;
+       struct mx2_fmt_cfg *prp = pcdev->emma_prp;
        struct mx2_buffer *buf;
        struct videobuf_buffer *vb;
        unsigned long phys;
@@ -1197,12 +1352,22 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
                vb = &buf->vb;
 #ifdef DEBUG
                phys = videobuf_to_dma_contig(vb);
-               if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum)
-                               != phys) {
-                       dev_err(pcdev->dev, "%p != %p\n", phys,
-                                       readl(pcdev->base_emma +
-                                               PRP_DEST_RGB1_PTR +
-                                               4 * bufnum));
+               if (prp->cfg.channel == 1) {
+                       if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR +
+                               4 * bufnum) != phys) {
+                               dev_err(pcdev->dev, "%p != %p\n", phys,
+                                               readl(pcdev->base_emma +
+                                                       PRP_DEST_RGB1_PTR +
+                                                       4 * bufnum));
+                       }
+               } else {
+                       if (readl(pcdev->base_emma + PRP_DEST_Y_PTR -
+                               0x14 * bufnum) != phys) {
+                               dev_err(pcdev->dev, "%p != %p\n", phys,
+                                               readl(pcdev->base_emma +
+                                                       PRP_DEST_Y_PTR -
+                                                       0x14 * bufnum));
+                       }
                }
 #endif
                dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb,
@@ -1211,14 +1376,29 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
                list_del(&vb->queue);
                vb->state = state;
                do_gettimeofday(&vb->ts);
-               vb->field_count++;
+               vb->field_count = pcdev->frame_count * 2;
+               pcdev->frame_count++;
 
                wake_up(&vb->done);
        }
 
        if (list_empty(&pcdev->capture)) {
-               writel(pcdev->discard_buffer_dma, pcdev->base_emma +
-                               PRP_DEST_RGB1_PTR + 4 * bufnum);
+               if (prp->cfg.channel == 1) {
+                       writel(pcdev->discard_buffer_dma, pcdev->base_emma +
+                                       PRP_DEST_RGB1_PTR + 4 * bufnum);
+               } else {
+                       writel(pcdev->discard_buffer_dma, pcdev->base_emma +
+                                               PRP_DEST_Y_PTR -
+                                               0x14 * bufnum);
+                       if (prp->out_fmt == V4L2_PIX_FMT_YUV420) {
+                               writel(pcdev->discard_buffer_dma + imgsize,
+                                      pcdev->base_emma + PRP_DEST_CB_PTR -
+                                      0x14 * bufnum);
+                               writel(pcdev->discard_buffer_dma +
+                                      ((5 * imgsize) / 4), pcdev->base_emma +
+                                      PRP_DEST_CR_PTR - 0x14 * bufnum);
+                       }
+               }
                return;
        }
 
@@ -1233,7 +1413,18 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
        vb->state = VIDEOBUF_ACTIVE;
 
        phys = videobuf_to_dma_contig(vb);
-       writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum);
+       if (prp->cfg.channel == 1) {
+               writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum);
+       } else {
+               writel(phys, pcdev->base_emma +
+                               PRP_DEST_Y_PTR - 0x14 * bufnum);
+               if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) {
+                       writel(phys + imgsize, pcdev->base_emma +
+                                       PRP_DEST_CB_PTR - 0x14 * bufnum);
+                       writel(phys + ((5 * imgsize) / 4), pcdev->base_emma +
+                                       PRP_DEST_CR_PTR - 0x14 * bufnum);
+               }
+       }
 }
 
 static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
@@ -1253,10 +1444,12 @@ static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
                 * the next one.
                 */
                cntl = readl(pcdev->base_emma + PRP_CNTL);
-               writel(cntl & ~PRP_CNTL_CH1EN, pcdev->base_emma + PRP_CNTL);
+               writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN),
+                      pcdev->base_emma + PRP_CNTL);
                writel(cntl, pcdev->base_emma + PRP_CNTL);
        }
-       if ((status & (3 << 5)) == (3 << 5)
+       if ((((status & (3 << 5)) == (3 << 5)) ||
+               ((status & (3 << 3)) == (3 << 3)))
                        && !list_empty(&pcdev->active_bufs)) {
                /*
                 * Both buffers have triggered, process the one we're expecting
@@ -1267,9 +1460,9 @@ static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
                mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE);
                status &= ~(1 << (6 - buf->bufnum)); /* mark processed */
        }
-       if (status & (1 << 6))
+       if ((status & (1 << 6)) || (status & (1 << 4)))
                mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE);
-       if (status & (1 << 5))
+       if ((status & (1 << 5)) || (status & (1 << 3)))
                mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE);
 
        writel(status, pcdev->base_emma + PRP_INTRSTATUS);
index f96f92f00f92f2e20de5a629238f55543006bf83..74522773e934c18e417f36b36aed40017b35e02f 100644 (file)
@@ -287,7 +287,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
                sg_dma_len(sg)          = new_size;
 
                txd = ichan->dma_chan.device->device_prep_slave_sg(
-                       &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE,
+                       &ichan->dma_chan, sg, 1, DMA_DEV_TO_MEM,
                        DMA_PREP_INTERRUPT);
                if (!txd)
                        goto error;
@@ -982,12 +982,13 @@ static int mx3_camera_querycap(struct soc_camera_host *ici,
        return 0;
 }
 
-static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+static int mx3_camera_set_bus_param(struct soc_camera_device *icd)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+       u32 pixfmt = icd->current_fmt->host_fmt->fourcc;
        unsigned long bus_flags, common_flags;
        u32 dw, sens_conf;
        const struct soc_mbus_pixelfmt *fmt;
@@ -1285,19 +1286,7 @@ static struct platform_driver mx3_camera_driver = {
        .remove         = __devexit_p(mx3_camera_remove),
 };
 
-
-static int __init mx3_camera_init(void)
-{
-       return platform_driver_register(&mx3_camera_driver);
-}
-
-static void __exit mx3_camera_exit(void)
-{
-       platform_driver_unregister(&mx3_camera_driver);
-}
-
-module_init(mx3_camera_init);
-module_exit(mx3_camera_exit);
+module_platform_driver(mx3_camera_driver);
 
 MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
index ee0d0b39cd170e1700b659a7af2e1085c580b9fa..1fb7d5bd5ec26a3f8955e8a6cdc3e7a6cd3841f9 100644 (file)
@@ -70,9 +70,9 @@ static u32 video1_numbuffers = 3;
 static u32 video2_numbuffers = 3;
 static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
 static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
-static u32 vid1_static_vrfb_alloc;
-static u32 vid2_static_vrfb_alloc;
-static int debug;
+static bool vid1_static_vrfb_alloc;
+static bool vid2_static_vrfb_alloc;
+static bool debug;
 
 /* Module parameters */
 module_param(video1_numbuffers, uint, S_IRUGO);
@@ -424,7 +424,7 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout,
                "%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n"
                "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n"
                "out_height=%d rotation_type=%d screen_width=%d\n",
-               __func__, info.enabled, info.paddr, info.width, info.height,
+               __func__, ovl->is_enabled(ovl), info.paddr, info.width, info.height,
                info.color_mode, info.rotation, info.mirror, info.pos_x,
                info.pos_y, info.out_width, info.out_height, info.rotation_type,
                info.screen_width);
@@ -524,10 +524,50 @@ static int omapvid_apply_changes(struct omap_vout_device *vout)
        return 0;
 }
 
+static int omapvid_handle_interlace_display(struct omap_vout_device *vout,
+               unsigned int irqstatus, struct timeval timevalue)
+{
+       u32 fid;
+
+       if (vout->first_int) {
+               vout->first_int = 0;
+               goto err;
+       }
+
+       if (irqstatus & DISPC_IRQ_EVSYNC_ODD)
+               fid = 1;
+       else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN)
+               fid = 0;
+       else
+               goto err;
+
+       vout->field_id ^= 1;
+       if (fid != vout->field_id) {
+               if (fid == 0)
+                       vout->field_id = fid;
+       } else if (0 == fid) {
+               if (vout->cur_frm == vout->next_frm)
+                       goto err;
+
+               vout->cur_frm->ts = timevalue;
+               vout->cur_frm->state = VIDEOBUF_DONE;
+               wake_up_interruptible(&vout->cur_frm->done);
+               vout->cur_frm = vout->next_frm;
+       } else {
+               if (list_empty(&vout->dma_queue) ||
+                               (vout->cur_frm != vout->next_frm))
+                       goto err;
+       }
+
+       return vout->field_id;
+err:
+       return 0;
+}
+
 static void omap_vout_isr(void *arg, unsigned int irqstatus)
 {
-       int ret;
-       u32 addr, fid;
+       int ret, fid, mgr_id;
+       u32 addr, irq;
        struct omap_overlay *ovl;
        struct timeval timevalue;
        struct omapvideo_info *ovid;
@@ -543,112 +583,73 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus)
        if (!ovl->manager || !ovl->manager->device)
                return;
 
+       mgr_id = ovl->manager->id;
        cur_display = ovl->manager->device;
 
        spin_lock(&vout->vbq_lock);
        do_gettimeofday(&timevalue);
 
-       if (cur_display->type != OMAP_DISPLAY_TYPE_VENC) {
-               switch (cur_display->type) {
-               case OMAP_DISPLAY_TYPE_DPI:
-                       if (!(irqstatus & (DISPC_IRQ_VSYNC | DISPC_IRQ_VSYNC2)))
-                               goto vout_isr_err;
-                       break;
-               case OMAP_DISPLAY_TYPE_HDMI:
-                       if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN))
-                               goto vout_isr_err;
-                       break;
-               default:
-                       goto vout_isr_err;
-               }
-               if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
-                       vout->cur_frm->ts = timevalue;
-                       vout->cur_frm->state = VIDEOBUF_DONE;
-                       wake_up_interruptible(&vout->cur_frm->done);
-                       vout->cur_frm = vout->next_frm;
-               }
-               vout->first_int = 0;
-               if (list_empty(&vout->dma_queue))
+       switch (cur_display->type) {
+       case OMAP_DISPLAY_TYPE_DSI:
+       case OMAP_DISPLAY_TYPE_DPI:
+               if (mgr_id == OMAP_DSS_CHANNEL_LCD)
+                       irq = DISPC_IRQ_VSYNC;
+               else if (mgr_id == OMAP_DSS_CHANNEL_LCD2)
+                       irq = DISPC_IRQ_VSYNC2;
+               else
                        goto vout_isr_err;
 
-               vout->next_frm = list_entry(vout->dma_queue.next,
-                               struct videobuf_buffer, queue);
-               list_del(&vout->next_frm->queue);
-
-               vout->next_frm->state = VIDEOBUF_ACTIVE;
+               if (!(irqstatus & irq))
+                       goto vout_isr_err;
+               break;
+       case OMAP_DISPLAY_TYPE_VENC:
+               fid = omapvid_handle_interlace_display(vout, irqstatus,
+                               timevalue);
+               if (!fid)
+                       goto vout_isr_err;
+               break;
+       case OMAP_DISPLAY_TYPE_HDMI:
+               if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN))
+                       goto vout_isr_err;
+               break;
+       default:
+               goto vout_isr_err;
+       }
 
-               addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
-                       + vout->cropped_offset;
+       if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
+               vout->cur_frm->ts = timevalue;
+               vout->cur_frm->state = VIDEOBUF_DONE;
+               wake_up_interruptible(&vout->cur_frm->done);
+               vout->cur_frm = vout->next_frm;
+       }
 
-               /* First save the configuration in ovelray structure */
-               ret = omapvid_init(vout, addr);
-               if (ret)
-                       printk(KERN_ERR VOUT_NAME
-                               "failed to set overlay info\n");
-               /* Enable the pipeline and set the Go bit */
-               ret = omapvid_apply_changes(vout);
-               if (ret)
-                       printk(KERN_ERR VOUT_NAME "failed to change mode\n");
-       } else {
+       vout->first_int = 0;
+       if (list_empty(&vout->dma_queue))
+               goto vout_isr_err;
 
-               if (vout->first_int) {
-                       vout->first_int = 0;
-                       goto vout_isr_err;
-               }
-               if (irqstatus & DISPC_IRQ_EVSYNC_ODD)
-                       fid = 1;
-               else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN)
-                       fid = 0;
-               else
-                       goto vout_isr_err;
+       vout->next_frm = list_entry(vout->dma_queue.next,
+                       struct videobuf_buffer, queue);
+       list_del(&vout->next_frm->queue);
 
-               vout->field_id ^= 1;
-               if (fid != vout->field_id) {
-                       if (0 == fid)
-                               vout->field_id = fid;
+       vout->next_frm->state = VIDEOBUF_ACTIVE;
 
-                       goto vout_isr_err;
-               }
-               if (0 == fid) {
-                       if (vout->cur_frm == vout->next_frm)
-                               goto vout_isr_err;
-
-                       vout->cur_frm->ts = timevalue;
-                       vout->cur_frm->state = VIDEOBUF_DONE;
-                       wake_up_interruptible(&vout->cur_frm->done);
-                       vout->cur_frm = vout->next_frm;
-               } else if (1 == fid) {
-                       if (list_empty(&vout->dma_queue) ||
-                                       (vout->cur_frm != vout->next_frm))
-                               goto vout_isr_err;
-
-                       vout->next_frm = list_entry(vout->dma_queue.next,
-                                       struct videobuf_buffer, queue);
-                       list_del(&vout->next_frm->queue);
-
-                       vout->next_frm->state = VIDEOBUF_ACTIVE;
-                       addr = (unsigned long)
-                               vout->queued_buf_addr[vout->next_frm->i] +
-                               vout->cropped_offset;
-                       /* First save the configuration in ovelray structure */
-                       ret = omapvid_init(vout, addr);
-                       if (ret)
-                               printk(KERN_ERR VOUT_NAME
-                                               "failed to set overlay info\n");
-                       /* Enable the pipeline and set the Go bit */
-                       ret = omapvid_apply_changes(vout);
-                       if (ret)
-                               printk(KERN_ERR VOUT_NAME
-                                               "failed to change mode\n");
-               }
+       addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
+               + vout->cropped_offset;
 
-       }
+       /* First save the configuration in ovelray structure */
+       ret = omapvid_init(vout, addr);
+       if (ret)
+               printk(KERN_ERR VOUT_NAME
+                       "failed to set overlay info\n");
+       /* Enable the pipeline and set the Go bit */
+       ret = omapvid_apply_changes(vout);
+       if (ret)
+               printk(KERN_ERR VOUT_NAME "failed to change mode\n");
 
 vout_isr_err:
        spin_unlock(&vout->vbq_lock);
 }
 
-
 /* Video buffer call backs */
 
 /*
@@ -664,10 +665,14 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
        u32 phy_addr = 0, virt_addr = 0;
        struct omap_vout_device *vout = q->priv_data;
        struct omapvideo_info *ovid = &vout->vid_info;
+       int vid_max_buf_size;
 
        if (!vout)
                return -EINVAL;
 
+       vid_max_buf_size = vout->vid == OMAP_VIDEO1 ? video1_bufsize :
+               video2_bufsize;
+
        if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
                return -EINVAL;
 
@@ -690,7 +695,7 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
                video1_numbuffers : video2_numbuffers;
 
        /* Check the size of the buffer */
-       if (*size > vout->buffer_size) {
+       if (*size > vid_max_buf_size) {
                v4l2_err(&vout->vid_dev->v4l2_dev,
                                "buffer allocation mismatch [%u] [%u]\n",
                                *size, vout->buffer_size);
@@ -943,12 +948,8 @@ static int omap_vout_release(struct file *file)
        /* Disable all the overlay managers connected with this interface */
        for (i = 0; i < ovid->num_overlays; i++) {
                struct omap_overlay *ovl = ovid->overlays[i];
-               if (ovl->manager && ovl->manager->device) {
-                       struct omap_overlay_info info;
-                       ovl->get_overlay_info(ovl, &info);
-                       info.enabled = 0;
-                       ovl->set_overlay_info(ovl, &info);
-               }
+               if (ovl->manager && ovl->manager->device)
+                       ovl->disable(ovl);
        }
        /* Turn off the pipeline */
        ret = omapvid_apply_changes(vout);
@@ -1041,7 +1042,8 @@ static int vidioc_querycap(struct file *file, void *fh,
        strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
        strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
        cap->bus_info[0] = '\0';
-       cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
+       cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT |
+               V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
 
        return 0;
 }
@@ -1668,7 +1670,6 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
                if (ovl->manager && ovl->manager->device) {
                        struct omap_overlay_info info;
                        ovl->get_overlay_info(ovl, &info);
-                       info.enabled = 1;
                        info.paddr = addr;
                        if (ovl->set_overlay_info(ovl, &info)) {
                                ret = -EINVAL;
@@ -1687,6 +1688,16 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
        if (ret)
                v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n");
 
+       for (j = 0; j < ovid->num_overlays; j++) {
+               struct omap_overlay *ovl = ovid->overlays[j];
+
+               if (ovl->manager && ovl->manager->device) {
+                       ret = ovl->enable(ovl);
+                       if (ret)
+                               goto streamon_err1;
+               }
+       }
+
        ret = 0;
 
 streamon_err1:
@@ -1716,16 +1727,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
        for (j = 0; j < ovid->num_overlays; j++) {
                struct omap_overlay *ovl = ovid->overlays[j];
 
-               if (ovl->manager && ovl->manager->device) {
-                       struct omap_overlay_info info;
-
-                       ovl->get_overlay_info(ovl, &info);
-                       info.enabled = 0;
-                       ret = ovl->set_overlay_info(ovl, &info);
-                       if (ret)
-                               v4l2_err(&vout->vid_dev->v4l2_dev,
-                               "failed to update overlay info in streamoff\n");
-               }
+               if (ovl->manager && ovl->manager->device)
+                       ovl->disable(ovl);
        }
 
        /* Turn of the pipeline */
@@ -1823,7 +1826,9 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
        ovid = &vout->vid_info;
        ovl = ovid->overlays[0];
 
-       a->flags = 0x0;
+       /* The video overlay must stay within the framebuffer and can't be
+          positioned independently. */
+       a->flags = V4L2_FBUF_FLAG_OVERLAY;
        a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY
                | V4L2_FBUF_CAP_SRC_CHROMAKEY;
 
index ebebcac49225209e133141f113b700bdbd65aa95..4be26abf6cea7a323ef0b15e7e1cedf3177ab916 100644 (file)
@@ -84,7 +84,7 @@ void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
 }
 
 int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
-                       u32 static_vrfb_allocation)
+                             bool static_vrfb_allocation)
 {
        int ret = 0, i, j;
        struct omap_vout_device *vout;
index d793501cafcc516710f319cd5a9d64acced3da49..27a95d23b913493db67d20b90857e37f621fdd10 100644 (file)
@@ -25,7 +25,7 @@
 #define MAC_VRFB_CTXS  4
 #define MAX_VOUT_DEV   2
 #define MAX_OVLS       3
-#define MAX_DISPLAYS   3
+#define MAX_DISPLAYS   10
 #define MAX_MANAGERS   3
 
 #define QQVGA_WIDTH            160
index 6a6cf388bae446d70a043eac83cb09e2b6a0e4e8..c20f5ecd67904d634d818b734b49a8f68f5dc2a3 100644 (file)
@@ -1436,13 +1436,13 @@ static int omap1_cam_querycap(struct soc_camera_host *ici,
        return 0;
 }
 
-static int omap1_cam_set_bus_param(struct soc_camera_device *icd,
-               __u32 pixfmt)
+static int omap1_cam_set_bus_param(struct soc_camera_device *icd)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct device *dev = icd->parent;
        struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct omap1_cam_dev *pcdev = ici->priv;
+       u32 pixfmt = icd->current_fmt->host_fmt->fourcc;
        const struct soc_camera_format_xlate *xlate;
        const struct soc_mbus_pixelfmt *fmt;
        struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
@@ -1713,17 +1713,7 @@ static struct platform_driver omap1_cam_driver = {
        .remove         = __exit_p(omap1_cam_remove),
 };
 
-static int __init omap1_cam_init(void)
-{
-       return platform_driver_register(&omap1_cam_driver);
-}
-module_init(omap1_cam_init);
-
-static void __exit omap1_cam_exit(void)
-{
-       platform_driver_unregister(&omap1_cam_driver);
-}
-module_exit(omap1_cam_exit);
+module_platform_driver(omap1_cam_driver);
 
 module_param(sg_mode, bool, 0644);
 MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg");
index 45522e603185f45dbc5bac41c3c99032f06da6ca..7d3864144368c30e7a1916ae169c4999765fba62 100644 (file)
@@ -1868,21 +1868,7 @@ static struct platform_driver omap24xxcam_driver = {
        },
 };
 
-/*
- *
- * Module initialisation and deinitialisation
- *
- */
-
-static int __init omap24xxcam_init(void)
-{
-       return platform_driver_register(&omap24xxcam_driver);
-}
-
-static void __exit omap24xxcam_cleanup(void)
-{
-       platform_driver_unregister(&omap24xxcam_driver);
-}
+module_platform_driver(omap24xxcam_driver);
 
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
 MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver");
@@ -1894,6 +1880,3 @@ MODULE_PARM_DESC(video_nr,
 module_param(capture_mem, int, 0);
 MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture "
                 "buffers (default 4800kiB)");
-
-module_init(omap24xxcam_init);
-module_exit(omap24xxcam_cleanup);
index d4c48ef227fb9379ed34ee4d09976cd86836658b..12d5f923e1d0fbf01ff18c08ce904cea53ab3fc4 100644 (file)
@@ -403,6 +403,7 @@ static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus)
 static void isp_isr_sbl(struct isp_device *isp)
 {
        struct device *dev = isp->dev;
+       struct isp_pipeline *pipe;
        u32 sbl_pcr;
 
        /*
@@ -416,27 +417,38 @@ static void isp_isr_sbl(struct isp_device *isp)
        if (sbl_pcr)
                dev_dbg(dev, "SBL overflow (PCR = 0x%08x)\n", sbl_pcr);
 
-       if (sbl_pcr & (ISPSBL_PCR_CCDC_WBL_OVF | ISPSBL_PCR_CSIA_WBL_OVF
-                    | ISPSBL_PCR_CSIB_WBL_OVF)) {
-               isp->isp_ccdc.error = 1;
-               if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW)
-                       isp->isp_prev.error = 1;
-               if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)
-                       isp->isp_res.error = 1;
+       if (sbl_pcr & ISPSBL_PCR_CSIB_WBL_OVF) {
+               pipe = to_isp_pipeline(&isp->isp_ccp2.subdev.entity);
+               if (pipe != NULL)
+                       pipe->error = true;
+       }
+
+       if (sbl_pcr & ISPSBL_PCR_CSIA_WBL_OVF) {
+               pipe = to_isp_pipeline(&isp->isp_csi2a.subdev.entity);
+               if (pipe != NULL)
+                       pipe->error = true;
+       }
+
+       if (sbl_pcr & ISPSBL_PCR_CCDC_WBL_OVF) {
+               pipe = to_isp_pipeline(&isp->isp_ccdc.subdev.entity);
+               if (pipe != NULL)
+                       pipe->error = true;
        }
 
        if (sbl_pcr & ISPSBL_PCR_PRV_WBL_OVF) {
-               isp->isp_prev.error = 1;
-               if (isp->isp_res.input == RESIZER_INPUT_VP &&
-                   !(isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER))
-                       isp->isp_res.error = 1;
+               pipe = to_isp_pipeline(&isp->isp_prev.subdev.entity);
+               if (pipe != NULL)
+                       pipe->error = true;
        }
 
        if (sbl_pcr & (ISPSBL_PCR_RSZ1_WBL_OVF
                       | ISPSBL_PCR_RSZ2_WBL_OVF
                       | ISPSBL_PCR_RSZ3_WBL_OVF
-                      | ISPSBL_PCR_RSZ4_WBL_OVF))
-               isp->isp_res.error = 1;
+                      | ISPSBL_PCR_RSZ4_WBL_OVF)) {
+               pipe = to_isp_pipeline(&isp->isp_res.subdev.entity);
+               if (pipe != NULL)
+                       pipe->error = true;
+       }
 
        if (sbl_pcr & ISPSBL_PCR_H3A_AF_WBL_OVF)
                omap3isp_stat_sbl_overflow(&isp->isp_af);
@@ -464,24 +476,17 @@ static irqreturn_t isp_isr(int irq, void *_isp)
                                       IRQ0STATUS_HS_VS_IRQ;
        struct isp_device *isp = _isp;
        u32 irqstatus;
-       int ret;
 
        irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
        isp_reg_writel(isp, irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
 
        isp_isr_sbl(isp);
 
-       if (irqstatus & IRQ0STATUS_CSIA_IRQ) {
-               ret = omap3isp_csi2_isr(&isp->isp_csi2a);
-               if (ret)
-                       isp->isp_ccdc.error = 1;
-       }
+       if (irqstatus & IRQ0STATUS_CSIA_IRQ)
+               omap3isp_csi2_isr(&isp->isp_csi2a);
 
-       if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
-               ret = omap3isp_ccp2_isr(&isp->isp_ccp2);
-               if (ret)
-                       isp->isp_ccdc.error = 1;
-       }
+       if (irqstatus & IRQ0STATUS_CSIB_IRQ)
+               omap3isp_ccp2_isr(&isp->isp_ccp2);
 
        if (irqstatus & IRQ0STATUS_CCDC_VD0_IRQ) {
                if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW)
@@ -2222,24 +2227,7 @@ static struct platform_driver omap3isp_driver = {
        },
 };
 
-/*
- * isp_init - ISP module initialization.
- */
-static int __init isp_init(void)
-{
-       return platform_driver_register(&omap3isp_driver);
-}
-
-/*
- * isp_cleanup - ISP module cleanup.
- */
-static void __exit isp_cleanup(void)
-{
-       platform_driver_unregister(&omap3isp_driver);
-}
-
-module_init(isp_init);
-module_exit(isp_cleanup);
+module_platform_driver(omap3isp_driver);
 
 MODULE_AUTHOR("Nokia Corporation");
 MODULE_DESCRIPTION("TI OMAP3 ISP driver");
index d341ba12593f0bc0a93fc1f66dc57a899b9aa1a7..a74a79701d346786fb8f3b91a7823694a6c74bdb 100644 (file)
@@ -1406,9 +1406,8 @@ static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
 
 static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc)
 {
-       struct isp_pipeline *pipe =
-               to_isp_pipeline(&ccdc->video_out.video.entity);
-       struct video_device *vdev = ccdc->subdev.devnode;
+       struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+       struct video_device *vdev = &ccdc->subdev.devnode;
        struct v4l2_event event;
 
        memset(&event, 0, sizeof(event));
@@ -1428,8 +1427,11 @@ static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events)
        unsigned long flags;
 
        if (events & IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ) {
+               struct isp_pipeline *pipe =
+                       to_isp_pipeline(&ccdc->subdev.entity);
+
                ccdc_lsc_error_handler(ccdc);
-               ccdc->error = 1;
+               pipe->error = true;
                dev_dbg(to_device(ccdc), "lsc prefetch error\n");
        }
 
@@ -1504,7 +1506,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
                goto done;
        }
 
-       buffer = omap3isp_video_buffer_next(&ccdc->video_out, ccdc->error);
+       buffer = omap3isp_video_buffer_next(&ccdc->video_out);
        if (buffer != NULL) {
                ccdc_set_outaddr(ccdc, buffer->isp_addr);
                restart = 1;
@@ -1518,7 +1520,6 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
                                        ISP_PIPELINE_STREAM_SINGLESHOT);
 
 done:
-       ccdc->error = 0;
        return restart;
 }
 
@@ -1744,7 +1745,6 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
                 */
                ccdc_config_vp(ccdc);
                ccdc_enable_vp(ccdc, 1);
-               ccdc->error = 0;
                ccdc_print_status(ccdc);
        }
 
index 483a19cac1ad9497ee9d1598eed3bf9f00830d45..6d0264bab75b0566c21e7939b39679a73a0a3d3a 100644 (file)
@@ -150,7 +150,6 @@ struct ispccdc_lsc {
  * @input: Active input
  * @output: Active outputs
  * @video_out: Output video node
- * @error: A hardware error occurred during capture
  * @alaw: A-law compression enabled (1) or disabled (0)
  * @lpf: Low pass filter enabled (1) or disabled (0)
  * @obclamp: Optical-black clamp enabled (1) or disabled (0)
@@ -178,7 +177,6 @@ struct isp_ccdc_device {
        enum ccdc_input_entity input;
        unsigned int output;
        struct isp_video video_out;
-       unsigned int error;
 
        unsigned int alaw:1,
                     lpf:1,
index 904ca8c8b17fb982e56faa32015336c1aea6435b..70ddbf35b223bc7f070d6572d0c1e60cbc15b74c 100644 (file)
@@ -556,7 +556,7 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
        struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
        struct isp_buffer *buffer;
 
-       buffer = omap3isp_video_buffer_next(&ccp2->video_in, ccp2->error);
+       buffer = omap3isp_video_buffer_next(&ccp2->video_in);
        if (buffer != NULL)
                ccp2_set_inaddr(ccp2, buffer->isp_addr);
 
@@ -567,8 +567,6 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
                        omap3isp_pipeline_set_stream(pipe,
                                                ISP_PIPELINE_STREAM_SINGLESHOT);
        }
-
-       ccp2->error = 0;
 }
 
 /*
@@ -576,13 +574,11 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
  * @ccp2: Pointer to ISP CCP2 device
  *
  * This will handle the CCP2 interrupts
- *
- * Returns -EIO in case of error, or 0 on success.
  */
-int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
+void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
 {
+       struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
        struct isp_device *isp = to_isp_device(ccp2);
-       int ret = 0;
        static const u32 ISPCCP2_LC01_ERROR =
                ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
                ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ |
@@ -604,19 +600,18 @@ int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
                       ISPCCP2_LCM_IRQSTATUS);
        /* Errors */
        if (lcx_irqstatus & ISPCCP2_LC01_ERROR) {
-               ccp2->error = 1;
+               pipe->error = true;
                dev_dbg(isp->dev, "CCP2 err:%x\n", lcx_irqstatus);
-               return -EIO;
+               return;
        }
 
        if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ) {
-               ccp2->error = 1;
+               pipe->error = true;
                dev_dbg(isp->dev, "CCP2 OCP err:%x\n", lcm_irqstatus);
-               ret = -EIO;
        }
 
        if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping))
-               return 0;
+               return;
 
        /* Frame number propagation */
        if (lcx_irqstatus & ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ) {
@@ -629,8 +624,6 @@ int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
        /* Handle queued buffers on frame end interrupts */
        if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ)
                ccp2_isr_buffer(ccp2);
-
-       return ret;
 }
 
 /* -----------------------------------------------------------------------------
@@ -867,7 +860,6 @@ static int ccp2_s_stream(struct v4l2_subdev *sd, int enable)
                if (enable == ISP_PIPELINE_STREAM_STOPPED)
                        return 0;
                atomic_set(&ccp2->stopping, 0);
-               ccp2->error = 0;
        }
 
        switch (enable) {
index 6674e9de2cd7aace79aedb9fbceb958fbb27bf63..76d65f4576ef017d6ca2dad854a0697e4799e35c 100644 (file)
@@ -82,7 +82,6 @@ struct isp_ccp2_device {
        struct isp_video video_in;
        struct isp_csiphy *phy;
        struct regulator *vdds_csib;
-       unsigned int error;
        enum isp_pipeline_stream_state state;
        wait_queue_head_t wait;
        atomic_t stopping;
@@ -94,6 +93,6 @@ void omap3isp_ccp2_cleanup(struct isp_device *isp);
 int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2,
                        struct v4l2_device *vdev);
 void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2);
-int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2);
+void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2);
 
 #endif /* OMAP3_ISP_CCP2_H */
index 0c5f1cb9d99d874d3807db776357879726bf9a0e..fcb5168996a73f740b513087b441dfaa66feaf39 100644 (file)
@@ -667,7 +667,7 @@ static void csi2_isr_buffer(struct isp_csi2_device *csi2)
 
        csi2_ctx_enable(isp, csi2, 0, 0);
 
-       buffer = omap3isp_video_buffer_next(&csi2->video_out, 0);
+       buffer = omap3isp_video_buffer_next(&csi2->video_out);
 
        /*
         * Let video queue operation restart engine if there is an underrun
@@ -727,17 +727,15 @@ static void csi2_isr_ctx(struct isp_csi2_device *csi2,
 
 /*
  * omap3isp_csi2_isr - CSI2 interrupt handling.
- *
- * Return -EIO on Transmission error
  */
-int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
+void omap3isp_csi2_isr(struct isp_csi2_device *csi2)
 {
+       struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity);
        u32 csi2_irqstatus, cpxio1_irqstatus;
        struct isp_device *isp = csi2->isp;
-       int retval = 0;
 
        if (!csi2->available)
-               return -ENODEV;
+               return;
 
        csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS);
        isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS);
@@ -750,7 +748,7 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
                               csi2->regs1, ISPCSI2_PHY_IRQSTATUS);
                dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ "
                        "%x\n", cpxio1_irqstatus);
-               retval = -EIO;
+               pipe->error = true;
        }
 
        if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
@@ -775,11 +773,11 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
                         ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0,
                        (csi2_irqstatus &
                         ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0);
-               retval = -EIO;
+               pipe->error = true;
        }
 
        if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping))
-               return 0;
+               return;
 
        /* Successful cases */
        if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0))
@@ -787,8 +785,6 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
 
        if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
                dev_dbg(isp->dev, "CSI2: ECC correction done\n");
-
-       return retval;
 }
 
 /* -----------------------------------------------------------------------------
index 456fb7fb8a0f68b853153c46840f4cd2d8d94958..885ad79a767842726bb93653517a11a9dfeacea9 100644 (file)
@@ -156,7 +156,7 @@ struct isp_csi2_device {
        atomic_t stopping;
 };
 
-int omap3isp_csi2_isr(struct isp_csi2_device *csi2);
+void omap3isp_csi2_isr(struct isp_csi2_device *csi2);
 int omap3isp_csi2_reset(struct isp_csi2_device *csi2);
 int omap3isp_csi2_init(struct isp_device *isp);
 void omap3isp_csi2_cleanup(struct isp_device *isp);
index ccb876fe023f1c1a1257d228b692305c9d6267e3..6d0fb2c8c26da01e4cc8643f749fa1aa8be4ea80 100644 (file)
@@ -116,11 +116,11 @@ static struct omap3isp_prev_csc flr_prev_csc = {
 #define PREV_MIN_IN_HEIGHT     8
 #define PREV_MAX_IN_HEIGHT     16384
 
-#define PREV_MIN_OUT_WIDTH     0
-#define PREV_MIN_OUT_HEIGHT    0
-#define PREV_MAX_OUT_WIDTH     1280
-#define PREV_MAX_OUT_WIDTH_ES2 3300
-#define PREV_MAX_OUT_WIDTH_3630        4096
+#define PREV_MIN_OUT_WIDTH             0
+#define PREV_MIN_OUT_HEIGHT            0
+#define PREV_MAX_OUT_WIDTH_REV_1       1280
+#define PREV_MAX_OUT_WIDTH_REV_2       3300
+#define PREV_MAX_OUT_WIDTH_REV_15      4096
 
 /*
  * Coeficient Tables for the submodules in Preview.
@@ -1306,14 +1306,14 @@ static unsigned int preview_max_out_width(struct isp_prev_device *prev)
 
        switch (isp->revision) {
        case ISP_REVISION_1_0:
-               return PREV_MAX_OUT_WIDTH;
+               return PREV_MAX_OUT_WIDTH_REV_1;
 
        case ISP_REVISION_2_0:
        default:
-               return PREV_MAX_OUT_WIDTH_ES2;
+               return PREV_MAX_OUT_WIDTH_REV_2;
 
        case ISP_REVISION_15_0:
-               return PREV_MAX_OUT_WIDTH_3630;
+               return PREV_MAX_OUT_WIDTH_REV_15;
        }
 }
 
@@ -1404,16 +1404,14 @@ static void preview_isr_buffer(struct isp_prev_device *prev)
        int restart = 0;
 
        if (prev->input == PREVIEW_INPUT_MEMORY) {
-               buffer = omap3isp_video_buffer_next(&prev->video_in,
-                                                   prev->error);
+               buffer = omap3isp_video_buffer_next(&prev->video_in);
                if (buffer != NULL)
                        preview_set_inaddr(prev, buffer->isp_addr);
                pipe->state |= ISP_PIPELINE_IDLE_INPUT;
        }
 
        if (prev->output & PREVIEW_OUTPUT_MEMORY) {
-               buffer = omap3isp_video_buffer_next(&prev->video_out,
-                                                   prev->error);
+               buffer = omap3isp_video_buffer_next(&prev->video_out);
                if (buffer != NULL) {
                        preview_set_outaddr(prev, buffer->isp_addr);
                        restart = 1;
@@ -1440,8 +1438,6 @@ static void preview_isr_buffer(struct isp_prev_device *prev)
        default:
                return;
        }
-
-       prev->error = 0;
 }
 
 /*
@@ -1565,7 +1561,6 @@ static int preview_set_stream(struct v4l2_subdev *sd, int enable)
                omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
                preview_configure(prev);
                atomic_set(&prev->stopping, 0);
-               prev->error = 0;
                preview_print_status(prev);
        }
 
index f54e775c2df4e2e2e9a6eba4935d34b4cff31b64..09686607973c4b7c13a340c43290228fa1173b9b 100644 (file)
@@ -157,7 +157,6 @@ struct isptables_update {
  * @output: Bitmask of the active output
  * @video_in: Input video entity
  * @video_out: Output video entity
- * @error: A hardware error occurred during capture
  * @params: Module configuration data
  * @shadow_update: If set, update the hardware configured in the next interrupt
  * @underrun: Whether the preview entity has queued buffers on the output
@@ -179,7 +178,6 @@ struct isp_prev_device {
        unsigned int output;
        struct isp_video video_in;
        struct isp_video video_out;
-       unsigned int error;
 
        struct prev_params params;
        unsigned int shadow_update:1;
index 50e593bfcfaf02d069311fe3f6543089eb0d749c..6958a9e3dc222864cf3caaa18435dd6c8901c86f 100644 (file)
@@ -1038,7 +1038,7 @@ static void resizer_isr_buffer(struct isp_res_device *res)
        /* Complete the output buffer and, if reading from memory, the input
         * buffer.
         */
-       buffer = omap3isp_video_buffer_next(&res->video_out, res->error);
+       buffer = omap3isp_video_buffer_next(&res->video_out);
        if (buffer != NULL) {
                resizer_set_outaddr(res, buffer->isp_addr);
                restart = 1;
@@ -1047,7 +1047,7 @@ static void resizer_isr_buffer(struct isp_res_device *res)
        pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
 
        if (res->input == RESIZER_INPUT_MEMORY) {
-               buffer = omap3isp_video_buffer_next(&res->video_in, 0);
+               buffer = omap3isp_video_buffer_next(&res->video_in);
                if (buffer != NULL)
                        resizer_set_inaddr(res, buffer->isp_addr);
                pipe->state |= ISP_PIPELINE_IDLE_INPUT;
@@ -1064,8 +1064,6 @@ static void resizer_isr_buffer(struct isp_res_device *res)
                if (restart)
                        resizer_enable_oneshot(res);
        }
-
-       res->error = 0;
 }
 
 /*
@@ -1154,7 +1152,6 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
 
                omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
                resizer_configure(res);
-               res->error = 0;
                resizer_print_status(res);
        }
 
index 76abc2e4212612c743d5d65c96d4b07acfe3a695..70c1c0e1bbdf687594c5ac26baa5361bd3b16a18 100644 (file)
@@ -107,7 +107,6 @@ struct isp_res_device {
        enum resizer_input_entity input;
        struct isp_video video_in;
        struct isp_video video_out;
-       unsigned int error;
 
        u32 addr_base;   /* stored source buffer address in memory mode */
        u32 crop_offset; /* additional offset for crop in memory mode */
index bd3aebafafa08c29502c5624623b3cf3c1830b74..b02070057724a47263f732ad8a05a6df56ad59ea 100644 (file)
@@ -211,14 +211,14 @@ static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix,
        mbus->width = pix->width;
        mbus->height = pix->height;
 
-       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+       /* Skip the last format in the loop so that it will be selected if no
+        * match is found.
+        */
+       for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) {
                if (formats[i].pixelformat == pix->pixelformat)
                        break;
        }
 
-       if (WARN_ON(i == ARRAY_SIZE(formats)))
-               return;
-
        mbus->code = formats[i].code;
        mbus->colorspace = pix->colorspace;
        mbus->field = pix->field;
@@ -581,21 +581,20 @@ static const struct isp_video_queue_operations isp_video_queue_ops = {
 /*
  * omap3isp_video_buffer_next - Complete the current buffer and return the next
  * @video: ISP video object
- * @error: Whether an error occurred during capture
  *
  * Remove the current video buffer from the DMA queue and fill its timestamp,
  * field count and state fields before waking up its completion handler.
  *
- * The buffer state is set to VIDEOBUF_DONE if no error occurred (@error is 0)
- * or VIDEOBUF_ERROR otherwise (@error is non-zero).
+ * For capture video nodes the buffer state is set to ISP_BUF_STATE_DONE if no
+ * error has been flagged in the pipeline, or to ISP_BUF_STATE_ERROR otherwise.
+ * For video output nodes the buffer state is always set to ISP_BUF_STATE_DONE.
  *
  * The DMA queue is expected to contain at least one buffer.
  *
  * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is
  * empty.
  */
-struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
-                                             unsigned int error)
+struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
 {
        struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
        struct isp_video_queue *queue = video->queue;
@@ -630,7 +629,13 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
        else
                buf->vbuf.sequence = atomic_read(&pipe->frame_number);
 
-       buf->state = error ? ISP_BUF_STATE_ERROR : ISP_BUF_STATE_DONE;
+       /* Report pipeline errors to userspace on the capture device side. */
+       if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) {
+               buf->state = ISP_BUF_STATE_ERROR;
+               pipe->error = false;
+       } else {
+               buf->state = ISP_BUF_STATE_DONE;
+       }
 
        wake_up(&buf->wait);
 
@@ -1016,6 +1021,8 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        if (ret < 0)
                goto error;
 
+       pipe->error = false;
+
        spin_lock_irqsave(&pipe->lock, flags);
        pipe->state &= ~ISP_PIPELINE_STREAM;
        pipe->state |= state;
index 08cbfa144e6e4f1a7beb1baa2a2dc2571a5b6d71..d91bdb919be0c8c925499a99cbdeb311fc0efb2f 100644 (file)
@@ -85,6 +85,10 @@ enum isp_pipeline_state {
        ISP_PIPELINE_STREAM = 64,
 };
 
+/*
+ * struct isp_pipeline - An ISP hardware pipeline
+ * @error: A hardware error occurred during capture
+ */
 struct isp_pipeline {
        struct media_pipeline pipe;
        spinlock_t lock;                /* Pipeline state and queue flags */
@@ -96,6 +100,7 @@ struct isp_pipeline {
        unsigned int max_rate;
        atomic_t frame_number;
        bool do_propagation; /* of frame number */
+       bool error;
        struct v4l2_fract max_timeperframe;
 };
 
@@ -194,8 +199,7 @@ void omap3isp_video_cleanup(struct isp_video *video);
 int omap3isp_video_register(struct isp_video *video,
                            struct v4l2_device *vdev);
 void omap3isp_video_unregister(struct isp_video *video);
-struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
-                                             unsigned int error);
+struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video);
 void omap3isp_video_resume(struct isp_video *video, int continuous);
 struct media_pad *omap3isp_video_remote_pad(struct isp_video *video);
 
index 8aa05853128098732c6090421a1bba38e1c8315a..6a564964853a2cd726e844664ad369c687a5b147 100644 (file)
@@ -25,7 +25,7 @@ MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
 MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
 MODULE_LICENSE("GPL");
 
-static int debug;
+static bool debug;
 module_param(debug, bool, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
index 122b45760f0d9103306502e09e08c9d0b03002ae..ebc2c7e39233c1430df417492542d6769203e301 100644 (file)
@@ -2546,8 +2546,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        }
 
        /* Define and configure additional controls from cx2341x module. */
-       hdw->mpeg_ctrl_info = kzalloc(
-               sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
+       hdw->mpeg_ctrl_info = kcalloc(MPEGDEF_COUNT,
+                                     sizeof(*(hdw->mpeg_ctrl_info)),
+                                     GFP_KERNEL);
        if (!hdw->mpeg_ctrl_info) goto fail;
        for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
                cptr = hdw->controls + idx + CTRLDEF_COUNT;
index 3977addf3ba8553d586bfb0a3b8521e146435e7e..1f506fde97d0a52433a7477f6ac843cc60af1f2f 100644 (file)
@@ -102,52 +102,18 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] =
 #include "pwc-nala.h"
 };
 
-static void pwc_set_image_buffer_size(struct pwc_device *pdev);
-
 /****************************************************************************/
 
-static int _send_control_msg(struct pwc_device *pdev,
-       u8 request, u16 value, int index, void *buf, int buflen)
-{
-       int rc;
-       void *kbuf = NULL;
-
-       if (buflen) {
-               kbuf = kmalloc(buflen, GFP_KERNEL); /* not allowed on stack */
-               if (kbuf == NULL)
-                       return -ENOMEM;
-               memcpy(kbuf, buf, buflen);
-       }
-
-       rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
-               request,
-               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               value,
-               index,
-               kbuf, buflen, USB_CTRL_SET_TIMEOUT);
-
-       kfree(kbuf);
-       return rc;
-}
-
 static int recv_control_msg(struct pwc_device *pdev,
-       u8 request, u16 value, void *buf, int buflen)
+       u8 request, u16 value, int recv_count)
 {
        int rc;
-       void *kbuf = kmalloc(buflen, GFP_KERNEL); /* not allowed on stack */
-
-       if (kbuf == NULL)
-               return -ENOMEM;
 
        rc = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
                request,
                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               value,
-               pdev->vcinterface,
-               kbuf, buflen, USB_CTRL_GET_TIMEOUT);
-       memcpy(buf, kbuf, buflen);
-       kfree(kbuf);
-
+               value, pdev->vcinterface,
+               pdev->ctrl_buf, recv_count, USB_CTRL_GET_TIMEOUT);
        if (rc < 0)
                PWC_ERROR("recv_control_msg error %d req %02x val %04x\n",
                          rc, request, value);
@@ -155,26 +121,39 @@ static int recv_control_msg(struct pwc_device *pdev,
 }
 
 static inline int send_video_command(struct pwc_device *pdev,
-       int index, void *buf, int buflen)
+       int index, const unsigned char *buf, int buflen)
 {
-       return _send_control_msg(pdev,
-               SET_EP_STREAM_CTL,
-               VIDEO_OUTPUT_CONTROL_FORMATTER,
-               index,
-               buf, buflen);
+       int rc;
+
+       memcpy(pdev->ctrl_buf, buf, buflen);
+
+       rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+                       SET_EP_STREAM_CTL,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       VIDEO_OUTPUT_CONTROL_FORMATTER, index,
+                       pdev->ctrl_buf, buflen, USB_CTRL_SET_TIMEOUT);
+       if (rc >= 0)
+               memcpy(pdev->cmd_buf, buf, buflen);
+       else
+               PWC_ERROR("send_video_command error %d\n", rc);
+
+       return rc;
 }
 
 int send_control_msg(struct pwc_device *pdev,
        u8 request, u16 value, void *buf, int buflen)
 {
-       return _send_control_msg(pdev,
-               request, value, pdev->vcinterface, buf, buflen);
+       return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
+                       request,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, pdev->vcinterface,
+                       buf, buflen, USB_CTRL_SET_TIMEOUT);
 }
 
-static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
+static int set_video_mode_Nala(struct pwc_device *pdev, int size, int pixfmt,
+                              int frames, int *compression, int send_to_cam)
 {
-       unsigned char buf[3];
-       int ret, fps;
+       int fps, ret = 0;
        struct Nala_table_entry *pEntry;
        int frames2frames[31] =
        { /* closest match of framerate */
@@ -196,35 +175,34 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
          7              /* 30    */
        };
 
-       if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25)
+       if (size < 0 || size > PSZ_CIF)
                return -EINVAL;
+       if (frames < 4)
+               frames = 4;
+       else if (frames > 25)
+               frames = 25;
        frames = frames2frames[frames];
        fps = frames2table[frames];
        pEntry = &Nala_table[size][fps];
        if (pEntry->alternate == 0)
                return -EINVAL;
 
-       memcpy(buf, pEntry->mode, 3);
-       ret = send_video_command(pdev, pdev->vendpoint, buf, 3);
-       if (ret < 0) {
-               PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret);
+       if (send_to_cam)
+               ret = send_video_command(pdev, pdev->vendpoint,
+                                        pEntry->mode, 3);
+       if (ret < 0)
                return ret;
-       }
-       if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
-               ret = pwc_dec1_init(pdev, pdev->type, pdev->release, buf);
-               if (ret < 0)
-                       return ret;
-       }
 
-       pdev->cmd_len = 3;
-       memcpy(pdev->cmd_buf, buf, 3);
+       if (pEntry->compressed && pixfmt == V4L2_PIX_FMT_YUV420)
+               pwc_dec1_init(pdev, pEntry->mode);
 
        /* Set various parameters */
+       pdev->pixfmt = pixfmt;
        pdev->vframes = frames;
-       pdev->vsize = size;
        pdev->valternate = pEntry->alternate;
-       pdev->image = pwc_image_sizes[size];
-       pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
+       pdev->width  = pwc_image_sizes[size][0];
+       pdev->height = pwc_image_sizes[size][1];
+       pdev->frame_size = (pdev->width * pdev->height * 3) / 2;
        if (pEntry->compressed) {
                if (pdev->release < 5) { /* 4 fold compression */
                        pdev->vbandlength = 528;
@@ -237,183 +215,142 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
        }
        else
                pdev->vbandlength = 0;
+
+       /* Let pwc-if.c:isoc_init know we don't support higher compression */
+       *compression = 3;
+
        return 0;
 }
 
 
-static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt,
+                               int frames, int *compression, int send_to_cam)
 {
-       unsigned char buf[13];
        const struct Timon_table_entry *pChoose;
-       int ret, fps;
+       int fps, ret = 0;
 
-       if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
-               return -EINVAL;
-       if (size == PSZ_VGA && frames > 15)
+       if (size >= PSZ_MAX || *compression < 0 || *compression > 3)
                return -EINVAL;
+       if (frames < 5)
+               frames = 5;
+       else if (size == PSZ_VGA && frames > 15)
+               frames = 15;
+       else if (frames > 30)
+               frames = 30;
        fps = (frames / 5) - 1;
 
-       /* Find a supported framerate with progressively higher compression ratios
-          if the preferred ratio is not available.
-       */
+       /* Find a supported framerate with progressively higher compression */
        pChoose = NULL;
-       while (compression <= 3) {
-          pChoose = &Timon_table[size][fps][compression];
-          if (pChoose->alternate != 0)
-            break;
-          compression++;
+       while (*compression <= 3) {
+               pChoose = &Timon_table[size][fps][*compression];
+               if (pChoose->alternate != 0)
+                       break;
+               (*compression)++;
        }
        if (pChoose == NULL || pChoose->alternate == 0)
                return -ENOENT; /* Not supported. */
 
-       memcpy(buf, pChoose->mode, 13);
-       if (snapshot)
-               buf[0] |= 0x80;
-       ret = send_video_command(pdev, pdev->vendpoint, buf, 13);
+       if (send_to_cam)
+               ret = send_video_command(pdev, pdev->vendpoint,
+                                        pChoose->mode, 13);
        if (ret < 0)
                return ret;
 
-       if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
-               ret = pwc_dec23_init(pdev, pdev->type, buf);
-               if (ret < 0)
-                       return ret;
-       }
-
-       pdev->cmd_len = 13;
-       memcpy(pdev->cmd_buf, buf, 13);
+       if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420)
+               pwc_dec23_init(pdev, pChoose->mode);
 
        /* Set various parameters */
-       pdev->vframes = frames;
-       pdev->vsize = size;
-       pdev->vsnapshot = snapshot;
+       pdev->pixfmt = pixfmt;
+       pdev->vframes = (fps + 1) * 5;
        pdev->valternate = pChoose->alternate;
-       pdev->image = pwc_image_sizes[size];
+       pdev->width  = pwc_image_sizes[size][0];
+       pdev->height = pwc_image_sizes[size][1];
        pdev->vbandlength = pChoose->bandlength;
        if (pChoose->bandlength > 0)
-               pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
+               pdev->frame_size = (pChoose->bandlength * pdev->height) / 4;
        else
-               pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+               pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
        return 0;
 }
 
 
-static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt,
+                               int frames, int *compression, int send_to_cam)
 {
        const struct Kiara_table_entry *pChoose = NULL;
-       int fps, ret;
-       unsigned char buf[12];
-       struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}};
+       int fps, ret = 0;
 
-       if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
-               return -EINVAL;
-       if (size == PSZ_VGA && frames > 15)
+       if (size >= PSZ_MAX || *compression < 0 || *compression > 3)
                return -EINVAL;
+       if (frames < 5)
+               frames = 5;
+       else if (size == PSZ_VGA && frames > 15)
+               frames = 15;
+       else if (frames > 30)
+               frames = 30;
        fps = (frames / 5) - 1;
 
-       /* special case: VGA @ 5 fps and snapshot is raw bayer mode */
-       if (size == PSZ_VGA && frames == 5 && snapshot && pdev->pixfmt != V4L2_PIX_FMT_YUV420)
-       {
-               /* Only available in case the raw palette is selected or
-                  we have the decompressor available. This mode is
-                  only available in compressed form
-               */
-               PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n");
-               pChoose = &RawEntry;
-       }
-       else
-       {
-               /* Find a supported framerate with progressively higher compression ratios
-                  if the preferred ratio is not available.
-                  Skip this step when using RAW modes.
-               */
-               snapshot = 0;
-               while (compression <= 3) {
-                       pChoose = &Kiara_table[size][fps][compression];
-                       if (pChoose->alternate != 0)
-                               break;
-                       compression++;
-               }
+       /* Find a supported framerate with progressively higher compression */
+       while (*compression <= 3) {
+               pChoose = &Kiara_table[size][fps][*compression];
+               if (pChoose->alternate != 0)
+                       break;
+               (*compression)++;
        }
        if (pChoose == NULL || pChoose->alternate == 0)
                return -ENOENT; /* Not supported. */
 
-       PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate);
-
-       /* usb_control_msg won't take staticly allocated arrays as argument?? */
-       memcpy(buf, pChoose->mode, 12);
-       if (snapshot)
-               buf[0] |= 0x80;
-
        /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
-       ret = send_video_command(pdev, 4 /* pdev->vendpoint */, buf, 12);
+       if (send_to_cam)
+               ret = send_video_command(pdev, 4, pChoose->mode, 12);
        if (ret < 0)
                return ret;
 
-       if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
-               ret = pwc_dec23_init(pdev, pdev->type, buf);
-               if (ret < 0)
-                       return ret;
-       }
+       if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420)
+               pwc_dec23_init(pdev, pChoose->mode);
 
-       pdev->cmd_len = 12;
-       memcpy(pdev->cmd_buf, buf, 12);
        /* All set and go */
-       pdev->vframes = frames;
-       pdev->vsize = size;
-       pdev->vsnapshot = snapshot;
+       pdev->pixfmt = pixfmt;
+       pdev->vframes = (fps + 1) * 5;
        pdev->valternate = pChoose->alternate;
-       pdev->image = pwc_image_sizes[size];
+       pdev->width  = pwc_image_sizes[size][0];
+       pdev->height = pwc_image_sizes[size][1];
        pdev->vbandlength = pChoose->bandlength;
        if (pdev->vbandlength > 0)
-               pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
+               pdev->frame_size = (pdev->vbandlength * pdev->height) / 4;
        else
-               pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
-       PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n",
-           pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength);
+               pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
+       PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n",
+           pdev->frame_size, pdev->vframes, size, pdev->vbandlength);
        return 0;
 }
 
-
-
-/**
-   @pdev: device structure
-   @width: viewport width
-   @height: viewport height
-   @frame: framerate, in fps
-   @compression: preferred compression ratio
-   @snapshot: snapshot mode or streaming
- */
-int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot)
+int pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
+       int pixfmt, int frames, int *compression, int send_to_cam)
 {
        int ret, size;
 
-       PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt);
-       size = pwc_decode_size(pdev, width, height);
-       if (size < 0) {
-               PWC_DEBUG_MODULE("Could not find suitable size.\n");
-               return -ERANGE;
-       }
+       PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n",
+                      width, height, frames, pixfmt);
+       size = pwc_get_size(pdev, width, height);
        PWC_TRACE("decode_size = %d.\n", size);
 
        if (DEVICE_USE_CODEC1(pdev->type)) {
-               ret = set_video_mode_Nala(pdev, size, frames);
-
+               ret = set_video_mode_Nala(pdev, size, pixfmt, frames,
+                                         compression, send_to_cam);
        } else if (DEVICE_USE_CODEC3(pdev->type)) {
-               ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
-
+               ret = set_video_mode_Kiara(pdev, size, pixfmt, frames,
+                                          compression, send_to_cam);
        } else {
-               ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
+               ret = set_video_mode_Timon(pdev, size, pixfmt, frames,
+                                          compression, send_to_cam);
        }
        if (ret < 0) {
                PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
                return ret;
        }
-       pdev->view.x = width;
-       pdev->view.y = height;
-       pdev->vcompression = compression;
        pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
-       pwc_set_image_buffer_size(pdev);
-       PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
+       PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height);
        return 0;
 }
 
@@ -470,44 +407,15 @@ unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned i
        return ret;
 }
 
-static void pwc_set_image_buffer_size(struct pwc_device *pdev)
-{
-       int factor = 0;
-
-       /* for V4L2_PIX_FMT_YUV420 */
-       switch (pdev->pixfmt) {
-       case V4L2_PIX_FMT_YUV420:
-               factor = 6;
-               break;
-       case V4L2_PIX_FMT_PWC1:
-       case V4L2_PIX_FMT_PWC2:
-               factor = 6; /* can be uncompressed YUV420P */
-               break;
-       }
-
-       /* Set sizes in bytes */
-       pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
-       pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
-
-       /* Align offset, or you'll get some very weird results in
-          YUV420 mode... x must be multiple of 4 (to get the Y's in
-          place), and y even (or you'll mixup U & V). This is less of a
-          problem for YUV420P.
-        */
-       pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
-       pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
-}
-
 int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
 {
        int ret;
-       u8 buf;
 
-       ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf));
+       ret = recv_control_msg(pdev, request, value, 1);
        if (ret < 0)
                return ret;
 
-       *data = buf;
+       *data = pdev->ctrl_buf[0];
        return 0;
 }
 
@@ -515,7 +423,8 @@ int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data)
 {
        int ret;
 
-       ret = send_control_msg(pdev, request, value, &data, sizeof(data));
+       pdev->ctrl_buf[0] = data;
+       ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 1);
        if (ret < 0)
                return ret;
 
@@ -525,37 +434,34 @@ int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data)
 int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
 {
        int ret;
-       s8 buf;
 
-       ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf));
+       ret = recv_control_msg(pdev, request, value, 1);
        if (ret < 0)
                return ret;
 
-       *data = buf;
+       *data = ((s8 *)pdev->ctrl_buf)[0];
        return 0;
 }
 
 int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
 {
        int ret;
-       u8 buf[2];
 
-       ret = recv_control_msg(pdev, request, value, buf, sizeof(buf));
+       ret = recv_control_msg(pdev, request, value, 2);
        if (ret < 0)
                return ret;
 
-       *data = (buf[1] << 8) | buf[0];
+       *data = (pdev->ctrl_buf[1] << 8) | pdev->ctrl_buf[0];
        return 0;
 }
 
 int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data)
 {
        int ret;
-       u8 buf[2];
 
-       buf[0] = data & 0xff;
-       buf[1] = data >> 8;
-       ret = send_control_msg(pdev, request, value, buf, sizeof(buf));
+       pdev->ctrl_buf[0] = data & 0xff;
+       pdev->ctrl_buf[1] = data >> 8;
+       ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 2);
        if (ret < 0)
                return ret;
 
@@ -576,7 +482,6 @@ int pwc_button_ctrl(struct pwc_device *pdev, u16 value)
 /* POWER */
 void pwc_camera_power(struct pwc_device *pdev, int power)
 {
-       char buf;
        int r;
 
        if (!pdev->power_save)
@@ -586,69 +491,18 @@ void pwc_camera_power(struct pwc_device *pdev, int power)
                return; /* Not supported by Nala or Timon < release 6 */
 
        if (power)
-               buf = 0x00; /* active */
+               pdev->ctrl_buf[0] = 0x00; /* active */
        else
-               buf = 0xFF; /* power save */
-       r = send_control_msg(pdev,
-               SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER,
-               &buf, sizeof(buf));
-
+               pdev->ctrl_buf[0] = 0xFF; /* power save */
+       r = send_control_msg(pdev, SET_STATUS_CTL,
+               SET_POWER_SAVE_MODE_FORMATTER, pdev->ctrl_buf, 1);
        if (r < 0)
                PWC_ERROR("Failed to power %s camera (%d)\n",
                          power ? "on" : "off", r);
 }
 
-static int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
-{
-       unsigned char buf;
-
-       /* useful range is 0x01..0x20 */
-       buf = speed / 0x7f0;
-       return send_control_msg(pdev,
-               SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf));
-}
-
-static int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *value = buf * 0x7f0;
-       return 0;
-}
-
-
-static int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
-{
-       unsigned char buf;
-
-       /* useful range is 0x01..0x3F */
-       buf = (delay >> 10);
-       return send_control_msg(pdev,
-               SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf));
-}
-
-static int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *value = buf << 10;
-       return 0;
-}
-
-
 int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
 {
-       unsigned char buf[2];
        int r;
 
        if (pdev->type < 730)
@@ -664,123 +518,20 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
        if (off_value > 0xff)
                off_value = 0xff;
 
-       buf[0] = on_value;
-       buf[1] = off_value;
+       pdev->ctrl_buf[0] = on_value;
+       pdev->ctrl_buf[1] = off_value;
 
        r = send_control_msg(pdev,
-               SET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf));
+               SET_STATUS_CTL, LED_FORMATTER, pdev->ctrl_buf, 2);
        if (r < 0)
                PWC_ERROR("Failed to set LED on/off time (%d)\n", r);
 
        return r;
 }
 
-static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
-{
-       unsigned char buf[2];
-       int ret;
-
-       if (pdev->type < 730) {
-               *on_value = -1;
-               *off_value = -1;
-               return 0;
-       }
-
-       ret = recv_control_msg(pdev,
-               GET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *on_value = buf[0] * 100;
-       *off_value = buf[1] * 100;
-       return 0;
-}
-
-static int _pwc_mpt_reset(struct pwc_device *pdev, int flags)
-{
-       unsigned char buf;
-
-       buf = flags & 0x03; // only lower two bits are currently used
-       return send_control_msg(pdev,
-               SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, &buf, sizeof(buf));
-}
-
-int pwc_mpt_reset(struct pwc_device *pdev, int flags)
-{
-       int ret;
-       ret = _pwc_mpt_reset(pdev, flags);
-       if (ret >= 0) {
-               pdev->pan_angle = 0;
-               pdev->tilt_angle = 0;
-       }
-       return ret;
-}
-
-static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
-{
-       unsigned char buf[4];
-
-       /* set new relative angle; angles are expressed in degrees * 100,
-          but cam as .5 degree resolution, hence divide by 200. Also
-          the angle must be multiplied by 64 before it's send to
-          the cam (??)
-        */
-       pan  =  64 * pan  / 100;
-       tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */
-       buf[0] = pan & 0xFF;
-       buf[1] = (pan >> 8) & 0xFF;
-       buf[2] = tilt & 0xFF;
-       buf[3] = (tilt >> 8) & 0xFF;
-       return send_control_msg(pdev,
-               SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, &buf, sizeof(buf));
-}
-
-int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
-{
-       int ret;
-
-       /* check absolute ranges */
-       if (pan  < pdev->angle_range.pan_min  ||
-           pan  > pdev->angle_range.pan_max  ||
-           tilt < pdev->angle_range.tilt_min ||
-           tilt > pdev->angle_range.tilt_max)
-               return -ERANGE;
-
-       /* go to relative range, check again */
-       pan  -= pdev->pan_angle;
-       tilt -= pdev->tilt_angle;
-       /* angles are specified in degrees * 100, thus the limit = 36000 */
-       if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000)
-               return -ERANGE;
-
-       ret = _pwc_mpt_set_angle(pdev, pan, tilt);
-       if (ret >= 0) {
-               pdev->pan_angle  += pan;
-               pdev->tilt_angle += tilt;
-       }
-       if (ret == -EPIPE) /* stall -> out of range */
-               ret = -ERANGE;
-       return ret;
-}
-
-static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
-{
-       int ret;
-       unsigned char buf[5];
-
-       ret = recv_control_msg(pdev,
-               GET_MPT_CTL, PT_STATUS_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       status->status = buf[0] & 0x7; // 3 bits are used for reporting
-       status->time_pan = (buf[1] << 8) + buf[2];
-       status->time_tilt = (buf[3] << 8) + buf[4];
-       return 0;
-}
-
 #ifdef CONFIG_USB_PWC_DEBUG
 int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
 {
-       unsigned char buf;
        int ret = -1, request;
 
        if (pdev->type < 675)
@@ -790,431 +541,13 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
        else
                request = SENSOR_TYPE_FORMATTER2;
 
-       ret = recv_control_msg(pdev,
-               GET_STATUS_CTL, request, &buf, sizeof(buf));
+       ret = recv_control_msg(pdev, GET_STATUS_CTL, request, 1);
        if (ret < 0)
                return ret;
        if (pdev->type < 675)
-               *sensor = buf | 0x100;
+               *sensor = pdev->ctrl_buf[0] | 0x100;
        else
-               *sensor = buf;
+               *sensor = pdev->ctrl_buf[0];
        return 0;
 }
 #endif
-
- /* End of Add-Ons                                    */
- /* ************************************************* */
-
-/* Linux 2.5.something and 2.6 pass direct pointers to arguments of
-   ioctl() calls. With 2.4, you have to do tedious copy_from_user()
-   and copy_to_user() calls. With these macros we circumvent this,
-   and let me maintain only one source file. The functionality is
-   exactly the same otherwise.
- */
-
-/* define local variable for arg */
-#define ARG_DEF(ARG_type, ARG_name)\
-       ARG_type *ARG_name = arg;
-/* copy arg to local variable */
-#define ARG_IN(ARG_name) /* nothing */
-/* argument itself (referenced) */
-#define ARGR(ARG_name) (*ARG_name)
-/* argument address */
-#define ARGA(ARG_name) ARG_name
-/* copy local variable to arg */
-#define ARG_OUT(ARG_name) /* nothing */
-
-/*
- * Our ctrls use native values, but the old custom pwc ioctl interface expects
- * values from 0 - 65535, define 2 helper functions to scale things. */
-static int pwc_ioctl_g_ctrl(struct v4l2_ctrl *ctrl)
-{
-       return v4l2_ctrl_g_ctrl(ctrl) * 65535 / ctrl->maximum;
-}
-
-static int pwc_ioctl_s_ctrl(struct v4l2_ctrl *ctrl, int val)
-{
-       return v4l2_ctrl_s_ctrl(ctrl, val * ctrl->maximum / 65535);
-}
-
-long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
-{
-       long ret = 0;
-
-       switch(cmd) {
-       case VIDIOCPWCRUSER:
-               ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER);
-               break;
-
-       case VIDIOCPWCSUSER:
-               ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER);
-               break;
-
-       case VIDIOCPWCFACTORY:
-               ret = pwc_button_ctrl(pdev, RESTORE_FACTORY_DEFAULTS_FORMATTER);
-               break;
-
-       case VIDIOCPWCSCQUAL:
-       {
-               ARG_DEF(int, qual)
-
-               if (vb2_is_streaming(&pdev->vb_queue)) {
-                       ret = -EBUSY;
-                       break;
-               }
-
-               ARG_IN(qual)
-               if (ARGR(qual) < 0 || ARGR(qual) > 3)
-                       ret = -EINVAL;
-               else
-                       ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
-               break;
-       }
-
-       case VIDIOCPWCGCQUAL:
-       {
-               ARG_DEF(int, qual)
-
-               ARGR(qual) = pdev->vcompression;
-               ARG_OUT(qual)
-               break;
-       }
-
-       case VIDIOCPWCPROBE:
-       {
-               ARG_DEF(struct pwc_probe, probe)
-
-               strcpy(ARGR(probe).name, pdev->vdev.name);
-               ARGR(probe).type = pdev->type;
-               ARG_OUT(probe)
-               break;
-       }
-
-       case VIDIOCPWCGSERIAL:
-       {
-               ARG_DEF(struct pwc_serial, serial)
-
-               strcpy(ARGR(serial).serial, pdev->serial);
-               ARG_OUT(serial)
-               break;
-       }
-
-       case VIDIOCPWCSAGC:
-       {
-               ARG_DEF(int, agc)
-               ARG_IN(agc)
-               ret = v4l2_ctrl_s_ctrl(pdev->autogain, ARGR(agc) < 0);
-               if (ret == 0 && ARGR(agc) >= 0)
-                       ret = pwc_ioctl_s_ctrl(pdev->gain, ARGR(agc));
-               break;
-       }
-
-       case VIDIOCPWCGAGC:
-       {
-               ARG_DEF(int, agc)
-               if (v4l2_ctrl_g_ctrl(pdev->autogain))
-                       ARGR(agc) = -1;
-               else
-                       ARGR(agc) = pwc_ioctl_g_ctrl(pdev->gain);
-               ARG_OUT(agc)
-               break;
-       }
-
-       case VIDIOCPWCSSHUTTER:
-       {
-               ARG_DEF(int, shutter)
-               ARG_IN(shutter)
-               ret = v4l2_ctrl_s_ctrl(pdev->exposure_auto,
-                                      /* Menu idx 0 = auto, idx 1 = manual */
-                                      ARGR(shutter) >= 0);
-               if (ret == 0 && ARGR(shutter) >= 0)
-                       ret = pwc_ioctl_s_ctrl(pdev->exposure, ARGR(shutter));
-               break;
-       }
-
-       case VIDIOCPWCSAWB:
-       {
-               ARG_DEF(struct pwc_whitebalance, wb)
-               ARG_IN(wb)
-               ret = v4l2_ctrl_s_ctrl(pdev->auto_white_balance,
-                                      ARGR(wb).mode);
-               if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL)
-                       ret = pwc_ioctl_s_ctrl(pdev->red_balance,
-                                              ARGR(wb).manual_red);
-               if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL)
-                       ret = pwc_ioctl_s_ctrl(pdev->blue_balance,
-                                              ARGR(wb).manual_blue);
-               break;
-       }
-
-       case VIDIOCPWCGAWB:
-       {
-               ARG_DEF(struct pwc_whitebalance, wb)
-               ARGR(wb).mode = v4l2_ctrl_g_ctrl(pdev->auto_white_balance);
-               ARGR(wb).manual_red = ARGR(wb).read_red =
-                       pwc_ioctl_g_ctrl(pdev->red_balance);
-               ARGR(wb).manual_blue = ARGR(wb).read_blue =
-                       pwc_ioctl_g_ctrl(pdev->blue_balance);
-               ARG_OUT(wb)
-               break;
-       }
-
-       case VIDIOCPWCSAWBSPEED:
-       {
-               ARG_DEF(struct pwc_wb_speed, wbs)
-
-               if (ARGR(wbs).control_speed > 0) {
-                       ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed);
-               }
-               if (ARGR(wbs).control_delay > 0) {
-                       ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay);
-               }
-               break;
-       }
-
-       case VIDIOCPWCGAWBSPEED:
-       {
-               ARG_DEF(struct pwc_wb_speed, wbs)
-
-               ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed);
-               if (ret < 0)
-                       break;
-               ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay);
-               if (ret < 0)
-                       break;
-               ARG_OUT(wbs)
-               break;
-       }
-
-       case VIDIOCPWCSLED:
-       {
-               ARG_DEF(struct pwc_leds, leds)
-
-               ARG_IN(leds)
-               ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off);
-               break;
-       }
-
-
-       case VIDIOCPWCGLED:
-       {
-               ARG_DEF(struct pwc_leds, leds)
-
-               ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off);
-               ARG_OUT(leds)
-               break;
-       }
-
-       case VIDIOCPWCSCONTOUR:
-       {
-               ARG_DEF(int, contour)
-               ARG_IN(contour)
-               ret = v4l2_ctrl_s_ctrl(pdev->autocontour, ARGR(contour) < 0);
-               if (ret == 0 && ARGR(contour) >= 0)
-                       ret = pwc_ioctl_s_ctrl(pdev->contour, ARGR(contour));
-               break;
-       }
-
-       case VIDIOCPWCGCONTOUR:
-       {
-               ARG_DEF(int, contour)
-               if (v4l2_ctrl_g_ctrl(pdev->autocontour))
-                       ARGR(contour) = -1;
-               else
-                       ARGR(contour) = pwc_ioctl_g_ctrl(pdev->contour);
-               ARG_OUT(contour)
-               break;
-       }
-
-       case VIDIOCPWCSBACKLIGHT:
-       {
-               ARG_DEF(int, backlight)
-               ARG_IN(backlight)
-               ret = v4l2_ctrl_s_ctrl(pdev->backlight, ARGR(backlight));
-               break;
-       }
-
-       case VIDIOCPWCGBACKLIGHT:
-       {
-               ARG_DEF(int, backlight)
-               ARGR(backlight) = v4l2_ctrl_g_ctrl(pdev->backlight);
-               ARG_OUT(backlight)
-               break;
-       }
-
-       case VIDIOCPWCSFLICKER:
-       {
-               ARG_DEF(int, flicker)
-               ARG_IN(flicker)
-               ret = v4l2_ctrl_s_ctrl(pdev->flicker, ARGR(flicker));
-               break;
-       }
-
-       case VIDIOCPWCGFLICKER:
-       {
-               ARG_DEF(int, flicker)
-               ARGR(flicker) = v4l2_ctrl_g_ctrl(pdev->flicker);
-               ARG_OUT(flicker)
-               break;
-       }
-
-       case VIDIOCPWCSDYNNOISE:
-       {
-               ARG_DEF(int, dynnoise)
-               ARG_IN(dynnoise)
-               ret = v4l2_ctrl_s_ctrl(pdev->noise_reduction, ARGR(dynnoise));
-               break;
-       }
-
-       case VIDIOCPWCGDYNNOISE:
-       {
-               ARG_DEF(int, dynnoise)
-               ARGR(dynnoise) = v4l2_ctrl_g_ctrl(pdev->noise_reduction);
-               ARG_OUT(dynnoise);
-               break;
-       }
-
-       case VIDIOCPWCGREALSIZE:
-       {
-               ARG_DEF(struct pwc_imagesize, size)
-
-               ARGR(size).width = pdev->image.x;
-               ARGR(size).height = pdev->image.y;
-               ARG_OUT(size)
-               break;
-       }
-
-       case VIDIOCPWCMPTRESET:
-       {
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       ARG_DEF(int, flags)
-
-                       ARG_IN(flags)
-                       ret = pwc_mpt_reset(pdev, ARGR(flags));
-               }
-               else
-               {
-                       ret = -ENXIO;
-               }
-               break;
-       }
-
-       case VIDIOCPWCMPTGRANGE:
-       {
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       ARG_DEF(struct pwc_mpt_range, range)
-
-                       ARGR(range) = pdev->angle_range;
-                       ARG_OUT(range)
-               }
-               else
-               {
-                       ret = -ENXIO;
-               }
-               break;
-       }
-
-       case VIDIOCPWCMPTSANGLE:
-       {
-               int new_pan, new_tilt;
-
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       ARG_DEF(struct pwc_mpt_angles, angles)
-
-                       ARG_IN(angles)
-                       /* The camera can only set relative angles, so
-                          do some calculations when getting an absolute angle .
-                        */
-                       if (ARGR(angles).absolute)
-                       {
-                               new_pan  = ARGR(angles).pan;
-                               new_tilt = ARGR(angles).tilt;
-                       }
-                       else
-                       {
-                               new_pan  = pdev->pan_angle  + ARGR(angles).pan;
-                               new_tilt = pdev->tilt_angle + ARGR(angles).tilt;
-                       }
-                       ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
-               }
-               else
-               {
-                       ret = -ENXIO;
-               }
-               break;
-       }
-
-       case VIDIOCPWCMPTGANGLE:
-       {
-
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       ARG_DEF(struct pwc_mpt_angles, angles)
-
-                       ARGR(angles).absolute = 1;
-                       ARGR(angles).pan  = pdev->pan_angle;
-                       ARGR(angles).tilt = pdev->tilt_angle;
-                       ARG_OUT(angles)
-               }
-               else
-               {
-                       ret = -ENXIO;
-               }
-               break;
-       }
-
-       case VIDIOCPWCMPTSTATUS:
-       {
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       ARG_DEF(struct pwc_mpt_status, status)
-
-                       ret = pwc_mpt_get_status(pdev, ARGA(status));
-                       ARG_OUT(status)
-               }
-               else
-               {
-                       ret = -ENXIO;
-               }
-               break;
-       }
-
-       case VIDIOCPWCGVIDCMD:
-       {
-               ARG_DEF(struct pwc_video_command, vcmd);
-
-               ARGR(vcmd).type = pdev->type;
-               ARGR(vcmd).release = pdev->release;
-               ARGR(vcmd).command_len = pdev->cmd_len;
-               memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
-               ARGR(vcmd).bandlength = pdev->vbandlength;
-               ARGR(vcmd).frame_size = pdev->frame_size;
-               ARG_OUT(vcmd)
-               break;
-       }
-       /*
-       case VIDIOCPWCGVIDTABLE:
-       {
-               ARG_DEF(struct pwc_table_init_buffer, table);
-               ARGR(table).len = pdev->cmd_len;
-               memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size);
-               ARG_OUT(table)
-               break;
-       }
-       */
-
-       default:
-               ret = -ENOIOCTLCMD;
-               break;
-       }
-
-       if (ret > 0)
-               return 0;
-       return ret;
-}
-
-
-/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
index be0e02cb487f1ff2cba5f32fbccd1826056eb93f..e899036aadf4a4734e0dd611386bf47909fe34bb 100644 (file)
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
-#include "pwc-dec1.h"
+#include "pwc.h"
 
-int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer)
+void pwc_dec1_init(struct pwc_device *pdev, const unsigned char *cmd)
 {
-       struct pwc_dec1_private *pdec;
+       struct pwc_dec1_private *pdec = &pdev->dec1;
 
-       if (pwc->decompress_data == NULL) {
-               pdec = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL);
-               if (pdec == NULL)
-                       return -ENOMEM;
-               pwc->decompress_data = pdec;
-       }
-       pdec = pwc->decompress_data;
-
-       return 0;
+       pdec->version = pdev->release;
 }
index a57d8601080babf0ca5ed403aef63220f900f2af..c565ef8f52fb3a83e29f5c428744aaf354b16db6 100644 (file)
 #ifndef PWC_DEC1_H
 #define PWC_DEC1_H
 
-#include "pwc.h"
+#include <linux/mutex.h>
+
+struct pwc_device;
 
 struct pwc_dec1_private
 {
        int version;
 };
 
-int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer);
+void pwc_dec1_init(struct pwc_device *pdev, const unsigned char *cmd);
 
 #endif
index 06a4e877ba40dea4d6b69e1050a7c3a364652376..3792fedff9515e85734200d8ffb22aa1ed15bb93 100644 (file)
@@ -27,7 +27,6 @@
 #include "pwc-timon.h"
 #include "pwc-kiara.h"
 #include "pwc-dec23.h"
-#include <media/pwc-ioctl.h>
 
 #include <linux/string.h>
 #include <linux/slab.h>
 # define USE_LOOKUP_TABLE_TO_CLAMP 1
 #endif
 
-/*
- * ENABLE_BAYER_DECODER
- *   0: bayer decoder is not build (save some space)
- *   1: bayer decoder is build and can be used
- */
-#define ENABLE_BAYER_DECODER 0
-
 static void build_subblock_pattern(struct pwc_dec23_private *pdec)
 {
        static const unsigned int initial_values[12] = {
@@ -302,20 +294,17 @@ static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE];
 
 
 /* If the type or the command change, we rebuild the lookup table */
-int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd)
+void pwc_dec23_init(struct pwc_device *pdev, const unsigned char *cmd)
 {
        int flags, version, shift, i;
-       struct pwc_dec23_private *pdec;
+       struct pwc_dec23_private *pdec = &pdev->dec23;
 
-       if (pwc->decompress_data == NULL) {
-               pdec = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
-               if (pdec == NULL)
-                       return -ENOMEM;
-               pwc->decompress_data = pdec;
-       }
-       pdec = pwc->decompress_data;
+       mutex_init(&pdec->lock);
 
-       if (DEVICE_USE_CODEC3(type)) {
+       if (pdec->last_cmd_valid && pdec->last_cmd == cmd[2])
+               return;
+
+       if (DEVICE_USE_CODEC3(pdev->type)) {
                flags = cmd[2] & 0x18;
                if (flags == 8)
                        pdec->nbits = 7;        /* More bits, mean more bits to encode the stream, but better quality */
@@ -362,7 +351,8 @@ int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd)
                pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255;
 #endif
 
-       return 0;
+       pdec->last_cmd = cmd[2];
+       pdec->last_cmd_valid = 1;
 }
 
 /*
@@ -467,123 +457,6 @@ static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned i
 #endif
 }
 
-#if ENABLE_BAYER_DECODER
-/*
- * Format: 8x2 pixels
- *   . G . G . G . G . G . G . G
- *   . . . . . . . . . . . . . .
- *   . G . G . G . G . G . G . G
- *   . . . . . . . . . . . . . .
- *   or
- *   . . . . . . . . . . . . . .
- *   G . G . G . G . G . G . G .
- *   . . . . . . . . . . . . . .
- *   G . G . G . G . G . G . G .
-*/
-static void copy_image_block_Green(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
-{
-#if UNROLL_LOOP_FOR_COPY
-       /* Unroll all loops */
-       const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
-       unsigned char *d = dst;
-       const int *c = src;
-
-       d[0] = cm[c[0] >> scalebits];
-       d[2] = cm[c[1] >> scalebits];
-       d[4] = cm[c[2] >> scalebits];
-       d[6] = cm[c[3] >> scalebits];
-       d[8] = cm[c[4] >> scalebits];
-       d[10] = cm[c[5] >> scalebits];
-       d[12] = cm[c[6] >> scalebits];
-       d[14] = cm[c[7] >> scalebits];
-
-       d = dst + bytes_per_line;
-       d[0] = cm[c[8] >> scalebits];
-       d[2] = cm[c[9] >> scalebits];
-       d[4] = cm[c[10] >> scalebits];
-       d[6] = cm[c[11] >> scalebits];
-       d[8] = cm[c[12] >> scalebits];
-       d[10] = cm[c[13] >> scalebits];
-       d[12] = cm[c[14] >> scalebits];
-       d[14] = cm[c[15] >> scalebits];
-#else
-       int i;
-       unsigned char *d;
-       const int *c = src;
-
-       d = dst;
-       for (i = 0; i < 8; i++, c++)
-               d[i*2] = CLAMP((*c) >> scalebits);
-
-       d = dst + bytes_per_line;
-       for (i = 0; i < 8; i++, c++)
-               d[i*2] = CLAMP((*c) >> scalebits);
-#endif
-}
-#endif
-
-#if ENABLE_BAYER_DECODER
-/*
- * Format: 4x4 pixels
- *   R . R . R . R
- *   . B . B . B .
- *   R . R . R . R
- *   . B . B . B .
- */
-static void copy_image_block_RedBlue(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
-{
-#if UNROLL_LOOP_FOR_COPY
-       /* Unroll all loops */
-       const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
-       unsigned char *d = dst;
-       const int *c = src;
-
-       d[0] = cm[c[0] >> scalebits];
-       d[2] = cm[c[1] >> scalebits];
-       d[4] = cm[c[2] >> scalebits];
-       d[6] = cm[c[3] >> scalebits];
-
-       d = dst + bytes_per_line;
-       d[1] = cm[c[4] >> scalebits];
-       d[3] = cm[c[5] >> scalebits];
-       d[5] = cm[c[6] >> scalebits];
-       d[7] = cm[c[7] >> scalebits];
-
-       d = dst + bytes_per_line*2;
-       d[0] = cm[c[8] >> scalebits];
-       d[2] = cm[c[9] >> scalebits];
-       d[4] = cm[c[10] >> scalebits];
-       d[6] = cm[c[11] >> scalebits];
-
-       d = dst + bytes_per_line*3;
-       d[1] = cm[c[12] >> scalebits];
-       d[3] = cm[c[13] >> scalebits];
-       d[5] = cm[c[14] >> scalebits];
-       d[7] = cm[c[15] >> scalebits];
-#else
-       int i;
-       unsigned char *d;
-       const int *c = src;
-
-       d = dst;
-       for (i = 0; i < 4; i++, c++)
-               d[i*2] = CLAMP((*c) >> scalebits);
-
-       d = dst + bytes_per_line;
-       for (i = 0; i < 4; i++, c++)
-               d[i*2+1] = CLAMP((*c) >> scalebits);
-
-       d = dst + bytes_per_line*2;
-       for (i = 0; i < 4; i++, c++)
-               d[i*2] = CLAMP((*c) >> scalebits);
-
-       d = dst + bytes_per_line*3;
-       for (i = 0; i < 4; i++, c++)
-               d[i*2+1] = CLAMP((*c) >> scalebits);
-#endif
-}
-#endif
-
 /*
  * To manage the stream, we keep bits in a 32 bits register.
  * fill_nbits(n): fill the reservoir with at least n bits
@@ -775,146 +648,44 @@ static void DecompressBand23(struct pwc_dec23_private *pdec,
 
 }
 
-#if ENABLE_BAYER_DECODER
-/*
- * Size need to be a multiple of 8 in width
- *
- * Return a block of four line encoded like this:
- *
- *   G R G R G R G R G R G R G R G R
- *   B G B G B G B G B G B G B G B G
- *   G R G R G R G R G R G R G R G R
- *   B G B G B G B G B G B G B G B G
- *
- */
-static void DecompressBandBayer(struct pwc_dec23_private *pdec,
-                               const unsigned char *rawyuv,
-                               unsigned char *rgbbayer,
-                               unsigned int   compressed_image_width,
-                               unsigned int   real_image_width)
-{
-       int compression_index, nblocks;
-       const unsigned char *ptable0004;
-       const unsigned char *ptable8004;
-       unsigned char *dest;
-
-       pdec->reservoir = 0;
-       pdec->nbits_in_reservoir = 0;
-       pdec->stream = rawyuv + 1;      /* The first byte of the stream is skipped */
-
-       get_nbits(pdec, 4, compression_index);
-
-       /* pass 1: uncompress RB component */
-       nblocks = compressed_image_width / 4;
-
-       ptable0004 = pdec->table_0004_pass1[compression_index];
-       ptable8004 = pdec->table_8004_pass1[compression_index];
-       dest = rgbbayer;
-
-       /* Each block decode a square of 4x4 */
-       while (nblocks) {
-               decode_block(pdec, ptable0004, ptable8004);
-               copy_image_block_RedBlue(pdec->temp_colors, rgbbayer, real_image_width, pdec->scalebits);
-               dest += 8;
-               nblocks--;
-       }
-
-       /* pass 2: uncompress G component */
-       nblocks = compressed_image_width / 8;
-
-       ptable0004 = pdec->table_0004_pass2[compression_index];
-       ptable8004 = pdec->table_8004_pass2[compression_index];
-
-       /* Each block decode a square of 4x4 */
-       while (nblocks) {
-               decode_block(pdec, ptable0004, ptable8004);
-               copy_image_block_Green(pdec->temp_colors, rgbbayer+1, real_image_width, pdec->scalebits);
-
-               decode_block(pdec, ptable0004, ptable8004);
-               copy_image_block_Green(pdec->temp_colors, rgbbayer+real_image_width, real_image_width, pdec->scalebits);
-
-               rgbbayer += 16;
-               nblocks -= 2;
-       }
-}
-#endif
-
-
 /**
  *
  * Uncompress a pwc23 buffer.
  *
- * pwc.view: size of the image wanted
- * pwc.image: size of the image returned by the camera
- * pwc.offset: (x,y) to displayer image in the view
- *
  * src: raw data
  * dst: image output
- * flags: PWCX_FLAG_PLANAR or PWCX_FLAG_BAYER
  */
-void pwc_dec23_decompress(const struct pwc_device *pwc,
+void pwc_dec23_decompress(struct pwc_device *pdev,
                          const void *src,
-                         void *dst,
-                         int flags)
+                         void *dst)
 {
-       int bandlines_left, stride, bytes_per_block;
-
-       bandlines_left = pwc->image.y / 4;
-       bytes_per_block = pwc->view.x * 4;
-
-       if (flags & PWCX_FLAG_BAYER) {
-#if ENABLE_BAYER_DECODER
-               /* RGB Bayer format */
-               unsigned char *rgbout;
-
-               stride = pwc->view.x * pwc->offset.y;
-               rgbout = dst + stride + pwc->offset.x;
-
-
-               while (bandlines_left--) {
-
-                       DecompressBandBayer(pwc->decompress_data,
-                                           src,
-                                           rgbout,
-                                           pwc->image.x, pwc->view.x);
-
-                       src += pwc->vbandlength;
-                       rgbout += bytes_per_block;
-
-               }
-#else
-               memset(dst, 0, pwc->view.x * pwc->view.y);
-#endif
-
-       } else {
-               /* YUV420P image format */
-               unsigned char *pout_planar_y;
-               unsigned char *pout_planar_u;
-               unsigned char *pout_planar_v;
-               unsigned int   plane_size;
-
-               plane_size = pwc->view.x * pwc->view.y;
-
-               /* offset in Y plane */
-               stride = pwc->view.x * pwc->offset.y;
-               pout_planar_y = dst + stride + pwc->offset.x;
-
-               /* offsets in U/V planes */
-               stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2;
-               pout_planar_u = dst + plane_size + stride;
-               pout_planar_v = dst + plane_size + plane_size / 4 + stride;
-
-               while (bandlines_left--) {
-
-                       DecompressBand23(pwc->decompress_data,
-                                        src,
-                                        pout_planar_y, pout_planar_u, pout_planar_v,
-                                        pwc->image.x, pwc->view.x);
-                       src += pwc->vbandlength;
-                       pout_planar_y += bytes_per_block;
-                       pout_planar_u += pwc->view.x;
-                       pout_planar_v += pwc->view.x;
-
-               }
+       int bandlines_left, bytes_per_block;
+       struct pwc_dec23_private *pdec = &pdev->dec23;
+
+       /* YUV420P image format */
+       unsigned char *pout_planar_y;
+       unsigned char *pout_planar_u;
+       unsigned char *pout_planar_v;
+       unsigned int   plane_size;
+
+       mutex_lock(&pdec->lock);
+
+       bandlines_left = pdev->height / 4;
+       bytes_per_block = pdev->width * 4;
+       plane_size = pdev->height * pdev->width;
+
+       pout_planar_y = dst;
+       pout_planar_u = dst + plane_size;
+       pout_planar_v = dst + plane_size + plane_size / 4;
+
+       while (bandlines_left--) {
+               DecompressBand23(pdec, src,
+                                pout_planar_y, pout_planar_u, pout_planar_v,
+                                pdev->width, pdev->width);
+               src += pdev->vbandlength;
+               pout_planar_y += bytes_per_block;
+               pout_planar_u += pdev->width;
+               pout_planar_v += pdev->width;
        }
+       mutex_unlock(&pdec->lock);
 }
index a0ac4f3dff81b6960a64c2158244f08d220eb1f8..c655b1c1e6a9f7d7c7e8ff725672190bb2829e0c 100644 (file)
 #ifndef PWC_DEC23_H
 #define PWC_DEC23_H
 
-#include "pwc.h"
+struct pwc_device;
 
 struct pwc_dec23_private
 {
+       struct mutex lock;
+
+       unsigned char last_cmd, last_cmd_valid;
+
   unsigned int scalebits;
   unsigned int nbitsmask, nbits; /* Number of bits of a color in the compressed stream */
 
   unsigned int reservoir;
   unsigned int nbits_in_reservoir;
+
   const unsigned char *stream;
   int temp_colors[16];
 
@@ -49,9 +54,8 @@ struct pwc_dec23_private
 
 };
 
-int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd);
-void pwc_dec23_decompress(const struct pwc_device *pwc,
+void pwc_dec23_init(struct pwc_device *pdev, const unsigned char *cmd);
+void pwc_dec23_decompress(struct pwc_device *pdev,
                          const void *src,
-                         void *dst,
-                         int flags);
+                         void *dst);
 #endif
index 01ff643e682dd8a7c9c20a79c980d8509b4b90a1..122fbd0081eb548a3416f2848661cc144066a78b 100644 (file)
@@ -128,33 +128,23 @@ static struct usb_driver pwc_driver = {
 #define MAX_DEV_HINTS  20
 #define MAX_ISOC_ERRORS        20
 
-static int default_fps = 10;
 #ifdef CONFIG_USB_PWC_DEBUG
        int pwc_trace = PWC_DEBUG_LEVEL;
 #endif
 static int power_save = -1;
-static int led_on = 100, led_off; /* defaults to LED that is on while in use */
-static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
-static struct {
-       int type;
-       char serial_number[30];
-       int device_node;
-       struct pwc_device *pdev;
-} device_hint[MAX_DEV_HINTS];
+static int leds[2] = { 100, 0 };
 
 /***/
 
-static int pwc_video_open(struct file *file);
 static int pwc_video_close(struct file *file);
 static ssize_t pwc_video_read(struct file *file, char __user *buf,
                          size_t count, loff_t *ppos);
 static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
 static int  pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
-static void pwc_video_release(struct video_device *vfd);
 
 static const struct v4l2_file_operations pwc_fops = {
        .owner =        THIS_MODULE,
-       .open =         pwc_video_open,
+       .open =         v4l2_fh_open,
        .release =      pwc_video_close,
        .read =         pwc_video_read,
        .poll =         pwc_video_poll,
@@ -163,7 +153,7 @@ static const struct v4l2_file_operations pwc_fops = {
 };
 static struct video_device pwc_template = {
        .name =         "Philips Webcam",       /* Filled in later */
-       .release =      pwc_video_release,
+       .release =      video_device_release_empty,
        .fops =         &pwc_fops,
        .ioctl_ops =    &pwc_ioctl_ops,
 };
@@ -191,7 +181,6 @@ static void pwc_snapshot_button(struct pwc_device *pdev, int down)
 {
        if (down) {
                PWC_TRACE("Snapshot button pressed.\n");
-               pdev->snapshot_button_status = 1;
        } else {
                PWC_TRACE("Snapshot button released.\n");
        }
@@ -375,6 +364,7 @@ static int pwc_isoc_init(struct pwc_device *pdev)
        int i, j, ret;
        struct usb_interface *intf;
        struct usb_host_interface *idesc = NULL;
+       int compression = 0; /* 0..3 = uncompressed..high */
 
        if (pdev->iso_init)
                return 0;
@@ -386,6 +376,12 @@ static int pwc_isoc_init(struct pwc_device *pdev)
        pdev->visoc_errors = 0;
        udev = pdev->udev;
 
+retry:
+       /* We first try with low compression and then retry with a higher
+          compression setting if there is not enough bandwidth. */
+       ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt,
+                                pdev->vframes, &compression, 1);
+
        /* Get the current alternate interface, adjust packet size */
        intf = usb_ifnum_to_if(udev, 0);
        if (intf)
@@ -408,9 +404,12 @@ static int pwc_isoc_init(struct pwc_device *pdev)
        }
 
        /* Set alternate interface */
-       ret = 0;
        PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
        ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
+       if (ret == -ENOSPC && compression < 3) {
+               compression++;
+               goto retry;
+       }
        if (ret < 0)
                return ret;
 
@@ -454,6 +453,12 @@ static int pwc_isoc_init(struct pwc_device *pdev)
        /* link */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL);
+               if (ret == -ENOSPC && compression < 3) {
+                       compression++;
+                       pdev->iso_init = 1;
+                       pwc_isoc_cleanup(pdev);
+                       goto retry;
+               }
                if (ret) {
                        PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
                        pdev->iso_init = 1;
@@ -517,12 +522,11 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
        PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
 }
 
-/*
- * Release all queued buffers, no need to take queued_bufs_lock, since all
- * iso urbs have been killed when we're called so pwc_isoc_handler won't run.
- */
 static void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
 {
+       unsigned long flags = 0;
+
+       spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
        while (!list_empty(&pdev->queued_bufs)) {
                struct pwc_frame_buf *buf;
 
@@ -531,84 +535,7 @@ static void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
                list_del(&buf->list);
                vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
        }
-}
-
-/*********
- * sysfs
- *********/
-static struct pwc_device *cd_to_pwc(struct device *cd)
-{
-       struct video_device *vdev = to_video_device(cd);
-       return video_get_drvdata(vdev);
-}
-
-static ssize_t show_pan_tilt(struct device *class_dev,
-                            struct device_attribute *attr, char *buf)
-{
-       struct pwc_device *pdev = cd_to_pwc(class_dev);
-       return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
-}
-
-static ssize_t store_pan_tilt(struct device *class_dev,
-                             struct device_attribute *attr,
-                             const char *buf, size_t count)
-{
-       struct pwc_device *pdev = cd_to_pwc(class_dev);
-       int pan, tilt;
-       int ret = -EINVAL;
-
-       if (strncmp(buf, "reset", 5) == 0)
-               ret = pwc_mpt_reset(pdev, 0x3);
-
-       else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
-               ret = pwc_mpt_set_angle(pdev, pan, tilt);
-
-       if (ret < 0)
-               return ret;
-       return strlen(buf);
-}
-static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
-                  store_pan_tilt);
-
-static ssize_t show_snapshot_button_status(struct device *class_dev,
-                                          struct device_attribute *attr, char *buf)
-{
-       struct pwc_device *pdev = cd_to_pwc(class_dev);
-       int status = pdev->snapshot_button_status;
-       pdev->snapshot_button_status = 0;
-       return sprintf(buf, "%d\n", status);
-}
-
-static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
-                  NULL);
-
-static int pwc_create_sysfs_files(struct pwc_device *pdev)
-{
-       int rc;
-
-       rc = device_create_file(&pdev->vdev.dev, &dev_attr_button);
-       if (rc)
-               goto err;
-       if (pdev->features & FEATURE_MOTOR_PANTILT) {
-               rc = device_create_file(&pdev->vdev.dev, &dev_attr_pan_tilt);
-               if (rc)
-                       goto err_button;
-       }
-
-       return 0;
-
-err_button:
-       device_remove_file(&pdev->vdev.dev, &dev_attr_button);
-err:
-       PWC_ERROR("Could not create sysfs files.\n");
-       return rc;
-}
-
-static void pwc_remove_sysfs_files(struct pwc_device *pdev)
-{
-       if (pdev->features & FEATURE_MOTOR_PANTILT)
-               device_remove_file(&pdev->vdev.dev, &dev_attr_pan_tilt);
-       device_remove_file(&pdev->vdev.dev, &dev_attr_button);
+       spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
 }
 
 #ifdef CONFIG_USB_PWC_DEBUG
@@ -644,85 +571,60 @@ static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
 /***************************************************************************/
 /* Video4Linux functions */
 
-static int pwc_video_open(struct file *file)
+int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file)
 {
-       struct video_device *vdev = video_devdata(file);
-       struct pwc_device *pdev;
-
-       PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
-
-       pdev = video_get_drvdata(vdev);
-       if (!pdev->udev)
-               return -ENODEV;
+       int r = 0;
 
-       file->private_data = vdev;
-       PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
-       return 0;
+       mutex_lock(&pdev->capt_file_lock);
+       if (pdev->capt_file != NULL &&
+           pdev->capt_file != file) {
+               r = -EBUSY;
+               goto leave;
+       }
+       pdev->capt_file = file;
+leave:
+       mutex_unlock(&pdev->capt_file_lock);
+       return r;
 }
 
-static void pwc_video_release(struct video_device *vfd)
+static void pwc_video_release(struct v4l2_device *v)
 {
-       struct pwc_device *pdev = container_of(vfd, struct pwc_device, vdev);
-       int hint;
-
-       /* search device_hint[] table if we occupy a slot, by any chance */
-       for (hint = 0; hint < MAX_DEV_HINTS; hint++)
-               if (device_hint[hint].pdev == pdev)
-                       device_hint[hint].pdev = NULL;
-
-       /* Free intermediate decompression buffer & tables */
-       if (pdev->decompress_data != NULL) {
-               PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n",
-                                pdev->decompress_data);
-               kfree(pdev->decompress_data);
-               pdev->decompress_data = NULL;
-       }
+       struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
 
        v4l2_ctrl_handler_free(&pdev->ctrl_handler);
-
+       kfree(pdev->ctrl_buf);
        kfree(pdev);
 }
 
 static int pwc_video_close(struct file *file)
 {
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-
-       PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
+       struct pwc_device *pdev = video_drvdata(file);
 
-       pdev = video_get_drvdata(vdev);
        if (pdev->capt_file == file) {
                vb2_queue_release(&pdev->vb_queue);
                pdev->capt_file = NULL;
        }
-
-       PWC_DEBUG_OPEN("<< video_close()\n");
-       return 0;
+       return v4l2_fh_release(file);
 }
 
 static ssize_t pwc_video_read(struct file *file, char __user *buf,
                              size_t count, loff_t *ppos)
 {
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev = video_get_drvdata(vdev);
+       struct pwc_device *pdev = video_drvdata(file);
 
        if (!pdev->udev)
                return -ENODEV;
 
-       if (pdev->capt_file != NULL &&
-           pdev->capt_file != file)
+       if (pwc_test_n_set_capt_file(pdev, file))
                return -EBUSY;
 
-       pdev->capt_file = file;
-
        return vb2_read(&pdev->vb_queue, buf, count, ppos,
                        file->f_flags & O_NONBLOCK);
 }
 
 static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
 {
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev = video_get_drvdata(vdev);
+       struct pwc_device *pdev = video_drvdata(file);
 
        if (!pdev->udev)
                return POLL_ERR;
@@ -732,8 +634,7 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
 
 static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev = video_get_drvdata(vdev);
+       struct pwc_device *pdev = video_drvdata(file);
 
        if (pdev->capt_file != file)
                return -EBUSY;
@@ -749,6 +650,7 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
                                unsigned int sizes[], void *alloc_ctxs[])
 {
        struct pwc_device *pdev = vb2_get_drv_priv(vq);
+       int size;
 
        if (*nbuffers < MIN_FRAMES)
                *nbuffers = MIN_FRAMES;
@@ -757,7 +659,9 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
 
        *nplanes = 1;
 
-       sizes[0] = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
+       size = pwc_get_size(pdev, MAX_WIDTH, MAX_HEIGHT);
+       sizes[0] = PAGE_ALIGN(pwc_image_sizes[size][0] *
+                             pwc_image_sizes[size][1] * 3 / 2);
 
        return 0;
 }
@@ -812,56 +716,59 @@ static void buffer_queue(struct vb2_buffer *vb)
        unsigned long flags = 0;
 
        spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
-       list_add_tail(&buf->list, &pdev->queued_bufs);
+       /* Check the device has not disconnected between prep and queuing */
+       if (pdev->udev)
+               list_add_tail(&buf->list, &pdev->queued_bufs);
+       else
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
        spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
 }
 
 static int start_streaming(struct vb2_queue *vq, unsigned int count)
 {
        struct pwc_device *pdev = vb2_get_drv_priv(vq);
+       int r;
 
-       if (!pdev->udev)
-               return -ENODEV;
+       mutex_lock(&pdev->udevlock);
+       if (!pdev->udev) {
+               r = -ENODEV;
+               goto leave;
+       }
 
        /* Turn on camera and set LEDS on */
        pwc_camera_power(pdev, 1);
-       if (pdev->power_save) {
-               /* Restore video mode */
-               pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y,
-                                  pdev->vframes, pdev->vcompression,
-                                  pdev->vsnapshot);
-       }
-       pwc_set_leds(pdev, led_on, led_off);
+       pwc_set_leds(pdev, leds[0], leds[1]);
 
-       return pwc_isoc_init(pdev);
+       r = pwc_isoc_init(pdev);
+       if (r) {
+               /* If we failed turn camera and LEDS back off */
+               pwc_set_leds(pdev, 0, 0);
+               pwc_camera_power(pdev, 0);
+               /* And cleanup any queued bufs!! */
+               pwc_cleanup_queued_bufs(pdev);
+       }
+leave:
+       mutex_unlock(&pdev->udevlock);
+       return r;
 }
 
 static int stop_streaming(struct vb2_queue *vq)
 {
        struct pwc_device *pdev = vb2_get_drv_priv(vq);
 
+       mutex_lock(&pdev->udevlock);
        if (pdev->udev) {
                pwc_set_leds(pdev, 0, 0);
                pwc_camera_power(pdev, 0);
                pwc_isoc_cleanup(pdev);
        }
+       mutex_unlock(&pdev->udevlock);
+
        pwc_cleanup_queued_bufs(pdev);
 
        return 0;
 }
 
-static void pwc_lock(struct vb2_queue *vq)
-{
-       struct pwc_device *pdev = vb2_get_drv_priv(vq);
-       mutex_lock(&pdev->modlock);
-}
-
-static void pwc_unlock(struct vb2_queue *vq)
-{
-       struct pwc_device *pdev = vb2_get_drv_priv(vq);
-       mutex_unlock(&pdev->modlock);
-}
-
 static struct vb2_ops pwc_vb_queue_ops = {
        .queue_setup            = queue_setup,
        .buf_init               = buffer_init,
@@ -871,8 +778,6 @@ static struct vb2_ops pwc_vb_queue_ops = {
        .buf_queue              = buffer_queue,
        .start_streaming        = start_streaming,
        .stop_streaming         = stop_streaming,
-       .wait_prepare           = pwc_unlock,
-       .wait_finish            = pwc_lock,
 };
 
 /***************************************************************************/
@@ -887,9 +792,9 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        struct usb_device *udev = interface_to_usbdev(intf);
        struct pwc_device *pdev = NULL;
        int vendor_id, product_id, type_id;
-       int hint, rc;
+       int rc;
        int features = 0;
-       int video_nr = -1; /* default: use next available device */
+       int compression = 0;
        int my_power_save = power_save;
        char serial_number[30], *name;
 
@@ -1149,28 +1054,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                return -ENOMEM;
        }
        pdev->type = type_id;
-       pdev->vframes = default_fps;
-       strcpy(pdev->serial, serial_number);
        pdev->features = features;
-       if (vendor_id == 0x046D && product_id == 0x08B5) {
-               /* Logitech QuickCam Orbit
-                  The ranges have been determined experimentally; they may differ from cam to cam.
-                  Also, the exact ranges left-right and up-down are different for my cam
-                 */
-               pdev->angle_range.pan_min  = -7000;
-               pdev->angle_range.pan_max  =  7000;
-               pdev->angle_range.tilt_min = -3000;
-               pdev->angle_range.tilt_max =  2500;
-       }
        pwc_construct(pdev); /* set min/max sizes correct */
 
-       mutex_init(&pdev->modlock);
+       mutex_init(&pdev->capt_file_lock);
        mutex_init(&pdev->udevlock);
        spin_lock_init(&pdev->queued_bufs_lock);
        INIT_LIST_HEAD(&pdev->queued_bufs);
 
        pdev->udev = udev;
-       pdev->vcompression = pwc_preferred_compression;
        pdev->power_save = my_power_save;
 
        /* Init videobuf2 queue structure */
@@ -1185,35 +1077,21 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
 
        /* Init video_device structure */
        memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template));
-       pdev->vdev.parent = &intf->dev;
-       pdev->vdev.lock = &pdev->modlock;
        strcpy(pdev->vdev.name, name);
+       set_bit(V4L2_FL_USE_FH_PRIO, &pdev->vdev.flags);
        video_set_drvdata(&pdev->vdev, pdev);
 
        pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
        PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
 
-       /* Now search device_hint[] table for a match, so we can hint a node number. */
-       for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
-               if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
-                    (device_hint[hint].pdev == NULL)) {
-                       /* so far, so good... try serial number */
-                       if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
-                               /* match! */
-                               video_nr = device_hint[hint].device_node;
-                               PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
-                               break;
-                       }
-               }
+       /* Allocate USB command buffers */
+       pdev->ctrl_buf = kmalloc(sizeof(pdev->cmd_buf), GFP_KERNEL);
+       if (!pdev->ctrl_buf) {
+               PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
+               rc = -ENOMEM;
+               goto err_free_mem;
        }
 
-       /* occupy slot */
-       if (hint < MAX_DEV_HINTS)
-               device_hint[hint].pdev = pdev;
-
-       PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
-       usb_set_intfdata(intf, pdev);
-
 #ifdef CONFIG_USB_PWC_DEBUG
        /* Query sensor type */
        if (pwc_get_cmos_sensor(pdev, &rc) >= 0) {
@@ -1227,8 +1105,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        pwc_set_leds(pdev, 0, 0);
 
        /* Setup intial videomode */
-       rc = pwc_set_video_mode(pdev, pdev->view_max.x, pdev->view_max.y,
-                               pdev->vframes, pdev->vcompression, 0);
+       rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT,
+                               V4L2_PIX_FMT_YUV420, 30, &compression, 1);
        if (rc)
                goto err_free_mem;
 
@@ -1239,20 +1117,25 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                goto err_free_mem;
        }
 
-       pdev->vdev.ctrl_handler = &pdev->ctrl_handler;
-
        /* And powerdown the camera until streaming starts */
        pwc_camera_power(pdev, 0);
 
-       rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr);
-       if (rc < 0) {
-               PWC_ERROR("Failed to register as video device (%d).\n", rc);
+       /* Register the v4l2_device structure */
+       pdev->v4l2_dev.release = pwc_video_release;
+       rc = v4l2_device_register(&intf->dev, &pdev->v4l2_dev);
+       if (rc) {
+               PWC_ERROR("Failed to register v4l2-device (%d).\n", rc);
                goto err_free_controls;
        }
-       rc = pwc_create_sysfs_files(pdev);
-       if (rc)
-               goto err_video_unreg;
 
+       pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler;
+       pdev->vdev.v4l2_dev = &pdev->v4l2_dev;
+
+       rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1);
+       if (rc < 0) {
+               PWC_ERROR("Failed to register as video device (%d).\n", rc);
+               goto err_unregister_v4l2_dev;
+       }
        PWC_INFO("Registered as %s.\n", video_device_node_name(&pdev->vdev));
 
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
@@ -1261,7 +1144,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        if (!pdev->button_dev) {
                PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
                rc = -ENOMEM;
-               pwc_remove_sysfs_files(pdev);
                goto err_video_unreg;
        }
 
@@ -1279,7 +1161,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        if (rc) {
                input_free_device(pdev->button_dev);
                pdev->button_dev = NULL;
-               pwc_remove_sysfs_files(pdev);
                goto err_video_unreg;
        }
 #endif
@@ -1287,13 +1168,13 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        return 0;
 
 err_video_unreg:
-       if (hint < MAX_DEV_HINTS)
-               device_hint[hint].pdev = NULL;
        video_unregister_device(&pdev->vdev);
+err_unregister_v4l2_dev:
+       v4l2_device_unregister(&pdev->v4l2_dev);
 err_free_controls:
        v4l2_ctrl_handler_free(&pdev->ctrl_handler);
 err_free_mem:
-       usb_set_intfdata(intf, NULL);
+       kfree(pdev->ctrl_buf);
        kfree(pdev);
        return rc;
 }
@@ -1301,27 +1182,26 @@ err_free_mem:
 /* The user yanked out the cable... */
 static void usb_pwc_disconnect(struct usb_interface *intf)
 {
-       struct pwc_device *pdev  = usb_get_intfdata(intf);
+       struct v4l2_device *v = usb_get_intfdata(intf);
+       struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
 
        mutex_lock(&pdev->udevlock);
-       mutex_lock(&pdev->modlock);
-
-       usb_set_intfdata(intf, NULL);
        /* No need to keep the urbs around after disconnection */
        pwc_isoc_cleanup(pdev);
-       pwc_cleanup_queued_bufs(pdev);
        pdev->udev = NULL;
-
-       mutex_unlock(&pdev->modlock);
        mutex_unlock(&pdev->udevlock);
 
-       pwc_remove_sysfs_files(pdev);
+       pwc_cleanup_queued_bufs(pdev);
+
        video_unregister_device(&pdev->vdev);
+       v4l2_device_unregister(&pdev->v4l2_dev);
 
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
        if (pdev->button_dev)
                input_unregister_device(pdev->button_dev);
 #endif
+
+       v4l2_device_put(&pdev->v4l2_dev);
 }
 
 
@@ -1329,30 +1209,19 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
  * Initialization code & module stuff
  */
 
-static int fps;
-static int compression = -1;
-static int leds[2] = { -1, -1 };
 static unsigned int leds_nargs;
-static char *dev_hint[MAX_DEV_HINTS];
-static unsigned int dev_hint_nargs;
 
-module_param(fps, int, 0444);
 #ifdef CONFIG_USB_PWC_DEBUG
 module_param_named(trace, pwc_trace, int, 0644);
 #endif
 module_param(power_save, int, 0644);
-module_param(compression, int, 0444);
 module_param_array(leds, int, &leds_nargs, 0444);
-module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
 
-MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
 #ifdef CONFIG_USB_PWC_DEBUG
 MODULE_PARM_DESC(trace, "For debugging purposes");
 #endif
 MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off");
-MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
 MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
-MODULE_PARM_DESC(dev_hint, "Device node hints");
 
 MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
 MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
@@ -1362,122 +1231,13 @@ MODULE_VERSION( PWC_VERSION );
 
 static int __init usb_pwc_init(void)
 {
-       int i;
-
-#ifdef CONFIG_USB_PWC_DEBUG
-       PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
-       PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
-       PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
-       PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
-
-       if (pwc_trace >= 0) {
-               PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
-       }
-#endif
-
-       if (fps) {
-               if (fps < 4 || fps > 30) {
-                       PWC_ERROR("Framerate out of bounds (4-30).\n");
-                       return -EINVAL;
-               }
-               default_fps = fps;
-               PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
-       }
-
-       if (compression >= 0) {
-               if (compression > 3) {
-                       PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
-                       return -EINVAL;
-               }
-               pwc_preferred_compression = compression;
-               PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
-       }
-       if (leds[0] >= 0)
-               led_on = leds[0];
-       if (leds[1] >= 0)
-               led_off = leds[1];
-
-       /* Big device node whoopla. Basically, it allows you to assign a
-          device node (/dev/videoX) to a camera, based on its type
-          & serial number. The format is [type[.serialnumber]:]node.
-
-          Any camera that isn't matched by these rules gets the next
-          available free device node.
-        */
-       for (i = 0; i < MAX_DEV_HINTS; i++) {
-               char *s, *colon, *dot;
-
-               /* This loop also initializes the array */
-               device_hint[i].pdev = NULL;
-               s = dev_hint[i];
-               if (s != NULL && *s != '\0') {
-                       device_hint[i].type = -1; /* wildcard */
-                       strcpy(device_hint[i].serial_number, "*");
-
-                       /* parse string: chop at ':' & '/' */
-                       colon = dot = s;
-                       while (*colon != '\0' && *colon != ':')
-                               colon++;
-                       while (*dot != '\0' && *dot != '.')
-                               dot++;
-                       /* Few sanity checks */
-                       if (*dot != '\0' && dot > colon) {
-                               PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
-                               return -EINVAL;
-                       }
-
-                       if (*colon == '\0') {
-                               /* No colon */
-                               if (*dot != '\0') {
-                                       PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
-                                       return -EINVAL;
-                               }
-                               else {
-                                       /* No type or serial number specified, just a number. */
-                                       device_hint[i].device_node =
-                                               simple_strtol(s, NULL, 10);
-                               }
-                       }
-                       else {
-                               /* There's a colon, so we have at least a type and a device node */
-                               device_hint[i].type =
-                                       simple_strtol(s, NULL, 10);
-                               device_hint[i].device_node =
-                                       simple_strtol(colon + 1, NULL, 10);
-                               if (*dot != '\0') {
-                                       /* There's a serial number as well */
-                                       int k;
-
-                                       dot++;
-                                       k = 0;
-                                       while (*dot != ':' && k < 29) {
-                                               device_hint[i].serial_number[k++] = *dot;
-                                               dot++;
-                                       }
-                                       device_hint[i].serial_number[k] = '\0';
-                               }
-                       }
-                       PWC_TRACE("device_hint[%d]:\n", i);
-                       PWC_TRACE("  type    : %d\n", device_hint[i].type);
-                       PWC_TRACE("  serial# : %s\n", device_hint[i].serial_number);
-                       PWC_TRACE("  node    : %d\n", device_hint[i].device_node);
-               }
-               else
-                       device_hint[i].type = 0; /* not filled */
-       } /* ..for MAX_DEV_HINTS */
-
-       PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
        return usb_register(&pwc_driver);
 }
 
 static void __exit usb_pwc_exit(void)
 {
-       PWC_DEBUG_MODULE("Deregistering driver.\n");
        usb_deregister(&pwc_driver);
-       PWC_INFO("Philips webcam module removed.\n");
 }
 
 module_init(usb_pwc_init);
 module_exit(usb_pwc_exit);
-
-/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
index 047dad8c15f7ca5b88c15e3cdb51d3d79703361d..8e02b7ac21391e2d5bfd5694d6e56ede70815604 100644 (file)
@@ -27,7 +27,7 @@
 #ifndef PWC_KIARA_H
 #define PWC_KIARA_H
 
-#include <media/pwc-ioctl.h>
+#include "pwc.h"
 
 #define PWC_FPS_MAX_KIARA 6
 
index 0b031336eab84aa1272c0a299360c739eee5e950..9be5adffa874683929ec57d41e17eeb36bf600aa 100644 (file)
 
 #include "pwc.h"
 
-const struct pwc_coord pwc_image_sizes[PSZ_MAX] =
+const int pwc_image_sizes[PSZ_MAX][2] =
 {
-       { 128,  96, 0 }, /* sqcif */
-       { 160, 120, 0 }, /* qsif */
-       { 176, 144, 0 }, /* qcif */
-       { 320, 240, 0 }, /* sif */
-       { 352, 288, 0 }, /* cif */
-       { 640, 480, 0 }, /* vga */
+       { 128,  96 }, /* sqcif */
+       { 160, 120 }, /* qsif */
+       { 176, 144 }, /* qcif */
+       { 320, 240 }, /* sif */
+       { 352, 288 }, /* cif */
+       { 640, 480 }, /* vga */
 };
 
 /* x,y -> PSZ_ */
-int pwc_decode_size(struct pwc_device *pdev, int width, int height)
+int pwc_get_size(struct pwc_device *pdev, int width, int height)
 {
-       int i, find;
-
-       /* Make sure we don't go beyond our max size.
-          NB: we have different limits for RAW and normal modes. In case
-          you don't have the decompressor loaded or use RAW mode,
-          the maximum viewable size is smaller.
-       */
-       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
-       {
-               if (width > pdev->abs_max.x || height > pdev->abs_max.y)
-               {
-                       PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
-                       return -1;
-               }
-       }
-       else
-       {
-               if (width > pdev->view_max.x || height > pdev->view_max.y)
-               {
-                       PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n");
-                       return -1;
-               }
-       }
+       int i;
 
        /* Find the largest size supported by the camera that fits into the
-          requested size.
-        */
-       find = -1;
+          requested size. */
+       for (i = PSZ_MAX - 1; i >= 0; i--) {
+               if (!(pdev->image_mask & (1 << i)))
+                       continue;
+
+               if (pwc_image_sizes[i][0] <= width &&
+                   pwc_image_sizes[i][1] <= height)
+                       return i;
+       }
+
+       /* No mode found, return the smallest mode we have */
        for (i = 0; i < PSZ_MAX; i++) {
-               if (pdev->image_mask & (1 << i)) {
-                       if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height)
-                               find = i;
-               }
+               if (pdev->image_mask & (1 << i))
+                       return i;
        }
-       return find;
+
+       /* Never reached there always is atleast one supported mode */
+       return 0;
 }
 
-/* initialize variables depending on type and decompressor*/
+/* initialize variables depending on type and decompressor */
 void pwc_construct(struct pwc_device *pdev)
 {
        if (DEVICE_USE_CODEC1(pdev->type)) {
 
-               pdev->view_min.x = 128;
-               pdev->view_min.y =  96;
-               pdev->view_max.x = 352;
-               pdev->view_max.y = 288;
-               pdev->abs_max.x  = 352;
-               pdev->abs_max.y  = 288;
                pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF;
                pdev->vcinterface = 2;
                pdev->vendpoint = 4;
@@ -96,13 +76,7 @@ void pwc_construct(struct pwc_device *pdev)
 
        } else if (DEVICE_USE_CODEC3(pdev->type)) {
 
-               pdev->view_min.x = 160;
-               pdev->view_min.y = 120;
-               pdev->view_max.x = 640;
-               pdev->view_max.y = 480;
                pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
-               pdev->abs_max.x = 640;
-               pdev->abs_max.y = 480;
                pdev->vcinterface = 3;
                pdev->vendpoint = 5;
                pdev->frame_header_size = TOUCAM_HEADER_SIZE;
@@ -110,20 +84,10 @@ void pwc_construct(struct pwc_device *pdev)
 
        } else /* if (DEVICE_USE_CODEC2(pdev->type)) */ {
 
-               pdev->view_min.x = 128;
-               pdev->view_min.y =  96;
-               /* Anthill bug #38: PWC always reports max size, even without PWCX */
-               pdev->view_max.x = 640;
-               pdev->view_max.y = 480;
                pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA;
-               pdev->abs_max.x = 640;
-               pdev->abs_max.y = 480;
                pdev->vcinterface = 3;
                pdev->vendpoint = 4;
                pdev->frame_header_size = 0;
                pdev->frame_trailer_size = 0;
        }
-       pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */
-       pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
-       pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
 }
index a6e22224c95f58206b68ae368e9c1eec8548ec7e..270c5b9010f6f11c9129e3699b73ea6d0919ef09 100644 (file)
@@ -42,7 +42,7 @@
 #ifndef PWC_TIMON_H
 #define PWC_TIMON_H
 
-#include <media/pwc-ioctl.h>
+#include "pwc.h"
 
 #define PWC_FPS_MAX_TIMON 6
 
index 51265092bd312014308d9ed90e0369952963aedd..b65903fbcf0d536c4b309408e24e73a737fb66d5 100644 (file)
@@ -35,7 +35,7 @@
 
 int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
 {
-       int n, line, col, stride;
+       int n, line, col;
        void *yuv, *image;
        u16 *src;
        u16 *dsty, *dstu, *dstv;
@@ -60,35 +60,23 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
                return 0;
        }
 
-       vb2_set_plane_payload(&fbuf->vb, 0, pdev->view.size);
+       vb2_set_plane_payload(&fbuf->vb, 0,
+                             pdev->width * pdev->height * 3 / 2);
 
        if (pdev->vbandlength == 0) {
                /* Uncompressed mode.
-                * We copy the data into the output buffer, using the viewport
-                * size (which may be larger than the image size).
-                * Unfortunately we have to do a bit of byte stuffing to get
-                * the desired output format/size.
                 *
                 * We do some byte shuffling here to go from the
                 * native format to YUV420P.
                 */
                src = (u16 *)yuv;
-               n = pdev->view.x * pdev->view.y;
+               n = pdev->width * pdev->height;
+               dsty = (u16 *)(image);
+               dstu = (u16 *)(image + n);
+               dstv = (u16 *)(image + n + n / 4);
 
-               /* offset in Y plane */
-               stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
-               dsty = (u16 *)(image + stride);
-
-               /* offsets in U/V planes */
-               stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
-               dstu = (u16 *)(image + n +         stride);
-               dstv = (u16 *)(image + n + n / 4 + stride);
-
-               /* increment after each line */
-               stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
-
-               for (line = 0; line < pdev->image.y; line++) {
-                       for (col = 0; col < pdev->image.x; col += 4) {
+               for (line = 0; line < pdev->height; line++) {
+                       for (col = 0; col < pdev->width; col += 4) {
                                *dsty++ = *src++;
                                *dsty++ = *src++;
                                if (line & 1)
@@ -96,11 +84,6 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
                                else
                                        *dstu++ = *src++;
                        }
-                       dsty += stride;
-                       if (line & 1)
-                               dstv += (stride >> 1);
-                       else
-                               dstu += (stride >> 1);
                }
 
                return 0;
@@ -111,12 +94,6 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
         * the decompressor routines will write the data in planar format
         * immediately.
         */
-       if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) {
-               PWC_ERROR("Mode Bayer is not supported for now\n");
-               /* flags |= PWCX_FLAG_BAYER; */
-               return -ENXIO; /* No such device or address: missing decompressor */
-       }
-
        if (DEVICE_USE_CODEC1(pdev->type)) {
 
                /* TODO & FIXME */
@@ -124,10 +101,7 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
                return -ENXIO; /* No such device or address: missing decompressor */
 
        } else {
-               pwc_dec23_decompress(pdev, yuv, image, PWCX_FLAG_PLANAR);
+               pwc_dec23_decompress(pdev, yuv, image);
        }
        return 0;
 }
-
-
-/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
index a10ff6b64acf21a552ae4bd58a686d7cfb27de93..f495eeb5403aaff31dd66ba582a07d86297752b9 100644 (file)
@@ -49,6 +49,7 @@ static const struct v4l2_ctrl_ops pwc_ctrl_ops = {
 
 enum { awb_indoor, awb_outdoor, awb_fl, awb_manual, awb_auto };
 enum { custom_autocontour, custom_contour, custom_noise_reduction,
+       custom_awb_speed, custom_awb_delay,
        custom_save_user, custom_restore_user, custom_restore_factory };
 
 const char * const pwc_auto_whitebal_qmenu[] = {
@@ -138,6 +139,26 @@ static const struct v4l2_ctrl_config pwc_restore_factory_cfg = {
        .name    = "Restore Factory Settings",
 };
 
+static const struct v4l2_ctrl_config pwc_awb_speed_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(awb_speed),
+       .type   = V4L2_CTRL_TYPE_INTEGER,
+       .name   = "Auto White Balance Speed",
+       .min    = 1,
+       .max    = 32,
+       .step   = 1,
+};
+
+static const struct v4l2_ctrl_config pwc_awb_delay_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(awb_delay),
+       .type   = V4L2_CTRL_TYPE_INTEGER,
+       .name   = "Auto White Balance Delay",
+       .min    = 0,
+       .max    = 63,
+       .step   = 1,
+};
+
 int pwc_init_controls(struct pwc_device *pdev)
 {
        struct v4l2_ctrl_handler *hdl;
@@ -338,6 +359,23 @@ int pwc_init_controls(struct pwc_device *pdev)
        if (pdev->restore_factory)
                pdev->restore_factory->flags |= V4L2_CTRL_FLAG_UPDATE;
 
+       /* Auto White Balance speed & delay */
+       r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL,
+                           AWB_CONTROL_SPEED_FORMATTER, &def);
+       if (r || def < 1 || def > 32)
+               def = 1;
+       cfg = pwc_awb_speed_cfg;
+       cfg.def = def;
+       pdev->awb_speed = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+
+       r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL,
+                           AWB_CONTROL_DELAY_FORMATTER, &def);
+       if (r || def > 63)
+               def = 0;
+       cfg = pwc_awb_delay_cfg;
+       cfg.def = def;
+       pdev->awb_delay = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+
        if (!(pdev->features & FEATURE_MOTOR_PANTILT))
                return hdl->error;
 
@@ -357,25 +395,16 @@ int pwc_init_controls(struct pwc_device *pdev)
        return hdl->error;
 }
 
-static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
+static void pwc_vidioc_fill_fmt(struct v4l2_format *f,
+       int width, int height, u32 pixfmt)
 {
        memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
-       f->fmt.pix.width        = pdev->view.x;
-       f->fmt.pix.height       = pdev->view.y;
+       f->fmt.pix.width        = width;
+       f->fmt.pix.height       = height;
        f->fmt.pix.field        = V4L2_FIELD_NONE;
-       if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
-               f->fmt.pix.pixelformat  = V4L2_PIX_FMT_YUV420;
-               f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
-               f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
-       } else {
-               /* vbandlength contains 4 lines ...  */
-               f->fmt.pix.bytesperline = pdev->vbandlength/4;
-               f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
-               if (DEVICE_USE_CODEC1(pdev->type))
-                       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC1;
-               else
-                       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC2;
-       }
+       f->fmt.pix.pixelformat  = pixfmt;
+       f->fmt.pix.bytesperline = f->fmt.pix.width;
+       f->fmt.pix.sizeimage    = f->fmt.pix.height * f->fmt.pix.width * 3 / 2;
        PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
                        "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
                        f->fmt.pix.width,
@@ -391,6 +420,8 @@ static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_forma
 /* ioctl(VIDIOC_TRY_FMT) */
 static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
 {
+       int size;
+
        if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
                return -EINVAL;
@@ -417,15 +448,11 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
 
        }
 
-       if (f->fmt.pix.width > pdev->view_max.x)
-               f->fmt.pix.width = pdev->view_max.x;
-       else if (f->fmt.pix.width < pdev->view_min.x)
-               f->fmt.pix.width = pdev->view_min.x;
-
-       if (f->fmt.pix.height > pdev->view_max.y)
-               f->fmt.pix.height = pdev->view_max.y;
-       else if (f->fmt.pix.height < pdev->view_min.y)
-               f->fmt.pix.height = pdev->view_min.y;
+       size = pwc_get_size(pdev, f->fmt.pix.width, f->fmt.pix.height);
+       pwc_vidioc_fill_fmt(f,
+                           pwc_image_sizes[size][0],
+                           pwc_image_sizes[size][1],
+                           f->fmt.pix.pixelformat);
 
        return 0;
 }
@@ -435,68 +462,45 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
 static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
 {
        struct pwc_device *pdev = video_drvdata(file);
-       int ret, fps, snapshot, compression, pixelformat;
-
-       if (!pdev->udev)
-               return -ENODEV;
+       int ret, pixelformat, compression = 0;
 
-       if (pdev->capt_file != NULL &&
-           pdev->capt_file != file)
+       if (pwc_test_n_set_capt_file(pdev, file))
                return -EBUSY;
 
-       pdev->capt_file = file;
-
        ret = pwc_vidioc_try_fmt(pdev, f);
-       if (ret<0)
+       if (ret < 0)
                return ret;
 
        pixelformat = f->fmt.pix.pixelformat;
-       compression = pdev->vcompression;
-       snapshot = 0;
-       fps = pdev->vframes;
-       if (f->fmt.pix.priv) {
-               compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
-               snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
-               fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
-               if (fps == 0)
-                       fps = pdev->vframes;
-       }
 
-       if (pixelformat != V4L2_PIX_FMT_YUV420 &&
-           pixelformat != V4L2_PIX_FMT_PWC1 &&
-           pixelformat != V4L2_PIX_FMT_PWC2)
-               return -EINVAL;
+       mutex_lock(&pdev->udevlock);
+       if (!pdev->udev) {
+               ret = -ENODEV;
+               goto leave;
+       }
 
-       if (vb2_is_streaming(&pdev->vb_queue))
-               return -EBUSY;
+       if (pdev->iso_init) {
+               ret = -EBUSY;
+               goto leave;
+       }
 
        PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d "
-                       "compression=%d snapshot=%d format=%c%c%c%c\n",
-                       f->fmt.pix.width, f->fmt.pix.height, fps,
-                       compression, snapshot,
+                       "format=%c%c%c%c\n",
+                       f->fmt.pix.width, f->fmt.pix.height, pdev->vframes,
                        (pixelformat)&255,
                        (pixelformat>>8)&255,
                        (pixelformat>>16)&255,
                        (pixelformat>>24)&255);
 
-       ret = pwc_set_video_mode(pdev,
-                                f->fmt.pix.width,
-                                f->fmt.pix.height,
-                                fps,
-                                compression,
-                                snapshot);
+       ret = pwc_set_video_mode(pdev, f->fmt.pix.width, f->fmt.pix.height,
+                                pixelformat, 30, &compression, 0);
 
        PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret);
 
-       if (ret)
-               return ret;
-
-       pdev->pixfmt = pixelformat;
-
-       pwc_vidioc_fill_fmt(pdev, f);
-
-       return 0;
-
+       pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt);
+leave:
+       mutex_unlock(&pdev->udevlock);
+       return ret;
 }
 
 static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
@@ -536,30 +540,14 @@ static int pwc_s_input(struct file *file, void *fh, unsigned int i)
        return i ? -EINVAL : 0;
 }
 
-static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+static int pwc_g_volatile_ctrl_unlocked(struct v4l2_ctrl *ctrl)
 {
        struct pwc_device *pdev =
                container_of(ctrl->handler, struct pwc_device, ctrl_handler);
        int ret = 0;
 
-       /*
-        * Sometimes it can take quite long for the pwc to complete usb control
-        * transfers, so release the modlock to give streaming by another
-        * process / thread the chance to continue with a dqbuf.
-        */
-       mutex_unlock(&pdev->modlock);
-
-       /*
-        * Take the udev-lock to protect against the disconnect handler
-        * completing and setting dev->udev to NULL underneath us. Other code
-        * does not need to do this since it is protected by the modlock.
-        */
-       mutex_lock(&pdev->udevlock);
-
-       if (!pdev->udev) {
-               ret = -ENODEV;
-               goto leave;
-       }
+       if (!pdev->udev)
+               return -ENODEV;
 
        switch (ctrl->id) {
        case V4L2_CID_AUTO_WHITE_BALANCE:
@@ -624,9 +612,18 @@ static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
        if (ret)
                PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret);
 
-leave:
+       return ret;
+}
+
+static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct pwc_device *pdev =
+               container_of(ctrl->handler, struct pwc_device, ctrl_handler);
+       int ret;
+
+       mutex_lock(&pdev->udevlock);
+       ret = pwc_g_volatile_ctrl_unlocked(ctrl);
        mutex_unlock(&pdev->udevlock);
-       mutex_lock(&pdev->modlock);
        return ret;
 }
 
@@ -643,6 +640,15 @@ static int pwc_set_awb(struct pwc_device *pdev)
 
                if (pdev->auto_white_balance->val != awb_manual)
                        pdev->color_bal_valid = false; /* Force cache update */
+
+               /*
+                * If this is a preset, update our red / blue balance values
+                * so that events get generated for the new preset values
+                */
+               if (pdev->auto_white_balance->val == awb_indoor ||
+                   pdev->auto_white_balance->val == awb_outdoor ||
+                   pdev->auto_white_balance->val == awb_fl)
+                       pwc_g_volatile_ctrl_unlocked(pdev->auto_white_balance);
        }
        if (pdev->auto_white_balance->val != awb_manual)
                return 0;
@@ -766,33 +772,33 @@ static int pwc_set_autogain_expo(struct pwc_device *pdev)
 static int pwc_set_motor(struct pwc_device *pdev)
 {
        int ret;
-       u8 buf[4];
 
-       buf[0] = 0;
+       pdev->ctrl_buf[0] = 0;
        if (pdev->motor_pan_reset->is_new)
-               buf[0] |= 0x01;
+               pdev->ctrl_buf[0] |= 0x01;
        if (pdev->motor_tilt_reset->is_new)
-               buf[0] |= 0x02;
+               pdev->ctrl_buf[0] |= 0x02;
        if (pdev->motor_pan_reset->is_new || pdev->motor_tilt_reset->is_new) {
                ret = send_control_msg(pdev, SET_MPT_CTL,
-                                      PT_RESET_CONTROL_FORMATTER, buf, 1);
+                                      PT_RESET_CONTROL_FORMATTER,
+                                      pdev->ctrl_buf, 1);
                if (ret < 0)
                        return ret;
        }
 
-       memset(buf, 0, sizeof(buf));
+       memset(pdev->ctrl_buf, 0, 4);
        if (pdev->motor_pan->is_new) {
-               buf[0] = pdev->motor_pan->val & 0xFF;
-               buf[1] = (pdev->motor_pan->val >> 8);
+               pdev->ctrl_buf[0] = pdev->motor_pan->val & 0xFF;
+               pdev->ctrl_buf[1] = (pdev->motor_pan->val >> 8);
        }
        if (pdev->motor_tilt->is_new) {
-               buf[2] = pdev->motor_tilt->val & 0xFF;
-               buf[3] = (pdev->motor_tilt->val >> 8);
+               pdev->ctrl_buf[2] = pdev->motor_tilt->val & 0xFF;
+               pdev->ctrl_buf[3] = (pdev->motor_tilt->val >> 8);
        }
        if (pdev->motor_pan->is_new || pdev->motor_tilt->is_new) {
                ret = send_control_msg(pdev, SET_MPT_CTL,
                                       PT_RELATIVE_CONTROL_FORMATTER,
-                                      buf, sizeof(buf));
+                                      pdev->ctrl_buf, 4);
                if (ret < 0)
                        return ret;
        }
@@ -806,8 +812,6 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
                container_of(ctrl->handler, struct pwc_device, ctrl_handler);
        int ret = 0;
 
-       /* See the comments on locking in pwc_g_volatile_ctrl */
-       mutex_unlock(&pdev->modlock);
        mutex_lock(&pdev->udevlock);
 
        if (!pdev->udev) {
@@ -891,6 +895,16 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
                ret = pwc_button_ctrl(pdev,
                                      RESTORE_FACTORY_DEFAULTS_FORMATTER);
                break;
+       case PWC_CID_CUSTOM(awb_speed):
+               ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
+                                     AWB_CONTROL_SPEED_FORMATTER,
+                                     ctrl->val);
+               break;
+       case PWC_CID_CUSTOM(awb_delay):
+               ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
+                                     AWB_CONTROL_DELAY_FORMATTER,
+                                     ctrl->val);
+               break;
        case V4L2_CID_PAN_RELATIVE:
                ret = pwc_set_motor(pdev);
                break;
@@ -903,7 +917,6 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
 
 leave:
        mutex_unlock(&pdev->udevlock);
-       mutex_lock(&pdev->modlock);
        return ret;
 }
 
@@ -933,9 +946,14 @@ static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
 {
        struct pwc_device *pdev = video_drvdata(file);
 
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       mutex_lock(&pdev->udevlock); /* To avoid race with s_fmt */
        PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",
-                       pdev->image.x, pdev->image.y);
-       pwc_vidioc_fill_fmt(pdev, f);
+                       pdev->width, pdev->height);
+       pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt);
+       mutex_unlock(&pdev->udevlock);
        return 0;
 }
 
@@ -951,12 +969,9 @@ static int pwc_reqbufs(struct file *file, void *fh,
 {
        struct pwc_device *pdev = video_drvdata(file);
 
-       if (pdev->capt_file != NULL &&
-           pdev->capt_file != file)
+       if (pwc_test_n_set_capt_file(pdev, file))
                return -EBUSY;
 
-       pdev->capt_file = file;
-
        return vb2_reqbufs(&pdev->vb_queue, rb);
 }
 
@@ -1025,25 +1040,21 @@ static int pwc_enum_framesizes(struct file *file, void *fh,
        struct pwc_device *pdev = video_drvdata(file);
        unsigned int i = 0, index = fsize->index;
 
-       if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
+       if (fsize->pixel_format == V4L2_PIX_FMT_YUV420 ||
+           (fsize->pixel_format == V4L2_PIX_FMT_PWC1 &&
+                       DEVICE_USE_CODEC1(pdev->type)) ||
+           (fsize->pixel_format == V4L2_PIX_FMT_PWC2 &&
+                       DEVICE_USE_CODEC23(pdev->type))) {
                for (i = 0; i < PSZ_MAX; i++) {
-                       if (pdev->image_mask & (1UL << i)) {
-                               if (!index--) {
-                                       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
-                                       fsize->discrete.width = pwc_image_sizes[i].x;
-                                       fsize->discrete.height = pwc_image_sizes[i].y;
-                                       return 0;
-                               }
+                       if (!(pdev->image_mask & (1UL << i)))
+                               continue;
+                       if (!index--) {
+                               fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+                               fsize->discrete.width = pwc_image_sizes[i][0];
+                               fsize->discrete.height = pwc_image_sizes[i][1];
+                               return 0;
                        }
                }
-       } else if (fsize->index == 0 &&
-                       ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
-                        (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
-
-               fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
-               fsize->discrete.width = pdev->abs_max.x;
-               fsize->discrete.height = pdev->abs_max.y;
-               return 0;
        }
        return -EINVAL;
 }
@@ -1056,8 +1067,8 @@ static int pwc_enum_frameintervals(struct file *file, void *fh,
        unsigned int i;
 
        for (i = 0; i < PSZ_MAX; i++) {
-               if (pwc_image_sizes[i].x == fival->width &&
-                               pwc_image_sizes[i].y == fival->height) {
+               if (pwc_image_sizes[i][0] == fival->width &&
+                               pwc_image_sizes[i][1] == fival->height) {
                        size = i;
                        break;
                }
@@ -1078,20 +1089,69 @@ static int pwc_enum_frameintervals(struct file *file, void *fh,
        return 0;
 }
 
-static int pwc_log_status(struct file *file, void *priv)
+static int pwc_g_parm(struct file *file, void *fh,
+                     struct v4l2_streamparm *parm)
 {
        struct pwc_device *pdev = video_drvdata(file);
 
-       v4l2_ctrl_handler_log_status(&pdev->ctrl_handler, PWC_NAME);
+       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memset(parm, 0, sizeof(*parm));
+
+       parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       parm->parm.capture.readbuffers = MIN_FRAMES;
+       parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME;
+       parm->parm.capture.timeperframe.denominator = pdev->vframes;
+       parm->parm.capture.timeperframe.numerator = 1;
+
        return 0;
 }
 
-static long pwc_default(struct file *file, void *fh, bool valid_prio,
-                       int cmd, void *arg)
+static int pwc_s_parm(struct file *file, void *fh,
+                     struct v4l2_streamparm *parm)
 {
        struct pwc_device *pdev = video_drvdata(file);
+       int compression = 0;
+       int ret, fps;
 
-       return pwc_ioctl(pdev, cmd, arg);
+       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           parm->parm.capture.timeperframe.numerator == 0)
+               return -EINVAL;
+
+       if (pwc_test_n_set_capt_file(pdev, file))
+               return -EBUSY;
+
+       fps = parm->parm.capture.timeperframe.denominator /
+             parm->parm.capture.timeperframe.numerator;
+
+       mutex_lock(&pdev->udevlock);
+       if (!pdev->udev) {
+               ret = -ENODEV;
+               goto leave;
+       }
+
+       if (pdev->iso_init) {
+               ret = -EBUSY;
+               goto leave;
+       }
+
+       ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt,
+                                fps, &compression, 0);
+
+       pwc_g_parm(file, fh, parm);
+
+leave:
+       mutex_unlock(&pdev->udevlock);
+       return ret;
+}
+
+static int pwc_log_status(struct file *file, void *priv)
+{
+       struct pwc_device *pdev = video_drvdata(file);
+
+       v4l2_ctrl_handler_log_status(&pdev->ctrl_handler, PWC_NAME);
+       return 0;
 }
 
 const struct v4l2_ioctl_ops pwc_ioctl_ops = {
@@ -1112,8 +1172,6 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = {
        .vidioc_log_status                  = pwc_log_status,
        .vidioc_enum_framesizes             = pwc_enum_framesizes,
        .vidioc_enum_frameintervals         = pwc_enum_frameintervals,
-       .vidioc_default             = pwc_default,
+       .vidioc_g_parm                      = pwc_g_parm,
+       .vidioc_s_parm                      = pwc_s_parm,
 };
-
-
-/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
index 0e4e2d7b78720a0c954bc0d5db9df787f7c813b4..e4d4d711dd1f4df7182d20bcc3591fda9e32f628 100644 (file)
 #include <asm/errno.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
 #include <media/videobuf2-vmalloc.h>
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
 #include <linux/input.h>
 #endif
-
-#include <media/pwc-ioctl.h>
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
 
 /* Version block */
 #define PWC_VERSION    "10.0.15"
 #define FEATURE_CODEC1                 0x0002
 #define FEATURE_CODEC2                 0x0004
 
+#define MAX_WIDTH              640
+#define MAX_HEIGHT             480
+
 /* Ignore errors in the first N frames, to allow for startup delays */
 #define FRAME_LOWMARK 5
 
 #define DEVICE_USE_CODEC3(x) ((x)>=700)
 #define DEVICE_USE_CODEC23(x) ((x)>=675)
 
-/* from pwc-dec.h */
-#define PWCX_FLAG_PLANAR        0x0001
-
 /* Request types: video */
 #define SET_LUM_CTL                    0x01
 #define GET_LUM_CTL                    0x02
 #define PT_RESET_CONTROL_FORMATTER             0x02
 #define PT_STATUS_FORMATTER                    0x03
 
+/* Enumeration of image sizes */
+#define PSZ_SQCIF      0x00
+#define PSZ_QSIF       0x01
+#define PSZ_QCIF       0x02
+#define PSZ_SIF                0x03
+#define PSZ_CIF                0x04
+#define PSZ_VGA                0x05
+#define PSZ_MAX                6
+
+struct pwc_raw_frame {
+       __le16 type;            /* type of the webcam */
+       __le16 vbandlength;     /* Size of 4 lines compressed (used by the
+                                  decompressor) */
+       __u8   cmd[4];          /* the four byte of the command (in case of
+                                  nala, only the first 3 bytes is filled) */
+       __u8   rawframe[0];     /* frame_size = H / 4 * vbandlength */
+} __packed;
+
 /* intermediate buffers with raw data from the USB cam */
 struct pwc_frame_buf
 {
@@ -198,39 +219,36 @@ struct pwc_frame_buf
 struct pwc_device
 {
        struct video_device vdev;
-       struct mutex modlock;
+       struct v4l2_device v4l2_dev;
 
        /* Pointer to our usb_device, may be NULL after unplug */
        struct usb_device *udev;
-       /* Protects the setting of udev to NULL by our disconnect handler */
        struct mutex udevlock;
 
        /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
        int type;
        int release;            /* release number */
        int features;           /* feature bits */
-       char serial[30];        /* serial number (string) */
 
        /*** Video data ***/
        struct file *capt_file; /* file doing video capture */
+       struct mutex capt_file_lock;
        int vendpoint;          /* video isoc endpoint */
        int vcinterface;        /* video control interface */
        int valternate;         /* alternate interface needed */
-       int vframes, vsize;     /* frames-per-second & size (see PSZ_*) */
+       int vframes;            /* frames-per-second */
        int pixfmt;             /* pixelformat: V4L2_PIX_FMT_YUV420 or _PWCX */
        int vframe_count;       /* received frames */
        int vmax_packet_size;   /* USB maxpacket size */
        int vlast_packet_size;  /* for frame synchronisation */
        int visoc_errors;       /* number of contiguous ISOC errors */
-       int vcompression;       /* desired compression factor */
        int vbandlength;        /* compressed band length; 0 is uncompressed */
-       char vsnapshot;         /* snapshot mode */
        char vsync;             /* used by isoc handler */
        char vmirror;           /* for ToUCaM series */
        char power_save;        /* Do powersaving for this cam */
 
-       int cmd_len;
        unsigned char cmd_buf[13];
+       unsigned char *ctrl_buf;
 
        struct urb *urbs[MAX_ISO_BUFS];
        char iso_init;
@@ -253,7 +271,10 @@ struct pwc_device
        int frame_total_size;   /* including header & trailer */
        int drop_frames;
 
-       void *decompress_data;  /* private data for decompression engine */
+       union { /* private data for decompression engine */
+               struct pwc_dec1_private dec1;
+               struct pwc_dec23_private dec23;
+       };
 
        /*
         * We have an 'image' and a 'view', where 'image' is the fixed-size img
@@ -262,21 +283,8 @@ struct pwc_device
         * a gray or black border. view_min <= image <= view <= view_max;
         */
        int image_mask;                         /* supported sizes */
-       struct pwc_coord view_min, view_max;    /* minimum and maximum view */
-       struct pwc_coord abs_max;               /* maximum supported size */
-       struct pwc_coord image, view;           /* image and viewport size */
-       struct pwc_coord offset;                /* offset of the viewport */
+       int width, height;                      /* current resolution */
 
-       /*** motorized pan/tilt feature */
-       struct pwc_mpt_range angle_range;
-       int pan_angle;                  /* in degrees * 100 */
-       int tilt_angle;                 /* absolute angle; 0,0 is home */
-
-       /*
-        * Set to 1 when the user push the button, reset to 0
-        * when this value is read from sysfs.
-        */
-       int snapshot_button_status;
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
        struct input_dev *button_dev;   /* webcam snapshot button input */
        char button_phys[64];
@@ -328,6 +336,8 @@ struct pwc_device
        struct v4l2_ctrl                *save_user;
        struct v4l2_ctrl                *restore_user;
        struct v4l2_ctrl                *restore_factory;
+       struct v4l2_ctrl                *awb_speed;
+       struct v4l2_ctrl                *awb_delay;
        struct {
                /* motor control cluster */
                struct v4l2_ctrl        *motor_pan;
@@ -344,19 +354,20 @@ struct pwc_device
 extern int pwc_trace;
 #endif
 
+int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file);
+
 /** Functions in pwc-misc.c */
 /* sizes in pixels */
-extern const struct pwc_coord pwc_image_sizes[PSZ_MAX];
+extern const int pwc_image_sizes[PSZ_MAX][2];
 
-int pwc_decode_size(struct pwc_device *pdev, int width, int height);
+int pwc_get_size(struct pwc_device *pdev, int width, int height);
 void pwc_construct(struct pwc_device *pdev);
 
 /** Functions in pwc-ctrl.c */
 /* Request a certain video mode. Returns < 0 if not possible */
-extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
+extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
+       int pixfmt, int frames, int *compression, int send_to_cam);
 extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size);
-extern int pwc_mpt_reset(struct pwc_device *pdev, int flags);
-extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt);
 extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
 extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
 extern int send_control_msg(struct pwc_device *pdev,
@@ -375,9 +386,6 @@ int pwc_init_controls(struct pwc_device *pdev);
 /* Power down or up the camera; not supported by all models */
 extern void pwc_camera_power(struct pwc_device *pdev, int power);
 
-/* Private ioctl()s; see pwc-ioctl.h */
-extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
-
 extern const struct v4l2_ioctl_ops pwc_ioctl_ops;
 
 /** pwc-uncompress.c */
index 79fb22c89ae9f10a894722381c94fbaab2b884b7..0bd7da26d018142878c35956ae8c1126a44c5bfb 100644 (file)
@@ -1133,12 +1133,13 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd,
        __raw_writel(cicr0, pcdev->base + CICR0);
 }
 
-static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+static int pxa_camera_set_bus_param(struct soc_camera_device *icd)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+       u32 pixfmt = icd->current_fmt->host_fmt->fourcc;
        unsigned long bus_flags, common_flags;
        int ret;
        struct pxa_cam *cam = icd->host_priv;
@@ -1851,19 +1852,7 @@ static struct platform_driver pxa_camera_driver = {
        .remove         = __devexit_p(pxa_camera_remove),
 };
 
-
-static int __init pxa_camera_init(void)
-{
-       return platform_driver_register(&pxa_camera_driver);
-}
-
-static void __exit pxa_camera_exit(void)
-{
-       platform_driver_unregister(&pxa_camera_driver);
-}
-
-module_init(pxa_camera_init);
-module_exit(pxa_camera_exit);
+module_platform_driver(pxa_camera_driver);
 
 MODULE_DESCRIPTION("PXA27x SoC Camera Host driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
index 2cc3b9166724f2eaf47ea1c05f5a12e5e7208ea7..a9e9653beeb4581a90ea34eed1b3d96eab2aae5d 100644 (file)
@@ -63,6 +63,8 @@ static int fimc_init_capture(struct fimc_dev *fimc)
                fimc_hw_set_effect(ctx, false);
                fimc_hw_set_output_path(ctx);
                fimc_hw_set_out_dma(ctx);
+               if (fimc->variant->has_alpha)
+                       fimc_hw_set_rgb_alpha(ctx);
                clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
        }
        spin_unlock_irqrestore(&fimc->slock, flags);
@@ -154,6 +156,8 @@ int fimc_capture_config_update(struct fimc_ctx *ctx)
                fimc_hw_set_rotation(ctx);
                fimc_prepare_dma_offset(ctx, &ctx->d_frame);
                fimc_hw_set_out_dma(ctx);
+               if (fimc->variant->has_alpha)
+                       fimc_hw_set_rgb_alpha(ctx);
                clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
        }
        spin_unlock(&ctx->slock);
@@ -689,7 +693,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
                        mf->code = 0;
                        continue;
                }
-               if (mf->width != tfmt->width || mf->width != tfmt->width) {
+               if (mf->width != tfmt->width || mf->height != tfmt->height) {
                        u32 fcc = ffmt->fourcc;
                        tfmt->width  = mf->width;
                        tfmt->height = mf->height;
@@ -698,7 +702,8 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
                                               NULL, &fcc, FIMC_SD_PAD_SOURCE);
                        if (ffmt && ffmt->mbus_code)
                                mf->code = ffmt->mbus_code;
-                       if (mf->width != tfmt->width || mf->width != tfmt->width)
+                       if (mf->width != tfmt->width ||
+                           mf->height != tfmt->height)
                                continue;
                        tfmt->code = mf->code;
                }
@@ -706,7 +711,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
                        ret = v4l2_subdev_call(csis, pad, set_fmt, NULL, &sfmt);
 
                if (mf->code == tfmt->code &&
-                   mf->width == tfmt->width && mf->width == tfmt->width)
+                   mf->width == tfmt->width && mf->height == tfmt->height)
                        break;
        }
 
@@ -812,6 +817,10 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
                                          FIMC_SD_PAD_SOURCE);
        if (!ff->fmt)
                return -EINVAL;
+
+       /* Update RGB Alpha control state and value range */
+       fimc_alpha_ctrl_update(ctx);
+
        /* Try to match format at the host and the sensor */
        if (!fimc->vid_cap.user_subdev_api) {
                mf->code   = ff->fmt->mbus_code;
@@ -1235,6 +1244,9 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
                *mf = fmt->format;
                return 0;
        }
+       /* Update RGB Alpha control state and value range */
+       fimc_alpha_ctrl_update(ctx);
+
        fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color));
 
        ff = fmt->pad == FIMC_SD_PAD_SINK ?
index 07c6254faee32b1ef3ee75964faa2b63b1f7615d..81bcbb9492ea0a6d425375a57f3600837082d773 100644 (file)
@@ -52,13 +52,29 @@ static struct fimc_fmt fimc_formats[] = {
                .colplanes      = 1,
                .flags          = FMT_FLAGS_M2M,
        }, {
-               .name           = "XRGB-8-8-8-8, 32 bpp",
+               .name           = "ARGB8888, 32 bpp",
                .fourcc         = V4L2_PIX_FMT_RGB32,
                .depth          = { 32 },
                .color          = S5P_FIMC_RGB888,
                .memplanes      = 1,
                .colplanes      = 1,
-               .flags          = FMT_FLAGS_M2M,
+               .flags          = FMT_FLAGS_M2M | FMT_HAS_ALPHA,
+       }, {
+               .name           = "ARGB1555",
+               .fourcc         = V4L2_PIX_FMT_RGB555,
+               .depth          = { 16 },
+               .color          = S5P_FIMC_RGB555,
+               .memplanes      = 1,
+               .colplanes      = 1,
+               .flags          = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
+       }, {
+               .name           = "ARGB4444",
+               .fourcc         = V4L2_PIX_FMT_RGB444,
+               .depth          = { 16 },
+               .color          = S5P_FIMC_RGB444,
+               .memplanes      = 1,
+               .colplanes      = 1,
+               .flags          = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
        }, {
                .name           = "YUV 4:2:2 packed, YCbYCr",
                .fourcc         = V4L2_PIX_FMT_YUYV,
@@ -171,6 +187,14 @@ static struct fimc_fmt fimc_formats[] = {
        },
 };
 
+static unsigned int get_m2m_fmt_flags(unsigned int stream_type)
+{
+       if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return FMT_FLAGS_M2M_IN;
+       else
+               return FMT_FLAGS_M2M_OUT;
+}
+
 int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
                            int dw, int dh, int rotation)
 {
@@ -652,8 +676,11 @@ static void fimc_dma_run(void *priv)
        if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS))
                fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1);
 
-       if (ctx->state & FIMC_PARAMS)
+       if (ctx->state & FIMC_PARAMS) {
                fimc_hw_set_out_dma(ctx);
+               if (fimc->variant->has_alpha)
+                       fimc_hw_set_rgb_alpha(ctx);
+       }
 
        fimc_activate_capture(ctx);
 
@@ -750,12 +777,11 @@ static struct vb2_ops fimc_qops = {
 #define ctrl_to_ctx(__ctrl) \
        container_of((__ctrl)->handler, struct fimc_ctx, ctrl_handler)
 
-static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
+static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
 {
-       struct fimc_ctx *ctx = ctrl_to_ctx(ctrl);
        struct fimc_dev *fimc = ctx->fimc_dev;
        struct samsung_fimc_variant *variant = fimc->variant;
-       unsigned long flags;
+       unsigned int flags = FIMC_DST_FMT | FIMC_SRC_FMT;
        int ret = 0;
 
        if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
@@ -763,59 +789,77 @@ static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
 
        switch (ctrl->id) {
        case V4L2_CID_HFLIP:
-               spin_lock_irqsave(&ctx->slock, flags);
                ctx->hflip = ctrl->val;
                break;
 
        case V4L2_CID_VFLIP:
-               spin_lock_irqsave(&ctx->slock, flags);
                ctx->vflip = ctrl->val;
                break;
 
        case V4L2_CID_ROTATE:
                if (fimc_capture_pending(fimc) ||
-                   fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
+                   (ctx->state & flags) == flags) {
                        ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
                                        ctx->s_frame.height, ctx->d_frame.width,
                                        ctx->d_frame.height, ctrl->val);
-               }
-               if (ret) {
-                       v4l2_err(fimc->m2m.vfd, "Out of scaler range\n");
-                       return -EINVAL;
+                       if (ret)
+                               return -EINVAL;
                }
                if ((ctrl->val == 90 || ctrl->val == 270) &&
                    !variant->has_out_rot)
                        return -EINVAL;
-               spin_lock_irqsave(&ctx->slock, flags);
+
                ctx->rotation = ctrl->val;
                break;
 
-       default:
-               v4l2_err(fimc->v4l2_dev, "Invalid control: 0x%X\n", ctrl->id);
-               return -EINVAL;
+       case V4L2_CID_ALPHA_COMPONENT:
+               ctx->d_frame.alpha = ctrl->val;
+               break;
        }
        ctx->state |= FIMC_PARAMS;
        set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
-       spin_unlock_irqrestore(&ctx->slock, flags);
        return 0;
 }
 
+static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct fimc_ctx *ctx = ctrl_to_ctx(ctrl);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&ctx->slock, flags);
+       ret = __fimc_s_ctrl(ctx, ctrl);
+       spin_unlock_irqrestore(&ctx->slock, flags);
+
+       return ret;
+}
+
 static const struct v4l2_ctrl_ops fimc_ctrl_ops = {
        .s_ctrl = fimc_s_ctrl,
 };
 
 int fimc_ctrls_create(struct fimc_ctx *ctx)
 {
+       struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+       unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt);
+
        if (ctx->ctrls_rdy)
                return 0;
-       v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
+       v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
 
        ctx->ctrl_rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
-                                    V4L2_CID_HFLIP, 0, 1, 1, 0);
+                                       V4L2_CID_ROTATE, 0, 270, 90, 0);
        ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
-                                   V4L2_CID_VFLIP, 0, 1, 1, 0);
+                                       V4L2_CID_HFLIP, 0, 1, 1, 0);
        ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
-                                   V4L2_CID_ROTATE, 0, 270, 90, 0);
+                                       V4L2_CID_VFLIP, 0, 1, 1, 0);
+       if (variant->has_alpha)
+               ctx->ctrl_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+                                   &fimc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
+                                   0, max_alpha, 1, 0);
+       else
+               ctx->ctrl_alpha = NULL;
+
        ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
 
        return ctx->ctrl_handler.error;
@@ -826,11 +870,14 @@ void fimc_ctrls_delete(struct fimc_ctx *ctx)
        if (ctx->ctrls_rdy) {
                v4l2_ctrl_handler_free(&ctx->ctrl_handler);
                ctx->ctrls_rdy = false;
+               ctx->ctrl_alpha = NULL;
        }
 }
 
 void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
 {
+       unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA;
+
        if (!ctx->ctrls_rdy)
                return;
 
@@ -838,6 +885,8 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
        v4l2_ctrl_activate(ctx->ctrl_rotate, active);
        v4l2_ctrl_activate(ctx->ctrl_hflip, active);
        v4l2_ctrl_activate(ctx->ctrl_vflip, active);
+       if (ctx->ctrl_alpha)
+               v4l2_ctrl_activate(ctx->ctrl_alpha, active && has_alpha);
 
        if (active) {
                ctx->rotation = ctx->ctrl_rotate->val;
@@ -851,6 +900,24 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
        mutex_unlock(&ctx->ctrl_handler.lock);
 }
 
+/* Update maximum value of the alpha color control */
+void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
+{
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct v4l2_ctrl *ctrl = ctx->ctrl_alpha;
+
+       if (ctrl == NULL || !fimc->variant->has_alpha)
+               return;
+
+       v4l2_ctrl_lock(ctrl);
+       ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt);
+
+       if (ctrl->cur.val > ctrl->maximum)
+               ctrl->cur.val = ctrl->maximum;
+
+       v4l2_ctrl_unlock(ctrl);
+}
+
 /*
  * V4L2 ioctl handlers
  */
@@ -874,7 +941,8 @@ static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv,
 {
        struct fimc_fmt *fmt;
 
-       fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_M2M, f->index);
+       fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type),
+                              f->index);
        if (!fmt)
                return -EINVAL;
 
@@ -938,6 +1006,7 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
        pix->colorspace = V4L2_COLORSPACE_JPEG;
        pix->field = V4L2_FIELD_NONE;
        pix->num_planes = fmt->memplanes;
+       pix->pixelformat = fmt->fourcc;
        pix->height = height;
        pix->width = width;
 
@@ -1017,7 +1086,8 @@ static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
 
        dbg("w: %d, h: %d", pix->width, pix->height);
 
-       fmt = fimc_find_format(&pix->pixelformat, NULL, FMT_FLAGS_M2M, 0);
+       fmt = fimc_find_format(&pix->pixelformat, NULL,
+                              get_m2m_fmt_flags(f->type), 0);
        if (WARN(fmt == NULL, "Pixel format lookup failed"))
                return -EINVAL;
 
@@ -1087,10 +1157,13 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
 
        pix = &f->fmt.pix_mp;
        frame->fmt = fimc_find_format(&pix->pixelformat, NULL,
-                                     FMT_FLAGS_M2M, 0);
+                                     get_m2m_fmt_flags(f->type), 0);
        if (!frame->fmt)
                return -EINVAL;
 
+       /* Update RGB Alpha control state and value range */
+       fimc_alpha_ctrl_update(ctx);
+
        for (i = 0; i < frame->fmt->colplanes; i++) {
                frame->payload[i] =
                        (pix->width * pix->height * frame->fmt->depth[i]) / 8;
@@ -1374,6 +1447,12 @@ static int fimc_m2m_open(struct file *file)
        if (!ctx)
                return -ENOMEM;
        v4l2_fh_init(&ctx->fh, fimc->m2m.vfd);
+       ctx->fimc_dev = fimc;
+
+       /* Default color format */
+       ctx->s_frame.fmt = &fimc_formats[0];
+       ctx->d_frame.fmt = &fimc_formats[0];
+
        ret = fimc_ctrls_create(ctx);
        if (ret)
                goto error_fh;
@@ -1383,10 +1462,6 @@ static int fimc_m2m_open(struct file *file)
        file->private_data = &ctx->fh;
        v4l2_fh_add(&ctx->fh);
 
-       ctx->fimc_dev = fimc;
-       /* Default color format */
-       ctx->s_frame.fmt = &fimc_formats[0];
-       ctx->d_frame.fmt = &fimc_formats[0];
        /* Setup the device context for memory-to-memory mode */
        ctx->state = FIMC_CTX_M2M;
        ctx->flags = 0;
@@ -1709,9 +1784,8 @@ static int fimc_runtime_resume(struct device *dev)
        /* Resume the capture or mem-to-mem device */
        if (fimc_capture_busy(fimc))
                return fimc_capture_resume(fimc);
-       else if (fimc_m2m_pending(fimc))
-               return fimc_m2m_resume(fimc);
-       return 0;
+
+       return fimc_m2m_resume(fimc);
 }
 
 static int fimc_runtime_suspend(struct device *dev)
@@ -1893,6 +1967,7 @@ static struct samsung_fimc_variant fimc0_variant_exynos4 = {
        .has_cam_if      = 1,
        .has_cistatus2   = 1,
        .has_mainscaler_ext = 1,
+       .has_alpha       = 1,
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
        .hor_offs_align  = 2,
@@ -1906,6 +1981,7 @@ static struct samsung_fimc_variant fimc3_variant_exynos4 = {
        .has_cam_if      = 1,
        .has_cistatus2   = 1,
        .has_mainscaler_ext = 1,
+       .has_alpha       = 1,
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
        .hor_offs_align  = 2,
index c7f01c47b20fe354e101bbf4ab904cab18e3ec55..4e20560c73d4d5ed6e74e81c324cd5ca7cc062ca 100644 (file)
@@ -85,7 +85,9 @@ enum fimc_datapath {
 };
 
 enum fimc_color_fmt {
-       S5P_FIMC_RGB565 = 0x10,
+       S5P_FIMC_RGB444 = 0x10,
+       S5P_FIMC_RGB555,
+       S5P_FIMC_RGB565,
        S5P_FIMC_RGB666,
        S5P_FIMC_RGB888,
        S5P_FIMC_RGB30_LOCAL,
@@ -160,8 +162,11 @@ struct fimc_fmt {
        u16     colplanes;
        u8      depth[VIDEO_MAX_PLANES];
        u16     flags;
-#define FMT_FLAGS_CAM  (1 << 0)
-#define FMT_FLAGS_M2M  (1 << 1)
+#define FMT_FLAGS_CAM          (1 << 0)
+#define FMT_FLAGS_M2M_IN       (1 << 1)
+#define FMT_FLAGS_M2M_OUT      (1 << 2)
+#define FMT_FLAGS_M2M          (1 << 1 | 1 << 2)
+#define FMT_HAS_ALPHA          (1 << 3)
 };
 
 /**
@@ -283,6 +288,7 @@ struct fimc_frame {
        struct fimc_addr        paddr;
        struct fimc_dma_offset  dma_offset;
        struct fimc_fmt         *fmt;
+       u8                      alpha;
 };
 
 /**
@@ -387,6 +393,7 @@ struct samsung_fimc_variant {
        unsigned int    has_cistatus2:1;
        unsigned int    has_mainscaler_ext:1;
        unsigned int    has_cam_if:1;
+       unsigned int    has_alpha:1;
        struct fimc_pix_limit *pix_limit;
        u16             min_inp_pixsize;
        u16             min_out_pixsize;
@@ -482,7 +489,8 @@ struct fimc_dev {
  * @ctrl_handler:      v4l2 controls handler
  * @ctrl_rotate                image rotation control
  * @ctrl_hflip         horizontal flip control
- * @ctrl_vflip         vartical flip control
+ * @ctrl_vflip         vertical flip control
+ * @ctrl_alpha         RGB alpha control
  * @ctrls_rdy:         true if the control handler is initialized
  */
 struct fimc_ctx {
@@ -509,6 +517,7 @@ struct fimc_ctx {
        struct v4l2_ctrl        *ctrl_rotate;
        struct v4l2_ctrl        *ctrl_hflip;
        struct v4l2_ctrl        *ctrl_vflip;
+       struct v4l2_ctrl        *ctrl_alpha;
        bool                    ctrls_rdy;
 };
 
@@ -578,6 +587,17 @@ static inline int tiled_fmt(struct fimc_fmt *fmt)
        return fmt->fourcc == V4L2_PIX_FMT_NV12MT;
 }
 
+/* Return the alpha component bit mask */
+static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt)
+{
+       switch (fmt->color) {
+       case S5P_FIMC_RGB444:   return 0x0f;
+       case S5P_FIMC_RGB555:   return 0x01;
+       case S5P_FIMC_RGB888:   return 0xff;
+       default:                return 0;
+       };
+}
+
 static inline void fimc_hw_clear_irq(struct fimc_dev *dev)
 {
        u32 cfg = readl(dev->regs + S5P_CIGCTRL);
@@ -674,6 +694,7 @@ void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
 void fimc_hw_set_mainscaler(struct fimc_ctx *ctx);
 void fimc_hw_en_capture(struct fimc_ctx *ctx);
 void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active);
+void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx);
 void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
 void fimc_hw_set_input_path(struct fimc_ctx *ctx);
 void fimc_hw_set_output_path(struct fimc_ctx *ctx);
@@ -695,6 +716,7 @@ int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
 int fimc_ctrls_create(struct fimc_ctx *ctx);
 void fimc_ctrls_delete(struct fimc_ctx *ctx);
 void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active);
+void fimc_alpha_ctrl_update(struct fimc_ctx *ctx);
 int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f);
 void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
                               struct v4l2_pix_format_mplane *pix);
index 615c862f0360ef20061e28701d1a99f460d0a7e1..8ea4ee116e46900224a528fa415d300d2c43196b 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/pm_runtime.h>
 #include <linux/types.h>
 #include <linux/slab.h>
-#include <linux/version.h>
 #include <media/v4l2-ctrls.h>
 #include <media/media-device.h>
 
index 44f5c2d1920bb50dd0dfe8e436eec1df32aa8c3f..15466d0529c14907e2cf2716cd49b1f1da03e8f5 100644 (file)
@@ -117,7 +117,7 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx)
                  S5P_CITRGFMT_VSIZE_MASK);
 
        switch (frame->fmt->color) {
-       case S5P_FIMC_RGB565...S5P_FIMC_RGB888:
+       case S5P_FIMC_RGB444...S5P_FIMC_RGB888:
                cfg |= S5P_CITRGFMT_RGB;
                break;
        case S5P_FIMC_YCBCR420:
@@ -175,6 +175,7 @@ void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
        struct fimc_dev *dev = ctx->fimc_dev;
        struct fimc_frame *frame = &ctx->d_frame;
        struct fimc_dma_offset *offset = &frame->dma_offset;
+       struct fimc_fmt *fmt = frame->fmt;
 
        /* Set the input dma offsets. */
        cfg = 0;
@@ -198,15 +199,22 @@ void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
        cfg = readl(dev->regs + S5P_CIOCTRL);
 
        cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK |
-                S5P_CIOCTRL_YCBCR_PLANE_MASK);
+                S5P_CIOCTRL_YCBCR_PLANE_MASK | S5P_CIOCTRL_RGB16FMT_MASK);
 
-       if (frame->fmt->colplanes == 1)
+       if (fmt->colplanes == 1)
                cfg |= ctx->out_order_1p;
-       else if (frame->fmt->colplanes == 2)
+       else if (fmt->colplanes == 2)
                cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE;
-       else if (frame->fmt->colplanes == 3)
+       else if (fmt->colplanes == 3)
                cfg |= S5P_CIOCTRL_YCBCR_3PLANE;
 
+       if (fmt->color == S5P_FIMC_RGB565)
+               cfg |= S5P_CIOCTRL_RGB565;
+       else if (fmt->color == S5P_FIMC_RGB555)
+               cfg |= S5P_CIOCTRL_ARGB1555;
+       else if (fmt->color == S5P_FIMC_RGB444)
+               cfg |= S5P_CIOCTRL_ARGB4444;
+
        writel(cfg, dev->regs + S5P_CIOCTRL);
 }
 
@@ -278,22 +286,28 @@ static void fimc_hw_set_scaler(struct fimc_ctx *ctx)
        if (sc->copy_mode)
                cfg |= S5P_CISCCTRL_ONE2ONE;
 
-
        if (ctx->in_path == FIMC_DMA) {
-               if (src_frame->fmt->color == S5P_FIMC_RGB565)
+               switch (src_frame->fmt->color) {
+               case S5P_FIMC_RGB565:
                        cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565;
-               else if (src_frame->fmt->color == S5P_FIMC_RGB666)
+                       break;
+               case S5P_FIMC_RGB666:
                        cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666;
-               else if (src_frame->fmt->color == S5P_FIMC_RGB888)
+                       break;
+               case S5P_FIMC_RGB888:
                        cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888;
+                       break;
+               }
        }
 
        if (ctx->out_path == FIMC_DMA) {
-               if (dst_frame->fmt->color == S5P_FIMC_RGB565)
+               u32 color = dst_frame->fmt->color;
+
+               if (color >= S5P_FIMC_RGB444 && color <= S5P_FIMC_RGB565)
                        cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565;
-               else if (dst_frame->fmt->color == S5P_FIMC_RGB666)
+               else if (color == S5P_FIMC_RGB666)
                        cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666;
-               else if (dst_frame->fmt->color == S5P_FIMC_RGB888)
+               else if (color == S5P_FIMC_RGB888)
                        cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
        } else {
                cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
@@ -379,6 +393,21 @@ void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active)
        writel(cfg, dev->regs + S5P_CIIMGEFF);
 }
 
+void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx)
+{
+       struct fimc_dev *dev = ctx->fimc_dev;
+       struct fimc_frame *frame = &ctx->d_frame;
+       u32 cfg;
+
+       if (!(frame->fmt->flags & FMT_HAS_ALPHA))
+               return;
+
+       cfg = readl(dev->regs + S5P_CIOCTRL);
+       cfg &= ~S5P_CIOCTRL_ALPHA_OUT_MASK;
+       cfg |= (frame->alpha << 4);
+       writel(cfg, dev->regs + S5P_CIOCTRL);
+}
+
 static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
 {
        struct fimc_dev *dev = ctx->fimc_dev;
index 59d79bc2f58a243c1de3cfa15b3af40b10c4cbaa..130335cf62fdc391fbb7862348b76832f6cbdbb3 100644 (file)
@@ -427,6 +427,23 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
        return 0;
 }
 
+static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+
+       format->colorspace = V4L2_COLORSPACE_JPEG;
+       format->code = s5pcsis_formats[0].code;
+       format->width = S5PCSIS_DEF_PIX_WIDTH;
+       format->height = S5PCSIS_DEF_PIX_HEIGHT;
+       format->field = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static const struct v4l2_subdev_internal_ops s5pcsis_sd_internal_ops = {
+       .open = s5pcsis_open,
+};
+
 static struct v4l2_subdev_core_ops s5pcsis_core_ops = {
        .s_power = s5pcsis_s_power,
 };
@@ -544,8 +561,13 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
        v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
        state->sd.owner = THIS_MODULE;
        strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name));
+       state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
        state->csis_fmt = &s5pcsis_formats[0];
 
+       state->format.code = s5pcsis_formats[0].code;
+       state->format.width = S5PCSIS_DEF_PIX_WIDTH;
+       state->format.height = S5PCSIS_DEF_PIX_HEIGHT;
+
        state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
        state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
        ret = media_entity_init(&state->sd.entity,
index f5691336dd5cb6b9dd3f6ed54540522dc7bae507..2709286396e1db8fa5ea963e8d802dd9571ee018 100644 (file)
@@ -19,4 +19,7 @@
 #define CSIS_PAD_SOURCE                1
 #define CSIS_PADS_NUM          2
 
+#define S5PCSIS_DEF_PIX_WIDTH  640
+#define S5PCSIS_DEF_PIX_HEIGHT 480
+
 #endif
index c8e3b94bd91d2ca7cf16c66886a33c9afbe1c290..c7a5bc51d571d860d6daee44a0076b99216d388f 100644 (file)
 #define S5P_CIOCTRL_YCBCR_3PLANE       (0 << 3)
 #define S5P_CIOCTRL_YCBCR_2PLANE       (1 << 3)
 #define S5P_CIOCTRL_YCBCR_PLANE_MASK   (1 << 3)
+#define S5P_CIOCTRL_ALPHA_OUT_MASK     (0xff << 4)
+#define S5P_CIOCTRL_RGB16FMT_MASK      (3 << 16)
+#define S5P_CIOCTRL_RGB565             (0 << 16)
+#define S5P_CIOCTRL_ARGB1555           (1 << 16)
+#define S5P_CIOCTRL_ARGB4444           (2 << 16)
 #define S5P_CIOCTRL_ORDER2P_SHIFT      (24)
 #define S5P_CIOCTRL_ORDER2P_MASK       (3 << 24)
 #define S5P_CIOCTRL_ORDER422_2P_LSB_CRCB (0 << 24)
diff --git a/drivers/media/video/s5p-g2d/Makefile b/drivers/media/video/s5p-g2d/Makefile
new file mode 100644 (file)
index 0000000..2c48c41
--- /dev/null
@@ -0,0 +1,3 @@
+s5p-g2d-objs := g2d.o g2d-hw.o
+
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D)    += s5p-g2d.o
diff --git a/drivers/media/video/s5p-g2d/g2d-hw.c b/drivers/media/video/s5p-g2d/g2d-hw.c
new file mode 100644 (file)
index 0000000..39937cf
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Samsung S5P G2D - 2D Graphics Accelerator Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.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/io.h>
+
+#include "g2d.h"
+#include "g2d-regs.h"
+
+#define w(x, a)        writel((x), d->regs + (a))
+#define r(a)   readl(d->regs + (a))
+
+/* g2d_reset clears all g2d registers */
+void g2d_reset(struct g2d_dev *d)
+{
+       w(1, SOFT_RESET_REG);
+}
+
+void g2d_set_src_size(struct g2d_dev *d, struct g2d_frame *f)
+{
+       u32 n;
+
+       w(f->stride & 0xFFFF, SRC_STRIDE_REG);
+
+       n = f->o_height & 0xFFF;
+       n <<= 16;
+       n |= f->o_width & 0xFFF;
+       w(n, SRC_LEFT_TOP_REG);
+
+       n = f->bottom & 0xFFF;
+       n <<= 16;
+       n |= f->right & 0xFFF;
+       w(n, SRC_RIGHT_BOTTOM_REG);
+
+       w(f->fmt->hw, SRC_COLOR_MODE_REG);
+}
+
+void g2d_set_src_addr(struct g2d_dev *d, dma_addr_t a)
+{
+       w(a, SRC_BASE_ADDR_REG);
+}
+
+void g2d_set_dst_size(struct g2d_dev *d, struct g2d_frame *f)
+{
+       u32 n;
+
+       w(f->stride & 0xFFFF, DST_STRIDE_REG);
+
+       n = f->o_height & 0xFFF;
+       n <<= 16;
+       n |= f->o_width & 0xFFF;
+       w(n, DST_LEFT_TOP_REG);
+
+       n = f->bottom & 0xFFF;
+       n <<= 16;
+       n |= f->right & 0xFFF;
+       w(n, DST_RIGHT_BOTTOM_REG);
+
+       w(f->fmt->hw, DST_COLOR_MODE_REG);
+}
+
+void g2d_set_dst_addr(struct g2d_dev *d, dma_addr_t a)
+{
+       w(a, DST_BASE_ADDR_REG);
+}
+
+void g2d_set_rop4(struct g2d_dev *d, u32 r)
+{
+       w(r, ROP4_REG);
+}
+
+u32 g2d_cmd_stretch(u32 e)
+{
+       e &= 1;
+       return e << 4;
+}
+
+void g2d_set_cmd(struct g2d_dev *d, u32 c)
+{
+       w(c, BITBLT_COMMAND_REG);
+}
+
+void g2d_start(struct g2d_dev *d)
+{
+       /* Clear cache */
+       w(0x7, CACHECTL_REG);
+       /* Enable interrupt */
+       w(1, INTEN_REG);
+       /* Start G2D engine */
+       w(1, BITBLT_START_REG);
+}
+
+void g2d_clear_int(struct g2d_dev *d)
+{
+       w(1, INTC_PEND_REG);
+}
diff --git a/drivers/media/video/s5p-g2d/g2d-regs.h b/drivers/media/video/s5p-g2d/g2d-regs.h
new file mode 100644 (file)
index 0000000..02e1cf5
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Samsung S5P G2D - 2D Graphics Accelerator Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.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
+ */
+
+/* General Registers */
+#define SOFT_RESET_REG         0x0000  /* Software reset reg */
+#define INTEN_REG              0x0004  /* Interrupt Enable reg */
+#define INTC_PEND_REG          0x000C  /* Interrupt Control Pending reg */
+#define FIFO_STAT_REG          0x0010  /* Command FIFO Status reg */
+#define AXI_ID_MODE_REG                0x0014  /* AXI Read ID Mode reg */
+#define CACHECTL_REG           0x0018  /* Cache & Buffer clear reg */
+#define AXI_MODE_REG           0x001C  /* AXI Mode reg */
+
+/* Command Registers */
+#define BITBLT_START_REG       0x0100  /* BitBLT Start reg */
+#define BITBLT_COMMAND_REG     0x0104  /* Command reg for BitBLT */
+
+/* Parameter Setting Registers (Rotate & Direction) */
+#define ROTATE_REG             0x0200  /* Rotation reg */
+#define SRC_MSK_DIRECT_REG     0x0204  /* Src and Mask Direction reg */
+#define DST_PAT_DIRECT_REG     0x0208  /* Dest and Pattern Direction reg */
+
+/* Parameter Setting Registers (Src) */
+#define SRC_SELECT_REG         0x0300  /* Src Image Selection reg */
+#define SRC_BASE_ADDR_REG      0x0304  /* Src Image Base Address reg */
+#define SRC_STRIDE_REG         0x0308  /* Src Stride reg */
+#define SRC_COLOR_MODE_REG     0x030C  /* Src Image Color Mode reg */
+#define SRC_LEFT_TOP_REG       0x0310  /* Src Left Top Coordinate reg */
+#define SRC_RIGHT_BOTTOM_REG   0x0314  /* Src Right Bottom Coordinate reg */
+
+/* Parameter Setting Registers (Dest) */
+#define DST_SELECT_REG         0x0400  /* Dest Image Selection reg */
+#define DST_BASE_ADDR_REG      0x0404  /* Dest Image Base Address reg */
+#define DST_STRIDE_REG         0x0408  /* Dest Stride reg */
+#define DST_COLOR_MODE_REG     0x040C  /* Dest Image Color Mode reg */
+#define DST_LEFT_TOP_REG       0x0410  /* Dest Left Top Coordinate reg */
+#define DST_RIGHT_BOTTOM_REG   0x0414  /* Dest Right Bottom Coordinate reg */
+
+/* Parameter Setting Registers (Pattern) */
+#define PAT_BASE_ADDR_REG      0x0500  /* Pattern Image Base Address reg */
+#define PAT_SIZE_REG           0x0504  /* Pattern Image Size reg */
+#define PAT_COLOR_MODE_REG     0x0508  /* Pattern Image Color Mode reg */
+#define PAT_OFFSET_REG         0x050C  /* Pattern Left Top Coordinate reg */
+#define PAT_STRIDE_REG         0x0510  /* Pattern Stride reg */
+
+/* Parameter Setting Registers (Mask) */
+#define MASK_BASE_ADDR_REG     0x0520  /* Mask Base Address reg */
+#define MASK_STRIDE_REG                0x0524  /* Mask Stride reg */
+
+/* Parameter Setting Registers (Clipping Window) */
+#define CW_LT_REG              0x0600  /* LeftTop coordinates of Clip Window */
+#define CW_RB_REG              0x0604  /* RightBottom coordinates of Clip
+                                                               Window */
+
+/* Parameter Setting Registers (ROP & Alpha Setting) */
+#define THIRD_OPERAND_REG      0x0610  /* Third Operand Selection reg */
+#define ROP4_REG               0x0614  /* Raster Operation reg */
+#define ALPHA_REG              0x0618  /* Alpha value, Fading offset value */
+
+/* Parameter Setting Registers (Color) */
+#define FG_COLOR_REG           0x0700  /* Foreground Color reg */
+#define BG_COLOR_REG           0x0704  /* Background Color reg */
+#define BS_COLOR_REG           0x0708  /* Blue Screen Color reg */
+
+/* Parameter Setting Registers (Color Key) */
+#define SRC_COLORKEY_CTRL_REG  0x0710  /* Src Colorkey control reg */
+#define SRC_COLORKEY_DR_MIN_REG        0x0714  /* Src Colorkey Decision Reference
+                                                               Min reg */
+#define SRC_COLORKEY_DR_MAX_REG        0x0718  /* Src Colorkey Decision Reference
+                                                               Max reg */
+#define DST_COLORKEY_CTRL_REG  0x071C  /* Dest Colorkey control reg */
+#define DST_COLORKEY_DR_MIN_REG        0x0720  /* Dest Colorkey Decision Reference
+                                                               Min reg */
+#define DST_COLORKEY_DR_MAX_REG        0x0724  /* Dest Colorkey Decision Reference
+                                                               Max reg */
+
+/* Color mode values */
+
+#define ORDER_XRGB             0
+#define ORDER_RGBX             1
+#define ORDER_XBGR             2
+#define ORDER_BGRX             3
+
+#define MODE_XRGB_8888         0
+#define MODE_ARGB_8888         1
+#define MODE_RGB_565           2
+#define MODE_XRGB_1555         3
+#define MODE_ARGB_1555         4
+#define MODE_XRGB_4444         5
+#define MODE_ARGB_4444         6
+#define MODE_PACKED_RGB_888    7
+
+#define COLOR_MODE(o, m)       (((o) << 4) | (m))
+
+/* ROP4 operation values */
+#define ROP4_COPY              0xCCCC
+#define ROP4_INVERT            0x3333
+
+/* Hardware limits */
+#define MAX_WIDTH              8000
+#define MAX_HEIGHT             8000
+
+#define G2D_TIMEOUT            500
+
+#define DEFAULT_WIDTH          100
+#define DEFAULT_HEIGHT         100
+
diff --git a/drivers/media/video/s5p-g2d/g2d.c b/drivers/media/video/s5p-g2d/g2d.c
new file mode 100644 (file)
index 0000000..febaa67
--- /dev/null
@@ -0,0 +1,811 @@
+/*
+ * Samsung S5P G2D - 2D Graphics Accelerator Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.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/fs.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "g2d.h"
+#include "g2d-regs.h"
+
+#define fh2ctx(__fh) container_of(__fh, struct g2d_ctx, fh)
+
+static struct g2d_fmt formats[] = {
+       {
+               .name   = "XRGB_8888",
+               .fourcc = V4L2_PIX_FMT_RGB32,
+               .depth  = 32,
+               .hw     = COLOR_MODE(ORDER_XRGB, MODE_XRGB_8888),
+       },
+       {
+               .name   = "RGB_565",
+               .fourcc = V4L2_PIX_FMT_RGB565X,
+               .depth  = 16,
+               .hw     = COLOR_MODE(ORDER_XRGB, MODE_RGB_565),
+       },
+       {
+               .name   = "XRGB_1555",
+               .fourcc = V4L2_PIX_FMT_RGB555X,
+               .depth  = 16,
+               .hw     = COLOR_MODE(ORDER_XRGB, MODE_XRGB_1555),
+       },
+       {
+               .name   = "XRGB_4444",
+               .fourcc = V4L2_PIX_FMT_RGB444,
+               .depth  = 16,
+               .hw     = COLOR_MODE(ORDER_XRGB, MODE_XRGB_4444),
+       },
+       {
+               .name   = "PACKED_RGB_888",
+               .fourcc = V4L2_PIX_FMT_RGB24,
+               .depth  = 24,
+               .hw     = COLOR_MODE(ORDER_XRGB, MODE_PACKED_RGB_888),
+       },
+};
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+struct g2d_frame def_frame = {
+       .width          = DEFAULT_WIDTH,
+       .height         = DEFAULT_HEIGHT,
+       .c_width        = DEFAULT_WIDTH,
+       .c_height       = DEFAULT_HEIGHT,
+       .o_width        = 0,
+       .o_height       = 0,
+       .fmt            = &formats[0],
+       .right          = DEFAULT_WIDTH,
+       .bottom         = DEFAULT_HEIGHT,
+};
+
+struct g2d_fmt *find_fmt(struct v4l2_format *f)
+{
+       unsigned int i;
+       for (i = 0; i < NUM_FORMATS; i++) {
+               if (formats[i].fourcc == f->fmt.pix.pixelformat)
+                       return &formats[i];
+       }
+       return NULL;
+}
+
+
+static struct g2d_frame *get_frame(struct g2d_ctx *ctx,
+                                                       enum v4l2_buf_type type)
+{
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               return &ctx->in;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return &ctx->out;
+       default:
+               return ERR_PTR(-EINVAL);
+       }
+}
+
+static int g2d_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                          unsigned int *nbuffers, unsigned int *nplanes,
+                          unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct g2d_ctx *ctx = vb2_get_drv_priv(vq);
+       struct g2d_frame *f = get_frame(ctx, vq->type);
+
+       if (IS_ERR(f))
+               return PTR_ERR(f);
+
+       sizes[0] = f->size;
+       *nplanes = 1;
+       alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+       if (*nbuffers == 0)
+               *nbuffers = 1;
+
+       return 0;
+}
+
+static int g2d_buf_prepare(struct vb2_buffer *vb)
+{
+       struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct g2d_frame *f = get_frame(ctx, vb->vb2_queue->type);
+
+       if (IS_ERR(f))
+               return PTR_ERR(f);
+       vb2_set_plane_payload(vb, 0, f->size);
+       return 0;
+}
+
+static void g2d_buf_queue(struct vb2_buffer *vb)
+{
+       struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+
+static struct vb2_ops g2d_qops = {
+       .queue_setup    = g2d_queue_setup,
+       .buf_prepare    = g2d_buf_prepare,
+       .buf_queue      = g2d_buf_queue,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+                                               struct vb2_queue *dst_vq)
+{
+       struct g2d_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->ops = &g2d_qops;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+       src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+       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->ops = &g2d_qops;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+       return vb2_queue_init(dst_vq);
+}
+
+static int g2d_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx,
+                                                               ctrl_handler);
+       switch (ctrl->id) {
+       case V4L2_CID_COLORFX:
+               if (ctrl->val == V4L2_COLORFX_NEGATIVE)
+                       ctx->rop = ROP4_INVERT;
+               else
+                       ctx->rop = ROP4_COPY;
+               break;
+       default:
+               v4l2_err(&ctx->dev->v4l2_dev, "unknown control\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops g2d_ctrl_ops = {
+       .s_ctrl         = g2d_s_ctrl,
+};
+
+int g2d_setup_ctrls(struct g2d_ctx *ctx)
+{
+       struct g2d_dev *dev = ctx->dev;
+
+       v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1);
+       if (ctx->ctrl_handler.error) {
+               v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n");
+               return ctx->ctrl_handler.error;
+       }
+
+       v4l2_ctrl_new_std_menu(
+               &ctx->ctrl_handler,
+               &g2d_ctrl_ops,
+               V4L2_CID_COLORFX,
+               V4L2_COLORFX_NEGATIVE,
+               ~((1 << V4L2_COLORFX_NONE) | (1 << V4L2_COLORFX_NEGATIVE)),
+               V4L2_COLORFX_NONE);
+
+       if (ctx->ctrl_handler.error) {
+               v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n");
+               return ctx->ctrl_handler.error;
+       }
+
+       return 0;
+}
+
+static int g2d_open(struct file *file)
+{
+       struct g2d_dev *dev = video_drvdata(file);
+       struct g2d_ctx *ctx = NULL;
+       int ret = 0;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+       ctx->dev = dev;
+       /* Set default formats */
+       ctx->in         = def_frame;
+       ctx->out        = def_frame;
+
+       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);
+               kfree(ctx);
+               return ret;
+       }
+       v4l2_fh_init(&ctx->fh, video_devdata(file));
+       file->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+
+       g2d_setup_ctrls(ctx);
+
+       /* Write the default values to the ctx struct */
+       v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+
+       ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+
+       v4l2_info(&dev->v4l2_dev, "instance opened\n");
+       return 0;
+}
+
+static int g2d_release(struct file *file)
+{
+       struct g2d_dev *dev = video_drvdata(file);
+       struct g2d_ctx *ctx = fh2ctx(file->private_data);
+
+       v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+       v4l2_info(&dev->v4l2_dev, "instance closed\n");
+       return 0;
+}
+
+
+static int vidioc_querycap(struct file *file, void *priv,
+                               struct v4l2_capability *cap)
+{
+       strncpy(cap->driver, G2D_NAME, sizeof(cap->driver) - 1);
+       strncpy(cap->card, G2D_NAME, sizeof(cap->card) - 1);
+       cap->bus_info[0] = 0;
+       cap->version = KERNEL_VERSION(1, 0, 0);
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+                                                       | V4L2_CAP_STREAMING;
+       return 0;
+}
+
+static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f)
+{
+       struct g2d_fmt *fmt;
+       if (f->index >= NUM_FORMATS)
+               return -EINVAL;
+       fmt = &formats[f->index];
+       f->pixelformat = fmt->fourcc;
+       strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+       return 0;
+}
+
+static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+       struct g2d_ctx *ctx = prv;
+       struct vb2_queue *vq;
+       struct g2d_frame *frm;
+
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+       frm = get_frame(ctx, f->type);
+       if (IS_ERR(frm))
+               return PTR_ERR(frm);
+
+       f->fmt.pix.width                = frm->width;
+       f->fmt.pix.height               = frm->height;
+       f->fmt.pix.field                = V4L2_FIELD_NONE;
+       f->fmt.pix.pixelformat          = frm->fmt->fourcc;
+       f->fmt.pix.bytesperline         = (frm->width * frm->fmt->depth) >> 3;
+       f->fmt.pix.sizeimage            = frm->size;
+       return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+       struct g2d_fmt *fmt;
+       enum v4l2_field *field;
+
+       fmt = find_fmt(f);
+       if (!fmt)
+               return -EINVAL;
+
+       field = &f->fmt.pix.field;
+       if (*field == V4L2_FIELD_ANY)
+               *field = V4L2_FIELD_NONE;
+       else if (*field != V4L2_FIELD_NONE)
+               return -EINVAL;
+
+       if (f->fmt.pix.width > MAX_WIDTH)
+               f->fmt.pix.width = MAX_WIDTH;
+       if (f->fmt.pix.height > MAX_HEIGHT)
+               f->fmt.pix.height = MAX_HEIGHT;
+
+       if (f->fmt.pix.width < 1)
+               f->fmt.pix.width = 1;
+       if (f->fmt.pix.height < 1)
+               f->fmt.pix.height = 1;
+
+       f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+       f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+       return 0;
+}
+
+static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+       struct g2d_ctx *ctx = prv;
+       struct g2d_dev *dev = ctx->dev;
+       struct vb2_queue *vq;
+       struct g2d_frame *frm;
+       struct g2d_fmt *fmt;
+       int ret = 0;
+
+       /* Adjust all values accordingly to the hardware capabilities
+        * and chosen format. */
+       ret = vidioc_try_fmt(file, prv, f);
+       if (ret)
+               return ret;
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (vb2_is_busy(vq)) {
+               v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type);
+               return -EBUSY;
+       }
+       frm = get_frame(ctx, f->type);
+       if (IS_ERR(frm))
+               return PTR_ERR(frm);
+       fmt = find_fmt(f);
+       if (!fmt)
+               return -EINVAL;
+       frm->width      = f->fmt.pix.width;
+       frm->height     = f->fmt.pix.height;
+       frm->size       = f->fmt.pix.sizeimage;
+       /* Reset crop settings */
+       frm->o_width    = 0;
+       frm->o_height   = 0;
+       frm->c_width    = frm->width;
+       frm->c_height   = frm->height;
+       frm->right      = frm->width;
+       frm->bottom     = frm->height;
+       frm->fmt        = fmt;
+       frm->stride     = f->fmt.pix.bytesperline;
+       return 0;
+}
+
+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);
+}
+
+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);
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+                       struct v4l2_requestbuffers *reqbufs)
+{
+       struct g2d_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 g2d_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 g2d_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 g2d_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 g2d_ctx *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 g2d_ctx *ctx = priv;
+       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_cropcap(struct file *file, void *priv,
+                                       struct v4l2_cropcap *cr)
+{
+       struct g2d_ctx *ctx = priv;
+       struct g2d_frame *f;
+
+       f = get_frame(ctx, cr->type);
+       if (IS_ERR(f))
+               return PTR_ERR(f);
+
+       cr->bounds.left         = 0;
+       cr->bounds.top          = 0;
+       cr->bounds.width        = f->width;
+       cr->bounds.height       = f->height;
+       cr->defrect             = cr->bounds;
+       return 0;
+}
+
+static int vidioc_g_crop(struct file *file, void *prv, struct v4l2_crop *cr)
+{
+       struct g2d_ctx *ctx = prv;
+       struct g2d_frame *f;
+
+       f = get_frame(ctx, cr->type);
+       if (IS_ERR(f))
+               return PTR_ERR(f);
+
+       cr->c.left      = f->o_height;
+       cr->c.top       = f->o_width;
+       cr->c.width     = f->c_width;
+       cr->c.height    = f->c_height;
+       return 0;
+}
+
+static int vidioc_try_crop(struct file *file, void *prv, struct v4l2_crop *cr)
+{
+       struct g2d_ctx *ctx = prv;
+       struct g2d_dev *dev = ctx->dev;
+       struct g2d_frame *f;
+
+       f = get_frame(ctx, cr->type);
+       if (IS_ERR(f))
+               return PTR_ERR(f);
+
+       if (cr->c.top < 0 || cr->c.left < 0) {
+               v4l2_err(&dev->v4l2_dev,
+                       "doesn't support negative values for top & left\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vidioc_s_crop(struct file *file, void *prv, struct v4l2_crop *cr)
+{
+       struct g2d_ctx *ctx = prv;
+       struct g2d_frame *f;
+       int ret;
+
+       ret = vidioc_try_crop(file, prv, cr);
+       if (ret)
+               return ret;
+       f = get_frame(ctx, cr->type);
+       if (IS_ERR(f))
+               return PTR_ERR(f);
+
+       f->c_width      = cr->c.width;
+       f->c_height     = cr->c.height;
+       f->o_width      = cr->c.left;
+       f->o_height     = cr->c.top;
+       f->bottom       = f->o_height + f->c_height;
+       f->right        = f->o_width + f->c_width;
+       return 0;
+}
+
+static void g2d_lock(void *prv)
+{
+       struct g2d_ctx *ctx = prv;
+       struct g2d_dev *dev = ctx->dev;
+       mutex_lock(&dev->mutex);
+}
+
+static void g2d_unlock(void *prv)
+{
+       struct g2d_ctx *ctx = prv;
+       struct g2d_dev *dev = ctx->dev;
+       mutex_unlock(&dev->mutex);
+}
+
+static void job_abort(void *prv)
+{
+       struct g2d_ctx *ctx = prv;
+       struct g2d_dev *dev = ctx->dev;
+       int ret;
+
+       if (dev->curr == 0) /* No job currently running */
+               return;
+
+       ret = wait_event_timeout(dev->irq_queue,
+               dev->curr == 0,
+               msecs_to_jiffies(G2D_TIMEOUT));
+}
+
+static void device_run(void *prv)
+{
+       struct g2d_ctx *ctx = prv;
+       struct g2d_dev *dev = ctx->dev;
+       struct vb2_buffer *src, *dst;
+       u32 cmd = 0;
+
+       dev->curr = ctx;
+
+       src = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+       dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+       clk_enable(dev->gate);
+       g2d_reset(dev);
+
+       g2d_set_src_size(dev, &ctx->in);
+       g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0));
+
+       g2d_set_dst_size(dev, &ctx->out);
+       g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0));
+
+       g2d_set_rop4(dev, ctx->rop);
+       if (ctx->in.c_width != ctx->out.c_width ||
+               ctx->in.c_height != ctx->out.c_height)
+               cmd |= g2d_cmd_stretch(1);
+       g2d_set_cmd(dev, cmd);
+       g2d_start(dev);
+}
+
+static irqreturn_t g2d_isr(int irq, void *prv)
+{
+       struct g2d_dev *dev = prv;
+       struct g2d_ctx *ctx = dev->curr;
+       struct vb2_buffer *src, *dst;
+
+       g2d_clear_int(dev);
+       clk_disable(dev->gate);
+
+       BUG_ON(ctx == 0);
+
+       src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+       dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+       BUG_ON(src == 0);
+       BUG_ON(dst == 0);
+
+       v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
+       v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
+       v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
+
+       dev->curr = 0;
+       wake_up(&dev->irq_queue);
+       return IRQ_HANDLED;
+}
+
+static const struct v4l2_file_operations g2d_fops = {
+       .owner          = THIS_MODULE,
+       .open           = g2d_open,
+       .release        = g2d_release,
+       .poll           = g2d_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = g2d_mmap,
+};
+
+static const struct v4l2_ioctl_ops g2d_ioctl_ops = {
+       .vidioc_querycap        = vidioc_querycap,
+
+       .vidioc_enum_fmt_vid_cap        = vidioc_enum_fmt,
+       .vidioc_g_fmt_vid_cap           = vidioc_g_fmt,
+       .vidioc_try_fmt_vid_cap         = vidioc_try_fmt,
+       .vidioc_s_fmt_vid_cap           = vidioc_s_fmt,
+
+       .vidioc_enum_fmt_vid_out        = vidioc_enum_fmt,
+       .vidioc_g_fmt_vid_out           = vidioc_g_fmt,
+       .vidioc_try_fmt_vid_out         = vidioc_try_fmt,
+       .vidioc_s_fmt_vid_out           = vidioc_s_fmt,
+
+       .vidioc_reqbufs                 = vidioc_reqbufs,
+       .vidioc_querybuf                = vidioc_querybuf,
+
+       .vidioc_qbuf                    = vidioc_qbuf,
+       .vidioc_dqbuf                   = vidioc_dqbuf,
+
+       .vidioc_streamon                = vidioc_streamon,
+       .vidioc_streamoff               = vidioc_streamoff,
+
+       .vidioc_g_crop                  = vidioc_g_crop,
+       .vidioc_s_crop                  = vidioc_s_crop,
+       .vidioc_cropcap                 = vidioc_cropcap,
+};
+
+static struct video_device g2d_videodev = {
+       .name           = G2D_NAME,
+       .fops           = &g2d_fops,
+       .ioctl_ops      = &g2d_ioctl_ops,
+       .minor          = -1,
+       .release        = video_device_release,
+};
+
+static struct v4l2_m2m_ops g2d_m2m_ops = {
+       .device_run     = device_run,
+       .job_abort      = job_abort,
+       .lock           = g2d_lock,
+       .unlock         = g2d_unlock,
+};
+
+static int g2d_probe(struct platform_device *pdev)
+{
+       struct g2d_dev *dev;
+       struct video_device *vfd;
+       struct resource *res;
+       int ret = 0;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+       spin_lock_init(&dev->irqlock);
+       mutex_init(&dev->mutex);
+       atomic_set(&dev->num_inst, 0);
+       init_waitqueue_head(&dev->irq_queue);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to find registers\n");
+               ret = -ENOENT;
+               goto free_dev;
+       }
+
+       dev->res_regs = request_mem_region(res->start, resource_size(res),
+                                               dev_name(&pdev->dev));
+
+       if (!dev->res_regs) {
+               dev_err(&pdev->dev, "failed to obtain register region\n");
+               ret = -ENOENT;
+               goto free_dev;
+       }
+
+       dev->regs = ioremap(res->start, resource_size(res));
+       if (!dev->regs) {
+               dev_err(&pdev->dev, "failed to map registers\n");
+               ret = -ENOENT;
+               goto rel_res_regs;
+       }
+
+       dev->clk = clk_get(&pdev->dev, "sclk_fimg2d");
+       if (IS_ERR_OR_NULL(dev->clk)) {
+               dev_err(&pdev->dev, "failed to get g2d clock\n");
+               ret = -ENXIO;
+               goto unmap_regs;
+       }
+
+       dev->gate = clk_get(&pdev->dev, "fimg2d");
+       if (IS_ERR_OR_NULL(dev->gate)) {
+               dev_err(&pdev->dev, "failed to get g2d clock gate\n");
+               ret = -ENXIO;
+               goto put_clk;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to find IRQ\n");
+               ret = -ENXIO;
+               goto put_clk_gate;
+       }
+
+       dev->irq = res->start;
+
+       ret = request_irq(dev->irq, g2d_isr, 0, pdev->name, dev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to install IRQ\n");
+               goto put_clk_gate;
+       }
+
+       dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(dev->alloc_ctx)) {
+               ret = PTR_ERR(dev->alloc_ctx);
+               goto rel_irq;
+       }
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret)
+               goto alloc_ctx_cleanup;
+       vfd = video_device_alloc();
+       if (!vfd) {
+               v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+               ret = -ENOMEM;
+               goto unreg_v4l2_dev;
+       }
+       *vfd = g2d_videodev;
+       vfd->lock = &dev->mutex;
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+               goto rel_vdev;
+       }
+       video_set_drvdata(vfd, dev);
+       snprintf(vfd->name, sizeof(vfd->name), "%s", g2d_videodev.name);
+       dev->vfd = vfd;
+       v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n",
+                                                               vfd->num);
+       platform_set_drvdata(pdev, dev);
+       dev->m2m_dev = v4l2_m2m_init(&g2d_m2m_ops);
+       if (IS_ERR(dev->m2m_dev)) {
+               v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+               ret = PTR_ERR(dev->m2m_dev);
+               goto unreg_video_dev;
+       }
+
+       def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
+
+       return 0;
+
+unreg_video_dev:
+       video_unregister_device(dev->vfd);
+rel_vdev:
+       video_device_release(vfd);
+unreg_v4l2_dev:
+       v4l2_device_unregister(&dev->v4l2_dev);
+alloc_ctx_cleanup:
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+rel_irq:
+       free_irq(dev->irq, dev);
+put_clk_gate:
+       clk_put(dev->gate);
+put_clk:
+       clk_put(dev->clk);
+unmap_regs:
+       iounmap(dev->regs);
+rel_res_regs:
+       release_resource(dev->res_regs);
+free_dev:
+       kfree(dev);
+       return ret;
+}
+
+static int g2d_remove(struct platform_device *pdev)
+{
+       struct g2d_dev *dev = (struct g2d_dev *)platform_get_drvdata(pdev);
+
+       v4l2_info(&dev->v4l2_dev, "Removing " G2D_NAME);
+       v4l2_m2m_release(dev->m2m_dev);
+       video_unregister_device(dev->vfd);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+       free_irq(dev->irq, dev);
+       clk_put(dev->gate);
+       clk_put(dev->clk);
+       iounmap(dev->regs);
+       release_resource(dev->res_regs);
+       kfree(dev);
+       return 0;
+}
+
+static struct platform_driver g2d_pdrv = {
+       .probe          = g2d_probe,
+       .remove         = g2d_remove,
+       .driver         = {
+               .name = G2D_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+module_platform_driver(g2d_pdrv);
+
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+MODULE_DESCRIPTION("S5P G2D 2d graphics accelerator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/s5p-g2d/g2d.h b/drivers/media/video/s5p-g2d/g2d.h
new file mode 100644 (file)
index 0000000..5eae901
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Samsung S5P G2D - 2D Graphics Accelerator Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.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 <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define G2D_NAME "s5p-g2d"
+
+struct g2d_dev {
+       struct v4l2_device      v4l2_dev;
+       struct v4l2_m2m_dev     *m2m_dev;
+       struct video_device     *vfd;
+       struct mutex            mutex;
+       spinlock_t              irqlock;
+       atomic_t                num_inst;
+       struct vb2_alloc_ctx    *alloc_ctx;
+       struct resource         *res_regs;
+       void __iomem            *regs;
+       struct clk              *clk;
+       struct clk              *gate;
+       struct g2d_ctx          *curr;
+       int irq;
+       wait_queue_head_t       irq_queue;
+};
+
+struct g2d_frame {
+       /* Original dimensions */
+       u32     width;
+       u32     height;
+       /* Crop size */
+       u32     c_width;
+       u32     c_height;
+       /* Offset */
+       u32     o_width;
+       u32     o_height;
+       /* Image format */
+       struct g2d_fmt *fmt;
+       /* Variables that can calculated once and reused */
+       u32     stride;
+       u32     bottom;
+       u32     right;
+       u32     size;
+};
+
+struct g2d_ctx {
+       struct v4l2_fh fh;
+       struct g2d_dev          *dev;
+       struct v4l2_m2m_ctx     *m2m_ctx;
+       struct g2d_frame        in;
+       struct g2d_frame        out;
+       struct v4l2_ctrl_handler ctrl_handler;
+       u32 rop;
+};
+
+struct g2d_fmt {
+       char    *name;
+       u32     fourcc;
+       int     depth;
+       u32     hw;
+};
+
+
+void g2d_reset(struct g2d_dev *d);
+void g2d_set_src_size(struct g2d_dev *d, struct g2d_frame *f);
+void g2d_set_src_addr(struct g2d_dev *d, dma_addr_t a);
+void g2d_set_dst_size(struct g2d_dev *d, struct g2d_frame *f);
+void g2d_set_dst_addr(struct g2d_dev *d, dma_addr_t a);
+void g2d_start(struct g2d_dev *d);
+void g2d_clear_int(struct g2d_dev *d);
+void g2d_set_rop4(struct g2d_dev *d, u32 r);
+u32 g2d_cmd_stretch(u32 e);
+void g2d_set_cmd(struct g2d_dev *d, u32 c);
+
+
diff --git a/drivers/media/video/s5p-jpeg/Makefile b/drivers/media/video/s5p-jpeg/Makefile
new file mode 100644 (file)
index 0000000..ddc2900
--- /dev/null
@@ -0,0 +1,2 @@
+s5p-jpeg-objs := jpeg-core.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) := s5p-jpeg.o
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c
new file mode 100644 (file)
index 0000000..1105a87
--- /dev/null
@@ -0,0 +1,1482 @@
+/* linux/drivers/media/video/s5p-jpeg/jpeg-core.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gfp.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "jpeg-core.h"
+#include "jpeg-hw.h"
+
+static struct s5p_jpeg_fmt formats_enc[] = {
+       {
+               .name           = "YUV 4:2:0 planar, YCbCr",
+               .fourcc         = V4L2_PIX_FMT_YUV420,
+               .depth          = 12,
+               .colplanes      = 3,
+               .types          = MEM2MEM_CAPTURE,
+       },
+       {
+               .name           = "YUV 4:2:2 packed, YCbYCr",
+               .fourcc         = V4L2_PIX_FMT_YUYV,
+               .depth          = 16,
+               .colplanes      = 1,
+               .types          = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+       },
+       {
+               .name           = "RGB565",
+               .fourcc         = V4L2_PIX_FMT_RGB565,
+               .depth          = 16,
+               .colplanes      = 1,
+               .types          = MEM2MEM_OUTPUT,
+       },
+};
+#define NUM_FORMATS_ENC ARRAY_SIZE(formats_enc)
+
+static struct s5p_jpeg_fmt formats_dec[] = {
+       {
+               .name           = "YUV 4:2:0 planar, YCbCr",
+               .fourcc         = V4L2_PIX_FMT_YUV420,
+               .depth          = 12,
+               .colplanes      = 3,
+               .h_align        = 4,
+               .v_align        = 4,
+               .types          = MEM2MEM_CAPTURE,
+       },
+       {
+               .name           = "YUV 4:2:2 packed, YCbYCr",
+               .fourcc         = V4L2_PIX_FMT_YUYV,
+               .depth          = 16,
+               .colplanes      = 1,
+               .h_align        = 4,
+               .v_align        = 3,
+               .types          = MEM2MEM_CAPTURE,
+       },
+       {
+               .name           = "JPEG JFIF",
+               .fourcc         = V4L2_PIX_FMT_JPEG,
+               .colplanes      = 1,
+               .types          = MEM2MEM_OUTPUT,
+       },
+};
+#define NUM_FORMATS_DEC ARRAY_SIZE(formats_dec)
+
+static const unsigned char qtbl_luminance[4][64] = {
+       {/* level 1 - high quality */
+                8,  6,  6,  8, 12, 14, 16, 17,
+                6,  6,  6,  8, 10, 13, 12, 15,
+                6,  6,  7,  8, 13, 14, 18, 24,
+                8,  8,  8, 14, 13, 19, 24, 35,
+               12, 10, 13, 13, 20, 26, 34, 39,
+               14, 13, 14, 19, 26, 34, 39, 39,
+               16, 12, 18, 24, 34, 39, 39, 39,
+               17, 15, 24, 35, 39, 39, 39, 39
+       },
+       {/* level 2 */
+               12,  8,  8, 12, 17, 21, 24, 23,
+                8,  9,  9, 11, 15, 19, 18, 23,
+                8,  9, 10, 12, 19, 20, 27, 36,
+               12, 11, 12, 21, 20, 28, 36, 53,
+               17, 15, 19, 20, 30, 39, 51, 59,
+               21, 19, 20, 28, 39, 51, 59, 59,
+               24, 18, 27, 36, 51, 59, 59, 59,
+               23, 23, 36, 53, 59, 59, 59, 59
+       },
+       {/* level 3 */
+               16, 11, 11, 16, 23, 27, 31, 30,
+               11, 12, 12, 15, 20, 23, 23, 30,
+               11, 12, 13, 16, 23, 26, 35, 47,
+               16, 15, 16, 23, 26, 37, 47, 64,
+               23, 20, 23, 26, 39, 51, 64, 64,
+               27, 23, 26, 37, 51, 64, 64, 64,
+               31, 23, 35, 47, 64, 64, 64, 64,
+               30, 30, 47, 64, 64, 64, 64, 64
+       },
+       {/*level 4 - low quality */
+               20, 16, 25, 39, 50, 46, 62, 68,
+               16, 18, 23, 38, 38, 53, 65, 68,
+               25, 23, 31, 38, 53, 65, 68, 68,
+               39, 38, 38, 53, 65, 68, 68, 68,
+               50, 38, 53, 65, 68, 68, 68, 68,
+               46, 53, 65, 68, 68, 68, 68, 68,
+               62, 65, 68, 68, 68, 68, 68, 68,
+               68, 68, 68, 68, 68, 68, 68, 68
+       }
+};
+
+static const unsigned char qtbl_chrominance[4][64] = {
+       {/* level 1 - high quality */
+                9,  8,  9, 11, 14, 17, 19, 24,
+                8, 10,  9, 11, 14, 13, 17, 22,
+                9,  9, 13, 14, 13, 15, 23, 26,
+               11, 11, 14, 14, 15, 20, 26, 33,
+               14, 14, 13, 15, 20, 24, 33, 39,
+               17, 13, 15, 20, 24, 32, 39, 39,
+               19, 17, 23, 26, 33, 39, 39, 39,
+               24, 22, 26, 33, 39, 39, 39, 39
+       },
+       {/* level 2 */
+               13, 11, 13, 16, 20, 20, 29, 37,
+               11, 14, 14, 14, 16, 20, 26, 32,
+               13, 14, 15, 17, 20, 23, 35, 40,
+               16, 14, 17, 21, 23, 30, 40, 50,
+               20, 16, 20, 23, 30, 37, 50, 59,
+               20, 20, 23, 30, 37, 48, 59, 59,
+               29, 26, 35, 40, 50, 59, 59, 59,
+               37, 32, 40, 50, 59, 59, 59, 59
+       },
+       {/* level 3 */
+               17, 15, 17, 21, 20, 26, 38, 48,
+               15, 19, 18, 17, 20, 26, 35, 43,
+               17, 18, 20, 22, 26, 30, 46, 53,
+               21, 17, 22, 28, 30, 39, 53, 64,
+               20, 20, 26, 30, 39, 48, 64, 64,
+               26, 26, 30, 39, 48, 63, 64, 64,
+               38, 35, 46, 53, 64, 64, 64, 64,
+               48, 43, 53, 64, 64, 64, 64, 64
+       },
+       {/*level 4 - low quality */
+               21, 25, 32, 38, 54, 68, 68, 68,
+               25, 28, 24, 38, 54, 68, 68, 68,
+               32, 24, 32, 43, 66, 68, 68, 68,
+               38, 38, 43, 53, 68, 68, 68, 68,
+               54, 54, 66, 68, 68, 68, 68, 68,
+               68, 68, 68, 68, 68, 68, 68, 68,
+               68, 68, 68, 68, 68, 68, 68, 68,
+               68, 68, 68, 68, 68, 68, 68, 68
+       }
+};
+
+static const unsigned char hdctbl0[16] = {
+       0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const unsigned char hdctblg0[12] = {
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb
+};
+static const unsigned char hactbl0[16] = {
+       0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
+};
+static const unsigned char hactblg0[162] = {
+       0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+       0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+       0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+       0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+       0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+       0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+       0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+       0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+       0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+       0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+       0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+       0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+       0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+       0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+       0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+       0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+       0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+       0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+       0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+       0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+       0xf9, 0xfa
+};
+
+static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl,
+                  unsigned long tab, int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
+}
+
+static inline void jpeg_set_qtbl_lum(void __iomem *regs, int quality)
+{
+       /* this driver fills quantisation table 0 with data for luma */
+       jpeg_set_qtbl(regs, qtbl_luminance[quality], S5P_JPG_QTBL_CONTENT(0),
+                     ARRAY_SIZE(qtbl_luminance[quality]));
+}
+
+static inline void jpeg_set_qtbl_chr(void __iomem *regs, int quality)
+{
+       /* this driver fills quantisation table 1 with data for chroma */
+       jpeg_set_qtbl(regs, qtbl_chrominance[quality], S5P_JPG_QTBL_CONTENT(1),
+                     ARRAY_SIZE(qtbl_chrominance[quality]));
+}
+
+static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl,
+                  unsigned long tab, int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
+}
+
+static inline void jpeg_set_hdctbl(void __iomem *regs)
+{
+       /* this driver fills table 0 for this component */
+       jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), ARRAY_SIZE(hdctbl0));
+}
+
+static inline void jpeg_set_hdctblg(void __iomem *regs)
+{
+       /* this driver fills table 0 for this component */
+       jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), ARRAY_SIZE(hdctblg0));
+}
+
+static inline void jpeg_set_hactbl(void __iomem *regs)
+{
+       /* this driver fills table 0 for this component */
+       jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), ARRAY_SIZE(hactbl0));
+}
+
+static inline void jpeg_set_hactblg(void __iomem *regs)
+{
+       /* this driver fills table 0 for this component */
+       jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), ARRAY_SIZE(hactblg0));
+}
+
+/*
+ * ============================================================================
+ * Device file operations
+ * ============================================================================
+ */
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+                     struct vb2_queue *dst_vq);
+static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
+                                                __u32 pixelformat);
+
+static int s5p_jpeg_open(struct file *file)
+{
+       struct s5p_jpeg *jpeg = video_drvdata(file);
+       struct video_device *vfd = video_devdata(file);
+       struct s5p_jpeg_ctx *ctx;
+       struct s5p_jpeg_fmt *out_fmt;
+
+       ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       file->private_data = ctx;
+       ctx->jpeg = jpeg;
+       if (vfd == jpeg->vfd_encoder) {
+               ctx->mode = S5P_JPEG_ENCODE;
+               out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_RGB565);
+       } else {
+               ctx->mode = S5P_JPEG_DECODE;
+               out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG);
+       }
+
+       ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
+       if (IS_ERR(ctx->m2m_ctx)) {
+               int err = PTR_ERR(ctx->m2m_ctx);
+               kfree(ctx);
+               return err;
+       }
+
+       ctx->out_q.fmt = out_fmt;
+       ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV);
+
+       return 0;
+}
+
+static int s5p_jpeg_release(struct file *file)
+{
+       struct s5p_jpeg_ctx *ctx = file->private_data;
+
+       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       kfree(ctx);
+
+       return 0;
+}
+
+static unsigned int s5p_jpeg_poll(struct file *file,
+                                struct poll_table_struct *wait)
+{
+       struct s5p_jpeg_ctx *ctx = file->private_data;
+
+       return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct s5p_jpeg_ctx *ctx = file->private_data;
+
+       return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations s5p_jpeg_fops = {
+       .owner          = THIS_MODULE,
+       .open           = s5p_jpeg_open,
+       .release        = s5p_jpeg_release,
+       .poll           = s5p_jpeg_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = s5p_jpeg_mmap,
+};
+
+/*
+ * ============================================================================
+ * video ioctl operations
+ * ============================================================================
+ */
+
+static int get_byte(struct s5p_jpeg_buffer *buf)
+{
+       if (buf->curr >= buf->size)
+               return -1;
+
+       return ((unsigned char *)buf->data)[buf->curr++];
+}
+
+static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
+{
+       unsigned int temp;
+       int byte;
+
+       byte = get_byte(buf);
+       if (byte == -1)
+               return -1;
+       temp = byte << 8;
+       byte = get_byte(buf);
+       if (byte == -1)
+               return -1;
+       *word = (unsigned int)byte | temp;
+       return 0;
+}
+
+static void skip(struct s5p_jpeg_buffer *buf, long len)
+{
+       if (len <= 0)
+               return;
+
+       while (len--)
+               get_byte(buf);
+}
+
+static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
+                              unsigned long buffer, unsigned long size)
+{
+       int c, components, notfound;
+       unsigned int height, width, word;
+       long length;
+       struct s5p_jpeg_buffer jpeg_buffer;
+
+       jpeg_buffer.size = size;
+       jpeg_buffer.data = buffer;
+       jpeg_buffer.curr = 0;
+
+       notfound = 1;
+       while (notfound) {
+               c = get_byte(&jpeg_buffer);
+               if (c == -1)
+                       break;
+               if (c != 0xff)
+                       continue;
+               do
+                       c = get_byte(&jpeg_buffer);
+               while (c == 0xff);
+               if (c == -1)
+                       break;
+               if (c == 0)
+                       continue;
+               length = 0;
+               switch (c) {
+               /* SOF0: baseline JPEG */
+               case SOF0:
+                       if (get_word_be(&jpeg_buffer, &word))
+                               break;
+                       if (get_byte(&jpeg_buffer) == -1)
+                               break;
+                       if (get_word_be(&jpeg_buffer, &height))
+                               break;
+                       if (get_word_be(&jpeg_buffer, &width))
+                               break;
+                       components = get_byte(&jpeg_buffer);
+                       if (components == -1)
+                               break;
+                       notfound = 0;
+
+                       skip(&jpeg_buffer, components * 3);
+                       break;
+
+               /* skip payload-less markers */
+               case RST ... RST + 7:
+               case SOI:
+               case EOI:
+               case TEM:
+                       break;
+
+               /* skip uninteresting payload markers */
+               default:
+                       if (get_word_be(&jpeg_buffer, &word))
+                               break;
+                       length = (long)word - 2;
+                       skip(&jpeg_buffer, length);
+                       break;
+               }
+       }
+       result->w = width;
+       result->h = height;
+       result->size = components;
+       return !notfound;
+}
+
+static int s5p_jpeg_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       struct s5p_jpeg_ctx *ctx = priv;
+
+       if (ctx->mode == S5P_JPEG_ENCODE) {
+               strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
+                       sizeof(cap->driver));
+               strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder",
+                       sizeof(cap->card));
+       } else {
+               strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder",
+                       sizeof(cap->driver));
+               strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder",
+                       sizeof(cap->card));
+       }
+       cap->bus_info[0] = 0;
+       cap->capabilities = V4L2_CAP_STREAMING |
+                           V4L2_CAP_VIDEO_CAPTURE |
+                           V4L2_CAP_VIDEO_OUTPUT;
+       return 0;
+}
+
+static int enum_fmt(struct s5p_jpeg_fmt *formats, int n,
+                   struct v4l2_fmtdesc *f, u32 type)
+{
+       int i, num = 0;
+
+       for (i = 0; i < n; ++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;
+               }
+       }
+
+       /* Format not found */
+       if (i >= n)
+               return -EINVAL;
+
+       strlcpy(f->description, formats[i].name, sizeof(f->description));
+       f->pixelformat = formats[i].fourcc;
+
+       return 0;
+}
+
+static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       struct s5p_jpeg_ctx *ctx;
+
+       ctx = priv;
+
+       if (ctx->mode == S5P_JPEG_ENCODE)
+               return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
+                               MEM2MEM_CAPTURE);
+
+       return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_CAPTURE);
+}
+
+static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       struct s5p_jpeg_ctx *ctx;
+
+       ctx = priv;
+
+       if (ctx->mode == S5P_JPEG_ENCODE)
+               return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
+                               MEM2MEM_OUTPUT);
+
+       return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_OUTPUT);
+}
+
+static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
+                                         enum v4l2_buf_type type)
+{
+       if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return &ctx->out_q;
+       if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return &ctx->cap_q;
+
+       return NULL;
+}
+
+static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct vb2_queue *vq;
+       struct s5p_jpeg_q_data *q_data = NULL;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct s5p_jpeg_ctx *ct = priv;
+
+       vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed)
+               return -EINVAL;
+       q_data = get_q_data(ct, f->type);
+       BUG_ON(q_data == NULL);
+
+       pix->width = q_data->w;
+       pix->height = q_data->h;
+       pix->field = V4L2_FIELD_NONE;
+       pix->pixelformat = q_data->fmt->fourcc;
+       pix->bytesperline = 0;
+       if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
+               u32 bpl = q_data->w;
+               if (q_data->fmt->colplanes == 1)
+                       bpl = (bpl * q_data->fmt->depth) >> 3;
+               pix->bytesperline = bpl;
+       }
+       pix->sizeimage = q_data->size;
+
+       return 0;
+}
+
+static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
+                                                u32 pixelformat)
+{
+       unsigned int k;
+       struct s5p_jpeg_fmt *formats;
+       int n;
+
+       if (mode == S5P_JPEG_ENCODE) {
+               formats = formats_enc;
+               n = NUM_FORMATS_ENC;
+       } else {
+               formats = formats_dec;
+               n = NUM_FORMATS_DEC;
+       }
+
+       for (k = 0; k < n; k++) {
+               struct s5p_jpeg_fmt *fmt = &formats[k];
+               if (fmt->fourcc == pixelformat)
+                       return fmt;
+       }
+
+       return NULL;
+
+}
+
+static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
+                                  unsigned int walign,
+                                  u32 *h, unsigned int hmin, unsigned int hmax,
+                                  unsigned int halign)
+{
+       int width, height, w_step, h_step;
+
+       width = *w;
+       height = *h;
+
+       w_step = 1 << walign;
+       h_step = 1 << halign;
+       v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
+
+       if (*w < width && (*w + w_step) < wmax)
+               *w += w_step;
+       if (*h < height && (*h + h_step) < hmax)
+               *h += h_step;
+
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
+                         struct s5p_jpeg_ctx *ctx, int q_type)
+{
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+
+       if (pix->field == V4L2_FIELD_ANY)
+               pix->field = V4L2_FIELD_NONE;
+       else if (pix->field != V4L2_FIELD_NONE)
+               return -EINVAL;
+
+       /* V4L2 specification suggests the driver corrects the format struct
+        * if any of the dimensions is unsupported */
+       if (q_type == MEM2MEM_OUTPUT)
+               jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
+                                      S5P_JPEG_MAX_WIDTH, 0,
+                                      &pix->height, S5P_JPEG_MIN_HEIGHT,
+                                      S5P_JPEG_MAX_HEIGHT, 0);
+       else
+               jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
+                                      S5P_JPEG_MAX_WIDTH, fmt->h_align,
+                                      &pix->height, S5P_JPEG_MIN_HEIGHT,
+                                      S5P_JPEG_MAX_HEIGHT, fmt->v_align);
+
+       if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
+               if (pix->sizeimage <= 0)
+                       pix->sizeimage = PAGE_SIZE;
+               pix->bytesperline = 0;
+       } else {
+               u32 bpl = pix->bytesperline;
+
+               if (fmt->colplanes > 1 && bpl < pix->width)
+                       bpl = pix->width; /* planar */
+
+               if (fmt->colplanes == 1 && /* packed */
+                   (bpl << 3) * fmt->depth < pix->width)
+                       bpl = (pix->width * fmt->depth) >> 3;
+
+               pix->bytesperline = bpl;
+               pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3;
+       }
+
+       return 0;
+}
+
+static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct s5p_jpeg_fmt *fmt;
+       struct s5p_jpeg_ctx *ctx = priv;
+
+       fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
+       if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
+               v4l2_err(&ctx->jpeg->v4l2_dev,
+                        "Fourcc format (0x%08x) invalid.\n",
+                        f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
+
+       return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_CAPTURE);
+}
+
+static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct s5p_jpeg_fmt *fmt;
+       struct s5p_jpeg_ctx *ctx = priv;
+
+       fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
+       if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
+               v4l2_err(&ctx->jpeg->v4l2_dev,
+                        "Fourcc format (0x%08x) invalid.\n",
+                        f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
+
+       return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_OUTPUT);
+}
+
+static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
+{
+       struct vb2_queue *vq;
+       struct s5p_jpeg_q_data *q_data = NULL;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+
+       vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       q_data = get_q_data(ct, f->type);
+       BUG_ON(q_data == NULL);
+
+       if (vb2_is_busy(vq)) {
+               v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__);
+               return -EBUSY;
+       }
+
+       q_data->fmt = s5p_jpeg_find_format(ct->mode, pix->pixelformat);
+       q_data->w = pix->width;
+       q_data->h = pix->height;
+       if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
+               q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
+       else
+               q_data->size = pix->sizeimage;
+
+       return 0;
+}
+
+static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       int ret;
+
+       ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f);
+       if (ret)
+               return ret;
+
+       return s5p_jpeg_s_fmt(priv, f);
+}
+
+static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       int ret;
+
+       ret = s5p_jpeg_try_fmt_vid_out(file, priv, f);
+       if (ret)
+               return ret;
+
+       return s5p_jpeg_s_fmt(priv, f);
+}
+
+static int s5p_jpeg_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *reqbufs)
+{
+       struct s5p_jpeg_ctx *ctx = priv;
+
+       return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int s5p_jpeg_querybuf(struct file *file, void *priv,
+                          struct v4l2_buffer *buf)
+{
+       struct s5p_jpeg_ctx *ctx = priv;
+
+       return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct s5p_jpeg_ctx *ctx = priv;
+
+       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int s5p_jpeg_dqbuf(struct file *file, void *priv,
+                         struct v4l2_buffer *buf)
+{
+       struct s5p_jpeg_ctx *ctx = priv;
+
+       return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int s5p_jpeg_streamon(struct file *file, void *priv,
+                          enum v4l2_buf_type type)
+{
+       struct s5p_jpeg_ctx *ctx = priv;
+
+       return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int s5p_jpeg_streamoff(struct file *file, void *priv,
+                           enum v4l2_buf_type type)
+{
+       struct s5p_jpeg_ctx *ctx = priv;
+
+       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+int s5p_jpeg_g_selection(struct file *file, void *priv,
+                        struct v4l2_selection *s)
+{
+       struct s5p_jpeg_ctx *ctx = priv;
+
+       if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+           s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       /* For JPEG blob active == default == bounds */
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP_ACTIVE:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+               s->r.width = ctx->out_q.w;
+               s->r.height = ctx->out_q.h;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+       case V4L2_SEL_TGT_COMPOSE_PADDED:
+               s->r.width = ctx->cap_q.w;
+               s->r.height = ctx->cap_q.h;
+               break;
+       default:
+               return -EINVAL;
+       }
+       s->r.left = 0;
+       s->r.top = 0;
+       return 0;
+}
+
+static int s5p_jpeg_g_jpegcomp(struct file *file, void *priv,
+                              struct v4l2_jpegcompression *compr)
+{
+       struct s5p_jpeg_ctx *ctx = priv;
+
+       if (ctx->mode == S5P_JPEG_DECODE)
+               return -ENOTTY;
+
+       memset(compr, 0, sizeof(*compr));
+       compr->quality = ctx->compr_quality;
+
+       return 0;
+}
+
+static int s5p_jpeg_s_jpegcomp(struct file *file, void *priv,
+                              struct v4l2_jpegcompression *compr)
+{
+       struct s5p_jpeg_ctx *ctx = priv;
+
+       if (ctx->mode == S5P_JPEG_DECODE)
+               return -ENOTTY;
+
+       compr->quality = clamp(compr->quality, S5P_JPEG_COMPR_QUAL_BEST,
+                              S5P_JPEG_COMPR_QUAL_WORST);
+
+       ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - compr->quality;
+
+       return 0;
+}
+
+static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
+       .vidioc_querycap                = s5p_jpeg_querycap,
+
+       .vidioc_enum_fmt_vid_cap        = s5p_jpeg_enum_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_out        = s5p_jpeg_enum_fmt_vid_out,
+
+       .vidioc_g_fmt_vid_cap           = s5p_jpeg_g_fmt,
+       .vidioc_g_fmt_vid_out           = s5p_jpeg_g_fmt,
+
+       .vidioc_try_fmt_vid_cap         = s5p_jpeg_try_fmt_vid_cap,
+       .vidioc_try_fmt_vid_out         = s5p_jpeg_try_fmt_vid_out,
+
+       .vidioc_s_fmt_vid_cap           = s5p_jpeg_s_fmt_vid_cap,
+       .vidioc_s_fmt_vid_out           = s5p_jpeg_s_fmt_vid_out,
+
+       .vidioc_reqbufs                 = s5p_jpeg_reqbufs,
+       .vidioc_querybuf                = s5p_jpeg_querybuf,
+
+       .vidioc_qbuf                    = s5p_jpeg_qbuf,
+       .vidioc_dqbuf                   = s5p_jpeg_dqbuf,
+
+       .vidioc_streamon                = s5p_jpeg_streamon,
+       .vidioc_streamoff               = s5p_jpeg_streamoff,
+
+       .vidioc_g_selection             = s5p_jpeg_g_selection,
+
+       .vidioc_g_jpegcomp              = s5p_jpeg_g_jpegcomp,
+       .vidioc_s_jpegcomp              = s5p_jpeg_s_jpegcomp,
+};
+
+/*
+ * ============================================================================
+ * mem2mem callbacks
+ * ============================================================================
+ */
+
+static void s5p_jpeg_device_run(void *priv)
+{
+       struct s5p_jpeg_ctx *ctx = priv;
+       struct s5p_jpeg *jpeg = ctx->jpeg;
+       struct vb2_buffer *src_buf, *dst_buf;
+       unsigned long src_addr, dst_addr;
+
+       src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+       src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+       dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+
+       jpeg_reset(jpeg->regs);
+       jpeg_poweron(jpeg->regs);
+       jpeg_proc_mode(jpeg->regs, ctx->mode);
+       if (ctx->mode == S5P_JPEG_ENCODE) {
+               if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
+                       jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565);
+               else
+                       jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422);
+               if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
+                       jpeg_subsampling_mode(jpeg->regs,
+                                             S5P_JPEG_SUBSAMPLING_422);
+               else
+                       jpeg_subsampling_mode(jpeg->regs,
+                                             S5P_JPEG_SUBSAMPLING_420);
+               jpeg_dri(jpeg->regs, 0);
+               jpeg_x(jpeg->regs, ctx->out_q.w);
+               jpeg_y(jpeg->regs, ctx->out_q.h);
+               jpeg_imgadr(jpeg->regs, src_addr);
+               jpeg_jpgadr(jpeg->regs, dst_addr);
+
+               /* ultimately comes from sizeimage from userspace */
+               jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
+
+               /* JPEG RGB to YCbCr conversion matrix */
+               jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
+               jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
+               jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
+               jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
+               jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
+               jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
+               jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
+               jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
+               jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
+
+               /*
+                * JPEG IP allows storing 4 quantization tables
+                * We fill table 0 for luma and table 1 for chroma
+                */
+               jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
+               jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
+               /* use table 0 for Y */
+               jpeg_qtbl(jpeg->regs, 1, 0);
+               /* use table 1 for Cb and Cr*/
+               jpeg_qtbl(jpeg->regs, 2, 1);
+               jpeg_qtbl(jpeg->regs, 3, 1);
+
+               /* Y, Cb, Cr use Huffman table 0 */
+               jpeg_htbl_ac(jpeg->regs, 1);
+               jpeg_htbl_dc(jpeg->regs, 1);
+               jpeg_htbl_ac(jpeg->regs, 2);
+               jpeg_htbl_dc(jpeg->regs, 2);
+               jpeg_htbl_ac(jpeg->regs, 3);
+               jpeg_htbl_dc(jpeg->regs, 3);
+       } else {
+               jpeg_rst_int_enable(jpeg->regs, true);
+               jpeg_data_num_int_enable(jpeg->regs, true);
+               jpeg_final_mcu_num_int_enable(jpeg->regs, true);
+               jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
+               jpeg_jpgadr(jpeg->regs, src_addr);
+               jpeg_imgadr(jpeg->regs, dst_addr);
+       }
+       jpeg_start(jpeg->regs);
+}
+
+static int s5p_jpeg_job_ready(void *priv)
+{
+       struct s5p_jpeg_ctx *ctx = priv;
+
+       if (ctx->mode == S5P_JPEG_DECODE)
+               return ctx->hdr_parsed;
+       return 1;
+}
+
+static void s5p_jpeg_job_abort(void *priv)
+{
+}
+
+static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
+       .device_run     = s5p_jpeg_device_run,
+       .job_ready      = s5p_jpeg_job_ready,
+       .job_abort      = s5p_jpeg_job_abort,
+};
+
+/*
+ * ============================================================================
+ * Queue operations
+ * ============================================================================
+ */
+
+static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
+                          const struct v4l2_format *fmt,
+                          unsigned int *nbuffers, unsigned int *nplanes,
+                          unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+       struct s5p_jpeg_q_data *q_data = NULL;
+       unsigned int size, count = *nbuffers;
+
+       q_data = get_q_data(ctx, vq->type);
+       BUG_ON(q_data == NULL);
+
+       size = q_data->size;
+
+       /*
+        * header is parsed during decoding and parsed information stored
+        * in the context so we do not allow another buffer to overwrite it
+        */
+       if (ctx->mode == S5P_JPEG_DECODE)
+               count = 1;
+
+       *nbuffers = count;
+       *nplanes = 1;
+       sizes[0] = size;
+       alloc_ctxs[0] = ctx->jpeg->alloc_ctx;
+
+       return 0;
+}
+
+static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
+{
+       struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct s5p_jpeg_q_data *q_data = NULL;
+
+       q_data = get_q_data(ctx, vb->vb2_queue->type);
+       BUG_ON(q_data == NULL);
+
+       if (vb2_plane_size(vb, 0) < q_data->size) {
+               pr_err("%s data will not fit into plane (%lu < %lu)\n",
+                               __func__, vb2_plane_size(vb, 0),
+                               (long)q_data->size);
+               return -EINVAL;
+       }
+
+       vb2_set_plane_payload(vb, 0, q_data->size);
+
+       return 0;
+}
+
+static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
+{
+       struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+       if (ctx->mode == S5P_JPEG_DECODE &&
+           vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               struct s5p_jpeg_q_data tmp, *q_data;
+               ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
+                    (unsigned long)vb2_plane_vaddr(vb, 0),
+                    min((unsigned long)ctx->out_q.size,
+                        vb2_get_plane_payload(vb, 0)));
+               if (!ctx->hdr_parsed) {
+                       vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+                       return;
+               }
+
+               q_data = &ctx->out_q;
+               q_data->w = tmp.w;
+               q_data->h = tmp.h;
+
+               q_data = &ctx->cap_q;
+               q_data->w = tmp.w;
+               q_data->h = tmp.h;
+
+               jpeg_bound_align_image(&q_data->w, S5P_JPEG_MIN_WIDTH,
+                                      S5P_JPEG_MAX_WIDTH, q_data->fmt->h_align,
+                                      &q_data->h, S5P_JPEG_MIN_HEIGHT,
+                                      S5P_JPEG_MAX_HEIGHT, q_data->fmt->v_align
+                                     );
+               q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
+       }
+       if (ctx->m2m_ctx)
+               v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void s5p_jpeg_wait_prepare(struct vb2_queue *vq)
+{
+       struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+
+       mutex_unlock(&ctx->jpeg->lock);
+}
+
+static void s5p_jpeg_wait_finish(struct vb2_queue *vq)
+{
+       struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+
+       mutex_lock(&ctx->jpeg->lock);
+}
+
+static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+       int ret;
+
+       ret = pm_runtime_get_sync(ctx->jpeg->dev);
+
+       return ret > 0 ? 0 : ret;
+}
+
+static int s5p_jpeg_stop_streaming(struct vb2_queue *q)
+{
+       struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+
+       pm_runtime_put(ctx->jpeg->dev);
+
+       return 0;
+}
+
+static struct vb2_ops s5p_jpeg_qops = {
+       .queue_setup            = s5p_jpeg_queue_setup,
+       .buf_prepare            = s5p_jpeg_buf_prepare,
+       .buf_queue              = s5p_jpeg_buf_queue,
+       .wait_prepare           = s5p_jpeg_wait_prepare,
+       .wait_finish            = s5p_jpeg_wait_finish,
+       .start_streaming        = s5p_jpeg_start_streaming,
+       .stop_streaming         = s5p_jpeg_stop_streaming,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+                     struct vb2_queue *dst_vq)
+{
+       struct s5p_jpeg_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 = &s5p_jpeg_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 | VB2_USERPTR;
+       dst_vq->drv_priv = ctx;
+       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       dst_vq->ops = &s5p_jpeg_qops;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+       return vb2_queue_init(dst_vq);
+}
+
+/*
+ * ============================================================================
+ * ISR
+ * ============================================================================
+ */
+
+static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
+{
+       struct s5p_jpeg *jpeg = dev_id;
+       struct s5p_jpeg_ctx *curr_ctx;
+       struct vb2_buffer *src_buf, *dst_buf;
+       unsigned long payload_size = 0;
+       enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
+       bool enc_jpeg_too_large = false;
+       bool timer_elapsed = false;
+       bool op_completed = false;
+
+       curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
+
+       src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+       dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+
+       if (curr_ctx->mode == S5P_JPEG_ENCODE)
+               enc_jpeg_too_large = jpeg_enc_stream_stat(jpeg->regs);
+       timer_elapsed = jpeg_timer_stat(jpeg->regs);
+       op_completed = jpeg_result_stat_ok(jpeg->regs);
+       if (curr_ctx->mode == S5P_JPEG_DECODE)
+               op_completed = op_completed && jpeg_stream_stat_ok(jpeg->regs);
+
+       if (enc_jpeg_too_large) {
+               state = VB2_BUF_STATE_ERROR;
+               jpeg_clear_enc_stream_stat(jpeg->regs);
+       } else if (timer_elapsed) {
+               state = VB2_BUF_STATE_ERROR;
+               jpeg_clear_timer_stat(jpeg->regs);
+       } else if (!op_completed) {
+               state = VB2_BUF_STATE_ERROR;
+       } else {
+               payload_size = jpeg_compressed_size(jpeg->regs);
+       }
+
+       v4l2_m2m_buf_done(src_buf, state);
+       if (curr_ctx->mode == S5P_JPEG_ENCODE)
+               vb2_set_plane_payload(dst_buf, 0, payload_size);
+       v4l2_m2m_buf_done(dst_buf, state);
+       v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx);
+
+       jpeg_clear_int(jpeg->regs);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * ============================================================================
+ * Driver basic infrastructure
+ * ============================================================================
+ */
+
+static int s5p_jpeg_probe(struct platform_device *pdev)
+{
+       struct s5p_jpeg *jpeg;
+       struct resource *res;
+       int ret;
+
+       /* JPEG IP abstraction struct */
+       jpeg = kzalloc(sizeof(struct s5p_jpeg), GFP_KERNEL);
+       if (!jpeg)
+               return -ENOMEM;
+
+       mutex_init(&jpeg->lock);
+       jpeg->dev = &pdev->dev;
+
+       /* memory-mapped registers */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "cannot find IO resource\n");
+               ret = -ENOENT;
+               goto jpeg_alloc_rollback;
+       }
+
+       jpeg->ioarea = request_mem_region(res->start, resource_size(res),
+                                         pdev->name);
+       if (!jpeg->ioarea) {
+               dev_err(&pdev->dev, "cannot request IO\n");
+               ret = -ENXIO;
+               goto jpeg_alloc_rollback;
+       }
+
+       jpeg->regs = ioremap(res->start, resource_size(res));
+       if (!jpeg->regs) {
+               dev_err(&pdev->dev, "cannot map IO\n");
+               ret = -ENXIO;
+               goto mem_region_rollback;
+       }
+
+       dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
+               jpeg->regs, jpeg->ioarea, res);
+
+       /* interrupt service routine registration */
+       jpeg->irq = ret = platform_get_irq(pdev, 0);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "cannot find IRQ\n");
+               goto ioremap_rollback;
+       }
+
+       ret = request_irq(jpeg->irq, s5p_jpeg_irq, 0,
+                         dev_name(&pdev->dev), jpeg);
+
+       if (ret) {
+               dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
+               goto ioremap_rollback;
+       }
+
+       /* clocks */
+       jpeg->clk = clk_get(&pdev->dev, "jpeg");
+       if (IS_ERR(jpeg->clk)) {
+               dev_err(&pdev->dev, "cannot get clock\n");
+               ret = PTR_ERR(jpeg->clk);
+               goto request_irq_rollback;
+       }
+       dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
+       clk_enable(jpeg->clk);
+
+       /* v4l2 device */
+       ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register v4l2 device\n");
+               goto clk_get_rollback;
+       }
+
+       /* mem2mem device */
+       jpeg->m2m_dev = v4l2_m2m_init(&s5p_jpeg_m2m_ops);
+       if (IS_ERR(jpeg->m2m_dev)) {
+               v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
+               ret = PTR_ERR(jpeg->m2m_dev);
+               goto device_register_rollback;
+       }
+
+       jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(jpeg->alloc_ctx)) {
+               v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n");
+               ret = PTR_ERR(jpeg->alloc_ctx);
+               goto m2m_init_rollback;
+       }
+
+       /* JPEG encoder /dev/videoX node */
+       jpeg->vfd_encoder = video_device_alloc();
+       if (!jpeg->vfd_encoder) {
+               v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
+               ret = -ENOMEM;
+               goto vb2_allocator_rollback;
+       }
+       strlcpy(jpeg->vfd_encoder->name, S5P_JPEG_M2M_NAME,
+               sizeof(jpeg->vfd_encoder->name));
+       jpeg->vfd_encoder->fops         = &s5p_jpeg_fops;
+       jpeg->vfd_encoder->ioctl_ops    = &s5p_jpeg_ioctl_ops;
+       jpeg->vfd_encoder->minor        = -1;
+       jpeg->vfd_encoder->release      = video_device_release;
+       jpeg->vfd_encoder->lock         = &jpeg->lock;
+       jpeg->vfd_encoder->v4l2_dev     = &jpeg->v4l2_dev;
+
+       ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
+       if (ret) {
+               v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
+               goto enc_vdev_alloc_rollback;
+       }
+
+       video_set_drvdata(jpeg->vfd_encoder, jpeg);
+       v4l2_info(&jpeg->v4l2_dev,
+                 "encoder device registered as /dev/video%d\n",
+                 jpeg->vfd_encoder->num);
+
+       /* JPEG decoder /dev/videoX node */
+       jpeg->vfd_decoder = video_device_alloc();
+       if (!jpeg->vfd_decoder) {
+               v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n");
+               ret = -ENOMEM;
+               goto enc_vdev_register_rollback;
+       }
+       strlcpy(jpeg->vfd_decoder->name, S5P_JPEG_M2M_NAME,
+               sizeof(jpeg->vfd_decoder->name));
+       jpeg->vfd_decoder->fops         = &s5p_jpeg_fops;
+       jpeg->vfd_decoder->ioctl_ops    = &s5p_jpeg_ioctl_ops;
+       jpeg->vfd_decoder->minor        = -1;
+       jpeg->vfd_decoder->release      = video_device_release;
+       jpeg->vfd_decoder->lock         = &jpeg->lock;
+       jpeg->vfd_decoder->v4l2_dev     = &jpeg->v4l2_dev;
+
+       ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
+       if (ret) {
+               v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
+               goto dec_vdev_alloc_rollback;
+       }
+
+       video_set_drvdata(jpeg->vfd_decoder, jpeg);
+       v4l2_info(&jpeg->v4l2_dev,
+                 "decoder device registered as /dev/video%d\n",
+                 jpeg->vfd_decoder->num);
+
+       /* final statements & power management */
+       platform_set_drvdata(pdev, jpeg);
+
+       pm_runtime_enable(&pdev->dev);
+
+       v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n");
+
+       return 0;
+
+dec_vdev_alloc_rollback:
+       video_device_release(jpeg->vfd_decoder);
+
+enc_vdev_register_rollback:
+       video_unregister_device(jpeg->vfd_encoder);
+
+enc_vdev_alloc_rollback:
+       video_device_release(jpeg->vfd_encoder);
+
+vb2_allocator_rollback:
+       vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
+
+m2m_init_rollback:
+       v4l2_m2m_release(jpeg->m2m_dev);
+
+device_register_rollback:
+       v4l2_device_unregister(&jpeg->v4l2_dev);
+
+clk_get_rollback:
+       clk_disable(jpeg->clk);
+       clk_put(jpeg->clk);
+
+request_irq_rollback:
+       free_irq(jpeg->irq, jpeg);
+
+ioremap_rollback:
+       iounmap(jpeg->regs);
+
+mem_region_rollback:
+       release_resource(jpeg->ioarea);
+       release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea));
+
+jpeg_alloc_rollback:
+       kfree(jpeg);
+       return ret;
+}
+
+static int s5p_jpeg_remove(struct platform_device *pdev)
+{
+       struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
+
+       pm_runtime_disable(jpeg->dev);
+
+       video_unregister_device(jpeg->vfd_decoder);
+       video_device_release(jpeg->vfd_decoder);
+       video_unregister_device(jpeg->vfd_encoder);
+       video_device_release(jpeg->vfd_encoder);
+       vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
+       v4l2_m2m_release(jpeg->m2m_dev);
+       v4l2_device_unregister(&jpeg->v4l2_dev);
+
+       clk_disable(jpeg->clk);
+       clk_put(jpeg->clk);
+
+       free_irq(jpeg->irq, jpeg);
+
+       iounmap(jpeg->regs);
+
+       release_resource(jpeg->ioarea);
+       release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea));
+       kfree(jpeg);
+
+       return 0;
+}
+
+static int s5p_jpeg_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int s5p_jpeg_runtime_resume(struct device *dev)
+{
+       struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
+       /*
+        * JPEG IP allows storing two Huffman tables for each component
+        * We fill table 0 for each component
+        */
+       jpeg_set_hdctbl(jpeg->regs);
+       jpeg_set_hdctblg(jpeg->regs);
+       jpeg_set_hactbl(jpeg->regs);
+       jpeg_set_hactblg(jpeg->regs);
+       return 0;
+}
+
+static const struct dev_pm_ops s5p_jpeg_pm_ops = {
+       .runtime_suspend = s5p_jpeg_runtime_suspend,
+       .runtime_resume  = s5p_jpeg_runtime_resume,
+};
+
+static struct platform_driver s5p_jpeg_driver = {
+       .probe = s5p_jpeg_probe,
+       .remove = s5p_jpeg_remove,
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = S5P_JPEG_M2M_NAME,
+               .pm = &s5p_jpeg_pm_ops,
+       },
+};
+
+static int __init
+s5p_jpeg_register(void)
+{
+       int ret;
+
+       pr_info("S5P JPEG V4L2 Driver, (c) 2011 Samsung Electronics\n");
+
+       ret = platform_driver_register(&s5p_jpeg_driver);
+
+       if (ret)
+               pr_err("%s: failed to register jpeg driver\n", __func__);
+
+       return ret;
+}
+
+static void __exit
+s5p_jpeg_unregister(void)
+{
+       platform_driver_unregister(&s5p_jpeg_driver);
+}
+
+module_init(s5p_jpeg_register);
+module_exit(s5p_jpeg_unregister);
+
+MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
+MODULE_DESCRIPTION("Samsung JPEG codec driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.h b/drivers/media/video/s5p-jpeg/jpeg-core.h
new file mode 100644 (file)
index 0000000..facad61
--- /dev/null
@@ -0,0 +1,143 @@
+/* linux/drivers/media/video/s5p-jpeg/jpeg-core.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef JPEG_CORE_H_
+#define JPEG_CORE_H_
+
+#include <media/v4l2-device.h>
+
+#define S5P_JPEG_M2M_NAME              "s5p-jpeg"
+
+/* JPEG compression quality setting */
+#define S5P_JPEG_COMPR_QUAL_BEST       0
+#define S5P_JPEG_COMPR_QUAL_WORST      3
+
+/* JPEG RGB to YCbCr conversion matrix coefficients */
+#define S5P_JPEG_COEF11                        0x4d
+#define S5P_JPEG_COEF12                        0x97
+#define S5P_JPEG_COEF13                        0x1e
+#define S5P_JPEG_COEF21                        0x2c
+#define S5P_JPEG_COEF22                        0x57
+#define S5P_JPEG_COEF23                        0x83
+#define S5P_JPEG_COEF31                        0x83
+#define S5P_JPEG_COEF32                        0x6e
+#define S5P_JPEG_COEF33                        0x13
+
+/* a selection of JPEG markers */
+#define TEM                            0x01
+#define SOF0                           0xc0
+#define RST                            0xd0
+#define SOI                            0xd8
+#define EOI                            0xd9
+#define DHP                            0xde
+
+/* Flags that indicate a format can be used for capture/output */
+#define MEM2MEM_CAPTURE                        (1 << 0)
+#define MEM2MEM_OUTPUT                 (1 << 1)
+
+/**
+ * struct s5p_jpeg - JPEG IP abstraction
+ * @lock:              the mutex protecting this structure
+ * @v4l2_dev:          v4l2 device for mem2mem mode
+ * @vfd_encoder:       video device node for encoder mem2mem mode
+ * @vfd_decoder:       video device node for decoder mem2mem mode
+ * @m2m_dev:           v4l2 mem2mem device data
+ * @ioarea:            JPEG IP memory region
+ * @regs:              JPEG IP registers mapping
+ * @irq:               JPEG IP irq
+ * @clk:               JPEG IP clock
+ * @dev:               JPEG IP struct device
+ * @alloc_ctx:         videobuf2 memory allocator's context
+ */
+struct s5p_jpeg {
+       struct mutex            lock;
+
+       struct v4l2_device      v4l2_dev;
+       struct video_device     *vfd_encoder;
+       struct video_device     *vfd_decoder;
+       struct v4l2_m2m_dev     *m2m_dev;
+
+       struct resource         *ioarea;
+       void __iomem            *regs;
+       unsigned int            irq;
+       struct clk              *clk;
+       struct device           *dev;
+       void                    *alloc_ctx;
+};
+
+/**
+ * struct jpeg_fmt - driver's internal color format data
+ * @name:      format descritpion
+ * @fourcc:    the fourcc code, 0 if not applicable
+ * @depth:     number of bits per pixel
+ * @colplanes: number of color planes (1 for packed formats)
+ * @h_align:   horizontal alignment order (align to 2^h_align)
+ * @v_align:   vertical alignment order (align to 2^v_align)
+ * @types:     types of queue this format is applicable to
+ */
+struct s5p_jpeg_fmt {
+       char    *name;
+       u32     fourcc;
+       int     depth;
+       int     colplanes;
+       int     h_align;
+       int     v_align;
+       u32     types;
+};
+
+/**
+ * s5p_jpeg_q_data - parameters of one queue
+ * @fmt:       driver-specific format of this queue
+ * @w:         image width
+ * @h:         image height
+ * @size:      image buffer size in bytes
+ */
+struct s5p_jpeg_q_data {
+       struct s5p_jpeg_fmt     *fmt;
+       u32                     w;
+       u32                     h;
+       u32                     size;
+};
+
+/**
+ * s5p_jpeg_ctx - the device context data
+ * @jpeg:              JPEG IP device for this context
+ * @mode:              compression (encode) operation or decompression (decode)
+ * @compr_quality:     destination image quality in compression (encode) mode
+ * @m2m_ctx:           mem2mem device context
+ * @out_q:             source (output) queue information
+ * @cap_fmt:           destination (capture) queue queue information
+ * @hdr_parsed:                set if header has been parsed during decompression
+ */
+struct s5p_jpeg_ctx {
+       struct s5p_jpeg         *jpeg;
+       unsigned int            mode;
+       unsigned int            compr_quality;
+       struct v4l2_m2m_ctx     *m2m_ctx;
+       struct s5p_jpeg_q_data  out_q;
+       struct s5p_jpeg_q_data  cap_q;
+       bool                    hdr_parsed;
+};
+
+/**
+ * s5p_jpeg_buffer - description of memory containing input JPEG data
+ * @size:      buffer size
+ * @curr:      current position in the buffer
+ * @data:      pointer to the data
+ */
+struct s5p_jpeg_buffer {
+       unsigned long size;
+       unsigned long curr;
+       unsigned long data;
+};
+
+#endif /* JPEG_CORE_H */
diff --git a/drivers/media/video/s5p-jpeg/jpeg-hw.h b/drivers/media/video/s5p-jpeg/jpeg-hw.h
new file mode 100644 (file)
index 0000000..e10c744
--- /dev/null
@@ -0,0 +1,353 @@
+/* linux/drivers/media/video/s5p-jpeg/jpeg-hw.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef JPEG_HW_H_
+#define JPEG_HW_H_
+
+#include <linux/io.h>
+
+#include "jpeg-hw.h"
+#include "jpeg-regs.h"
+
+#define S5P_JPEG_MIN_WIDTH             32
+#define S5P_JPEG_MIN_HEIGHT            32
+#define S5P_JPEG_MAX_WIDTH             8192
+#define S5P_JPEG_MAX_HEIGHT            8192
+#define S5P_JPEG_ENCODE                        0
+#define S5P_JPEG_DECODE                        1
+#define S5P_JPEG_RAW_IN_565            0
+#define S5P_JPEG_RAW_IN_422            1
+#define S5P_JPEG_SUBSAMPLING_422       0
+#define S5P_JPEG_SUBSAMPLING_420       1
+#define S5P_JPEG_RAW_OUT_422           0
+#define S5P_JPEG_RAW_OUT_420           1
+
+static inline void jpeg_reset(void __iomem *regs)
+{
+       unsigned long reg;
+
+       writel(1, regs + S5P_JPG_SW_RESET);
+       reg = readl(regs + S5P_JPG_SW_RESET);
+       /* no other way but polling for when JPEG IP becomes operational */
+       while (reg != 0) {
+               cpu_relax();
+               reg = readl(regs + S5P_JPG_SW_RESET);
+       }
+}
+
+static inline void jpeg_poweron(void __iomem *regs)
+{
+       writel(S5P_POWER_ON, regs + S5P_JPGCLKCON);
+}
+
+static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode)
+{
+       unsigned long reg, m;
+
+       m = S5P_MOD_SEL_565;
+       if (mode == S5P_JPEG_RAW_IN_565)
+               m = S5P_MOD_SEL_565;
+       else if (mode == S5P_JPEG_RAW_IN_422)
+               m = S5P_MOD_SEL_422;
+
+       reg = readl(regs + S5P_JPGCMOD);
+       reg &= ~S5P_MOD_SEL_MASK;
+       reg |= m;
+       writel(reg, regs + S5P_JPGCMOD);
+}
+
+static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPGCMOD);
+       if (y16)
+               reg |= S5P_MODE_Y16;
+       else
+               reg &= ~S5P_MODE_Y16_MASK;
+       writel(reg, regs + S5P_JPGCMOD);
+}
+
+static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode)
+{
+       unsigned long reg, m;
+
+       m = S5P_PROC_MODE_DECOMPR;
+       if (mode == S5P_JPEG_ENCODE)
+               m = S5P_PROC_MODE_COMPR;
+       else
+               m = S5P_PROC_MODE_DECOMPR;
+       reg = readl(regs + S5P_JPGMOD);
+       reg &= ~S5P_PROC_MODE_MASK;
+       reg |= m;
+       writel(reg, regs + S5P_JPGMOD);
+}
+
+static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned long mode)
+{
+       unsigned long reg, m;
+
+       m = S5P_SUBSAMPLING_MODE_422;
+       if (mode == S5P_JPEG_SUBSAMPLING_422)
+               m = S5P_SUBSAMPLING_MODE_422;
+       else if (mode == S5P_JPEG_SUBSAMPLING_420)
+               m = S5P_SUBSAMPLING_MODE_420;
+       reg = readl(regs + S5P_JPGMOD);
+       reg &= ~S5P_SUBSAMPLING_MODE_MASK;
+       reg |= m;
+       writel(reg, regs + S5P_JPGMOD);
+}
+
+static inline void jpeg_dri(void __iomem *regs, unsigned int dri)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPGDRI_U);
+       reg &= ~0xff;
+       reg |= (dri >> 8) & 0xff;
+       writel(reg, regs + S5P_JPGDRI_U);
+
+       reg = readl(regs + S5P_JPGDRI_L);
+       reg &= ~0xff;
+       reg |= dri & 0xff;
+       writel(reg, regs + S5P_JPGDRI_L);
+}
+
+static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPG_QTBL);
+       reg &= ~S5P_QT_NUMt_MASK(t);
+       reg |= (n << S5P_QT_NUMt_SHIFT(t)) & S5P_QT_NUMt_MASK(t);
+       writel(reg, regs + S5P_JPG_QTBL);
+}
+
+static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPG_HTBL);
+       reg &= ~S5P_HT_NUMt_AC_MASK(t);
+       /* this driver uses table 0 for all color components */
+       reg |= (0 << S5P_HT_NUMt_AC_SHIFT(t)) & S5P_HT_NUMt_AC_MASK(t);
+       writel(reg, regs + S5P_JPG_HTBL);
+}
+
+static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPG_HTBL);
+       reg &= ~S5P_HT_NUMt_DC_MASK(t);
+       /* this driver uses table 0 for all color components */
+       reg |= (0 << S5P_HT_NUMt_DC_SHIFT(t)) & S5P_HT_NUMt_DC_MASK(t);
+       writel(reg, regs + S5P_JPG_HTBL);
+}
+
+static inline void jpeg_y(void __iomem *regs, unsigned int y)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPGY_U);
+       reg &= ~0xff;
+       reg |= (y >> 8) & 0xff;
+       writel(reg, regs + S5P_JPGY_U);
+
+       reg = readl(regs + S5P_JPGY_L);
+       reg &= ~0xff;
+       reg |= y & 0xff;
+       writel(reg, regs + S5P_JPGY_L);
+}
+
+static inline void jpeg_x(void __iomem *regs, unsigned int x)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPGX_U);
+       reg &= ~0xff;
+       reg |= (x >> 8) & 0xff;
+       writel(reg, regs + S5P_JPGX_U);
+
+       reg = readl(regs + S5P_JPGX_L);
+       reg &= ~0xff;
+       reg |= x & 0xff;
+       writel(reg, regs + S5P_JPGX_L);
+}
+
+static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPGINTSE);
+       reg &= ~S5P_RSTm_INT_EN_MASK;
+       if (enable)
+               reg |= S5P_RSTm_INT_EN;
+       writel(reg, regs + S5P_JPGINTSE);
+}
+
+static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPGINTSE);
+       reg &= ~S5P_DATA_NUM_INT_EN_MASK;
+       if (enable)
+               reg |= S5P_DATA_NUM_INT_EN;
+       writel(reg, regs + S5P_JPGINTSE);
+}
+
+static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPGINTSE);
+       reg &= ~S5P_FINAL_MCU_NUM_INT_EN_MASK;
+       if (enbl)
+               reg |= S5P_FINAL_MCU_NUM_INT_EN;
+       writel(reg, regs + S5P_JPGINTSE);
+}
+
+static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPG_TIMER_SE);
+       reg |= S5P_TIMER_INT_EN;
+       reg &= ~S5P_TIMER_INIT_MASK;
+       reg |= val & S5P_TIMER_INIT_MASK;
+       writel(reg, regs + S5P_JPG_TIMER_SE);
+}
+
+static inline void jpeg_timer_disable(void __iomem *regs)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPG_TIMER_SE);
+       reg &= ~S5P_TIMER_INT_EN_MASK;
+       writel(reg, regs + S5P_JPG_TIMER_SE);
+}
+
+static inline int jpeg_timer_stat(void __iomem *regs)
+{
+       return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK)
+                    >> S5P_TIMER_INT_STAT_SHIFT);
+}
+
+static inline void jpeg_clear_timer_stat(void __iomem *regs)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPG_TIMER_SE);
+       reg &= ~S5P_TIMER_INT_STAT_MASK;
+       writel(reg, regs + S5P_JPG_TIMER_SE);
+}
+
+static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE);
+       reg &= ~S5P_ENC_STREAM_BOUND_MASK;
+       reg |= S5P_ENC_STREAM_INT_EN;
+       reg |= size & S5P_ENC_STREAM_BOUND_MASK;
+       writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
+}
+
+static inline int jpeg_enc_stream_stat(void __iomem *regs)
+{
+       return (int)(readl(regs + S5P_JPG_ENC_STREAM_INTST) &
+                    S5P_ENC_STREAM_INT_STAT_MASK);
+}
+
+static inline void jpeg_clear_enc_stream_stat(void __iomem *regs)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE);
+       reg &= ~S5P_ENC_STREAM_INT_MASK;
+       writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
+}
+
+static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format)
+{
+       unsigned long reg, f;
+
+       f = S5P_DEC_OUT_FORMAT_422;
+       if (format == S5P_JPEG_RAW_OUT_422)
+               f = S5P_DEC_OUT_FORMAT_422;
+       else if (format == S5P_JPEG_RAW_OUT_420)
+               f = S5P_DEC_OUT_FORMAT_420;
+       reg = readl(regs + S5P_JPG_OUTFORM);
+       reg &= ~S5P_DEC_OUT_FORMAT_MASK;
+       reg |= f;
+       writel(reg, regs + S5P_JPG_OUTFORM);
+}
+
+static inline void jpeg_jpgadr(void __iomem *regs, unsigned long addr)
+{
+       writel(addr, regs + S5P_JPG_JPGADR);
+}
+
+static inline void jpeg_imgadr(void __iomem *regs, unsigned long addr)
+{
+       writel(addr, regs + S5P_JPG_IMGADR);
+}
+
+static inline void jpeg_coef(void __iomem *regs, unsigned int i,
+                            unsigned int j, unsigned int coef)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPG_COEF(i));
+       reg &= ~S5P_COEFn_MASK(j);
+       reg |= (coef << S5P_COEFn_SHIFT(j)) & S5P_COEFn_MASK(j);
+       writel(reg, regs + S5P_JPG_COEF(i));
+}
+
+static inline void jpeg_start(void __iomem *regs)
+{
+       writel(1, regs + S5P_JSTART);
+}
+
+static inline int jpeg_result_stat_ok(void __iomem *regs)
+{
+       return (int)((readl(regs + S5P_JPGINTST) & S5P_RESULT_STAT_MASK)
+                    >> S5P_RESULT_STAT_SHIFT);
+}
+
+static inline int jpeg_stream_stat_ok(void __iomem *regs)
+{
+       return !(int)((readl(regs + S5P_JPGINTST) & S5P_STREAM_STAT_MASK)
+                     >> S5P_STREAM_STAT_SHIFT);
+}
+
+static inline void jpeg_clear_int(void __iomem *regs)
+{
+       unsigned long reg;
+
+       reg = readl(regs + S5P_JPGINTST);
+       writel(S5P_INT_RELEASE, regs + S5P_JPGCOM);
+       reg = readl(regs + S5P_JPGOPR);
+}
+
+static inline unsigned int jpeg_compressed_size(void __iomem *regs)
+{
+       unsigned long jpeg_size = 0;
+
+       jpeg_size |= (readl(regs + S5P_JPGCNT_U) & 0xff) << 16;
+       jpeg_size |= (readl(regs + S5P_JPGCNT_M) & 0xff) << 8;
+       jpeg_size |= (readl(regs + S5P_JPGCNT_L) & 0xff);
+
+       return (unsigned int)jpeg_size;
+}
+
+#endif /* JPEG_HW_H_ */
diff --git a/drivers/media/video/s5p-jpeg/jpeg-regs.h b/drivers/media/video/s5p-jpeg/jpeg-regs.h
new file mode 100644 (file)
index 0000000..91f4dd5
--- /dev/null
@@ -0,0 +1,170 @@
+/* linux/drivers/media/video/s5p-jpeg/jpeg-regs.h
+ *
+ * Register definition file for Samsung JPEG codec driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef JPEG_REGS_H_
+#define JPEG_REGS_H_
+
+/* JPEG mode register */
+#define S5P_JPGMOD                     0x00
+#define S5P_PROC_MODE_MASK             (0x1 << 3)
+#define S5P_PROC_MODE_DECOMPR          (0x1 << 3)
+#define S5P_PROC_MODE_COMPR            (0x0 << 3)
+#define S5P_SUBSAMPLING_MODE_MASK      0x7
+#define S5P_SUBSAMPLING_MODE_444       (0x0 << 0)
+#define S5P_SUBSAMPLING_MODE_422       (0x1 << 0)
+#define S5P_SUBSAMPLING_MODE_420       (0x2 << 0)
+#define S5P_SUBSAMPLING_MODE_GRAY      (0x3 << 0)
+
+/* JPEG operation status register */
+#define S5P_JPGOPR                     0x04
+
+/* Quantization tables*/
+#define S5P_JPG_QTBL                   0x08
+#define S5P_QT_NUMt_SHIFT(t)           (((t) - 1) << 1)
+#define S5P_QT_NUMt_MASK(t)            (0x3 << S5P_QT_NUMt_SHIFT(t))
+
+/* Huffman tables */
+#define S5P_JPG_HTBL                   0x0c
+#define S5P_HT_NUMt_AC_SHIFT(t)                (((t) << 1) - 1)
+#define S5P_HT_NUMt_AC_MASK(t)         (0x1 << S5P_HT_NUMt_AC_SHIFT(t))
+
+#define S5P_HT_NUMt_DC_SHIFT(t)                (((t) - 1) << 1)
+#define S5P_HT_NUMt_DC_MASK(t)         (0x1 << S5P_HT_NUMt_DC_SHIFT(t))
+
+/* JPEG restart interval register upper byte */
+#define S5P_JPGDRI_U                   0x10
+
+/* JPEG restart interval register lower byte */
+#define S5P_JPGDRI_L                   0x14
+
+/* JPEG vertical resolution register upper byte */
+#define S5P_JPGY_U                     0x18
+
+/* JPEG vertical resolution register lower byte */
+#define S5P_JPGY_L                     0x1c
+
+/* JPEG horizontal resolution register upper byte */
+#define S5P_JPGX_U                     0x20
+
+/* JPEG horizontal resolution register lower byte */
+#define S5P_JPGX_L                     0x24
+
+/* JPEG byte count register upper byte */
+#define S5P_JPGCNT_U                   0x28
+
+/* JPEG byte count register middle byte */
+#define S5P_JPGCNT_M                   0x2c
+
+/* JPEG byte count register lower byte */
+#define S5P_JPGCNT_L                   0x30
+
+/* JPEG interrupt setting register */
+#define S5P_JPGINTSE                   0x34
+#define S5P_RSTm_INT_EN_MASK           (0x1 << 7)
+#define S5P_RSTm_INT_EN                        (0x1 << 7)
+#define S5P_DATA_NUM_INT_EN_MASK       (0x1 << 6)
+#define S5P_DATA_NUM_INT_EN            (0x1 << 6)
+#define S5P_FINAL_MCU_NUM_INT_EN_MASK  (0x1 << 5)
+#define S5P_FINAL_MCU_NUM_INT_EN       (0x1 << 5)
+
+/* JPEG interrupt status register */
+#define S5P_JPGINTST                   0x38
+#define S5P_RESULT_STAT_SHIFT          6
+#define S5P_RESULT_STAT_MASK           (0x1 << S5P_RESULT_STAT_SHIFT)
+#define S5P_STREAM_STAT_SHIFT          5
+#define S5P_STREAM_STAT_MASK           (0x1 << S5P_STREAM_STAT_SHIFT)
+
+/* JPEG command register */
+#define S5P_JPGCOM                     0x4c
+#define S5P_INT_RELEASE                        (0x1 << 2)
+
+/* Raw image data r/w address register */
+#define S5P_JPG_IMGADR                 0x50
+
+/* JPEG file r/w address register */
+#define S5P_JPG_JPGADR                 0x58
+
+/* Coefficient for RGB-to-YCbCr converter register */
+#define S5P_JPG_COEF(n)                        (0x5c + (((n) - 1) << 2))
+#define S5P_COEFn_SHIFT(j)             ((3 - (j)) << 3)
+#define S5P_COEFn_MASK(j)              (0xff << S5P_COEFn_SHIFT(j))
+
+/* JPEG color mode register */
+#define S5P_JPGCMOD                    0x68
+#define S5P_MOD_SEL_MASK               (0x7 << 5)
+#define S5P_MOD_SEL_422                        (0x1 << 5)
+#define S5P_MOD_SEL_565                        (0x2 << 5)
+#define S5P_MODE_Y16_MASK              (0x1 << 1)
+#define S5P_MODE_Y16                   (0x1 << 1)
+
+/* JPEG clock control register */
+#define S5P_JPGCLKCON                  0x6c
+#define S5P_CLK_DOWN_READY             (0x1 << 1)
+#define S5P_POWER_ON                   (0x1 << 0)
+
+/* JPEG start register */
+#define S5P_JSTART                     0x70
+
+/* JPEG SW reset register */
+#define S5P_JPG_SW_RESET               0x78
+
+/* JPEG timer setting register */
+#define S5P_JPG_TIMER_SE               0x7c
+#define S5P_TIMER_INT_EN_MASK          (0x1 << 31)
+#define S5P_TIMER_INT_EN               (0x1 << 31)
+#define S5P_TIMER_INIT_MASK            0x7fffffff
+
+/* JPEG timer status register */
+#define S5P_JPG_TIMER_ST               0x80
+#define S5P_TIMER_INT_STAT_SHIFT       31
+#define S5P_TIMER_INT_STAT_MASK                (0x1 << S5P_TIMER_INT_STAT_SHIFT)
+#define S5P_TIMER_CNT_SHIFT            0
+#define S5P_TIMER_CNT_MASK             0x7fffffff
+
+/* JPEG decompression output format register */
+#define S5P_JPG_OUTFORM                        0x88
+#define S5P_DEC_OUT_FORMAT_MASK                (0x1 << 0)
+#define S5P_DEC_OUT_FORMAT_422         (0x0 << 0)
+#define S5P_DEC_OUT_FORMAT_420         (0x1 << 0)
+
+/* JPEG version register */
+#define S5P_JPG_VERSION                        0x8c
+
+/* JPEG compressed stream size interrupt setting register */
+#define S5P_JPG_ENC_STREAM_INTSE       0x98
+#define S5P_ENC_STREAM_INT_MASK                (0x1 << 24)
+#define S5P_ENC_STREAM_INT_EN          (0x1 << 24)
+#define S5P_ENC_STREAM_BOUND_MASK      0xffffff
+
+/* JPEG compressed stream size interrupt status register */
+#define S5P_JPG_ENC_STREAM_INTST       0x9c
+#define S5P_ENC_STREAM_INT_STAT_MASK   0x1
+
+/* JPEG quantizer table register */
+#define S5P_JPG_QTBL_CONTENT(n)                (0x400 + (n) * 0x100)
+
+/* JPEG DC Huffman table register */
+#define S5P_JPG_HDCTBL(n)              (0x800 + (n) * 0x400)
+
+/* JPEG DC Huffman table register */
+#define S5P_JPG_HDCTBLG(n)             (0x840 + (n) * 0x400)
+
+/* JPEG AC Huffman table register */
+#define S5P_JPG_HACTBL(n)              (0x880 + (n) * 0x400)
+
+/* JPEG AC Huffman table register */
+#define S5P_JPG_HACTBLG(n)             (0x8c0 + (n) * 0x400)
+
+#endif /* JPEG_REGS_H_ */
+
index 8be8b54eb749769449a49f68fcf23f57b3628bd9..83fe461af263529df7502f020886f58d63b68c1c 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/platform_device.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <linux/workqueue.h>
 #include <media/videobuf2-core.h>
@@ -475,7 +474,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
                        ctx->mv_size = 0;
                }
                ctx->dpb_count = s5p_mfc_get_dpb_count();
-               if (ctx->img_width == 0 || ctx->img_width == 0)
+               if (ctx->img_width == 0 || ctx->img_height == 0)
                        ctx->state = MFCINST_ERROR;
                else
                        ctx->state = MFCINST_HEAD_PARSED;
@@ -1245,27 +1244,7 @@ static struct platform_driver s5p_mfc_driver = {
        },
 };
 
-static char banner[] __initdata =
-                       "S5P MFC V4L2 Driver, (C) 2011 Samsung Electronics\n";
-
-static int __init s5p_mfc_init(void)
-{
-       int ret;
-
-       pr_info("%s", banner);
-       ret = platform_driver_register(&s5p_mfc_driver);
-       if (ret)
-               pr_err("Platform device registration failed.\n");
-       return ret;
-}
-
-static void __exit s5p_mfc_exit(void)
-{
-       platform_driver_unregister(&s5p_mfc_driver);
-}
-
-module_init(s5p_mfc_init);
-module_exit(s5p_mfc_exit);
+module_platform_driver(s5p_mfc_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
index 844a4d7797bc0be85ff01eae08837d5d49dbee69..c25ec022d2678f734e46b1f1f3b5b0d496150c8d 100644 (file)
@@ -165,7 +165,7 @@ static struct mfc_control controls[] = {
                .maximum = 32,
                .step = 1,
                .default_value = 1,
-               .flags = V4L2_CTRL_FLAG_VOLATILE,
+               .is_volatile = 1,
        },
 };
 
index 0279e6e89febaf74db82d92c5ea783ab557ce187..8b41a0410ab175ab3968ad66036c6290301a6a68 100644 (file)
@@ -838,8 +838,8 @@ static int hdmi_resources_init(struct hdmi_device *hdev)
                dev_err(dev, "failed to get clock 'hdmiphy'\n");
                goto fail;
        }
-       res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
-               sizeof res->regul_bulk[0], GFP_KERNEL);
+       res->regul_bulk = kcalloc(ARRAY_SIZE(supply),
+                                 sizeof(res->regul_bulk[0]), GFP_KERNEL);
        if (!res->regul_bulk) {
                dev_err(dev, "failed to get memory for regulators\n");
                goto fail;
@@ -1016,28 +1016,4 @@ static struct platform_driver hdmi_driver __refdata = {
        }
 };
 
-/* D R I V E R   I N I T I A L I Z A T I O N */
-
-static int __init hdmi_init(void)
-{
-       int ret;
-       static const char banner[] __initdata = KERN_INFO \
-               "Samsung HDMI output driver, "
-               "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
-       printk(banner);
-
-       ret = platform_driver_register(&hdmi_driver);
-       if (ret)
-               printk(KERN_ERR "HDMI platform driver register failed\n");
-
-       return ret;
-}
-module_init(hdmi_init);
-
-static void __exit hdmi_exit(void)
-{
-       platform_driver_unregister(&hdmi_driver);
-}
-module_exit(hdmi_exit);
-
-
+module_platform_driver(hdmi_driver);
index 51ad59b30358aa7e869a94d6d68df581e2d7b539..1597078c4a5070043270d1b54b9d980ba6cadc90 100644 (file)
@@ -86,6 +86,17 @@ struct mxr_crop {
        unsigned int field;
 };
 
+/** stages of geometry operations */
+enum mxr_geometry_stage {
+       MXR_GEOMETRY_SINK,
+       MXR_GEOMETRY_COMPOSE,
+       MXR_GEOMETRY_CROP,
+       MXR_GEOMETRY_SOURCE,
+};
+
+/* flag indicating that offset should be 0 */
+#define MXR_NO_OFFSET  0x80000000
+
 /** description of transformation from source to destination image */
 struct mxr_geometry {
        /** cropping for source image */
@@ -133,7 +144,8 @@ struct mxr_layer_ops {
        /** streaming stop/start */
        void (*stream_set)(struct mxr_layer *, int);
        /** adjusting geometry */
-       void (*fix_geometry)(struct mxr_layer *);
+       void (*fix_geometry)(struct mxr_layer *,
+               enum mxr_geometry_stage, unsigned long);
 };
 
 /** layer instance, a single window and content displayed on output */
index de8270c2b6e7d408569d1c731f9549579153b548..b93a21f5aa131656cbc62649e164031ca3a08c86 100644 (file)
@@ -101,47 +101,132 @@ static void mxr_graph_format_set(struct mxr_layer *layer)
                layer->fmt, &layer->geo);
 }
 
-static void mxr_graph_fix_geometry(struct mxr_layer *layer)
+static inline unsigned int closest(unsigned int x, unsigned int a,
+       unsigned int b, unsigned long flags)
+{
+       unsigned int mid = (a + b) / 2;
+
+       /* choosing closest value with constraints according to table:
+        * -------------+-----+-----+-----+-------+
+        * flags        |  0  |  LE |  GE | LE|GE |
+        * -------------+-----+-----+-----+-------+
+        * x <= a       |  a  |  a  |  a  |   a   |
+        * a < x <= mid |  a  |  a  |  b  |   a   |
+        * mid < x < b  |  b  |  a  |  b  |   b   |
+        * b <= x       |  b  |  b  |  b  |   b   |
+        * -------------+-----+-----+-----+-------+
+        */
+
+       /* remove all non-constraint flags */
+       flags &= V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE;
+
+       if (x <= a)
+               return  a;
+       if (x >= b)
+               return b;
+       if (flags == V4L2_SEL_FLAG_LE)
+               return a;
+       if (flags == V4L2_SEL_FLAG_GE)
+               return b;
+       if (x <= mid)
+               return a;
+       return b;
+}
+
+static inline unsigned int do_center(unsigned int center,
+       unsigned int size, unsigned int upper, unsigned int flags)
+{
+       unsigned int lower;
+
+       if (flags & MXR_NO_OFFSET)
+               return 0;
+
+       lower = center - min(center, size / 2);
+       return min(lower, upper - size);
+}
+
+static void mxr_graph_fix_geometry(struct mxr_layer *layer,
+       enum mxr_geometry_stage stage, unsigned long flags)
 {
        struct mxr_geometry *geo = &layer->geo;
+       struct mxr_crop *src = &geo->src;
+       struct mxr_crop *dst = &geo->dst;
+       unsigned int x_center, y_center;
 
-       /* limit to boundary size */
-       geo->src.full_width = clamp_val(geo->src.full_width, 1, 32767);
-       geo->src.full_height = clamp_val(geo->src.full_height, 1, 2047);
-       geo->src.width = clamp_val(geo->src.width, 1, geo->src.full_width);
-       geo->src.width = min(geo->src.width, 2047U);
-       /* not possible to crop of Y axis */
-       geo->src.y_offset = min(geo->src.y_offset, geo->src.full_height - 1);
-       geo->src.height = geo->src.full_height - geo->src.y_offset;
-       /* limitting offset */
-       geo->src.x_offset = min(geo->src.x_offset,
-               geo->src.full_width - geo->src.width);
-
-       /* setting position in output */
-       geo->dst.width = min(geo->dst.width, geo->dst.full_width);
-       geo->dst.height = min(geo->dst.height, geo->dst.full_height);
-
-       /* Mixer supports only 1x and 2x scaling */
-       if (geo->dst.width >= 2 * geo->src.width) {
-               geo->x_ratio = 1;
-               geo->dst.width = 2 * geo->src.width;
-       } else {
-               geo->x_ratio = 0;
-               geo->dst.width = geo->src.width;
-       }
+       switch (stage) {
 
-       if (geo->dst.height >= 2 * geo->src.height) {
-               geo->y_ratio = 1;
-               geo->dst.height = 2 * geo->src.height;
-       } else {
-               geo->y_ratio = 0;
-               geo->dst.height = geo->src.height;
-       }
+       case MXR_GEOMETRY_SINK: /* nothing to be fixed here */
+               flags = 0;
+               /* fall through */
+
+       case MXR_GEOMETRY_COMPOSE:
+               /* remember center of the area */
+               x_center = dst->x_offset + dst->width / 2;
+               y_center = dst->y_offset + dst->height / 2;
+               /* round up/down to 2 multiple depending on flags */
+               if (flags & V4L2_SEL_FLAG_LE) {
+                       dst->width = round_down(dst->width, 2);
+                       dst->height = round_down(dst->height, 2);
+               } else {
+                       dst->width = round_up(dst->width, 2);
+                       dst->height = round_up(dst->height, 2);
+               }
+               /* assure that compose rect is inside display area */
+               dst->width = min(dst->width, dst->full_width);
+               dst->height = min(dst->height, dst->full_height);
+
+               /* ensure that compose is reachable using 2x scaling */
+               dst->width = min(dst->width, 2 * src->full_width);
+               dst->height = min(dst->height, 2 * src->full_height);
+
+               /* setup offsets */
+               dst->x_offset = do_center(x_center, dst->width,
+                       dst->full_width, flags);
+               dst->y_offset = do_center(y_center, dst->height,
+                       dst->full_height, flags);
+               flags = 0;
+               /* fall through */
 
-       geo->dst.x_offset = min(geo->dst.x_offset,
-               geo->dst.full_width - geo->dst.width);
-       geo->dst.y_offset = min(geo->dst.y_offset,
-               geo->dst.full_height - geo->dst.height);
+       case MXR_GEOMETRY_CROP:
+               /* remember center of the area */
+               x_center = src->x_offset + src->width / 2;
+               y_center = src->y_offset + src->height / 2;
+               /* ensure that cropping area lies inside the buffer */
+               if (src->full_width < dst->width)
+                       src->width = dst->width / 2;
+               else
+                       src->width = closest(src->width, dst->width / 2,
+                               dst->width, flags);
+
+               if (src->width == dst->width)
+                       geo->x_ratio = 0;
+               else
+                       geo->x_ratio = 1;
+
+               if (src->full_height < dst->height)
+                       src->height = dst->height / 2;
+               else
+                       src->height = closest(src->height, dst->height / 2,
+                               dst->height, flags);
+
+               if (src->height == dst->height)
+                       geo->y_ratio = 0;
+               else
+                       geo->y_ratio = 1;
+
+               /* setup offsets */
+               src->x_offset = do_center(x_center, src->width,
+                       src->full_width, flags);
+               src->y_offset = do_center(y_center, src->height,
+                       src->full_height, flags);
+               flags = 0;
+               /* fall through */
+       case MXR_GEOMETRY_SOURCE:
+               src->full_width = clamp_val(src->full_width,
+                       src->width + src->x_offset, 32767);
+               src->full_height = clamp_val(src->full_height,
+                       src->height + src->y_offset, 2047);
+       };
 }
 
 /* PUBLIC API */
index b47d0c06ecf5ab3ee66c911f1d035df1948b31e7..7884baeff76a8748133abda13659aedc48a6dff2 100644 (file)
@@ -170,18 +170,22 @@ static int mxr_querycap(struct file *file, void *priv,
        return 0;
 }
 
-/* Geometry handling */
-static void mxr_layer_geo_fix(struct mxr_layer *layer)
+static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
 {
-       struct mxr_device *mdev = layer->mdev;
-       struct v4l2_mbus_framefmt mbus_fmt;
-
-       /* TODO: add some dirty flag to avoid unnecessary adjustments */
-       mxr_get_mbus_fmt(mdev, &mbus_fmt);
-       layer->geo.dst.full_width = mbus_fmt.width;
-       layer->geo.dst.full_height = mbus_fmt.height;
-       layer->geo.dst.field = mbus_fmt.field;
-       layer->ops.fix_geometry(layer);
+       mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
+               geo->src.full_width, geo->src.full_height);
+       mxr_dbg(mdev, "src.size = (%u, %u)\n",
+               geo->src.width, geo->src.height);
+       mxr_dbg(mdev, "src.offset = (%u, %u)\n",
+               geo->src.x_offset, geo->src.y_offset);
+       mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
+               geo->dst.full_width, geo->dst.full_height);
+       mxr_dbg(mdev, "dst.size = (%u, %u)\n",
+               geo->dst.width, geo->dst.height);
+       mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
+               geo->dst.x_offset, geo->dst.y_offset);
+       mxr_dbg(mdev, "ratio = (%u, %u)\n",
+               geo->x_ratio, geo->y_ratio);
 }
 
 static void mxr_layer_default_geo(struct mxr_layer *layer)
@@ -204,27 +208,29 @@ static void mxr_layer_default_geo(struct mxr_layer *layer)
        layer->geo.src.width = layer->geo.src.full_width;
        layer->geo.src.height = layer->geo.src.full_height;
 
-       layer->ops.fix_geometry(layer);
+       mxr_geometry_dump(mdev, &layer->geo);
+       layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0);
+       mxr_geometry_dump(mdev, &layer->geo);
 }
 
-static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
+static void mxr_layer_update_output(struct mxr_layer *layer)
 {
-       mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
-               geo->src.full_width, geo->src.full_height);
-       mxr_dbg(mdev, "src.size = (%u, %u)\n",
-               geo->src.width, geo->src.height);
-       mxr_dbg(mdev, "src.offset = (%u, %u)\n",
-               geo->src.x_offset, geo->src.y_offset);
-       mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
-               geo->dst.full_width, geo->dst.full_height);
-       mxr_dbg(mdev, "dst.size = (%u, %u)\n",
-               geo->dst.width, geo->dst.height);
-       mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
-               geo->dst.x_offset, geo->dst.y_offset);
-       mxr_dbg(mdev, "ratio = (%u, %u)\n",
-               geo->x_ratio, geo->y_ratio);
-}
+       struct mxr_device *mdev = layer->mdev;
+       struct v4l2_mbus_framefmt mbus_fmt;
+
+       mxr_get_mbus_fmt(mdev, &mbus_fmt);
+       /* checking if update is needed */
+       if (layer->geo.dst.full_width == mbus_fmt.width &&
+               layer->geo.dst.full_height == mbus_fmt.width)
+               return;
 
+       layer->geo.dst.full_width = mbus_fmt.width;
+       layer->geo.dst.full_height = mbus_fmt.height;
+       layer->geo.dst.field = mbus_fmt.field;
+       layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0);
+
+       mxr_geometry_dump(mdev, &layer->geo);
+}
 
 static const struct mxr_format *find_format_by_fourcc(
        struct mxr_layer *layer, unsigned long fourcc);
@@ -249,37 +255,6 @@ static int mxr_enum_fmt(struct file *file, void  *priv,
        return 0;
 }
 
-static int mxr_s_fmt(struct file *file, void *priv,
-       struct v4l2_format *f)
-{
-       struct mxr_layer *layer = video_drvdata(file);
-       const struct mxr_format *fmt;
-       struct v4l2_pix_format_mplane *pix;
-       struct mxr_device *mdev = layer->mdev;
-       struct mxr_geometry *geo = &layer->geo;
-
-       mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
-
-       pix = &f->fmt.pix_mp;
-       fmt = find_format_by_fourcc(layer, pix->pixelformat);
-       if (fmt == NULL) {
-               mxr_warn(mdev, "not recognized fourcc: %08x\n",
-                       pix->pixelformat);
-               return -EINVAL;
-       }
-       layer->fmt = fmt;
-       geo->src.full_width = pix->width;
-       geo->src.width = pix->width;
-       geo->src.full_height = pix->height;
-       geo->src.height = pix->height;
-       /* assure consistency of geometry */
-       mxr_layer_geo_fix(layer);
-       mxr_dbg(mdev, "width=%u height=%u span=%u\n",
-               geo->src.width, geo->src.height, geo->src.full_width);
-
-       return 0;
-}
-
 static unsigned int divup(unsigned int divident, unsigned int divisor)
 {
        return (divident + divisor - 1) / divisor;
@@ -299,6 +274,10 @@ static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
 {
        int i;
 
+       /* checking if nothing to fill */
+       if (!planes)
+               return;
+
        memset(planes, 0, sizeof(*planes) * fmt->num_subframes);
        for (i = 0; i < fmt->num_planes; ++i) {
                struct v4l2_plane_pix_format *plane = planes
@@ -332,73 +311,194 @@ static int mxr_g_fmt(struct file *file, void *priv,
        return 0;
 }
 
-static inline struct mxr_crop *choose_crop_by_type(struct mxr_geometry *geo,
-       enum v4l2_buf_type type)
-{
-       switch (type) {
-       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-               return &geo->dst;
-       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               return &geo->src;
-       default:
-               return NULL;
-       }
-}
-
-static int mxr_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+static int mxr_s_fmt(struct file *file, void *priv,
+       struct v4l2_format *f)
 {
        struct mxr_layer *layer = video_drvdata(file);
-       struct mxr_crop *crop;
+       const struct mxr_format *fmt;
+       struct v4l2_pix_format_mplane *pix;
+       struct mxr_device *mdev = layer->mdev;
+       struct mxr_geometry *geo = &layer->geo;
 
-       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
-       crop = choose_crop_by_type(&layer->geo, a->type);
-       if (crop == NULL)
+       mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+
+       pix = &f->fmt.pix_mp;
+       fmt = find_format_by_fourcc(layer, pix->pixelformat);
+       if (fmt == NULL) {
+               mxr_warn(mdev, "not recognized fourcc: %08x\n",
+                       pix->pixelformat);
                return -EINVAL;
-       mxr_layer_geo_fix(layer);
-       a->c.left = crop->x_offset;
-       a->c.top = crop->y_offset;
-       a->c.width = crop->width;
-       a->c.height = crop->height;
+       }
+       layer->fmt = fmt;
+       /* set source size to highest accepted value */
+       geo->src.full_width = max(geo->dst.full_width, pix->width);
+       geo->src.full_height = max(geo->dst.full_height, pix->height);
+       layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0);
+       mxr_geometry_dump(mdev, &layer->geo);
+       /* set cropping to total visible screen */
+       geo->src.width = pix->width;
+       geo->src.height = pix->height;
+       geo->src.x_offset = 0;
+       geo->src.y_offset = 0;
+       /* assure consistency of geometry */
+       layer->ops.fix_geometry(layer, MXR_GEOMETRY_CROP, MXR_NO_OFFSET);
+       mxr_geometry_dump(mdev, &layer->geo);
+       /* set full size to lowest possible value */
+       geo->src.full_width = 0;
+       geo->src.full_height = 0;
+       layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0);
+       mxr_geometry_dump(mdev, &layer->geo);
+
+       /* returning results */
+       mxr_g_fmt(file, priv, f);
+
        return 0;
 }
 
-static int mxr_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+static int mxr_g_selection(struct file *file, void *fh,
+       struct v4l2_selection *s)
 {
        struct mxr_layer *layer = video_drvdata(file);
-       struct mxr_crop *crop;
+       struct mxr_geometry *geo = &layer->geo;
 
        mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
-       crop = choose_crop_by_type(&layer->geo, a->type);
-       if (crop == NULL)
+
+       if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+               s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return -EINVAL;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP_ACTIVE:
+               s->r.left = geo->src.x_offset;
+               s->r.top = geo->src.y_offset;
+               s->r.width = geo->src.width;
+               s->r.height = geo->src.height;
+               break;
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = geo->src.full_width;
+               s->r.height = geo->src.full_height;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+       case V4L2_SEL_TGT_COMPOSE_PADDED:
+               s->r.left = geo->dst.x_offset;
+               s->r.top = geo->dst.y_offset;
+               s->r.width = geo->dst.width;
+               s->r.height = geo->dst.height;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = geo->dst.full_width;
+               s->r.height = geo->dst.full_height;
+               break;
+       default:
                return -EINVAL;
-       crop->x_offset = a->c.left;
-       crop->y_offset = a->c.top;
-       crop->width = a->c.width;
-       crop->height = a->c.height;
-       mxr_layer_geo_fix(layer);
+       }
+
        return 0;
 }
 
-static int mxr_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+/* returns 1 if rectangle 'a' is inside 'b' */
+static int mxr_is_rect_inside(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+       if (a->left < b->left)
+               return 0;
+       if (a->top < b->top)
+               return 0;
+       if (a->left + a->width > b->left + b->width)
+               return 0;
+       if (a->top + a->height > b->top + b->height)
+               return 0;
+       return 1;
+}
+
+static int mxr_s_selection(struct file *file, void *fh,
+       struct v4l2_selection *s)
 {
        struct mxr_layer *layer = video_drvdata(file);
-       struct mxr_crop *crop;
+       struct mxr_geometry *geo = &layer->geo;
+       struct mxr_crop *target = NULL;
+       enum mxr_geometry_stage stage;
+       struct mxr_geometry tmp;
+       struct v4l2_rect res;
 
-       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
-       crop = choose_crop_by_type(&layer->geo, a->type);
-       if (crop == NULL)
+       memset(&res, 0, sizeof res);
+
+       mxr_dbg(layer->mdev, "%s: rect: %dx%d@%d,%d\n", __func__,
+               s->r.width, s->r.height, s->r.left, s->r.top);
+
+       if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+               s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
                return -EINVAL;
-       mxr_layer_geo_fix(layer);
-       a->bounds.left = 0;
-       a->bounds.top = 0;
-       a->bounds.width = crop->full_width;
-       a->bounds.top = crop->full_height;
-       a->defrect = a->bounds;
-       /* setting pixel aspect to 1/1 */
-       a->pixelaspect.numerator = 1;
-       a->pixelaspect.denominator = 1;
+
+       switch (s->target) {
+       /* ignore read-only targets */
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               res.width = geo->src.full_width;
+               res.height = geo->src.full_height;
+               break;
+
+       /* ignore read-only targets */
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               res.width = geo->dst.full_width;
+               res.height = geo->dst.full_height;
+               break;
+
+       case V4L2_SEL_TGT_CROP_ACTIVE:
+               target = &geo->src;
+               stage = MXR_GEOMETRY_CROP;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+       case V4L2_SEL_TGT_COMPOSE_PADDED:
+               target = &geo->dst;
+               stage = MXR_GEOMETRY_COMPOSE;
+               break;
+       default:
+               return -EINVAL;
+       }
+       /* apply change and update geometry if needed */
+       if (target) {
+               /* backup current geometry if setup fails */
+               memcpy(&tmp, geo, sizeof tmp);
+
+               /* apply requested selection */
+               target->x_offset = s->r.left;
+               target->y_offset = s->r.top;
+               target->width = s->r.width;
+               target->height = s->r.height;
+
+               layer->ops.fix_geometry(layer, stage, s->flags);
+
+               /* retrieve update selection rectangle */
+               res.left = target->x_offset;
+               res.top = target->y_offset;
+               res.width = target->width;
+               res.height = target->height;
+
+               mxr_geometry_dump(layer->mdev, &layer->geo);
+       }
+
+       /* checking if the rectangle satisfies constraints */
+       if ((s->flags & V4L2_SEL_FLAG_LE) && !mxr_is_rect_inside(&res, &s->r))
+               goto fail;
+       if ((s->flags & V4L2_SEL_FLAG_GE) && !mxr_is_rect_inside(&s->r, &res))
+               goto fail;
+
+       /* return result rectangle */
+       s->r = res;
+
        return 0;
+fail:
+       /* restore old geometry, which is not touched if target is NULL */
+       if (target)
+               memcpy(geo, &tmp, sizeof tmp);
+       return -ERANGE;
 }
 
 static int mxr_enum_dv_presets(struct file *file, void *fh,
@@ -438,6 +538,8 @@ static int mxr_s_dv_preset(struct file *file, void *fh,
 
        mutex_unlock(&mdev->mutex);
 
+       mxr_layer_update_output(layer);
+
        /* any failure should return EINVAL according to V4L2 doc */
        return ret ? -EINVAL : 0;
 }
@@ -478,6 +580,8 @@ static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
 
        mutex_unlock(&mdev->mutex);
 
+       mxr_layer_update_output(layer);
+
        return ret ? -EINVAL : 0;
 }
 
@@ -526,25 +630,27 @@ static int mxr_s_output(struct file *file, void *fh, unsigned int i)
        struct video_device *vfd = video_devdata(file);
        struct mxr_layer *layer = video_drvdata(file);
        struct mxr_device *mdev = layer->mdev;
-       int ret = 0;
 
        if (i >= mdev->output_cnt || mdev->output[i] == NULL)
                return -EINVAL;
 
        mutex_lock(&mdev->mutex);
        if (mdev->n_output > 0) {
-               ret = -EBUSY;
-               goto done;
+               mutex_unlock(&mdev->mutex);
+               return -EBUSY;
        }
        mdev->current_output = i;
        vfd->tvnorms = 0;
        v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output,
                &vfd->tvnorms);
+       mutex_unlock(&mdev->mutex);
+
+       /* update layers geometry */
+       mxr_layer_update_output(layer);
+
        mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms);
 
-done:
-       mutex_unlock(&mdev->mutex);
-       return ret;
+       return 0;
 }
 
 static int mxr_g_output(struct file *file, void *fh, unsigned int *p)
@@ -633,10 +739,9 @@ static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
        .vidioc_enum_output = mxr_enum_output,
        .vidioc_s_output = mxr_s_output,
        .vidioc_g_output = mxr_g_output,
-       /* Crop ioctls */
-       .vidioc_g_crop = mxr_g_crop,
-       .vidioc_s_crop = mxr_s_crop,
-       .vidioc_cropcap = mxr_cropcap,
+       /* selection ioctls */
+       .vidioc_g_selection = mxr_g_selection,
+       .vidioc_s_selection = mxr_s_selection,
 };
 
 static int mxr_video_open(struct file *file)
@@ -805,10 +910,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
        /* block any changes in output configuration */
        mxr_output_get(mdev);
 
-       /* update layers geometry */
-       mxr_layer_geo_fix(layer);
-       mxr_geometry_dump(mdev, &layer->geo);
-
+       mxr_layer_update_output(layer);
        layer->ops.format_set(layer);
        /* enabling layer in hardware */
        spin_lock_irqsave(&layer->enq_slock, flags);
index f3bb2e34cb517d11bdb1dd11d716cb18255f0e4b..3d13a636877be73ce50079a3d286014b6182b3c3 100644 (file)
@@ -127,47 +127,77 @@ static void mxr_vp_format_set(struct mxr_layer *layer)
        mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo);
 }
 
-static void mxr_vp_fix_geometry(struct mxr_layer *layer)
+static inline unsigned int do_center(unsigned int center,
+       unsigned int size, unsigned int upper, unsigned int flags)
 {
-       struct mxr_geometry *geo = &layer->geo;
+       unsigned int lower;
+
+       if (flags & MXR_NO_OFFSET)
+               return 0;
+
+       lower = center - min(center, size / 2);
+       return min(lower, upper - size);
+}
 
-       /* align horizontal size to 8 pixels */
-       geo->src.full_width = ALIGN(geo->src.full_width, 8);
-       /* limit to boundary size */
-       geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192);
-       geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192);
-       geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width);
-       geo->src.width = min(geo->src.width, 2047U);
-       geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height);
-       geo->src.height = min(geo->src.height, 2047U);
-
-       /* setting size of output window */
-       geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width);
-       geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height);
-
-       /* ensure that scaling is in range 1/4x to 16x */
-       if (geo->src.width >= 4 * geo->dst.width)
-               geo->src.width = 4 * geo->dst.width;
-       if (geo->dst.width >= 16 * geo->src.width)
-               geo->dst.width = 16 * geo->src.width;
-       if (geo->src.height >= 4 * geo->dst.height)
-               geo->src.height = 4 * geo->dst.height;
-       if (geo->dst.height >= 16 * geo->src.height)
-               geo->dst.height = 16 * geo->src.height;
-
-       /* setting scaling ratio */
-       geo->x_ratio = (geo->src.width << 16) / geo->dst.width;
-       geo->y_ratio = (geo->src.height << 16) / geo->dst.height;
-
-       /* adjust offsets */
-       geo->src.x_offset = min(geo->src.x_offset,
-               geo->src.full_width - geo->src.width);
-       geo->src.y_offset = min(geo->src.y_offset,
-               geo->src.full_height - geo->src.height);
-       geo->dst.x_offset = min(geo->dst.x_offset,
-               geo->dst.full_width - geo->dst.width);
-       geo->dst.y_offset = min(geo->dst.y_offset,
-               geo->dst.full_height - geo->dst.height);
+static void mxr_vp_fix_geometry(struct mxr_layer *layer,
+       enum mxr_geometry_stage stage, unsigned long flags)
+{
+       struct mxr_geometry *geo = &layer->geo;
+       struct mxr_crop *src = &geo->src;
+       struct mxr_crop *dst = &geo->dst;
+       unsigned long x_center, y_center;
+
+       switch (stage) {
+
+       case MXR_GEOMETRY_SINK: /* nothing to be fixed here */
+       case MXR_GEOMETRY_COMPOSE:
+               /* remember center of the area */
+               x_center = dst->x_offset + dst->width / 2;
+               y_center = dst->y_offset + dst->height / 2;
+
+               /* ensure that compose is reachable using 16x scaling */
+               dst->width = clamp(dst->width, 8U, 16 * src->full_width);
+               dst->height = clamp(dst->height, 1U, 16 * src->full_height);
+
+               /* setup offsets */
+               dst->x_offset = do_center(x_center, dst->width,
+                       dst->full_width, flags);
+               dst->y_offset = do_center(y_center, dst->height,
+                       dst->full_height, flags);
+               flags = 0; /* remove possible MXR_NO_OFFSET flag */
+               /* fall through */
+       case MXR_GEOMETRY_CROP:
+               /* remember center of the area */
+               x_center = src->x_offset + src->width / 2;
+               y_center = src->y_offset + src->height / 2;
+
+               /* ensure scaling is between 0.25x .. 16x */
+               src->width = clamp(src->width, round_up(dst->width / 16, 4),
+                       dst->width * 4);
+               src->height = clamp(src->height, round_up(dst->height / 16, 4),
+                       dst->height * 4);
+
+               /* hardware limits */
+               src->width = clamp(src->width, 32U, 2047U);
+               src->height = clamp(src->height, 4U, 2047U);
+
+               /* setup offsets */
+               src->x_offset = do_center(x_center, src->width,
+                       src->full_width, flags);
+               src->y_offset = do_center(y_center, src->height,
+                       src->full_height, flags);
+
+               /* setting scaling ratio */
+               geo->x_ratio = (src->width << 16) / dst->width;
+               geo->y_ratio = (src->height << 16) / dst->height;
+               /* fall through */
+
+       case MXR_GEOMETRY_SOURCE:
+               src->full_width = clamp(src->full_width,
+                       ALIGN(src->width + src->x_offset, 8), 8192U);
+               src->full_height = clamp(src->full_height,
+                       src->height + src->y_offset, 8192U);
+       };
 }
 
 /* PUBLIC API */
index 8cec67ef48c9214b0f529039e905de235bca219c..059e7749ce95322962a58c0b411fe33007293a58 100644 (file)
@@ -457,24 +457,4 @@ static struct platform_driver sdo_driver __refdata = {
        }
 };
 
-static int __init sdo_init(void)
-{
-       int ret;
-       static const char banner[] __initdata = KERN_INFO \
-               "Samsung Standard Definition Output (SDO) driver, "
-               "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
-       printk(banner);
-
-       ret = platform_driver_register(&sdo_driver);
-       if (ret)
-               printk(KERN_ERR "SDO platform driver register failed\n");
-
-       return ret;
-}
-module_init(sdo_init);
-
-static void __exit sdo_exit(void)
-{
-       platform_driver_unregister(&sdo_driver);
-}
-module_exit(sdo_exit);
+module_platform_driver(sdo_driver);
index 5cfdbc78b91848df1305feef404c5677d587e260..0ef5484696b647a653c82744061c03f203a29fb7 100644 (file)
@@ -57,7 +57,7 @@ MODULE_AUTHOR(  "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
                "Hans Verkuil, Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL");
 
-static int debug;
+static bool debug;
 module_param(debug, bool, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
index 0f9fb99adeb4e06224445f42d25546038b0bf878..065d0f6be4a061121eed47c5956ad5953980383b 100644 (file)
@@ -5691,6 +5691,27 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = LINE1,
                },
        },
+       [SAA7134_BOARD_SENSORAY811_911] = {
+               .name           = "Sensoray 811/911",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .inputs         = {{
+                       .name   = name_comp1,
+                       .vmux   = 0,
+                       .amux   = LINE1,
+               }, {
+                       .name   = name_comp3,
+                       .vmux   = 2,
+                       .amux   = LINE1,
+               }, {
+                       .name   = name_svideo,
+                       .vmux   = 8,
+                       .amux   = LINE1,
+               } },
+       },
 
 };
 
@@ -6913,6 +6934,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x17de,
                .subdevice    = 0xd136,
                .driver_data  = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x6000,
+               .subdevice    = 0x0811,
+               .driver_data  = SAA7134_BOARD_SENSORAY811_911,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x6000,
+               .subdevice    = 0x0911,
+               .driver_data  = SAA7134_BOARD_SENSORAY811_911,
        }, {
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
index ca65cda3e101880d63b1c002412af0f80a6561a2..5fbb4e49495c8278f25da91b4dca454c405e5dc0 100644 (file)
@@ -1263,7 +1263,6 @@ static int saa7134_resume(struct pci_dev *pci_dev)
        saa7134_tvaudio_setmute(dev);
        saa7134_tvaudio_setvolume(dev, dev->ctl_volume);
        saa7134_tvaudio_init(dev);
-       saa7134_tvaudio_do_scan(dev);
        saa7134_enable_i2s(dev);
        saa7134_hw_enable2(dev);
 
index 1e4ef16698879f5904fd7b378a4883f48b987640..089fa0fb5c94d359c1a91ce9c5b2630a209a0991 100644 (file)
@@ -183,9 +183,9 @@ static int mt352_avermedia_xc3028_init(struct dvb_frontend *fe)
        return 0;
 }
 
-static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
-                                          struct dvb_frontend_parameters* params)
+static int mt352_pinnacle_tuner_set_params(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        u8 off[] = { 0x00, 0xf1};
        u8 on[]  = { 0x00, 0x71};
        struct i2c_msg msg = {.addr=0x43, .flags=0, .buf=off, .len = sizeof(off)};
@@ -196,7 +196,7 @@ static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
        /* set frequency (mt2050) */
        f.tuner     = 0;
        f.type      = V4L2_TUNER_DIGITAL_TV;
-       f.frequency = params->frequency / 1000 * 16 / 1000;
+       f.frequency = c->frequency / 1000 * 16 / 1000;
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(&dev->i2c_adap, &msg, 1);
@@ -287,8 +287,9 @@ static int philips_tda1004x_request_firmware(struct dvb_frontend *fe,
  * these tuners are tu1216, td1316(a)
  */
 
-static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda6651_pll_set(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct saa7134_dev *dev = fe->dvb->priv;
        struct tda1004x_state *state = fe->demodulator_priv;
        u8 addr = state->config->tuner_address;
@@ -299,7 +300,7 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
        u8 band, cp, filter;
 
        /* determine charge pump */
-       tuner_frequency = params->frequency + 36166000;
+       tuner_frequency = c->frequency + 36166000;
        if (tuner_frequency < 87000000)
                return -EINVAL;
        else if (tuner_frequency < 130000000)
@@ -324,28 +325,28 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
                return -EINVAL;
 
        /* determine band */
-       if (params->frequency < 49000000)
+       if (c->frequency < 49000000)
                return -EINVAL;
-       else if (params->frequency < 161000000)
+       else if (c->frequency < 161000000)
                band = 1;
-       else if (params->frequency < 444000000)
+       else if (c->frequency < 444000000)
                band = 2;
-       else if (params->frequency < 861000000)
+       else if (c->frequency < 861000000)
                band = 4;
        else
                return -EINVAL;
 
        /* setup PLL filter */
-       switch (params->u.ofdm.bandwidth) {
-       case BANDWIDTH_6_MHZ:
+       switch (c->bandwidth_hz) {
+       case 6000000:
                filter = 0;
                break;
 
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                filter = 0;
                break;
 
-       case BANDWIDTH_8_MHZ:
+       case 8000000:
                filter = 1;
                break;
 
@@ -356,7 +357,7 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
        /* calculate divisor
         * ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
         */
-       tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000;
+       tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000;
 
        /* setup tuner buffer */
        tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
@@ -436,9 +437,9 @@ static int philips_td1316_tuner_init(struct dvb_frontend *fe)
        return 0;
 }
 
-static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_td1316_tuner_set_params(struct dvb_frontend *fe)
 {
-       return philips_tda6651_pll_set(fe, params);
+       return philips_tda6651_pll_set(fe);
 }
 
 static int philips_td1316_tuner_sleep(struct dvb_frontend *fe)
index d4ee24bf692820dd0f58004d480d010d1be18c29..22ecd7297d2d3d8465e66336ce1a081408b00cff 100644 (file)
@@ -235,22 +235,25 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 
 static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
-       unsigned char buf[5], cod4, code3, code4;
+       unsigned char buf[5];
 
        /* poll IR chip */
        if (5 != i2c_master_recv(ir->c, buf, 5))
                return -EIO;
 
-       cod4    = buf[4];
-       code4   = (cod4 >> 2);
-       code3   = buf[3];
-       if (code3 == 0)
-               /* no key pressed */
+       /* Check if some key were pressed */
+       if (!(buf[0] & 0x80))
                return 0;
 
-       /* return key */
-       *ir_key = code4;
-       *ir_raw = code4;
+       /*
+        * buf[3] & 0x80 is always high.
+        * buf[3] & 0x40 is a parity bit. A repeat event is marked
+        * by preserving it into two separate readings
+        * buf[4] bits 0 and 1, and buf[1] and buf[2] are always
+        * zero.
+        */
+       *ir_key = 0x1fff & ((buf[3] << 8) | (buf[4] >> 2));
+       *ir_raw = *ir_key;
        return 1;
 }
 
@@ -752,7 +755,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                polling      = 50; /* ms */
                break;
        case SAA7134_BOARD_VIDEOMATE_M1F:
-               ir_codes     = RC_MAP_VIDEOMATE_M1F;
+               ir_codes     = RC_MAP_VIDEOMATE_K100;
                mask_keycode = 0x0ff00;
                mask_keyup   = 0x040000;
                break;
index 57e646bb48b394008e42b686922dc3233554fb9f..b7a99bee2f98b404abbb398e3db48131ca132b64 100644 (file)
@@ -332,6 +332,13 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan)
 {
        __s32 left,right,value;
 
+       if (!(dev->tvnorm->id & scan->std)) {
+               value = 0;
+               dprintk("skipping %d.%03d MHz [%4s]\n",
+                       scan->carr / 1000, scan->carr % 1000, scan->name);
+               return 0;
+       }
+
        if (audio_debug > 1) {
                int i;
                dprintk("debug %d:",scan->carr);
@@ -348,30 +355,25 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan)
                }
                printk("\n");
        }
-       if (dev->tvnorm->id & scan->std) {
-               tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90);
-               saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
-               if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
-                       return -1;
-               left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
-
-               tvaudio_setcarrier(dev,scan->carr+90,scan->carr+90);
-               saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
-               if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
-                       return -1;
-               right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
-
-               left >>= 16;
-               right >>= 16;
-               value = left > right ? left - right : right - left;
-               dprintk("scanning %d.%03d MHz [%4s] =>  dc is %5d [%d/%d]\n",
-                       scan->carr / 1000, scan->carr % 1000,
-                       scan->name, value, left, right);
-       } else {
-               value = 0;
-               dprintk("skipping %d.%03d MHz [%4s]\n",
-                       scan->carr / 1000, scan->carr % 1000, scan->name);
-       }
+
+       tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90);
+       saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+       if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+               return -1;
+       left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+
+       tvaudio_setcarrier(dev,scan->carr+90,scan->carr+90);
+       saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+       if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+               return -1;
+       right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+
+       left >>= 16;
+       right >>= 16;
+       value = left > right ? left - right : right - left;
+       dprintk("scanning %d.%03d MHz [%4s] =>  dc is %5d [%d/%d]\n",
+               scan->carr / 1000, scan->carr % 1000,
+               scan->name, value, left, right);
        return value;
 }
 
@@ -546,6 +548,7 @@ static int tvaudio_thread(void *data)
                                dev->tvnorm->name, carrier/1000, carrier%1000,
                                max1, max2);
                        dev->last_carrier = carrier;
+                       dev->automute = 0;
 
                } else if (0 != dev->last_carrier) {
                        /* no carrier -- try last detected one as fallback */
@@ -553,6 +556,7 @@ static int tvaudio_thread(void *data)
                        dprintk("audio carrier scan failed, "
                                "using %d.%03d MHz [last detected]\n",
                                carrier/1000, carrier%1000);
+                       dev->automute = 1;
 
                } else {
                        /* no carrier + no fallback -- use default */
@@ -560,9 +564,9 @@ static int tvaudio_thread(void *data)
                        dprintk("audio carrier scan failed, "
                                "using %d.%03d MHz [default]\n",
                                carrier/1000, carrier%1000);
+                       dev->automute = 1;
                }
                tvaudio_setcarrier(dev,carrier,carrier);
-               dev->automute = 0;
                saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00);
                saa7134_tvaudio_setmute(dev);
                /* find the exact tv audio norm */
@@ -601,7 +605,7 @@ static int tvaudio_thread(void *data)
                        if (kthread_should_stop())
                                break;
                        if (UNSET == dev->thread.mode) {
-                               rx = tvaudio_getstereo(dev,&tvaudio[i]);
+                               rx = tvaudio_getstereo(dev, &tvaudio[audio]);
                                mode = saa7134_tvaudio_rx2mode(rx);
                        } else {
                                mode = dev->thread.mode;
@@ -1020,6 +1024,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
        }
 
        dev->thread.thread = NULL;
+       dev->thread.scan1 = dev->thread.scan2 = 0;
        if (my_thread) {
                saa7134_tvaudio_init(dev);
                /* start tvaudio thread */
@@ -1029,13 +1034,19 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
                               dev->name);
                        /* XXX: missing error handling here */
                }
-               saa7134_tvaudio_do_scan(dev);
        }
 
        saa7134_enable_i2s(dev);
        return 0;
 }
 
+int saa7134_tvaudio_close(struct saa7134_dev *dev)
+{
+       dev->automute = 1;
+       /* anything else to undo? */
+       return 0;
+}
+
 int saa7134_tvaudio_fini(struct saa7134_dev *dev)
 {
        /* shutdown tvaudio thread */
index 9cf7914f6f90eb87c03205650a39396a50b84f38..417034eb6ad258d55cfe10dc0d160e00b9a6130f 100644 (file)
@@ -1462,6 +1462,8 @@ static int video_release(struct file *file)
        struct saa6588_command cmd;
        unsigned long flags;
 
+       saa7134_tvaudio_close(dev);
+
        /* turn off overlay */
        if (res_check(fh, RESOURCE_OVERLAY)) {
                spin_lock_irqsave(&dev->slock,flags);
index 9b550687213a44c7b808ca73bfa6713e05aebb50..42fba4f93c72b95cf1429f2e846b0b608ac2c77b 100644 (file)
@@ -330,6 +330,7 @@ struct saa7134_card_ir {
 #define SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2 185
 #define SAA7134_BOARD_BEHOLD_501            186
 #define SAA7134_BOARD_BEHOLD_503FM          187
+#define SAA7134_BOARD_SENSORAY811_911       188
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
@@ -817,6 +818,7 @@ void saa7134_tvaudio_init(struct saa7134_dev *dev);
 int saa7134_tvaudio_init2(struct saa7134_dev *dev);
 int saa7134_tvaudio_fini(struct saa7134_dev *dev);
 int saa7134_tvaudio_do_scan(struct saa7134_dev *dev);
+int saa7134_tvaudio_close(struct saa7134_dev *dev);
 
 int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value);
 
index 466e1b02f91f42c38c9a8af77d0eb1f9794c55f5..a7f58a9987522c06a45dfcaf3f45ab138f8c3699 100644 (file)
@@ -149,7 +149,7 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
        saa7164_bus_verify(dev);
 
        msg->size = cpu_to_le16(msg->size);
-       msg->command = cpu_to_le16(msg->command);
+       msg->command = cpu_to_le32(msg->command);
        msg->controlselector = cpu_to_le16(msg->controlselector);
 
        if (msg->size > dev->bus.m_wMaxReqSize) {
@@ -464,7 +464,7 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
 
 peekout:
        msg->size = le16_to_cpu(msg->size);
-       msg->command = le16_to_cpu(msg->command);
+       msg->command = le32_to_cpu(msg->command);
        msg->controlselector = le16_to_cpu(msg->controlselector);
        ret = SAA_OK;
 out:
index 971591d6450fccc5a7164adb94cb40e3404fb635..5b72da5ce4183c15bf98dd570762f2f8f2ffb9de 100644 (file)
@@ -269,8 +269,6 @@ struct saa7164_board saa7164_boards[] = {
                .portb          = SAA7164_MPEG_DVB,
                .portc          = SAA7164_MPEG_ENCODER,
                .portd          = SAA7164_MPEG_ENCODER,
-               .portc          = SAA7164_MPEG_ENCODER,
-               .portd          = SAA7164_MPEG_ENCODER,
                .porte          = SAA7164_MPEG_VBI,
                .portf          = SAA7164_MPEG_VBI,
                .chiprev        = SAA7164_CHIP_REV3,
@@ -333,8 +331,6 @@ struct saa7164_board saa7164_boards[] = {
                .portd          = SAA7164_MPEG_ENCODER,
                .porte          = SAA7164_MPEG_VBI,
                .portf          = SAA7164_MPEG_VBI,
-               .porte          = SAA7164_MPEG_VBI,
-               .portf          = SAA7164_MPEG_VBI,
                .chiprev        = SAA7164_CHIP_REV3,
                .unit           = {{
                        .id             = 0x28,
index c51decfcae197cedb83f6d68169cc0a6251f621d..f854d85a387c0956a6cf4caf349ff9a5af056377 100644 (file)
@@ -786,8 +786,7 @@ static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev,
                V4L2_MBUS_DATA_ACTIVE_HIGH)
 
 /* Capture is not running, no interrupts, no locking needed */
-static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
-                                      __u32 pixfmt)
+static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
@@ -925,11 +924,6 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
        ceu_write(pcdev, CDOCR, value);
        ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
 
-       dev_dbg(icd->parent, "S_FMT successful for %c%c%c%c %ux%u\n",
-               pixfmt & 0xff, (pixfmt >> 8) & 0xff,
-               (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
-               icd->user_width, icd->user_height);
-
        capture_restore(pcdev, capsr);
 
        /* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */
@@ -1966,8 +1960,7 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
                if (!ret) {
                        icd->user_width         = out_width & ~3;
                        icd->user_height        = out_height & ~3;
-                       ret = sh_mobile_ceu_set_bus_param(icd,
-                                       icd->current_fmt->host_fmt->fourcc);
+                       ret = sh_mobile_ceu_set_bus_param(icd);
                }
        }
 
index 8a652b53ff7e9a8a1a4ad0f00bf7a874bf8f3bf6..05286500b4d432de590fa206070c2611bcb57a5a 100644 (file)
@@ -390,18 +390,7 @@ static struct platform_driver __refdata sh_csi2_pdrv = {
        },
 };
 
-static int __init sh_csi2_init(void)
-{
-       return platform_driver_register(&sh_csi2_pdrv);
-}
-
-static void __exit sh_csi2_exit(void)
-{
-       platform_driver_unregister(&sh_csi2_pdrv);
-}
-
-module_init(sh_csi2_init);
-module_exit(sh_csi2_exit);
+module_platform_driver(sh_csi2_pdrv);
 
 MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
index 7025be1292864d951607d823b74f1f3c777c08a9..c2882fa5be85f3d0a3eda99648b806860f1b0db9 100644 (file)
@@ -75,8 +75,8 @@ MODULE_PARM_DESC(video_nr,
                 "\none and for every other camera."
                 "\n");
 
-static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
-                              SN9C102_FORCE_MUNMAP};
+static bool force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
+                             SN9C102_FORCE_MUNMAP};
 module_param_array(force_munmap, bool, NULL, 0444);
 MODULE_PARM_DESC(force_munmap,
                 " <0|1[,...]>"
index 62e4312515cb99a5e640cfe440954f1b8f5994cd..b82710745ba8b40fdd3b3f7f1326050541eacad8 100644 (file)
@@ -487,7 +487,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
                icd->user_width, icd->user_height);
 
        /* set physical bus parameters */
-       return ici->ops->set_bus_param(icd, pix->pixelformat);
+       return ici->ops->set_bus_param(icd);
 }
 
 static int soc_camera_open(struct file *file)
@@ -600,9 +600,9 @@ static int soc_camera_close(struct file *file)
                pm_runtime_suspend(&icd->vdev->dev);
                pm_runtime_disable(&icd->vdev->dev);
 
-               ici->ops->remove(icd);
                if (ici->ops->init_videobuf2)
                        vb2_queue_release(&icd->vb2_vidq);
+               ici->ops->remove(icd);
 
                soc_camera_power_off(icd, icl);
        }
index 4402a8a74f7a727fc7dd87492a98b5c8ad426d7a..f59ccade07c8b5cb9a0c3ebb4c4bdb539e2cbea8 100644 (file)
@@ -189,18 +189,7 @@ static struct platform_driver soc_camera_platform_driver = {
        .remove         = soc_camera_platform_remove,
 };
 
-static int __init soc_camera_platform_module_init(void)
-{
-       return platform_driver_register(&soc_camera_platform_driver);
-}
-
-static void __exit soc_camera_platform_module_exit(void)
-{
-       platform_driver_unregister(&soc_camera_platform_driver);
-}
-
-module_init(soc_camera_platform_module_init);
-module_exit(soc_camera_platform_module_exit);
+module_platform_driver(soc_camera_platform_driver);
 
 MODULE_DESCRIPTION("SoC Camera Platform driver");
 MODULE_AUTHOR("Magnus Damm");
index b7fb5a5cad7e7582690acbb6443a1e2c1bfa0d10..d427f8436c70468721140d655eb00196d9ccf80b 100644 (file)
 #include "stk-webcam.h"
 
 
-static int hflip = 1;
+static bool hflip = 1;
 module_param(hflip, bool, 0444);
 MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1");
 
-static int vflip = 1;
+static bool vflip = 1;
 module_param(vflip, bool, 0444);
 MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1");
 
@@ -377,8 +377,8 @@ static int stk_prepare_iso(struct stk_camera *dev)
        if (dev->isobufs)
                STK_ERROR("isobufs already allocated. Bad\n");
        else
-               dev->isobufs = kzalloc(MAX_ISO_BUFS * sizeof(*dev->isobufs),
-                                       GFP_KERNEL);
+               dev->isobufs = kcalloc(MAX_ISO_BUFS, sizeof(*dev->isobufs),
+                                      GFP_KERNEL);
        if (dev->isobufs == NULL) {
                STK_ERROR("Unable to allocate iso buffers\n");
                return -ENOMEM;
index a0895bf07487847c921505e7d119dfa434c40037..4ed1c7c28ae704b4f1e843cb8db0ae7b74981c02 100644 (file)
@@ -565,7 +565,7 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
        spin_unlock_irq(&fh->queue_lock);
 
        desc = fh->chan->device->device_prep_slave_sg(fh->chan,
-               buf->sg, sg_elems, DMA_FROM_DEVICE,
+               buf->sg, sg_elems, DMA_DEV_TO_MEM,
                DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
        if (!desc) {
                spin_lock_irq(&fh->queue_lock);
@@ -872,20 +872,7 @@ static struct platform_driver timblogiw_platform_driver = {
        .remove         = __devexit_p(timblogiw_remove),
 };
 
-/* Module functions */
-
-static int __init timblogiw_init(void)
-{
-       return platform_driver_register(&timblogiw_platform_driver);
-}
-
-static void __exit timblogiw_exit(void)
-{
-       platform_driver_unregister(&timblogiw_platform_driver);
-}
-
-module_init(timblogiw_init);
-module_exit(timblogiw_exit);
+module_platform_driver(timblogiw_platform_driver);
 
 MODULE_DESCRIPTION(TIMBLOGIWIN_NAME);
 MODULE_AUTHOR("Pelagicore AB <info@pelagicore.com>");
index 56564e6aaac2b60c19238604607499011d68ba58..5dd73b7857d12087a7689c4d4dbe81bce77c3c6e 100644 (file)
@@ -140,7 +140,7 @@ struct pd_dvb_adapter {
        u8                      reserved[3];
 
        /* data for power resume*/
-       struct dvb_frontend_parameters fe_param;
+       struct dtv_frontend_properties fe_param;
 
        /* for channel scanning */
        int             prev_freq;
index d0da11ae19dfe5cd4d218975db4b3de0747a41a8..30fcb117e89899a25208428061900d22eefb829c 100644 (file)
@@ -12,9 +12,9 @@
 static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb);
 
 static int dvb_bandwidth[][2] = {
-       { TLG_BW_8, BANDWIDTH_8_MHZ },
-       { TLG_BW_7, BANDWIDTH_7_MHZ },
-       { TLG_BW_6, BANDWIDTH_6_MHZ }
+       { TLG_BW_8, 8000000 },
+       { TLG_BW_7, 7000000 },
+       { TLG_BW_6, 6000000 }
 };
 static int dvb_bandwidth_length = ARRAY_SIZE(dvb_bandwidth);
 
@@ -146,9 +146,9 @@ static int fw_delay_overflow(struct pd_dvb_adapter *adapter)
        return msec > 800 ? true : false;
 }
 
-static int poseidon_set_fe(struct dvb_frontend *fe,
-                       struct dvb_frontend_parameters *fep)
+static int poseidon_set_fe(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        s32 ret = 0, cmd_status = 0;
        s32 i, bandwidth = -1;
        struct poseidon *pd = fe->demodulator_priv;
@@ -159,7 +159,7 @@ static int poseidon_set_fe(struct dvb_frontend *fe,
 
        mutex_lock(&pd->lock);
        for (i = 0; i < dvb_bandwidth_length; i++)
-               if (fep->u.ofdm.bandwidth == dvb_bandwidth[i][1])
+               if (fep->bandwidth_hz == dvb_bandwidth[i][1])
                        bandwidth = dvb_bandwidth[i][0];
 
        if (check_scan_ok(fep->frequency, bandwidth, pd_dvb)) {
@@ -210,7 +210,7 @@ static int pm_dvb_resume(struct poseidon *pd)
 
        poseidon_check_mode_dvbt(pd);
        msleep(300);
-       poseidon_set_fe(&pd_dvb->dvb_fe, &pd_dvb->fe_param);
+       poseidon_set_fe(&pd_dvb->dvb_fe);
 
        dvb_start_streaming(pd_dvb);
        return 0;
@@ -227,13 +227,13 @@ static s32 poseidon_fe_init(struct dvb_frontend *fe)
        pd->pm_resume  = pm_dvb_resume;
 #endif
        memset(&pd_dvb->fe_param, 0,
-                       sizeof(struct dvb_frontend_parameters));
+                       sizeof(struct dtv_frontend_properties));
        return 0;
 }
 
-static int poseidon_get_fe(struct dvb_frontend *fe,
-                       struct dvb_frontend_parameters *fep)
+static int poseidon_get_fe(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
        struct poseidon *pd = fe->demodulator_priv;
        struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
 
@@ -332,9 +332,9 @@ static int poseidon_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
 }
 
 static struct dvb_frontend_ops poseidon_frontend_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                .name           = "Poseidon DVB-T",
-               .type           = FE_OFDM,
                .frequency_min  = 174000000,
                .frequency_max  = 862000000,
                .frequency_stepsize       = 62500,/* FIXME */
index 129f135d5a5fe1deffaa12fdc81611bd2ecd12d4..c096b3f742003bcbcfc40df79b49a2728f8b9539 100644 (file)
@@ -374,7 +374,7 @@ static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev)
 }
 #endif
 
-static bool check_firmware(struct usb_device *udev, int *down_firmware)
+static int check_firmware(struct usb_device *udev, int *down_firmware)
 {
        void *buf;
        int ret;
@@ -398,7 +398,7 @@ static bool check_firmware(struct usb_device *udev, int *down_firmware)
                *down_firmware = 1;
                return firmware_download(udev);
        }
-       return ret;
+       return 0;
 }
 
 static int poseidon_probe(struct usb_interface *interface,
index 114eec8a630a62f8610b7f9df8e7254c55e583e4..a43b77abd931996199ec83c49734e8a3afefa652 100644 (file)
@@ -1,6 +1,6 @@
 config VIDEO_TM6000
        tristate "TV Master TM5600/6000/6010 driver"
-       depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB && EXPERIMENTAL
+       depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB
        select VIDEO_TUNER
        select MEDIA_TUNER_XC2028
        select MEDIA_TUNER_XC5000
@@ -16,7 +16,7 @@ config VIDEO_TM6000
 
 config VIDEO_TM6000_ALSA
        tristate "TV Master TM5600/6000/6010 audio support"
-       depends on VIDEO_TM6000 && SND && EXPERIMENTAL
+       depends on VIDEO_TM6000 && SND
        select SND_PCM
        ---help---
          This is a video4linux driver for direct (DMA) audio for
@@ -27,7 +27,7 @@ config VIDEO_TM6000_ALSA
 
 config VIDEO_TM6000_DVB
        tristate "DVB Support for tm6000 based TV cards"
-       depends on VIDEO_TM6000 && DVB_CORE && USB && EXPERIMENTAL
+       depends on VIDEO_TM6000 && DVB_CORE && USB
        select DVB_ZL10353
        ---help---
          This adds support for DVB cards based on the tm5600/tm6000 chip.
index 7d675c72fd479cffac862f00c6afb9bd85342688..bd07ec707956d377eae03f3278fa8972e8cf4972 100644 (file)
@@ -42,7 +42,7 @@
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 
-static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
+static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
 
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled.");
@@ -146,20 +146,21 @@ static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
 #define DEFAULT_FIFO_SIZE      4096
 
 static struct snd_pcm_hardware snd_tm6000_digital_hw = {
-       .info = SNDRV_PCM_INFO_MMAP |
+       .info = SNDRV_PCM_INFO_BATCH |
+               SNDRV_PCM_INFO_MMAP |
                SNDRV_PCM_INFO_INTERLEAVED |
                SNDRV_PCM_INFO_BLOCK_TRANSFER |
                SNDRV_PCM_INFO_MMAP_VALID,
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
 
-       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+       .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
        .rate_min = 48000,
        .rate_max = 48000,
        .channels_min = 2,
        .channels_max = 2,
        .period_bytes_min = 64,
        .period_bytes_max = 12544,
-       .periods_min = 1,
+       .periods_min = 2,
        .periods_max = 98,
        .buffer_bytes_max = 62720 * 8,
 };
@@ -181,6 +182,7 @@ static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
        chip->substream = substream;
 
        runtime->hw = snd_tm6000_digital_hw;
+       snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
 
        return 0;
 _error:
@@ -347,9 +349,13 @@ static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
        int err = 0;
 
        switch (cmd) {
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
+       case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
        case SNDRV_PCM_TRIGGER_START:
                atomic_set(&core->stream_started, 1);
                break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
+       case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
        case SNDRV_PCM_TRIGGER_STOP:
                atomic_set(&core->stream_started, 0);
                break;
@@ -371,6 +377,14 @@ static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
        return chip->buf_pos;
 }
 
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+                                            unsigned long offset)
+{
+       void *pageptr = subs->runtime->dma_area + offset;
+
+       return vmalloc_to_page(pageptr);
+}
+
 /*
  * operators
  */
@@ -383,6 +397,7 @@ static struct snd_pcm_ops snd_tm6000_pcm_ops = {
        .prepare = snd_tm6000_prepare,
        .trigger = snd_tm6000_card_trigger,
        .pointer = snd_tm6000_pointer,
+       .page = snd_pcm_get_vmalloc_page,
 };
 
 /*
index ff939bc0e0b997adc0b41f0fc8c0bffa24a1edcc..034659b1317480a3c389ff9619dd3123c9aeb39d 100644 (file)
@@ -351,6 +351,7 @@ static struct tm6000_board tm6000_boards[] = {
                .tuner_addr   = 0xc2 >> 1,
                .demod_addr   = 0x1e >> 1,
                .type         = TM6010,
+               .ir_codes = RC_MAP_HAUPPAUGE,
                .caps = {
                        .has_tuner    = 1,
                        .has_dvb      = 1,
@@ -639,6 +640,7 @@ static struct usb_device_id tm6000_id_table[] = {
        { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
        { }
 };
+MODULE_DEVICE_TABLE(usb, tm6000_id_table);
 
 /* Control power led for show some activity */
 void tm6000_flash_led(struct tm6000_core *dev, u8 state)
@@ -941,6 +943,7 @@ static void tm6000_config_tuner(struct tm6000_core *dev)
                case TM6010_BOARD_HAUPPAUGE_900H:
                case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
                case TM6010_BOARD_TWINHAN_TU501:
+                       ctl.max_len = 80;
                        ctl.fname = "xc3028L-v36.fw";
                        break;
                default:
@@ -1002,6 +1005,7 @@ static int fill_board_specific_data(struct tm6000_core *dev)
        /* setup per-model quirks */
        switch (dev->model) {
        case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+       case TM6010_BOARD_HAUPPAUGE_900H:
                dev->quirks |= TM6000_QUIRK_NO_USB_DELAY;
                break;
 
@@ -1050,6 +1054,33 @@ static void use_alternative_detection_method(struct tm6000_core *dev)
               tm6000_boards[model].name, model);
 }
 
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+       struct tm6000_core *dev = container_of(work, struct tm6000_core,
+                                              request_module_wk);
+
+       request_module("tm6000-alsa");
+
+       if (dev->caps.has_dvb)
+               request_module("tm6000-dvb");
+}
+
+static void request_modules(struct tm6000_core *dev)
+{
+       INIT_WORK(&dev->request_module_wk, request_module_async);
+       schedule_work(&dev->request_module_wk);
+}
+
+static void flush_request_modules(struct tm6000_core *dev)
+{
+       flush_work_sync(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#define flush_request_modules(dev)
+#endif /* CONFIG_MODULES */
+
 static int tm6000_init_dev(struct tm6000_core *dev)
 {
        struct v4l2_frequency f;
@@ -1112,6 +1143,8 @@ static int tm6000_init_dev(struct tm6000_core *dev)
 
        tm6000_ir_init(dev);
 
+       request_modules(dev);
+
        mutex_unlock(&dev->lock);
        return 0;
 
@@ -1324,6 +1357,8 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
 
        printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
 
+       flush_request_modules(dev);
+
        tm6000_ir_fini(dev);
 
        if (dev->gpio.power_led) {
index 9783616a0da2791b83680132168d1522baf8b9af..22cc0116deb65e9f9e26f8b2ba844c778d6a5c57 100644 (file)
@@ -38,6 +38,7 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
        int          ret, i;
        unsigned int pipe;
        u8           *data = NULL;
+       int delay = 5000;
 
        mutex_lock(&dev->usb_lock);
 
@@ -88,7 +89,20 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
        }
 
        kfree(data);
-       msleep(5);
+
+       if (dev->quirks & TM6000_QUIRK_NO_USB_DELAY)
+               delay = 0;
+
+       if (req == REQ_16_SET_GET_I2C_WR1_RDN && !(req_type & USB_DIR_IN)) {
+               unsigned int tsleep;
+               /* Calculate delay time, 14000us for 64 bytes */
+               tsleep = (len * 200) + 200;
+               if (tsleep < delay)
+                       tsleep = delay;
+               usleep_range(tsleep, tsleep + 1000);
+       }
+       else if (delay)
+               usleep_range(delay, delay + 1000);
 
        mutex_unlock(&dev->usb_lock);
        return ret;
@@ -125,14 +139,14 @@ int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
        u8 new_index;
 
        rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
-                                       value, index, buf, 1);
+                                       value, 0, buf, 1);
 
        if (rc < 0)
                return rc;
 
        new_index = (buf[0] & ~mask) | (index & mask);
 
-       if (new_index == index)
+       if (new_index == buf[0])
                return 0;
 
        return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
@@ -536,16 +550,16 @@ static struct reg_init tm6010_init_tab[] = {
 
        { TM6010_REQ05_R18_IMASK7, 0x00 },
 
-       { TM6010_REQ07_RD8_IR_LEADER1, 0xaa },
-       { TM6010_REQ07_RD8_IR_LEADER0, 0x30 },
-       { TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20 },
-       { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0 },
+       { TM6010_REQ07_RDC_IR_LEADER1, 0xaa },
+       { TM6010_REQ07_RDD_IR_LEADER0, 0x30 },
+       { TM6010_REQ07_RDE_IR_PULSE_CNT1, 0x20 },
+       { TM6010_REQ07_RDF_IR_PULSE_CNT0, 0xd0 },
        { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 },
-       { TM6010_REQ07_RD8_IR, 0x2f },
+       { TM6010_REQ07_RD8_IR, 0x0f },
 
        /* set remote wakeup key:any key wakeup */
        { TM6010_REQ07_RE5_REMOTE_WAKEUP,  0xfe },
-       { TM6010_REQ07_RD8_IR_WAKEUP_SEL,  0xff },
+       { TM6010_REQ07_RDA_IR_WAKEUP_SEL,  0xff },
 };
 
 int tm6000_init(struct tm6000_core *dev)
@@ -599,55 +613,6 @@ int tm6000_init(struct tm6000_core *dev)
        return rc;
 }
 
-int tm6000_reset(struct tm6000_core *dev)
-{
-       int pipe;
-       int err;
-
-       msleep(500);
-
-       err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 0);
-       if (err < 0) {
-               tm6000_err("failed to select interface %d, alt. setting 0\n",
-                               dev->isoc_in.bInterfaceNumber);
-               return err;
-       }
-
-       err = usb_reset_configuration(dev->udev);
-       if (err < 0) {
-               tm6000_err("failed to reset configuration\n");
-               return err;
-       }
-
-       if ((dev->quirks & TM6000_QUIRK_NO_USB_DELAY) == 0)
-               msleep(5);
-
-       /*
-        * Not all devices have int_in defined
-        */
-       if (!dev->int_in.endp)
-               return 0;
-
-       err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 2);
-       if (err < 0) {
-               tm6000_err("failed to select interface %d, alt. setting 2\n",
-                               dev->isoc_in.bInterfaceNumber);
-               return err;
-       }
-
-       msleep(5);
-
-       pipe = usb_rcvintpipe(dev->udev,
-                       dev->int_in.endp->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
-
-       err = usb_clear_halt(dev->udev, pipe);
-       if (err < 0) {
-               tm6000_err("usb_clear_halt failed: %d\n", err);
-               return err;
-       }
-
-       return 0;
-}
 
 int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
 {
@@ -696,11 +661,13 @@ int tm6000_set_audio_rinput(struct tm6000_core *dev)
        if (dev->dev_type == TM6010) {
                /* Audio crossbar setting, default SIF1 */
                u8 areg_f0;
+               u8 areg_07 = 0x10;
 
                switch (dev->rinput.amux) {
                case TM6000_AMUX_SIF1:
                case TM6000_AMUX_SIF2:
                        areg_f0 = 0x03;
+                       areg_07 = 0x30;
                        break;
                case TM6000_AMUX_ADC1:
                        areg_f0 = 0x00;
@@ -720,6 +687,9 @@ int tm6000_set_audio_rinput(struct tm6000_core *dev)
                /* Set audio input crossbar */
                tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
                                                        areg_f0, 0x0f);
+               /* Mux overflow workaround */
+               tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
+                       areg_07, 0xf0);
        } else {
                u8 areg_eb;
                /* Audio setting, default LINE1 */
index 5e6c129a4bebd2564f18779be0051573fa9b9242..e1f3f66e1e63018f3db3074bfb276f765808dc96 100644 (file)
@@ -89,9 +89,19 @@ static void tm6000_urb_received(struct urb *urb)
        int ret;
        struct tm6000_core *dev = urb->context;
 
-       if (urb->status != 0)
+       switch (urb->status) {
+       case 0:
+       case -ETIMEDOUT:
+               break;
+       case -ENOENT:
+       case -ECONNRESET:
+       case -ESHUTDOWN:
+               return;
+       default:
                print_err_status(dev, 0, urb->status);
-       else if (urb->actual_length > 0)
+       }
+
+       if (urb->actual_length > 0)
                dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
                                                   urb->actual_length);
 
@@ -151,7 +161,7 @@ static int tm6000_start_stream(struct tm6000_core *dev)
                printk(KERN_ERR "tm6000: pipe resetted\n");
 
 /*     mutex_lock(&tm6000_driver.open_close_mutex); */
-       ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
+       ret = usb_submit_urb(dvb->bulk_urb, GFP_ATOMIC);
 
 /*     mutex_unlock(&tm6000_driver.open_close_mutex); */
        if (ret) {
@@ -396,6 +406,11 @@ static int dvb_init(struct tm6000_core *dev)
        if (!dev->caps.has_dvb)
                return 0;
 
+       if (dev->udev->speed == USB_SPEED_FULL) {
+               printk(KERN_INFO "This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)\n");
+               return 0;
+       }
+
        dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL);
        if (!dvb) {
                printk(KERN_INFO "Cannot allocate memory\n");
index 0290bbf00c3e68c0541e87803d98963b721e8a41..c7e23e3dd75ed4f47276ace2f8480b461a9131fe 100644 (file)
@@ -46,11 +46,10 @@ static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr,
                                __u8 reg, char *buf, int len)
 {
        int rc;
-       unsigned int tsleep;
        unsigned int i2c_packet_limit = 16;
 
        if (dev->dev_type == TM6010)
-               i2c_packet_limit = 64;
+               i2c_packet_limit = 80;
 
        if (!buf)
                return -1;
@@ -71,10 +70,6 @@ static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr,
                return rc;
        }
 
-       /* Calculate delay time, 14000us for 64 bytes */
-       tsleep = ((len * 200) + 200 + 1000) / 1000;
-       msleep(tsleep);
-
        /* release mutex */
        return rc;
 }
@@ -145,7 +140,6 @@ static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr,
                        return rc;
                }
 
-               msleep(1400 / 1000);
                rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
                        USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ,
                        reg, 0, buf, len);
index 405d12729d057c0d6eebce12d5614f266c3211a8..7844607dd45adac97646a08aaf3bcdfc74bbd2f6 100644 (file)
 
 static unsigned int ir_debug;
 module_param(ir_debug, int, 0644);
-MODULE_PARM_DESC(ir_debug, "enable debug message [IR]");
+MODULE_PARM_DESC(ir_debug, "debug message level");
 
 static unsigned int enable_ir = 1;
 module_param(enable_ir, int, 0644);
 MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)");
 
-/* number of 50ms for ON-OFF-ON power led */
-/* show IR activity */
-#define PWLED_OFF 2
+static unsigned int ir_clock_mhz = 12;
+module_param(ir_clock_mhz, int, 0644);
+MODULE_PARM_DESC(enable_ir, "ir clock, in MHz");
+
+#define URB_SUBMIT_DELAY       100     /* ms - Delay to submit an URB request on retrial and init */
+#define URB_INT_LED_DELAY      100     /* ms - Delay to turn led on again on int mode */
 
 #undef dprintk
 
-#define dprintk(fmt, arg...) \
-       if (ir_debug) { \
+#define dprintk(level, fmt, arg...) do {\
+       if (ir_debug >= level) \
                printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
-       }
+       } while (0)
 
 struct tm6000_ir_poll_result {
        u16 rc_data;
@@ -62,20 +65,15 @@ struct tm6000_IR {
        int                     polling;
        struct delayed_work     work;
        u8                      wait:1;
-       u8                      key:1;
-       u8                      pwled:1;
-       u8                      pwledcnt;
+       u8                      pwled:2;
+       u8                      submit_urb:1;
        u16                     key_addr;
        struct urb              *int_urb;
-       u8                      *urb_data;
-
-       int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *);
 
        /* IR device properties */
        u64                     rc_type;
 };
 
-
 void tm6000_ir_wait(struct tm6000_core *dev, u8 state)
 {
        struct tm6000_IR *ir = dev->ir;
@@ -83,62 +81,84 @@ void tm6000_ir_wait(struct tm6000_core *dev, u8 state)
        if (!dev->ir)
                return;
 
+       dprintk(2, "%s: %i\n",__func__, ir->wait);
+
        if (state)
                ir->wait = 1;
        else
                ir->wait = 0;
 }
 
-
 static int tm6000_ir_config(struct tm6000_IR *ir)
 {
        struct tm6000_core *dev = ir->dev;
-       u8 buf[10];
-       int rc;
+       u32 pulse = 0, leader = 0;
+
+       dprintk(2, "%s\n",__func__);
+
+       /*
+        * The IR decoder supports RC-5 or NEC, with a configurable timing.
+        * The timing configuration there is not that accurate, as it uses
+        * approximate values. The NEC spec mentions a 562.5 unit period,
+        * and RC-5 uses a 888.8 period.
+        * Currently, driver assumes a clock provided by a 12 MHz XTAL, but
+        * a modprobe parameter can adjust it.
+        * Adjustments are required for other timings.
+        * It seems that the 900ms timing for NEC is used to detect a RC-5
+        * IR, in order to discard such decoding
+        */
 
        switch (ir->rc_type) {
        case RC_TYPE_NEC:
-               /* Setup IR decoder for NEC standard 12MHz system clock */
-               /* IR_LEADER_CNT = 0.9ms             */
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa);
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30);
-               /* IR_PULSE_CNT = 0.7ms              */
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20);
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0);
-               /* Remote WAKEUP = enable */
-               tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe);
-               /* IR_WKUP_SEL = Low byte in decoded IR data */
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff);
-               /* IR_WKU_ADD code */
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff);
-               tm6000_flash_led(dev, 0);
-               msleep(100);
-               tm6000_flash_led(dev, 1);
+               leader = 900;   /* ms */
+               pulse  = 700;   /* ms - the actual value would be 562 */
                break;
        default:
-               /* hack */
-               buf[0] = 0xff;
-               buf[1] = 0xff;
-               buf[2] = 0xf2;
-               buf[3] = 0x2b;
-               buf[4] = 0x20;
-               buf[5] = 0x35;
-               buf[6] = 0x60;
-               buf[7] = 0x04;
-               buf[8] = 0xc0;
-               buf[9] = 0x08;
-
-               rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
-                       USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
-               msleep(100);
-
-               if (rc < 0) {
-                       printk(KERN_INFO "IR configuration failed");
-                       return rc;
-               }
+       case RC_TYPE_RC5:
+               leader = 900;   /* ms - from the NEC decoding */
+               pulse  = 1780;  /* ms - The actual value would be 1776 */
                break;
        }
 
+       pulse = ir_clock_mhz * pulse;
+       leader = ir_clock_mhz * leader;
+       if (ir->rc_type == RC_TYPE_NEC)
+               leader = leader | 0x8000;
+
+       dprintk(2, "%s: %s, %d MHz, leader = 0x%04x, pulse = 0x%06x \n",
+               __func__,
+               (ir->rc_type == RC_TYPE_NEC) ? "NEC" : "RC-5",
+               ir_clock_mhz, leader, pulse);
+
+       /* Remote WAKEUP = enable, normal mode, from IR decoder output */
+       tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe);
+
+       /* Enable IR reception on non-busrt mode */
+       tm6000_set_reg(dev, TM6010_REQ07_RD8_IR, 0x2f);
+
+       /* IR_WKUP_SEL = Low byte in decoded IR data */
+       tm6000_set_reg(dev, TM6010_REQ07_RDA_IR_WAKEUP_SEL, 0xff);
+       /* IR_WKU_ADD code */
+       tm6000_set_reg(dev, TM6010_REQ07_RDB_IR_WAKEUP_ADD, 0xff);
+
+       tm6000_set_reg(dev, TM6010_REQ07_RDC_IR_LEADER1, leader >> 8);
+       tm6000_set_reg(dev, TM6010_REQ07_RDD_IR_LEADER0, leader);
+
+       tm6000_set_reg(dev, TM6010_REQ07_RDE_IR_PULSE_CNT1, pulse >> 8);
+       tm6000_set_reg(dev, TM6010_REQ07_RDF_IR_PULSE_CNT0, pulse);
+
+       if (!ir->polling)
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
+       else
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
+       msleep(10);
+
+       /* Shows that IR is working via the LED */
+       tm6000_flash_led(dev, 0);
+       msleep(100);
+       tm6000_flash_led(dev, 1);
+       ir->pwled = 1;
+
        return 0;
 }
 
@@ -146,132 +166,124 @@ static void tm6000_ir_urb_received(struct urb *urb)
 {
        struct tm6000_core *dev = urb->context;
        struct tm6000_IR *ir = dev->ir;
+       struct tm6000_ir_poll_result poll_result;
+       char *buf;
        int rc;
 
-       if (urb->status != 0)
-               printk(KERN_INFO "not ready\n");
-       else if (urb->actual_length > 0) {
-               memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length);
+       dprintk(2, "%s\n",__func__);
+       if (urb->status < 0 || urb->actual_length <= 0) {
+               printk(KERN_INFO "tm6000: IR URB failure: status: %i, length %i\n",
+                      urb->status, urb->actual_length);
+               ir->submit_urb = 1;
+               schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY));
+               return;
+       }
+       buf = urb->transfer_buffer;
 
-               dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0],
-                       ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]);
+       if (ir_debug)
+               print_hex_dump(KERN_DEBUG, "tm6000: IR data: ",
+                              DUMP_PREFIX_OFFSET,16, 1,
+                              buf, urb->actual_length, false);
 
-               ir->key = 1;
-       }
+       poll_result.rc_data = buf[0];
+       if (urb->actual_length > 1)
+               poll_result.rc_data |= buf[1] << 8;
+
+       dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data);
+       rc_keydown(ir->rc, poll_result.rc_data, 0);
 
        rc = usb_submit_urb(urb, GFP_ATOMIC);
+       /*
+        * Flash the led. We can't do it here, as it is running on IRQ context.
+        * So, use the scheduler to do it, in a few ms.
+        */
+       ir->pwled = 2;
+       schedule_delayed_work(&ir->work, msecs_to_jiffies(10));
 }
 
-static int default_polling_getkey(struct tm6000_IR *ir,
-                               struct tm6000_ir_poll_result *poll_result)
+static void tm6000_ir_handle_key(struct work_struct *work)
 {
+       struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
        struct tm6000_core *dev = ir->dev;
+       struct tm6000_ir_poll_result poll_result;
        int rc;
        u8 buf[2];
 
-       if (ir->wait && !&dev->int_in)
-               return 0;
-
-       if (&dev->int_in) {
-               switch (ir->rc_type) {
-               case RC_TYPE_RC5:
-                       poll_result->rc_data = ir->urb_data[0];
-                       break;
-               case RC_TYPE_NEC:
-                       if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) {
-                               poll_result->rc_data = ir->urb_data[0]
-                                                       | ir->urb_data[1] << 8;
-                       }
-                       break;
-               default:
-                       poll_result->rc_data = ir->urb_data[0]
-                                       | ir->urb_data[1] << 8;
-                       break;
-               }
-       } else {
-               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
-               msleep(10);
-               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
-               msleep(10);
-
-               if (ir->rc_type == RC_TYPE_RC5) {
-                       rc = tm6000_read_write_usb(dev, USB_DIR_IN |
-                               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               REQ_02_GET_IR_CODE, 0, 0, buf, 1);
-
-                       msleep(10);
-
-                       dprintk("read data=%02x\n", buf[0]);
-                       if (rc < 0)
-                               return rc;
+       if (ir->wait)
+               return;
 
-                       poll_result->rc_data = buf[0];
-               } else {
-                       rc = tm6000_read_write_usb(dev, USB_DIR_IN |
-                               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               REQ_02_GET_IR_CODE, 0, 0, buf, 2);
+       dprintk(3, "%s\n",__func__);
 
-                       msleep(10);
+       rc = tm6000_read_write_usb(dev, USB_DIR_IN |
+               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               REQ_02_GET_IR_CODE, 0, 0, buf, 2);
+       if (rc < 0)
+               return;
 
-                       dprintk("read data=%04x\n", buf[0] | buf[1] << 8);
-                       if (rc < 0)
-                               return rc;
+       if (rc > 1)
+               poll_result.rc_data = buf[0] | buf[1] << 8;
+       else
+               poll_result.rc_data = buf[0];
 
-                       poll_result->rc_data = buf[0] | buf[1] << 8;
+       /* Check if something was read */
+       if ((poll_result.rc_data & 0xff) == 0xff) {
+               if (!ir->pwled) {
+                       tm6000_flash_led(dev, 1);
+                       ir->pwled = 1;
                }
-               if ((poll_result->rc_data & 0x00ff) != 0xff)
-                       ir->key = 1;
+               return;
        }
-       return 0;
+
+       dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data);
+       rc_keydown(ir->rc, poll_result.rc_data, 0);
+       tm6000_flash_led(dev, 0);
+       ir->pwled = 0;
+
+       /* Re-schedule polling */
+       schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
 }
 
-static void tm6000_ir_handle_key(struct tm6000_IR *ir)
+static void tm6000_ir_int_work(struct work_struct *work)
 {
+       struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
        struct tm6000_core *dev = ir->dev;
-       int result;
-       struct tm6000_ir_poll_result poll_result;
+       int rc;
 
-       /* read the registers containing the IR status */
-       result = ir->get_key(ir, &poll_result);
-       if (result < 0) {
-               printk(KERN_INFO "ir->get_key() failed %d\n", result);
-               return;
-       }
+       dprintk(3, "%s, submit_urb = %d, pwled = %d\n",__func__, ir->submit_urb,
+               ir->pwled);
 
-       dprintk("ir->get_key result data=%04x\n", poll_result.rc_data);
+       if (ir->submit_urb) {
+               dprintk(3, "Resubmit urb\n");
+               tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
 
-       if (ir->pwled) {
-               if (ir->pwledcnt >= PWLED_OFF) {
-                       ir->pwled = 0;
-                       ir->pwledcnt = 0;
-                       tm6000_flash_led(dev, 1);
-               } else
-                       ir->pwledcnt += 1;
+               rc = usb_submit_urb(ir->int_urb, GFP_ATOMIC);
+               if (rc < 0) {
+                       printk(KERN_ERR "tm6000: Can't submit an IR interrupt. Error %i\n",
+                              rc);
+                       /* Retry in 100 ms */
+                       schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY));
+                       return;
+               }
+               ir->submit_urb = 0;
        }
 
-       if (ir->key) {
-               rc_keydown(ir->rc, poll_result.rc_data, 0);
-               ir->key = 0;
-               ir->pwled = 1;
-               ir->pwledcnt = 0;
+       /* Led is enabled only if USB submit doesn't fail */
+       if (ir->pwled == 2) {
                tm6000_flash_led(dev, 0);
+               ir->pwled = 0;
+               schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_INT_LED_DELAY));
+       } else if (!ir->pwled) {
+               tm6000_flash_led(dev, 1);
+               ir->pwled = 1;
        }
-       return;
-}
-
-static void tm6000_ir_work(struct work_struct *work)
-{
-       struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
-
-       tm6000_ir_handle_key(ir);
-       schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
 }
 
 static int tm6000_ir_start(struct rc_dev *rc)
 {
        struct tm6000_IR *ir = rc->priv;
 
-       INIT_DELAYED_WORK(&ir->work, tm6000_ir_work);
+       dprintk(2, "%s\n",__func__);
+
        schedule_delayed_work(&ir->work, 0);
 
        return 0;
@@ -281,6 +293,8 @@ static void tm6000_ir_stop(struct rc_dev *rc)
 {
        struct tm6000_IR *ir = rc->priv;
 
+       dprintk(2, "%s\n",__func__);
+
        cancel_delayed_work_sync(&ir->work);
 }
 
@@ -291,10 +305,11 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
        if (!ir)
                return 0;
 
+       dprintk(2, "%s\n",__func__);
+
        if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC))
                ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff);
 
-       ir->get_key = default_polling_getkey;
        ir->rc_type = rc_type;
 
        tm6000_ir_config(ir);
@@ -302,17 +317,19 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
        return 0;
 }
 
-int tm6000_ir_int_start(struct tm6000_core *dev)
+static int __tm6000_ir_int_start(struct rc_dev *rc)
 {
-       struct tm6000_IR *ir = dev->ir;
+       struct tm6000_IR *ir = rc->priv;
+       struct tm6000_core *dev = ir->dev;
        int pipe, size;
        int err = -ENOMEM;
 
-
        if (!ir)
                return -ENODEV;
 
-       ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+       dprintk(2, "%s\n",__func__);
+
+       ir->int_urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!ir->int_urb)
                return -ENOMEM;
 
@@ -321,42 +338,59 @@ int tm6000_ir_int_start(struct tm6000_core *dev)
                & USB_ENDPOINT_NUMBER_MASK);
 
        size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
-       dprintk("IR max size: %d\n", size);
+       dprintk(1, "IR max size: %d\n", size);
 
-       ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
+       ir->int_urb->transfer_buffer = kzalloc(size, GFP_ATOMIC);
        if (ir->int_urb->transfer_buffer == NULL) {
                usb_free_urb(ir->int_urb);
                return err;
        }
-       dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
+       dprintk(1, "int interval: %d\n", dev->int_in.endp->desc.bInterval);
+
        usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
                ir->int_urb->transfer_buffer, size,
                tm6000_ir_urb_received, dev,
                dev->int_in.endp->desc.bInterval);
-       err = usb_submit_urb(ir->int_urb, GFP_KERNEL);
-       if (err) {
-               kfree(ir->int_urb->transfer_buffer);
-               usb_free_urb(ir->int_urb);
-               return err;
-       }
-       ir->urb_data = kzalloc(size, GFP_KERNEL);
+
+       ir->submit_urb = 1;
+       schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY));
 
        return 0;
 }
 
-void tm6000_ir_int_stop(struct tm6000_core *dev)
+static void __tm6000_ir_int_stop(struct rc_dev *rc)
 {
-       struct tm6000_IR *ir = dev->ir;
+       struct tm6000_IR *ir = rc->priv;
 
-       if (!ir)
+       if (!ir || !ir->int_urb)
                return;
 
+       dprintk(2, "%s\n",__func__);
+
        usb_kill_urb(ir->int_urb);
        kfree(ir->int_urb->transfer_buffer);
        usb_free_urb(ir->int_urb);
        ir->int_urb = NULL;
-       kfree(ir->urb_data);
-       ir->urb_data = NULL;
+}
+
+int tm6000_ir_int_start(struct tm6000_core *dev)
+{
+       struct tm6000_IR *ir = dev->ir;
+
+       if (!ir)
+               return 0;
+
+       return __tm6000_ir_int_start(ir->rc);
+}
+
+void tm6000_ir_int_stop(struct tm6000_core *dev)
+{
+       struct tm6000_IR *ir = dev->ir;
+
+       if (!ir || !ir->rc)
+               return;
+
+       __tm6000_ir_int_stop(ir->rc);
 }
 
 int tm6000_ir_init(struct tm6000_core *dev)
@@ -374,29 +408,36 @@ int tm6000_ir_init(struct tm6000_core *dev)
        if (!dev->ir_codes)
                return 0;
 
-       ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+       ir = kzalloc(sizeof(*ir), GFP_ATOMIC);
        rc = rc_allocate_device();
        if (!ir || !rc)
                goto out;
 
+       dprintk(2, "%s\n", __func__);
+
        /* record handles to ourself */
        ir->dev = dev;
        dev->ir = ir;
        ir->rc = rc;
 
-       /* input einrichten */
+       /* input setup */
        rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC;
+       /* Neded, in order to support NEC remotes with 24 or 32 bits */
+       rc->scanmask = 0xffff;
        rc->priv = ir;
        rc->change_protocol = tm6000_ir_change_protocol;
-       rc->open = tm6000_ir_start;
-       rc->close = tm6000_ir_stop;
+       if (dev->int_in.endp) {
+               rc->open    = __tm6000_ir_int_start;
+               rc->close   = __tm6000_ir_int_stop;
+               INIT_DELAYED_WORK(&ir->work, tm6000_ir_int_work);
+       } else {
+               rc->open  = tm6000_ir_start;
+               rc->close = tm6000_ir_stop;
+               ir->polling = 50;
+               INIT_DELAYED_WORK(&ir->work, tm6000_ir_handle_key);
+       }
        rc->driver_type = RC_DRIVER_SCANCODE;
 
-       ir->polling = 50;
-       ir->pwled = 0;
-       ir->pwledcnt = 0;
-
-
        snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
                                                dev->name);
 
@@ -415,15 +456,6 @@ int tm6000_ir_init(struct tm6000_core *dev)
        rc->driver_name = "tm6000";
        rc->dev.parent = &dev->udev->dev;
 
-       if (&dev->int_in) {
-               dprintk("IR over int\n");
-
-               err = tm6000_ir_int_start(dev);
-
-               if (err)
-                       goto out;
-       }
-
        /* ir register */
        err = rc_register_device(rc);
        if (err)
@@ -447,10 +479,19 @@ int tm6000_ir_fini(struct tm6000_core *dev)
        if (!ir)
                return 0;
 
+       dprintk(2, "%s\n",__func__);
+
        rc_unregister_device(ir->rc);
 
-       if (ir->int_urb)
-               tm6000_ir_int_stop(dev);
+       if (!ir->polling)
+               __tm6000_ir_int_stop(ir->rc);
+
+       tm6000_ir_stop(ir->rc);
+
+       /* Turn off the led */
+       tm6000_flash_led(dev, 0);
+       ir->pwled = 0;
+
 
        kfree(ir);
        dev->ir = NULL;
index 7f491b6de9337a22d7bfda621203218712176ac3..a38c251ed57bbe89443158d851052761cc5eb60e 100644 (file)
@@ -284,19 +284,19 @@ enum {
 /* ONLY for TM6010 */
 #define TM6010_REQ07_RD8_IR                            0x07, 0xd8
 /* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_BSIZE                      0x07, 0xd9
+#define TM6010_REQ07_RD9_IR_BSIZE                      0x07, 0xd9
 /* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_WAKEUP_SEL                 0x07, 0xda
+#define TM6010_REQ07_RDA_IR_WAKEUP_SEL                 0x07, 0xda
 /* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_WAKEUP_ADD                 0x07, 0xdb
+#define TM6010_REQ07_RDB_IR_WAKEUP_ADD                 0x07, 0xdb
 /* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_LEADER1                    0x07, 0xdc
+#define TM6010_REQ07_RDC_IR_LEADER1                    0x07, 0xdc
 /* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_LEADER0                    0x07, 0xdd
+#define TM6010_REQ07_RDD_IR_LEADER0                    0x07, 0xdd
 /* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_PULSE_CNT1                 0x07, 0xde
+#define TM6010_REQ07_RDE_IR_PULSE_CNT1                 0x07, 0xde
 /* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR_PULSE_CNT0                 0x07, 0xdf
+#define TM6010_REQ07_RDF_IR_PULSE_CNT0                 0x07, 0xdf
 /* ONLY for TM6010 */
 #define TM6010_REQ07_RE0_DVIDEO_SOURCE                 0x07, 0xe0
 /* ONLY for TM6010 */
index 9a4145dc3d8750d573d5ec286598e625179598c2..9dc0831d813f8332e9d9394dfdc89e0720880365 100644 (file)
@@ -361,82 +361,51 @@ static int tm6000_set_audio_std(struct tm6000_core *dev)
                return 0;
        }
 
-       switch (tm6010_a_mode) {
+       /*
+        * STD/MN shouldn't be affected by tm6010_a_mode, as there's just one
+        * audio standard for each V4L2_STD type.
+        */
+       if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_KR) {
+               areg_05 |= 0x04;
+       } else if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_JP) {
+               areg_05 |= 0x43;
+       } else if (dev->norm & V4L2_STD_MN) {
+               areg_05 |= 0x22;
+       } else switch (tm6010_a_mode) {
        /* auto */
        case 0:
-               switch (dev->norm) {
-               case V4L2_STD_NTSC_M_KR:
+               if ((dev->norm & V4L2_STD_SECAM) == V4L2_STD_SECAM_L)
                        areg_05 |= 0x00;
-                       break;
-               case V4L2_STD_NTSC_M_JP:
-                       areg_05 |= 0x40;
-                       break;
-               case V4L2_STD_NTSC_M:
-               case V4L2_STD_PAL_M:
-               case V4L2_STD_PAL_N:
-                       areg_05 |= 0x20;
-                       break;
-               case V4L2_STD_PAL_Nc:
-                       areg_05 |= 0x60;
-                       break;
-               case V4L2_STD_SECAM_L:
-                       areg_05 |= 0x00;
-                       break;
-               case V4L2_STD_DK:
+               else    /* Other PAL/SECAM standards */
                        areg_05 |= 0x10;
-                       break;
-               }
                break;
        /* A2 */
        case 1:
-               switch (dev->norm) {
-               case V4L2_STD_B:
-               case V4L2_STD_GH:
-                       areg_05 = 0x05;
-                       break;
-               case V4L2_STD_DK:
+               if (dev->norm & V4L2_STD_DK)
                        areg_05 = 0x09;
-                       break;
-               }
+               else
+                       areg_05 = 0x05;
                break;
        /* NICAM */
        case 2:
-               switch (dev->norm) {
-               case V4L2_STD_B:
-               case V4L2_STD_GH:
-                       areg_05 = 0x07;
-                       break;
-               case V4L2_STD_DK:
+               if (dev->norm & V4L2_STD_DK) {
                        areg_05 = 0x06;
-                       break;
-               case V4L2_STD_PAL_I:
+               } else if (dev->norm & V4L2_STD_PAL_I) {
                        areg_05 = 0x08;
-                       break;
-               case V4L2_STD_SECAM_L:
+               } else if (dev->norm & V4L2_STD_SECAM_L) {
                        areg_05 = 0x0a;
                        areg_02 = 0x02;
-                       break;
+               } else {
+                       areg_05 = 0x07;
                }
                nicam_flag = 1;
                break;
        /* other */
        case 3:
-               switch (dev->norm) {
-               /* DK3_A2 */
-               case V4L2_STD_DK:
+               if (dev->norm & V4L2_STD_DK) {
                        areg_05 = 0x0b;
-                       break;
-               /* Korea */
-               case V4L2_STD_NTSC_M_KR:
-                       areg_05 = 0x04;
-                       break;
-               /* EIAJ */
-               case V4L2_STD_NTSC_M_JP:
-                       areg_05 = 0x03;
-                       break;
-               default:
+               } else {
                        areg_05 = 0x02;
-                       break;
                }
                break;
        }
@@ -557,10 +526,16 @@ int tm6000_set_standard(struct tm6000_core *dev)
                case TM6000_AMUX_ADC1:
                        tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
                                0x00, 0x0f);
+                       /* Mux overflow workaround */
+                       tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
+                               0x10, 0xf0);
                        break;
                case TM6000_AMUX_ADC2:
                        tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
                                0x08, 0x0f);
+                       /* Mux overflow workaround */
+                       tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
+                               0x10, 0xf0);
                        break;
                case TM6000_AMUX_SIF1:
                        reg_08_e2 |= 0x02;
@@ -570,6 +545,9 @@ int tm6000_set_standard(struct tm6000_core *dev)
                        tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3);
                        tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
                                0x02, 0x0f);
+                       /* Mux overflow workaround */
+                       tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
+                               0x30, 0xf0);
                        break;
                case TM6000_AMUX_SIF2:
                        reg_08_e2 |= 0x02;
@@ -579,6 +557,9 @@ int tm6000_set_standard(struct tm6000_core *dev)
                        tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf7);
                        tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
                                0x02, 0x0f);
+                       /* Mux overflow workaround */
+                       tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
+                               0x30, 0xf0);
                        break;
                default:
                        break;
index 1e5ace0b5d10517f4e36baf81698d2851b459f45..bc13db736e2457e7d89575b8b7c656f3e05a8ce7 100644 (file)
@@ -1605,16 +1605,25 @@ static int tm6000_release(struct file *file)
        res_free(dev, fh);
 
        if (!dev->users) {
-               int err;
-
                tm6000_uninit_isoc(dev);
 
+               /* Stop interrupt USB pipe */
+               tm6000_ir_int_stop(dev);
+
+               usb_reset_configuration(dev->udev);
+
+               if (dev->int_in.endp)
+                       usb_set_interface(dev->udev,
+                                       dev->isoc_in.bInterfaceNumber, 2);
+               else
+                       usb_set_interface(dev->udev,
+                                       dev->isoc_in.bInterfaceNumber, 0);
+
+               /* Start interrupt USB pipe */
+               tm6000_ir_int_start(dev);
+
                if (!fh->radio)
                        videobuf_mmap_free(&fh->vb_vidq);
-
-               err = tm6000_reset(dev);
-               if (err < 0)
-                       dev_err(&vdev->dev, "reset failed: %d\n", err);
        }
 
        kfree(fh);
index 2777e514eff27a8a95fa0d315f7b040c1ff2c8b3..27ba659cfa85610be14ecd957d5e11d9cdb775c0 100644 (file)
@@ -188,6 +188,9 @@ struct tm6000_core {
        /* Device Capabilities*/
        struct tm6000_capabilities      caps;
 
+       /* Used to load alsa/dvb */
+        struct work_struct             request_module_wk;
+
        /* Tuner configuration */
        int                             tuner_type;             /* type of the tuner */
        int                             tuner_addr;             /* tuner address */
index 11cc980b0cd5e7113da25b6b39297de8e33038da..4059ea178c2d95e680e8679319d8aa1c661fa1b1 100644 (file)
@@ -326,6 +326,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
                t->mode_mask = T_RADIO;
                break;
        case TUNER_PHILIPS_FMD1216ME_MK3:
+       case TUNER_PHILIPS_FMD1216MEX_MK3:
                buffer[0] = 0x0b;
                buffer[1] = 0xdc;
                buffer[2] = 0x9c;
index 926f03931156541f98937ac9a3b0040c7a0f6a12..dd26cacd0556bac6bfe2d75d1ae54848a6f80698 100644 (file)
@@ -52,7 +52,7 @@
 #define LOCK_RETRY_DELAY                (200)
 
 /* Debug functions */
-static int debug;
+static bool debug;
 module_param(debug, bool, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
index 6abaa16ae136b950657e1086fee643a0f6cc8b50..6be9910a6e24a8fb2f22985701e23e43fdab7c5f 100644 (file)
@@ -703,21 +703,21 @@ static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
        /* First tests should be against specific std */
 
        if (std == V4L2_STD_ALL) {
-               fmt = 0;        /* Autodetect mode */
+               fmt = VIDEO_STD_AUTO_SWITCH_BIT;        /* Autodetect mode */
        } else if (std & V4L2_STD_NTSC_443) {
-               fmt = 0xa;
+               fmt = VIDEO_STD_NTSC_4_43_BIT;
        } else if (std & V4L2_STD_PAL_M) {
-               fmt = 0x6;
+               fmt = VIDEO_STD_PAL_M_BIT;
        } else if (std & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) {
-               fmt = 0x8;
+               fmt = VIDEO_STD_PAL_COMBINATION_N_BIT;
        } else {
                /* Then, test against generic ones */
                if (std & V4L2_STD_NTSC)
-                       fmt = 0x2;
+                       fmt = VIDEO_STD_NTSC_MJ_BIT;
                else if (std & V4L2_STD_PAL)
-                       fmt = 0x4;
+                       fmt = VIDEO_STD_PAL_BDGHIN_BIT;
                else if (std & V4L2_STD_SECAM)
-                       fmt = 0xc;
+                       fmt = VIDEO_STD_SECAM_BIT;
        }
 
        v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt);
@@ -779,6 +779,70 @@ static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
        return -EINVAL;
 }
 
+static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd)
+{
+       int val = tvp5150_read(sd, TVP5150_STATUS_REG_5);
+
+       switch (val & 0x0F) {
+       case 0x01:
+               return V4L2_STD_NTSC;
+       case 0x03:
+               return V4L2_STD_PAL;
+       case 0x05:
+               return V4L2_STD_PAL_M;
+       case 0x07:
+               return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc;
+       case 0x09:
+               return V4L2_STD_NTSC_443;
+       case 0xb:
+               return V4L2_STD_SECAM;
+       default:
+               return V4L2_STD_UNKNOWN;
+       }
+}
+
+static int tvp5150_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+                                               enum v4l2_mbus_pixelcode *code)
+{
+       if (index)
+               return -EINVAL;
+
+       *code = V4L2_MBUS_FMT_YUYV8_2X8;
+       return 0;
+}
+
+static int tvp5150_mbus_fmt(struct v4l2_subdev *sd,
+                           struct v4l2_mbus_framefmt *f)
+{
+       struct tvp5150 *decoder = to_tvp5150(sd);
+       v4l2_std_id std;
+
+       if (f == NULL)
+               return -EINVAL;
+
+       tvp5150_reset(sd, 0);
+
+       /* Calculate height and width based on current standard */
+       if (decoder->norm == V4L2_STD_ALL)
+               std = tvp5150_read_std(sd);
+       else
+               std = decoder->norm;
+
+       f->width = 720;
+       if (std & V4L2_STD_525_60)
+               f->height = 480;
+       else
+               f->height = 576;
+
+       f->code = V4L2_MBUS_FMT_YUYV8_2X8;
+       f->field = V4L2_FIELD_SEQ_TB;
+       f->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+       v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", f->width,
+                       f->height);
+       return 0;
+}
+
 /****************************************************************************
                        I2C Command
  ****************************************************************************/
@@ -931,6 +995,9 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
 
 static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
        .s_routing = tvp5150_s_routing,
+       .enum_mbus_fmt = tvp5150_enum_mbus_fmt,
+       .s_mbus_fmt = tvp5150_mbus_fmt,
+       .try_mbus_fmt = tvp5150_mbus_fmt,
 };
 
 static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
index 7875e80cb2ff277bdd555e55f52cdb0d87f666d0..236c559d5f51f11e25cff118173a0b3643baf379 100644 (file)
@@ -63,7 +63,7 @@ MODULE_LICENSE("GPL");
 #define TVP7002_CL_MASK                0x0f
 
 /* Debug functions */
-static int debug;
+static bool debug;
 module_param(debug, bool, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-2)");
 
index 9bbe61700fd5c238d253d309ea37a21a4f3ca6a1..65d065aa6091eb34ee4cea5c18b6e73ea892b1d1 100644 (file)
@@ -34,7 +34,7 @@ MODULE_DESCRIPTION("uPD64083 driver");
 MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static int debug;
+static bool debug;
 module_param(debug, bool, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
index d7f97513b2894c61902ed9783898997acae0893a..89fec029e9246c6933b7cfa6aea9441fc403536b 100644 (file)
@@ -110,42 +110,20 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap,
 
        unsigned char addr;
        int ret;
-       if ((flags & I2C_M_TEN)) {
-               /* a ten bit address */
-               addr = 0xf0 | ((msg->addr >> 7) & 0x03);
-               /* try extended address code... */
-               ret = try_write_address(i2c_adap, addr, retries);
-               if (ret != 1) {
-                       dev_err(&i2c_adap->dev,
-                               "died at extended address code, while writing\n");
-                       return -EREMOTEIO;
-               }
-               add[0] = addr;
-               if (flags & I2C_M_RD) {
-                       /* okay, now switch into reading mode */
-                       addr |= 0x01;
-                       ret = try_read_address(i2c_adap, addr, retries);
-                       if (ret != 1) {
-                               dev_err(&i2c_adap->dev,
-                                       "died at extended address code, while reading\n");
-                               return -EREMOTEIO;
-                       }
-               }
 
-       } else {                /* normal 7bit address  */
-               addr = (msg->addr << 1);
-               if (flags & I2C_M_RD)
-                       addr |= 1;
+       addr = (msg->addr << 1);
+       if (flags & I2C_M_RD)
+               addr |= 1;
 
-               add[0] = addr;
-               if (flags & I2C_M_RD)
-                       ret = try_read_address(i2c_adap, addr, retries);
-               else
-                       ret = try_write_address(i2c_adap, addr, retries);
+       add[0] = addr;
+       if (flags & I2C_M_RD)
+               ret = try_read_address(i2c_adap, addr, retries);
+       else
+               ret = try_write_address(i2c_adap, addr, retries);
+
+       if (ret != 1)
+               return -EREMOTEIO;
 
-               if (ret != 1)
-                       return -EREMOTEIO;
-       }
        return 0;
 }
 
@@ -184,7 +162,7 @@ usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
 
 static u32 functionality(struct i2c_adapter *adap)
 {
-       return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
 }
 
 /* -----exported algorithm data: ------------------------------------- */
index 2956a7637219acd6735a53f7d5292fec4ad45926..6c197da531b239b7dcc9c38058842c1b9af93c1c 100644 (file)
@@ -1,5 +1,6 @@
 config USB_VIDEO_CLASS
        tristate "USB Video Class (UVC)"
+       select VIDEOBUF2_VMALLOC
        ---help---
          Support for the USB Video Class (UVC).  Currently only video
          input devices, such as webcams, are supported.
index 2071ca8a2f031d86bb876fde6e3dcd79af31b92a..c26d12fdb8f4ef12d67222c40d99675cc0a045c5 100644 (file)
@@ -1,5 +1,5 @@
 uvcvideo-objs  := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
-                 uvc_status.o uvc_isight.o
+                 uvc_status.o uvc_isight.o uvc_debugfs.o
 ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
 uvcvideo-objs  += uvc_entity.o
 endif
index 254d32688843bdc3f0a38a782e13fef2ec8d5a18..0efd3b10b3537f94662bfb8be82f87ad5f3aee18 100644 (file)
@@ -878,8 +878,21 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
                                     chain->dev->intfnum, ctrl->info.selector,
                                     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
                                     ctrl->info.size);
-               if (ret < 0)
-                       return ret;
+               if (ret < 0) {
+                       if (UVC_ENTITY_TYPE(ctrl->entity) !=
+                           UVC_VC_EXTENSION_UNIT)
+                               return ret;
+
+                       /* GET_RES is mandatory for XU controls, but some
+                        * cameras still choke on it. Ignore errors and set the
+                        * resolution value to zero.
+                        */
+                       uvc_warn_once(chain->dev, UVC_WARN_XU_GET_RES,
+                                     "UVC non compliance - GET_RES failed on "
+                                     "an XU control. Enabling workaround.\n");
+                       memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), 0,
+                              ctrl->info.size);
+               }
        }
 
        ctrl->cached = 1;
@@ -1861,7 +1874,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
                if (ncontrols == 0)
                        continue;
 
-               entity->controls = kzalloc(ncontrols * sizeof(*ctrl),
+               entity->controls = kcalloc(ncontrols, sizeof(*ctrl),
                                           GFP_KERNEL);
                if (entity->controls == NULL)
                        return -ENOMEM;
diff --git a/drivers/media/video/uvc/uvc_debugfs.c b/drivers/media/video/uvc/uvc_debugfs.c
new file mode 100644 (file)
index 0000000..14561a5
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *      uvc_debugfs.c --  USB Video Class driver - Debugging support
+ *
+ *      Copyright (C) 2011
+ *          Laurent Pinchart (laurent.pinchart@ideasonboard.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/debugfs.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "uvcvideo.h"
+
+/* -----------------------------------------------------------------------------
+ * Statistics
+ */
+
+#define UVC_DEBUGFS_BUF_SIZE   1024
+
+struct uvc_debugfs_buffer {
+       size_t count;
+       char data[UVC_DEBUGFS_BUF_SIZE];
+};
+
+static int uvc_debugfs_stats_open(struct inode *inode, struct file *file)
+{
+       struct uvc_streaming *stream = inode->i_private;
+       struct uvc_debugfs_buffer *buf;
+
+       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       buf->count = uvc_video_stats_dump(stream, buf->data, sizeof(buf->data));
+
+       file->private_data = buf;
+       return 0;
+}
+
+static ssize_t uvc_debugfs_stats_read(struct file *file, char __user *user_buf,
+                                     size_t nbytes, loff_t *ppos)
+{
+       struct uvc_debugfs_buffer *buf = file->private_data;
+
+       return simple_read_from_buffer(user_buf, nbytes, ppos, buf->data,
+                                      buf->count);
+}
+
+static int uvc_debugfs_stats_release(struct inode *inode, struct file *file)
+{
+       kfree(file->private_data);
+       file->private_data = NULL;
+
+       return 0;
+}
+
+static const struct file_operations uvc_debugfs_stats_fops = {
+       .owner = THIS_MODULE,
+       .open = uvc_debugfs_stats_open,
+       .llseek = no_llseek,
+       .read = uvc_debugfs_stats_read,
+       .release = uvc_debugfs_stats_release,
+};
+
+/* -----------------------------------------------------------------------------
+ * Global and stream initialization/cleanup
+ */
+
+static struct dentry *uvc_debugfs_root_dir;
+
+int uvc_debugfs_init_stream(struct uvc_streaming *stream)
+{
+       struct usb_device *udev = stream->dev->udev;
+       struct dentry *dent;
+       char dir_name[32];
+
+       if (uvc_debugfs_root_dir == NULL)
+               return -ENODEV;
+
+       sprintf(dir_name, "%u-%u", udev->bus->busnum, udev->devnum);
+
+       dent = debugfs_create_dir(dir_name, uvc_debugfs_root_dir);
+       if (IS_ERR_OR_NULL(dent)) {
+               uvc_printk(KERN_INFO, "Unable to create debugfs %s "
+                          "directory.\n", dir_name);
+               return -ENODEV;
+       }
+
+       stream->debugfs_dir = dent;
+
+       dent = debugfs_create_file("stats", 0444, stream->debugfs_dir,
+                                  stream, &uvc_debugfs_stats_fops);
+       if (IS_ERR_OR_NULL(dent)) {
+               uvc_printk(KERN_INFO, "Unable to create debugfs stats file.\n");
+               uvc_debugfs_cleanup_stream(stream);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream)
+{
+       if (stream->debugfs_dir == NULL)
+               return;
+
+       debugfs_remove_recursive(stream->debugfs_dir);
+       stream->debugfs_dir = NULL;
+}
+
+int uvc_debugfs_init(void)
+{
+       struct dentry *dir;
+
+       dir = debugfs_create_dir("uvcvideo", usb_debug_root);
+       if (IS_ERR_OR_NULL(dir)) {
+               uvc_printk(KERN_INFO, "Unable to create debugfs directory\n");
+               return -ENODATA;
+       }
+
+       uvc_debugfs_root_dir = dir;
+       return 0;
+}
+
+void uvc_debugfs_cleanup(void)
+{
+       if (uvc_debugfs_root_dir != NULL)
+               debugfs_remove_recursive(uvc_debugfs_root_dir);
+}
index 656d4c9e3b9f85a07d96a57b5401b13e9526aa4d..a240d43d15d1b595720ff31925182d17b41b982e 100644 (file)
@@ -1675,6 +1675,8 @@ static void uvc_unregister_video(struct uvc_device *dev)
 
                video_unregister_device(stream->vdev);
                stream->vdev = NULL;
+
+               uvc_debugfs_cleanup_stream(stream);
        }
 
        /* Decrement the stream count and call uvc_delete explicitly if there
@@ -1700,6 +1702,8 @@ static int uvc_register_video(struct uvc_device *dev,
                return ret;
        }
 
+       uvc_debugfs_init_stream(stream);
+
        /* Register the device with V4L. */
        vdev = video_device_alloc();
        if (vdev == NULL) {
@@ -2033,6 +2037,15 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
  * though they are compliant.
  */
 static struct usb_device_id uvc_ids[] = {
+       /* LogiLink Wireless Webcam */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x0416,
+         .idProduct            = 0xa91a,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* Genius eFace 2025 */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2396,17 +2409,24 @@ struct uvc_driver uvc_driver = {
 
 static int __init uvc_init(void)
 {
-       int result;
+       int ret;
+
+       uvc_debugfs_init();
 
-       result = usb_register(&uvc_driver.driver);
-       if (result == 0)
-               printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");
-       return result;
+       ret = usb_register(&uvc_driver.driver);
+       if (ret < 0) {
+               uvc_debugfs_cleanup();
+               return ret;
+       }
+
+       printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");
+       return 0;
 }
 
 static void __exit uvc_cleanup(void)
 {
        usb_deregister(&uvc_driver.driver);
+       uvc_debugfs_cleanup();
 }
 
 module_init(uvc_init);
index 74bbe8f18f3e51a6b337a22963a8de2474809763..8510e7259e7639cdf30e343801fa38792dd619f0 100644 (file)
@@ -74,7 +74,7 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
         * Empty buffers (bytesused == 0) don't trigger end of frame detection
         * as it doesn't make sense to return an empty buffer.
         */
-       if (is_header && buf->buf.bytesused != 0) {
+       if (is_header && buf->bytesused != 0) {
                buf->state = UVC_BUF_STATE_DONE;
                return -EAGAIN;
        }
@@ -83,13 +83,13 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
         * contain no data.
         */
        if (!is_header) {
-               maxlen = buf->buf.length - buf->buf.bytesused;
-               mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+               maxlen = buf->length - buf->bytesused;
+               mem = buf->mem + buf->bytesused;
                nbytes = min(len, maxlen);
                memcpy(mem, data, nbytes);
-               buf->buf.bytesused += nbytes;
+               buf->bytesused += nbytes;
 
-               if (len > maxlen || buf->buf.bytesused == buf->buf.length) {
+               if (len > maxlen || buf->bytesused == buf->length) {
                        uvc_trace(UVC_TRACE_FRAME, "Frame complete "
                                  "(overflow).\n");
                        buf->state = UVC_BUF_STATE_DONE;
index 677691c44500f1ee0d8212c6639acf64861d1428..518f77d3a4d820bad41129be9ab623077ada54dc 100644 (file)
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/atomic.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/list.h>
@@ -19,7 +20,7 @@
 #include <linux/videodev2.h>
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
-#include <linux/atomic.h>
+#include <media/videobuf2-vmalloc.h>
 
 #include "uvcvideo.h"
 
  * Video queues is initialized by uvc_queue_init(). The function performs
  * basic initialization of the uvc_video_queue struct and never fails.
  *
- * Video buffer allocation and freeing are performed by uvc_alloc_buffers and
- * uvc_free_buffers respectively. The former acquires the video queue lock,
- * while the later must be called with the lock held (so that allocation can
- * free previously allocated buffers). Trying to free buffers that are mapped
- * to user space will return -EBUSY.
- *
- * Video buffers are managed using two queues. However, unlike most USB video
- * drivers that use an in queue and an out queue, we use a main queue to hold
- * all queued buffers (both 'empty' and 'done' buffers), and an irq queue to
- * hold empty buffers. This design (copied from video-buf) minimizes locking
- * in interrupt, as only one queue is shared between interrupt and user
- * contexts.
- *
- * Use cases
- * ---------
- *
- * Unless stated otherwise, all operations that modify the irq buffers queue
- * are protected by the irq spinlock.
- *
- * 1. The user queues the buffers, starts streaming and dequeues a buffer.
- *
- *    The buffers are added to the main and irq queues. Both operations are
- *    protected by the queue lock, and the later is protected by the irq
- *    spinlock as well.
- *
- *    The completion handler fetches a buffer from the irq queue and fills it
- *    with video data. If no buffer is available (irq queue empty), the handler
- *    returns immediately.
- *
- *    When the buffer is full, the completion handler removes it from the irq
- *    queue, marks it as done (UVC_BUF_STATE_DONE) and wakes its wait queue.
- *    At that point, any process waiting on the buffer will be woken up. If a
- *    process tries to dequeue a buffer after it has been marked done, the
- *    dequeing will succeed immediately.
- *
- * 2. Buffers are queued, user is waiting on a buffer and the device gets
- *    disconnected.
- *
- *    When the device is disconnected, the kernel calls the completion handler
- *    with an appropriate status code. The handler marks all buffers in the
- *    irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so
- *    that any process waiting on a buffer gets woken up.
- *
- *    Waking up up the first buffer on the irq list is not enough, as the
- *    process waiting on the buffer might restart the dequeue operation
- *    immediately.
- *
+ * Video buffers are managed by videobuf2. The driver uses a mutex to protect
+ * the videobuf2 queue operations by serializing calls to videobuf2 and a
+ * spinlock to protect the IRQ queue that holds the buffers to be processed by
+ * the driver.
  */
 
-void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
-                   int drop_corrupted)
-{
-       mutex_init(&queue->mutex);
-       spin_lock_init(&queue->irqlock);
-       INIT_LIST_HEAD(&queue->mainqueue);
-       INIT_LIST_HEAD(&queue->irqqueue);
-       queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0;
-       queue->type = type;
-}
-
-/*
- * Free the video buffers.
- *
- * This function must be called with the queue lock held.
+/* -----------------------------------------------------------------------------
+ * videobuf2 queue operations
  */
-static int __uvc_free_buffers(struct uvc_video_queue *queue)
+
+static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                          unsigned int *nbuffers, unsigned int *nplanes,
+                          unsigned int sizes[], void *alloc_ctxs[])
 {
-       unsigned int i;
+       struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
+       struct uvc_streaming *stream =
+                       container_of(queue, struct uvc_streaming, queue);
 
-       for (i = 0; i < queue->count; ++i) {
-               if (queue->buffer[i].vma_use_count != 0)
-                       return -EBUSY;
-       }
+       if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
+               *nbuffers = UVC_MAX_VIDEO_BUFFERS;
 
-       if (queue->count) {
-               uvc_queue_cancel(queue, 0);
-               INIT_LIST_HEAD(&queue->mainqueue);
-               vfree(queue->mem);
-               queue->count = 0;
-       }
+       *nplanes = 1;
+
+       sizes[0] = stream->ctrl.dwMaxVideoFrameSize;
 
        return 0;
 }
 
-int uvc_free_buffers(struct uvc_video_queue *queue)
+static int uvc_buffer_prepare(struct vb2_buffer *vb)
 {
-       int ret;
+       struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+       struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
 
-       mutex_lock(&queue->mutex);
-       ret = __uvc_free_buffers(queue);
-       mutex_unlock(&queue->mutex);
+       if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+           vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
+               uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
+               return -EINVAL;
+       }
 
-       return ret;
-}
+       if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED))
+               return -ENODEV;
 
-/*
- * Allocate the video buffers.
- *
- * Pages are reserved to make sure they will not be swapped, as they will be
- * filled in the URB completion handler.
- *
- * Buffers will be individually mapped, so they must all be page aligned.
- */
-int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
-               unsigned int buflength)
-{
-       unsigned int bufsize = PAGE_ALIGN(buflength);
-       unsigned int i;
-       void *mem = NULL;
-       int ret;
+       buf->state = UVC_BUF_STATE_QUEUED;
+       buf->error = 0;
+       buf->mem = vb2_plane_vaddr(vb, 0);
+       buf->length = vb2_plane_size(vb, 0);
+       if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               buf->bytesused = 0;
+       else
+               buf->bytesused = vb2_get_plane_payload(vb, 0);
 
-       if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
-               nbuffers = UVC_MAX_VIDEO_BUFFERS;
+       return 0;
+}
 
-       mutex_lock(&queue->mutex);
+static void uvc_buffer_queue(struct vb2_buffer *vb)
+{
+       struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+       struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
+       unsigned long flags;
 
-       if ((ret = __uvc_free_buffers(queue)) < 0)
-               goto done;
+       spin_lock_irqsave(&queue->irqlock, flags);
+       if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
+               list_add_tail(&buf->queue, &queue->irqqueue);
+       } else {
+               /* If the device is disconnected return the buffer to userspace
+                * directly. The next QBUF call will fail with -ENODEV.
+                */
+               buf->state = UVC_BUF_STATE_ERROR;
+               vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
+       }
 
-       /* Bail out if no buffers should be allocated. */
-       if (nbuffers == 0)
-               goto done;
+       spin_unlock_irqrestore(&queue->irqlock, flags);
+}
 
-       /* Decrement the number of buffers until allocation succeeds. */
-       for (; nbuffers > 0; --nbuffers) {
-               mem = vmalloc_32(nbuffers * bufsize);
-               if (mem != NULL)
-                       break;
-       }
+static int uvc_buffer_finish(struct vb2_buffer *vb)
+{
+       struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+       struct uvc_streaming *stream =
+                       container_of(queue, struct uvc_streaming, queue);
+       struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
 
-       if (mem == NULL) {
-               ret = -ENOMEM;
-               goto done;
-       }
+       uvc_video_clock_update(stream, &vb->v4l2_buf, buf);
+       return 0;
+}
 
-       for (i = 0; i < nbuffers; ++i) {
-               memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
-               queue->buffer[i].buf.index = i;
-               queue->buffer[i].buf.m.offset = i * bufsize;
-               queue->buffer[i].buf.length = buflength;
-               queue->buffer[i].buf.type = queue->type;
-               queue->buffer[i].buf.field = V4L2_FIELD_NONE;
-               queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
-               queue->buffer[i].buf.flags = 0;
-               init_waitqueue_head(&queue->buffer[i].wait);
-       }
+static struct vb2_ops uvc_queue_qops = {
+       .queue_setup = uvc_queue_setup,
+       .buf_prepare = uvc_buffer_prepare,
+       .buf_queue = uvc_buffer_queue,
+       .buf_finish = uvc_buffer_finish,
+};
 
-       queue->mem = mem;
-       queue->count = nbuffers;
-       queue->buf_size = bufsize;
-       ret = nbuffers;
+void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
+                   int drop_corrupted)
+{
+       queue->queue.type = type;
+       queue->queue.io_modes = VB2_MMAP;
+       queue->queue.drv_priv = queue;
+       queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
+       queue->queue.ops = &uvc_queue_qops;
+       queue->queue.mem_ops = &vb2_vmalloc_memops;
+       vb2_queue_init(&queue->queue);
 
-done:
-       mutex_unlock(&queue->mutex);
-       return ret;
+       mutex_init(&queue->mutex);
+       spin_lock_init(&queue->irqlock);
+       INIT_LIST_HEAD(&queue->irqqueue);
+       queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0;
 }
 
-/*
- * Check if buffers have been allocated.
+/* -----------------------------------------------------------------------------
+ * V4L2 queue operations
  */
-int uvc_queue_allocated(struct uvc_video_queue *queue)
+
+int uvc_alloc_buffers(struct uvc_video_queue *queue,
+                     struct v4l2_requestbuffers *rb)
 {
-       int allocated;
+       int ret;
 
        mutex_lock(&queue->mutex);
-       allocated = queue->count != 0;
+       ret = vb2_reqbufs(&queue->queue, rb);
        mutex_unlock(&queue->mutex);
 
-       return allocated;
+       return ret ? ret : rb->count;
 }
 
-static void __uvc_query_buffer(struct uvc_buffer *buf,
-               struct v4l2_buffer *v4l2_buf)
+void uvc_free_buffers(struct uvc_video_queue *queue)
 {
-       memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
-
-       if (buf->vma_use_count)
-               v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
-
-       switch (buf->state) {
-       case UVC_BUF_STATE_ERROR:
-       case UVC_BUF_STATE_DONE:
-               v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
-               break;
-       case UVC_BUF_STATE_QUEUED:
-       case UVC_BUF_STATE_ACTIVE:
-       case UVC_BUF_STATE_READY:
-               v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
-               break;
-       case UVC_BUF_STATE_IDLE:
-       default:
-               break;
-       }
+       mutex_lock(&queue->mutex);
+       vb2_queue_release(&queue->queue);
+       mutex_unlock(&queue->mutex);
 }
 
-int uvc_query_buffer(struct uvc_video_queue *queue,
-               struct v4l2_buffer *v4l2_buf)
+int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
 {
-       int ret = 0;
+       int ret;
 
        mutex_lock(&queue->mutex);
-       if (v4l2_buf->index >= queue->count) {
-               ret = -EINVAL;
-               goto done;
-       }
-
-       __uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
-
-done:
+       ret = vb2_querybuf(&queue->queue, buf);
        mutex_unlock(&queue->mutex);
+
        return ret;
 }
 
-/*
- * Queue a video buffer. Attempting to queue a buffer that has already been
- * queued will return -EINVAL.
- */
-int uvc_queue_buffer(struct uvc_video_queue *queue,
-       struct v4l2_buffer *v4l2_buf)
+int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
 {
-       struct uvc_buffer *buf;
-       unsigned long flags;
-       int ret = 0;
-
-       uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
-
-       if (v4l2_buf->type != queue->type ||
-           v4l2_buf->memory != V4L2_MEMORY_MMAP) {
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
-                       "and/or memory (%u).\n", v4l2_buf->type,
-                       v4l2_buf->memory);
-               return -EINVAL;
-       }
+       int ret;
 
        mutex_lock(&queue->mutex);
-       if (v4l2_buf->index >= queue->count) {
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
-               ret = -EINVAL;
-               goto done;
-       }
-
-       buf = &queue->buffer[v4l2_buf->index];
-       if (buf->state != UVC_BUF_STATE_IDLE) {
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
-                       "(%u).\n", buf->state);
-               ret = -EINVAL;
-               goto done;
-       }
-
-       if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-           v4l2_buf->bytesused > buf->buf.length) {
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
-               ret = -EINVAL;
-               goto done;
-       }
-
-       spin_lock_irqsave(&queue->irqlock, flags);
-       if (queue->flags & UVC_QUEUE_DISCONNECTED) {
-               spin_unlock_irqrestore(&queue->irqlock, flags);
-               ret = -ENODEV;
-               goto done;
-       }
-       buf->state = UVC_BUF_STATE_QUEUED;
-       if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               buf->buf.bytesused = 0;
-       else
-               buf->buf.bytesused = v4l2_buf->bytesused;
-
-       list_add_tail(&buf->stream, &queue->mainqueue);
-       list_add_tail(&buf->queue, &queue->irqqueue);
-       spin_unlock_irqrestore(&queue->irqlock, flags);
-
-done:
+       ret = vb2_qbuf(&queue->queue, buf);
        mutex_unlock(&queue->mutex);
-       return ret;
-}
 
-static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
-{
-       if (nonblocking) {
-               return (buf->state != UVC_BUF_STATE_QUEUED &&
-                       buf->state != UVC_BUF_STATE_ACTIVE &&
-                       buf->state != UVC_BUF_STATE_READY)
-                       ? 0 : -EAGAIN;
-       }
-
-       return wait_event_interruptible(buf->wait,
-               buf->state != UVC_BUF_STATE_QUEUED &&
-               buf->state != UVC_BUF_STATE_ACTIVE &&
-               buf->state != UVC_BUF_STATE_READY);
+       return ret;
 }
 
-/*
- * Dequeue a video buffer. If nonblocking is false, block until a buffer is
- * available.
- */
-int uvc_dequeue_buffer(struct uvc_video_queue *queue,
-               struct v4l2_buffer *v4l2_buf, int nonblocking)
+int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf,
+                      int nonblocking)
 {
-       struct uvc_buffer *buf;
-       int ret = 0;
-
-       if (v4l2_buf->type != queue->type ||
-           v4l2_buf->memory != V4L2_MEMORY_MMAP) {
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
-                       "and/or memory (%u).\n", v4l2_buf->type,
-                       v4l2_buf->memory);
-               return -EINVAL;
-       }
+       int ret;
 
        mutex_lock(&queue->mutex);
-       if (list_empty(&queue->mainqueue)) {
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
-               ret = -EINVAL;
-               goto done;
-       }
-
-       buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
-       if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0)
-               goto done;
-
-       uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n",
-               buf->buf.index, buf->state, buf->buf.bytesused);
-
-       switch (buf->state) {
-       case UVC_BUF_STATE_ERROR:
-               uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data "
-                       "(transmission error).\n");
-               ret = -EIO;
-       case UVC_BUF_STATE_DONE:
-               buf->state = UVC_BUF_STATE_IDLE;
-               break;
-
-       case UVC_BUF_STATE_IDLE:
-       case UVC_BUF_STATE_QUEUED:
-       case UVC_BUF_STATE_ACTIVE:
-       case UVC_BUF_STATE_READY:
-       default:
-               uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
-                       "(driver bug?).\n", buf->state);
-               ret = -EINVAL;
-               goto done;
-       }
-
-       list_del(&buf->stream);
-       __uvc_query_buffer(buf, v4l2_buf);
-
-done:
+       ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
        mutex_unlock(&queue->mutex);
-       return ret;
-}
 
-/*
- * VMA operations.
- */
-static void uvc_vm_open(struct vm_area_struct *vma)
-{
-       struct uvc_buffer *buffer = vma->vm_private_data;
-       buffer->vma_use_count++;
-}
-
-static void uvc_vm_close(struct vm_area_struct *vma)
-{
-       struct uvc_buffer *buffer = vma->vm_private_data;
-       buffer->vma_use_count--;
+       return ret;
 }
 
-static const struct vm_operations_struct uvc_vm_ops = {
-       .open           = uvc_vm_open,
-       .close          = uvc_vm_close,
-};
-
-/*
- * Memory-map a video buffer.
- *
- * This function implements video buffers memory mapping and is intended to be
- * used by the device mmap handler.
- */
 int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
 {
-       struct uvc_buffer *uninitialized_var(buffer);
-       struct page *page;
-       unsigned long addr, start, size;
-       unsigned int i;
-       int ret = 0;
-
-       start = vma->vm_start;
-       size = vma->vm_end - vma->vm_start;
+       int ret;
 
        mutex_lock(&queue->mutex);
+       ret = vb2_mmap(&queue->queue, vma);
+       mutex_unlock(&queue->mutex);
 
-       for (i = 0; i < queue->count; ++i) {
-               buffer = &queue->buffer[i];
-               if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
-                       break;
-       }
-
-       if (i == queue->count || PAGE_ALIGN(size) != queue->buf_size) {
-               ret = -EINVAL;
-               goto done;
-       }
-
-       /*
-        * VM_IO marks the area as being an mmaped region for I/O to a
-        * device. It also prevents the region from being core dumped.
-        */
-       vma->vm_flags |= VM_IO;
-
-       addr = (unsigned long)queue->mem + buffer->buf.m.offset;
-#ifdef CONFIG_MMU
-       while (size > 0) {
-               page = vmalloc_to_page((void *)addr);
-               if ((ret = vm_insert_page(vma, start, page)) < 0)
-                       goto done;
-
-               start += PAGE_SIZE;
-               addr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-#endif
+       return ret;
+}
 
-       vma->vm_ops = &uvc_vm_ops;
-       vma->vm_private_data = buffer;
-       uvc_vm_open(vma);
+unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
+                           poll_table *wait)
+{
+       unsigned int ret;
 
-done:
+       mutex_lock(&queue->mutex);
+       ret = vb2_poll(&queue->queue, file, wait);
        mutex_unlock(&queue->mutex);
+
        return ret;
 }
 
-/*
- * Poll the video queue.
+/* -----------------------------------------------------------------------------
  *
- * This function implements video queue polling and is intended to be used by
- * the device poll handler.
  */
-unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
-               poll_table *wait)
+
+/*
+ * Check if buffers have been allocated.
+ */
+int uvc_queue_allocated(struct uvc_video_queue *queue)
 {
-       struct uvc_buffer *buf;
-       unsigned int mask = 0;
+       int allocated;
 
        mutex_lock(&queue->mutex);
-       if (list_empty(&queue->mainqueue)) {
-               mask |= POLLERR;
-               goto done;
-       }
-       buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
-
-       poll_wait(file, &buf->wait, wait);
-       if (buf->state == UVC_BUF_STATE_DONE ||
-           buf->state == UVC_BUF_STATE_ERROR) {
-               if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       mask |= POLLIN | POLLRDNORM;
-               else
-                       mask |= POLLOUT | POLLWRNORM;
-       }
-
-done:
+       allocated = vb2_is_busy(&queue->queue);
        mutex_unlock(&queue->mutex);
-       return mask;
+
+       return allocated;
 }
 
 #ifndef CONFIG_MMU
@@ -515,7 +260,7 @@ unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
                ret = -EINVAL;
                goto done;
        }
-       ret = (unsigned long)queue->mem + buffer->buf.m.offset;
+       ret = (unsigned long)buf->mem;
 done:
        mutex_unlock(&queue->mutex);
        return ret;
@@ -540,27 +285,24 @@ done:
  */
 int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
 {
-       unsigned int i;
-       int ret = 0;
+       unsigned long flags;
+       int ret;
 
        mutex_lock(&queue->mutex);
        if (enable) {
-               if (uvc_queue_streaming(queue)) {
-                       ret = -EBUSY;
+               ret = vb2_streamon(&queue->queue, queue->queue.type);
+               if (ret < 0)
                        goto done;
-               }
-               queue->flags |= UVC_QUEUE_STREAMING;
+
                queue->buf_used = 0;
        } else {
-               uvc_queue_cancel(queue, 0);
-               INIT_LIST_HEAD(&queue->mainqueue);
-
-               for (i = 0; i < queue->count; ++i) {
-                       queue->buffer[i].error = 0;
-                       queue->buffer[i].state = UVC_BUF_STATE_IDLE;
-               }
+               ret = vb2_streamoff(&queue->queue, queue->queue.type);
+               if (ret < 0)
+                       goto done;
 
-               queue->flags &= ~UVC_QUEUE_STREAMING;
+               spin_lock_irqsave(&queue->irqlock, flags);
+               INIT_LIST_HEAD(&queue->irqqueue);
+               spin_unlock_irqrestore(&queue->irqlock, flags);
        }
 
 done:
@@ -591,12 +333,12 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
                                       queue);
                list_del(&buf->queue);
                buf->state = UVC_BUF_STATE_ERROR;
-               wake_up(&buf->wait);
+               vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
        }
        /* This must be protected by the irqlock spinlock to avoid race
-        * conditions between uvc_queue_buffer and the disconnection event that
+        * conditions between uvc_buffer_queue and the disconnection event that
         * could result in an interruptible wait in uvc_dequeue_buffer. Do not
-        * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED
+        * blindly replace this logic by checking for the UVC_QUEUE_DISCONNECTED
         * state outside the queue code.
         */
        if (disconnect)
@@ -613,14 +355,12 @@ 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->buf.bytesused = 0;
+               vb2_set_plane_payload(&buf->buf, 0, 0);
                return buf;
        }
 
        spin_lock_irqsave(&queue->irqlock, flags);
        list_del(&buf->queue);
-       buf->error = 0;
-       buf->state = UVC_BUF_STATE_DONE;
        if (!list_empty(&queue->irqqueue))
                nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
                                           queue);
@@ -628,7 +368,9 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
                nextbuf = NULL;
        spin_unlock_irqrestore(&queue->irqlock, flags);
 
-       wake_up(&buf->wait);
+       buf->state = buf->error ? VB2_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
+       vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);
+       vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
+
        return nextbuf;
 }
-
index dadf11f704dc742e8fe21d8df0880f35e3b9128e..2ae4f880ea05ed5bd67bee2a4816fcea7ed464ae 100644 (file)
@@ -58,6 +58,15 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
                break;
 
        case V4L2_CTRL_TYPE_MENU:
+               /* Prevent excessive memory consumption, as well as integer
+                * overflows.
+                */
+               if (xmap->menu_count == 0 ||
+                   xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) {
+                       ret = -EINVAL;
+                       goto done;
+               }
+
                size = xmap->menu_count * sizeof(*map->menu_info);
                map->menu_info = kmalloc(size, GFP_KERNEL);
                if (map->menu_info == NULL) {
@@ -513,10 +522,7 @@ static int uvc_v4l2_release(struct file *file)
        /* Only free resources if this is a privileged handle. */
        if (uvc_has_privileges(handle)) {
                uvc_video_enable(stream, 0);
-
-               if (uvc_free_buffers(&stream->queue) < 0)
-                       uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
-                                       "free buffers.\n");
+               uvc_free_buffers(&stream->queue);
        }
 
        /* Release the file handle. */
@@ -914,19 +920,11 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        /* Buffers & streaming */
        case VIDIOC_REQBUFS:
-       {
-               struct v4l2_requestbuffers *rb = arg;
-
-               if (rb->type != stream->type ||
-                   rb->memory != V4L2_MEMORY_MMAP)
-                       return -EINVAL;
-
                if ((ret = uvc_acquire_privileges(handle)) < 0)
                        return ret;
 
                mutex_lock(&stream->mutex);
-               ret = uvc_alloc_buffers(&stream->queue, rb->count,
-                                       stream->ctrl.dwMaxVideoFrameSize);
+               ret = uvc_alloc_buffers(&stream->queue, arg);
                mutex_unlock(&stream->mutex);
                if (ret < 0)
                        return ret;
@@ -934,18 +932,13 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                if (ret == 0)
                        uvc_dismiss_privileges(handle);
 
-               rb->count = ret;
                ret = 0;
                break;
-       }
 
        case VIDIOC_QUERYBUF:
        {
                struct v4l2_buffer *buf = arg;
 
-               if (buf->type != stream->type)
-                       return -EINVAL;
-
                if (!uvc_has_privileges(handle))
                        return -EBUSY;
 
index b015e8e5e8b08ad6ade229a02e63f2ea2396edaf..c7e69b8f81c9555b5a1296b96355957b8e91089b 100644 (file)
@@ -351,25 +351,553 @@ done:
        return ret;
 }
 
-int uvc_commit_video(struct uvc_streaming *stream,
-       struct uvc_streaming_control *probe)
+static int uvc_commit_video(struct uvc_streaming *stream,
+                           struct uvc_streaming_control *probe)
 {
        return uvc_set_video_ctrl(stream, probe, 0);
 }
 
+/* -----------------------------------------------------------------------------
+ * Clocks and timestamps
+ */
+
+static void
+uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
+                      const __u8 *data, int len)
+{
+       struct uvc_clock_sample *sample;
+       unsigned int header_size;
+       bool has_pts = false;
+       bool has_scr = false;
+       unsigned long flags;
+       struct timespec ts;
+       u16 host_sof;
+       u16 dev_sof;
+
+       switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
+       case UVC_STREAM_PTS | UVC_STREAM_SCR:
+               header_size = 12;
+               has_pts = true;
+               has_scr = true;
+               break;
+       case UVC_STREAM_PTS:
+               header_size = 6;
+               has_pts = true;
+               break;
+       case UVC_STREAM_SCR:
+               header_size = 8;
+               has_scr = true;
+               break;
+       default:
+               header_size = 2;
+               break;
+       }
+
+       /* Check for invalid headers. */
+       if (len < header_size)
+               return;
+
+       /* Extract the timestamps:
+        *
+        * - store the frame PTS in the buffer structure
+        * - if the SCR field is present, retrieve the host SOF counter and
+        *   kernel timestamps and store them with the SCR STC and SOF fields
+        *   in the ring buffer
+        */
+       if (has_pts && buf != NULL)
+               buf->pts = get_unaligned_le32(&data[2]);
+
+       if (!has_scr)
+               return;
+
+       /* To limit the amount of data, drop SCRs with an SOF identical to the
+        * previous one.
+        */
+       dev_sof = get_unaligned_le16(&data[header_size - 2]);
+       if (dev_sof == stream->clock.last_sof)
+               return;
+
+       stream->clock.last_sof = dev_sof;
+
+       host_sof = usb_get_current_frame_number(stream->dev->udev);
+       ktime_get_ts(&ts);
+
+       /* The UVC specification allows device implementations that can't obtain
+        * the USB frame number to keep their own frame counters as long as they
+        * match the size and frequency of the frame number associated with USB
+        * SOF tokens. The SOF values sent by such devices differ from the USB
+        * SOF tokens by a fixed offset that needs to be estimated and accounted
+        * for to make timestamp recovery as accurate as possible.
+        *
+        * The offset is estimated the first time a device SOF value is received
+        * as the difference between the host and device SOF values. As the two
+        * SOF values can differ slightly due to transmission delays, consider
+        * that the offset is null if the difference is not higher than 10 ms
+        * (negative differences can not happen and are thus considered as an
+        * offset). The video commit control wDelay field should be used to
+        * compute a dynamic threshold instead of using a fixed 10 ms value, but
+        * devices don't report reliable wDelay values.
+        *
+        * See uvc_video_clock_host_sof() for an explanation regarding why only
+        * the 8 LSBs of the delta are kept.
+        */
+       if (stream->clock.sof_offset == (u16)-1) {
+               u16 delta_sof = (host_sof - dev_sof) & 255;
+               if (delta_sof >= 10)
+                       stream->clock.sof_offset = delta_sof;
+               else
+                       stream->clock.sof_offset = 0;
+       }
+
+       dev_sof = (dev_sof + stream->clock.sof_offset) & 2047;
+
+       spin_lock_irqsave(&stream->clock.lock, flags);
+
+       sample = &stream->clock.samples[stream->clock.head];
+       sample->dev_stc = get_unaligned_le32(&data[header_size - 6]);
+       sample->dev_sof = dev_sof;
+       sample->host_sof = host_sof;
+       sample->host_ts = ts;
+
+       /* Update the sliding window head and count. */
+       stream->clock.head = (stream->clock.head + 1) % stream->clock.size;
+
+       if (stream->clock.count < stream->clock.size)
+               stream->clock.count++;
+
+       spin_unlock_irqrestore(&stream->clock.lock, flags);
+}
+
+static int uvc_video_clock_init(struct uvc_streaming *stream)
+{
+       struct uvc_clock *clock = &stream->clock;
+
+       spin_lock_init(&clock->lock);
+       clock->head = 0;
+       clock->count = 0;
+       clock->size = 32;
+       clock->last_sof = -1;
+       clock->sof_offset = -1;
+
+       clock->samples = kmalloc(clock->size * sizeof(*clock->samples),
+                                GFP_KERNEL);
+       if (clock->samples == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void uvc_video_clock_cleanup(struct uvc_streaming *stream)
+{
+       kfree(stream->clock.samples);
+       stream->clock.samples = NULL;
+}
+
+/*
+ * uvc_video_clock_host_sof - Return the host SOF value for a clock sample
+ *
+ * Host SOF counters reported by usb_get_current_frame_number() usually don't
+ * cover the whole 11-bits SOF range (0-2047) but are limited to the HCI frame
+ * schedule window. They can be limited to 8, 9 or 10 bits depending on the host
+ * controller and its configuration.
+ *
+ * We thus need to recover the SOF value corresponding to the host frame number.
+ * As the device and host frame numbers are sampled in a short interval, the
+ * difference between their values should be equal to a small delta plus an
+ * integer multiple of 256 caused by the host frame number limited precision.
+ *
+ * To obtain the recovered host SOF value, compute the small delta by masking
+ * the high bits of the host frame counter and device SOF difference and add it
+ * to the device SOF value.
+ */
+static u16 uvc_video_clock_host_sof(const struct uvc_clock_sample *sample)
+{
+       /* The delta value can be negative. */
+       s8 delta_sof;
+
+       delta_sof = (sample->host_sof - sample->dev_sof) & 255;
+
+       return (sample->dev_sof + delta_sof) & 2047;
+}
+
+/*
+ * uvc_video_clock_update - Update the buffer timestamp
+ *
+ * This function converts the buffer PTS timestamp to the host clock domain by
+ * going through the USB SOF clock domain and stores the result in the V4L2
+ * buffer timestamp field.
+ *
+ * The relationship between the device clock and the host clock isn't known.
+ * However, the device and the host share the common USB SOF clock which can be
+ * used to recover that relationship.
+ *
+ * The relationship between the device clock and the USB SOF clock is considered
+ * to be linear over the clock samples sliding window and is given by
+ *
+ * SOF = m * PTS + p
+ *
+ * Several methods to compute the slope (m) and intercept (p) can be used. As
+ * the clock drift should be small compared to the sliding window size, we
+ * assume that the line that goes through the points at both ends of the window
+ * is a good approximation. Naming those points P1 and P2, we get
+ *
+ * SOF = (SOF2 - SOF1) / (STC2 - STC1) * PTS
+ *     + (SOF1 * STC2 - SOF2 * STC1) / (STC2 - STC1)
+ *
+ * or
+ *
+ * SOF = ((SOF2 - SOF1) * PTS + SOF1 * STC2 - SOF2 * STC1) / (STC2 - STC1)   (1)
+ *
+ * to avoid loosing precision in the division. Similarly, the host timestamp is
+ * computed with
+ *
+ * TS = ((TS2 - TS1) * PTS + TS1 * SOF2 - TS2 * SOF1) / (SOF2 - SOF1)       (2)
+ *
+ * SOF values are coded on 11 bits by USB. We extend their precision with 16
+ * decimal bits, leading to a 11.16 coding.
+ *
+ * TODO: To avoid surprises with device clock values, PTS/STC timestamps should
+ * be normalized using the nominal device clock frequency reported through the
+ * UVC descriptors.
+ *
+ * Both the PTS/STC and SOF counters roll over, after a fixed but device
+ * specific amount of time for PTS/STC and after 2048ms for SOF. As long as the
+ * sliding window size is smaller than the rollover period, differences computed
+ * on unsigned integers will produce the correct result. However, the p term in
+ * the linear relations will be miscomputed.
+ *
+ * To fix the issue, we subtract a constant from the PTS and STC values to bring
+ * PTS to half the 32 bit STC range. The sliding window STC values then fit into
+ * the 32 bit range without any rollover.
+ *
+ * Similarly, we add 2048 to the device SOF values to make sure that the SOF
+ * computed by (1) will never be smaller than 0. This offset is then compensated
+ * by adding 2048 to the SOF values used in (2). However, this doesn't prevent
+ * rollovers between (1) and (2): the SOF value computed by (1) can be slightly
+ * lower than 4096, and the host SOF counters can have rolled over to 2048. This
+ * case is handled by subtracting 2048 from the SOF value if it exceeds the host
+ * SOF value at the end of the sliding window.
+ *
+ * Finally we subtract a constant from the host timestamps to bring the first
+ * timestamp of the sliding window to 1s.
+ */
+void uvc_video_clock_update(struct uvc_streaming *stream,
+                           struct v4l2_buffer *v4l2_buf,
+                           struct uvc_buffer *buf)
+{
+       struct uvc_clock *clock = &stream->clock;
+       struct uvc_clock_sample *first;
+       struct uvc_clock_sample *last;
+       unsigned long flags;
+       struct timespec ts;
+       u32 delta_stc;
+       u32 y1, y2;
+       u32 x1, x2;
+       u32 mean;
+       u32 sof;
+       u32 div;
+       u32 rem;
+       u64 y;
+
+       spin_lock_irqsave(&clock->lock, flags);
+
+       if (clock->count < clock->size)
+               goto done;
+
+       first = &clock->samples[clock->head];
+       last = &clock->samples[(clock->head - 1) % clock->size];
+
+       /* First step, PTS to SOF conversion. */
+       delta_stc = buf->pts - (1UL << 31);
+       x1 = first->dev_stc - delta_stc;
+       x2 = last->dev_stc - delta_stc;
+       y1 = (first->dev_sof + 2048) << 16;
+       y2 = (last->dev_sof + 2048) << 16;
+
+       if (y2 < y1)
+               y2 += 2048 << 16;
+
+       y = (u64)(y2 - y1) * (1ULL << 31) + (u64)y1 * (u64)x2
+         - (u64)y2 * (u64)x1;
+       y = div_u64(y, x2 - x1);
+
+       sof = y;
+
+       uvc_trace(UVC_TRACE_CLOCK, "%s: PTS %u y %llu.%06llu SOF %u.%06llu "
+                 "(x1 %u x2 %u y1 %u y2 %u SOF offset %u)\n",
+                 stream->dev->name, buf->pts,
+                 y >> 16, div_u64((y & 0xffff) * 1000000, 65536),
+                 sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),
+                 x1, x2, y1, y2, clock->sof_offset);
+
+       /* Second step, SOF to host clock conversion. */
+       ts = timespec_sub(last->host_ts, first->host_ts);
+       x1 = (uvc_video_clock_host_sof(first) + 2048) << 16;
+       x2 = (uvc_video_clock_host_sof(last) + 2048) << 16;
+       y1 = NSEC_PER_SEC;
+       y2 = (ts.tv_sec + 1) * NSEC_PER_SEC + ts.tv_nsec;
+
+       if (x2 < x1)
+               x2 += 2048 << 16;
+
+       /* Interpolated and host SOF timestamps can wrap around at slightly
+        * different times. Handle this by adding or removing 2048 to or from
+        * the computed SOF value to keep it close to the SOF samples mean
+        * value.
+        */
+       mean = (x1 + x2) / 2;
+       if (mean - (1024 << 16) > sof)
+               sof += 2048 << 16;
+       else if (sof > mean + (1024 << 16))
+               sof -= 2048 << 16;
+
+       y = (u64)(y2 - y1) * (u64)sof + (u64)y1 * (u64)x2
+         - (u64)y2 * (u64)x1;
+       y = div_u64(y, x2 - x1);
+
+       div = div_u64_rem(y, NSEC_PER_SEC, &rem);
+       ts.tv_sec = first->host_ts.tv_sec - 1 + div;
+       ts.tv_nsec = first->host_ts.tv_nsec + rem;
+       if (ts.tv_nsec >= NSEC_PER_SEC) {
+               ts.tv_sec++;
+               ts.tv_nsec -= NSEC_PER_SEC;
+       }
+
+       uvc_trace(UVC_TRACE_CLOCK, "%s: SOF %u.%06llu y %llu ts %lu.%06lu "
+                 "buf ts %lu.%06lu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n",
+                 stream->dev->name,
+                 sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),
+                 y, ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC,
+                 v4l2_buf->timestamp.tv_sec, v4l2_buf->timestamp.tv_usec,
+                 x1, first->host_sof, first->dev_sof,
+                 x2, last->host_sof, last->dev_sof, y1, y2);
+
+       /* Update the V4L2 buffer. */
+       v4l2_buf->timestamp.tv_sec = ts.tv_sec;
+       v4l2_buf->timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+
+done:
+       spin_unlock_irqrestore(&stream->clock.lock, flags);
+}
+
 /* ------------------------------------------------------------------------
- * Video codecs
+ * Stream statistics
  */
 
-/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
-#define UVC_STREAM_EOH (1 << 7)
-#define UVC_STREAM_ERR (1 << 6)
-#define UVC_STREAM_STI (1 << 5)
-#define UVC_STREAM_RES (1 << 4)
-#define UVC_STREAM_SCR (1 << 3)
-#define UVC_STREAM_PTS (1 << 2)
-#define UVC_STREAM_EOF (1 << 1)
-#define UVC_STREAM_FID (1 << 0)
+static void uvc_video_stats_decode(struct uvc_streaming *stream,
+               const __u8 *data, int len)
+{
+       unsigned int header_size;
+       bool has_pts = false;
+       bool has_scr = false;
+       u16 uninitialized_var(scr_sof);
+       u32 uninitialized_var(scr_stc);
+       u32 uninitialized_var(pts);
+
+       if (stream->stats.stream.nb_frames == 0 &&
+           stream->stats.frame.nb_packets == 0)
+               ktime_get_ts(&stream->stats.stream.start_ts);
+
+       switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
+       case UVC_STREAM_PTS | UVC_STREAM_SCR:
+               header_size = 12;
+               has_pts = true;
+               has_scr = true;
+               break;
+       case UVC_STREAM_PTS:
+               header_size = 6;
+               has_pts = true;
+               break;
+       case UVC_STREAM_SCR:
+               header_size = 8;
+               has_scr = true;
+               break;
+       default:
+               header_size = 2;
+               break;
+       }
+
+       /* Check for invalid headers. */
+       if (len < header_size || data[0] < header_size) {
+               stream->stats.frame.nb_invalid++;
+               return;
+       }
+
+       /* Extract the timestamps. */
+       if (has_pts)
+               pts = get_unaligned_le32(&data[2]);
+
+       if (has_scr) {
+               scr_stc = get_unaligned_le32(&data[header_size - 6]);
+               scr_sof = get_unaligned_le16(&data[header_size - 2]);
+       }
+
+       /* Is PTS constant through the whole frame ? */
+       if (has_pts && stream->stats.frame.nb_pts) {
+               if (stream->stats.frame.pts != pts) {
+                       stream->stats.frame.nb_pts_diffs++;
+                       stream->stats.frame.last_pts_diff =
+                               stream->stats.frame.nb_packets;
+               }
+       }
+
+       if (has_pts) {
+               stream->stats.frame.nb_pts++;
+               stream->stats.frame.pts = pts;
+       }
+
+       /* Do all frames have a PTS in their first non-empty packet, or before
+        * their first empty packet ?
+        */
+       if (stream->stats.frame.size == 0) {
+               if (len > header_size)
+                       stream->stats.frame.has_initial_pts = has_pts;
+               if (len == header_size && has_pts)
+                       stream->stats.frame.has_early_pts = true;
+       }
+
+       /* Do the SCR.STC and SCR.SOF fields vary through the frame ? */
+       if (has_scr && stream->stats.frame.nb_scr) {
+               if (stream->stats.frame.scr_stc != scr_stc)
+                       stream->stats.frame.nb_scr_diffs++;
+       }
+
+       if (has_scr) {
+               /* Expand the SOF counter to 32 bits and store its value. */
+               if (stream->stats.stream.nb_frames > 0 ||
+                   stream->stats.frame.nb_scr > 0)
+                       stream->stats.stream.scr_sof_count +=
+                               (scr_sof - stream->stats.stream.scr_sof) % 2048;
+               stream->stats.stream.scr_sof = scr_sof;
+
+               stream->stats.frame.nb_scr++;
+               stream->stats.frame.scr_stc = scr_stc;
+               stream->stats.frame.scr_sof = scr_sof;
+
+               if (scr_sof < stream->stats.stream.min_sof)
+                       stream->stats.stream.min_sof = scr_sof;
+               if (scr_sof > stream->stats.stream.max_sof)
+                       stream->stats.stream.max_sof = scr_sof;
+       }
+
+       /* Record the first non-empty packet number. */
+       if (stream->stats.frame.size == 0 && len > header_size)
+               stream->stats.frame.first_data = stream->stats.frame.nb_packets;
+
+       /* Update the frame size. */
+       stream->stats.frame.size += len - header_size;
+
+       /* Update the packets counters. */
+       stream->stats.frame.nb_packets++;
+       if (len > header_size)
+               stream->stats.frame.nb_empty++;
+
+       if (data[1] & UVC_STREAM_ERR)
+               stream->stats.frame.nb_errors++;
+}
+
+static void uvc_video_stats_update(struct uvc_streaming *stream)
+{
+       struct uvc_stats_frame *frame = &stream->stats.frame;
+
+       uvc_trace(UVC_TRACE_STATS, "frame %u stats: %u/%u/%u packets, "
+                 "%u/%u/%u pts (%searly %sinitial), %u/%u scr, "
+                 "last pts/stc/sof %u/%u/%u\n",
+                 stream->sequence, frame->first_data,
+                 frame->nb_packets - frame->nb_empty, frame->nb_packets,
+                 frame->nb_pts_diffs, frame->last_pts_diff, frame->nb_pts,
+                 frame->has_early_pts ? "" : "!",
+                 frame->has_initial_pts ? "" : "!",
+                 frame->nb_scr_diffs, frame->nb_scr,
+                 frame->pts, frame->scr_stc, frame->scr_sof);
+
+       stream->stats.stream.nb_frames++;
+       stream->stats.stream.nb_packets += stream->stats.frame.nb_packets;
+       stream->stats.stream.nb_empty += stream->stats.frame.nb_empty;
+       stream->stats.stream.nb_errors += stream->stats.frame.nb_errors;
+       stream->stats.stream.nb_invalid += stream->stats.frame.nb_invalid;
+
+       if (frame->has_early_pts)
+               stream->stats.stream.nb_pts_early++;
+       if (frame->has_initial_pts)
+               stream->stats.stream.nb_pts_initial++;
+       if (frame->last_pts_diff <= frame->first_data)
+               stream->stats.stream.nb_pts_constant++;
+       if (frame->nb_scr >= frame->nb_packets - frame->nb_empty)
+               stream->stats.stream.nb_scr_count_ok++;
+       if (frame->nb_scr_diffs + 1 == frame->nb_scr)
+               stream->stats.stream.nb_scr_diffs_ok++;
+
+       memset(&stream->stats.frame, 0, sizeof(stream->stats.frame));
+}
+
+size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
+                           size_t size)
+{
+       unsigned int scr_sof_freq;
+       unsigned int duration;
+       struct timespec ts;
+       size_t count = 0;
+
+       ts.tv_sec = stream->stats.stream.stop_ts.tv_sec
+                 - stream->stats.stream.start_ts.tv_sec;
+       ts.tv_nsec = stream->stats.stream.stop_ts.tv_nsec
+                  - stream->stats.stream.start_ts.tv_nsec;
+       if (ts.tv_nsec < 0) {
+               ts.tv_sec--;
+               ts.tv_nsec += 1000000000;
+       }
+
+       /* Compute the SCR.SOF frequency estimate. At the nominal 1kHz SOF
+        * frequency this will not overflow before more than 1h.
+        */
+       duration = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+       if (duration != 0)
+               scr_sof_freq = stream->stats.stream.scr_sof_count * 1000
+                            / duration;
+       else
+               scr_sof_freq = 0;
+
+       count += scnprintf(buf + count, size - count,
+                          "frames:  %u\npackets: %u\nempty:   %u\n"
+                          "errors:  %u\ninvalid: %u\n",
+                          stream->stats.stream.nb_frames,
+                          stream->stats.stream.nb_packets,
+                          stream->stats.stream.nb_empty,
+                          stream->stats.stream.nb_errors,
+                          stream->stats.stream.nb_invalid);
+       count += scnprintf(buf + count, size - count,
+                          "pts: %u early, %u initial, %u ok\n",
+                          stream->stats.stream.nb_pts_early,
+                          stream->stats.stream.nb_pts_initial,
+                          stream->stats.stream.nb_pts_constant);
+       count += scnprintf(buf + count, size - count,
+                          "scr: %u count ok, %u diff ok\n",
+                          stream->stats.stream.nb_scr_count_ok,
+                          stream->stats.stream.nb_scr_diffs_ok);
+       count += scnprintf(buf + count, size - count,
+                          "sof: %u <= sof <= %u, freq %u.%03u kHz\n",
+                          stream->stats.stream.min_sof,
+                          stream->stats.stream.max_sof,
+                          scr_sof_freq / 1000, scr_sof_freq % 1000);
+
+       return count;
+}
+
+static void uvc_video_stats_start(struct uvc_streaming *stream)
+{
+       memset(&stream->stats, 0, sizeof(stream->stats));
+       stream->stats.stream.min_sof = 2048;
+}
+
+static void uvc_video_stats_stop(struct uvc_streaming *stream)
+{
+       ktime_get_ts(&stream->stats.stream.stop_ts);
+}
+
+/* ------------------------------------------------------------------------
+ * Video codecs
+ */
 
 /* Video payload decoding is handled by uvc_video_decode_start(),
  * uvc_video_decode_data() and uvc_video_decode_end().
@@ -416,14 +944,9 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
         * - bHeaderLength value must be at least 2 bytes (see above)
         * - bHeaderLength value can't be larger than the packet size.
         */
-       if (len < 2 || data[0] < 2 || data[0] > len)
+       if (len < 2 || data[0] < 2 || data[0] > len) {
+               stream->stats.frame.nb_invalid++;
                return -EINVAL;
-
-       /* Skip payloads marked with the error bit ("error frames"). */
-       if (data[1] & UVC_STREAM_ERR) {
-               uvc_trace(UVC_TRACE_FRAME, "Dropping payload (error bit "
-                         "set).\n");
-               return -ENODATA;
        }
 
        fid = data[1] & UVC_STREAM_FID;
@@ -431,8 +954,14 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
        /* Increase the sequence number regardless of any buffer states, so
         * that discontinuous sequence numbers always indicate lost frames.
         */
-       if (stream->last_fid != fid)
+       if (stream->last_fid != fid) {
                stream->sequence++;
+               if (stream->sequence)
+                       uvc_video_stats_update(stream);
+       }
+
+       uvc_video_clock_decode(stream, buf, data, len);
+       uvc_video_stats_decode(stream, data, len);
 
        /* Store the payload FID bit and return immediately when the buffer is
         * NULL.
@@ -442,6 +971,13 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
                return -ENODATA;
        }
 
+       /* Mark the buffer as bad if the error bit is set. */
+       if (data[1] & UVC_STREAM_ERR) {
+               uvc_trace(UVC_TRACE_FRAME, "Marking buffer as bad (error bit "
+                         "set).\n");
+               buf->error = 1;
+       }
+
        /* Synchronize to the input stream by waiting for the FID bit to be
         * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
         * stream->last_fid is initialized to -1, so the first isochronous
@@ -467,9 +1003,10 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
                else
                        ktime_get_real_ts(&ts);
 
-               buf->buf.sequence = stream->sequence;
-               buf->buf.timestamp.tv_sec = ts.tv_sec;
-               buf->buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+               buf->buf.v4l2_buf.sequence = stream->sequence;
+               buf->buf.v4l2_buf.timestamp.tv_sec = ts.tv_sec;
+               buf->buf.v4l2_buf.timestamp.tv_usec =
+                       ts.tv_nsec / NSEC_PER_USEC;
 
                /* TODO: Handle PTS and SCR. */
                buf->state = UVC_BUF_STATE_ACTIVE;
@@ -490,7 +1027,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
         * avoids detecting end of frame conditions at FID toggling if the
         * previous payload had the EOF bit set.
         */
-       if (fid != stream->last_fid && buf->buf.bytesused != 0) {
+       if (fid != stream->last_fid && buf->bytesused != 0) {
                uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
                                "toggled).\n");
                buf->state = UVC_BUF_STATE_READY;
@@ -505,7 +1042,6 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
 static void uvc_video_decode_data(struct uvc_streaming *stream,
                struct uvc_buffer *buf, const __u8 *data, int len)
 {
-       struct uvc_video_queue *queue = &stream->queue;
        unsigned int maxlen, nbytes;
        void *mem;
 
@@ -513,11 +1049,11 @@ static void uvc_video_decode_data(struct uvc_streaming *stream,
                return;
 
        /* Copy the video data to the buffer. */
-       maxlen = buf->buf.length - buf->buf.bytesused;
-       mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+       maxlen = buf->length - buf->bytesused;
+       mem = buf->mem + buf->bytesused;
        nbytes = min((unsigned int)len, maxlen);
        memcpy(mem, data, nbytes);
-       buf->buf.bytesused += nbytes;
+       buf->bytesused += nbytes;
 
        /* Complete the current frame if the buffer size was exceeded. */
        if (len > maxlen) {
@@ -530,7 +1066,7 @@ static void uvc_video_decode_end(struct uvc_streaming *stream,
                struct uvc_buffer *buf, const __u8 *data, int len)
 {
        /* Mark the buffer as done if the EOF marker is set. */
-       if (data[1] & UVC_STREAM_EOF && buf->buf.bytesused != 0) {
+       if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) {
                uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
                if (data[0] == len)
                        uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
@@ -568,8 +1104,8 @@ static int uvc_video_encode_data(struct uvc_streaming *stream,
        void *mem;
 
        /* Copy video data to the URB buffer. */
-       mem = queue->mem + buf->buf.m.offset + queue->buf_used;
-       nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
+       mem = buf->mem + queue->buf_used;
+       nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used);
        nbytes = min(stream->bulk.max_payload_size - stream->bulk.payload_size,
                        nbytes);
        memcpy(data, mem, nbytes);
@@ -624,7 +1160,7 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
                        urb->iso_frame_desc[i].actual_length);
 
                if (buf->state == UVC_BUF_STATE_READY) {
-                       if (buf->buf.length != buf->buf.bytesused &&
+                       if (buf->length != buf->bytesused &&
                            !(stream->cur_format->flags &
                              UVC_FMT_FLAG_COMPRESSED))
                                buf->error = 1;
@@ -724,12 +1260,12 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
        stream->bulk.payload_size += ret;
        len -= ret;
 
-       if (buf->buf.bytesused == stream->queue.buf_used ||
+       if (buf->bytesused == stream->queue.buf_used ||
            stream->bulk.payload_size == stream->bulk.max_payload_size) {
-               if (buf->buf.bytesused == stream->queue.buf_used) {
+               if (buf->bytesused == stream->queue.buf_used) {
                        stream->queue.buf_used = 0;
                        buf->state = UVC_BUF_STATE_READY;
-                       buf->buf.sequence = ++stream->sequence;
+                       buf->buf.v4l2_buf.sequence = ++stream->sequence;
                        uvc_queue_next_buffer(&stream->queue, buf);
                        stream->last_fid ^= UVC_STREAM_FID;
                }
@@ -870,6 +1406,8 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)
        struct urb *urb;
        unsigned int i;
 
+       uvc_video_stats_stop(stream);
+
        for (i = 0; i < UVC_URBS; ++i) {
                urb = stream->urb[i];
                if (urb == NULL)
@@ -882,6 +1420,8 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)
 
        if (free_buffers)
                uvc_free_urb_buffers(stream);
+
+       uvc_video_clock_cleanup(stream);
 }
 
 /*
@@ -1009,6 +1549,12 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
        stream->bulk.skip_payload = 0;
        stream->bulk.payload_size = 0;
 
+       uvc_video_stats_start(stream);
+
+       ret = uvc_video_clock_init(stream);
+       if (ret < 0)
+               return ret;
+
        if (intf->num_altsetting > 1) {
                struct usb_host_endpoint *best_ep = NULL;
                unsigned int best_psize = 3 * 1024;
@@ -1283,6 +1829,11 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable)
                return ret;
        }
 
-       return uvc_init_video(stream, GFP_KERNEL);
-}
+       ret = uvc_init_video(stream, GFP_KERNEL);
+       if (ret < 0) {
+               usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+               uvc_queue_enable(&stream->queue, 0);
+       }
 
+       return ret;
+}
index 4c1392ebcd4bd2634b245a23209f37c129e7be1f..67f88d85bb168b53e9dc9dd990c9d17fac1fd975 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/videodev2.h>
 #include <media/media-device.h>
 #include <media/v4l2-device.h>
+#include <media/videobuf2-core.h>
 
 /* --------------------------------------------------------------------------
  * UVC constants
 
 /* Maximum allowed number of control mappings per device */
 #define UVC_MAX_CONTROL_MAPPINGS       1024
+#define UVC_MAX_CONTROL_MENU_ENTRIES   32
 
 /* Devices quirks */
 #define UVC_QUIRK_STATUS_INTERVAL      0x00000001
@@ -319,35 +321,30 @@ enum uvc_buffer_state {
 };
 
 struct uvc_buffer {
-       unsigned long vma_use_count;
-       struct list_head stream;
-
-       /* Touched by interrupt handler. */
-       struct v4l2_buffer buf;
+       struct vb2_buffer buf;
        struct list_head queue;
-       wait_queue_head_t wait;
+
        enum uvc_buffer_state state;
        unsigned int error;
+
+       void *mem;
+       unsigned int length;
+       unsigned int bytesused;
+
+       u32 pts;
 };
 
-#define UVC_QUEUE_STREAMING            (1 << 0)
-#define UVC_QUEUE_DISCONNECTED         (1 << 1)
-#define UVC_QUEUE_DROP_CORRUPTED       (1 << 2)
+#define UVC_QUEUE_DISCONNECTED         (1 << 0)
+#define UVC_QUEUE_DROP_CORRUPTED       (1 << 1)
 
 struct uvc_video_queue {
-       enum v4l2_buf_type type;
+       struct vb2_queue queue;
+       struct mutex mutex;                     /* Protects queue */
 
-       void *mem;
        unsigned int flags;
-
-       unsigned int count;
-       unsigned int buf_size;
        unsigned int buf_used;
-       struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
-       struct mutex mutex;     /* protects buffers and mainqueue */
-       spinlock_t irqlock;     /* protects irqqueue */
 
-       struct list_head mainqueue;
+       spinlock_t irqlock;                     /* Protects irqqueue */
        struct list_head irqqueue;
 };
 
@@ -362,6 +359,51 @@ struct uvc_video_chain {
        struct mutex ctrl_mutex;                /* Protects ctrl.info */
 };
 
+struct uvc_stats_frame {
+       unsigned int size;              /* Number of bytes captured */
+       unsigned int first_data;        /* Index of the first non-empty packet */
+
+       unsigned int nb_packets;        /* Number of packets */
+       unsigned int nb_empty;          /* Number of empty packets */
+       unsigned int nb_invalid;        /* Number of packets with an invalid header */
+       unsigned int nb_errors;         /* Number of packets with the error bit set */
+
+       unsigned int nb_pts;            /* Number of packets with a PTS timestamp */
+       unsigned int nb_pts_diffs;      /* Number of PTS differences inside a frame */
+       unsigned int last_pts_diff;     /* Index of the last PTS difference */
+       bool has_initial_pts;           /* Whether the first non-empty packet has a PTS */
+       bool has_early_pts;             /* Whether a PTS is present before the first non-empty packet */
+       u32 pts;                        /* PTS of the last packet */
+
+       unsigned int nb_scr;            /* Number of packets with a SCR timestamp */
+       unsigned int nb_scr_diffs;      /* Number of SCR.STC differences inside a frame */
+       u16 scr_sof;                    /* SCR.SOF of the last packet */
+       u32 scr_stc;                    /* SCR.STC of the last packet */
+};
+
+struct uvc_stats_stream {
+       struct timespec start_ts;       /* Stream start timestamp */
+       struct timespec stop_ts;        /* Stream stop timestamp */
+
+       unsigned int nb_frames;         /* Number of frames */
+
+       unsigned int nb_packets;        /* Number of packets */
+       unsigned int nb_empty;          /* Number of empty packets */
+       unsigned int nb_invalid;        /* Number of packets with an invalid header */
+       unsigned int nb_errors;         /* Number of packets with the error bit set */
+
+       unsigned int nb_pts_constant;   /* Number of frames with constant PTS */
+       unsigned int nb_pts_early;      /* Number of frames with early PTS */
+       unsigned int nb_pts_initial;    /* Number of frames with initial PTS */
+
+       unsigned int nb_scr_count_ok;   /* Number of frames with at least one SCR per non empty packet */
+       unsigned int nb_scr_diffs_ok;   /* Number of frames with varying SCR.STC */
+       unsigned int scr_sof_count;     /* STC.SOF counter accumulated since stream start */
+       unsigned int scr_sof;           /* STC.SOF of the last packet */
+       unsigned int min_sof;           /* Minimum STC.SOF value */
+       unsigned int max_sof;           /* Maximum STC.SOF value */
+};
+
 struct uvc_streaming {
        struct list_head list;
        struct uvc_device *dev;
@@ -387,6 +429,7 @@ struct uvc_streaming {
         */
        struct mutex mutex;
 
+       /* Buffers queue. */
        unsigned int frozen : 1;
        struct uvc_video_queue queue;
        void (*decode) (struct urb *urb, struct uvc_streaming *video,
@@ -408,6 +451,32 @@ struct uvc_streaming {
 
        __u32 sequence;
        __u8 last_fid;
+
+       /* debugfs */
+       struct dentry *debugfs_dir;
+       struct {
+               struct uvc_stats_frame frame;
+               struct uvc_stats_stream stream;
+       } stats;
+
+       /* Timestamps support. */
+       struct uvc_clock {
+               struct uvc_clock_sample {
+                       u32 dev_stc;
+                       u16 dev_sof;
+                       struct timespec host_ts;
+                       u16 host_sof;
+               } *samples;
+
+               unsigned int head;
+               unsigned int count;
+               unsigned int size;
+
+               u16 last_sof;
+               u16 sof_offset;
+
+               spinlock_t lock;
+       } clock;
 };
 
 enum uvc_device_state {
@@ -479,9 +548,12 @@ struct uvc_driver {
 #define UVC_TRACE_SUSPEND      (1 << 8)
 #define UVC_TRACE_STATUS       (1 << 9)
 #define UVC_TRACE_VIDEO                (1 << 10)
+#define UVC_TRACE_STATS                (1 << 11)
+#define UVC_TRACE_CLOCK                (1 << 12)
 
 #define UVC_WARN_MINMAX                0
 #define UVC_WARN_PROBE_DEF     1
+#define UVC_WARN_XU_GET_RES    2
 
 extern unsigned int uvc_clock_param;
 extern unsigned int uvc_no_drop_param;
@@ -516,8 +588,8 @@ extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
 extern void uvc_queue_init(struct uvc_video_queue *queue,
                enum v4l2_buf_type type, int drop_corrupted);
 extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
-               unsigned int nbuffers, unsigned int buflength);
-extern int uvc_free_buffers(struct uvc_video_queue *queue);
+               struct v4l2_requestbuffers *rb);
+extern void uvc_free_buffers(struct uvc_video_queue *queue);
 extern int uvc_query_buffer(struct uvc_video_queue *queue,
                struct v4l2_buffer *v4l2_buf);
 extern int uvc_queue_buffer(struct uvc_video_queue *queue,
@@ -539,7 +611,7 @@ extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
 extern int uvc_queue_allocated(struct uvc_video_queue *queue);
 static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
 {
-       return queue->flags & UVC_QUEUE_STREAMING;
+       return vb2_is_streaming(&queue->queue);
 }
 
 /* V4L2 interface */
@@ -556,10 +628,11 @@ extern int uvc_video_resume(struct uvc_streaming *stream, int reset);
 extern int uvc_video_enable(struct uvc_streaming *stream, int enable);
 extern int uvc_probe_video(struct uvc_streaming *stream,
                struct uvc_streaming_control *probe);
-extern int uvc_commit_video(struct uvc_streaming *stream,
-               struct uvc_streaming_control *ctrl);
 extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
                __u8 intfnum, __u8 cs, void *data, __u16 size);
+void uvc_video_clock_update(struct uvc_streaming *stream,
+                           struct v4l2_buffer *v4l2_buf,
+                           struct uvc_buffer *buf);
 
 /* Status */
 extern int uvc_status_init(struct uvc_device *dev);
@@ -612,4 +685,13 @@ extern struct usb_host_endpoint *uvc_find_endpoint(
 void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
                struct uvc_buffer *buf);
 
+/* debugfs and statistics */
+int uvc_debugfs_init(void);
+void uvc_debugfs_cleanup(void);
+int uvc_debugfs_init_stream(struct uvc_streaming *stream);
+void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream);
+
+size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
+                           size_t size);
+
 #endif
index c68531b882794d46abfa260f378b1f4b3ec9f9c7..af4419e6c65855eca787bd4a61777f33cf5b0c7f 100644 (file)
@@ -985,6 +985,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
        case VIDIOC_CROPCAP:
        case VIDIOC_G_CROP:
        case VIDIOC_S_CROP:
+       case VIDIOC_G_SELECTION:
+       case VIDIOC_S_SELECTION:
        case VIDIOC_G_JPEGCOMP:
        case VIDIOC_S_JPEGCOMP:
        case VIDIOC_QUERYSTD:
index 0f415dade05ae4bec936b2300f9c81e93fa535eb..cccd42be718ae7cc25d2b21189f9880528f38225 100644 (file)
@@ -465,8 +465,9 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_CHROMA_GAIN:              return "Chroma Gain";
        case V4L2_CID_ILLUMINATORS_1:           return "Illuminator 1";
        case V4L2_CID_ILLUMINATORS_2:           return "Illuminator 2";
-       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:  return "Minimum Number of Capture Buffers";
-       case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:   return "Minimum Number of Output Buffers";
+       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:  return "Min Number of Capture Buffers";
+       case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:   return "Min Number of Output Buffers";
+       case V4L2_CID_ALPHA_COMPONENT:          return "Alpha Component";
 
        /* MPEG controls */
        /* Keep the order of the 'case's the same as in videodev2.h! */
@@ -505,25 +506,25 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_MPEG_VIDEO_MUTE_YUV:      return "Video Mute YUV";
        case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:       return "Decoder Slice Interface";
        case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:  return "MPEG4 Loop Filter Enable";
-       case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:       return "The Number of Intra Refresh MBs";
+       case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:       return "Number of Intra Refresh MBs";
        case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:               return "Frame Level Rate Control Enable";
        case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:                  return "H264 MB Level Rate Control";
        case V4L2_CID_MPEG_VIDEO_HEADER_MODE:                   return "Sequence Header Mode";
-       case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC:                   return "The Max Number of Reference Picture";
+       case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC:                   return "Max Number of Reference Pics";
        case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:               return "H263 I-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:               return "H263 P frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:               return "H263 B frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:               return "H263 P-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:               return "H263 B-Frame QP Value";
        case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:                   return "H263 Minimum QP Value";
        case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:                   return "H263 Maximum QP Value";
        case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:               return "H264 I-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:               return "H264 P frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:               return "H264 B frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:               return "H264 P-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:               return "H264 B-Frame QP Value";
        case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:                   return "H264 Maximum QP Value";
        case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:                   return "H264 Minimum QP Value";
        case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:            return "H264 8x8 Transform Enable";
        case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:                 return "H264 CPB Buffer Size";
-       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:             return "H264 Entorpy Mode";
-       case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:                 return "H264 I Period";
+       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:             return "H264 Entropy Mode";
+       case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:                 return "H264 I-Frame Period";
        case V4L2_CID_MPEG_VIDEO_H264_LEVEL:                    return "H264 Level";
        case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:        return "H264 Loop Filter Alpha Offset";
        case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:         return "H264 Loop Filter Beta Offset";
@@ -534,16 +535,16 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:           return "Aspect Ratio VUI Enable";
        case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:              return "VUI Aspect Ratio IDC";
        case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:              return "MPEG4 I-Frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:              return "MPEG4 P frame QP Value";
-       case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:              return "MPEG4 B frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:              return "MPEG4 P-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:              return "MPEG4 B-Frame QP Value";
        case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:                  return "MPEG4 Minimum QP Value";
        case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:                  return "MPEG4 Maximum QP Value";
        case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:                   return "MPEG4 Level";
        case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:                 return "MPEG4 Profile";
        case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:                    return "Quarter Pixel Search Enable";
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:         return "The Maximum Bytes Per Slice";
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:            return "The Number of MB in a Slice";
-       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:              return "The Slice Partitioning Method";
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:         return "Maximum Bytes in a Slice";
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:            return "Number of MBs in a Slice";
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:              return "Slice Partitioning Method";
        case V4L2_CID_MPEG_VIDEO_VBV_SIZE:                      return "VBV Buffer Size";
 
        /* CAMERA controls */
@@ -579,7 +580,7 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_AUDIO_LIMITER_ENABLED:    return "Audio Limiter Feature Enabled";
        case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
        case V4L2_CID_AUDIO_LIMITER_DEVIATION:  return "Audio Limiter Deviation";
-       case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Feature Enabled";
+       case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Enabled";
        case V4L2_CID_AUDIO_COMPRESSION_GAIN:   return "Audio Compression Gain";
        case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold";
        case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time";
@@ -587,24 +588,24 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_PILOT_TONE_ENABLED:       return "Pilot Tone Feature Enabled";
        case V4L2_CID_PILOT_TONE_DEVIATION:     return "Pilot Tone Deviation";
        case V4L2_CID_PILOT_TONE_FREQUENCY:     return "Pilot Tone Frequency";
-       case V4L2_CID_TUNE_PREEMPHASIS:         return "Pre-emphasis settings";
+       case V4L2_CID_TUNE_PREEMPHASIS:         return "Pre-Emphasis";
        case V4L2_CID_TUNE_POWER_LEVEL:         return "Tune Power Level";
        case V4L2_CID_TUNE_ANTENNA_CAPACITOR:   return "Tune Antenna Capacitor";
 
        /* Flash controls */
-       case V4L2_CID_FLASH_CLASS:              return "Flash controls";
-       case V4L2_CID_FLASH_LED_MODE:           return "LED mode";
-       case V4L2_CID_FLASH_STROBE_SOURCE:      return "Strobe source";
+       case V4L2_CID_FLASH_CLASS:              return "Flash Controls";
+       case V4L2_CID_FLASH_LED_MODE:           return "LED Mode";
+       case V4L2_CID_FLASH_STROBE_SOURCE:      return "Strobe Source";
        case V4L2_CID_FLASH_STROBE:             return "Strobe";
-       case V4L2_CID_FLASH_STROBE_STOP:        return "Stop strobe";
-       case V4L2_CID_FLASH_STROBE_STATUS:      return "Strobe status";
-       case V4L2_CID_FLASH_TIMEOUT:            return "Strobe timeout";
-       case V4L2_CID_FLASH_INTENSITY:          return "Intensity, flash mode";
-       case V4L2_CID_FLASH_TORCH_INTENSITY:    return "Intensity, torch mode";
-       case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, indicator";
+       case V4L2_CID_FLASH_STROBE_STOP:        return "Stop Strobe";
+       case V4L2_CID_FLASH_STROBE_STATUS:      return "Strobe Status";
+       case V4L2_CID_FLASH_TIMEOUT:            return "Strobe Timeout";
+       case V4L2_CID_FLASH_INTENSITY:          return "Intensity, Flash Mode";
+       case V4L2_CID_FLASH_TORCH_INTENSITY:    return "Intensity, Torch Mode";
+       case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, Indicator";
        case V4L2_CID_FLASH_FAULT:              return "Faults";
        case V4L2_CID_FLASH_CHARGE:             return "Charge";
-       case V4L2_CID_FLASH_READY:              return "Ready to strobe";
+       case V4L2_CID_FLASH_READY:              return "Ready to Strobe";
 
        default:
                return NULL;
@@ -1108,8 +1109,8 @@ int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl,
        INIT_LIST_HEAD(&hdl->ctrls);
        INIT_LIST_HEAD(&hdl->ctrl_refs);
        hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;
-       hdl->buckets = kzalloc(sizeof(hdl->buckets[0]) * hdl->nr_of_buckets,
-                                                               GFP_KERNEL);
+       hdl->buckets = kcalloc(hdl->nr_of_buckets, sizeof(hdl->buckets[0]),
+                              GFP_KERNEL);
        hdl->error = hdl->buckets ? 0 : -ENOMEM;
        return hdl->error;
 }
index a5c9ed128b974aaac3e4cba8ac03e4a2292d77d4..96e9615663e9d912b8868719b7c53d5ca73cfae6 100644 (file)
@@ -146,10 +146,9 @@ static void v4l2_device_release(struct device *cd)
        struct v4l2_device *v4l2_dev = vdev->v4l2_dev;
 
        mutex_lock(&videodev_lock);
-       if (video_device[vdev->minor] != vdev) {
-               mutex_unlock(&videodev_lock);
+       if (WARN_ON(video_device[vdev->minor] != vdev)) {
                /* should not happen */
-               WARN_ON(1);
+               mutex_unlock(&videodev_lock);
                return;
        }
 
@@ -168,7 +167,7 @@ static void v4l2_device_release(struct device *cd)
        mutex_unlock(&videodev_lock);
 
 #if defined(CONFIG_MEDIA_CONTROLLER)
-       if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+       if (v4l2_dev && v4l2_dev->mdev &&
            vdev->vfl_type != VFL_TYPE_SUBDEV)
                media_device_unregister_entity(&vdev->entity);
 #endif
@@ -556,8 +555,7 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
        vdev->minor = -1;
 
        /* the release callback MUST be present */
-       WARN_ON(!vdev->release);
-       if (!vdev->release)
+       if (WARN_ON(!vdev->release))
                return -EINVAL;
 
        /* v4l2_fh support */
@@ -703,8 +701,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
            vdev->vfl_type != VFL_TYPE_SUBDEV) {
                vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
                vdev->entity.name = vdev->name;
-               vdev->entity.v4l.major = VIDEO_MAJOR;
-               vdev->entity.v4l.minor = vdev->minor;
+               vdev->entity.info.v4l.major = VIDEO_MAJOR;
+               vdev->entity.info.v4l.minor = vdev->minor;
                ret = media_device_register_entity(vdev->v4l2_dev->mdev,
                        &vdev->entity);
                if (ret < 0)
index 0edd618b9ddf17c1a117b157428df48ceccca1ae..1f203b85a63739463a448259800b31f240359bbf 100644 (file)
@@ -234,8 +234,8 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
                        goto clean_up;
                }
 #if defined(CONFIG_MEDIA_CONTROLLER)
-               sd->entity.v4l.major = VIDEO_MAJOR;
-               sd->entity.v4l.minor = vdev->minor;
+               sd->entity.info.v4l.major = VIDEO_MAJOR;
+               sd->entity.info.v4l.minor = vdev->minor;
 #endif
                sd->devnode = vdev;
        }
index e1da8fc9dd2f192e4451318bdc66a93fbea3279d..3f623859a337126aa035df7c00817a6ad5da6fee 100644 (file)
@@ -238,6 +238,8 @@ static const char *v4l2_ioctls[] = {
        [_IOC_NR(VIDIOC_CROPCAP)]          = "VIDIOC_CROPCAP",
        [_IOC_NR(VIDIOC_G_CROP)]           = "VIDIOC_G_CROP",
        [_IOC_NR(VIDIOC_S_CROP)]           = "VIDIOC_S_CROP",
+       [_IOC_NR(VIDIOC_G_SELECTION)]      = "VIDIOC_G_SELECTION",
+       [_IOC_NR(VIDIOC_S_SELECTION)]      = "VIDIOC_S_SELECTION",
        [_IOC_NR(VIDIOC_G_JPEGCOMP)]       = "VIDIOC_G_JPEGCOMP",
        [_IOC_NR(VIDIOC_S_JPEGCOMP)]       = "VIDIOC_S_JPEGCOMP",
        [_IOC_NR(VIDIOC_QUERYSTD)]         = "VIDIOC_QUERYSTD",
@@ -1547,11 +1549,32 @@ static long __video_do_ioctl(struct file *file,
        {
                struct v4l2_crop *p = arg;
 
-               if (!ops->vidioc_g_crop)
+               if (!ops->vidioc_g_crop && !ops->vidioc_g_selection)
                        break;
 
                dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
-               ret = ops->vidioc_g_crop(file, fh, p);
+
+               if (ops->vidioc_g_crop) {
+                       ret = ops->vidioc_g_crop(file, fh, p);
+               } else {
+                       /* simulate capture crop using selection api */
+                       struct v4l2_selection s = {
+                               .type = p->type,
+                       };
+
+                       /* crop means compose for output devices */
+                       if (V4L2_TYPE_IS_OUTPUT(p->type))
+                               s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
+                       else
+                               s.target = V4L2_SEL_TGT_CROP_ACTIVE;
+
+                       ret = ops->vidioc_g_selection(file, fh, &s);
+
+                       /* copying results to old structure on success */
+                       if (!ret)
+                               p->c = s.r;
+               }
+
                if (!ret)
                        dbgrect(vfd, "", &p->c);
                break;
@@ -1560,15 +1583,65 @@ static long __video_do_ioctl(struct file *file,
        {
                struct v4l2_crop *p = arg;
 
-               if (!ops->vidioc_s_crop)
+               if (!ops->vidioc_s_crop && !ops->vidioc_s_selection)
                        break;
+
                if (ret_prio) {
                        ret = ret_prio;
                        break;
                }
                dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
                dbgrect(vfd, "", &p->c);
-               ret = ops->vidioc_s_crop(file, fh, p);
+
+               if (ops->vidioc_s_crop) {
+                       ret = ops->vidioc_s_crop(file, fh, p);
+               } else {
+                       /* simulate capture crop using selection api */
+                       struct v4l2_selection s = {
+                               .type = p->type,
+                               .r = p->c,
+                       };
+
+                       /* crop means compose for output devices */
+                       if (V4L2_TYPE_IS_OUTPUT(p->type))
+                               s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
+                       else
+                               s.target = V4L2_SEL_TGT_CROP_ACTIVE;
+
+                       ret = ops->vidioc_s_selection(file, fh, &s);
+               }
+               break;
+       }
+       case VIDIOC_G_SELECTION:
+       {
+               struct v4l2_selection *p = arg;
+
+               if (!ops->vidioc_g_selection)
+                       break;
+
+               dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+
+               ret = ops->vidioc_g_selection(file, fh, p);
+               if (!ret)
+                       dbgrect(vfd, "", &p->r);
+               break;
+       }
+       case VIDIOC_S_SELECTION:
+       {
+               struct v4l2_selection *p = arg;
+
+               if (!ops->vidioc_s_selection)
+                       break;
+
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
+
+               dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+               dbgrect(vfd, "", &p->r);
+
+               ret = ops->vidioc_s_selection(file, fh, p);
                break;
        }
        case VIDIOC_CROPCAP:
@@ -1576,11 +1649,42 @@ static long __video_do_ioctl(struct file *file,
                struct v4l2_cropcap *p = arg;
 
                /*FIXME: Should also show v4l2_fract pixelaspect */
-               if (!ops->vidioc_cropcap)
+               if (!ops->vidioc_cropcap && !ops->vidioc_g_selection)
                        break;
 
                dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
-               ret = ops->vidioc_cropcap(file, fh, p);
+               if (ops->vidioc_cropcap) {
+                       ret = ops->vidioc_cropcap(file, fh, p);
+               } else {
+                       struct v4l2_selection s = { .type = p->type };
+
+                       /* obtaining bounds */
+                       if (V4L2_TYPE_IS_OUTPUT(p->type))
+                               s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS;
+                       else
+                               s.target = V4L2_SEL_TGT_CROP_BOUNDS;
+
+                       ret = ops->vidioc_g_selection(file, fh, &s);
+                       if (ret)
+                               break;
+                       p->bounds = s.r;
+
+                       /* obtaining defrect */
+                       if (V4L2_TYPE_IS_OUTPUT(p->type))
+                               s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
+                       else
+                               s.target = V4L2_SEL_TGT_CROP_DEFAULT;
+
+                       ret = ops->vidioc_g_selection(file, fh, &s);
+                       if (ret)
+                               break;
+                       p->defrect = s.r;
+
+                       /* setting trivial pixelaspect */
+                       p->pixelaspect.numerator = 1;
+                       p->pixelaspect.denominator = 1;
+               }
+
                if (!ret) {
                        dbgrect(vfd, "bounds ", &p->bounds);
                        dbgrect(vfd, "defrect ", &p->defrect);
@@ -1767,6 +1871,7 @@ static long __video_do_ioctl(struct file *file,
        case VIDIOC_S_FREQUENCY:
        {
                struct v4l2_frequency *p = arg;
+               enum v4l2_tuner_type type;
 
                if (!ops->vidioc_s_frequency)
                        break;
@@ -1774,9 +1879,14 @@ static long __video_do_ioctl(struct file *file,
                        ret = ret_prio;
                        break;
                }
+               type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+                       V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
                dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
                                p->tuner, p->type, p->frequency);
-               ret = ops->vidioc_s_frequency(file, fh, p);
+               if (p->type != type)
+                       ret = -EINVAL;
+               else
+                       ret = ops->vidioc_s_frequency(file, fh, p);
                break;
        }
        case VIDIOC_G_SLICED_VBI_CAP:
@@ -2226,6 +2336,10 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
                struct v4l2_ext_controls *ctrls = parg;
 
                if (ctrls->count != 0) {
+                       if (ctrls->count > V4L2_CID_MAX_CTRLS) {
+                               ret = -EINVAL;
+                               break;
+                       }
                        *user_ptr = (void __user *)ctrls->controls;
                        *kernel_ptr = (void *)&ctrls->controls;
                        *array_size = sizeof(struct v4l2_ext_control)
index 65ade5f03c2ef56efa5331c58a44391caa30f2ac..41d118ee2de63860fdac7b9eba76c1c4cf318c13 100644 (file)
@@ -193,6 +193,10 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                return v4l2_subdev_call(sd, core, s_register, p);
        }
 #endif
+
+       case VIDIOC_LOG_STATUS:
+               return v4l2_subdev_call(sd, core, log_status);
+
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
        case VIDIOC_SUBDEV_G_FMT: {
                struct v4l2_subdev_format *format = arg;
index cbf13d09b4ac84c20c6cfe2ba86180e07355bbfc..20f7237b824213537f55b33a86edc467fe44f433 100644 (file)
@@ -34,13 +34,13 @@ MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
 MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver");
 MODULE_LICENSE("GPL");
 
-static int flip_image;
+static bool flip_image;
 module_param(flip_image, bool, 0444);
 MODULE_PARM_DESC(flip_image,
                "If set, the sensor will be instructed to flip the image "
                "vertically.");
 
-static int override_serial;
+static bool override_serial;
 module_param(override_serial, bool, 0444);
 MODULE_PARM_DESC(override_serial,
                "The camera driver will normally refuse to load if "
@@ -156,14 +156,10 @@ static struct via_format {
                .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
                .bpp            = 2,
        },
-       {
-               .desc           = "RGB 565",
-               .pixelformat    = V4L2_PIX_FMT_RGB565,
-               .mbus_code      = V4L2_MBUS_FMT_RGB565_2X8_LE,
-               .bpp            = 2,
-       },
        /* RGB444 and Bayer should be doable, but have never been
-          tested with this driver. */
+          tested with this driver. RGB565 seems to work at the default
+          resolution, but results in color corruption when being scaled by
+          viacam_set_scaled(), and is disabled as a result. */
 };
 #define N_VIA_FMTS ARRAY_SIZE(via_formats)
 
@@ -1504,14 +1500,4 @@ static struct platform_driver viacam_driver = {
        .remove = viacam_remove,
 };
 
-static int viacam_init(void)
-{
-       return platform_driver_register(&viacam_driver);
-}
-module_init(viacam_init);
-
-static void viacam_exit(void)
-{
-       platform_driver_unregister(&viacam_driver);
-}
-module_exit(viacam_exit);
+module_platform_driver(viacam_driver);
index 3de7c7e4402de7f461c1eb4a41bde553f9062ada..59cb54aa2946e24cf29ae08846684d20c896642d 100644 (file)
@@ -226,9 +226,10 @@ static int videobuf_dvb_register_frontend(struct dvb_adapter *adapter,
        }
 
        /* register network adapter */
-       dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx);
-       if (dvb->net.dvbdev == NULL) {
-               result = -ENOMEM;
+       result = dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx);
+       if (result < 0) {
+               printk(KERN_WARNING "%s: dvb_net_init failed (errno = %d)\n",
+                      dvb->name, result);
                goto fail_fe_conn;
        }
        return 0;
index 95a3f5e82aef14c74a81045baa26874eb008e7c1..2e8f1df775b622ef9f877be16916fd7d9d0e0c80 100644 (file)
@@ -30,7 +30,7 @@ module_param(debug, int, 0644);
                        printk(KERN_DEBUG "vb2: " fmt, ## arg);         \
        } while (0)
 
-#define call_memop(q, plane, op, args...)                              \
+#define call_memop(q, op, args...)                                     \
        (((q)->mem_ops->op) ?                                           \
                ((q)->mem_ops->op(args)) : 0)
 
@@ -52,7 +52,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
 
        /* Allocate memory for all planes in this buffer */
        for (plane = 0; plane < vb->num_planes; ++plane) {
-               mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane],
+               mem_priv = call_memop(q, alloc, q->alloc_ctx[plane],
                                      q->plane_sizes[plane]);
                if (IS_ERR_OR_NULL(mem_priv))
                        goto free;
@@ -65,8 +65,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
        return 0;
 free:
        /* Free already allocated memory if one of the allocations failed */
-       for (; plane > 0; --plane)
-               call_memop(q, plane, put, vb->planes[plane - 1].mem_priv);
+       for (; plane > 0; --plane) {
+               call_memop(q, put, vb->planes[plane - 1].mem_priv);
+               vb->planes[plane - 1].mem_priv = NULL;
+       }
 
        return -ENOMEM;
 }
@@ -80,10 +82,10 @@ static void __vb2_buf_mem_free(struct vb2_buffer *vb)
        unsigned int plane;
 
        for (plane = 0; plane < vb->num_planes; ++plane) {
-               call_memop(q, plane, put, vb->planes[plane].mem_priv);
+               call_memop(q, put, vb->planes[plane].mem_priv);
                vb->planes[plane].mem_priv = NULL;
-               dprintk(3, "Freed plane %d of buffer %d\n",
-                               plane, vb->v4l2_buf.index);
+               dprintk(3, "Freed plane %d of buffer %d\n", plane,
+                       vb->v4l2_buf.index);
        }
 }
 
@@ -97,12 +99,9 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb)
        unsigned int plane;
 
        for (plane = 0; plane < vb->num_planes; ++plane) {
-               void *mem_priv = vb->planes[plane].mem_priv;
-
-               if (mem_priv) {
-                       call_memop(q, plane, put_userptr, mem_priv);
-                       vb->planes[plane].mem_priv = NULL;
-               }
+               if (vb->planes[plane].mem_priv)
+                       call_memop(q, put_userptr, vb->planes[plane].mem_priv);
+               vb->planes[plane].mem_priv = NULL;
        }
 }
 
@@ -305,7 +304,7 @@ static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
                 * case anyway. If num_users() returns more than 1,
                 * we are not the only user of the plane's memory.
                 */
-               if (mem_priv && call_memop(q, plane, num_users, mem_priv) > 1)
+               if (mem_priv && call_memop(q, num_users, mem_priv) > 1)
                        return true;
        }
        return false;
@@ -731,10 +730,10 @@ void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no)
 {
        struct vb2_queue *q = vb->vb2_queue;
 
-       if (plane_no > vb->num_planes)
+       if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv)
                return NULL;
 
-       return call_memop(q, plane_no, vaddr, vb->planes[plane_no].mem_priv);
+       return call_memop(q, vaddr, vb->planes[plane_no].mem_priv);
 
 }
 EXPORT_SYMBOL_GPL(vb2_plane_vaddr);
@@ -754,10 +753,10 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no)
 {
        struct vb2_queue *q = vb->vb2_queue;
 
-       if (plane_no > vb->num_planes)
+       if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv)
                return NULL;
 
-       return call_memop(q, plane_no, cookie, vb->planes[plane_no].mem_priv);
+       return call_memop(q, cookie, vb->planes[plane_no].mem_priv);
 }
 EXPORT_SYMBOL_GPL(vb2_plane_cookie);
 
@@ -883,7 +882,8 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 
        for (plane = 0; plane < vb->num_planes; ++plane) {
                /* Skip the plane if already verified */
-               if (vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr
+               if (vb->v4l2_planes[plane].m.userptr &&
+                   vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr
                    && vb->v4l2_planes[plane].length == planes[plane].length)
                        continue;
 
@@ -898,27 +898,23 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 
                /* Release previously acquired memory if present */
                if (vb->planes[plane].mem_priv)
-                       call_memop(q, plane, put_userptr,
-                                       vb->planes[plane].mem_priv);
+                       call_memop(q, put_userptr, vb->planes[plane].mem_priv);
 
                vb->planes[plane].mem_priv = NULL;
                vb->v4l2_planes[plane].m.userptr = 0;
                vb->v4l2_planes[plane].length = 0;
 
                /* Acquire each plane's memory */
-               if (q->mem_ops->get_userptr) {
-                       mem_priv = q->mem_ops->get_userptr(q->alloc_ctx[plane],
-                                                       planes[plane].m.userptr,
-                                                       planes[plane].length,
-                                                       write);
-                       if (IS_ERR(mem_priv)) {
-                               dprintk(1, "qbuf: failed acquiring userspace "
+               mem_priv = call_memop(q, get_userptr, q->alloc_ctx[plane],
+                                     planes[plane].m.userptr,
+                                     planes[plane].length, write);
+               if (IS_ERR_OR_NULL(mem_priv)) {
+                       dprintk(1, "qbuf: failed acquiring userspace "
                                                "memory for plane %d\n", plane);
-                               ret = PTR_ERR(mem_priv);
-                               goto err;
-                       }
-                       vb->planes[plane].mem_priv = mem_priv;
+                       ret = mem_priv ? PTR_ERR(mem_priv) : -EINVAL;
+                       goto err;
                }
+               vb->planes[plane].mem_priv = mem_priv;
        }
 
        /*
@@ -943,8 +939,7 @@ err:
        /* In case of errors, release planes that were already acquired */
        for (plane = 0; plane < vb->num_planes; ++plane) {
                if (vb->planes[plane].mem_priv)
-                       call_memop(q, plane, put_userptr,
-                                  vb->planes[plane].mem_priv);
+                       call_memop(q, put_userptr, vb->planes[plane].mem_priv);
                vb->planes[plane].mem_priv = NULL;
                vb->v4l2_planes[plane].m.userptr = 0;
                vb->v4l2_planes[plane].length = 0;
@@ -1081,46 +1076,76 @@ EXPORT_SYMBOL_GPL(vb2_prepare_buf);
  */
 int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
 {
+       struct rw_semaphore *mmap_sem = NULL;
        struct vb2_buffer *vb;
-       int ret;
+       int ret = 0;
+
+       /*
+        * In case of user pointer buffers vb2 allocator needs to get direct
+        * access to userspace pages. This requires getting read access on
+        * mmap semaphore in the current process structure. The same
+        * semaphore is taken before calling mmap operation, while both mmap
+        * and qbuf are called by the driver or v4l2 core with driver's lock
+        * held. To avoid a AB-BA deadlock (mmap_sem then driver's lock in
+        * mmap and driver's lock then mmap_sem in qbuf) the videobuf2 core
+        * release driver's lock, takes mmap_sem and then takes again driver's
+        * lock.
+        *
+        * To avoid race with other vb2 calls, which might be called after
+        * releasing driver's lock, this operation is performed at the
+        * beggining of qbuf processing. This way the queue status is
+        * consistent after getting driver's lock back.
+        */
+       if (q->memory == V4L2_MEMORY_USERPTR) {
+               mmap_sem = &current->mm->mmap_sem;
+               call_qop(q, wait_prepare, q);
+               down_read(mmap_sem);
+               call_qop(q, wait_finish, q);
+       }
 
        if (q->fileio) {
                dprintk(1, "qbuf: file io in progress\n");
-               return -EBUSY;
+               ret = -EBUSY;
+               goto unlock;
        }
 
        if (b->type != q->type) {
                dprintk(1, "qbuf: invalid buffer type\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto unlock;
        }
 
        if (b->index >= q->num_buffers) {
                dprintk(1, "qbuf: buffer index out of range\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto unlock;
        }
 
        vb = q->bufs[b->index];
        if (NULL == vb) {
                /* Should never happen */
                dprintk(1, "qbuf: buffer is NULL\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto unlock;
        }
 
        if (b->memory != q->memory) {
                dprintk(1, "qbuf: invalid memory type\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto unlock;
        }
 
        switch (vb->state) {
        case VB2_BUF_STATE_DEQUEUED:
                ret = __buf_prepare(vb, b);
                if (ret)
-                       return ret;
+                       goto unlock;
        case VB2_BUF_STATE_PREPARED:
                break;
        default:
                dprintk(1, "qbuf: buffer already in use\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto unlock;
        }
 
        /*
@@ -1141,7 +1166,10 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
        __fill_v4l2_buffer(vb, b);
 
        dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index);
-       return 0;
+unlock:
+       if (mmap_sem)
+               up_read(mmap_sem);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(vb2_qbuf);
 
@@ -1521,7 +1549,6 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
 int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
 {
        unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
-       struct vb2_plane *vb_plane;
        struct vb2_buffer *vb;
        unsigned int buffer, plane;
        int ret;
@@ -1558,9 +1585,8 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
                return ret;
 
        vb = q->bufs[buffer];
-       vb_plane = &vb->planes[plane];
 
-       ret = q->mem_ops->mmap(vb_plane->mem_priv, vma);
+       ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma);
        if (ret)
                return ret;
 
index 3bad8b105fea3260ffcb5fff745009b943885eec..25c3b360e1adf1cdfdce19f80c59f847d38f18b4 100644 (file)
@@ -140,7 +140,6 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
        if (!buf->pages)
                goto userptr_fail_pages_array_alloc;
 
-       down_read(&current->mm->mmap_sem);
        num_pages_from_user = get_user_pages(current, current->mm,
                                             vaddr & PAGE_MASK,
                                             buf->sg_desc.num_pages,
@@ -148,7 +147,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
                                             1, /* force */
                                             buf->pages,
                                             NULL);
-       up_read(&current->mm->mmap_sem);
+
        if (num_pages_from_user != buf->sg_desc.num_pages)
                goto userptr_fail_get_user_pages;
 
index 71a7a78c3fc05ce039b87661644f880ea15b4a79..c41cb60245d6c0b593f4614f3baeb2a7b88bc4f2 100644 (file)
@@ -100,29 +100,26 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
        unsigned long offset, start, end;
        unsigned long this_pfn, prev_pfn;
        dma_addr_t pa = 0;
-       int ret = -EFAULT;
 
        start = vaddr;
        offset = start & ~PAGE_MASK;
        end = start + size;
 
-       down_read(&mm->mmap_sem);
        vma = find_vma(mm, start);
 
        if (vma == NULL || vma->vm_end < end)
-               goto done;
+               return -EFAULT;
 
        for (prev_pfn = 0; start < end; start += PAGE_SIZE) {
-               ret = follow_pfn(vma, start, &this_pfn);
+               int ret = follow_pfn(vma, start, &this_pfn);
                if (ret)
-                       goto done;
+                       return ret;
 
                if (prev_pfn == 0)
                        pa = this_pfn << PAGE_SHIFT;
-               else if (this_pfn != prev_pfn + 1) {
-                       ret = -EFAULT;
-                       goto done;
-               }
+               else if (this_pfn != prev_pfn + 1)
+                       return -EFAULT;
+
                prev_pfn = this_pfn;
        }
 
@@ -130,16 +127,11 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
         * Memory is contigous, lock vma and return to the caller
         */
        *res_vma = vb2_get_vma(vma);
-       if (*res_vma == NULL) {
-               ret = -ENOMEM;
-               goto done;
-       }
-       *res_pa = pa + offset;
-       ret = 0;
+       if (*res_vma == NULL)
+               return -ENOMEM;
 
-done:
-       up_read(&mm->mmap_sem);
-       return ret;
+       *res_pa = pa + offset;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
 
index a3a884234059afcacae18bd2e246190bfcfa5970..4e789a178f8a810ca5ec6341e5d1db9d2ae34ce7 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/module.h>
 #include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 
 
 struct vb2_vmalloc_buf {
        void                            *vaddr;
+       struct page                     **pages;
+       int                             write;
        unsigned long                   size;
+       unsigned int                    n_pages;
        atomic_t                        refcount;
        struct vb2_vmarea_handler       handler;
 };
@@ -31,7 +35,7 @@ static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
 {
        struct vb2_vmalloc_buf *buf;
 
-       buf = kzalloc(sizeof *buf, GFP_KERNEL);
+       buf = kzalloc(sizeof(*buf), GFP_KERNEL);
        if (!buf)
                return NULL;
 
@@ -42,15 +46,12 @@ static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
        buf->handler.arg = buf;
 
        if (!buf->vaddr) {
-               printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size);
+               pr_debug("vmalloc of size %ld failed\n", buf->size);
                kfree(buf);
                return NULL;
        }
 
        atomic_inc(&buf->refcount);
-       printk(KERN_DEBUG "Allocated vmalloc buffer of size %ld at vaddr=%p\n",
-                       buf->size, buf->vaddr);
-
        return buf;
 }
 
@@ -59,21 +60,84 @@ static void vb2_vmalloc_put(void *buf_priv)
        struct vb2_vmalloc_buf *buf = buf_priv;
 
        if (atomic_dec_and_test(&buf->refcount)) {
-               printk(KERN_DEBUG "%s: Freeing vmalloc mem at vaddr=%p\n",
-                       __func__, buf->vaddr);
                vfree(buf->vaddr);
                kfree(buf);
        }
 }
 
-static void *vb2_vmalloc_vaddr(void *buf_priv)
+static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
+                                    unsigned long size, int write)
+{
+       struct vb2_vmalloc_buf *buf;
+       unsigned long first, last;
+       int n_pages, offset;
+
+       buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->write = write;
+       offset = vaddr & ~PAGE_MASK;
+       buf->size = size;
+
+       first = vaddr >> PAGE_SHIFT;
+       last  = (vaddr + size - 1) >> PAGE_SHIFT;
+       buf->n_pages = last - first + 1;
+       buf->pages = kzalloc(buf->n_pages * sizeof(struct page *), GFP_KERNEL);
+       if (!buf->pages)
+               goto fail_pages_array_alloc;
+
+       /* current->mm->mmap_sem is taken by videobuf2 core */
+       n_pages = get_user_pages(current, current->mm, vaddr & PAGE_MASK,
+                                buf->n_pages, write, 1, /* force */
+                                buf->pages, NULL);
+       if (n_pages != buf->n_pages)
+               goto fail_get_user_pages;
+
+       buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, PAGE_KERNEL);
+       if (!buf->vaddr)
+               goto fail_get_user_pages;
+
+       buf->vaddr += offset;
+       return buf;
+
+fail_get_user_pages:
+       pr_debug("get_user_pages requested/got: %d/%d]\n", n_pages,
+                buf->n_pages);
+       while (--n_pages >= 0)
+               put_page(buf->pages[n_pages]);
+       kfree(buf->pages);
+
+fail_pages_array_alloc:
+       kfree(buf);
+
+       return NULL;
+}
+
+static void vb2_vmalloc_put_userptr(void *buf_priv)
 {
        struct vb2_vmalloc_buf *buf = buf_priv;
+       unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK;
+       unsigned int i;
+
+       if (vaddr)
+               vm_unmap_ram((void *)vaddr, buf->n_pages);
+       for (i = 0; i < buf->n_pages; ++i) {
+               if (buf->write)
+                       set_page_dirty_lock(buf->pages[i]);
+               put_page(buf->pages[i]);
+       }
+       kfree(buf->pages);
+       kfree(buf);
+}
 
-       BUG_ON(!buf);
+static void *vb2_vmalloc_vaddr(void *buf_priv)
+{
+       struct vb2_vmalloc_buf *buf = buf_priv;
 
        if (!buf->vaddr) {
-               printk(KERN_ERR "Address of an unallocated plane requested\n");
+               pr_err("Address of an unallocated plane requested "
+                      "or cannot map user pointer\n");
                return NULL;
        }
 
@@ -92,13 +156,13 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
        int ret;
 
        if (!buf) {
-               printk(KERN_ERR "No memory to map\n");
+               pr_err("No memory to map\n");
                return -EINVAL;
        }
 
        ret = remap_vmalloc_range(vma, buf->vaddr, 0);
        if (ret) {
-               printk(KERN_ERR "Remapping vmalloc memory, error: %d\n", ret);
+               pr_err("Remapping vmalloc memory, error: %d\n", ret);
                return ret;
        }
 
@@ -121,6 +185,8 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
 const struct vb2_mem_ops vb2_vmalloc_memops = {
        .alloc          = vb2_vmalloc_alloc,
        .put            = vb2_vmalloc_put,
+       .get_userptr    = vb2_vmalloc_get_userptr,
+       .put_userptr    = vb2_vmalloc_put_userptr,
        .vaddr          = vb2_vmalloc_vaddr,
        .mmap           = vb2_vmalloc_mmap,
        .num_users      = vb2_vmalloc_num_users,
index 52a0a3736c820d156025c8fc91df13d20cb31663..4d7391ec80013279d965db1070f978f3948cf241 100644 (file)
@@ -708,7 +708,7 @@ static int vino_allocate_buffer(struct vino_framebuffer *fb,
                size, count);
 
        /* allocate memory for table with virtual (page) addresses */
-       fb->desc_table.virtual = (unsigned long *)
+       fb->desc_table.virtual =
                kmalloc(count * sizeof(unsigned long), GFP_KERNEL);
        if (!fb->desc_table.virtual)
                return -ENOMEM;
index e8a27844bf39c36e14f466ebb9cd2941f61b4ef3..e86173bd1327865cc8c07147b0dfcc7d43c84700 100644 (file)
@@ -57,7 +57,7 @@
                   ZR36057_ISR_GIRQ1 | \
                   ZR36057_ISR_JPEGRepIRQ )
 
-static int lml33dpath;         /* default = 0
+static bool lml33dpath;                /* default = 0
                                 * 1 will use digital path in capture
                                 * mode instead of analog. It can be
                                 * used for picture adjustments using
index f6d26419445ee8728367fe925ed3f80d2d484092..4c09ab781ec3a3cbf503f2626c64b449e94dabf3 100644 (file)
@@ -1958,7 +1958,6 @@ static int zoran_g_fbuf(struct file *file, void *__fh,
        mutex_unlock(&zr->resource_lock);
        fb->fmt.colorspace = V4L2_COLORSPACE_SRGB;
        fb->fmt.field = V4L2_FIELD_INTERLACED;
-       fb->flags = V4L2_FBUF_FLAG_OVERLAY;
        fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
 
        return 0;
index 5e4f57cbf31478d35f361a55ca2adc8f2f77f3b3..f08546fe22347718777c8b330b9ec4ce54bb91d5 100644 (file)
@@ -50,7 +50,7 @@
 /* amount of chips attached via this driver */
 static int zr36060_codecs;
 
-static int low_bitrate;
+static bool low_bitrate;
 module_param(low_bitrate, bool, 0);
 MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate");
 
index 6ce70e9615d342660f7da9e71339ffad4c3087a3..5319e9b65847e0749b033f6e55a5d0a82261ef21 100644 (file)
@@ -21,7 +21,7 @@
 
 #define DRIVER_NAME "jmb38x_ms"
 
-static int no_dma;
+static bool no_dma;
 module_param(no_dma, bool, 0644);
 
 enum {
index 668f5c6a0399f932743cbf16a8c03f1264c78b50..29b2172ae18fc4f6439d4a026bdf511e496bb076 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/swab.h>
 #include "r592.h"
 
-static int r592_enable_dma = 1;
+static bool r592_enable_dma = 1;
 static int debug;
 
 static const char *tpc_names[] = {
index b7aacf47703a33c1609f51ddfb5c7ec56a91a1de..6902b83eb1b48a803bff1fe51bfc0741ed8ed2a3 100644 (file)
@@ -22,7 +22,7 @@
 
 #define DRIVER_NAME "tifm_ms"
 
-static int no_dma;
+static bool no_dma;
 module_param(no_dma, bool, 0644);
 
 /*
index e017dc88622ada48f145457585e5fc376a6d155e..f93dd9571c3c81e8b44f26dc51d54b0901039cd6 100644 (file)
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
 #include <linux/mfd/88pm860x.h>
 #include <linux/slab.h>
 
-static inline int pm860x_read_device(struct i2c_client *i2c,
-                                    int reg, int bytes, void *dest)
-{
-       unsigned char data;
-       int ret;
-
-       data = (unsigned char)reg;
-       ret = i2c_master_send(i2c, &data, 1);
-       if (ret < 0)
-               return ret;
-
-       ret = i2c_master_recv(i2c, dest, bytes);
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-static inline int pm860x_write_device(struct i2c_client *i2c,
-                                     int reg, int bytes, void *src)
-{
-       unsigned char buf[bytes + 1];
-       int ret;
-
-       buf[0] = (unsigned char)reg;
-       memcpy(&buf[1], src, bytes);
-
-       ret = i2c_master_send(i2c, buf, bytes + 1);
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
 int pm860x_reg_read(struct i2c_client *i2c, int reg)
 {
        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
-       unsigned char data;
+       struct regmap *map = (i2c == chip->client) ? chip->regmap
+                               : chip->regmap_companion;
+       unsigned int data;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       ret = pm860x_read_device(i2c, reg, 1, &data);
-       mutex_unlock(&chip->io_lock);
-
+       ret = regmap_read(map, reg, &data);
        if (ret < 0)
                return ret;
        else
@@ -68,12 +37,11 @@ int pm860x_reg_write(struct i2c_client *i2c, int reg,
                     unsigned char data)
 {
        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+       struct regmap *map = (i2c == chip->client) ? chip->regmap
+                               : chip->regmap_companion;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       ret = pm860x_write_device(i2c, reg, 1, &data);
-       mutex_unlock(&chip->io_lock);
-
+       ret = regmap_write(map, reg, data);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_reg_write);
@@ -82,12 +50,11 @@ int pm860x_bulk_read(struct i2c_client *i2c, int reg,
                     int count, unsigned char *buf)
 {
        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+       struct regmap *map = (i2c == chip->client) ? chip->regmap
+                               : chip->regmap_companion;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       ret = pm860x_read_device(i2c, reg, count, buf);
-       mutex_unlock(&chip->io_lock);
-
+       ret = regmap_raw_read(map, reg, buf, count);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_bulk_read);
@@ -96,12 +63,11 @@ int pm860x_bulk_write(struct i2c_client *i2c, int reg,
                      int count, unsigned char *buf)
 {
        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+       struct regmap *map = (i2c == chip->client) ? chip->regmap
+                               : chip->regmap_companion;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       ret = pm860x_write_device(i2c, reg, count, buf);
-       mutex_unlock(&chip->io_lock);
-
+       ret = regmap_raw_write(map, reg, buf, count);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_bulk_write);
@@ -110,39 +76,78 @@ int pm860x_set_bits(struct i2c_client *i2c, int reg,
                    unsigned char mask, unsigned char data)
 {
        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
-       unsigned char value;
+       struct regmap *map = (i2c == chip->client) ? chip->regmap
+                               : chip->regmap_companion;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       ret = pm860x_read_device(i2c, reg, 1, &value);
-       if (ret < 0)
-               goto out;
-       value &= ~mask;
-       value |= data;
-       ret = pm860x_write_device(i2c, reg, 1, &value);
-out:
-       mutex_unlock(&chip->io_lock);
+       ret = regmap_update_bits(map, reg, mask, data);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_set_bits);
 
+static int read_device(struct i2c_client *i2c, int reg,
+                      int bytes, void *dest)
+{
+       unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3];
+       unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2];
+       struct i2c_adapter *adap = i2c->adapter;
+       struct i2c_msg msg[2] = {{i2c->addr, 0, 1, msgbuf0},
+                                {i2c->addr, I2C_M_RD, 0, msgbuf1},
+                               };
+       int num = 1, ret = 0;
+
+       if (dest == NULL)
+               return -EINVAL;
+       msgbuf0[0] = (unsigned char)reg;        /* command */
+       msg[1].len = bytes;
+
+       /* if data needs to read back, num should be 2 */
+       if (bytes > 0)
+               num = 2;
+       ret = adap->algo->master_xfer(adap, msg, num);
+       memcpy(dest, msgbuf1, bytes);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static int write_device(struct i2c_client *i2c, int reg,
+                       int bytes, void *src)
+{
+       unsigned char buf[bytes + 1];
+       struct i2c_adapter *adap = i2c->adapter;
+       struct i2c_msg msg;
+       int ret;
+
+       buf[0] = (unsigned char)reg;
+       memcpy(&buf[1], src, bytes);
+       msg.addr = i2c->addr;
+       msg.flags = 0;
+       msg.len = bytes + 1;
+       msg.buf = buf;
+
+       ret = adap->algo->master_xfer(adap, &msg, 1);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
 int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
 {
-       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
        unsigned char zero = 0;
        unsigned char data;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       pm860x_write_device(i2c, 0xFA, 0, &zero);
-       pm860x_write_device(i2c, 0xFB, 0, &zero);
-       pm860x_write_device(i2c, 0xFF, 0, &zero);
-       ret = pm860x_read_device(i2c, reg, 1, &data);
+       i2c_lock_adapter(i2c->adapter);
+       read_device(i2c, 0xFA, 0, &zero);
+       read_device(i2c, 0xFB, 0, &zero);
+       read_device(i2c, 0xFF, 0, &zero);
+       ret = read_device(i2c, reg, 1, &data);
        if (ret >= 0)
                ret = (int)data;
-       pm860x_write_device(i2c, 0xFE, 0, &zero);
-       pm860x_write_device(i2c, 0xFC, 0, &zero);
-       mutex_unlock(&chip->io_lock);
+       read_device(i2c, 0xFE, 0, &zero);
+       read_device(i2c, 0xFC, 0, &zero);
+       i2c_unlock_adapter(i2c->adapter);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_page_reg_read);
@@ -150,18 +155,17 @@ EXPORT_SYMBOL(pm860x_page_reg_read);
 int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
                          unsigned char data)
 {
-       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
        unsigned char zero;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       pm860x_write_device(i2c, 0xFA, 0, &zero);
-       pm860x_write_device(i2c, 0xFB, 0, &zero);
-       pm860x_write_device(i2c, 0xFF, 0, &zero);
-       ret = pm860x_write_device(i2c, reg, 1, &data);
-       pm860x_write_device(i2c, 0xFE, 0, &zero);
-       pm860x_write_device(i2c, 0xFC, 0, &zero);
-       mutex_unlock(&chip->io_lock);
+       i2c_lock_adapter(i2c->adapter);
+       read_device(i2c, 0xFA, 0, &zero);
+       read_device(i2c, 0xFB, 0, &zero);
+       read_device(i2c, 0xFF, 0, &zero);
+       ret = write_device(i2c, reg, 1, &data);
+       read_device(i2c, 0xFE, 0, &zero);
+       read_device(i2c, 0xFC, 0, &zero);
+       i2c_unlock_adapter(i2c->adapter);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_page_reg_write);
@@ -169,18 +173,17 @@ EXPORT_SYMBOL(pm860x_page_reg_write);
 int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
                          int count, unsigned char *buf)
 {
-       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
        unsigned char zero = 0;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       pm860x_write_device(i2c, 0xFA, 0, &zero);
-       pm860x_write_device(i2c, 0xFB, 0, &zero);
-       pm860x_write_device(i2c, 0xFF, 0, &zero);
-       ret = pm860x_read_device(i2c, reg, count, buf);
-       pm860x_write_device(i2c, 0xFE, 0, &zero);
-       pm860x_write_device(i2c, 0xFC, 0, &zero);
-       mutex_unlock(&chip->io_lock);
+       i2c_lock_adapter(i2c->adapter);
+       read_device(i2c, 0xfa, 0, &zero);
+       read_device(i2c, 0xfb, 0, &zero);
+       read_device(i2c, 0xff, 0, &zero);
+       ret = read_device(i2c, reg, count, buf);
+       read_device(i2c, 0xFE, 0, &zero);
+       read_device(i2c, 0xFC, 0, &zero);
+       i2c_unlock_adapter(i2c->adapter);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_page_bulk_read);
@@ -188,18 +191,18 @@ EXPORT_SYMBOL(pm860x_page_bulk_read);
 int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
                           int count, unsigned char *buf)
 {
-       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
        unsigned char zero = 0;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       pm860x_write_device(i2c, 0xFA, 0, &zero);
-       pm860x_write_device(i2c, 0xFB, 0, &zero);
-       pm860x_write_device(i2c, 0xFF, 0, &zero);
-       ret = pm860x_write_device(i2c, reg, count, buf);
-       pm860x_write_device(i2c, 0xFE, 0, &zero);
-       pm860x_write_device(i2c, 0xFC, 0, &zero);
-       mutex_unlock(&chip->io_lock);
+       i2c_lock_adapter(i2c->adapter);
+       read_device(i2c, 0xFA, 0, &zero);
+       read_device(i2c, 0xFB, 0, &zero);
+       read_device(i2c, 0xFF, 0, &zero);
+       ret = write_device(i2c, reg, count, buf);
+       read_device(i2c, 0xFE, 0, &zero);
+       read_device(i2c, 0xFC, 0, &zero);
+       i2c_unlock_adapter(i2c->adapter);
+       i2c_unlock_adapter(i2c->adapter);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_page_bulk_write);
@@ -207,25 +210,24 @@ EXPORT_SYMBOL(pm860x_page_bulk_write);
 int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
                         unsigned char mask, unsigned char data)
 {
-       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
        unsigned char zero;
        unsigned char value;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       pm860x_write_device(i2c, 0xFA, 0, &zero);
-       pm860x_write_device(i2c, 0xFB, 0, &zero);
-       pm860x_write_device(i2c, 0xFF, 0, &zero);
-       ret = pm860x_read_device(i2c, reg, 1, &value);
+       i2c_lock_adapter(i2c->adapter);
+       read_device(i2c, 0xFA, 0, &zero);
+       read_device(i2c, 0xFB, 0, &zero);
+       read_device(i2c, 0xFF, 0, &zero);
+       ret = read_device(i2c, reg, 1, &value);
        if (ret < 0)
                goto out;
        value &= ~mask;
        value |= data;
-       ret = pm860x_write_device(i2c, reg, 1, &value);
+       ret = write_device(i2c, reg, 1, &value);
 out:
-       pm860x_write_device(i2c, 0xFE, 0, &zero);
-       pm860x_write_device(i2c, 0xFC, 0, &zero);
-       mutex_unlock(&chip->io_lock);
+       read_device(i2c, 0xFE, 0, &zero);
+       read_device(i2c, 0xFC, 0, &zero);
+       i2c_unlock_adapter(i2c->adapter);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_page_set_bits);
@@ -257,11 +259,17 @@ static int verify_addr(struct i2c_client *i2c)
        return 0;
 }
 
+static struct regmap_config pm860x_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
 static int __devinit pm860x_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
        struct pm860x_platform_data *pdata = client->dev.platform_data;
        struct pm860x_chip *chip;
+       int ret;
 
        if (!pdata) {
                pr_info("No platform data in %s!\n", __func__);
@@ -273,10 +281,17 @@ static int __devinit pm860x_probe(struct i2c_client *client,
                return -ENOMEM;
 
        chip->id = verify_addr(client);
+       chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config);
+       if (IS_ERR(chip->regmap)) {
+               ret = PTR_ERR(chip->regmap);
+               dev_err(&client->dev, "Failed to allocate register map: %d\n",
+                               ret);
+               kfree(chip);
+               return ret;
+       }
        chip->client = client;
        i2c_set_clientdata(client, chip);
        chip->dev = &client->dev;
-       mutex_init(&chip->io_lock);
        dev_set_drvdata(chip->dev, chip);
 
        /*
@@ -290,6 +305,14 @@ static int __devinit pm860x_probe(struct i2c_client *client,
                chip->companion_addr = pdata->companion_addr;
                chip->companion = i2c_new_dummy(chip->client->adapter,
                                                chip->companion_addr);
+               chip->regmap_companion = regmap_init_i2c(chip->companion,
+                                                       &pm860x_regmap_config);
+               if (IS_ERR(chip->regmap_companion)) {
+                       ret = PTR_ERR(chip->regmap_companion);
+                       dev_err(&chip->companion->dev,
+                               "Failed to allocate register map: %d\n", ret);
+                       return ret;
+               }
                i2c_set_clientdata(chip->companion, chip);
        }
 
@@ -302,7 +325,11 @@ static int __devexit pm860x_remove(struct i2c_client *client)
        struct pm860x_chip *chip = i2c_get_clientdata(client);
 
        pm860x_device_exit(chip);
-       i2c_unregister_device(chip->companion);
+       if (chip->companion) {
+               regmap_exit(chip->regmap_companion);
+               i2c_unregister_device(chip->companion);
+       }
+       regmap_exit(chip->regmap);
        kfree(chip);
        return 0;
 }
index 053208d31fb9f2ff3bad030e184fd67e1966ea3d..cd13e9f2f5e668d14927b698b851b6d0f99dd7bb 100644 (file)
@@ -12,6 +12,7 @@ config MFD_CORE
 config MFD_88PM860X
        bool "Support Marvell 88PM8606/88PM8607"
        depends on I2C=y && GENERIC_HARDIRQS
+       select REGMAP_I2C
        select MFD_CORE
        help
          This supports for Marvell 88PM8606/88PM8607 Power Management IC.
@@ -199,7 +200,7 @@ config MENELAUS
 
 config TWL4030_CORE
        bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y && GENERIC_HARDIRQS && IRQ_DOMAIN
        help
          Say yes here if you have TWL4030 / TWL6030 family chip on your board.
          This core driver provides register access and IRQ handling
@@ -257,7 +258,7 @@ config TWL6040_CORE
 
 config MFD_STMPE
        bool "Support STMicroelectronics STMPE"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS
        select MFD_CORE
        help
          Support for the STMPE family of I/O Expanders from
@@ -278,6 +279,23 @@ config MFD_STMPE
                Keypad: stmpe-keypad
                Touchscreen: stmpe-ts
 
+menu "STMPE Interface Drivers"
+depends on MFD_STMPE
+
+config STMPE_I2C
+       bool "STMPE I2C Inteface"
+       depends on I2C=y
+       default y
+       help
+         This is used to enable I2C interface of STMPE
+
+config STMPE_SPI
+       bool "STMPE SPI Inteface"
+       depends on SPI_MASTER
+       help
+         This is used to enable SPI interface of STMPE
+endmenu
+
 config MFD_TC3589X
        bool "Support Toshiba TC35892 and variants"
        depends on I2C=y && GENERIC_HARDIRQS
@@ -311,7 +329,7 @@ config MFD_TC6387XB
 
 config MFD_TC6393XB
        bool "Support Toshiba TC6393XB"
-       depends on GPIOLIB && ARM
+       depends on GPIOLIB && ARM && HAVE_CLK
        select MFD_CORE
        select MFD_TMIO
        help
@@ -399,6 +417,17 @@ config MFD_MAX8998
          additional drivers must be enabled in order to use the functionality
          of the device.
 
+config MFD_S5M_CORE
+       bool "SAMSUNG S5M Series Support"
+       depends on I2C=y && GENERIC_HARDIRQS
+       select MFD_CORE
+       select REGMAP_I2C
+       help
+        Support for the Samsung Electronics S5M MFD series.
+        This driver provies common support for accessing the device,
+        additional drivers must be enabled in order to use the functionality
+        of the device
+
 config MFD_WM8400
        tristate "Support Wolfson Microelectronics WM8400"
        select MFD_CORE
index 47591fc7d0d2ccca33fc01348ca1e99304d715ec..b953bab934f7f872a7f53307a865a7efa22312ac 100644 (file)
@@ -16,6 +16,8 @@ obj-$(CONFIG_MFD_DM355EVM_MSP)        += dm355evm_msp.o
 obj-$(CONFIG_MFD_TI_SSP)       += ti-ssp.o
 
 obj-$(CONFIG_MFD_STMPE)                += stmpe.o
+obj-$(CONFIG_STMPE_I2C)                += stmpe-i2c.o
+obj-$(CONFIG_STMPE_SPI)                += stmpe-spi.o
 obj-$(CONFIG_MFD_TC3589X)      += tc3589x.o
 obj-$(CONFIG_MFD_T7L66XB)      += t7l66xb.o tmio_core.o
 obj-$(CONFIG_MFD_TC6387XB)     += tc6387xb.o tmio_core.o
@@ -109,3 +111,4 @@ obj-$(CONFIG_MFD_PM8XXX_IRQ)        += pm8xxx-irq.o
 obj-$(CONFIG_TPS65911_COMPARATOR)      += tps65911-comparator.o
 obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
 obj-$(CONFIG_MFD_INTEL_MSIC)   += intel_msic.o
+obj-$(CONFIG_MFD_S5M_CORE)     += s5m-core.o s5m-irq.o
index 02c42015ba5108344c46cd29986d30e64e5cd304..3aa36eb5c79bcf769616013cd3176ed04af500bc 100644 (file)
@@ -407,13 +407,13 @@ static int aat2870_i2c_probe(struct i2c_client *client,
                aat2870->init(aat2870);
 
        if (aat2870->en_pin >= 0) {
-               ret = gpio_request(aat2870->en_pin, "aat2870-en");
+               ret = gpio_request_one(aat2870->en_pin, GPIOF_OUT_INIT_HIGH,
+                                      "aat2870-en");
                if (ret < 0) {
                        dev_err(&client->dev,
                                "Failed to request GPIO %d\n", aat2870->en_pin);
                        goto out_kfree;
                }
-               gpio_direction_output(aat2870->en_pin, 1);
        }
 
        aat2870_enable(aat2870);
@@ -468,9 +468,10 @@ static int aat2870_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int aat2870_i2c_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct aat2870_data *aat2870 = i2c_get_clientdata(client);
 
        aat2870_disable(aat2870);
@@ -478,8 +479,9 @@ static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state)
        return 0;
 }
 
-static int aat2870_i2c_resume(struct i2c_client *client)
+static int aat2870_i2c_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct aat2870_data *aat2870 = i2c_get_clientdata(client);
        struct aat2870_register *reg = NULL;
        int i;
@@ -495,12 +497,12 @@ static int aat2870_i2c_resume(struct i2c_client *client)
 
        return 0;
 }
-#else
-#define aat2870_i2c_suspend    NULL
-#define aat2870_i2c_resume     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(aat2870_pm_ops, aat2870_i2c_suspend,
+                        aat2870_i2c_resume);
 
-static struct i2c_device_id aat2870_i2c_id_table[] = {
+static const struct i2c_device_id aat2870_i2c_id_table[] = {
        { "aat2870", 0 },
        { }
 };
@@ -510,11 +512,10 @@ static struct i2c_driver aat2870_i2c_driver = {
        .driver = {
                .name   = "aat2870",
                .owner  = THIS_MODULE,
+               .pm     = &aat2870_pm_ops,
        },
        .probe          = aat2870_i2c_probe,
        .remove         = aat2870_i2c_remove,
-       .suspend        = aat2870_i2c_suspend,
-       .resume         = aat2870_i2c_resume,
        .id_table       = aat2870_i2c_id_table,
 };
 
index ec10629a0b0b151b5235432dc08bb238f4783b22..bd56a764dea1f36cb522225e09ce4992e0733a56 100644 (file)
@@ -22,8 +22,8 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/random.h>
-#include <linux/mfd/ab5500/ab5500.h>
 #include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab5500.h>
 #include <linux/list.h>
 #include <linux/bitops.h>
 #include <linux/spinlock.h>
index b7b2d3483fd4e1e1f8bb5b6a2feb6e7c349c57f3..72006940937ae54a1500ac66fd3461d2e6ca9b32 100644 (file)
@@ -7,8 +7,8 @@
 #include <linux/module.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
-#include <linux/mfd/ab5500/ab5500.h>
 #include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab5500.h>
 #include <linux/uaccess.h>
 
 #include "ab5500-core.h"
index d3d572b2317b888be174bf52d3d17c65b391ef07..53e2a80f42facb931f56c4adcde9221f5b5c69e1 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/regulator/ab8500.h>
 
 /*
index dedb7f65cea600a205f83fc2e81e385649cf74ee..9a0211aa88971c0207b3caa18d30eab6cb57821a 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/platform_device.h>
 
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 
 static u32 debug_bank;
 static u32 debug_address;
index e985d1701a83df56a463cb47ff2a1169bc894ba6..c39fc716e1dcf520592bc866cba0be4e661d0e09 100644 (file)
@@ -18,9 +18,9 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/list.h>
-#include <linux/mfd/ab8500.h>
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500/gpadc.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
 
 /*
  * GPADC register offsets
index 9be541c6b004c8adc9cf6cde3416c6bff31c9e31..087fecd71ce032b2ad459467c02aef47197f13ea 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/mfd/db8500-prcmu.h>
 
 static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
index f20feefac19020969dc55a24bb8a8d162934adb5..c28d4eb1eff019517d166476c590652f2ac1b8b1 100644 (file)
@@ -7,9 +7,9 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/ab8500.h>
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500/sysctrl.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-sysctrl.h>
 
 static struct device *sysctrl_dev;
 
index 155fa04078821d6fc8d5a5475225bba3a436ba06..315fef5d466ac3f2d380246ffa75a056d131cb52 100644 (file)
@@ -172,14 +172,14 @@ static void __devexit cs5535_mfd_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-static struct pci_device_id cs5535_mfd_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(cs5535_mfd_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl);
 
-static struct pci_driver cs5535_mfd_drv = {
+static struct pci_driver cs5535_mfd_driver = {
        .name = DRV_NAME,
        .id_table = cs5535_mfd_pci_tbl,
        .probe = cs5535_mfd_probe,
@@ -188,12 +188,12 @@ static struct pci_driver cs5535_mfd_drv = {
 
 static int __init cs5535_mfd_init(void)
 {
-       return pci_register_driver(&cs5535_mfd_drv);
+       return pci_register_driver(&cs5535_mfd_driver);
 }
 
 static void __exit cs5535_mfd_exit(void)
 {
-       pci_unregister_driver(&cs5535_mfd_drv);
+       pci_unregister_driver(&cs5535_mfd_driver);
 }
 
 module_init(cs5535_mfd_init);
index 8ad88da647b9abfd201c659eb92ec12072b03a60..7710227d284e82f3ea98bd6dcf307abd177f71e9 100644 (file)
@@ -308,8 +308,7 @@ static int add_children(struct i2c_client *client)
        for (i = 0; i < ARRAY_SIZE(config_inputs); i++) {
                int gpio = dm355evm_msp_gpio.base + config_inputs[i].offset;
 
-               gpio_request(gpio, config_inputs[i].label);
-               gpio_direction_input(gpio);
+               gpio_request_one(gpio, GPIOF_IN, config_inputs[i].label);
 
                /* make it easy for userspace to see these */
                gpio_export(gpio, false);
index 97c27762174f1527af8c2b72c5438c4eebc12144..b76657eb0c51044503e3c71b7345c98596d33cbd 100644 (file)
@@ -485,17 +485,7 @@ static struct platform_driver intel_msic_driver = {
        },
 };
 
-static int __init intel_msic_init(void)
-{
-       return platform_driver_register(&intel_msic_driver);
-}
-module_init(intel_msic_init);
-
-static void __exit intel_msic_exit(void)
-{
-       platform_driver_unregister(&intel_msic_driver);
-}
-module_exit(intel_msic_exit);
+module_platform_driver(intel_msic_driver);
 
 MODULE_DESCRIPTION("Driver for Intel MSIC");
 MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
index 5c2a06acb77fce5d226c183e2197602eff8f434d..a9223ed1b7c5d9a152a8533c72ac1faafd3b7385 100644 (file)
@@ -33,7 +33,7 @@
 
 /* Module Parameters */
 static unsigned int num_modules = CMODIO_MAX_MODULES;
-static unsigned char *modules[CMODIO_MAX_MODULES] = {
+static char *modules[CMODIO_MAX_MODULES] = {
        "empty", "empty", "empty", "empty",
 };
 
index ef39528088f2298a47e7f62f69317b2a6af428ee..87662a17dec62d527a3af1b8b7fb8c782c85dd92 100644 (file)
@@ -181,7 +181,7 @@ static struct resource jz4740_battery_resources[] = {
        },
 };
 
-const struct mfd_cell jz4740_adc_cells[] = {
+static struct mfd_cell jz4740_adc_cells[] = {
        {
                .id = 0,
                .name = "jz4740-hwmon",
@@ -338,17 +338,7 @@ static struct platform_driver jz4740_adc_driver = {
        },
 };
 
-static int __init jz4740_adc_init(void)
-{
-       return platform_driver_register(&jz4740_adc_driver);
-}
-module_init(jz4740_adc_init);
-
-static void __exit jz4740_adc_exit(void)
-{
-       platform_driver_unregister(&jz4740_adc_driver);
-}
-module_exit(jz4740_adc_exit);
+module_platform_driver(jz4740_adc_driver);
 
 MODULE_DESCRIPTION("JZ4740 SoC ADC driver");
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
index ea1169b04779597cb4bf8964b26d7f861ba75afa..abc421364a454f0f596f7e5be734e346838318cb 100644 (file)
@@ -74,7 +74,7 @@ static struct mfd_cell tunnelcreek_cells[] = {
        },
 };
 
-static struct pci_device_id lpc_sch_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) },
        { 0, }
index 0219115e00c73f84c925045afceb96d65ea83ea3..d9e4b36edee984e3f5008b02f16d8d9becdb703f 100644 (file)
@@ -161,6 +161,8 @@ static int __devinit max8925_probe(struct i2c_client *client,
        chip->adc = i2c_new_dummy(chip->i2c->adapter, ADC_I2C_ADDR);
        i2c_set_clientdata(chip->adc, chip);
 
+       device_init_wakeup(&client->dev, 1);
+
        max8925_device_init(chip, pdata);
 
        return 0;
@@ -177,10 +179,35 @@ static int __devexit max8925_remove(struct i2c_client *client)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int max8925_suspend(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct max8925_chip *chip = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev) && chip->wakeup_flag)
+               enable_irq_wake(chip->core_irq);
+       return 0;
+}
+
+static int max8925_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct max8925_chip *chip = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev) && chip->wakeup_flag)
+               disable_irq_wake(chip->core_irq);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max8925_pm_ops, max8925_suspend, max8925_resume);
+
 static struct i2c_driver max8925_driver = {
        .driver = {
                .name   = "max8925",
                .owner  = THIS_MODULE,
+               .pm     = &max8925_pm_ops,
        },
        .probe          = max8925_probe,
        .remove         = __devexit_p(max8925_remove),
index 5be53ae9b61cf2a6d6c318c881e43605b3dee526..cb83a7ab53e73b9825c4eb527211ab49ccd33a7e 100644 (file)
@@ -43,7 +43,8 @@ static struct mfd_cell max8997_devs[] = {
        { .name = "max8997-battery", },
        { .name = "max8997-haptic", },
        { .name = "max8997-muic", },
-       { .name = "max8997-flash", },
+       { .name = "max8997-led", .id = 1 },
+       { .name = "max8997-led", .id = 2 },
 };
 
 int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
index de4096aee24877fccbaf36ae981b06483d41da50..6ef56d28c05686bf298f589cebf91c43fcc707b8 100644 (file)
@@ -176,6 +176,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
        if (ret < 0)
                goto err;
 
+       device_init_wakeup(max8998->dev, max8998->wakeup);
+
        return ret;
 
 err:
@@ -210,7 +212,7 @@ static int max8998_suspend(struct device *dev)
        struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
        struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
 
-       if (max8998->wakeup)
+       if (device_may_wakeup(dev))
                irq_set_irq_wake(max8998->irq, 1);
        return 0;
 }
@@ -220,7 +222,7 @@ static int max8998_resume(struct device *dev)
        struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
        struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
 
-       if (max8998->wakeup)
+       if (device_may_wakeup(dev))
                irq_set_irq_wake(max8998->irq, 0);
        /*
         * In LP3974, if IRQ registers are not "read & clear"
index e9619acc02375342276d84e5d9aee83e7a2597a8..7122386b4e3cf1830dbb3cab2f552efefeb43834 100644 (file)
 #include <linux/spi/spi.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/mc13xxx.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 
 struct mc13xxx {
        struct spi_device *spidev;
        struct mutex lock;
        int irq;
+       int flags;
 
        irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
        void *irqdata[MC13XXX_NUM_IRQ];
@@ -550,10 +554,7 @@ static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
 
 int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
 {
-       struct mc13xxx_platform_data *pdata =
-               dev_get_platdata(&mc13xxx->spidev->dev);
-
-       return pdata->flags;
+       return mc13xxx->flags;
 }
 EXPORT_SYMBOL(mc13xxx_get_flags);
 
@@ -615,13 +616,13 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
                break;
 
        case MC13XXX_ADC_MODE_SINGLE_CHAN:
-               adc0 |= old_adc0 & MC13XXX_ADC0_TSMOD_MASK;
+               adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
                adc1 |= (channel & 0x7) << MC13XXX_ADC1_CHAN0_SHIFT;
                adc1 |= MC13XXX_ADC1_RAND;
                break;
 
        case MC13XXX_ADC_MODE_MULT_CHAN:
-               adc0 |= old_adc0 & MC13XXX_ADC0_TSMOD_MASK;
+               adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
                adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT;
                break;
 
@@ -696,17 +697,67 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
        return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
 }
 
+#ifdef CONFIG_OF
+static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
+{
+       struct device_node *np = mc13xxx->spidev->dev.of_node;
+
+       if (!np)
+               return -ENODEV;
+
+       if (of_get_property(np, "fsl,mc13xxx-uses-adc", NULL))
+               mc13xxx->flags |= MC13XXX_USE_ADC;
+
+       if (of_get_property(np, "fsl,mc13xxx-uses-codec", NULL))
+               mc13xxx->flags |= MC13XXX_USE_CODEC;
+
+       if (of_get_property(np, "fsl,mc13xxx-uses-rtc", NULL))
+               mc13xxx->flags |= MC13XXX_USE_RTC;
+
+       if (of_get_property(np, "fsl,mc13xxx-uses-touch", NULL))
+               mc13xxx->flags |= MC13XXX_USE_TOUCHSCREEN;
+
+       return 0;
+}
+#else
+static inline int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
+{
+       return -ENODEV;
+}
+#endif
+
+static const struct spi_device_id mc13xxx_device_id[] = {
+       {
+               .name = "mc13783",
+               .driver_data = MC13XXX_ID_MC13783,
+       }, {
+               .name = "mc13892",
+               .driver_data = MC13XXX_ID_MC13892,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
+
+static const struct of_device_id mc13xxx_dt_ids[] = {
+       { .compatible = "fsl,mc13783", .data = (void *) MC13XXX_ID_MC13783, },
+       { .compatible = "fsl,mc13892", .data = (void *) MC13XXX_ID_MC13892, },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
+
 static int mc13xxx_probe(struct spi_device *spi)
 {
+       const struct of_device_id *of_id;
+       struct spi_driver *sdrv = to_spi_driver(spi->dev.driver);
        struct mc13xxx *mc13xxx;
        struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
        enum mc13xxx_id id;
        int ret;
 
-       if (!pdata) {
-               dev_err(&spi->dev, "invalid platform data\n");
-               return -EINVAL;
-       }
+       of_id = of_match_device(mc13xxx_dt_ids, &spi->dev);
+       if (of_id)
+               sdrv->id_table = &mc13xxx_device_id[(enum mc13xxx_id) of_id->data];
 
        mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
        if (!mc13xxx)
@@ -749,28 +800,33 @@ err_revision:
 
        mc13xxx_unlock(mc13xxx);
 
-       if (pdata->flags & MC13XXX_USE_ADC)
+       if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata)
+               mc13xxx->flags = pdata->flags;
+
+       if (mc13xxx->flags & MC13XXX_USE_ADC)
                mc13xxx_add_subdevice(mc13xxx, "%s-adc");
 
-       if (pdata->flags & MC13XXX_USE_CODEC)
+       if (mc13xxx->flags & MC13XXX_USE_CODEC)
                mc13xxx_add_subdevice(mc13xxx, "%s-codec");
 
-       mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
-               &pdata->regulators, sizeof(pdata->regulators));
-
-       if (pdata->flags & MC13XXX_USE_RTC)
+       if (mc13xxx->flags & MC13XXX_USE_RTC)
                mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
 
-       if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
+       if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
                mc13xxx_add_subdevice(mc13xxx, "%s-ts");
 
-       if (pdata->leds)
+       if (pdata) {
+               mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
+                       &pdata->regulators, sizeof(pdata->regulators));
                mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
                                pdata->leds, sizeof(*pdata->leds));
-
-       if (pdata->buttons)
                mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton",
                                pdata->buttons, sizeof(*pdata->buttons));
+       } else {
+               mc13xxx_add_subdevice(mc13xxx, "%s-regulator");
+               mc13xxx_add_subdevice(mc13xxx, "%s-led");
+               mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton");
+       }
 
        return 0;
 }
@@ -788,25 +844,12 @@ static int __devexit mc13xxx_remove(struct spi_device *spi)
        return 0;
 }
 
-static const struct spi_device_id mc13xxx_device_id[] = {
-       {
-               .name = "mc13783",
-               .driver_data = MC13XXX_ID_MC13783,
-       }, {
-               .name = "mc13892",
-               .driver_data = MC13XXX_ID_MC13892,
-       }, {
-               /* sentinel */
-       }
-};
-MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
-
 static struct spi_driver mc13xxx_driver = {
        .id_table = mc13xxx_device_id,
        .driver = {
                .name = "mc13xxx",
-               .bus = &spi_bus_type,
                .owner = THIS_MODULE,
+               .of_match_table = mc13xxx_dt_ids,
        },
        .probe = mc13xxx_probe,
        .remove = __devexit_p(mc13xxx_remove),
index 84815f9ef636eb0e91c26c1869094bb5c83977d0..63be60bc3455396e764fa57661f497d5670b04a8 100644 (file)
 #define to_mcp(d)              container_of(d, struct mcp, attached_device)
 #define to_mcp_driver(d)       container_of(d, struct mcp_driver, drv)
 
+static const struct mcp_device_id *mcp_match_id(const struct mcp_device_id *id,
+                                               const char *codec)
+{
+       while (id->name[0]) {
+               if (strcmp(codec, id->name) == 0)
+                       return id;
+               id++;
+       }
+       return NULL;
+}
+
+const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp)
+{
+       const struct mcp_driver *driver =
+               to_mcp_driver(mcp->attached_device.driver);
+
+       return mcp_match_id(driver->id_table, mcp->codec);
+}
+EXPORT_SYMBOL(mcp_get_device_id);
+
 static int mcp_bus_match(struct device *dev, struct device_driver *drv)
 {
-       return 1;
+       const struct mcp *mcp = to_mcp(dev);
+       const struct mcp_driver *driver = to_mcp_driver(drv);
+
+       if (driver->id_table)
+               return !!mcp_match_id(driver->id_table, mcp->codec);
+
+       return 0;
 }
 
 static int mcp_bus_probe(struct device *dev)
@@ -74,9 +100,18 @@ static int mcp_bus_resume(struct device *dev)
        return ret;
 }
 
+static int mcp_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct mcp *mcp = to_mcp(dev);
+
+       add_uevent_var(env, "MODALIAS=%s%s", MCP_MODULE_PREFIX, mcp->codec);
+       return 0;
+}
+
 static struct bus_type mcp_bus_type = {
        .name           = "mcp",
        .match          = mcp_bus_match,
+       .uevent         = mcp_bus_uevent,
        .probe          = mcp_bus_probe,
        .remove         = mcp_bus_remove,
        .suspend        = mcp_bus_suspend,
@@ -212,9 +247,14 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
 }
 EXPORT_SYMBOL(mcp_host_alloc);
 
-int mcp_host_register(struct mcp *mcp)
+int mcp_host_register(struct mcp *mcp, void *pdata)
 {
+       if (!mcp->codec)
+               return -EINVAL;
+
+       mcp->attached_device.platform_data = pdata;
        dev_set_name(&mcp->attached_device, "mcp0");
+       request_module("%s%s", MCP_MODULE_PREFIX, mcp->codec);
        return device_register(&mcp->attached_device);
 }
 EXPORT_SYMBOL(mcp_host_register);
index 2dab02d9ac8b6f87168e3e6e1069023f9372fe93..9adc2eb6949252031b3964320d3e6e1dfa4d4ed0 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/mcp.h>
+#include <linux/io.h>
 
 #include <mach/dma.h>
 #include <mach/hardware.h>
 #include <asm/system.h>
 #include <mach/mcp.h>
 
-#include <mach/assabet.h>
-
+/* Register offsets */
+#define MCCR0  0x00
+#define MCDR0  0x08
+#define MCDR1  0x0C
+#define MCDR2  0x10
+#define MCSR   0x18
+#define MCCR1  0x00
 
 struct mcp_sa11x0 {
-       u32     mccr0;
-       u32     mccr1;
+       u32             mccr0;
+       u32             mccr1;
+       unsigned char   *mccr0_base;
+       unsigned char   *mccr1_base;
 };
 
 #define priv(mcp)      ((struct mcp_sa11x0 *)mcp_priv(mcp))
@@ -39,25 +47,25 @@ struct mcp_sa11x0 {
 static void
 mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
 {
-       unsigned int mccr0;
+       struct mcp_sa11x0 *priv = priv(mcp);
 
        divisor /= 32;
 
-       mccr0 = Ser4MCCR0 & ~0x00007f00;
-       mccr0 |= divisor << 8;
-       Ser4MCCR0 = mccr0;
+       priv->mccr0 &= ~0x00007f00;
+       priv->mccr0 |= divisor << 8;
+       __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
 }
 
 static void
 mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
 {
-       unsigned int mccr0;
+       struct mcp_sa11x0 *priv = priv(mcp);
 
        divisor /= 32;
 
-       mccr0 = Ser4MCCR0 & ~0x0000007f;
-       mccr0 |= divisor;
-       Ser4MCCR0 = mccr0;
+       priv->mccr0 &= ~0x0000007f;
+       priv->mccr0 |= divisor;
+       __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
 }
 
 /*
@@ -71,12 +79,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
 {
        int ret = -ETIME;
        int i;
+       u32 mcpreg;
+       struct mcp_sa11x0 *priv = priv(mcp);
 
-       Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
+       mcpreg = reg << 17 | MCDR2_Wr | (val & 0xffff);
+       __raw_writel(mcpreg, priv->mccr0_base + MCDR2);
 
        for (i = 0; i < 2; i++) {
                udelay(mcp->rw_timeout);
-               if (Ser4MCSR & MCSR_CWC) {
+               mcpreg = __raw_readl(priv->mccr0_base + MCSR);
+               if (mcpreg & MCSR_CWC) {
                        ret = 0;
                        break;
                }
@@ -97,13 +109,18 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
 {
        int ret = -ETIME;
        int i;
+       u32 mcpreg;
+       struct mcp_sa11x0 *priv = priv(mcp);
 
-       Ser4MCDR2 = reg << 17 | MCDR2_Rd;
+       mcpreg = reg << 17 | MCDR2_Rd;
+       __raw_writel(mcpreg, priv->mccr0_base + MCDR2);
 
        for (i = 0; i < 2; i++) {
                udelay(mcp->rw_timeout);
-               if (Ser4MCSR & MCSR_CRC) {
-                       ret = Ser4MCDR2 & 0xffff;
+               mcpreg = __raw_readl(priv->mccr0_base + MCSR);
+               if (mcpreg & MCSR_CRC) {
+                       ret = __raw_readl(priv->mccr0_base + MCDR2)
+                               & 0xffff;
                        break;
                }
        }
@@ -116,13 +133,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
 
 static void mcp_sa11x0_enable(struct mcp *mcp)
 {
-       Ser4MCSR = -1;
-       Ser4MCCR0 |= MCCR0_MCE;
+       struct mcp_sa11x0 *priv = priv(mcp);
+
+       __raw_writel(-1, priv->mccr0_base + MCSR);
+       priv->mccr0 |= MCCR0_MCE;
+       __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
 }
 
 static void mcp_sa11x0_disable(struct mcp *mcp)
 {
-       Ser4MCCR0 &= ~MCCR0_MCE;
+       struct mcp_sa11x0 *priv = priv(mcp);
+
+       priv->mccr0 &= ~MCCR0_MCE;
+       __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
 }
 
 /*
@@ -142,50 +165,69 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
        struct mcp_plat_data *data = pdev->dev.platform_data;
        struct mcp *mcp;
        int ret;
+       struct mcp_sa11x0 *priv;
+       struct resource *res_mem0, *res_mem1;
+       u32 size0, size1;
 
        if (!data)
                return -ENODEV;
 
-       if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
+       if (!data->codec)
+               return -ENODEV;
+
+       res_mem0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res_mem0)
+               return -ENODEV;
+       size0 = res_mem0->end - res_mem0->start + 1;
+
+       res_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res_mem1)
+               return -ENODEV;
+       size1 = res_mem1->end - res_mem1->start + 1;
+
+       if (!request_mem_region(res_mem0->start, size0, "sa11x0-mcp"))
                return -EBUSY;
 
+       if (!request_mem_region(res_mem1->start, size1, "sa11x0-mcp")) {
+               ret = -EBUSY;
+               goto release;
+       }
+
        mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
        if (!mcp) {
                ret = -ENOMEM;
-               goto release;
+               goto release2;
        }
 
+       priv = priv(mcp);
+
        mcp->owner              = THIS_MODULE;
        mcp->ops                = &mcp_sa11x0;
        mcp->sclk_rate          = data->sclk_rate;
-       mcp->dma_audio_rd       = DMA_Ser4MCP0Rd;
-       mcp->dma_audio_wr       = DMA_Ser4MCP0Wr;
-       mcp->dma_telco_rd       = DMA_Ser4MCP1Rd;
-       mcp->dma_telco_wr       = DMA_Ser4MCP1Wr;
-       mcp->gpio_base          = data->gpio_base;
+       mcp->dma_audio_rd       = DDAR_DevAdd(res_mem0->start + MCDR0)
+                               + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
+       mcp->dma_audio_wr       = DDAR_DevAdd(res_mem0->start + MCDR0)
+                               + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
+       mcp->dma_telco_rd       = DDAR_DevAdd(res_mem0->start + MCDR1)
+                               + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
+       mcp->dma_telco_wr       = DDAR_DevAdd(res_mem0->start + MCDR1)
+                               + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
+       mcp->codec              = data->codec;
 
        platform_set_drvdata(pdev, mcp);
 
-       if (machine_is_assabet()) {
-               ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
-       }
-
-       /*
-        * Setup the PPC unit correctly.
-        */
-       PPDR &= ~PPC_RXD4;
-       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
-       PSDR |= PPC_RXD4;
-       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
-       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
-
        /*
         * Initialise device.  Note that we initially
         * set the sampling rate to minimum.
         */
-       Ser4MCSR = -1;
-       Ser4MCCR1 = data->mccr1;
-       Ser4MCCR0 = data->mccr0 | 0x7f7f;
+       priv->mccr0_base = ioremap(res_mem0->start, size0);
+       priv->mccr1_base = ioremap(res_mem1->start, size1);
+
+       __raw_writel(-1, priv->mccr0_base + MCSR);
+       priv->mccr1 = data->mccr1;
+       priv->mccr0 = data->mccr0 | 0x7f7f;
+       __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+       __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
 
        /*
         * Calculate the read/write timeout (us) from the bit clock
@@ -195,36 +237,53 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
        mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
                          mcp->sclk_rate;
 
-       ret = mcp_host_register(mcp);
+       ret = mcp_host_register(mcp, data->codec_pdata);
        if (ret == 0)
                goto out;
 
+ release2:
+       release_mem_region(res_mem1->start, size1);
  release:
-       release_mem_region(0x80060000, 0x60);
+       release_mem_region(res_mem0->start, size0);
        platform_set_drvdata(pdev, NULL);
 
  out:
        return ret;
 }
 
-static int mcp_sa11x0_remove(struct platform_device *dev)
+static int mcp_sa11x0_remove(struct platform_device *pdev)
 {
-       struct mcp *mcp = platform_get_drvdata(dev);
+       struct mcp *mcp = platform_get_drvdata(pdev);
+       struct mcp_sa11x0 *priv = priv(mcp);
+       struct resource *res_mem;
+       u32 size;
 
-       platform_set_drvdata(dev, NULL);
+       platform_set_drvdata(pdev, NULL);
        mcp_host_unregister(mcp);
-       release_mem_region(0x80060000, 0x60);
 
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res_mem) {
+               size = res_mem->end - res_mem->start + 1;
+               release_mem_region(res_mem->start, size);
+       }
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res_mem) {
+               size = res_mem->end - res_mem->start + 1;
+               release_mem_region(res_mem->start, size);
+       }
+       iounmap(priv->mccr0_base);
+       iounmap(priv->mccr1_base);
        return 0;
 }
 
 static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
 {
        struct mcp *mcp = platform_get_drvdata(dev);
+       struct mcp_sa11x0 *priv = priv(mcp);
+       u32 mccr0;
 
-       priv(mcp)->mccr0 = Ser4MCCR0;
-       priv(mcp)->mccr1 = Ser4MCCR1;
-       Ser4MCCR0 &= ~MCCR0_MCE;
+       mccr0 = priv->mccr0 & ~MCCR0_MCE;
+       __raw_writel(mccr0, priv->mccr0_base + MCCR0);
 
        return 0;
 }
@@ -232,9 +291,10 @@ static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
 static int mcp_sa11x0_resume(struct platform_device *dev)
 {
        struct mcp *mcp = platform_get_drvdata(dev);
+       struct mcp_sa11x0 *priv = priv(mcp);
 
-       Ser4MCCR1 = priv(mcp)->mccr1;
-       Ser4MCCR0 = priv(mcp)->mccr0;
+       __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+       __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
 
        return 0;
 }
@@ -251,24 +311,14 @@ static struct platform_driver mcp_sa11x0_driver = {
        .resume         = mcp_sa11x0_resume,
        .driver         = {
                .name   = "sa11x0-mcp",
+               .owner  = THIS_MODULE,
        },
 };
 
 /*
  * This needs re-working
  */
-static int __init mcp_sa11x0_init(void)
-{
-       return platform_driver_register(&mcp_sa11x0_driver);
-}
-
-static void __exit mcp_sa11x0_exit(void)
-{
-       platform_driver_unregister(&mcp_sa11x0_driver);
-}
-
-module_init(mcp_sa11x0_init);
-module_exit(mcp_sa11x0_exit);
+module_platform_driver(mcp_sa11x0_driver);
 
 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
index 3f565ef3e149438c86a0054f354627231a2258b2..68ac2c55d5ae0bb1381c0681b641846079345f54 100644 (file)
@@ -503,19 +503,13 @@ static void omap_usbhs_init(struct device *dev)
        spin_lock_irqsave(&omap->lock, flags);
 
        if (pdata->ehci_data->phy_reset) {
-               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) {
-                       gpio_request(pdata->ehci_data->reset_gpio_port[0],
-                                               "USB1 PHY reset");
-                       gpio_direction_output
-                               (pdata->ehci_data->reset_gpio_port[0], 0);
-               }
+               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
+                       gpio_request_one(pdata->ehci_data->reset_gpio_port[0],
+                                        GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
 
-               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) {
-                       gpio_request(pdata->ehci_data->reset_gpio_port[1],
-                                               "USB2 PHY reset");
-                       gpio_direction_output
-                               (pdata->ehci_data->reset_gpio_port[1], 0);
-               }
+               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
+                       gpio_request_one(pdata->ehci_data->reset_gpio_port[1],
+                                        GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
 
                /* Hold the PHY in RESET for enough time till DIR is high */
                udelay(10);
index aed0d2a9b032e0b3e5babe7949037df19470e1c7..3927c17e4175d9cd4bc28b9c756286a7f1b4efd4 100644 (file)
@@ -249,17 +249,7 @@ static struct platform_driver pcf50633_adc_driver = {
        .remove = __devexit_p(pcf50633_adc_remove),
 };
 
-static int __init pcf50633_adc_init(void)
-{
-       return platform_driver_register(&pcf50633_adc_driver);
-}
-module_init(pcf50633_adc_init);
-
-static void __exit pcf50633_adc_exit(void)
-{
-       platform_driver_unregister(&pcf50633_adc_driver);
-}
-module_exit(pcf50633_adc_exit);
+module_platform_driver(pcf50633_adc_driver);
 
 MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
 MODULE_DESCRIPTION("PCF50633 adc driver");
diff --git a/drivers/mfd/s5m-core.c b/drivers/mfd/s5m-core.c
new file mode 100644 (file)
index 0000000..e075c11
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * s5m87xx.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License 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/moduleparam.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/mutex.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/s5m87xx/s5m-core.h>
+#include <linux/mfd/s5m87xx/s5m-pmic.h>
+#include <linux/mfd/s5m87xx/s5m-rtc.h>
+#include <linux/regmap.h>
+
+static struct mfd_cell s5m87xx_devs[] = {
+       {
+               .name = "s5m8767-pmic",
+       }, {
+               .name = "s5m-rtc",
+       },
+};
+
+int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest)
+{
+       return regmap_read(s5m87xx->regmap, reg, dest);
+}
+EXPORT_SYMBOL_GPL(s5m_reg_read);
+
+int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
+{
+       return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);;
+}
+EXPORT_SYMBOL_GPL(s5m_bulk_read);
+
+int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value)
+{
+       return regmap_write(s5m87xx->regmap, reg, value);
+}
+EXPORT_SYMBOL_GPL(s5m_reg_write);
+
+int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
+{
+       return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16));
+}
+EXPORT_SYMBOL_GPL(s5m_bulk_write);
+
+int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask)
+{
+       return regmap_update_bits(s5m87xx->regmap, reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(s5m_reg_update);
+
+static struct regmap_config s5m_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int s5m87xx_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct s5m_platform_data *pdata = i2c->dev.platform_data;
+       struct s5m87xx_dev *s5m87xx;
+       int ret = 0;
+       int error;
+
+       s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL);
+       if (s5m87xx == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, s5m87xx);
+       s5m87xx->dev = &i2c->dev;
+       s5m87xx->i2c = i2c;
+       s5m87xx->irq = i2c->irq;
+       s5m87xx->type = id->driver_data;
+
+       if (pdata) {
+               s5m87xx->device_type = pdata->device_type;
+               s5m87xx->ono = pdata->ono;
+               s5m87xx->irq_base = pdata->irq_base;
+               s5m87xx->wakeup = pdata->wakeup;
+       }
+
+       s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
+       if (IS_ERR(s5m87xx->regmap)) {
+               error = PTR_ERR(s5m87xx->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       error);
+               goto err;
+       }
+
+       s5m87xx->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
+       i2c_set_clientdata(s5m87xx->rtc, s5m87xx);
+
+       if (pdata->cfg_pmic_irq)
+               pdata->cfg_pmic_irq();
+
+       s5m_irq_init(s5m87xx);
+
+       pm_runtime_set_active(s5m87xx->dev);
+
+       ret = mfd_add_devices(s5m87xx->dev, -1,
+                               s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs),
+                               NULL, 0);
+
+       if (ret < 0)
+               goto err;
+
+       return ret;
+
+err:
+       mfd_remove_devices(s5m87xx->dev);
+       s5m_irq_exit(s5m87xx);
+       i2c_unregister_device(s5m87xx->rtc);
+       regmap_exit(s5m87xx->regmap);
+       kfree(s5m87xx);
+       return ret;
+}
+
+static int s5m87xx_i2c_remove(struct i2c_client *i2c)
+{
+       struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
+
+       mfd_remove_devices(s5m87xx->dev);
+       s5m_irq_exit(s5m87xx);
+       i2c_unregister_device(s5m87xx->rtc);
+       regmap_exit(s5m87xx->regmap);
+       kfree(s5m87xx);
+       return 0;
+}
+
+static const struct i2c_device_id s5m87xx_i2c_id[] = {
+       { "s5m87xx", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, s5m87xx_i2c_id);
+
+static struct i2c_driver s5m87xx_i2c_driver = {
+       .driver = {
+                  .name = "s5m87xx",
+                  .owner = THIS_MODULE,
+       },
+       .probe = s5m87xx_i2c_probe,
+       .remove = s5m87xx_i2c_remove,
+       .id_table = s5m87xx_i2c_id,
+};
+
+static int __init s5m87xx_i2c_init(void)
+{
+       return i2c_add_driver(&s5m87xx_i2c_driver);
+}
+
+subsys_initcall(s5m87xx_i2c_init);
+
+static void __exit s5m87xx_i2c_exit(void)
+{
+       i2c_del_driver(&s5m87xx_i2c_driver);
+}
+module_exit(s5m87xx_i2c_exit);
+
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_DESCRIPTION("Core support for the S5M MFD");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/s5m-irq.c b/drivers/mfd/s5m-irq.c
new file mode 100644 (file)
index 0000000..de76dfb
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * s5m-irq.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mfd/s5m87xx/s5m-core.h>
+
+struct s5m_irq_data {
+       int reg;
+       int mask;
+};
+
+static struct s5m_irq_data s5m8767_irqs[] = {
+       [S5M8767_IRQ_PWRR] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_PWRR_MASK,
+       },
+       [S5M8767_IRQ_PWRF] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_PWRF_MASK,
+       },
+       [S5M8767_IRQ_PWR1S] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_PWR1S_MASK,
+       },
+       [S5M8767_IRQ_JIGR] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_JIGR_MASK,
+       },
+       [S5M8767_IRQ_JIGF] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_JIGF_MASK,
+       },
+       [S5M8767_IRQ_LOWBAT2] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_LOWBAT2_MASK,
+       },
+       [S5M8767_IRQ_LOWBAT1] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_LOWBAT1_MASK,
+       },
+       [S5M8767_IRQ_MRB] = {
+               .reg = 2,
+               .mask = S5M8767_IRQ_MRB_MASK,
+       },
+       [S5M8767_IRQ_DVSOK2] = {
+               .reg = 2,
+               .mask = S5M8767_IRQ_DVSOK2_MASK,
+       },
+       [S5M8767_IRQ_DVSOK3] = {
+               .reg = 2,
+               .mask = S5M8767_IRQ_DVSOK3_MASK,
+       },
+       [S5M8767_IRQ_DVSOK4] = {
+               .reg = 2,
+               .mask = S5M8767_IRQ_DVSOK4_MASK,
+       },
+       [S5M8767_IRQ_RTC60S] = {
+               .reg = 3,
+               .mask = S5M8767_IRQ_RTC60S_MASK,
+       },
+       [S5M8767_IRQ_RTCA1] = {
+               .reg = 3,
+               .mask = S5M8767_IRQ_RTCA1_MASK,
+       },
+       [S5M8767_IRQ_RTCA2] = {
+               .reg = 3,
+               .mask = S5M8767_IRQ_RTCA2_MASK,
+       },
+       [S5M8767_IRQ_SMPL] = {
+               .reg = 3,
+               .mask = S5M8767_IRQ_SMPL_MASK,
+       },
+       [S5M8767_IRQ_RTC1S] = {
+               .reg = 3,
+               .mask = S5M8767_IRQ_RTC1S_MASK,
+       },
+       [S5M8767_IRQ_WTSR] = {
+               .reg = 3,
+               .mask = S5M8767_IRQ_WTSR_MASK,
+       },
+};
+
+static struct s5m_irq_data s5m8763_irqs[] = {
+       [S5M8763_IRQ_DCINF] = {
+               .reg = 1,
+               .mask = S5M8763_IRQ_DCINF_MASK,
+       },
+       [S5M8763_IRQ_DCINR] = {
+               .reg = 1,
+               .mask = S5M8763_IRQ_DCINR_MASK,
+       },
+       [S5M8763_IRQ_JIGF] = {
+               .reg = 1,
+               .mask = S5M8763_IRQ_JIGF_MASK,
+       },
+       [S5M8763_IRQ_JIGR] = {
+               .reg = 1,
+               .mask = S5M8763_IRQ_JIGR_MASK,
+       },
+       [S5M8763_IRQ_PWRONF] = {
+               .reg = 1,
+               .mask = S5M8763_IRQ_PWRONF_MASK,
+       },
+       [S5M8763_IRQ_PWRONR] = {
+               .reg = 1,
+               .mask = S5M8763_IRQ_PWRONR_MASK,
+       },
+       [S5M8763_IRQ_WTSREVNT] = {
+               .reg = 2,
+               .mask = S5M8763_IRQ_WTSREVNT_MASK,
+       },
+       [S5M8763_IRQ_SMPLEVNT] = {
+               .reg = 2,
+               .mask = S5M8763_IRQ_SMPLEVNT_MASK,
+       },
+       [S5M8763_IRQ_ALARM1] = {
+               .reg = 2,
+               .mask = S5M8763_IRQ_ALARM1_MASK,
+       },
+       [S5M8763_IRQ_ALARM0] = {
+               .reg = 2,
+               .mask = S5M8763_IRQ_ALARM0_MASK,
+       },
+       [S5M8763_IRQ_ONKEY1S] = {
+               .reg = 3,
+               .mask = S5M8763_IRQ_ONKEY1S_MASK,
+       },
+       [S5M8763_IRQ_TOPOFFR] = {
+               .reg = 3,
+               .mask = S5M8763_IRQ_TOPOFFR_MASK,
+       },
+       [S5M8763_IRQ_DCINOVPR] = {
+               .reg = 3,
+               .mask = S5M8763_IRQ_DCINOVPR_MASK,
+       },
+       [S5M8763_IRQ_CHGRSTF] = {
+               .reg = 3,
+               .mask = S5M8763_IRQ_CHGRSTF_MASK,
+       },
+       [S5M8763_IRQ_DONER] = {
+               .reg = 3,
+               .mask = S5M8763_IRQ_DONER_MASK,
+       },
+       [S5M8763_IRQ_CHGFAULT] = {
+               .reg = 3,
+               .mask = S5M8763_IRQ_CHGFAULT_MASK,
+       },
+       [S5M8763_IRQ_LOBAT1] = {
+               .reg = 4,
+               .mask = S5M8763_IRQ_LOBAT1_MASK,
+       },
+       [S5M8763_IRQ_LOBAT2] = {
+               .reg = 4,
+               .mask = S5M8763_IRQ_LOBAT2_MASK,
+       },
+};
+
+static inline struct s5m_irq_data *
+irq_to_s5m8767_irq(struct s5m87xx_dev *s5m87xx, int irq)
+{
+       return &s5m8767_irqs[irq - s5m87xx->irq_base];
+}
+
+static void s5m8767_irq_lock(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&s5m87xx->irqlock);
+}
+
+static void s5m8767_irq_sync_unlock(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
+               if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
+                       s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
+                       s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i,
+                                       s5m87xx->irq_masks_cur[i]);
+               }
+       }
+
+       mutex_unlock(&s5m87xx->irqlock);
+}
+
+static void s5m8767_irq_unmask(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+       struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
+                                                              data->irq);
+
+       s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
+}
+
+static void s5m8767_irq_mask(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+       struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
+                                                              data->irq);
+
+       s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
+}
+
+static struct irq_chip s5m8767_irq_chip = {
+       .name = "s5m8767",
+       .irq_bus_lock = s5m8767_irq_lock,
+       .irq_bus_sync_unlock = s5m8767_irq_sync_unlock,
+       .irq_mask = s5m8767_irq_mask,
+       .irq_unmask = s5m8767_irq_unmask,
+};
+
+static inline struct s5m_irq_data *
+irq_to_s5m8763_irq(struct s5m87xx_dev *s5m87xx, int irq)
+{
+       return &s5m8763_irqs[irq - s5m87xx->irq_base];
+}
+
+static void s5m8763_irq_lock(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&s5m87xx->irqlock);
+}
+
+static void s5m8763_irq_sync_unlock(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
+               if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
+                       s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
+                       s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i,
+                                       s5m87xx->irq_masks_cur[i]);
+               }
+       }
+
+       mutex_unlock(&s5m87xx->irqlock);
+}
+
+static void s5m8763_irq_unmask(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+       struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
+                                                              data->irq);
+
+       s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
+}
+
+static void s5m8763_irq_mask(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+       struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
+                                                              data->irq);
+
+       s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
+}
+
+static struct irq_chip s5m8763_irq_chip = {
+       .name = "s5m8763",
+       .irq_bus_lock = s5m8763_irq_lock,
+       .irq_bus_sync_unlock = s5m8763_irq_sync_unlock,
+       .irq_mask = s5m8763_irq_mask,
+       .irq_unmask = s5m8763_irq_unmask,
+};
+
+
+static irqreturn_t s5m8767_irq_thread(int irq, void *data)
+{
+       struct s5m87xx_dev *s5m87xx = data;
+       u8 irq_reg[NUM_IRQ_REGS-1];
+       int ret;
+       int i;
+
+
+       ret = s5m_bulk_read(s5m87xx, S5M8767_REG_INT1,
+                               NUM_IRQ_REGS - 1, irq_reg);
+       if (ret < 0) {
+               dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
+                               ret);
+               return IRQ_NONE;
+       }
+
+       for (i = 0; i < NUM_IRQ_REGS - 1; i++)
+               irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
+
+       for (i = 0; i < S5M8767_IRQ_NR; i++) {
+               if (irq_reg[s5m8767_irqs[i].reg - 1] & s5m8767_irqs[i].mask)
+                       handle_nested_irq(s5m87xx->irq_base + i);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t s5m8763_irq_thread(int irq, void *data)
+{
+       struct s5m87xx_dev *s5m87xx = data;
+       u8 irq_reg[NUM_IRQ_REGS];
+       int ret;
+       int i;
+
+       ret = s5m_bulk_read(s5m87xx, S5M8763_REG_IRQ1,
+                               NUM_IRQ_REGS, irq_reg);
+       if (ret < 0) {
+               dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
+                               ret);
+               return IRQ_NONE;
+       }
+
+       for (i = 0; i < NUM_IRQ_REGS; i++)
+               irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
+
+       for (i = 0; i < S5M8763_IRQ_NR; i++) {
+               if (irq_reg[s5m8763_irqs[i].reg - 1] & s5m8763_irqs[i].mask)
+                       handle_nested_irq(s5m87xx->irq_base + i);
+       }
+
+       return IRQ_HANDLED;
+}
+
+int s5m_irq_resume(struct s5m87xx_dev *s5m87xx)
+{
+       if (s5m87xx->irq && s5m87xx->irq_base){
+               switch (s5m87xx->device_type) {
+               case S5M8763X:
+                       s5m8763_irq_thread(s5m87xx->irq_base, s5m87xx);
+                       break;
+               case S5M8767X:
+                       s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
+                       break;
+               default:
+                       break;
+
+               }
+       }
+       return 0;
+}
+
+int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
+{
+       int i;
+       int cur_irq;
+       int ret = 0;
+       int type = s5m87xx->device_type;
+
+       if (!s5m87xx->irq) {
+               dev_warn(s5m87xx->dev,
+                        "No interrupt specified, no interrupts\n");
+               s5m87xx->irq_base = 0;
+               return 0;
+       }
+
+       if (!s5m87xx->irq_base) {
+               dev_err(s5m87xx->dev,
+                       "No interrupt base specified, no interrupts\n");
+               return 0;
+       }
+
+       mutex_init(&s5m87xx->irqlock);
+
+       switch (type) {
+       case S5M8763X:
+               for (i = 0; i < NUM_IRQ_REGS; i++) {
+                       s5m87xx->irq_masks_cur[i] = 0xff;
+                       s5m87xx->irq_masks_cache[i] = 0xff;
+                       s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i,
+                                               0xff);
+               }
+
+               s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM1, 0xff);
+               s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM2, 0xff);
+
+               for (i = 0; i < S5M8763_IRQ_NR; i++) {
+                       cur_irq = i + s5m87xx->irq_base;
+                       irq_set_chip_data(cur_irq, s5m87xx);
+                       irq_set_chip_and_handler(cur_irq, &s5m8763_irq_chip,
+                                                handle_edge_irq);
+                       irq_set_nested_thread(cur_irq, 1);
+#ifdef CONFIG_ARM
+                       set_irq_flags(cur_irq, IRQF_VALID);
+#else
+                       irq_set_noprobe(cur_irq);
+#endif
+               }
+
+               ret = request_threaded_irq(s5m87xx->irq, NULL,
+                                       s5m8763_irq_thread,
+                                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                       "s5m87xx-irq", s5m87xx);
+               if (ret) {
+                       dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
+                               s5m87xx->irq, ret);
+                       return ret;
+               }
+               break;
+       case S5M8767X:
+               for (i = 0; i < NUM_IRQ_REGS - 1; i++) {
+                       s5m87xx->irq_masks_cur[i] = 0xff;
+                       s5m87xx->irq_masks_cache[i] = 0xff;
+                       s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i,
+                                               0xff);
+               }
+               for (i = 0; i < S5M8767_IRQ_NR; i++) {
+                       cur_irq = i + s5m87xx->irq_base;
+                       irq_set_chip_data(cur_irq, s5m87xx);
+                       if (ret) {
+                               dev_err(s5m87xx->dev,
+                                       "Failed to irq_set_chip_data %d: %d\n",
+                                       s5m87xx->irq, ret);
+                               return ret;
+                       }
+
+                       irq_set_chip_and_handler(cur_irq, &s5m8767_irq_chip,
+                                                handle_edge_irq);
+                       irq_set_nested_thread(cur_irq, 1);
+#ifdef CONFIG_ARM
+                       set_irq_flags(cur_irq, IRQF_VALID);
+#else
+                       irq_set_noprobe(cur_irq);
+#endif
+               }
+
+               ret = request_threaded_irq(s5m87xx->irq, NULL,
+                                          s5m8767_irq_thread,
+                                          IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                          "s5m87xx-irq", s5m87xx);
+               if (ret) {
+                       dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
+                               s5m87xx->irq, ret);
+                       return ret;
+               }
+               break;
+       default:
+               break;
+       }
+
+       if (!s5m87xx->ono)
+               return 0;
+
+       switch (type) {
+       case S5M8763X:
+               ret = request_threaded_irq(s5m87xx->ono, NULL,
+                                               s5m8763_irq_thread,
+                                               IRQF_TRIGGER_FALLING |
+                                               IRQF_TRIGGER_RISING |
+                                               IRQF_ONESHOT, "s5m87xx-ono",
+                                               s5m87xx);
+               break;
+       case S5M8767X:
+               ret = request_threaded_irq(s5m87xx->ono, NULL,
+                                       s5m8767_irq_thread,
+                                       IRQF_TRIGGER_FALLING |
+                                       IRQF_TRIGGER_RISING |
+                                       IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
+               break;
+       default:
+               break;
+       }
+
+       if (ret)
+               dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
+                       s5m87xx->ono, ret);
+
+       return 0;
+}
+
+void s5m_irq_exit(struct s5m87xx_dev *s5m87xx)
+{
+       if (s5m87xx->ono)
+               free_irq(s5m87xx->ono, s5m87xx);
+
+       if (s5m87xx->irq)
+               free_irq(s5m87xx->irq, s5m87xx);
+}
index df3702c1756df9aae08dcfbbf1bde345d7520172..f4d86117f44a21bcc140e93b8fd116798d6d5054 100644 (file)
@@ -1720,7 +1720,7 @@ static int sm501_plat_remove(struct platform_device *dev)
        return 0;
 }
 
-static struct pci_device_id sm501_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(sm501_pci_tbl) = {
        { 0x126f, 0x0501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { 0, },
 };
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c
new file mode 100644 (file)
index 0000000..373f423
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * ST Microelectronics MFD: stmpe's i2c client specific driver
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Copyright (C) ST Microelectronics SA 2011
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * Author: Viresh Kumar <viresh.kumar@st.com> for ST Microelectronics
+ */
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include "stmpe.h"
+
+static int i2c_reg_read(struct stmpe *stmpe, u8 reg)
+{
+       struct i2c_client *i2c = stmpe->client;
+
+       return i2c_smbus_read_byte_data(i2c, reg);
+}
+
+static int i2c_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
+{
+       struct i2c_client *i2c = stmpe->client;
+
+       return i2c_smbus_write_byte_data(i2c, reg, val);
+}
+
+static int i2c_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values)
+{
+       struct i2c_client *i2c = stmpe->client;
+
+       return i2c_smbus_read_i2c_block_data(i2c, reg, length, values);
+}
+
+static int i2c_block_write(struct stmpe *stmpe, u8 reg, u8 length,
+               const u8 *values)
+{
+       struct i2c_client *i2c = stmpe->client;
+
+       return i2c_smbus_write_i2c_block_data(i2c, reg, length, values);
+}
+
+static struct stmpe_client_info i2c_ci = {
+       .read_byte = i2c_reg_read,
+       .write_byte = i2c_reg_write,
+       .read_block = i2c_block_read,
+       .write_block = i2c_block_write,
+};
+
+static int __devinit
+stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+       i2c_ci.data = (void *)id;
+       i2c_ci.irq = i2c->irq;
+       i2c_ci.client = i2c;
+       i2c_ci.dev = &i2c->dev;
+
+       return stmpe_probe(&i2c_ci, id->driver_data);
+}
+
+static int __devexit stmpe_i2c_remove(struct i2c_client *i2c)
+{
+       struct stmpe *stmpe = dev_get_drvdata(&i2c->dev);
+
+       return stmpe_remove(stmpe);
+}
+
+static const struct i2c_device_id stmpe_i2c_id[] = {
+       { "stmpe610", STMPE610 },
+       { "stmpe801", STMPE801 },
+       { "stmpe811", STMPE811 },
+       { "stmpe1601", STMPE1601 },
+       { "stmpe2401", STMPE2401 },
+       { "stmpe2403", STMPE2403 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, stmpe_id);
+
+static struct i2c_driver stmpe_i2c_driver = {
+       .driver.name    = "stmpe-i2c",
+       .driver.owner   = THIS_MODULE,
+#ifdef CONFIG_PM
+       .driver.pm      = &stmpe_dev_pm_ops,
+#endif
+       .probe          = stmpe_i2c_probe,
+       .remove         = __devexit_p(stmpe_i2c_remove),
+       .id_table       = stmpe_i2c_id,
+};
+
+static int __init stmpe_init(void)
+{
+       return i2c_add_driver(&stmpe_i2c_driver);
+}
+subsys_initcall(stmpe_init);
+
+static void __exit stmpe_exit(void)
+{
+       i2c_del_driver(&stmpe_i2c_driver);
+}
+module_exit(stmpe_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("STMPE MFD I2C Interface Driver");
+MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c
new file mode 100644 (file)
index 0000000..b58c43c
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * ST Microelectronics MFD: stmpe's spi client specific driver
+ *
+ * Copyright (C) ST Microelectronics SA 2011
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Viresh Kumar <viresh.kumar@st.com> for ST Microelectronics
+ */
+
+#include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include "stmpe.h"
+
+#define READ_CMD       (1 << 7)
+
+static int spi_reg_read(struct stmpe *stmpe, u8 reg)
+{
+       struct spi_device *spi = stmpe->client;
+       int status = spi_w8r16(spi, reg | READ_CMD);
+
+       return (status < 0) ? status : status >> 8;
+}
+
+static int spi_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
+{
+       struct spi_device *spi = stmpe->client;
+       u16 cmd = (val << 8) | reg;
+
+       return spi_write(spi, (const u8 *)&cmd, 2);
+}
+
+static int spi_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values)
+{
+       int ret, i;
+
+       for (i = 0; i < length; i++) {
+               ret = spi_reg_read(stmpe, reg + i);
+               if (ret < 0)
+                       return ret;
+               *(values + i) = ret;
+       }
+
+       return 0;
+}
+
+static int spi_block_write(struct stmpe *stmpe, u8 reg, u8 length,
+               const u8 *values)
+{
+       int ret = 0, i;
+
+       for (i = length; i > 0; i--, reg++) {
+               ret = spi_reg_write(stmpe, reg, *(values + i - 1));
+               if (ret < 0)
+                       return ret;
+       }
+
+       return ret;
+}
+
+static void spi_init(struct stmpe *stmpe)
+{
+       struct spi_device *spi = stmpe->client;
+
+       spi->bits_per_word = 8;
+
+       /* This register is only present for stmpe811 */
+       if (stmpe->variant->id_val == 0x0811)
+               spi_reg_write(stmpe, STMPE811_REG_SPI_CFG, spi->mode);
+
+       if (spi_setup(spi) < 0)
+               dev_dbg(&spi->dev, "spi_setup failed\n");
+}
+
+static struct stmpe_client_info spi_ci = {
+       .read_byte = spi_reg_read,
+       .write_byte = spi_reg_write,
+       .read_block = spi_block_read,
+       .write_block = spi_block_write,
+       .init = spi_init,
+};
+
+static int __devinit
+stmpe_spi_probe(struct spi_device *spi)
+{
+       const struct spi_device_id *id = spi_get_device_id(spi);
+
+       /* don't exceed max specified rate - 1MHz - Limitation of STMPE */
+       if (spi->max_speed_hz > 1000000) {
+               dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
+                               (spi->max_speed_hz/1000));
+               return -EINVAL;
+       }
+
+       spi_ci.irq = spi->irq;
+       spi_ci.client = spi;
+       spi_ci.dev = &spi->dev;
+
+       return stmpe_probe(&spi_ci, id->driver_data);
+}
+
+static int __devexit stmpe_spi_remove(struct spi_device *spi)
+{
+       struct stmpe *stmpe = dev_get_drvdata(&spi->dev);
+
+       return stmpe_remove(stmpe);
+}
+
+static const struct spi_device_id stmpe_spi_id[] = {
+       { "stmpe610", STMPE610 },
+       { "stmpe801", STMPE801 },
+       { "stmpe811", STMPE811 },
+       { "stmpe1601", STMPE1601 },
+       { "stmpe2401", STMPE2401 },
+       { "stmpe2403", STMPE2403 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, stmpe_id);
+
+static struct spi_driver stmpe_spi_driver = {
+       .driver = {
+               .name   = "stmpe-spi",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &stmpe_dev_pm_ops,
+#endif
+       },
+       .probe          = stmpe_spi_probe,
+       .remove         = __devexit_p(stmpe_spi_remove),
+       .id_table       = stmpe_spi_id,
+};
+
+static int __init stmpe_init(void)
+{
+       return spi_register_driver(&stmpe_spi_driver);
+}
+subsys_initcall(stmpe_init);
+
+static void __exit stmpe_exit(void)
+{
+       spi_unregister_driver(&stmpe_spi_driver);
+}
+module_exit(stmpe_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("STMPE MFD SPI Interface Driver");
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
index 2963689cf45c2c93dcd56e56fea26b0b4debdf92..e07947e56b2a0e2bd68d5aa7da434ae6aa5ed878 100644 (file)
@@ -1,18 +1,20 @@
 /*
+ * ST Microelectronics MFD: stmpe's driver
+ *
  * Copyright (C) ST-Ericsson SA 2010
  *
  * License Terms: GNU General Public License, version 2
  * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
  */
 
+#include <linux/gpio.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/pm.h>
 #include <linux/slab.h>
-#include <linux/i2c.h>
 #include <linux/mfd/core.h>
-#include <linux/mfd/stmpe.h>
 #include "stmpe.h"
 
 static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
@@ -29,10 +31,9 @@ static int __stmpe_reg_read(struct stmpe *stmpe, u8 reg)
 {
        int ret;
 
-       ret = i2c_smbus_read_byte_data(stmpe->i2c, reg);
+       ret = stmpe->ci->read_byte(stmpe, reg);
        if (ret < 0)
-               dev_err(stmpe->dev, "failed to read reg %#x: %d\n",
-                       reg, ret);
+               dev_err(stmpe->dev, "failed to read reg %#x: %d\n", reg, ret);
 
        dev_vdbg(stmpe->dev, "rd: reg %#x => data %#x\n", reg, ret);
 
@@ -45,10 +46,9 @@ static int __stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
 
        dev_vdbg(stmpe->dev, "wr: reg %#x <= %#x\n", reg, val);
 
-       ret = i2c_smbus_write_byte_data(stmpe->i2c, reg, val);
+       ret = stmpe->ci->write_byte(stmpe, reg, val);
        if (ret < 0)
-               dev_err(stmpe->dev, "failed to write reg %#x: %d\n",
-                       reg, ret);
+               dev_err(stmpe->dev, "failed to write reg %#x: %d\n", reg, ret);
 
        return ret;
 }
@@ -72,10 +72,9 @@ static int __stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length,
 {
        int ret;
 
-       ret = i2c_smbus_read_i2c_block_data(stmpe->i2c, reg, length, values);
+       ret = stmpe->ci->read_block(stmpe, reg, length, values);
        if (ret < 0)
-               dev_err(stmpe->dev, "failed to read regs %#x: %d\n",
-                       reg, ret);
+               dev_err(stmpe->dev, "failed to read regs %#x: %d\n", reg, ret);
 
        dev_vdbg(stmpe->dev, "rd: reg %#x (%d) => ret %#x\n", reg, length, ret);
        stmpe_dump_bytes("stmpe rd: ", values, length);
@@ -91,11 +90,9 @@ static int __stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
        dev_vdbg(stmpe->dev, "wr: regs %#x (%d)\n", reg, length);
        stmpe_dump_bytes("stmpe wr: ", values, length);
 
-       ret = i2c_smbus_write_i2c_block_data(stmpe->i2c, reg, length,
-                                            values);
+       ret = stmpe->ci->write_block(stmpe, reg, length, values);
        if (ret < 0)
-               dev_err(stmpe->dev, "failed to write regs %#x: %d\n",
-                       reg, ret);
+               dev_err(stmpe->dev, "failed to write regs %#x: %d\n", reg, ret);
 
        return ret;
 }
@@ -245,12 +242,14 @@ int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins, enum stmpe_block block)
        u8 regaddr = stmpe->regs[STMPE_IDX_GPAFR_U_MSB];
        int af_bits = variant->af_bits;
        int numregs = DIV_ROUND_UP(stmpe->num_gpios * af_bits, 8);
-       int afperreg = 8 / af_bits;
        int mask = (1 << af_bits) - 1;
        u8 regs[numregs];
-       int af;
-       int ret;
+       int af, afperreg, ret;
+
+       if (!variant->get_altfunc)
+               return 0;
 
+       afperreg = 8 / af_bits;
        mutex_lock(&stmpe->lock);
 
        ret = __stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
@@ -325,7 +324,51 @@ static struct mfd_cell stmpe_keypad_cell = {
 };
 
 /*
- * Touchscreen (STMPE811)
+ * STMPE801
+ */
+static const u8 stmpe801_regs[] = {
+       [STMPE_IDX_CHIP_ID]     = STMPE801_REG_CHIP_ID,
+       [STMPE_IDX_ICR_LSB]     = STMPE801_REG_SYS_CTRL,
+       [STMPE_IDX_GPMR_LSB]    = STMPE801_REG_GPIO_MP_STA,
+       [STMPE_IDX_GPSR_LSB]    = STMPE801_REG_GPIO_SET_PIN,
+       [STMPE_IDX_GPCR_LSB]    = STMPE801_REG_GPIO_SET_PIN,
+       [STMPE_IDX_GPDR_LSB]    = STMPE801_REG_GPIO_DIR,
+       [STMPE_IDX_IEGPIOR_LSB] = STMPE801_REG_GPIO_INT_EN,
+       [STMPE_IDX_ISGPIOR_MSB] = STMPE801_REG_GPIO_INT_STA,
+
+};
+
+static struct stmpe_variant_block stmpe801_blocks[] = {
+       {
+               .cell   = &stmpe_gpio_cell,
+               .irq    = 0,
+               .block  = STMPE_BLOCK_GPIO,
+       },
+};
+
+static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
+                          bool enable)
+{
+       if (blocks & STMPE_BLOCK_GPIO)
+               return 0;
+       else
+               return -EINVAL;
+}
+
+static struct stmpe_variant_info stmpe801 = {
+       .name           = "stmpe801",
+       .id_val         = STMPE801_ID,
+       .id_mask        = 0xffff,
+       .num_gpios      = 8,
+       .regs           = stmpe801_regs,
+       .blocks         = stmpe801_blocks,
+       .num_blocks     = ARRAY_SIZE(stmpe801_blocks),
+       .num_irqs       = STMPE801_NR_INTERNAL_IRQS,
+       .enable         = stmpe801_enable,
+};
+
+/*
+ * Touchscreen (STMPE811 or STMPE610)
  */
 
 static struct resource stmpe_ts_resources[] = {
@@ -350,7 +393,7 @@ static struct mfd_cell stmpe_ts_cell = {
 };
 
 /*
- * STMPE811
+ * STMPE811 or STMPE610
  */
 
 static const u8 stmpe811_regs[] = {
@@ -421,6 +464,21 @@ static struct stmpe_variant_info stmpe811 = {
        .get_altfunc    = stmpe811_get_altfunc,
 };
 
+/* Similar to 811, except number of gpios */
+static struct stmpe_variant_info stmpe610 = {
+       .name           = "stmpe610",
+       .id_val         = 0x0811,
+       .id_mask        = 0xffff,
+       .num_gpios      = 6,
+       .af_bits        = 1,
+       .regs           = stmpe811_regs,
+       .blocks         = stmpe811_blocks,
+       .num_blocks     = ARRAY_SIZE(stmpe811_blocks),
+       .num_irqs       = STMPE811_NR_INTERNAL_IRQS,
+       .enable         = stmpe811_enable,
+       .get_altfunc    = stmpe811_get_altfunc,
+};
+
 /*
  * STMPE1601
  */
@@ -655,6 +713,8 @@ static struct stmpe_variant_info stmpe2403 = {
 };
 
 static struct stmpe_variant_info *stmpe_variant_info[] = {
+       [STMPE610]      = &stmpe610,
+       [STMPE801]      = &stmpe801,
        [STMPE811]      = &stmpe811,
        [STMPE1601]     = &stmpe1601,
        [STMPE2401]     = &stmpe2401,
@@ -671,6 +731,11 @@ static irqreturn_t stmpe_irq(int irq, void *data)
        int ret;
        int i;
 
+       if (variant->id_val == STMPE801_ID) {
+               handle_nested_irq(stmpe->irq_base);
+               return IRQ_HANDLED;
+       }
+
        ret = stmpe_block_read(stmpe, israddr, num, isr);
        if (ret < 0)
                return IRQ_NONE;
@@ -757,14 +822,17 @@ static struct irq_chip stmpe_irq_chip = {
 
 static int __devinit stmpe_irq_init(struct stmpe *stmpe)
 {
+       struct irq_chip *chip = NULL;
        int num_irqs = stmpe->variant->num_irqs;
        int base = stmpe->irq_base;
        int irq;
 
+       if (stmpe->variant->id_val != STMPE801_ID)
+               chip = &stmpe_irq_chip;
+
        for (irq = base; irq < base + num_irqs; irq++) {
                irq_set_chip_data(irq, stmpe);
-               irq_set_chip_and_handler(irq, &stmpe_irq_chip,
-                                        handle_edge_irq);
+               irq_set_chip_and_handler(irq, chip, handle_edge_irq);
                irq_set_nested_thread(irq, 1);
 #ifdef CONFIG_ARM
                set_irq_flags(irq, IRQF_VALID);
@@ -796,7 +864,7 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
        unsigned int irq_trigger = stmpe->pdata->irq_trigger;
        int autosleep_timeout = stmpe->pdata->autosleep_timeout;
        struct stmpe_variant_info *variant = stmpe->variant;
-       u8 icr = STMPE_ICR_LSB_GIM;
+       u8 icr;
        unsigned int id;
        u8 data[2];
        int ret;
@@ -819,16 +887,32 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
        if (ret)
                return ret;
 
-       if (irq_trigger == IRQF_TRIGGER_FALLING ||
-           irq_trigger == IRQF_TRIGGER_RISING)
-               icr |= STMPE_ICR_LSB_EDGE;
+       if (id == STMPE801_ID)
+               icr = STMPE801_REG_SYS_CTRL_INT_EN;
+       else
+               icr = STMPE_ICR_LSB_GIM;
+
+       /* STMPE801 doesn't support Edge interrupts */
+       if (id != STMPE801_ID) {
+               if (irq_trigger == IRQF_TRIGGER_FALLING ||
+                               irq_trigger == IRQF_TRIGGER_RISING)
+                       icr |= STMPE_ICR_LSB_EDGE;
+       }
 
        if (irq_trigger == IRQF_TRIGGER_RISING ||
-           irq_trigger == IRQF_TRIGGER_HIGH)
-               icr |= STMPE_ICR_LSB_HIGH;
+                       irq_trigger == IRQF_TRIGGER_HIGH) {
+               if (id == STMPE801_ID)
+                       icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+               else
+                       icr |= STMPE_ICR_LSB_HIGH;
+       }
 
-       if (stmpe->pdata->irq_invert_polarity)
-               icr ^= STMPE_ICR_LSB_HIGH;
+       if (stmpe->pdata->irq_invert_polarity) {
+               if (id == STMPE801_ID)
+                       icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
+               else
+                       icr ^= STMPE_ICR_LSB_HIGH;
+       }
 
        if (stmpe->pdata->autosleep) {
                ret = stmpe_autosleep(stmpe, autosleep_timeout);
@@ -873,32 +957,10 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe)
        return ret;
 }
 
-#ifdef CONFIG_PM
-static int stmpe_suspend(struct device *dev)
-{
-       struct i2c_client *i2c = to_i2c_client(dev);
-
-       if (device_may_wakeup(&i2c->dev))
-               enable_irq_wake(i2c->irq);
-
-       return 0;
-}
-
-static int stmpe_resume(struct device *dev)
-{
-       struct i2c_client *i2c = to_i2c_client(dev);
-
-       if (device_may_wakeup(&i2c->dev))
-               disable_irq_wake(i2c->irq);
-
-       return 0;
-}
-#endif
-
-static int __devinit stmpe_probe(struct i2c_client *i2c,
-                                const struct i2c_device_id *id)
+/* Called from client specific probe routines */
+int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
 {
-       struct stmpe_platform_data *pdata = i2c->dev.platform_data;
+       struct stmpe_platform_data *pdata = dev_get_platdata(ci->dev);
        struct stmpe *stmpe;
        int ret;
 
@@ -912,30 +974,43 @@ static int __devinit stmpe_probe(struct i2c_client *i2c,
        mutex_init(&stmpe->irq_lock);
        mutex_init(&stmpe->lock);
 
-       stmpe->dev = &i2c->dev;
-       stmpe->i2c = i2c;
-
+       stmpe->dev = ci->dev;
+       stmpe->client = ci->client;
        stmpe->pdata = pdata;
        stmpe->irq_base = pdata->irq_base;
-
-       stmpe->partnum = id->driver_data;
-       stmpe->variant = stmpe_variant_info[stmpe->partnum];
+       stmpe->ci = ci;
+       stmpe->partnum = partnum;
+       stmpe->variant = stmpe_variant_info[partnum];
        stmpe->regs = stmpe->variant->regs;
        stmpe->num_gpios = stmpe->variant->num_gpios;
+       dev_set_drvdata(stmpe->dev, stmpe);
 
-       i2c_set_clientdata(i2c, stmpe);
+       if (ci->init)
+               ci->init(stmpe);
+
+       if (pdata->irq_over_gpio) {
+               ret = gpio_request_one(pdata->irq_gpio, GPIOF_DIR_IN, "stmpe");
+               if (ret) {
+                       dev_err(stmpe->dev, "failed to request IRQ GPIO: %d\n",
+                                       ret);
+                       goto out_free;
+               }
+
+               stmpe->irq = gpio_to_irq(pdata->irq_gpio);
+       } else {
+               stmpe->irq = ci->irq;
+       }
 
        ret = stmpe_chip_init(stmpe);
        if (ret)
-               goto out_free;
+               goto free_gpio;
 
        ret = stmpe_irq_init(stmpe);
        if (ret)
-               goto out_free;
+               goto free_gpio;
 
-       ret = request_threaded_irq(stmpe->i2c->irq, NULL, stmpe_irq,
-                                  pdata->irq_trigger | IRQF_ONESHOT,
-                                  "stmpe", stmpe);
+       ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
+                       pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe);
        if (ret) {
                dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
                goto out_removeirq;
@@ -951,67 +1026,55 @@ static int __devinit stmpe_probe(struct i2c_client *i2c,
 
 out_removedevs:
        mfd_remove_devices(stmpe->dev);
-       free_irq(stmpe->i2c->irq, stmpe);
+       free_irq(stmpe->irq, stmpe);
 out_removeirq:
        stmpe_irq_remove(stmpe);
+free_gpio:
+       if (pdata->irq_over_gpio)
+               gpio_free(pdata->irq_gpio);
 out_free:
        kfree(stmpe);
        return ret;
 }
 
-static int __devexit stmpe_remove(struct i2c_client *client)
+int stmpe_remove(struct stmpe *stmpe)
 {
-       struct stmpe *stmpe = i2c_get_clientdata(client);
-
        mfd_remove_devices(stmpe->dev);
 
-       free_irq(stmpe->i2c->irq, stmpe);
+       free_irq(stmpe->irq, stmpe);
        stmpe_irq_remove(stmpe);
 
+       if (stmpe->pdata->irq_over_gpio)
+               gpio_free(stmpe->pdata->irq_gpio);
+
        kfree(stmpe);
 
        return 0;
 }
 
-static const struct i2c_device_id stmpe_id[] = {
-       { "stmpe811", STMPE811 },
-       { "stmpe1601", STMPE1601 },
-       { "stmpe2401", STMPE2401 },
-       { "stmpe2403", STMPE2403 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, stmpe_id);
-
 #ifdef CONFIG_PM
-static const struct dev_pm_ops stmpe_dev_pm_ops = {
-       .suspend        = stmpe_suspend,
-       .resume         = stmpe_resume,
-};
-#endif
+static int stmpe_suspend(struct device *dev)
+{
+       struct stmpe *stmpe = dev_get_drvdata(dev);
 
-static struct i2c_driver stmpe_driver = {
-       .driver.name    = "stmpe",
-       .driver.owner   = THIS_MODULE,
-#ifdef CONFIG_PM
-       .driver.pm      = &stmpe_dev_pm_ops,
-#endif
-       .probe          = stmpe_probe,
-       .remove         = __devexit_p(stmpe_remove),
-       .id_table       = stmpe_id,
-};
+       if (device_may_wakeup(dev))
+               enable_irq_wake(stmpe->irq);
 
-static int __init stmpe_init(void)
-{
-       return i2c_add_driver(&stmpe_driver);
+       return 0;
 }
-subsys_initcall(stmpe_init);
 
-static void __exit stmpe_exit(void)
+static int stmpe_resume(struct device *dev)
 {
-       i2c_del_driver(&stmpe_driver);
+       struct stmpe *stmpe = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(stmpe->irq);
+
+       return 0;
 }
-module_exit(stmpe_exit);
 
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("STMPE MFD core driver");
-MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
+const struct dev_pm_ops stmpe_dev_pm_ops = {
+       .suspend        = stmpe_suspend,
+       .resume         = stmpe_resume,
+};
+#endif
index e4ee38956583069fbf912ac78e59279dbd6615e2..7b8e13f5b764dc5fde59a8dcb8389820abe017cd 100644 (file)
@@ -8,6 +8,14 @@
 #ifndef __STMPE_H
 #define __STMPE_H
 
+#include <linux/device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/stmpe.h>
+#include <linux/printk.h>
+#include <linux/types.h>
+
+extern const struct dev_pm_ops stmpe_dev_pm_ops;
+
 #ifdef STMPE_DUMP_BYTES
 static inline void stmpe_dump_bytes(const char *str, const void *buf,
                                    size_t len)
@@ -67,10 +75,54 @@ struct stmpe_variant_info {
        int (*enable_autosleep)(struct stmpe *stmpe, int autosleep_timeout);
 };
 
+/**
+ * struct stmpe_client_info - i2c or spi specific routines/info
+ * @data: client specific data
+ * @read_byte: read single byte
+ * @write_byte: write single byte
+ * @read_block: read block or multiple bytes
+ * @write_block: write block or multiple bytes
+ * @init: client init routine, called during probe
+ */
+struct stmpe_client_info {
+       void *data;
+       int irq;
+       void *client;
+       struct device *dev;
+       int (*read_byte)(struct stmpe *stmpe, u8 reg);
+       int (*write_byte)(struct stmpe *stmpe, u8 reg, u8 val);
+       int (*read_block)(struct stmpe *stmpe, u8 reg, u8 len, u8 *values);
+       int (*write_block)(struct stmpe *stmpe, u8 reg, u8 len,
+                       const u8 *values);
+       void (*init)(struct stmpe *stmpe);
+};
+
+int stmpe_probe(struct stmpe_client_info *ci, int partnum);
+int stmpe_remove(struct stmpe *stmpe);
+
 #define STMPE_ICR_LSB_HIGH     (1 << 2)
 #define STMPE_ICR_LSB_EDGE     (1 << 1)
 #define STMPE_ICR_LSB_GIM      (1 << 0)
 
+/*
+ * STMPE801
+ */
+#define STMPE801_ID                    0x0108
+#define STMPE801_NR_INTERNAL_IRQS      1
+
+#define STMPE801_REG_CHIP_ID           0x00
+#define STMPE801_REG_VERSION_ID                0x02
+#define STMPE801_REG_SYS_CTRL          0x04
+#define STMPE801_REG_GPIO_INT_EN       0x08
+#define STMPE801_REG_GPIO_INT_STA      0x09
+#define STMPE801_REG_GPIO_MP_STA       0x10
+#define STMPE801_REG_GPIO_SET_PIN      0x11
+#define STMPE801_REG_GPIO_DIR          0x12
+
+#define STMPE801_REG_SYS_CTRL_RESET    (1 << 7)
+#define STMPE801_REG_SYS_CTRL_INT_EN   (1 << 2)
+#define STMPE801_REG_SYS_CTRL_INT_HI   (1 << 0)
+
 /*
  * STMPE811
  */
@@ -87,6 +139,7 @@ struct stmpe_variant_info {
 
 #define STMPE811_REG_CHIP_ID           0x00
 #define STMPE811_REG_SYS_CTRL2         0x04
+#define STMPE811_REG_SPI_CFG           0x08
 #define STMPE811_REG_INT_CTRL          0x09
 #define STMPE811_REG_INT_EN            0x0A
 #define STMPE811_REG_INT_STA           0x0B
index 91ad21ef7721cddd335e5470717f3f878191bf0d..2d9e8799e733c6644c18aa9335e9796ef0c0709f 100644 (file)
@@ -442,21 +442,7 @@ static struct platform_driver t7l66xb_platform_driver = {
 
 /*--------------------------------------------------------------------------*/
 
-static int __init t7l66xb_init(void)
-{
-       int retval = 0;
-
-       retval = platform_driver_register(&t7l66xb_platform_driver);
-       return retval;
-}
-
-static void __exit t7l66xb_exit(void)
-{
-       platform_driver_unregister(&t7l66xb_platform_driver);
-}
-
-module_init(t7l66xb_init);
-module_exit(t7l66xb_exit);
+module_platform_driver(t7l66xb_platform_driver);
 
 MODULE_DESCRIPTION("Toshiba T7L66XB core driver");
 MODULE_LICENSE("GPL v2");
index 71bc835324d8743d55ff95383b03027652645f7b..d20a284ad4baca528c36eb351200ff16fdd5282e 100644 (file)
@@ -234,19 +234,7 @@ static struct platform_driver tc6387xb_platform_driver = {
        .resume         = tc6387xb_resume,
 };
 
-
-static int __init tc6387xb_init(void)
-{
-       return platform_driver_register(&tc6387xb_platform_driver);
-}
-
-static void __exit tc6387xb_exit(void)
-{
-       platform_driver_unregister(&tc6387xb_platform_driver);
-}
-
-module_init(tc6387xb_init);
-module_exit(tc6387xb_exit);
+module_platform_driver(tc6387xb_platform_driver);
 
 MODULE_DESCRIPTION("Toshiba TC6387XB core driver");
 MODULE_LICENSE("GPL v2");
index af9ab0e5ca64ac9f9f9f3fe1faed06fb6b13a0fb..4fb0e6c8e8fe0fbfee94299b7c0de45920621a25 100644 (file)
@@ -458,17 +458,7 @@ static struct platform_driver ti_ssp_driver = {
        }
 };
 
-static int __init ti_ssp_init(void)
-{
-       return platform_driver_register(&ti_ssp_driver);
-}
-module_init(ti_ssp_init);
-
-static void __exit ti_ssp_exit(void)
-{
-       platform_driver_unregister(&ti_ssp_driver);
-}
-module_exit(ti_ssp_exit);
+module_platform_driver(ti_ssp_driver);
 
 MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
 MODULE_AUTHOR("Cyril Chemparathy");
index 02d65692ceb415a1ae95a863dd660adda46807c9..0ba26fb12cf532f948fefa1e4df6599ce7db347b 100644 (file)
@@ -857,7 +857,7 @@ static void __devexit timb_remove(struct pci_dev *dev)
        kfree(priv);
 }
 
-static struct pci_device_id timberdale_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(timberdale_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) },
        { 0 }
 };
index a56be931551c9ac7ee34e546a18891e8a2b6549d..95c0d7978bec4a67cfaa74d8c93b430dc715974b 100644 (file)
@@ -215,6 +215,7 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq,
 
 int tps65910_irq_exit(struct tps65910 *tps65910)
 {
-       free_irq(tps65910->chip_irq, tps65910);
+       if (tps65910->chip_irq)
+               free_irq(tps65910->chip_irq, tps65910);
        return 0;
 }
index c1da84bc1573f563c4b698f0bc786068e7f911bc..01cf5012a08fb26c3b561fde99341d6ab84749e2 100644 (file)
@@ -172,15 +172,12 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
 
        tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
 
-       ret = tps65910_irq_init(tps65910, init_data->irq, init_data);
-       if (ret < 0)
-               goto err;
+       tps65910_irq_init(tps65910, init_data->irq, init_data);
 
        kfree(init_data);
        return ret;
 
 err:
-       mfd_remove_devices(tps65910->dev);
        kfree(tps65910);
        kfree(init_data);
        return ret;
@@ -190,8 +187,8 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
 {
        struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
 
-       mfd_remove_devices(tps65910->dev);
        tps65910_irq_exit(tps65910);
+       mfd_remove_devices(tps65910->dev);
        kfree(tps65910);
 
        return 0;
index 6d71e0d2574498abb3c5d22c4b91cb24fefe4c5b..27d3302d56b8f2b13bb8ffad371c33d67d3e529c 100644 (file)
@@ -111,7 +111,6 @@ static int __devexit tps65912_spi_remove(struct spi_device *spi)
 static struct spi_driver tps65912_spi_driver = {
        .driver = {
                .name = "tps65912",
-               .bus = &spi_bus_type,
                .owner = THIS_MODULE,
        },
        .probe  = tps65912_spi_probe,
index 61e70cfaa774fb977adcba8cc697a06edd673210..e04e04ddc15e41f933b2a58de5f3bc8d28e86c25 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/irqdomain.h>
 
 #include <linux/regulator/machine.h>
 
 
 #define TWL_MODULE_LAST TWL4030_MODULE_LAST
 
+#define TWL4030_NR_IRQS    8
+#define TWL6030_NR_IRQS    20
+
 /* Base Address defns for twl4030_map[] */
 
 /* subchip/slave 0 - USB ID */
@@ -255,6 +263,7 @@ struct twl_client {
 
 static struct twl_client twl_modules[TWL_NUM_SLAVES];
 
+static struct irq_domain domain;
 
 /* mapping the module id to slave id and base address */
 struct twl_mapping {
@@ -1183,14 +1192,48 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
        int                             status;
        unsigned                        i;
        struct twl4030_platform_data    *pdata = client->dev.platform_data;
+       struct device_node              *node = client->dev.of_node;
        u8 temp;
        int ret = 0;
+       int nr_irqs = TWL4030_NR_IRQS;
+
+       if ((id->driver_data) & TWL6030_CLASS)
+               nr_irqs = TWL6030_NR_IRQS;
+
+       if (node && !pdata) {
+               /*
+                * XXX: Temporary pdata until the information is correctly
+                * retrieved by every TWL modules from DT.
+                */
+               pdata = devm_kzalloc(&client->dev,
+                                    sizeof(struct twl4030_platform_data),
+                                    GFP_KERNEL);
+               if (!pdata)
+                       return -ENOMEM;
+       }
 
        if (!pdata) {
                dev_dbg(&client->dev, "no platform data?\n");
                return -EINVAL;
        }
 
+       status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0);
+       if (IS_ERR_VALUE(status)) {
+               dev_err(&client->dev, "Fail to allocate IRQ descs\n");
+               return status;
+       }
+
+       pdata->irq_base = status;
+       pdata->irq_end = pdata->irq_base + nr_irqs;
+
+       domain.irq_base = pdata->irq_base;
+       domain.nr_irq = nr_irqs;
+#ifdef CONFIG_OF_IRQ
+       domain.of_node = of_node_get(node);
+       domain.ops = &irq_domain_simple_ops;
+#endif
+       irq_domain_add(&domain);
+
        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
                dev_dbg(&client->dev, "can't talk I2C?\n");
                return -EIO;
@@ -1270,7 +1313,13 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
        }
 
-       status = add_children(pdata, id->driver_data);
+#ifdef CONFIG_OF_DEVICE
+       if (node)
+               status = of_platform_populate(node, NULL, NULL, &client->dev);
+       else
+#endif
+               status = add_children(pdata, id->driver_data);
+
 fail:
        if (status < 0)
                twl_remove(client);
index ae51ab5d0e5d935f9be35c0465b8cd20f07fdb47..838ce4eb444e24ce44bd3b120fe21a9f977d6e75 100644 (file)
@@ -261,17 +261,7 @@ static struct platform_driver twl4030_audio_driver = {
        },
 };
 
-static int __devinit twl4030_audio_init(void)
-{
-       return platform_driver_register(&twl4030_audio_driver);
-}
-module_init(twl4030_audio_init);
-
-static void __devexit twl4030_audio_exit(void)
-{
-       platform_driver_unregister(&twl4030_audio_driver);
-}
-module_exit(twl4030_audio_exit);
+module_platform_driver(twl4030_audio_driver);
 
 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 MODULE_LICENSE("GPL");
index 29f11e0765feef54093b839b6e288ae56bc0bf3f..b69bb517b102a4595b76342afeb58e0c9b3270c2 100644 (file)
@@ -492,7 +492,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data)
                        u8      bytes[4];
                } imr;
 
-               /* byte[0] gets overwriten as we write ... */
+               /* byte[0] gets overwritten as we write ... */
                imr.word = cpu_to_le32(agent->imr << 8);
                agent->imr_change_pending = false;
 
@@ -667,6 +667,7 @@ int twl4030_sih_setup(int module)
                irq_set_chip_data(irq, agent);
                irq_set_chip_and_handler(irq, &twl4030_sih_irq_chip,
                                         handle_edge_irq);
+               irq_set_nested_thread(irq, 1);
                activate_irq(irq);
        }
 
index 834f824d3c11075b18098a5c0b64a1abf066cd69..456ecb5ac4fe52e1a5515f1793eda270c5407056 100644 (file)
@@ -807,19 +807,7 @@ static struct platform_driver twl4030_madc_driver = {
                   },
 };
 
-static int __init twl4030_madc_init(void)
-{
-       return platform_driver_register(&twl4030_madc_driver);
-}
-
-module_init(twl4030_madc_init);
-
-static void __exit twl4030_madc_exit(void)
-{
-       platform_driver_unregister(&twl4030_madc_driver);
-}
-
-module_exit(twl4030_madc_exit);
+module_platform_driver(twl4030_madc_driver);
 
 MODULE_DESCRIPTION("TWL4030 ADC driver");
 MODULE_LICENSE("GPL");
index a764676f09220146fb0ebc84addfe5e79ad9943e..d905f5171153e7f5ee3d8a808c493255883dd704 100644 (file)
@@ -34,7 +34,8 @@
 static u8 twl4030_start_script_address = 0x2b;
 
 #define PWR_P1_SW_EVENTS       0x10
-#define PWR_DEVOFF     (1<<0)
+#define PWR_DEVOFF             (1 << 0)
+#define SEQ_OFFSYNC            (1 << 0)
 
 #define PHY_TO_OFF_PM_MASTER(p)                (p - 0x36)
 #define PHY_TO_OFF_PM_RECEIVER(p)      (p - 0x5b)
@@ -511,12 +512,27 @@ int twl4030_remove_script(u8 flags)
        return err;
 }
 
+/*
+ * In master mode, start the power off sequence.
+ * After a successful execution, TWL shuts down the power to the SoC
+ * and all peripherals connected to it.
+ */
+void twl4030_power_off(void)
+{
+       int err;
+
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, PWR_DEVOFF,
+                              TWL4030_PM_MASTER_P1_SW_EVENTS);
+       if (err)
+               pr_err("TWL4030 Unable to power off\n");
+}
+
 void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
 {
        int err = 0;
        int i;
        struct twl4030_resconfig *resconfig;
-       u8 address = twl4030_start_script_address;
+       u8 val, address = twl4030_start_script_address;
 
        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
                        TWL4030_PM_MASTER_KEY_CFG1,
@@ -548,6 +564,28 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
                }
        }
 
+       /* Board has to be wired properly to use this feature */
+       if (twl4030_scripts->use_poweroff && !pm_power_off) {
+               /* Default for SEQ_OFFSYNC is set, lets ensure this */
+               err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
+                                     TWL4030_PM_MASTER_CFG_P123_TRANSITION);
+               if (err) {
+                       pr_warning("TWL4030 Unable to read registers\n");
+
+               } else if (!(val & SEQ_OFFSYNC)) {
+                       val |= SEQ_OFFSYNC;
+                       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
+                                       TWL4030_PM_MASTER_CFG_P123_TRANSITION);
+                       if (err) {
+                               pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n");
+                               goto relock;
+                       }
+               }
+
+               pm_power_off = twl4030_power_off;
+       }
+
+relock:
        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
                        TWL4030_PM_MASTER_PROTECT_KEY);
        if (err)
index 268f80fd04394e2e7abca10d065d0be20625d37e..dda86293dc9fc0a3f8baaf678591d764824cfe14 100644 (file)
@@ -509,13 +509,10 @@ static int __devinit twl6040_probe(struct platform_device *pdev)
                twl6040->audpwron = -EINVAL;
 
        if (gpio_is_valid(twl6040->audpwron)) {
-               ret = gpio_request(twl6040->audpwron, "audpwron");
+               ret = gpio_request_one(twl6040->audpwron, GPIOF_OUT_INIT_LOW,
+                                      "audpwron");
                if (ret)
                        goto gpio1_err;
-
-               ret = gpio_direction_output(twl6040->audpwron, 0);
-               if (ret)
-                       goto gpio2_err;
        }
 
        /* codec interrupt */
@@ -619,18 +616,7 @@ static struct platform_driver twl6040_driver = {
        },
 };
 
-static int __devinit twl6040_init(void)
-{
-       return platform_driver_register(&twl6040_driver);
-}
-module_init(twl6040_init);
-
-static void __devexit twl6040_exit(void)
-{
-       platform_driver_unregister(&twl6040_driver);
-}
-
-module_exit(twl6040_exit);
+module_platform_driver(twl6040_driver);
 
 MODULE_DESCRIPTION("TWL6040 MFD");
 MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
index b281217334eb3c68d35c7695b8104dd327e6bcf6..91c4f25e0e558fe20a04ae10e1554d98f0f3fff9 100644 (file)
@@ -36,6 +36,15 @@ static DEFINE_MUTEX(ucb1x00_mutex);
 static LIST_HEAD(ucb1x00_drivers);
 static LIST_HEAD(ucb1x00_devices);
 
+static struct mcp_device_id ucb1x00_id[] = {
+       { "ucb1x00", 0 },  /* auto-detection */
+       { "ucb1200", UCB_ID_1200 },
+       { "ucb1300", UCB_ID_1300 },
+       { "tc35143", UCB_ID_TC35143 },
+       { }
+};
+MODULE_DEVICE_TABLE(mcp, ucb1x00_id);
+
 /**
  *     ucb1x00_io_set_dir - set IO direction
  *     @ucb: UCB1x00 structure describing chip
@@ -527,17 +536,33 @@ static struct class ucb1x00_class = {
 
 static int ucb1x00_probe(struct mcp *mcp)
 {
+       const struct mcp_device_id *mid;
        struct ucb1x00 *ucb;
        struct ucb1x00_driver *drv;
+       struct ucb1x00_plat_data *pdata;
        unsigned int id;
        int ret = -ENODEV;
        int temp;
 
        mcp_enable(mcp);
        id = mcp_reg_read(mcp, UCB_ID);
+       mid = mcp_get_device_id(mcp);
 
-       if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
-               printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
+       if (mid && mid->driver_data) {
+               if (id != mid->driver_data) {
+                       printk(KERN_WARNING "%s wrong ID %04x found: %04x\n",
+                               mid->name, (unsigned int) mid->driver_data, id);
+                       goto err_disable;
+               }
+       } else {
+               mid = &ucb1x00_id[1];
+               while (mid->driver_data) {
+                       if (id == mid->driver_data)
+                               break;
+                       mid++;
+               }
+               printk(KERN_WARNING "%s ID not found: %04x\n",
+                       ucb1x00_id[0].name, id);
                goto err_disable;
        }
 
@@ -546,28 +571,28 @@ static int ucb1x00_probe(struct mcp *mcp)
        if (!ucb)
                goto err_disable;
 
-
+       pdata = mcp->attached_device.platform_data;
        ucb->dev.class = &ucb1x00_class;
        ucb->dev.parent = &mcp->attached_device;
-       dev_set_name(&ucb->dev, "ucb1x00");
+       dev_set_name(&ucb->dev, mid->name);
 
        spin_lock_init(&ucb->lock);
        spin_lock_init(&ucb->io_lock);
        sema_init(&ucb->adc_sem, 1);
 
-       ucb->id  = id;
+       ucb->id  = mid;
        ucb->mcp = mcp;
        ucb->irq = ucb1x00_detect_irq(ucb);
        if (ucb->irq == NO_IRQ) {
-               printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
+               printk(KERN_ERR "%s: IRQ probe failed\n", mid->name);
                ret = -ENODEV;
                goto err_free;
        }
 
        ucb->gpio.base = -1;
-       if (mcp->gpio_base != 0) {
+       if (pdata && (pdata->gpio_base >= 0)) {
                ucb->gpio.label = dev_name(&ucb->dev);
-               ucb->gpio.base = mcp->gpio_base;
+               ucb->gpio.base = pdata->gpio_base;
                ucb->gpio.ngpio = 10;
                ucb->gpio.set = ucb1x00_gpio_set;
                ucb->gpio.get = ucb1x00_gpio_get;
@@ -580,10 +605,10 @@ static int ucb1x00_probe(struct mcp *mcp)
                dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
 
        ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
-                         "UCB1x00", ucb);
+                         mid->name, ucb);
        if (ret) {
-               printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
-                       ucb->irq, ret);
+               printk(KERN_ERR "%s: unable to grab irq%d: %d\n",
+                       mid->name, ucb->irq, ret);
                goto err_gpio;
        }
 
@@ -705,6 +730,7 @@ static struct mcp_driver ucb1x00_driver = {
        .remove         = ucb1x00_remove,
        .suspend        = ucb1x00_suspend,
        .resume         = ucb1x00_resume,
+       .id_table       = ucb1x00_id,
 };
 
 static int __init ucb1x00_init(void)
index 38ffbd50a0d27bc24cbc9826c5dae1e95a54b560..40ec3c118868d7f02e104d2ed10e2f766840a0f4 100644 (file)
@@ -382,7 +382,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
        ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
 
        idev->name       = "Touchscreen panel";
-       idev->id.product = ts->ucb->id;
+       idev->id.product = ts->ucb->id->driver_data;
        idev->open       = ucb1x00_ts_open;
        idev->close      = ucb1x00_ts_close;
 
index d698703dbd462c73b7267d9cd1a37a55bdd99d60..b73cc15e00818d4e15f2f44f9fe0a9f12e6196a6 100644 (file)
@@ -118,7 +118,7 @@ static void __devexit vx855_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-static struct pci_device_id vx855_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(vx855_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) },
        { 0, }
 };
index 0a2b8d41a7020229223c7dcf5876d2d9cc532b43..f5e54fae8ada924bb029a1afe9a0239f3eb959b3 100644 (file)
@@ -559,6 +559,8 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg,
                dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n",
                         buf[i], reg + i, reg + i);
                ret = regmap_write(wm831x->regmap, reg + i, buf[i]);
+               if (ret != 0)
+                       return ret;
        }
 
        return 0;
@@ -1875,7 +1877,6 @@ err_irq:
 err_regmap:
        mfd_remove_devices(wm831x->dev);
        regmap_exit(wm831x->regmap);
-       kfree(wm831x);
        return ret;
 }
 
@@ -1887,7 +1888,6 @@ void wm831x_device_exit(struct wm831x *wm831x)
                free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x);
        wm831x_irq_exit(wm831x);
        regmap_exit(wm831x->regmap);
-       kfree(wm831x);
 }
 
 int wm831x_device_suspend(struct wm831x *wm831x)
index ac8da1d439daab72b9118ae6cf8675f3bac6dc9a..cb15609b0a4871ff7999498440703901fb511076 100644 (file)
@@ -30,7 +30,7 @@ static int wm831x_i2c_probe(struct i2c_client *i2c,
        struct wm831x *wm831x;
        int ret;
 
-       wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
+       wm831x = devm_kzalloc(&i2c->dev, sizeof(struct wm831x), GFP_KERNEL);
        if (wm831x == NULL)
                return -ENOMEM;
 
@@ -42,7 +42,6 @@ static int wm831x_i2c_probe(struct i2c_client *i2c,
                ret = PTR_ERR(wm831x->regmap);
                dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
                        ret);
-               kfree(wm831x);
                return ret;
        }
 
index f4747a4a9a93fb8d3c906d5060442117860ddaf7..bec4d053916012a696442fff39b847be647b9db0 100644 (file)
@@ -325,11 +325,6 @@ static inline int irq_data_to_status_reg(struct wm831x_irq_data *irq_data)
        return WM831X_INTERRUPT_STATUS_1 - 1 + irq_data->reg;
 }
 
-static inline int irq_data_to_mask_reg(struct wm831x_irq_data *irq_data)
-{
-       return WM831X_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg;
-}
-
 static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x,
                                                        int irq)
 {
@@ -477,8 +472,7 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
                handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD);
        if (primary & WM831X_TCHDATA_INT)
                handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA);
-       if (primary & (WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT))
-               goto out;
+       primary &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT);
 
        for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) {
                int offset = wm831x_irqs[i].reg - 1;
index 8d6a9a969dbc246e87d46eb8bf38e0b62b796149..62ef3254105ffdebef5dcdcfa476a038ca14f997 100644 (file)
@@ -30,7 +30,7 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
 
        type = (enum wm831x_parent)id->driver_data;
 
-       wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
+       wm831x = devm_kzalloc(&spi->dev, sizeof(struct wm831x), GFP_KERNEL);
        if (wm831x == NULL)
                return -ENOMEM;
 
@@ -45,7 +45,6 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
                ret = PTR_ERR(wm831x->regmap);
                dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
                        ret);
-               kfree(wm831x);
                return ret;
        }
 
@@ -95,7 +94,6 @@ MODULE_DEVICE_TABLE(spi, wm831x_spi_id);
 static struct spi_driver wm831x_spi_driver = {
        .driver = {
                .name   = "wm831x",
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
                .pm     = &wm831x_spi_pm,
        },
index e81cc31e42020a8ceff6620d73b3f251ca6aeffd..dd1caaac55e4d4138ccc69b19997793418a76e7d 100644 (file)
@@ -573,6 +573,8 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
        u16 id1, id2, mask_rev;
        u16 cust_id, mode, chip_rev;
 
+       dev_set_drvdata(wm8350->dev, wm8350);
+
        /* get WM8350 revision and config mode */
        ret = wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
        if (ret != 0) {
index 5fe5de166adb39bdafb2e7714ce046f58b6ccb3b..d955faaf27c4a8f824301ae5e3e34998f4333bf0 100644 (file)
@@ -63,7 +63,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c,
        struct wm8350 *wm8350;
        int ret = 0;
 
-       wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL);
+       wm8350 = devm_kzalloc(&i2c->dev, sizeof(struct wm8350), GFP_KERNEL);
        if (wm8350 == NULL)
                return -ENOMEM;
 
@@ -80,7 +80,6 @@ static int wm8350_i2c_probe(struct i2c_client *i2c,
        return ret;
 
 err:
-       kfree(wm8350);
        return ret;
 }
 
@@ -89,7 +88,6 @@ static int wm8350_i2c_remove(struct i2c_client *i2c)
        struct wm8350 *wm8350 = i2c_get_clientdata(i2c);
 
        wm8350_device_exit(wm8350);
-       kfree(wm8350);
 
        return 0;
 }
index 62b4626f4561029102ece804a7de96708186b2cb..2204893444a6ca6a4f2a245023169e1ff9e69379 100644 (file)
@@ -344,7 +344,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
        struct wm8400 *wm8400;
        int ret;
 
-       wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL);
+       wm8400 = devm_kzalloc(&i2c->dev, sizeof(struct wm8400), GFP_KERNEL);
        if (wm8400 == NULL) {
                ret = -ENOMEM;
                goto err;
@@ -353,7 +353,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
        wm8400->regmap = regmap_init_i2c(i2c, &wm8400_regmap_config);
        if (IS_ERR(wm8400->regmap)) {
                ret = PTR_ERR(wm8400->regmap);
-               goto struct_err;
+               goto err;
        }
 
        wm8400->dev = &i2c->dev;
@@ -367,8 +367,6 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
 
 map_err:
        regmap_exit(wm8400->regmap);
-struct_err:
-       kfree(wm8400);
 err:
        return ret;
 }
@@ -379,7 +377,6 @@ static int wm8400_i2c_remove(struct i2c_client *i2c)
 
        wm8400_release(wm8400);
        regmap_exit(wm8400->regmap);
-       kfree(wm8400);
 
        return 0;
 }
index 5664696f2d3a8512c6ef96aca461dde22e5d486f..6a1a092db1461f3413defc6d11ca74ce68b9d282 100644 (file)
@@ -500,6 +500,14 @@ config USB_SWITCH_FSA9480
          stereo and mono audio, video, microphone and UART data to use
          a common connector port.
 
+config MAX8997_MUIC
+       tristate "MAX8997 MUIC Support"
+       depends on MFD_MAX8997
+       help
+         If you say yes here you get support for the MUIC device of
+         Maxim MAX8997 PMIC.
+         The MAX8997 MUIC is a USB port accessory detector and switch.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
index b26495a0255494d7c1ee03f987d4a12ac39b8196..3e1d80106f04e36fad4b82806b8939afcfae50cc 100644 (file)
@@ -48,3 +48,4 @@ obj-y                         += lis3lv02d/
 obj-y                          += carma/
 obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
 obj-$(CONFIG_ALTERA_STAPL)     +=altera-stapl/
+obj-$(CONFIG_MAX8997_MUIC)     += max8997-muic.o
index 2208a9d526222a9ebb30a0f2538553029e6f4e19..d7a9aa14e5d5aafd8c0efc907b127147a202d197 100644 (file)
@@ -8,8 +8,8 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/pwm.h>
-#include <linux/mfd/ab8500.h>
 #include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/module.h>
 
 /*
index eb5cd28bc6d8d7a1917f7f15d82b267b692315f8..a2d25e4857e31387fc0457b5a47efc4c1e438bd0 100644 (file)
@@ -513,7 +513,7 @@ static noinline int fpga_program_dma(struct fpga_dev *priv)
         * transaction, and then put it under external control
         */
        memset(&config, 0, sizeof(config));
-       config.direction = DMA_TO_DEVICE;
+       config.direction = DMA_MEM_TO_DEV;
        config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
        config.dst_maxburst = fpga_fifo_size(priv->regs) / 2 / 4;
        ret = chan->device->device_control(chan, DMA_SLAVE_CONFIG,
index b1f4563be9aecb92f946e7fc6795ad80e7cc0fae..701eb600b1271c2e795b038d48f6ca1e2e1b4fce 100644 (file)
@@ -376,20 +376,20 @@ static int blocks;
 module_param(blocks, int, 0604);
 MODULE_PARM_DESC(blocks, "max_blocks_to_send");
 
-static int dump;
+static bool dump;
 module_param(dump, bool, 0604);
 MODULE_PARM_DESC(dump, "dump_hex_content");
 
-static int jump = 1;
+static bool jump = 1;
 module_param(jump, bool, 0604);
 
-static int direct = 1;
+static bool direct = 1;
 module_param(direct, bool, 0604);
 
-static int checksum = 1;
+static bool checksum = 1;
 module_param(checksum, bool, 0604);
 
-static int fw_download = 1;
+static bool fw_download = 1;
 module_param(fw_download, bool, 0604);
 
 static int block_size = IWMC_SDIO_BLK_SIZE;
@@ -398,7 +398,7 @@ module_param(block_size, int, 0404);
 static int download_trans_blks = IWMC_DEFAULT_TR_BLK;
 module_param(download_trans_blks, int, 0604);
 
-static int rubbish_barker;
+static bool rubbish_barker;
 module_param(rubbish_barker, bool, 0604);
 
 #ifdef CONFIG_IWMC3200TOP_DEBUG
index 29d12a70eb1bcbb2ccb08ab76f907057ee368021..a981e2a42f92a9427058d528fd784ed2798c6883 100644 (file)
@@ -111,6 +111,8 @@ static struct kernel_param_ops param_ops_axis = {
        .get = param_get_int,
 };
 
+#define param_check_axis(name, p) param_check_int(name, p)
+
 module_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644);
 MODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions");
 
diff --git a/drivers/misc/max8997-muic.c b/drivers/misc/max8997-muic.c
new file mode 100644 (file)
index 0000000..d74ef41
--- /dev/null
@@ -0,0 +1,505 @@
+/*
+ * max8997-muic.c - MAX8997 muic driver for the Maxim 8997
+ *
+ *  Copyright (C) 2011 Samsung Electrnoics
+ *  Donggeun Kim <dg77.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/kobject.h>
+#include <linux/mfd/max8997.h>
+#include <linux/mfd/max8997-private.h>
+
+/* MAX8997-MUIC STATUS1 register */
+#define STATUS1_ADC_SHIFT              0
+#define STATUS1_ADCLOW_SHIFT           5
+#define STATUS1_ADCERR_SHIFT           6
+#define STATUS1_ADC_MASK               (0x1f << STATUS1_ADC_SHIFT)
+#define STATUS1_ADCLOW_MASK            (0x1 << STATUS1_ADCLOW_SHIFT)
+#define STATUS1_ADCERR_MASK            (0x1 << STATUS1_ADCERR_SHIFT)
+
+/* MAX8997-MUIC STATUS2 register */
+#define STATUS2_CHGTYP_SHIFT           0
+#define STATUS2_CHGDETRUN_SHIFT                3
+#define STATUS2_DCDTMR_SHIFT           4
+#define STATUS2_DBCHG_SHIFT            5
+#define STATUS2_VBVOLT_SHIFT           6
+#define STATUS2_CHGTYP_MASK            (0x7 << STATUS2_CHGTYP_SHIFT)
+#define STATUS2_CHGDETRUN_MASK         (0x1 << STATUS2_CHGDETRUN_SHIFT)
+#define STATUS2_DCDTMR_MASK            (0x1 << STATUS2_DCDTMR_SHIFT)
+#define STATUS2_DBCHG_MASK             (0x1 << STATUS2_DBCHG_SHIFT)
+#define STATUS2_VBVOLT_MASK            (0x1 << STATUS2_VBVOLT_SHIFT)
+
+/* MAX8997-MUIC STATUS3 register */
+#define STATUS3_OVP_SHIFT              2
+#define STATUS3_OVP_MASK               (0x1 << STATUS3_OVP_SHIFT)
+
+/* MAX8997-MUIC CONTROL1 register */
+#define COMN1SW_SHIFT                  0
+#define COMP2SW_SHIFT                  3
+#define COMN1SW_MASK                   (0x7 << COMN1SW_SHIFT)
+#define COMP2SW_MASK                   (0x7 << COMP2SW_SHIFT)
+#define SW_MASK                                (COMP2SW_MASK | COMN1SW_MASK)
+
+#define MAX8997_SW_USB         ((1 << COMP2SW_SHIFT) | (1 << COMN1SW_SHIFT))
+#define MAX8997_SW_AUDIO       ((2 << COMP2SW_SHIFT) | (2 << COMN1SW_SHIFT))
+#define MAX8997_SW_UART                ((3 << COMP2SW_SHIFT) | (3 << COMN1SW_SHIFT))
+#define MAX8997_SW_OPEN                ((0 << COMP2SW_SHIFT) | (0 << COMN1SW_SHIFT))
+
+#define        MAX8997_ADC_GROUND              0x00
+#define        MAX8997_ADC_MHL                 0x01
+#define        MAX8997_ADC_JIG_USB_1           0x18
+#define        MAX8997_ADC_JIG_USB_2           0x19
+#define        MAX8997_ADC_DESKDOCK            0x1a
+#define        MAX8997_ADC_JIG_UART            0x1c
+#define        MAX8997_ADC_CARDOCK             0x1d
+#define        MAX8997_ADC_OPEN                0x1f
+
+struct max8997_muic_irq {
+       unsigned int irq;
+       const char *name;
+};
+
+static struct max8997_muic_irq muic_irqs[] = {
+       { MAX8997_MUICIRQ_ADCError, "muic-ADC_error" },
+       { MAX8997_MUICIRQ_ADCLow, "muic-ADC_low" },
+       { MAX8997_MUICIRQ_ADC, "muic-ADC" },
+       { MAX8997_MUICIRQ_VBVolt, "muic-VB_voltage" },
+       { MAX8997_MUICIRQ_DBChg, "muic-DB_charger" },
+       { MAX8997_MUICIRQ_DCDTmr, "muic-DCD_timer" },
+       { MAX8997_MUICIRQ_ChgDetRun, "muic-CDR_status" },
+       { MAX8997_MUICIRQ_ChgTyp, "muic-charger_type" },
+       { MAX8997_MUICIRQ_OVP, "muic-over_voltage" },
+};
+
+struct max8997_muic_info {
+       struct device *dev;
+       struct max8997_dev *iodev;
+       struct i2c_client *muic;
+       struct max8997_muic_platform_data *muic_pdata;
+
+       int irq;
+       struct work_struct irq_work;
+
+       enum max8997_muic_charger_type pre_charger_type;
+       int pre_adc;
+
+       struct mutex mutex;
+};
+
+static int max8997_muic_handle_usb(struct max8997_muic_info *info,
+                       enum max8997_muic_usb_type usb_type, bool attached)
+{
+       struct max8997_muic_platform_data *mdata = info->muic_pdata;
+       int ret = 0;
+
+       if (usb_type == MAX8997_USB_HOST) {
+               /* switch to USB */
+               ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
+                               attached ? MAX8997_SW_USB : MAX8997_SW_OPEN,
+                               SW_MASK);
+               if (ret) {
+                       dev_err(info->dev, "failed to update muic register\n");
+                       goto out;
+               }
+       }
+
+       if (mdata->usb_callback)
+               mdata->usb_callback(usb_type, attached);
+out:
+       return ret;
+}
+
+static void max8997_muic_handle_mhl(struct max8997_muic_info *info,
+                       bool attached)
+{
+       struct max8997_muic_platform_data *mdata = info->muic_pdata;
+
+       if (mdata->mhl_callback)
+               mdata->mhl_callback(attached);
+}
+
+static int max8997_muic_handle_dock(struct max8997_muic_info *info,
+                       int adc, bool attached)
+{
+       struct max8997_muic_platform_data *mdata = info->muic_pdata;
+       int ret = 0;
+
+       /* switch to AUDIO */
+       ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
+                               attached ? MAX8997_SW_AUDIO : MAX8997_SW_OPEN,
+                               SW_MASK);
+       if (ret) {
+               dev_err(info->dev, "failed to update muic register\n");
+               goto out;
+       }
+
+       switch (adc) {
+       case MAX8997_ADC_DESKDOCK:
+               if (mdata->deskdock_callback)
+                       mdata->deskdock_callback(attached);
+               break;
+       case MAX8997_ADC_CARDOCK:
+               if (mdata->cardock_callback)
+                       mdata->cardock_callback(attached);
+               break;
+       default:
+               break;
+       }
+out:
+       return ret;
+}
+
+static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
+                       bool attached)
+{
+       struct max8997_muic_platform_data *mdata = info->muic_pdata;
+       int ret = 0;
+
+       /* switch to UART */
+       ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
+                               attached ? MAX8997_SW_UART : MAX8997_SW_OPEN,
+                               SW_MASK);
+       if (ret) {
+               dev_err(info->dev, "failed to update muic register\n");
+               goto out;
+       }
+
+       if (mdata->uart_callback)
+               mdata->uart_callback(attached);
+out:
+       return ret;
+}
+
+static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info)
+{
+       int ret = 0;
+
+       switch (info->pre_adc) {
+       case MAX8997_ADC_GROUND:
+               ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false);
+               break;
+       case MAX8997_ADC_MHL:
+               max8997_muic_handle_mhl(info, false);
+               break;
+       case MAX8997_ADC_JIG_USB_1:
+       case MAX8997_ADC_JIG_USB_2:
+               ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, false);
+               break;
+       case MAX8997_ADC_DESKDOCK:
+       case MAX8997_ADC_CARDOCK:
+               ret = max8997_muic_handle_dock(info, info->pre_adc, false);
+               break;
+       case MAX8997_ADC_JIG_UART:
+               ret = max8997_muic_handle_jig_uart(info, false);
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
+{
+       int ret = 0;
+
+       switch (adc) {
+       case MAX8997_ADC_GROUND:
+               ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true);
+               break;
+       case MAX8997_ADC_MHL:
+               max8997_muic_handle_mhl(info, true);
+               break;
+       case MAX8997_ADC_JIG_USB_1:
+       case MAX8997_ADC_JIG_USB_2:
+               ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, true);
+               break;
+       case MAX8997_ADC_DESKDOCK:
+       case MAX8997_ADC_CARDOCK:
+               ret = max8997_muic_handle_dock(info, adc, true);
+               break;
+       case MAX8997_ADC_JIG_UART:
+               ret = max8997_muic_handle_jig_uart(info, true);
+               break;
+       case MAX8997_ADC_OPEN:
+               ret = max8997_muic_handle_adc_detach(info);
+               break;
+       default:
+               break;
+       }
+
+       info->pre_adc = adc;
+
+       return ret;
+}
+
+static int max8997_muic_handle_charger_type(struct max8997_muic_info *info,
+                               enum max8997_muic_charger_type charger_type)
+{
+       struct max8997_muic_platform_data *mdata = info->muic_pdata;
+       u8 adc;
+       int ret;
+
+       ret = max8997_read_reg(info->muic, MAX8997_MUIC_REG_STATUS1, &adc);
+       if (ret) {
+               dev_err(info->dev, "failed to read muic register\n");
+               goto out;
+       }
+
+       switch (charger_type) {
+       case MAX8997_CHARGER_TYPE_NONE:
+               if (mdata->charger_callback)
+                       mdata->charger_callback(false, charger_type);
+               if (info->pre_charger_type == MAX8997_CHARGER_TYPE_USB) {
+                       max8997_muic_handle_usb(info,
+                                       MAX8997_USB_DEVICE, false);
+               }
+               break;
+       case MAX8997_CHARGER_TYPE_USB:
+               if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) {
+                       max8997_muic_handle_usb(info,
+                                       MAX8997_USB_DEVICE, true);
+               }
+               if (mdata->charger_callback)
+                       mdata->charger_callback(true, charger_type);
+               break;
+       case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
+       case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
+       case MAX8997_CHARGER_TYPE_500MA:
+       case MAX8997_CHARGER_TYPE_1A:
+               if (mdata->charger_callback)
+                       mdata->charger_callback(true, charger_type);
+               break;
+       default:
+               break;
+       }
+
+       info->pre_charger_type = charger_type;
+out:
+       return ret;
+}
+
+static void max8997_muic_irq_work(struct work_struct *work)
+{
+       struct max8997_muic_info *info = container_of(work,
+                       struct max8997_muic_info, irq_work);
+       struct max8997_platform_data *pdata =
+                               dev_get_platdata(info->iodev->dev);
+       u8 status[3];
+       u8 adc, chg_type;
+
+       int irq_type = info->irq - pdata->irq_base;
+       int ret;
+
+       mutex_lock(&info->mutex);
+
+       ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
+                               3, status);
+       if (ret) {
+               dev_err(info->dev, "failed to read muic register\n");
+               mutex_unlock(&info->mutex);
+               return;
+       }
+
+       dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__,
+                       status[0], status[1]);
+
+       switch (irq_type) {
+       case MAX8997_MUICIRQ_ADC:
+               adc = status[0] & STATUS1_ADC_MASK;
+               adc >>= STATUS1_ADC_SHIFT;
+
+               max8997_muic_handle_adc(info, adc);
+               break;
+       case MAX8997_MUICIRQ_ChgTyp:
+               chg_type = status[1] & STATUS2_CHGTYP_MASK;
+               chg_type >>= STATUS2_CHGTYP_SHIFT;
+
+               max8997_muic_handle_charger_type(info, chg_type);
+               break;
+       default:
+               dev_info(info->dev, "misc interrupt: %s occurred\n",
+                        muic_irqs[irq_type].name);
+               break;
+       }
+
+       mutex_unlock(&info->mutex);
+
+       return;
+}
+
+static irqreturn_t max8997_muic_irq_handler(int irq, void *data)
+{
+       struct max8997_muic_info *info = data;
+
+       dev_dbg(info->dev, "irq:%d\n", irq);
+       info->irq = irq;
+
+       schedule_work(&info->irq_work);
+
+       return IRQ_HANDLED;
+}
+
+static void max8997_muic_detect_dev(struct max8997_muic_info *info)
+{
+       int ret;
+       u8 status[2], adc, chg_type;
+
+       ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
+                               2, status);
+       if (ret) {
+               dev_err(info->dev, "failed to read muic register\n");
+               return;
+       }
+
+       dev_info(info->dev, "STATUS1:0x%x, STATUS2:0x%x\n",
+                       status[0], status[1]);
+
+       adc = status[0] & STATUS1_ADC_MASK;
+       adc >>= STATUS1_ADC_SHIFT;
+
+       chg_type = status[1] & STATUS2_CHGTYP_MASK;
+       chg_type >>= STATUS2_CHGTYP_SHIFT;
+
+       max8997_muic_handle_adc(info, adc);
+       max8997_muic_handle_charger_type(info, chg_type);
+}
+
+static void max8997_initialize_device(struct max8997_muic_info *info)
+{
+       struct max8997_muic_platform_data *mdata = info->muic_pdata;
+       int i;
+
+       for (i = 0; i < mdata->num_init_data; i++) {
+               max8997_write_reg(info->muic, mdata->init_data[i].addr,
+                               mdata->init_data[i].data);
+       }
+}
+
+static int __devinit max8997_muic_probe(struct platform_device *pdev)
+{
+       struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
+       struct max8997_muic_info *info;
+       int ret, i;
+
+       info = kzalloc(sizeof(struct max8997_muic_info), GFP_KERNEL);
+       if (!info) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               ret = -ENOMEM;
+               goto err_kfree;
+       }
+
+       if (!pdata->muic_pdata) {
+               dev_err(&pdev->dev, "failed to get platform_data\n");
+               ret = -EINVAL;
+               goto err_pdata;
+       }
+       info->muic_pdata = pdata->muic_pdata;
+
+       info->dev = &pdev->dev;
+       info->iodev = iodev;
+       info->muic = iodev->muic;
+
+       platform_set_drvdata(pdev, info);
+       mutex_init(&info->mutex);
+
+       INIT_WORK(&info->irq_work, max8997_muic_irq_work);
+
+       for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
+               struct max8997_muic_irq *muic_irq = &muic_irqs[i];
+
+               ret = request_threaded_irq(pdata->irq_base + muic_irq->irq,
+                               NULL, max8997_muic_irq_handler,
+                               0, muic_irq->name,
+                               info);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "failed: irq request (IRQ: %d,"
+                               " error :%d)\n",
+                               muic_irq->irq, ret);
+
+                       for (i = i - 1; i >= 0; i--)
+                               free_irq(muic_irq->irq, info);
+
+                       goto err_irq;
+               }
+       }
+
+       /* Initialize registers according to platform data */
+       max8997_initialize_device(info);
+
+       /* Initial device detection */
+       max8997_muic_detect_dev(info);
+
+       return ret;
+
+err_irq:
+err_pdata:
+       kfree(info);
+err_kfree:
+       return ret;
+}
+
+static int __devexit max8997_muic_remove(struct platform_device *pdev)
+{
+       struct max8997_muic_info *info = platform_get_drvdata(pdev);
+       struct max8997_platform_data *pdata =
+                               dev_get_platdata(info->iodev->dev);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
+               free_irq(pdata->irq_base + muic_irqs[i].irq, info);
+       cancel_work_sync(&info->irq_work);
+
+       kfree(info);
+
+       return 0;
+}
+
+static struct platform_driver max8997_muic_driver = {
+       .driver         = {
+               .name   = "max8997-muic",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = max8997_muic_probe,
+       .remove         = __devexit_p(max8997_muic_remove),
+};
+
+static int __init max8997_muic_init(void)
+{
+       return platform_driver_register(&max8997_muic_driver);
+}
+module_init(max8997_muic_init);
+
+static void __exit max8997_muic_exit(void)
+{
+       platform_driver_unregister(&max8997_muic_driver);
+}
+module_exit(max8997_muic_exit);
+
+MODULE_DESCRIPTION("Maxim MAX8997 MUIC driver");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_LICENSE("GPL");
index 12eef393e2160103ac3e63dadcefd5817e99a6a9..400756ec7c492dfd527dc5154b6601ae0ef1060d 100644 (file)
@@ -6,5 +6,4 @@ subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_MMC)              += core/
 obj-$(CONFIG_MMC)              += card/
-obj-$(CONFIG_MMC)              += host/
-
+obj-$(subst m,y,$(CONFIG_MMC)) += host/
index 1e0e27cbe98786e82abf3d5d9e6ede36cc8f0eb2..0cad48a284a85366e6ad72aa607fd6d9f3da59ce 100644 (file)
@@ -107,6 +107,8 @@ struct mmc_blk_data {
         */
        unsigned int    part_curr;
        struct device_attribute force_ro;
+       struct device_attribute power_ro_lock;
+       int     area_type;
 };
 
 static DEFINE_MUTEX(open_lock);
@@ -119,6 +121,7 @@ enum mmc_blk_status {
        MMC_BLK_ABORT,
        MMC_BLK_DATA_ERR,
        MMC_BLK_ECC_ERR,
+       MMC_BLK_NOMEDIUM,
 };
 
 module_param(perdev_minors, int, 0444);
@@ -165,6 +168,70 @@ static void mmc_blk_put(struct mmc_blk_data *md)
        mutex_unlock(&open_lock);
 }
 
+static ssize_t power_ro_lock_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       int ret;
+       struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+       struct mmc_card *card = md->queue.card;
+       int locked = 0;
+
+       if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
+               locked = 2;
+       else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
+               locked = 1;
+
+       ret = snprintf(buf, PAGE_SIZE, "%d\n", locked);
+
+       return ret;
+}
+
+static ssize_t power_ro_lock_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       struct mmc_blk_data *md, *part_md;
+       struct mmc_card *card;
+       unsigned long set;
+
+       if (kstrtoul(buf, 0, &set))
+               return -EINVAL;
+
+       if (set != 1)
+               return count;
+
+       md = mmc_blk_get(dev_to_disk(dev));
+       card = md->queue.card;
+
+       mmc_claim_host(card->host);
+
+       ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
+                               card->ext_csd.boot_ro_lock |
+                               EXT_CSD_BOOT_WP_B_PWR_WP_EN,
+                               card->ext_csd.part_time);
+       if (ret)
+               pr_err("%s: Locking boot partition ro until next power on failed: %d\n", md->disk->disk_name, ret);
+       else
+               card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
+
+       mmc_release_host(card->host);
+
+       if (!ret) {
+               pr_info("%s: Locking boot partition ro until next power on\n",
+                       md->disk->disk_name);
+               set_disk_ro(md->disk, 1);
+
+               list_for_each_entry(part_md, &md->part, part)
+                       if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) {
+                               pr_info("%s: Locking boot partition ro until next power on\n", part_md->disk->disk_name);
+                               set_disk_ro(part_md->disk, 1);
+                       }
+       }
+
+       mmc_blk_put(md);
+       return count;
+}
+
 static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
@@ -266,6 +333,9 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
                goto idata_err;
        }
 
+       if (!idata->buf_bytes)
+               return idata;
+
        idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL);
        if (!idata->buf) {
                err = -ENOMEM;
@@ -312,25 +382,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
        if (IS_ERR(idata))
                return PTR_ERR(idata);
 
-       cmd.opcode = idata->ic.opcode;
-       cmd.arg = idata->ic.arg;
-       cmd.flags = idata->ic.flags;
-
-       data.sg = &sg;
-       data.sg_len = 1;
-       data.blksz = idata->ic.blksz;
-       data.blocks = idata->ic.blocks;
-
-       sg_init_one(data.sg, idata->buf, idata->buf_bytes);
-
-       if (idata->ic.write_flag)
-               data.flags = MMC_DATA_WRITE;
-       else
-               data.flags = MMC_DATA_READ;
-
-       mrq.cmd = &cmd;
-       mrq.data = &data;
-
        md = mmc_blk_get(bdev->bd_disk);
        if (!md) {
                err = -EINVAL;
@@ -343,6 +394,48 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
                goto cmd_done;
        }
 
+       cmd.opcode = idata->ic.opcode;
+       cmd.arg = idata->ic.arg;
+       cmd.flags = idata->ic.flags;
+
+       if (idata->buf_bytes) {
+               data.sg = &sg;
+               data.sg_len = 1;
+               data.blksz = idata->ic.blksz;
+               data.blocks = idata->ic.blocks;
+
+               sg_init_one(data.sg, idata->buf, idata->buf_bytes);
+
+               if (idata->ic.write_flag)
+                       data.flags = MMC_DATA_WRITE;
+               else
+                       data.flags = MMC_DATA_READ;
+
+               /* data.flags must already be set before doing this. */
+               mmc_set_data_timeout(&data, card);
+
+               /* Allow overriding the timeout_ns for empirical tuning. */
+               if (idata->ic.data_timeout_ns)
+                       data.timeout_ns = idata->ic.data_timeout_ns;
+
+               if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
+                       /*
+                        * Pretend this is a data transfer and rely on the
+                        * host driver to compute timeout.  When all host
+                        * drivers support cmd.cmd_timeout for R1B, this
+                        * can be changed to:
+                        *
+                        *     mrq.data = NULL;
+                        *     cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
+                        */
+                       data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
+               }
+
+               mrq.data = &data;
+       }
+
+       mrq.cmd = &cmd;
+
        mmc_claim_host(card->host);
 
        if (idata->ic.is_acmd) {
@@ -351,24 +444,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
                        goto cmd_rel_host;
        }
 
-       /* data.flags must already be set before doing this. */
-       mmc_set_data_timeout(&data, card);
-       /* Allow overriding the timeout_ns for empirical tuning. */
-       if (idata->ic.data_timeout_ns)
-               data.timeout_ns = idata->ic.data_timeout_ns;
-
-       if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
-               /*
-                * Pretend this is a data transfer and rely on the host driver
-                * to compute timeout.  When all host drivers support
-                * cmd.cmd_timeout for R1B, this can be changed to:
-                *
-                *     mrq.data = NULL;
-                *     cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
-                */
-               data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
-       }
-
        mmc_wait_for_req(card->host, &mrq);
 
        if (cmd.error) {
@@ -565,6 +640,7 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries)
        return err;
 }
 
+#define ERR_NOMEDIUM   3
 #define ERR_RETRY      2
 #define ERR_ABORT      1
 #define ERR_CONTINUE   0
@@ -632,6 +708,9 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
        u32 status, stop_status = 0;
        int err, retry;
 
+       if (mmc_card_removed(card))
+               return ERR_NOMEDIUM;
+
        /*
         * Try to get card status which indicates both the card state
         * and why there was no response.  If the first attempt fails,
@@ -648,8 +727,12 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
        }
 
        /* We couldn't get a response from the card.  Give up. */
-       if (err)
+       if (err) {
+               /* Check if the card is removed */
+               if (mmc_detect_card_removed(card->host))
+                       return ERR_NOMEDIUM;
                return ERR_ABORT;
+       }
 
        /* Flag ECC errors */
        if ((status & R1_CARD_ECC_FAILED) ||
@@ -922,6 +1005,8 @@ static int mmc_blk_err_check(struct mmc_card *card,
                        return MMC_BLK_RETRY;
                case ERR_ABORT:
                        return MMC_BLK_ABORT;
+               case ERR_NOMEDIUM:
+                       return MMC_BLK_NOMEDIUM;
                case ERR_CONTINUE:
                        break;
                }
@@ -1255,6 +1340,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
                        if (!ret)
                                goto start_new_req;
                        break;
+               case MMC_BLK_NOMEDIUM:
+                       goto cmd_abort;
                }
 
                if (ret) {
@@ -1271,6 +1358,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 
  cmd_abort:
        spin_lock_irq(&md->lock);
+       if (mmc_card_removed(card))
+               req->cmd_flags |= REQ_QUIET;
        while (ret)
                ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
        spin_unlock_irq(&md->lock);
@@ -1339,7 +1428,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
                                              struct device *parent,
                                              sector_t size,
                                              bool default_ro,
-                                             const char *subname)
+                                             const char *subname,
+                                             int area_type)
 {
        struct mmc_blk_data *md;
        int devidx, ret;
@@ -1364,11 +1454,12 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
        if (!subname) {
                md->name_idx = find_first_zero_bit(name_use, max_devices);
                __set_bit(md->name_idx, name_use);
-       }
-       else
+       } else
                md->name_idx = ((struct mmc_blk_data *)
                                dev_to_disk(parent)->private_data)->name_idx;
 
+       md->area_type = area_type;
+
        /*
         * Set the read-only status based on the supported commands
         * and the write protect switch.
@@ -1462,7 +1553,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
                size = card->csd.capacity << (card->csd.read_blkbits - 9);
        }
 
-       md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL);
+       md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL,
+                                       MMC_BLK_DATA_AREA_MAIN);
        return md;
 }
 
@@ -1471,13 +1563,14 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
                              unsigned int part_type,
                              sector_t size,
                              bool default_ro,
-                             const char *subname)
+                             const char *subname,
+                             int area_type)
 {
        char cap_str[10];
        struct mmc_blk_data *part_md;
 
        part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
-                                   subname);
+                                   subname, area_type);
        if (IS_ERR(part_md))
                return PTR_ERR(part_md);
        part_md->part_type = part_type;
@@ -1510,7 +1603,8 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
                                card->part[idx].part_cfg,
                                card->part[idx].size >> 9,
                                card->part[idx].force_ro,
-                               card->part[idx].name);
+                               card->part[idx].name,
+                               card->part[idx].area_type);
                        if (ret)
                                return ret;
                }
@@ -1539,9 +1633,16 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 
 static void mmc_blk_remove_req(struct mmc_blk_data *md)
 {
+       struct mmc_card *card;
+
        if (md) {
+               card = md->queue.card;
                if (md->disk->flags & GENHD_FL_UP) {
                        device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+                       if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
+                                       card->ext_csd.boot_ro_lockable)
+                               device_remove_file(disk_to_dev(md->disk),
+                                       &md->power_ro_lock);
 
                        /* Stop new requests from getting into the queue */
                        del_gendisk(md->disk);
@@ -1570,6 +1671,7 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
 static int mmc_add_disk(struct mmc_blk_data *md)
 {
        int ret;
+       struct mmc_card *card = md->queue.card;
 
        add_disk(md->disk);
        md->force_ro.show = force_ro_show;
@@ -1579,18 +1681,53 @@ static int mmc_add_disk(struct mmc_blk_data *md)
        md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
        ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
        if (ret)
-               del_gendisk(md->disk);
+               goto force_ro_fail;
+
+       if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
+            card->ext_csd.boot_ro_lockable) {
+               mode_t mode;
+
+               if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
+                       mode = S_IRUGO;
+               else
+                       mode = S_IRUGO | S_IWUSR;
+
+               md->power_ro_lock.show = power_ro_lock_show;
+               md->power_ro_lock.store = power_ro_lock_store;
+               md->power_ro_lock.attr.mode = mode;
+               md->power_ro_lock.attr.name =
+                                       "ro_lock_until_next_power_on";
+               ret = device_create_file(disk_to_dev(md->disk),
+                               &md->power_ro_lock);
+               if (ret)
+                       goto power_ro_lock_fail;
+       }
+       return ret;
+
+power_ro_lock_fail:
+       device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+force_ro_fail:
+       del_gendisk(md->disk);
 
        return ret;
 }
 
+#define CID_MANFID_SANDISK     0x2
+#define CID_MANFID_TOSHIBA     0x11
+#define CID_MANFID_MICRON      0x13
+
 static const struct mmc_fixup blk_fixups[] =
 {
-       MMC_FIXUP("SEM02G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
-       MMC_FIXUP("SEM04G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
-       MMC_FIXUP("SEM08G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
-       MMC_FIXUP("SEM16G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
-       MMC_FIXUP("SEM32G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
 
        /*
         * Some MMC cards experience performance degradation with CMD23
@@ -1600,18 +1737,18 @@ static const struct mmc_fixup blk_fixups[] =
         *
         * N.B. This doesn't affect SD cards.
         */
-       MMC_FIXUP("MMC08G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+       MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
                  MMC_QUIRK_BLK_NO_CMD23),
-       MMC_FIXUP("MMC16G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+       MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
                  MMC_QUIRK_BLK_NO_CMD23),
-       MMC_FIXUP("MMC32G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+       MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
                  MMC_QUIRK_BLK_NO_CMD23),
 
        /*
         * Some Micron MMC cards needs longer data read timeout than
         * indicated in CSD.
         */
-       MMC_FIXUP(CID_NAME_ANY, 0x13, 0x200, add_quirk_mmc,
+       MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc,
                  MMC_QUIRK_LONG_READ_TIME),
 
        END_FIXUP
index e99bdc18002df76b09b54e269714401596419f7c..759714ed6bee8f791b2cbd4a5959f2ca12d7e9ec 100644 (file)
@@ -1581,6 +1581,7 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
 
        t->max_segs = test->card->host->max_segs;
        t->max_seg_sz = test->card->host->max_seg_size;
+       t->max_seg_sz -= t->max_seg_sz % 512;
 
        t->max_tfr = t->max_sz;
        if (t->max_tfr >> 9 > test->card->host->max_blk_count)
index dcad59cbfef11a873b0dfa49ef9dcd4e8fcf1d83..2517547b4366a9bbdc6eea69ce1f1dc35ef09f08 100644 (file)
@@ -29,6 +29,8 @@
  */
 static int mmc_prep_request(struct request_queue *q, struct request *req)
 {
+       struct mmc_queue *mq = q->queuedata;
+
        /*
         * We only like normal block requests and discards.
         */
@@ -37,6 +39,9 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
                return BLKPREP_KILL;
        }
 
+       if (mq && mmc_card_removed(mq->card))
+               return BLKPREP_KILL;
+
        req->cmd_flags |= REQ_DONTPREP;
 
        return BLKPREP_OK;
index 639501970b412c7315c4d516da44aa9bf930a203..dca4428380f15c53adf73ce79810e7e26c0543f9 100644 (file)
@@ -7,6 +7,6 @@ mmc_core-y                      := core.o bus.o host.o \
                                   mmc.o mmc_ops.o sd.o sd_ops.o \
                                   sdio.o sdio_ops.o sdio_bus.o \
                                   sdio_cis.o sdio_io.o sdio_irq.o \
-                                  quirks.o
+                                  quirks.o cd-gpio.o
 
 mmc_core-$(CONFIG_DEBUG_FS)    += debugfs.o
index 6be49249895a21bab3c06cd4bc658f347ed99124..5d011a39dfff3b68a88813e202c76a4722fa3c57 100644 (file)
@@ -303,10 +303,11 @@ int mmc_add_card(struct mmc_card *card)
                        mmc_card_ddr_mode(card) ? "DDR " : "",
                        type);
        } else {
-               printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
+               pr_info("%s: new %s%s%s%s card at address %04x\n",
                        mmc_hostname(card->host),
-                       mmc_sd_card_uhs(card) ? "ultra high speed " :
+                       mmc_card_uhs(card) ? "ultra high speed " :
                        (mmc_card_highspeed(card) ? "high speed " : ""),
+                       (mmc_card_hs200(card) ? "HS200 " : ""),
                        mmc_card_ddr_mode(card) ? "DDR " : "",
                        type, card->rca);
        }
diff --git a/drivers/mmc/core/cd-gpio.c b/drivers/mmc/core/cd-gpio.c
new file mode 100644 (file)
index 0000000..082202a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Generic GPIO card-detect helper
+ *
+ * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+struct mmc_cd_gpio {
+       unsigned int gpio;
+       char label[0];
+};
+
+static irqreturn_t mmc_cd_gpio_irqt(int irq, void *dev_id)
+{
+       /* Schedule a card detection after a debounce timeout */
+       mmc_detect_change(dev_id, msecs_to_jiffies(100));
+       return IRQ_HANDLED;
+}
+
+int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio,
+                       unsigned int irq, unsigned long flags)
+{
+       size_t len = strlen(dev_name(host->parent)) + 4;
+       struct mmc_cd_gpio *cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL);
+       int ret;
+
+       if (!cd)
+               return -ENOMEM;
+
+       snprintf(cd->label, len, "%s cd", dev_name(host->parent));
+
+       ret = gpio_request_one(gpio, GPIOF_DIR_IN, cd->label);
+       if (ret < 0)
+               goto egpioreq;
+
+       ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt,
+                                  flags, cd->label, host);
+       if (ret < 0)
+               goto eirqreq;
+
+       cd->gpio = gpio;
+       host->hotplug.irq = irq;
+       host->hotplug.handler_priv = cd;
+
+       return 0;
+
+eirqreq:
+       gpio_free(gpio);
+egpioreq:
+       kfree(cd);
+       return ret;
+}
+EXPORT_SYMBOL(mmc_cd_gpio_request);
+
+void mmc_cd_gpio_free(struct mmc_host *host)
+{
+       struct mmc_cd_gpio *cd = host->hotplug.handler_priv;
+
+       free_irq(host->hotplug.irq, host);
+       gpio_free(cd->gpio);
+       kfree(cd);
+}
+EXPORT_SYMBOL(mmc_cd_gpio_free);
index 950b97d7412a4f6f5f562401f132ed0d568a969a..f545a3e6eb80587fa3995bbf1413e68b205c9cdf 100644 (file)
@@ -48,7 +48,7 @@ static struct workqueue_struct *workqueue;
  * performance cost, and for other reasons may not always be desired.
  * So we allow it it to be disabled.
  */
-int use_spi_crc = 1;
+bool use_spi_crc = 1;
 module_param(use_spi_crc, bool, 0);
 
 /*
@@ -58,9 +58,9 @@ module_param(use_spi_crc, bool, 0);
  * overridden if necessary.
  */
 #ifdef CONFIG_MMC_UNSAFE_RESUME
-int mmc_assume_removable;
+bool mmc_assume_removable;
 #else
-int mmc_assume_removable = 1;
+bool mmc_assume_removable = 1;
 #endif
 EXPORT_SYMBOL(mmc_assume_removable);
 module_param_named(removable, mmc_assume_removable, bool, 0644);
@@ -140,7 +140,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
                        cmd->retries = 0;
        }
 
-       if (err && cmd->retries) {
+       if (err && cmd->retries && !mmc_card_removed(host->card)) {
                /*
                 * Request starter must handle retries - see
                 * mmc_wait_for_req_done().
@@ -247,6 +247,11 @@ static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
 {
        init_completion(&mrq->completion);
        mrq->done = mmc_wait_done;
+       if (mmc_card_removed(host->card)) {
+               mrq->cmd->error = -ENOMEDIUM;
+               complete(&mrq->completion);
+               return;
+       }
        mmc_start_request(host, mrq);
 }
 
@@ -259,7 +264,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
                wait_for_completion(&mrq->completion);
 
                cmd = mrq->cmd;
-               if (!cmd->error || !cmd->retries)
+               if (!cmd->error || !cmd->retries ||
+                   mmc_card_removed(host->card))
                        break;
 
                pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
@@ -1456,7 +1462,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
        WARN_ON(host->removed);
        spin_unlock_irqrestore(&host->lock, flags);
 #endif
-
+       host->detect_change = 1;
        mmc_schedule_delayed_work(&host->detect, delay);
 }
 
@@ -2049,6 +2055,43 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
        return -EIO;
 }
 
+int _mmc_detect_card_removed(struct mmc_host *host)
+{
+       int ret;
+
+       if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive)
+               return 0;
+
+       if (!host->card || mmc_card_removed(host->card))
+               return 1;
+
+       ret = host->bus_ops->alive(host);
+       if (ret) {
+               mmc_card_set_removed(host->card);
+               pr_debug("%s: card remove detected\n", mmc_hostname(host));
+       }
+
+       return ret;
+}
+
+int mmc_detect_card_removed(struct mmc_host *host)
+{
+       struct mmc_card *card = host->card;
+
+       WARN_ON(!host->claimed);
+       /*
+        * The card will be considered unchanged unless we have been asked to
+        * detect a change or host requires polling to provide card detection.
+        */
+       if (card && !host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
+               return mmc_card_removed(card);
+
+       host->detect_change = 0;
+
+       return _mmc_detect_card_removed(host);
+}
+EXPORT_SYMBOL(mmc_detect_card_removed);
+
 void mmc_rescan(struct work_struct *work)
 {
        static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
@@ -2069,6 +2112,8 @@ void mmc_rescan(struct work_struct *work)
            && !(host->caps & MMC_CAP_NONREMOVABLE))
                host->bus_ops->detect(host);
 
+       host->detect_change = 0;
+
        /*
         * Let mmc_bus_put() free the bus/bus_ops if we've found that
         * the card is no longer present.
@@ -2130,6 +2175,7 @@ void mmc_stop_host(struct mmc_host *host)
 
        mmc_bus_get(host);
        if (host->bus_ops && !host->bus_dead) {
+               /* Calling bus_ops->remove() with a claimed host can deadlock */
                if (host->bus_ops->remove)
                        host->bus_ops->remove(host);
 
@@ -2201,6 +2247,9 @@ int mmc_card_awake(struct mmc_host *host)
 {
        int err = -ENOSYS;
 
+       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
+               return 0;
+
        mmc_bus_get(host);
 
        if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
@@ -2216,6 +2265,9 @@ int mmc_card_sleep(struct mmc_host *host)
 {
        int err = -ENOSYS;
 
+       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
+               return 0;
+
        mmc_bus_get(host);
 
        if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep)
@@ -2270,6 +2322,7 @@ EXPORT_SYMBOL(mmc_flush_cache);
 int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
 {
        struct mmc_card *card = host->card;
+       unsigned int timeout;
        int err = 0;
 
        if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
@@ -2280,16 +2333,18 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
                        (card->ext_csd.cache_size > 0)) {
                enable = !!enable;
 
-               if (card->ext_csd.cache_ctrl ^ enable)
+               if (card->ext_csd.cache_ctrl ^ enable) {
+                       timeout = enable ? card->ext_csd.generic_cmd6_time : 0;
                        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                       EXT_CSD_CACHE_CTRL, enable, 0);
-               if (err)
-                       pr_err("%s: cache %s error %d\n",
-                                       mmc_hostname(card->host),
-                                       enable ? "on" : "off",
-                                       err);
-               else
-                       card->ext_csd.cache_ctrl = enable;
+                                       EXT_CSD_CACHE_CTRL, enable, timeout);
+                       if (err)
+                               pr_err("%s: cache %s error %d\n",
+                                               mmc_hostname(card->host),
+                                               enable ? "on" : "off",
+                                               err);
+                       else
+                               card->ext_csd.cache_ctrl = enable;
+               }
        }
 
        return err;
@@ -2310,7 +2365,13 @@ int mmc_suspend_host(struct mmc_host *host)
                cancel_delayed_work(&host->disable);
        cancel_delayed_work(&host->detect);
        mmc_flush_scheduled_work();
-       err = mmc_cache_ctrl(host, 0);
+       if (mmc_try_claim_host(host)) {
+               err = mmc_cache_ctrl(host, 0);
+               mmc_do_release_host(host);
+       } else {
+               err = -EBUSY;
+       }
+
        if (err)
                goto out;
 
@@ -2338,7 +2399,9 @@ int mmc_suspend_host(struct mmc_host *host)
                        if (err == -ENOSYS || !host->bus_ops->resume) {
                                /*
                                 * We simply "remove" the card in this case.
-                                * It will be redetected on resume.
+                                * It will be redetected on resume.  (Calling
+                                * bus_ops->remove() with a claimed host can
+                                * deadlock.)
                                 */
                                if (host->bus_ops->remove)
                                        host->bus_ops->remove(host);
@@ -2431,11 +2494,11 @@ int mmc_pm_notify(struct notifier_block *notify_block,
                if (!host->bus_ops || host->bus_ops->suspend)
                        break;
 
-               mmc_claim_host(host);
-
+               /* Calling bus_ops->remove() with a claimed host can deadlock */
                if (host->bus_ops->remove)
                        host->bus_ops->remove(host);
 
+               mmc_claim_host(host);
                mmc_detach_bus(host);
                mmc_power_off(host);
                mmc_release_host(host);
index 14664f1fb16fb560c526dd30817cc10ae6db1adf..3bdafbca354f4ecdce7f4db56ce9baf82ba11cbb 100644 (file)
@@ -24,6 +24,7 @@ struct mmc_bus_ops {
        int (*resume)(struct mmc_host *);
        int (*power_save)(struct mmc_host *);
        int (*power_restore)(struct mmc_host *);
+       int (*alive)(struct mmc_host *);
 };
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -59,12 +60,14 @@ void mmc_rescan(struct work_struct *work);
 void mmc_start_host(struct mmc_host *host);
 void mmc_stop_host(struct mmc_host *host);
 
+int _mmc_detect_card_removed(struct mmc_host *host);
+
 int mmc_attach_mmc(struct mmc_host *host);
 int mmc_attach_sd(struct mmc_host *host);
 int mmc_attach_sdio(struct mmc_host *host);
 
 /* Module parameters */
-extern int use_spi_crc;
+extern bool use_spi_crc;
 
 /* Debugfs information for hosts and cards */
 void mmc_add_host_debugfs(struct mmc_host *host);
index 3923880118b64d0519d7eb00d084e9709b271b59..9ab5b17d488ae45f63756a43bfe8917e88b52e86 100644 (file)
@@ -57,6 +57,8 @@ static int mmc_ios_show(struct seq_file *s, void *data)
        const char *str;
 
        seq_printf(s, "clock:\t\t%u Hz\n", ios->clock);
+       if (host->actual_clock)
+               seq_printf(s, "actual clock:\t%u Hz\n", host->actual_clock);
        seq_printf(s, "vdd:\t\t%u ", ios->vdd);
        if ((1 << ios->vdd) & MMC_VDD_165_195)
                seq_printf(s, "(1.65 - 1.95 V)\n");
@@ -133,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
        case MMC_TIMING_UHS_DDR50:
                str = "sd uhs DDR50";
                break;
+       case MMC_TIMING_MMC_HS200:
+               str = "mmc high-speed SDR200";
+               break;
        default:
                str = "invalid";
                break;
index d31c78b72b0fd8d1e53adb2f403454790896fafe..30055f2b0d445b3e0c08ed131f939146fef68626 100644 (file)
@@ -54,6 +54,27 @@ static DEFINE_IDR(mmc_host_idr);
 static DEFINE_SPINLOCK(mmc_host_lock);
 
 #ifdef CONFIG_MMC_CLKGATE
+static ssize_t clkgate_delay_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct mmc_host *host = cls_dev_to_mmc_host(dev);
+       return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay);
+}
+
+static ssize_t clkgate_delay_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct mmc_host *host = cls_dev_to_mmc_host(dev);
+       unsigned long flags, value;
+
+       if (kstrtoul(buf, 0, &value))
+               return -EINVAL;
+
+       spin_lock_irqsave(&host->clk_lock, flags);
+       host->clkgate_delay = value;
+       spin_unlock_irqrestore(&host->clk_lock, flags);
+       return count;
+}
 
 /*
  * Enabling clock gating will make the core call out to the host
@@ -114,7 +135,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host)
 static void mmc_host_clk_gate_work(struct work_struct *work)
 {
        struct mmc_host *host = container_of(work, struct mmc_host,
-                                             clk_gate_work);
+                                             clk_gate_work.work);
 
        mmc_host_clk_gate_delayed(host);
 }
@@ -131,6 +152,8 @@ void mmc_host_clk_hold(struct mmc_host *host)
 {
        unsigned long flags;
 
+       /* cancel any clock gating work scheduled by mmc_host_clk_release() */
+       cancel_delayed_work_sync(&host->clk_gate_work);
        mutex_lock(&host->clk_gate_mutex);
        spin_lock_irqsave(&host->clk_lock, flags);
        if (host->clk_gated) {
@@ -180,7 +203,8 @@ void mmc_host_clk_release(struct mmc_host *host)
        host->clk_requests--;
        if (mmc_host_may_gate_card(host->card) &&
            !host->clk_requests)
-               queue_work(system_nrt_wq, &host->clk_gate_work);
+               queue_delayed_work(system_nrt_wq, &host->clk_gate_work,
+                               msecs_to_jiffies(host->clkgate_delay));
        spin_unlock_irqrestore(&host->clk_lock, flags);
 }
 
@@ -213,8 +237,13 @@ static inline void mmc_host_clk_init(struct mmc_host *host)
        host->clk_requests = 0;
        /* Hold MCI clock for 8 cycles by default */
        host->clk_delay = 8;
+       /*
+        * Default clock gating delay is 200ms.
+        * This value can be tuned by writing into sysfs entry.
+        */
+       host->clkgate_delay = 200;
        host->clk_gated = false;
-       INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
+       INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
        spin_lock_init(&host->clk_lock);
        mutex_init(&host->clk_gate_mutex);
 }
@@ -229,7 +258,7 @@ static inline void mmc_host_clk_exit(struct mmc_host *host)
         * Wait for any outstanding gate and then make sure we're
         * ungated before exiting.
         */
-       if (cancel_work_sync(&host->clk_gate_work))
+       if (cancel_delayed_work_sync(&host->clk_gate_work))
                mmc_host_clk_gate_delayed(host);
        if (host->clk_gated)
                mmc_host_clk_hold(host);
@@ -237,6 +266,17 @@ static inline void mmc_host_clk_exit(struct mmc_host *host)
        WARN_ON(host->clk_requests > 1);
 }
 
+static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
+{
+       host->clkgate_delay_attr.show = clkgate_delay_show;
+       host->clkgate_delay_attr.store = clkgate_delay_store;
+       sysfs_attr_init(&host->clkgate_delay_attr.attr);
+       host->clkgate_delay_attr.attr.name = "clkgate_delay";
+       host->clkgate_delay_attr.attr.mode = S_IRUGO | S_IWUSR;
+       if (device_create_file(&host->class_dev, &host->clkgate_delay_attr))
+               pr_err("%s: Failed to create clkgate_delay sysfs entry\n",
+                               mmc_hostname(host));
+}
 #else
 
 static inline void mmc_host_clk_init(struct mmc_host *host)
@@ -247,6 +287,10 @@ static inline void mmc_host_clk_exit(struct mmc_host *host)
 {
 }
 
+static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
+{
+}
+
 #endif
 
 /**
@@ -335,6 +379,7 @@ int mmc_add_host(struct mmc_host *host)
 #ifdef CONFIG_DEBUG_FS
        mmc_add_host_debugfs(host);
 #endif
+       mmc_host_clk_sysfs_init(host);
 
        mmc_start_host(host);
        register_pm_notifier(&host->pm_notify);
index d240427c12462dd545b233d6d6e75787e4b48abb..59b9ba52e66a1fb420ae26f7da3350b0c8d1d592 100644 (file)
@@ -286,6 +286,27 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
        }
        card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
        switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
+       case EXT_CSD_CARD_TYPE_SDR_ALL:
+       case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
+       case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
+       case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
+               card->ext_csd.hs_max_dtr = 200000000;
+               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
+               break;
+       case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
+       case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
+       case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
+       case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
+               card->ext_csd.hs_max_dtr = 200000000;
+               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
+               break;
+       case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
+       case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
+       case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
+       case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
+               card->ext_csd.hs_max_dtr = 200000000;
+               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
+               break;
        case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
             EXT_CSD_CARD_TYPE_26:
                card->ext_csd.hs_max_dtr = 52000000;
@@ -348,7 +369,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                                part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
                                mmc_part_add(card, part_size,
                                        EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx,
-                                       "boot%d", idx, true);
+                                       "boot%d", idx, true,
+                                       MMC_BLK_DATA_AREA_BOOT);
                        }
                }
        }
@@ -435,7 +457,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                                        hc_wp_grp_sz);
                                mmc_part_add(card, part_size << 19,
                                        EXT_CSD_PART_CONFIG_ACC_GP0 + idx,
-                                       "gp%d", idx, false);
+                                       "gp%d", idx, false,
+                                       MMC_BLK_DATA_AREA_GP);
                        }
                }
                card->ext_csd.sec_trim_mult =
@@ -446,6 +469,14 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                        ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
                card->ext_csd.trim_timeout = 300 *
                        ext_csd[EXT_CSD_TRIM_MULT];
+
+               /*
+                * Note that the call to mmc_part_add above defaults to read
+                * only. If this default assumption is changed, the call must
+                * take into account the value of boot_locked below.
+                */
+               card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP];
+               card->ext_csd.boot_ro_lockable = true;
        }
 
        if (card->ext_csd.rev >= 5) {
@@ -689,6 +720,79 @@ static int mmc_select_powerclass(struct mmc_card *card,
        return err;
 }
 
+/*
+ * Selects the desired buswidth and switch to the HS200 mode
+ * if bus width set without error
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+       int idx, err = 0;
+       struct mmc_host *host;
+       static unsigned ext_csd_bits[] = {
+               EXT_CSD_BUS_WIDTH_4,
+               EXT_CSD_BUS_WIDTH_8,
+       };
+       static unsigned bus_widths[] = {
+               MMC_BUS_WIDTH_4,
+               MMC_BUS_WIDTH_8,
+       };
+
+       BUG_ON(!card);
+
+       host = card->host;
+
+       if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
+           host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
+               if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0))
+                       err = mmc_set_signal_voltage(host,
+                                                    MMC_SIGNAL_VOLTAGE_180, 0);
+
+       /* If fails try again during next card power cycle */
+       if (err)
+               goto err;
+
+       idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+
+       /*
+        * Unlike SD, MMC cards dont have a configuration register to notify
+        * supported bus width. So bus test command should be run to identify
+        * the supported bus width or compare the ext csd values of current
+        * bus width and ext csd values of 1 bit mode read earlier.
+        */
+       for (; idx >= 0; idx--) {
+
+               /*
+                * Host is capable of 8bit transfer, then switch
+                * the device to work in 8bit transfer mode. If the
+                * mmc switch command returns error then switch to
+                * 4bit transfer mode. On success set the corresponding
+                * bus width on the host.
+                */
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                EXT_CSD_BUS_WIDTH,
+                                ext_csd_bits[idx],
+                                card->ext_csd.generic_cmd6_time);
+               if (err)
+                       continue;
+
+               mmc_set_bus_width(card->host, bus_widths[idx]);
+
+               if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
+                       err = mmc_compare_ext_csds(card, bus_widths[idx]);
+               else
+                       err = mmc_bus_test(card, bus_widths[idx]);
+               if (!err)
+                       break;
+       }
+
+       /* switch to HS200 mode if bus width set successfully */
+       if (!err)
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                EXT_CSD_HS_TIMING, 2, 0);
+err:
+       return err;
+}
+
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -895,11 +999,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        /*
         * Activate high speed (if supported)
         */
-       if ((card->ext_csd.hs_max_dtr != 0) &&
-               (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
-               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                EXT_CSD_HS_TIMING, 1,
-                                card->ext_csd.generic_cmd6_time);
+       if (card->ext_csd.hs_max_dtr != 0) {
+               err = 0;
+               if (card->ext_csd.hs_max_dtr > 52000000 &&
+                   host->caps2 & MMC_CAP2_HS200)
+                       err = mmc_select_hs200(card);
+               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
+                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                        EXT_CSD_HS_TIMING, 1, 0);
+
                if (err && err != -EBADMSG)
                        goto free_card;
 
@@ -908,8 +1016,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                               mmc_hostname(card->host));
                        err = 0;
                } else {
-                       mmc_card_set_highspeed(card);
-                       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+                       if (card->ext_csd.hs_max_dtr > 52000000 &&
+                           host->caps2 & MMC_CAP2_HS200) {
+                               mmc_card_set_hs200(card);
+                               mmc_set_timing(card->host,
+                                              MMC_TIMING_MMC_HS200);
+                       } else {
+                               mmc_card_set_highspeed(card);
+                               mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+                       }
                }
        }
 
@@ -934,7 +1049,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         */
        max_dtr = (unsigned int)-1;
 
-       if (mmc_card_highspeed(card)) {
+       if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
                if (max_dtr > card->ext_csd.hs_max_dtr)
                        max_dtr = card->ext_csd.hs_max_dtr;
        } else if (max_dtr > card->csd.max_dtr) {
@@ -959,10 +1074,49 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                                ddr = MMC_1_2V_DDR_MODE;
        }
 
+       /*
+        * Indicate HS200 SDR mode (if supported).
+        */
+       if (mmc_card_hs200(card)) {
+               u32 ext_csd_bits;
+               u32 bus_width = card->host->ios.bus_width;
+
+               /*
+                * For devices supporting HS200 mode, the bus width has
+                * to be set before executing the tuning function. If
+                * set before tuning, then device will respond with CRC
+                * errors for responses on CMD line. So for HS200 the
+                * sequence will be
+                * 1. set bus width 4bit / 8 bit (1 bit not supported)
+                * 2. switch to HS200 mode
+                * 3. set the clock to > 52Mhz <=200MHz and
+                * 4. execute tuning for HS200
+                */
+               if ((host->caps2 & MMC_CAP2_HS200) &&
+                   card->host->ops->execute_tuning)
+                       err = card->host->ops->execute_tuning(card->host,
+                               MMC_SEND_TUNING_BLOCK_HS200);
+               if (err) {
+                       pr_warning("%s: tuning execution failed\n",
+                                  mmc_hostname(card->host));
+                       goto err;
+               }
+
+               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+                               EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
+               err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
+               if (err) {
+                       pr_err("%s: power class selection to bus width %d failed\n",
+                               mmc_hostname(card->host), 1 << bus_width);
+                       goto err;
+               }
+       }
+
        /*
         * Activate wide bus and DDR (if supported).
         */
-       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
+       if (!mmc_card_hs200(card) &&
+           (card->csd.mmca_vsn >= CSD_SPEC_VER_3) &&
            (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
                static unsigned ext_csd_bits[][2] = {
                        { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
@@ -1048,7 +1202,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                         *
                         * WARNING: eMMC rules are NOT the same as SD DDR
                         */
-                       if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) {
+                       if (ddr == MMC_1_2V_DDR_MODE) {
                                err = mmc_set_signal_voltage(host,
                                        MMC_SIGNAL_VOLTAGE_120, 0);
                                if (err)
@@ -1067,14 +1221,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
                        card->ext_csd.cache_size > 0) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                               EXT_CSD_CACHE_CTRL, 1, 0);
+                               EXT_CSD_CACHE_CTRL, 1,
+                               card->ext_csd.generic_cmd6_time);
                if (err && err != -EBADMSG)
                        goto free_card;
 
                /*
                 * Only if no error, cache is turned on successfully.
                 */
-               card->ext_csd.cache_ctrl = err ? 0 : 1;
+               if (err) {
+                       pr_warning("%s: Cache is supported, "
+                                       "but failed to turn on (%d)\n",
+                                       mmc_hostname(card->host), err);
+                       card->ext_csd.cache_ctrl = 0;
+                       err = 0;
+               } else {
+                       card->ext_csd.cache_ctrl = 1;
+               }
        }
 
        if (!oldcard)
@@ -1104,6 +1267,14 @@ static void mmc_remove(struct mmc_host *host)
        host->card = NULL;
 }
 
+/*
+ * Card detection - card is alive.
+ */
+static int mmc_alive(struct mmc_host *host)
+{
+       return mmc_send_status(host->card, NULL);
+}
+
 /*
  * Card detection callback from host.
  */
@@ -1119,7 +1290,7 @@ static void mmc_detect(struct mmc_host *host)
        /*
         * Just check if our card has been removed.
         */
-       err = mmc_send_status(host->card, NULL);
+       err = _mmc_detect_card_removed(host);
 
        mmc_release_host(host);
 
@@ -1224,6 +1395,7 @@ static const struct mmc_bus_ops mmc_ops = {
        .suspend = NULL,
        .resume = NULL,
        .power_restore = mmc_power_restore,
+       .alive = mmc_alive,
 };
 
 static const struct mmc_bus_ops mmc_ops_unsafe = {
@@ -1234,6 +1406,7 @@ static const struct mmc_bus_ops mmc_ops_unsafe = {
        .suspend = mmc_suspend,
        .resume = mmc_resume,
        .power_restore = mmc_power_restore,
+       .alive = mmc_alive,
 };
 
 static void mmc_attach_bus_ops(struct mmc_host *host)
index f2a05ea40f2a3ed705e220fd5216d508d538b033..c63ad03c29c7ff61065ec64d66ae28eeb90884cc 100644 (file)
@@ -307,8 +307,8 @@ static int mmc_read_switch(struct mmc_card *card)
                goto out;
        }
 
-       if (status[13] & UHS_SDR50_BUS_SPEED)
-               card->sw_caps.hs_max_dtr = 50000000;
+       if (status[13] & SD_MODE_HIGH_SPEED)
+               card->sw_caps.hs_max_dtr = HIGH_SPEED_MAX_DTR;
 
        if (card->scr.sda_spec3) {
                card->sw_caps.sd3_bus_mode = status[13];
@@ -661,7 +661,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
 
        /* SPI mode doesn't define CMD19 */
        if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
-               err = card->host->ops->execute_tuning(card->host);
+               err = card->host->ops->execute_tuning(card->host,
+                                                     MMC_SEND_TUNING_BLOCK);
 
 out:
        kfree(status);
@@ -960,7 +961,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
                        goto free_card;
 
                /* Card is an ultra-high-speed card */
-               mmc_sd_card_set_uhs(card);
+               mmc_card_set_uhs(card);
 
                /*
                 * Since initialization is now complete, enable preset
@@ -1018,6 +1019,14 @@ static void mmc_sd_remove(struct mmc_host *host)
        host->card = NULL;
 }
 
+/*
+ * Card detection - card is alive.
+ */
+static int mmc_sd_alive(struct mmc_host *host)
+{
+       return mmc_send_status(host->card, NULL);
+}
+
 /*
  * Card detection callback from host.
  */
@@ -1033,7 +1042,7 @@ static void mmc_sd_detect(struct mmc_host *host)
        /*
         * Just check if our card has been removed.
         */
-       err = mmc_send_status(host->card, NULL);
+       err = _mmc_detect_card_removed(host);
 
        mmc_release_host(host);
 
@@ -1102,6 +1111,7 @@ static const struct mmc_bus_ops mmc_sd_ops = {
        .suspend = NULL,
        .resume = NULL,
        .power_restore = mmc_sd_power_restore,
+       .alive = mmc_sd_alive,
 };
 
 static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
@@ -1110,6 +1120,7 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
        .suspend = mmc_sd_suspend,
        .resume = mmc_sd_resume,
        .power_restore = mmc_sd_power_restore,
+       .alive = mmc_sd_alive,
 };
 
 static void mmc_sd_attach_bus_ops(struct mmc_host *host)
index 3ab565e32a6aca624d6f462879a0c19b7cae7697..bd7bacc950dc03b386d2a6907aff047f870bc14d 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
@@ -102,6 +103,7 @@ static int sdio_read_cccr(struct mmc_card *card)
        int ret;
        int cccr_vsn;
        unsigned char data;
+       unsigned char speed;
 
        memset(&card->cccr, 0, sizeof(struct sdio_cccr));
 
@@ -140,12 +142,60 @@ static int sdio_read_cccr(struct mmc_card *card)
        }
 
        if (cccr_vsn >= SDIO_CCCR_REV_1_20) {
-               ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data);
+               ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
                if (ret)
                        goto out;
 
-               if (data & SDIO_SPEED_SHS)
-                       card->cccr.high_speed = 1;
+               card->scr.sda_spec3 = 0;
+               card->sw_caps.sd3_bus_mode = 0;
+               card->sw_caps.sd3_drv_type = 0;
+               if (cccr_vsn >= SDIO_CCCR_REV_3_00) {
+                       card->scr.sda_spec3 = 1;
+                       ret = mmc_io_rw_direct(card, 0, 0,
+                               SDIO_CCCR_UHS, 0, &data);
+                       if (ret)
+                               goto out;
+
+                       if (card->host->caps &
+                               (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+                                MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
+                                MMC_CAP_UHS_DDR50)) {
+                               if (data & SDIO_UHS_DDR50)
+                                       card->sw_caps.sd3_bus_mode
+                                               |= SD_MODE_UHS_DDR50;
+
+                               if (data & SDIO_UHS_SDR50)
+                                       card->sw_caps.sd3_bus_mode
+                                               |= SD_MODE_UHS_SDR50;
+
+                               if (data & SDIO_UHS_SDR104)
+                                       card->sw_caps.sd3_bus_mode
+                                               |= SD_MODE_UHS_SDR104;
+                       }
+
+                       ret = mmc_io_rw_direct(card, 0, 0,
+                               SDIO_CCCR_DRIVE_STRENGTH, 0, &data);
+                       if (ret)
+                               goto out;
+
+                       if (data & SDIO_DRIVE_SDTA)
+                               card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_A;
+                       if (data & SDIO_DRIVE_SDTC)
+                               card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C;
+                       if (data & SDIO_DRIVE_SDTD)
+                               card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D;
+               }
+
+               /* if no uhs mode ensure we check for high speed */
+               if (!card->sw_caps.sd3_bus_mode) {
+                       if (speed & SDIO_SPEED_SHS) {
+                               card->cccr.high_speed = 1;
+                               card->sw_caps.hs_max_dtr = 50000000;
+                       } else {
+                               card->cccr.high_speed = 0;
+                               card->sw_caps.hs_max_dtr = 25000000;
+                       }
+               }
        }
 
 out:
@@ -327,6 +377,194 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
        return max_dtr;
 }
 
+static unsigned char host_drive_to_sdio_drive(int host_strength)
+{
+       switch (host_strength) {
+       case MMC_SET_DRIVER_TYPE_A:
+               return SDIO_DTSx_SET_TYPE_A;
+       case MMC_SET_DRIVER_TYPE_B:
+               return SDIO_DTSx_SET_TYPE_B;
+       case MMC_SET_DRIVER_TYPE_C:
+               return SDIO_DTSx_SET_TYPE_C;
+       case MMC_SET_DRIVER_TYPE_D:
+               return SDIO_DTSx_SET_TYPE_D;
+       default:
+               return SDIO_DTSx_SET_TYPE_B;
+       }
+}
+
+static void sdio_select_driver_type(struct mmc_card *card)
+{
+       int host_drv_type = SD_DRIVER_TYPE_B;
+       int card_drv_type = SD_DRIVER_TYPE_B;
+       int drive_strength;
+       unsigned char card_strength;
+       int err;
+
+       /*
+        * If the host doesn't support any of the Driver Types A,C or D,
+        * or there is no board specific handler then default Driver
+        * Type B is used.
+        */
+       if (!(card->host->caps &
+               (MMC_CAP_DRIVER_TYPE_A |
+                MMC_CAP_DRIVER_TYPE_C |
+                MMC_CAP_DRIVER_TYPE_D)))
+               return;
+
+       if (!card->host->ops->select_drive_strength)
+               return;
+
+       if (card->host->caps & MMC_CAP_DRIVER_TYPE_A)
+               host_drv_type |= SD_DRIVER_TYPE_A;
+
+       if (card->host->caps & MMC_CAP_DRIVER_TYPE_C)
+               host_drv_type |= SD_DRIVER_TYPE_C;
+
+       if (card->host->caps & MMC_CAP_DRIVER_TYPE_D)
+               host_drv_type |= SD_DRIVER_TYPE_D;
+
+       if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
+               card_drv_type |= SD_DRIVER_TYPE_A;
+
+       if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
+               card_drv_type |= SD_DRIVER_TYPE_C;
+
+       if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_D)
+               card_drv_type |= SD_DRIVER_TYPE_D;
+
+       /*
+        * The drive strength that the hardware can support
+        * depends on the board design.  Pass the appropriate
+        * information and let the hardware specific code
+        * return what is possible given the options
+        */
+       drive_strength = card->host->ops->select_drive_strength(
+               card->sw_caps.uhs_max_dtr,
+               host_drv_type, card_drv_type);
+
+       /* if error just use default for drive strength B */
+       err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0,
+               &card_strength);
+       if (err)
+               return;
+
+       card_strength &= ~(SDIO_DRIVE_DTSx_MASK<<SDIO_DRIVE_DTSx_SHIFT);
+       card_strength |= host_drive_to_sdio_drive(drive_strength);
+
+       err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_DRIVE_STRENGTH,
+               card_strength, NULL);
+
+       /* if error default to drive strength B */
+       if (!err)
+               mmc_set_driver_type(card->host, drive_strength);
+}
+
+
+static int sdio_set_bus_speed_mode(struct mmc_card *card)
+{
+       unsigned int bus_speed, timing;
+       int err;
+       unsigned char speed;
+
+       /*
+        * If the host doesn't support any of the UHS-I modes, fallback on
+        * default speed.
+        */
+       if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+           MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
+               return 0;
+
+       bus_speed = SDIO_SPEED_SDR12;
+       timing = MMC_TIMING_UHS_SDR12;
+       if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
+           (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
+                       bus_speed = SDIO_SPEED_SDR104;
+                       timing = MMC_TIMING_UHS_SDR104;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
+       } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
+                  (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
+                       bus_speed = SDIO_SPEED_DDR50;
+                       timing = MMC_TIMING_UHS_DDR50;
+                       card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
+       } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+                   MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
+                   SD_MODE_UHS_SDR50)) {
+                       bus_speed = SDIO_SPEED_SDR50;
+                       timing = MMC_TIMING_UHS_SDR50;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
+       } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+                   MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
+                  (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
+                       bus_speed = SDIO_SPEED_SDR25;
+                       timing = MMC_TIMING_UHS_SDR25;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
+       } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+                   MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
+                   MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
+                   SD_MODE_UHS_SDR12)) {
+                       bus_speed = SDIO_SPEED_SDR12;
+                       timing = MMC_TIMING_UHS_SDR12;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
+       }
+
+       err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
+       if (err)
+               return err;
+
+       speed &= ~SDIO_SPEED_BSS_MASK;
+       speed |= bus_speed;
+       err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
+       if (err)
+               return err;
+
+       if (bus_speed) {
+               mmc_set_timing(card->host, timing);
+               mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
+       }
+
+       return 0;
+}
+
+/*
+ * UHS-I specific initialization procedure
+ */
+static int mmc_sdio_init_uhs_card(struct mmc_card *card)
+{
+       int err;
+
+       if (!card->scr.sda_spec3)
+               return 0;
+
+       /*
+        * Switch to wider bus (if supported).
+        */
+       if (card->host->caps & MMC_CAP_4_BIT_DATA) {
+               err = sdio_enable_4bit_bus(card);
+               if (err > 0) {
+                       mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+                       err = 0;
+               }
+       }
+
+       /* Set the driver strength for the card */
+       sdio_select_driver_type(card);
+
+       /* Set bus speed mode of the card */
+       err = sdio_set_bus_speed_mode(card);
+       if (err)
+               goto out;
+
+       /* Initialize and start re-tuning timer */
+       if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
+               err = card->host->ops->execute_tuning(card->host,
+                                                     MMC_SEND_TUNING_BLOCK);
+
+out:
+
+       return err;
+}
+
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -393,6 +631,30 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
        if (host->ops->init_card)
                host->ops->init_card(host, card);
 
+       /*
+        * If the host and card support UHS-I mode request the card
+        * to switch to 1.8V signaling level.  No 1.8v signalling if
+        * UHS mode is not enabled to maintain compatibilty and some
+        * systems that claim 1.8v signalling in fact do not support
+        * it.
+        */
+       if ((ocr & R4_18V_PRESENT) &&
+               (host->caps &
+                       (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+                        MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
+                        MMC_CAP_UHS_DDR50))) {
+               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
+                               true);
+               if (err) {
+                       ocr &= ~R4_18V_PRESENT;
+                       host->ocr &= ~R4_18V_PRESENT;
+               }
+               err = 0;
+       } else {
+               ocr &= ~R4_18V_PRESENT;
+               host->ocr &= ~R4_18V_PRESENT;
+       }
+
        /*
         * For native busses:  set card RCA and quit open drain mode.
         */
@@ -492,29 +754,39 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
        if (err)
                goto remove;
 
-       /*
-        * Switch to high-speed (if supported).
-        */
-       err = sdio_enable_hs(card);
-       if (err > 0)
-               mmc_sd_go_highspeed(card);
-       else if (err)
-               goto remove;
+       /* Initialization sequence for UHS-I cards */
+       /* Only if card supports 1.8v and UHS signaling */
+       if ((ocr & R4_18V_PRESENT) && card->sw_caps.sd3_bus_mode) {
+               err = mmc_sdio_init_uhs_card(card);
+               if (err)
+                       goto remove;
 
-       /*
-        * Change to the card's maximum speed.
-        */
-       mmc_set_clock(host, mmc_sdio_get_max_clock(card));
+               /* Card is an ultra-high-speed card */
+               mmc_card_set_uhs(card);
+       } else {
+               /*
+                * Switch to high-speed (if supported).
+                */
+               err = sdio_enable_hs(card);
+               if (err > 0)
+                       mmc_sd_go_highspeed(card);
+               else if (err)
+                       goto remove;
 
-       /*
-        * Switch to wider bus (if supported).
-        */
-       err = sdio_enable_4bit_bus(card);
-       if (err > 0)
-               mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
-       else if (err)
-               goto remove;
+               /*
+                * Change to the card's maximum speed.
+                */
+               mmc_set_clock(host, mmc_sdio_get_max_clock(card));
 
+               /*
+                * Switch to wider bus (if supported).
+                */
+               err = sdio_enable_4bit_bus(card);
+               if (err > 0)
+                       mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+               else if (err)
+                       goto remove;
+       }
 finish:
        if (!oldcard)
                host->card = card;
@@ -549,6 +821,14 @@ static void mmc_sdio_remove(struct mmc_host *host)
        host->card = NULL;
 }
 
+/*
+ * Card detection - card is alive.
+ */
+static int mmc_sdio_alive(struct mmc_host *host)
+{
+       return mmc_select_card(host->card);
+}
+
 /*
  * Card detection callback from host.
  */
@@ -571,7 +851,7 @@ static void mmc_sdio_detect(struct mmc_host *host)
        /*
         * Just check if our card has been removed.
         */
-       err = mmc_select_card(host->card);
+       err = _mmc_detect_card_removed(host);
 
        mmc_release_host(host);
 
@@ -749,6 +1029,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
        .suspend = mmc_sdio_suspend,
        .resume = mmc_sdio_resume,
        .power_restore = mmc_sdio_power_restore,
+       .alive = mmc_sdio_alive,
 };
 
 
@@ -797,8 +1078,17 @@ int mmc_attach_sdio(struct mmc_host *host)
         * Detect and init the card.
         */
        err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
-       if (err)
-               goto err;
+       if (err) {
+               if (err == -EAGAIN) {
+                       /*
+                        * Retry initialization with S18R set to 0.
+                        */
+                       host->ocr &= ~R4_18V_PRESENT;
+                       err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
+               }
+               if (err)
+                       goto err;
+       }
        card = host->card;
 
        /*
index b1f3168f791b5fcbabe144faf9c6f23243957c5d..8f6f5ac131fc43cd44e544151826d0e0ad29ac61 100644 (file)
@@ -196,6 +196,9 @@ static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
        else
                mval = min(mval, func->max_blksize);
 
+       if (mmc_card_broken_byte_mode_512(func->card))
+               return min(mval, 511u);
+
        return min(mval, 512u); /* maximum size for byte mode */
 }
 
@@ -314,7 +317,7 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
                        func->card->host->max_seg_size / func->cur_blksize);
                max_blocks = min(max_blocks, 511u);
 
-               while (remainder > func->cur_blksize) {
+               while (remainder >= func->cur_blksize) {
                        unsigned blocks;
 
                        blocks = remainder / func->cur_blksize;
@@ -339,8 +342,9 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
        while (remainder > 0) {
                size = min(remainder, sdio_max_byte_size(func));
 
+               /* Indicate byte mode by setting "blocks" = 0 */
                ret = mmc_io_rw_extended(func->card, write, func->num, addr,
-                        incr_addr, buf, 1, size);
+                        incr_addr, buf, 0, size);
                if (ret)
                        return ret;
 
index b0517cc06200177d16766c84f237214a6f813d2f..d29e20630eed9249d339240d8e3ddd114d606a0a 100644 (file)
@@ -128,8 +128,6 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
 
        BUG_ON(!card);
        BUG_ON(fn > 7);
-       BUG_ON(blocks == 1 && blksz > 512);
-       WARN_ON(blocks == 0);
        WARN_ON(blksz == 0);
 
        /* sanity check */
@@ -144,22 +142,20 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        cmd.arg |= fn << 28;
        cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
        cmd.arg |= addr << 9;
-       if (blocks == 1 && blksz < 512)
-               cmd.arg |= blksz;                       /* byte mode */
-       else if (blocks == 1 && blksz == 512 &&
-                !(mmc_card_broken_byte_mode_512(card)))
-               cmd.arg |= 0;                           /* byte mode, 0==512 */
+       if (blocks == 0)
+               cmd.arg |= (blksz == 512) ? 0 : blksz;  /* byte mode */
        else
                cmd.arg |= 0x08000000 | blocks;         /* block mode */
        cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
 
        data.blksz = blksz;
-       data.blocks = blocks;
+       /* Code in host drivers/fwk assumes that "blocks" always is >=1 */
+       data.blocks = blocks ? blocks : 1;
        data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
        data.sg = &sg;
        data.sg_len = 1;
 
-       sg_init_one(&sg, buf, blksz * blocks);
+       sg_init_one(&sg, buf, data.blksz * data.blocks);
 
        mmc_set_data_timeout(&data, card);
 
index b4b83f302e325f52a9d138884644cf8c9eb52819..745f8fce251986278b408951fd1d5b4a12015893 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_MMC_MXC)           += mxcmmc.o
 obj-$(CONFIG_MMC_MXS)          += mxs-mmc.o
 obj-$(CONFIG_MMC_SDHCI)                += sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)    += sdhci-pci.o
+obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI))       += sdhci-pci-data.o
 obj-$(CONFIG_MMC_SDHCI_PXAV3)  += sdhci-pxav3.o
 obj-$(CONFIG_MMC_SDHCI_PXAV2)  += sdhci-pxav2.o
 obj-$(CONFIG_MMC_SDHCI_S3C)    += sdhci-s3c.o
index f437c3e6f3aaa9b5cf5b96df2d5128c6029dfac1..947faa5d2ce4ebb243f049bca62430541c286efa 100644 (file)
@@ -236,7 +236,7 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
 
                sg = &data->sg[i];
 
-               sgbuffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
+               sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset;
                amount = min(size, sg->length);
                size -= amount;
 
@@ -252,7 +252,7 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
                        dmabuf = (unsigned *)tmpv;
                }
 
-               kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
+               kunmap_atomic(sgbuffer);
 
                if (size == 0)
                        break;
@@ -302,7 +302,7 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
 
                sg = &data->sg[i];
 
-               sgbuffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
+               sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset;
                amount = min(size, sg->length);
                size -= amount;
 
@@ -318,7 +318,7 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
                }
 
                flush_kernel_dcache_page(sg_page(sg));
-               kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
+               kunmap_atomic(sgbuffer);
                data->bytes_xfered += amount;
                if (size == 0)
                        break;
index a7ee5027146528aafc6b18fa8c2e55f32e32a174..fcfe1eb5acc8f421a1e10a3c387c3c139171ef4d 100644 (file)
@@ -823,6 +823,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
        struct scatterlist              *sg;
        unsigned int                    i;
        enum dma_data_direction         direction;
+       enum dma_transfer_direction     slave_dirn;
        unsigned int                    sglen;
        u32 iflags;
 
@@ -860,16 +861,19 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
        if (host->caps.has_dma)
                atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(3) | ATMCI_DMAEN);
 
-       if (data->flags & MMC_DATA_READ)
+       if (data->flags & MMC_DATA_READ) {
                direction = DMA_FROM_DEVICE;
-       else
+               slave_dirn = DMA_DEV_TO_MEM;
+       } else {
                direction = DMA_TO_DEVICE;
+               slave_dirn = DMA_MEM_TO_DEV;
+       }
 
        sglen = dma_map_sg(chan->device->dev, data->sg,
                        data->sg_len, direction);
 
        desc = chan->device->device_prep_slave_sg(chan,
-                       data->sg, sglen, direction,
+                       data->sg, sglen, slave_dirn,
                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc)
                goto unmap_exit;
index 5d3b9ae645236dd8b7857a383825694286705b8a..dbd0c8a4e98a8d5c5aaa07957f7658c45aa6b881 100644 (file)
@@ -153,6 +153,7 @@ static inline int has_dbdma(void)
 {
        switch (alchemy_get_cputype()) {
        case ALCHEMY_CPU_AU1200:
+       case ALCHEMY_CPU_AU1300:
                return 1;
        default:
                return 0;
@@ -768,11 +769,15 @@ static void au1xmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
        config2 = au_readl(HOST_CONFIG2(host));
        switch (ios->bus_width) {
+       case MMC_BUS_WIDTH_8:
+               config2 |= SD_CONFIG2_BB;
+               break;
        case MMC_BUS_WIDTH_4:
+               config2 &= ~SD_CONFIG2_BB;
                config2 |= SD_CONFIG2_WB;
                break;
        case MMC_BUS_WIDTH_1:
-               config2 &= ~SD_CONFIG2_WB;
+               config2 &= ~(SD_CONFIG2_WB | SD_CONFIG2_BB);
                break;
        }
        au_writel(config2, HOST_CONFIG2(host));
@@ -943,7 +948,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
        struct mmc_host *mmc;
        struct au1xmmc_host *host;
        struct resource *r;
-       int ret;
+       int ret, iflag;
 
        mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
        if (!mmc) {
@@ -982,37 +987,43 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "no IRQ defined\n");
                goto out3;
        }
-
        host->irq = r->start;
-       /* IRQ is shared among both SD controllers */
-       ret = request_irq(host->irq, au1xmmc_irq, IRQF_SHARED,
-                         DRIVER_NAME, host);
-       if (ret) {
-               dev_err(&pdev->dev, "cannot grab IRQ\n");
-               goto out3;
-       }
 
        mmc->ops = &au1xmmc_ops;
 
        mmc->f_min =   450000;
        mmc->f_max = 24000000;
 
+       mmc->max_blk_size = 2048;
+       mmc->max_blk_count = 512;
+
+       mmc->ocr_avail = AU1XMMC_OCR;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
+       mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT;
+
+       iflag = IRQF_SHARED;    /* Au1100/Au1200: one int for both ctrls */
+
        switch (alchemy_get_cputype()) {
        case ALCHEMY_CPU_AU1100:
                mmc->max_seg_size = AU1100_MMC_DESCRIPTOR_SIZE;
-               mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT;
                break;
        case ALCHEMY_CPU_AU1200:
                mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE;
-               mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT;
+               break;
+       case ALCHEMY_CPU_AU1300:
+               iflag = 0;      /* nothing is shared */
+               mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE;
+               mmc->f_max = 52000000;
+               if (host->ioarea->start == AU1100_SD0_PHYS_ADDR)
+                       mmc->caps |= MMC_CAP_8_BIT_DATA;
                break;
        }
 
-       mmc->max_blk_size = 2048;
-       mmc->max_blk_count = 512;
-
-       mmc->ocr_avail = AU1XMMC_OCR;
-       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
+       ret = request_irq(host->irq, au1xmmc_irq, iflag, DRIVER_NAME, host);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot grab IRQ\n");
+               goto out3;
+       }
 
        host->status = HOST_S_IDLE;
 
index 0371bf502249baf416d78b85c88ca1ba218f28b0..03666174ca483e61a351626ad428a9bc833ef981 100644 (file)
@@ -627,17 +627,7 @@ static struct platform_driver sdh_driver = {
        },
 };
 
-static int __init sdh_init(void)
-{
-       return platform_driver_register(&sdh_driver);
-}
-module_init(sdh_init);
-
-static void __exit sdh_exit(void)
-{
-       platform_driver_unregister(&sdh_driver);
-}
-module_exit(sdh_exit);
+module_platform_driver(sdh_driver);
 
 MODULE_DESCRIPTION("Blackfin Secure Digital Host Driver");
 MODULE_AUTHOR("Cliff Cai, Roy Huang");
index ce2a47b71dd6a0fe8b73d5eefb616607d04fe731..83693fd7c6b35718e5a65d81d3e8499a7694a378 100644 (file)
@@ -780,18 +780,7 @@ static struct platform_driver cb710_mmc_driver = {
 #endif
 };
 
-static int __init cb710_mmc_init_module(void)
-{
-       return platform_driver_register(&cb710_mmc_driver);
-}
-
-static void __exit cb710_mmc_cleanup_module(void)
-{
-       platform_driver_unregister(&cb710_mmc_driver);
-}
-
-module_init(cb710_mmc_init_module);
-module_exit(cb710_mmc_cleanup_module);
+module_platform_driver(cb710_mmc_driver);
 
 MODULE_AUTHOR("MichaÅ‚ MirosÅ‚aw <mirq-linux@rere.qmqm.pl>");
 MODULE_DESCRIPTION("ENE CB710 memory card reader driver - MMC/SD part");
index 3aaeb0841914f6a1fdc790de71e6dbaaf15e735b..0e342793ff142f2f2616da2a6bce85542e9e4cf7 100644 (file)
@@ -588,11 +588,11 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot)
        mci_writel(host, CTYPE, (slot->ctype << slot->id));
 }
 
-static void dw_mci_start_request(struct dw_mci *host,
-                                struct dw_mci_slot *slot)
+static void __dw_mci_start_request(struct dw_mci *host,
+                                  struct dw_mci_slot *slot,
+                                  struct mmc_command *cmd)
 {
        struct mmc_request *mrq;
-       struct mmc_command *cmd;
        struct mmc_data *data;
        u32 cmdflags;
 
@@ -610,14 +610,13 @@ static void dw_mci_start_request(struct dw_mci *host,
        host->completed_events = 0;
        host->data_status = 0;
 
-       data = mrq->data;
+       data = cmd->data;
        if (data) {
                dw_mci_set_timeout(host);
                mci_writel(host, BYTCNT, data->blksz*data->blocks);
                mci_writel(host, BLKSIZ, data->blksz);
        }
 
-       cmd = mrq->cmd;
        cmdflags = dw_mci_prepare_command(slot->mmc, cmd);
 
        /* this is the first command, send the initialization clock */
@@ -635,6 +634,16 @@ static void dw_mci_start_request(struct dw_mci *host,
                host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
 }
 
+static void dw_mci_start_request(struct dw_mci *host,
+                                struct dw_mci_slot *slot)
+{
+       struct mmc_request *mrq = slot->mrq;
+       struct mmc_command *cmd;
+
+       cmd = mrq->sbc ? mrq->sbc : mrq->cmd;
+       __dw_mci_start_request(host, slot, cmd);
+}
+
 /* must be called with host->lock held */
 static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
                                 struct mmc_request *mrq)
@@ -698,12 +707,15 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                break;
        }
 
+       regs = mci_readl(slot->host, UHS_REG);
+
        /* DDR mode set */
-       if (ios->timing == MMC_TIMING_UHS_DDR50) {
-               regs = mci_readl(slot->host, UHS_REG);
+       if (ios->timing == MMC_TIMING_UHS_DDR50)
                regs |= (0x1 << slot->id) << 16;
-               mci_writel(slot->host, UHS_REG, regs);
-       }
+       else
+               regs &= ~(0x1 << slot->id) << 16;
+
+       mci_writel(slot->host, UHS_REG, regs);
 
        if (ios->clock) {
                /*
@@ -889,7 +901,14 @@ static void dw_mci_tasklet_func(unsigned long priv)
                        cmd = host->cmd;
                        host->cmd = NULL;
                        set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
-                       dw_mci_command_complete(host, host->mrq->cmd);
+                       dw_mci_command_complete(host, cmd);
+                       if (cmd == host->mrq->sbc && !cmd->error) {
+                               prev_state = state = STATE_SENDING_CMD;
+                               __dw_mci_start_request(host, host->cur_slot,
+                                                      host->mrq->cmd);
+                               goto unlock;
+                       }
+
                        if (!host->mrq->data || cmd->error) {
                                dw_mci_request_end(host, host->mrq);
                                goto unlock;
@@ -967,6 +986,12 @@ static void dw_mci_tasklet_func(unsigned long priv)
                                goto unlock;
                        }
 
+                       if (host->mrq->sbc && !data->error) {
+                               data->stop->error = 0;
+                               dw_mci_request_end(host, host->mrq);
+                               goto unlock;
+                       }
+
                        prev_state = state = STATE_SENDING_STOP;
                        if (!data->error)
                                send_stop_cmd(host, data);
@@ -1678,8 +1703,9 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 
        if (host->pdata->caps)
                mmc->caps = host->pdata->caps;
-       else
-               mmc->caps = 0;
+
+       if (host->pdata->caps2)
+               mmc->caps2 = host->pdata->caps2;
 
        if (host->pdata->get_bus_wd)
                if (host->pdata->get_bus_wd(slot->id) >= 4)
@@ -1923,7 +1949,7 @@ static int dw_mci_probe(struct platform_device *pdev)
                 * should put it in the platform data.
                 */
                fifo_size = mci_readl(host, FIFOTH);
-               fifo_size = 1 + ((fifo_size >> 16) & 0x7ff);
+               fifo_size = 1 + ((fifo_size >> 16) & 0xfff);
        } else {
                fifo_size = host->pdata->fifo_depth;
        }
@@ -2062,14 +2088,14 @@ static int __exit dw_mci_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * TODO: we should probably disable the clock to the card in the suspend path.
  */
-static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg)
+static int dw_mci_suspend(struct device *dev)
 {
        int i, ret;
-       struct dw_mci *host = platform_get_drvdata(pdev);
+       struct dw_mci *host = dev_get_drvdata(dev);
 
        for (i = 0; i < host->num_slots; i++) {
                struct dw_mci_slot *slot = host->slot[i];
@@ -2092,10 +2118,10 @@ static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg)
        return 0;
 }
 
-static int dw_mci_resume(struct platform_device *pdev)
+static int dw_mci_resume(struct device *dev)
 {
        int i, ret;
-       struct dw_mci *host = platform_get_drvdata(pdev);
+       struct dw_mci *host = dev_get_drvdata(dev);
 
        if (host->vmmc)
                regulator_enable(host->vmmc);
@@ -2103,7 +2129,7 @@ static int dw_mci_resume(struct platform_device *pdev)
        if (host->dma_ops->init)
                host->dma_ops->init(host);
 
-       if (!mci_wait_reset(&pdev->dev, host)) {
+       if (!mci_wait_reset(dev, host)) {
                ret = -ENODEV;
                return ret;
        }
@@ -2131,14 +2157,15 @@ static int dw_mci_resume(struct platform_device *pdev)
 #else
 #define dw_mci_suspend NULL
 #define dw_mci_resume  NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(dw_mci_pmops, dw_mci_suspend, dw_mci_resume);
 
 static struct platform_driver dw_mci_driver = {
        .remove         = __exit_p(dw_mci_remove),
-       .suspend        = dw_mci_suspend,
-       .resume         = dw_mci_resume,
        .driver         = {
                .name           = "dw_mmc",
+               .pm             = &dw_mci_pmops,
        },
 };
 
index 72c071f6e0015c7c0d254560fc3d3c344569de39..df392a1143f279d75e798a89e37c4e13356f8291 100644 (file)
 #define SDMMC_CMD_RESP_EXP             BIT(6)
 #define SDMMC_CMD_INDX(n)              ((n) & 0x1F)
 /* Status register defines */
-#define SDMMC_GET_FCNT(x)              (((x)>>17) & 0x1FF)
+#define SDMMC_GET_FCNT(x)              (((x)>>17) & 0x1FFF)
 /* Internal DMAC interrupt defines */
 #define SDMMC_IDMAC_INT_AI             BIT(9)
 #define SDMMC_IDMAC_INT_NI             BIT(8)
index 74218ad677e4955d2dcb0941f68ed45c3fa4e85b..c8852a8128a90c119d7d53c5eec5381aa9678008 100644 (file)
@@ -1012,17 +1012,7 @@ static struct platform_driver jz4740_mmc_driver = {
        },
 };
 
-static int __init jz4740_mmc_init(void)
-{
-       return platform_driver_register(&jz4740_mmc_driver);
-}
-module_init(jz4740_mmc_init);
-
-static void __exit jz4740_mmc_exit(void)
-{
-       platform_driver_unregister(&jz4740_mmc_driver);
-}
-module_exit(jz4740_mmc_exit);
+module_platform_driver(jz4740_mmc_driver);
 
 MODULE_DESCRIPTION("JZ4740 SD/MMC controller driver");
 MODULE_LICENSE("GPL");
index 92946b84e9faa58e9958a1cbf7e371332748afd3..273306c68d58e916d8a588fffb8fd73385c405f2 100644 (file)
@@ -1525,7 +1525,6 @@ static struct of_device_id mmc_spi_of_match_table[] __devinitdata = {
 static struct spi_driver mmc_spi_driver = {
        .driver = {
                .name =         "mmc_spi",
-               .bus =          &spi_bus_type,
                .owner =        THIS_MODULE,
                .of_match_table = mmc_spi_of_match_table,
        },
index fa8dd2fda4b270d0858f144ed34abfc30a30da4a..0d955ffaf44e2c3ec5961f966687da3e675819d9 100644 (file)
@@ -374,6 +374,7 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
        struct dma_chan *chan;
        struct dma_device *device;
        struct dma_async_tx_descriptor *desc;
+       enum dma_data_direction buffer_dirn;
        int nr_sg;
 
        /* Check if next job is already prepared */
@@ -387,10 +388,12 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
        }
 
        if (data->flags & MMC_DATA_READ) {
-               conf.direction = DMA_FROM_DEVICE;
+               conf.direction = DMA_DEV_TO_MEM;
+               buffer_dirn = DMA_FROM_DEVICE;
                chan = host->dma_rx_channel;
        } else {
-               conf.direction = DMA_TO_DEVICE;
+               conf.direction = DMA_MEM_TO_DEV;
+               buffer_dirn = DMA_TO_DEVICE;
                chan = host->dma_tx_channel;
        }
 
@@ -403,7 +406,7 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
                return -EINVAL;
 
        device = chan->device;
-       nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, conf.direction);
+       nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, buffer_dirn);
        if (nr_sg == 0)
                return -EINVAL;
 
@@ -426,7 +429,7 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
  unmap_exit:
        if (!next)
                dmaengine_terminate_all(chan);
-       dma_unmap_sg(device->dev, data->sg, data->sg_len, conf.direction);
+       dma_unmap_sg(device->dev, data->sg, data->sg_len, buffer_dirn);
        return -ENOMEM;
 }
 
@@ -1245,6 +1248,7 @@ static int __devinit mmci_probe(struct amba_device *dev,
        if (host->vcc == NULL)
                mmc->ocr_avail = plat->ocr_mask;
        mmc->caps = plat->capabilities;
+       mmc->caps2 = plat->capabilities2;
 
        /*
         * We can do SGIO
index 80d8eb143b486c92ee143f6e70992570625e33e3..1d14cda95e56c8191c2168b26d4e0543eb39ddac 100644 (file)
@@ -689,8 +689,8 @@ msmsdcc_pio_irq(int irq, void *dev_id)
 
                /* Map the current scatter buffer */
                local_irq_save(flags);
-               buffer = kmap_atomic(sg_page(host->pio.sg),
-                                    KM_BIO_SRC_IRQ) + host->pio.sg->offset;
+               buffer = kmap_atomic(sg_page(host->pio.sg))
+                                    + host->pio.sg->offset;
                buffer += host->pio.sg_off;
                remain = host->pio.sg->length - host->pio.sg_off;
                len = 0;
@@ -700,7 +700,7 @@ msmsdcc_pio_irq(int irq, void *dev_id)
                        len = msmsdcc_pio_write(host, buffer, remain, status);
 
                /* Unmap the buffer */
-               kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
+               kunmap_atomic(buffer);
                local_irq_restore(flags);
 
                host->pio.sg_off += len;
@@ -1480,18 +1480,7 @@ static struct platform_driver msmsdcc_driver = {
        },
 };
 
-static int __init msmsdcc_init(void)
-{
-       return platform_driver_register(&msmsdcc_driver);
-}
-
-static void __exit msmsdcc_exit(void)
-{
-       platform_driver_unregister(&msmsdcc_driver);
-}
-
-module_init(msmsdcc_init);
-module_exit(msmsdcc_exit);
+module_platform_driver(msmsdcc_driver);
 
 MODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver");
 MODULE_LICENSE("GPL");
index 8e0fbe99404778ee1cc4f512b767479d7dad9855..4184b7946bbf34fd459c671a921ae6baf659e4d2 100644 (file)
@@ -218,6 +218,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
        unsigned int blksz = data->blksz;
        unsigned int datasize = nob * blksz;
        struct scatterlist *sg;
+       enum dma_transfer_direction slave_dirn;
        int i, nents;
 
        if (data->flags & MMC_DATA_STREAM)
@@ -240,10 +241,13 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
                }
        }
 
-       if (data->flags & MMC_DATA_READ)
+       if (data->flags & MMC_DATA_READ) {
                host->dma_dir = DMA_FROM_DEVICE;
-       else
+               slave_dirn = DMA_DEV_TO_MEM;
+       } else {
                host->dma_dir = DMA_TO_DEVICE;
+               slave_dirn = DMA_MEM_TO_DEV;
+       }
 
        nents = dma_map_sg(host->dma->device->dev, data->sg,
                                     data->sg_len,  host->dma_dir);
@@ -251,7 +255,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
                return -EINVAL;
 
        host->desc = host->dma->device->device_prep_slave_sg(host->dma,
-               data->sg, data->sg_len, host->dma_dir,
+               data->sg, data->sg_len, slave_dirn,
                DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 
        if (!host->desc) {
@@ -1047,18 +1051,7 @@ static struct platform_driver mxcmci_driver = {
        }
 };
 
-static int __init mxcmci_init(void)
-{
-       return platform_driver_register(&mxcmci_driver);
-}
-
-static void __exit mxcmci_exit(void)
-{
-       platform_driver_unregister(&mxcmci_driver);
-}
-
-module_init(mxcmci_init);
-module_exit(mxcmci_exit);
+module_platform_driver(mxcmci_driver);
 
 MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver");
 MODULE_AUTHOR("Sascha Hauer, Pengutronix");
index 973011f9a298ba7ecf9e49d26847d25d5ad99518..382c835d217cf23372594b230dcd7923971288d5 100644 (file)
@@ -154,6 +154,7 @@ struct mxs_mmc_host {
        struct dma_chan                 *dmach;
        struct mxs_dma_data             dma_data;
        unsigned int                    dma_dir;
+       enum dma_transfer_direction     slave_dirn;
        u32                             ssp_pio_words[SSP_PIO_NUM];
 
        unsigned int                    version;
@@ -324,7 +325,7 @@ static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
        }
 
        desc = host->dmach->device->device_prep_slave_sg(host->dmach,
-                               sgl, sg_len, host->dma_dir, append);
+                               sgl, sg_len, host->slave_dirn, append);
        if (desc) {
                desc->callback = mxs_mmc_dma_irq_callback;
                desc->callback_param = host;
@@ -356,6 +357,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host)
        host->ssp_pio_words[1] = cmd0;
        host->ssp_pio_words[2] = cmd1;
        host->dma_dir = DMA_NONE;
+       host->slave_dirn = DMA_TRANS_NONE;
        desc = mxs_mmc_prep_dma(host, 0);
        if (!desc)
                goto out;
@@ -395,6 +397,7 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host)
        host->ssp_pio_words[1] = cmd0;
        host->ssp_pio_words[2] = cmd1;
        host->dma_dir = DMA_NONE;
+       host->slave_dirn = DMA_TRANS_NONE;
        desc = mxs_mmc_prep_dma(host, 0);
        if (!desc)
                goto out;
@@ -433,6 +436,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
        int i;
 
        unsigned short dma_data_dir, timeout;
+       enum dma_transfer_direction slave_dirn;
        unsigned int data_size = 0, log2_blksz;
        unsigned int blocks = data->blocks;
 
@@ -448,9 +452,11 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
 
        if (data->flags & MMC_DATA_WRITE) {
                dma_data_dir = DMA_TO_DEVICE;
+               slave_dirn = DMA_MEM_TO_DEV;
                read = 0;
        } else {
                dma_data_dir = DMA_FROM_DEVICE;
+               slave_dirn = DMA_DEV_TO_MEM;
                read = BM_SSP_CTRL0_READ;
        }
 
@@ -510,6 +516,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
        host->ssp_pio_words[1] = cmd0;
        host->ssp_pio_words[2] = cmd1;
        host->dma_dir = DMA_NONE;
+       host->slave_dirn = DMA_TRANS_NONE;
        desc = mxs_mmc_prep_dma(host, 0);
        if (!desc)
                goto out;
@@ -518,6 +525,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
        WARN_ON(host->data != NULL);
        host->data = data;
        host->dma_dir = dma_data_dir;
+       host->slave_dirn = slave_dirn;
        desc = mxs_mmc_prep_dma(host, 1);
        if (!desc)
                goto out;
@@ -855,18 +863,7 @@ static struct platform_driver mxs_mmc_driver = {
        },
 };
 
-static int __init mxs_mmc_init(void)
-{
-       return platform_driver_register(&mxs_mmc_driver);
-}
-
-static void __exit mxs_mmc_exit(void)
-{
-       platform_driver_unregister(&mxs_mmc_driver);
-}
-
-module_init(mxs_mmc_init);
-module_exit(mxs_mmc_exit);
+module_platform_driver(mxs_mmc_driver);
 
 MODULE_DESCRIPTION("FREESCALE MXS MMC peripheral");
 MODULE_AUTHOR("Freescale Semiconductor");
index d1fb561e089d8e0ba24888d702b01ef428745b25..fd0c661bbad38a7152a37955146ff6068d4d7137 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
-#include <linux/workqueue.h>
 #include <linux/timer.h>
 #include <linux/clk.h>
 #include <linux/mmc/host.h>
 
 #define MMC_AUTOSUSPEND_DELAY  100
 #define MMC_TIMEOUT_MS         20
-#define OMAP_MMC_MASTER_CLOCK  96000000
 #define OMAP_MMC_MIN_CLOCK     400000
 #define OMAP_MMC_MAX_CLOCK     52000000
 #define DRIVER_NAME            "omap_hsmmc"
@@ -163,7 +161,6 @@ struct omap_hsmmc_host {
         */
        struct  regulator       *vcc;
        struct  regulator       *vcc_aux;
-       struct  work_struct     mmc_carddetect_work;
        void    __iomem         *base;
        resource_size_t         mapbase;
        spinlock_t              irq_lock; /* Prevent races with irq handler */
@@ -598,12 +595,12 @@ static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)
 }
 
 /* Calculate divisor for the given clock frequency */
-static u16 calc_divisor(struct mmc_ios *ios)
+static u16 calc_divisor(struct omap_hsmmc_host *host, struct mmc_ios *ios)
 {
        u16 dsor = 0;
 
        if (ios->clock) {
-               dsor = DIV_ROUND_UP(OMAP_MMC_MASTER_CLOCK, ios->clock);
+               dsor = DIV_ROUND_UP(clk_get_rate(host->fclk), ios->clock);
                if (dsor > 250)
                        dsor = 250;
        }
@@ -623,7 +620,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
 
        regval = OMAP_HSMMC_READ(host->base, SYSCTL);
        regval = regval & ~(CLKD_MASK | DTO_MASK);
-       regval = regval | (calc_divisor(ios) << 6) | (DTO << 16);
+       regval = regval | (calc_divisor(host, ios) << 6) | (DTO << 16);
        OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
        OMAP_HSMMC_WRITE(host->base, SYSCTL,
                OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
@@ -1280,17 +1277,16 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
 }
 
 /*
- * Work Item to notify the core about card insertion/removal
+ * irq handler to notify the core about card insertion/removal
  */
-static void omap_hsmmc_detect(struct work_struct *work)
+static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id)
 {
-       struct omap_hsmmc_host *host =
-               container_of(work, struct omap_hsmmc_host, mmc_carddetect_work);
+       struct omap_hsmmc_host *host = dev_id;
        struct omap_mmc_slot_data *slot = &mmc_slot(host);
        int carddetect;
 
        if (host->suspended)
-               return;
+               return IRQ_HANDLED;
 
        sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
 
@@ -1305,19 +1301,6 @@ static void omap_hsmmc_detect(struct work_struct *work)
                mmc_detect_change(host->mmc, (HZ * 200) / 1000);
        else
                mmc_detect_change(host->mmc, (HZ * 50) / 1000);
-}
-
-/*
- * ISR for handling card insertion and removal
- */
-static irqreturn_t omap_hsmmc_cd_handler(int irq, void *dev_id)
-{
-       struct omap_hsmmc_host *host = (struct omap_hsmmc_host *)dev_id;
-
-       if (host->suspended)
-               return IRQ_HANDLED;
-       schedule_work(&host->mmc_carddetect_work);
-
        return IRQ_HANDLED;
 }
 
@@ -1919,7 +1902,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
        host->next_data.cookie = 1;
 
        platform_set_drvdata(pdev, host);
-       INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect);
 
        mmc->ops        = &omap_hsmmc_ops;
 
@@ -2049,10 +2031,11 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 
        /* Request IRQ for card detect */
        if ((mmc_slot(host).card_detect_irq)) {
-               ret = request_irq(mmc_slot(host).card_detect_irq,
-                                 omap_hsmmc_cd_handler,
-                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                                 mmc_hostname(mmc), host);
+               ret = request_threaded_irq(mmc_slot(host).card_detect_irq,
+                                          NULL,
+                                          omap_hsmmc_detect,
+                                          IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                                          mmc_hostname(mmc), host);
                if (ret) {
                        dev_dbg(mmc_dev(host->mmc),
                                "Unable to grab MMC CD IRQ\n");
@@ -2131,7 +2114,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
                free_irq(host->irq, host);
                if (mmc_slot(host).card_detect_irq)
                        free_irq(mmc_slot(host).card_detect_irq, host);
-               flush_work_sync(&host->mmc_carddetect_work);
 
                pm_runtime_put_sync(host->dev);
                pm_runtime_disable(host->dev);
@@ -2178,7 +2160,6 @@ static int omap_hsmmc_suspend(struct device *dev)
                                return ret;
                        }
                }
-               cancel_work_sync(&host->mmc_carddetect_work);
                ret = mmc_suspend_host(host->mmc);
 
                if (ret) {
index fc4356e00d46ff7366ed38a6f76ab2f3e2c9cbce..cb2dc0e75ba7fc1ff8d6610176326fa4eb675a5d 100644 (file)
@@ -872,18 +872,7 @@ static struct platform_driver pxamci_driver = {
        },
 };
 
-static int __init pxamci_init(void)
-{
-       return platform_driver_register(&pxamci_driver);
-}
-
-static void __exit pxamci_exit(void)
-{
-       platform_driver_unregister(&pxamci_driver);
-}
-
-module_init(pxamci_init);
-module_exit(pxamci_exit);
+module_platform_driver(pxamci_driver);
 
 MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
 MODULE_LICENSE("GPL");
index 720f99334a7f95ffb7f133b2710b7294abe70369..1bcfd6dbb5cc242eb97de198f3eb383d85655e98 100644 (file)
@@ -1914,18 +1914,7 @@ static struct platform_driver s3cmci_driver = {
        .shutdown       = s3cmci_shutdown,
 };
 
-static int __init s3cmci_init(void)
-{
-       return platform_driver_register(&s3cmci_driver);
-}
-
-static void __exit s3cmci_exit(void)
-{
-       platform_driver_unregister(&s3cmci_driver);
-}
-
-module_init(s3cmci_init);
-module_exit(s3cmci_exit);
+module_platform_driver(s3cmci_driver);
 
 MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver");
 MODULE_LICENSE("GPL v2");
index b4257e700617c6e4f51455a462df1f063dfa0294..28a870804f60bc3cb0dbbe5e7a9d48e3e9088004 100644 (file)
@@ -115,17 +115,7 @@ static struct platform_driver sdhci_cns3xxx_driver = {
        .remove         = __devexit_p(sdhci_cns3xxx_remove),
 };
 
-static int __init sdhci_cns3xxx_init(void)
-{
-       return platform_driver_register(&sdhci_cns3xxx_driver);
-}
-module_init(sdhci_cns3xxx_init);
-
-static void __exit sdhci_cns3xxx_exit(void)
-{
-       platform_driver_unregister(&sdhci_cns3xxx_driver);
-}
-module_exit(sdhci_cns3xxx_exit);
+module_platform_driver(sdhci_cns3xxx_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for CNS3xxx");
 MODULE_AUTHOR("Scott Shu, "
index a81312c91f7086625d10f963df9f31c0b64e0c4c..46fd1fd1b605033b8f437a70da844f11f5e04226 100644 (file)
@@ -88,17 +88,7 @@ static struct platform_driver sdhci_dove_driver = {
        .remove         = __devexit_p(sdhci_dove_remove),
 };
 
-static int __init sdhci_dove_init(void)
-{
-       return platform_driver_register(&sdhci_dove_driver);
-}
-module_init(sdhci_dove_init);
-
-static void __exit sdhci_dove_exit(void)
-{
-       platform_driver_unregister(&sdhci_dove_driver);
-}
-module_exit(sdhci_dove_exit);
+module_platform_driver(sdhci_dove_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for Dove");
 MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>, "
index 38ebc4ea259fcb659f855fe446e45e0dc7fa9952..d601e41af282105ad5c3a86d30d569dfef3def8c 100644 (file)
@@ -606,17 +606,7 @@ static struct platform_driver sdhci_esdhc_imx_driver = {
        .remove         = __devexit_p(sdhci_esdhc_imx_remove),
 };
 
-static int __init sdhci_esdhc_imx_init(void)
-{
-       return platform_driver_register(&sdhci_esdhc_imx_driver);
-}
-module_init(sdhci_esdhc_imx_init);
-
-static void __exit sdhci_esdhc_imx_exit(void)
-{
-       platform_driver_unregister(&sdhci_esdhc_imx_driver);
-}
-module_exit(sdhci_esdhc_imx_exit);
+module_platform_driver(sdhci_esdhc_imx_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
 MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
index c3b08f1119426d66d7f7ee1f4e0d466038631f9d..b97b2f5dafdb4d15160701dd12060b05c394b464 100644 (file)
@@ -73,7 +73,7 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
                | (div << ESDHC_DIVIDER_SHIFT)
                | (pre_div << ESDHC_PREDIV_SHIFT));
        sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
-       mdelay(100);
+       mdelay(1);
 out:
        host->clock = clock;
 }
index 01e5f627e0f047b2a7c63474a931fbedab0a1444..ff4adc0180418578ff10594f3f80cb2c0564d756 100644 (file)
@@ -131,17 +131,7 @@ static struct platform_driver sdhci_esdhc_driver = {
        .remove = __devexit_p(sdhci_esdhc_remove),
 };
 
-static int __init sdhci_esdhc_init(void)
-{
-       return platform_driver_register(&sdhci_esdhc_driver);
-}
-module_init(sdhci_esdhc_init);
-
-static void __exit sdhci_esdhc_exit(void)
-{
-       platform_driver_unregister(&sdhci_esdhc_driver);
-}
-module_exit(sdhci_esdhc_exit);
+module_platform_driver(sdhci_esdhc_driver);
 
 MODULE_DESCRIPTION("SDHCI OF driver for Freescale MPC eSDHC");
 MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, "
index 3619adc7d9fc36548283386f82e08be2d195a608..0ce088ae02289ecf743e00c120a210e7de550d45 100644 (file)
@@ -93,17 +93,7 @@ static struct platform_driver sdhci_hlwd_driver = {
        .remove = __devexit_p(sdhci_hlwd_remove),
 };
 
-static int __init sdhci_hlwd_init(void)
-{
-       return platform_driver_register(&sdhci_hlwd_driver);
-}
-module_init(sdhci_hlwd_init);
-
-static void __exit sdhci_hlwd_exit(void)
-{
-       platform_driver_unregister(&sdhci_hlwd_driver);
-}
-module_exit(sdhci_hlwd_exit);
+module_platform_driver(sdhci_hlwd_driver);
 
 MODULE_DESCRIPTION("Nintendo Wii SDHCI OF driver");
 MODULE_AUTHOR("The GameCube Linux Team, Albert Herranz");
diff --git a/drivers/mmc/host/sdhci-pci-data.c b/drivers/mmc/host/sdhci-pci-data.c
new file mode 100644 (file)
index 0000000..a611217
--- /dev/null
@@ -0,0 +1,5 @@
+#include <linux/module.h>
+#include <linux/mmc/sdhci-pci-data.h>
+
+struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, int slotno);
+EXPORT_SYMBOL_GPL(sdhci_pci_get_data);
index 6878a94626bc35b18bf493a4dcbf522dc3403255..7165e6a092742e82f9b7cf108ad9f034a1173304 100644 (file)
@@ -23,8 +23,8 @@
 #include <linux/scatterlist.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
-#include <linux/sfi.h>
 #include <linux/pm_runtime.h>
+#include <linux/mmc/sdhci-pci-data.h>
 
 #include "sdhci.h"
 
@@ -61,6 +61,7 @@ struct sdhci_pci_fixes {
 struct sdhci_pci_slot {
        struct sdhci_pci_chip   *chip;
        struct sdhci_host       *host;
+       struct sdhci_pci_data   *data;
 
        int                     pci_bar;
        int                     rst_n_gpio;
@@ -171,32 +172,9 @@ static int mrst_hc_probe(struct sdhci_pci_chip *chip)
        return 0;
 }
 
-/* Medfield eMMC hardware reset GPIOs */
-static int mfd_emmc0_rst_gpio = -EINVAL;
-static int mfd_emmc1_rst_gpio = -EINVAL;
-
-static int mfd_emmc_gpio_parse(struct sfi_table_header *table)
-{
-       struct sfi_table_simple *sb = (struct sfi_table_simple *)table;
-       struct sfi_gpio_table_entry *entry;
-       int i, num;
-
-       num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry);
-       entry = (struct sfi_gpio_table_entry *)sb->pentry;
-
-       for (i = 0; i < num; i++, entry++) {
-               if (!strncmp(entry->pin_name, "emmc0_rst", SFI_NAME_LEN))
-                       mfd_emmc0_rst_gpio = entry->pin_no;
-               else if (!strncmp(entry->pin_name, "emmc1_rst", SFI_NAME_LEN))
-                       mfd_emmc1_rst_gpio = entry->pin_no;
-       }
-
-       return 0;
-}
-
 #ifdef CONFIG_PM_RUNTIME
 
-static irqreturn_t mfd_sd_cd(int irq, void *dev_id)
+static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id)
 {
        struct sdhci_pci_slot *slot = dev_id;
        struct sdhci_host *host = slot->host;
@@ -205,15 +183,16 @@ static irqreturn_t mfd_sd_cd(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-#define MFLD_SD_CD_PIN 69
-
-static int mfd_sd_probe_slot(struct sdhci_pci_slot *slot)
+static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
 {
-       int err, irq, gpio = MFLD_SD_CD_PIN;
+       int err, irq, gpio = slot->cd_gpio;
 
        slot->cd_gpio = -EINVAL;
        slot->cd_irq = -EINVAL;
 
+       if (!gpio_is_valid(gpio))
+               return;
+
        err = gpio_request(gpio, "sd_cd");
        if (err < 0)
                goto out;
@@ -226,72 +205,53 @@ static int mfd_sd_probe_slot(struct sdhci_pci_slot *slot)
        if (irq < 0)
                goto out_free;
 
-       err = request_irq(irq, mfd_sd_cd, IRQF_TRIGGER_RISING |
+       err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING |
                          IRQF_TRIGGER_FALLING, "sd_cd", slot);
        if (err)
                goto out_free;
 
        slot->cd_gpio = gpio;
        slot->cd_irq = irq;
-       slot->host->quirks2 |= SDHCI_QUIRK2_OWN_CARD_DETECTION;
 
-       return 0;
+       return;
 
 out_free:
        gpio_free(gpio);
 out:
        dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n");
-       return 0;
 }
 
-static void mfd_sd_remove_slot(struct sdhci_pci_slot *slot, int dead)
+static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
 {
        if (slot->cd_irq >= 0)
                free_irq(slot->cd_irq, slot);
-       gpio_free(slot->cd_gpio);
+       if (gpio_is_valid(slot->cd_gpio))
+               gpio_free(slot->cd_gpio);
 }
 
 #else
 
-#define mfd_sd_probe_slot      NULL
-#define mfd_sd_remove_slot     NULL
+static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
+{
+}
+
+static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
+{
+}
 
 #endif
 
 static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot)
 {
-       const char *name = NULL;
-       int gpio = -EINVAL;
-
-       sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, mfd_emmc_gpio_parse);
-
-       switch (slot->chip->pdev->device) {
-       case PCI_DEVICE_ID_INTEL_MFD_EMMC0:
-               gpio = mfd_emmc0_rst_gpio;
-               name = "eMMC0_reset";
-               break;
-       case PCI_DEVICE_ID_INTEL_MFD_EMMC1:
-               gpio = mfd_emmc1_rst_gpio;
-               name = "eMMC1_reset";
-               break;
-       }
-
-       if (!gpio_request(gpio, name)) {
-               gpio_direction_output(gpio, 1);
-               slot->rst_n_gpio = gpio;
-               slot->host->mmc->caps |= MMC_CAP_HW_RESET;
-       }
-
        slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
-
        slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC;
-
        return 0;
 }
 
-static void mfd_emmc_remove_slot(struct sdhci_pci_slot *slot, int dead)
+static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot)
 {
-       gpio_free(slot->rst_n_gpio);
+       slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD;
+       return 0;
 }
 
 static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = {
@@ -307,20 +267,18 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = {
 static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
        .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
        .allow_runtime_pm = true,
-       .probe_slot     = mfd_sd_probe_slot,
-       .remove_slot    = mfd_sd_remove_slot,
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = {
        .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
        .allow_runtime_pm = true,
+       .probe_slot     = mfd_sdio_probe_slot,
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = {
        .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
        .allow_runtime_pm = true,
        .probe_slot     = mfd_emmc_probe_slot,
-       .remove_slot    = mfd_emmc_remove_slot,
 };
 
 /* O2Micro extra registers */
@@ -1012,11 +970,8 @@ static int sdhci_pci_suspend(struct device *dev)
 
                ret = sdhci_suspend_host(slot->host);
 
-               if (ret) {
-                       for (i--; i >= 0; i--)
-                               sdhci_resume_host(chip->slots[i]->host);
-                       return ret;
-               }
+               if (ret)
+                       goto err_pci_suspend;
 
                slot_pm_flags = slot->host->mmc->pm_flags;
                if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ)
@@ -1027,11 +982,8 @@ static int sdhci_pci_suspend(struct device *dev)
 
        if (chip->fixes && chip->fixes->suspend) {
                ret = chip->fixes->suspend(chip);
-               if (ret) {
-                       for (i = chip->num_slots - 1; i >= 0; i--)
-                               sdhci_resume_host(chip->slots[i]->host);
-                       return ret;
-               }
+               if (ret)
+                       goto err_pci_suspend;
        }
 
        pci_save_state(pdev);
@@ -1048,6 +1000,11 @@ static int sdhci_pci_suspend(struct device *dev)
        }
 
        return 0;
+
+err_pci_suspend:
+       while (--i >= 0)
+               sdhci_resume_host(chip->slots[i]->host);
+       return ret;
 }
 
 static int sdhci_pci_resume(struct device *dev)
@@ -1113,23 +1070,22 @@ static int sdhci_pci_runtime_suspend(struct device *dev)
 
                ret = sdhci_runtime_suspend_host(slot->host);
 
-               if (ret) {
-                       for (i--; i >= 0; i--)
-                               sdhci_runtime_resume_host(chip->slots[i]->host);
-                       return ret;
-               }
+               if (ret)
+                       goto err_pci_runtime_suspend;
        }
 
        if (chip->fixes && chip->fixes->suspend) {
                ret = chip->fixes->suspend(chip);
-               if (ret) {
-                       for (i = chip->num_slots - 1; i >= 0; i--)
-                               sdhci_runtime_resume_host(chip->slots[i]->host);
-                       return ret;
-               }
+               if (ret)
+                       goto err_pci_runtime_suspend;
        }
 
        return 0;
+
+err_pci_runtime_suspend:
+       while (--i >= 0)
+               sdhci_runtime_resume_host(chip->slots[i]->host);
+       return ret;
 }
 
 static int sdhci_pci_runtime_resume(struct device *dev)
@@ -1190,11 +1146,12 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = {
 \*****************************************************************************/
 
 static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
-       struct pci_dev *pdev, struct sdhci_pci_chip *chip, int bar)
+       struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar,
+       int slotno)
 {
        struct sdhci_pci_slot *slot;
        struct sdhci_host *host;
-       int ret;
+       int ret, bar = first_bar + slotno;
 
        if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
                dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar);
@@ -1228,6 +1185,23 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
        slot->host = host;
        slot->pci_bar = bar;
        slot->rst_n_gpio = -EINVAL;
+       slot->cd_gpio = -EINVAL;
+
+       /* Retrieve platform data if there is any */
+       if (*sdhci_pci_get_data)
+               slot->data = sdhci_pci_get_data(pdev, slotno);
+
+       if (slot->data) {
+               if (slot->data->setup) {
+                       ret = slot->data->setup(slot->data);
+                       if (ret) {
+                               dev_err(&pdev->dev, "platform setup failed\n");
+                               goto free;
+                       }
+               }
+               slot->rst_n_gpio = slot->data->rst_n_gpio;
+               slot->cd_gpio = slot->data->cd_gpio;
+       }
 
        host->hw_name = "PCI";
        host->ops = &sdhci_pci_ops;
@@ -1238,7 +1212,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
        ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc));
        if (ret) {
                dev_err(&pdev->dev, "cannot request region\n");
-               goto free;
+               goto cleanup;
        }
 
        host->ioaddr = pci_ioremap_bar(pdev, bar);
@@ -1254,15 +1228,30 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
                        goto unmap;
        }
 
+       if (gpio_is_valid(slot->rst_n_gpio)) {
+               if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) {
+                       gpio_direction_output(slot->rst_n_gpio, 1);
+                       slot->host->mmc->caps |= MMC_CAP_HW_RESET;
+               } else {
+                       dev_warn(&pdev->dev, "failed to request rst_n_gpio\n");
+                       slot->rst_n_gpio = -EINVAL;
+               }
+       }
+
        host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
 
        ret = sdhci_add_host(host);
        if (ret)
                goto remove;
 
+       sdhci_pci_add_own_cd(slot);
+
        return slot;
 
 remove:
+       if (gpio_is_valid(slot->rst_n_gpio))
+               gpio_free(slot->rst_n_gpio);
+
        if (chip->fixes && chip->fixes->remove_slot)
                chip->fixes->remove_slot(slot, 0);
 
@@ -1272,6 +1261,10 @@ unmap:
 release:
        pci_release_region(pdev, bar);
 
+cleanup:
+       if (slot->data && slot->data->cleanup)
+               slot->data->cleanup(slot->data);
+
 free:
        sdhci_free_host(host);
 
@@ -1283,6 +1276,8 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
        int dead;
        u32 scratch;
 
+       sdhci_pci_remove_own_cd(slot);
+
        dead = 0;
        scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS);
        if (scratch == (u32)-1)
@@ -1290,9 +1285,15 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
 
        sdhci_remove_host(slot->host, dead);
 
+       if (gpio_is_valid(slot->rst_n_gpio))
+               gpio_free(slot->rst_n_gpio);
+
        if (slot->chip->fixes && slot->chip->fixes->remove_slot)
                slot->chip->fixes->remove_slot(slot, dead);
 
+       if (slot->data && slot->data->cleanup)
+               slot->data->cleanup(slot->data);
+
        pci_release_region(slot->chip->pdev, slot->pci_bar);
 
        sdhci_free_host(slot->host);
@@ -1379,7 +1380,7 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
        slots = chip->num_slots;        /* Quirk may have changed this */
 
        for (i = 0; i < slots; i++) {
-               slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i);
+               slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i);
                if (IS_ERR(slot)) {
                        for (i--; i >= 0; i--)
                                sdhci_pci_remove_slot(chip->slots[i]);
index 7a039c3cb1f10a8651ae04091c8303008ad2cbe2..dbb75bfbcffb3e181f6d0af195209e5187c3b210 100644 (file)
@@ -223,18 +223,8 @@ static struct platform_driver sdhci_pxav2_driver = {
        .probe          = sdhci_pxav2_probe,
        .remove         = __devexit_p(sdhci_pxav2_remove),
 };
-static int __init sdhci_pxav2_init(void)
-{
-       return platform_driver_register(&sdhci_pxav2_driver);
-}
-
-static void __exit sdhci_pxav2_exit(void)
-{
-       platform_driver_unregister(&sdhci_pxav2_driver);
-}
 
-module_init(sdhci_pxav2_init);
-module_exit(sdhci_pxav2_exit);
+module_platform_driver(sdhci_pxav2_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for pxav2");
 MODULE_AUTHOR("Marvell International Ltd.");
index 15673a7ee6a59a70d7455179f3afe30b3fb15588..f29695683556df8f7c01ad6f145a9fc36583e410 100644 (file)
@@ -269,18 +269,8 @@ static struct platform_driver sdhci_pxav3_driver = {
        .probe          = sdhci_pxav3_probe,
        .remove         = __devexit_p(sdhci_pxav3_remove),
 };
-static int __init sdhci_pxav3_init(void)
-{
-       return platform_driver_register(&sdhci_pxav3_driver);
-}
-
-static void __exit sdhci_pxav3_exit(void)
-{
-       platform_driver_unregister(&sdhci_pxav3_driver);
-}
 
-module_init(sdhci_pxav3_init);
-module_exit(sdhci_pxav3_exit);
+module_platform_driver(sdhci_pxav3_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for pxav3");
 MODULE_AUTHOR("Marvell International Ltd.");
index 9a20d1f55bb7a616408f3bc5fc0f41cefec0c64f..1af756ee0f9ab5e43db1a348505021a6fd5eee28 100644 (file)
@@ -80,7 +80,7 @@ static void sdhci_s3c_check_sclk(struct sdhci_host *host)
 
                tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
                tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
-               writel(tmp, host->ioaddr + 0x80);
+               writel(tmp, host->ioaddr + S3C_SDHCI_CONTROL2);
        }
 }
 
@@ -521,6 +521,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        if (pdata->host_caps)
                host->mmc->caps |= pdata->host_caps;
 
+       if (pdata->pm_caps)
+               host->mmc->pm_caps |= pdata->pm_caps;
+
        host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR |
                         SDHCI_QUIRK_32BIT_DMA_SIZE);
 
@@ -654,18 +657,7 @@ static struct platform_driver sdhci_s3c_driver = {
        },
 };
 
-static int __init sdhci_s3c_init(void)
-{
-       return platform_driver_register(&sdhci_s3c_driver);
-}
-
-static void __exit sdhci_s3c_exit(void)
-{
-       platform_driver_unregister(&sdhci_s3c_driver);
-}
-
-module_init(sdhci_s3c_init);
-module_exit(sdhci_s3c_exit);
+module_platform_driver(sdhci_s3c_driver);
 
 MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue");
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
index 63cc8b6a1c9e6335113f67b5dd84766819b7cb80..b7f8b33c5f19f7202f66d65fd90ff14b503f8dd4 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
 #include <linux/slab.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sdhci-spear.h>
@@ -271,26 +272,54 @@ static int __devexit sdhci_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int sdhci_suspend(struct device *dev)
+{
+       struct sdhci_host *host = dev_get_drvdata(dev);
+       struct spear_sdhci *sdhci = dev_get_platdata(dev);
+       int ret;
+
+       ret = sdhci_suspend_host(host);
+       if (!ret)
+               clk_disable(sdhci->clk);
+
+       return ret;
+}
+
+static int sdhci_resume(struct device *dev)
+{
+       struct sdhci_host *host = dev_get_drvdata(dev);
+       struct spear_sdhci *sdhci = dev_get_platdata(dev);
+       int ret;
+
+       ret = clk_enable(sdhci->clk);
+       if (ret) {
+               dev_dbg(dev, "Resume: Error enabling clock\n");
+               return ret;
+       }
+
+       return sdhci_resume_host(host);
+}
+
+const struct dev_pm_ops sdhci_pm_ops = {
+       .suspend        = sdhci_suspend,
+       .resume         = sdhci_resume,
+};
+#endif
+
 static struct platform_driver sdhci_driver = {
        .driver = {
                .name   = "sdhci",
                .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &sdhci_pm_ops,
+#endif
        },
        .probe          = sdhci_probe,
        .remove         = __devexit_p(sdhci_remove),
 };
 
-static int __init sdhci_init(void)
-{
-       return platform_driver_register(&sdhci_driver);
-}
-module_init(sdhci_init);
-
-static void __exit sdhci_exit(void)
-{
-       platform_driver_unregister(&sdhci_driver);
-}
-module_exit(sdhci_exit);
+module_platform_driver(sdhci_driver);
 
 MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver");
 MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
index e2e18d3f949c45dda79395646484a848a84d9326..78a36eba4df0b77d5fd433a3a805373484c50c22 100644 (file)
@@ -324,17 +324,7 @@ static struct platform_driver sdhci_tegra_driver = {
        .remove         = __devexit_p(sdhci_tegra_remove),
 };
 
-static int __init sdhci_tegra_init(void)
-{
-       return platform_driver_register(&sdhci_tegra_driver);
-}
-module_init(sdhci_tegra_init);
-
-static void __exit sdhci_tegra_exit(void)
-{
-       platform_driver_unregister(&sdhci_tegra_driver);
-}
-module_exit(sdhci_tegra_exit);
+module_platform_driver(sdhci_tegra_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for Tegra");
 MODULE_AUTHOR(" Google, Inc.");
index 19ed580f2cabf2fca09ae59d52cb86f5265f9ab8..8d66706824a6105ceeac2f63526372a4f0c521fd 100644 (file)
@@ -49,7 +49,7 @@ static void sdhci_finish_data(struct sdhci_host *);
 
 static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
 static void sdhci_finish_command(struct sdhci_host *);
-static int sdhci_execute_tuning(struct mmc_host *mmc);
+static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 static void sdhci_tuning_timer(unsigned long data);
 
 #ifdef CONFIG_PM_RUNTIME
@@ -146,10 +146,8 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
 {
        u32 present, irqs;
 
-       if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
-               return;
-
-       if (host->quirks2 & SDHCI_QUIRK2_OWN_CARD_DETECTION)
+       if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
+           !mmc_card_is_removable(host->mmc))
                return;
 
        present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
@@ -214,6 +212,11 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 
        if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
                sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
+
+       if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+               if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
+                       host->ops->enable_dma(host);
+       }
 }
 
 static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
@@ -423,12 +426,12 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
 static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
 {
        local_irq_save(*flags);
-       return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
+       return kmap_atomic(sg_page(sg)) + sg->offset;
 }
 
 static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
 {
-       kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
+       kunmap_atomic(buffer);
        local_irq_restore(*flags);
 }
 
@@ -1016,7 +1019,8 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
                flags |= SDHCI_CMD_INDEX;
 
        /* CMD19 is special in that the Data Present Select should be set */
-       if (cmd->data || (cmd->opcode == MMC_SEND_TUNING_BLOCK))
+       if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK ||
+           cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
                flags |= SDHCI_CMD_DATA;
 
        sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
@@ -1066,12 +1070,15 @@ static void sdhci_finish_command(struct sdhci_host *host)
 static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 {
        int div = 0; /* Initialized for compiler warning */
+       int real_div = div, clk_mul = 1;
        u16 clk = 0;
        unsigned long timeout;
 
-       if (clock == host->clock)
+       if (clock && clock == host->clock)
                return;
 
+       host->mmc->actual_clock = 0;
+
        if (host->ops->set_clock) {
                host->ops->set_clock(host, clock);
                if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
@@ -1109,6 +1116,8 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                                 * Control register.
                                 */
                                clk = SDHCI_PROG_CLOCK_MODE;
+                               real_div = div;
+                               clk_mul = host->clk_mul;
                                div--;
                        }
                } else {
@@ -1122,6 +1131,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                                                break;
                                }
                        }
+                       real_div = div;
                        div >>= 1;
                }
        } else {
@@ -1130,9 +1140,13 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                        if ((host->max_clk / div) <= clock)
                                break;
                }
+               real_div = div;
                div >>= 1;
        }
 
+       if (real_div)
+               host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div;
+
        clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
        clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
                << SDHCI_DIVIDER_HI_SHIFT;
@@ -1160,7 +1174,7 @@ out:
        host->clock = clock;
 }
 
-static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
+static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
 {
        u8 pwr = 0;
 
@@ -1183,13 +1197,13 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
        }
 
        if (host->pwr == pwr)
-               return;
+               return -1;
 
        host->pwr = pwr;
 
        if (pwr == 0) {
                sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
-               return;
+               return 0;
        }
 
        /*
@@ -1216,6 +1230,8 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
         */
        if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
                mdelay(10);
+
+       return power;
 }
 
 /*****************************************************************************\
@@ -1277,7 +1293,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
                if ((host->flags & SDHCI_NEEDS_RETUNING) &&
                    !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
                        spin_unlock_irqrestore(&host->lock, flags);
-                       sdhci_execute_tuning(mmc);
+                       sdhci_execute_tuning(mmc, mrq->cmd->opcode);
                        spin_lock_irqsave(&host->lock, flags);
 
                        /* Restore original mmc_request structure */
@@ -1297,12 +1313,17 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 {
        unsigned long flags;
+       int vdd_bit = -1;
        u8 ctrl;
 
        spin_lock_irqsave(&host->lock, flags);
 
-       if (host->flags & SDHCI_DEVICE_DEAD)
-               goto out;
+       if (host->flags & SDHCI_DEVICE_DEAD) {
+               spin_unlock_irqrestore(&host->lock, flags);
+               if (host->vmmc && ios->power_mode == MMC_POWER_OFF)
+                       mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
+               return;
+       }
 
        /*
         * Reset the chip on each power off.
@@ -1316,9 +1337,15 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
        sdhci_set_clock(host, ios->clock);
 
        if (ios->power_mode == MMC_POWER_OFF)
-               sdhci_set_power(host, -1);
+               vdd_bit = sdhci_set_power(host, -1);
        else
-               sdhci_set_power(host, ios->vdd);
+               vdd_bit = sdhci_set_power(host, ios->vdd);
+
+       if (host->vmmc && vdd_bit != -1) {
+               spin_unlock_irqrestore(&host->lock, flags);
+               mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
+               spin_lock_irqsave(&host->lock, flags);
+       }
 
        if (host->ops->platform_send_init_74_clocks)
                host->ops->platform_send_init_74_clocks(host, ios->power_mode);
@@ -1361,11 +1388,11 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                unsigned int clock;
 
                /* In case of UHS-I modes, set High Speed Enable */
-               if ((ios->timing == MMC_TIMING_UHS_SDR50) ||
+               if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+                   (ios->timing == MMC_TIMING_UHS_SDR50) ||
                    (ios->timing == MMC_TIMING_UHS_SDR104) ||
                    (ios->timing == MMC_TIMING_UHS_DDR50) ||
-                   (ios->timing == MMC_TIMING_UHS_SDR25) ||
-                   (ios->timing == MMC_TIMING_UHS_SDR12))
+                   (ios->timing == MMC_TIMING_UHS_SDR25))
                        ctrl |= SDHCI_CTRL_HISPD;
 
                ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
@@ -1415,7 +1442,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                        ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
                        /* Select Bus Speed Mode for host */
                        ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-                       if (ios->timing == MMC_TIMING_UHS_SDR12)
+                       if (ios->timing == MMC_TIMING_MMC_HS200)
+                               ctrl_2 |= SDHCI_CTRL_HS_SDR200;
+                       else if (ios->timing == MMC_TIMING_UHS_SDR12)
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
                        else if (ios->timing == MMC_TIMING_UHS_SDR25)
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
@@ -1443,7 +1472,6 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
        if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
                sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
-out:
        mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 }
@@ -1663,7 +1691,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
        return err;
 }
 
-static int sdhci_execute_tuning(struct mmc_host *mmc)
+static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
        struct sdhci_host *host;
        u16 ctrl;
@@ -1671,6 +1699,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc)
        int tuning_loop_counter = MAX_TUNING_LOOP;
        unsigned long timeout;
        int err = 0;
+       bool requires_tuning_nonuhs = false;
 
        host = mmc_priv(mmc);
 
@@ -1681,13 +1710,19 @@ static int sdhci_execute_tuning(struct mmc_host *mmc)
        ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 
        /*
-        * Host Controller needs tuning only in case of SDR104 mode
-        * and for SDR50 mode when Use Tuning for SDR50 is set in
+        * The Host Controller needs tuning only in case of SDR104 mode
+        * and for SDR50 mode when Use Tuning for SDR50 is set in the
         * Capabilities register.
+        * If the Host Controller supports the HS200 mode then the
+        * tuning function has to be executed.
         */
+       if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
+           (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
+            host->flags & SDHCI_HS200_NEEDS_TUNING))
+               requires_tuning_nonuhs = true;
+
        if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
-           (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
-           (host->flags & SDHCI_SDR50_NEEDS_TUNING)))
+           requires_tuning_nonuhs)
                ctrl |= SDHCI_CTRL_EXEC_TUNING;
        else {
                spin_unlock(&host->lock);
@@ -1723,7 +1758,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc)
                if (!tuning_loop_counter && !timeout)
                        break;
 
-               cmd.opcode = MMC_SEND_TUNING_BLOCK;
+               cmd.opcode = opcode;
                cmd.arg = 0;
                cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
                cmd.retries = 0;
@@ -1738,7 +1773,17 @@ static int sdhci_execute_tuning(struct mmc_host *mmc)
                 * block to the Host Controller. So we set the block size
                 * to 64 here.
                 */
-               sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);
+               if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) {
+                       if (mmc->ios.bus_width == MMC_BUS_WIDTH_8)
+                               sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128),
+                                            SDHCI_BLOCK_SIZE);
+                       else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4)
+                               sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
+                                            SDHCI_BLOCK_SIZE);
+               } else {
+                       sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
+                                    SDHCI_BLOCK_SIZE);
+               }
 
                /*
                 * The tuning block is sent by the card to the host controller.
@@ -2121,12 +2166,14 @@ static void sdhci_show_adma_error(struct sdhci_host *host) { }
 
 static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 {
+       u32 command;
        BUG_ON(intmask == 0);
 
        /* CMD19 generates _only_ Buffer Read Ready interrupt */
        if (intmask & SDHCI_INT_DATA_AVAIL) {
-               if (SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) ==
-                   MMC_SEND_TUNING_BLOCK) {
+               command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND));
+               if (command == MMC_SEND_TUNING_BLOCK ||
+                   command == MMC_SEND_TUNING_BLOCK_HS200) {
                        host->tuning_done = 1;
                        wake_up(&host->buf_ready_int);
                        return;
@@ -2330,26 +2377,33 @@ out:
 int sdhci_suspend_host(struct sdhci_host *host)
 {
        int ret;
+       bool has_tuning_timer;
 
        sdhci_disable_card_detection(host);
 
        /* Disable tuning since we are suspending */
-       if (host->version >= SDHCI_SPEC_300 && host->tuning_count &&
-           host->tuning_mode == SDHCI_TUNING_MODE_1) {
+       has_tuning_timer = host->version >= SDHCI_SPEC_300 &&
+               host->tuning_count && host->tuning_mode == SDHCI_TUNING_MODE_1;
+       if (has_tuning_timer) {
+               del_timer_sync(&host->tuning_timer);
                host->flags &= ~SDHCI_NEEDS_RETUNING;
-               mod_timer(&host->tuning_timer, jiffies +
-                       host->tuning_count * HZ);
        }
 
        ret = mmc_suspend_host(host->mmc);
-       if (ret)
+       if (ret) {
+               if (has_tuning_timer) {
+                       host->flags |= SDHCI_NEEDS_RETUNING;
+                       mod_timer(&host->tuning_timer, jiffies +
+                                       host->tuning_count * HZ);
+               }
+
+               sdhci_enable_card_detection(host);
+
                return ret;
+       }
 
        free_irq(host->irq, host);
 
-       if (host->vmmc)
-               ret = regulator_disable(host->vmmc);
-
        return ret;
 }
 
@@ -2359,12 +2413,6 @@ int sdhci_resume_host(struct sdhci_host *host)
 {
        int ret;
 
-       if (host->vmmc) {
-               int ret = regulator_enable(host->vmmc);
-               if (ret)
-                       return ret;
-       }
-
        if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
                if (host->ops->enable_dma)
                        host->ops->enable_dma(host);
@@ -2727,10 +2775,14 @@ int sdhci_add_host(struct sdhci_host *host)
        if (caps[1] & SDHCI_SUPPORT_DDR50)
                mmc->caps |= MMC_CAP_UHS_DDR50;
 
-       /* Does the host needs tuning for SDR50? */
+       /* Does the host need tuning for SDR50? */
        if (caps[1] & SDHCI_USE_SDR50_TUNING)
                host->flags |= SDHCI_SDR50_NEEDS_TUNING;
 
+       /* Does the host need tuning for HS200? */
+       if (mmc->caps2 & MMC_CAP2_HS200)
+               host->flags |= SDHCI_HS200_NEEDS_TUNING;
+
        /* Driver Type(s) (A, C, D) supported by the host */
        if (caps[1] & SDHCI_DRIVER_TYPE_A)
                mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
@@ -2926,8 +2978,6 @@ 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);
        }
 
        sdhci_init(host, 0);
@@ -3016,10 +3066,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
        tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->finish_tasklet);
 
-       if (host->vmmc) {
-               regulator_disable(host->vmmc);
+       if (host->vmmc)
                regulator_put(host->vmmc);
-       }
 
        kfree(host->adma_desc);
        kfree(host->align_buffer);
index a04d4d0c6fd20911c29f59a4f0132eea2cffa6b7..ad265b96b75b4f25262186ff68a171202c4474ee 100644 (file)
 #define   SDHCI_CTRL_UHS_SDR50         0x0002
 #define   SDHCI_CTRL_UHS_SDR104                0x0003
 #define   SDHCI_CTRL_UHS_DDR50         0x0004
+#define   SDHCI_CTRL_HS_SDR200         0x0005 /* reserved value in SDIO spec */
 #define  SDHCI_CTRL_VDD_180            0x0008
 #define  SDHCI_CTRL_DRV_TYPE_MASK      0x0030
 #define   SDHCI_CTRL_DRV_TYPE_B                0x0000
index d5505f3fe2a170d04fc9011c5b5d2ff886a31df7..f5d8b53be333aa9c997b0e82c1e8e69a8204eb0d 100644 (file)
  *
  */
 
+/*
+ * The MMCIF driver is now processing MMC requests asynchronously, according
+ * to the Linux MMC API requirement.
+ *
+ * The MMCIF driver processes MMC requests in up to 3 stages: command, optional
+ * data, and optional stop. To achieve asynchronous processing each of these
+ * stages is split into two halves: a top and a bottom half. The top half
+ * initialises the hardware, installs a timeout handler to handle completion
+ * timeouts, and returns. In case of the command stage this immediately returns
+ * control to the caller, leaving all further processing to run asynchronously.
+ * All further request processing is performed by the bottom halves.
+ *
+ * The bottom half further consists of a "hard" IRQ handler, an IRQ handler
+ * thread, a DMA completion callback, if DMA is used, a timeout work, and
+ * request- and stage-specific handler methods.
+ *
+ * Each bottom half run begins with either a hardware interrupt, a DMA callback
+ * invocation, or a timeout work run. In case of an error or a successful
+ * processing completion, the MMC core is informed and the request processing is
+ * finished. In case processing has to continue, i.e., if data has to be read
+ * from or written to the card, or if a stop command has to be sent, the next
+ * top half is called, which performs the necessary hardware handling and
+ * reschedules the timeout work. This returns the driver state machine into the
+ * bottom half waiting state.
+ */
+
+#include <linux/bitops.h>
 #include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
 #define MASK_MRBSYTO           (1 << 1)
 #define MASK_MRSPTO            (1 << 0)
 
+#define MASK_START_CMD         (MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | \
+                                MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | \
+                                MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | \
+                                MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO)
+
 /* CE_HOST_STS1 */
 #define STS1_CMDSEQ            (1 << 31)
 
@@ -162,9 +194,21 @@ enum mmcif_state {
        STATE_IOS,
 };
 
+enum mmcif_wait_for {
+       MMCIF_WAIT_FOR_REQUEST,
+       MMCIF_WAIT_FOR_CMD,
+       MMCIF_WAIT_FOR_MREAD,
+       MMCIF_WAIT_FOR_MWRITE,
+       MMCIF_WAIT_FOR_READ,
+       MMCIF_WAIT_FOR_WRITE,
+       MMCIF_WAIT_FOR_READ_END,
+       MMCIF_WAIT_FOR_WRITE_END,
+       MMCIF_WAIT_FOR_STOP,
+};
+
 struct sh_mmcif_host {
        struct mmc_host *mmc;
-       struct mmc_data *data;
+       struct mmc_request *mrq;
        struct platform_device *pd;
        struct sh_dmae_slave dma_slave_tx;
        struct sh_dmae_slave dma_slave_rx;
@@ -172,11 +216,17 @@ struct sh_mmcif_host {
        unsigned int clk;
        int bus_width;
        bool sd_error;
+       bool dying;
        long timeout;
        void __iomem *addr;
-       struct completion intr_wait;
+       u32 *pio_ptr;
+       spinlock_t lock;                /* protect sh_mmcif_host::state */
        enum mmcif_state state;
-       spinlock_t lock;
+       enum mmcif_wait_for wait_for;
+       struct delayed_work timeout_work;
+       size_t blocksize;
+       int sg_idx;
+       int sg_blkidx;
        bool power;
        bool card_present;
 
@@ -202,19 +252,21 @@ static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host,
 static void mmcif_dma_complete(void *arg)
 {
        struct sh_mmcif_host *host = arg;
+       struct mmc_data *data = host->mrq->data;
+
        dev_dbg(&host->pd->dev, "Command completed\n");
 
-       if (WARN(!host->data, "%s: NULL data in DMA completion!\n",
+       if (WARN(!data, "%s: NULL data in DMA completion!\n",
                 dev_name(&host->pd->dev)))
                return;
 
-       if (host->data->flags & MMC_DATA_READ)
+       if (data->flags & MMC_DATA_READ)
                dma_unmap_sg(host->chan_rx->device->dev,
-                            host->data->sg, host->data->sg_len,
+                            data->sg, data->sg_len,
                             DMA_FROM_DEVICE);
        else
                dma_unmap_sg(host->chan_tx->device->dev,
-                            host->data->sg, host->data->sg_len,
+                            data->sg, data->sg_len,
                             DMA_TO_DEVICE);
 
        complete(&host->dma_complete);
@@ -222,18 +274,19 @@ static void mmcif_dma_complete(void *arg)
 
 static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
 {
-       struct scatterlist *sg = host->data->sg;
+       struct mmc_data *data = host->mrq->data;
+       struct scatterlist *sg = data->sg;
        struct dma_async_tx_descriptor *desc = NULL;
        struct dma_chan *chan = host->chan_rx;
        dma_cookie_t cookie = -EINVAL;
        int ret;
 
-       ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len,
+       ret = dma_map_sg(chan->device->dev, sg, data->sg_len,
                         DMA_FROM_DEVICE);
        if (ret > 0) {
                host->dma_active = true;
                desc = chan->device->device_prep_slave_sg(chan, sg, ret,
-                       DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+                       DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        }
 
        if (desc) {
@@ -244,7 +297,7 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
                dma_async_issue_pending(chan);
        }
        dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
-               __func__, host->data->sg_len, ret, cookie);
+               __func__, data->sg_len, ret, cookie);
 
        if (!desc) {
                /* DMA failed, fall back to PIO */
@@ -265,23 +318,24 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
        }
 
        dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__,
-               desc, cookie, host->data->sg_len);
+               desc, cookie, data->sg_len);
 }
 
 static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
 {
-       struct scatterlist *sg = host->data->sg;
+       struct mmc_data *data = host->mrq->data;
+       struct scatterlist *sg = data->sg;
        struct dma_async_tx_descriptor *desc = NULL;
        struct dma_chan *chan = host->chan_tx;
        dma_cookie_t cookie = -EINVAL;
        int ret;
 
-       ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len,
+       ret = dma_map_sg(chan->device->dev, sg, data->sg_len,
                         DMA_TO_DEVICE);
        if (ret > 0) {
                host->dma_active = true;
                desc = chan->device->device_prep_slave_sg(chan, sg, ret,
-                       DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+                       DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        }
 
        if (desc) {
@@ -292,7 +346,7 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
                dma_async_issue_pending(chan);
        }
        dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
-               __func__, host->data->sg_len, ret, cookie);
+               __func__, data->sg_len, ret, cookie);
 
        if (!desc) {
                /* DMA failed, fall back to PIO */
@@ -399,7 +453,7 @@ static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
                sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK);
        else
                sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR &
-                       (ilog2(__rounddown_pow_of_two(host->clk / clk)) << 16));
+                               ((fls(host->clk / clk) - 1) << 16));
 
        sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
 }
@@ -421,7 +475,7 @@ static void sh_mmcif_sync_reset(struct sh_mmcif_host *host)
 static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
 {
        u32 state1, state2;
-       int ret, timeout = 10000000;
+       int ret, timeout;
 
        host->sd_error = false;
 
@@ -433,155 +487,212 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
        if (state1 & STS1_CMDSEQ) {
                sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
                sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK);
-               while (1) {
-                       timeout--;
-                       if (timeout < 0) {
-                               dev_err(&host->pd->dev,
-                                       "Forceed end of command sequence timeout err\n");
-                               return -EIO;
-                       }
+               for (timeout = 10000000; timeout; timeout--) {
                        if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1)
-                                                               & STS1_CMDSEQ))
+                             & STS1_CMDSEQ))
                                break;
                        mdelay(1);
                }
+               if (!timeout) {
+                       dev_err(&host->pd->dev,
+                               "Forced end of command sequence timeout err\n");
+                       return -EIO;
+               }
                sh_mmcif_sync_reset(host);
                dev_dbg(&host->pd->dev, "Forced end of command sequence\n");
                return -EIO;
        }
 
        if (state2 & STS2_CRC_ERR) {
-               dev_dbg(&host->pd->dev, ": Happened CRC error\n");
+               dev_dbg(&host->pd->dev, ": CRC error\n");
                ret = -EIO;
        } else if (state2 & STS2_TIMEOUT_ERR) {
-               dev_dbg(&host->pd->dev, ": Happened Timeout error\n");
+               dev_dbg(&host->pd->dev, ": Timeout\n");
                ret = -ETIMEDOUT;
        } else {
-               dev_dbg(&host->pd->dev, ": Happened End/Index error\n");
+               dev_dbg(&host->pd->dev, ": End/Index error\n");
                ret = -EIO;
        }
        return ret;
 }
 
-static int sh_mmcif_single_read(struct sh_mmcif_host *host,
-                                       struct mmc_request *mrq)
+static bool sh_mmcif_next_block(struct sh_mmcif_host *host, u32 *p)
 {
-       struct mmc_data *data = mrq->data;
-       long time;
-       u32 blocksize, i, *p = sg_virt(data->sg);
+       struct mmc_data *data = host->mrq->data;
+
+       host->sg_blkidx += host->blocksize;
+
+       /* data->sg->length must be a multiple of host->blocksize? */
+       BUG_ON(host->sg_blkidx > data->sg->length);
+
+       if (host->sg_blkidx == data->sg->length) {
+               host->sg_blkidx = 0;
+               if (++host->sg_idx < data->sg_len)
+                       host->pio_ptr = sg_virt(++data->sg);
+       } else {
+               host->pio_ptr = p;
+       }
+
+       if (host->sg_idx == data->sg_len)
+               return false;
+
+       return true;
+}
+
+static void sh_mmcif_single_read(struct sh_mmcif_host *host,
+                                struct mmc_request *mrq)
+{
+       host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
+                          BLOCK_SIZE_MASK) + 3;
+
+       host->wait_for = MMCIF_WAIT_FOR_READ;
+       schedule_delayed_work(&host->timeout_work, host->timeout);
 
        /* buf read enable */
        sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
-       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                       host->timeout);
-       if (time <= 0 || host->sd_error)
-               return sh_mmcif_error_manage(host);
-
-       blocksize = (BLOCK_SIZE_MASK &
-                       sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
-       for (i = 0; i < blocksize / 4; i++)
+}
+
+static bool sh_mmcif_read_block(struct sh_mmcif_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+       u32 *p = sg_virt(data->sg);
+       int i;
+
+       if (host->sd_error) {
+               data->error = sh_mmcif_error_manage(host);
+               return false;
+       }
+
+       for (i = 0; i < host->blocksize / 4; i++)
                *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA);
 
        /* buffer read end */
        sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
-       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                       host->timeout);
-       if (time <= 0 || host->sd_error)
-               return sh_mmcif_error_manage(host);
+       host->wait_for = MMCIF_WAIT_FOR_READ_END;
 
-       return 0;
+       return true;
 }
 
-static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
-                                       struct mmc_request *mrq)
+static void sh_mmcif_multi_read(struct sh_mmcif_host *host,
+                               struct mmc_request *mrq)
 {
        struct mmc_data *data = mrq->data;
-       long time;
-       u32 blocksize, i, j, sec, *p;
-
-       blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr,
-                                                    MMCIF_CE_BLOCK_SET);
-       for (j = 0; j < data->sg_len; j++) {
-               p = sg_virt(data->sg);
-               for (sec = 0; sec < data->sg->length / blocksize; sec++) {
-                       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
-                       /* buf read enable */
-                       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                               host->timeout);
-
-                       if (time <= 0 || host->sd_error)
-                               return sh_mmcif_error_manage(host);
-
-                       for (i = 0; i < blocksize / 4; i++)
-                               *p++ = sh_mmcif_readl(host->addr,
-                                                     MMCIF_CE_DATA);
-               }
-               if (j < data->sg_len - 1)
-                       data->sg++;
+
+       if (!data->sg_len || !data->sg->length)
+               return;
+
+       host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
+               BLOCK_SIZE_MASK;
+
+       host->wait_for = MMCIF_WAIT_FOR_MREAD;
+       host->sg_idx = 0;
+       host->sg_blkidx = 0;
+       host->pio_ptr = sg_virt(data->sg);
+       schedule_delayed_work(&host->timeout_work, host->timeout);
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
+}
+
+static bool sh_mmcif_mread_block(struct sh_mmcif_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+       u32 *p = host->pio_ptr;
+       int i;
+
+       if (host->sd_error) {
+               data->error = sh_mmcif_error_manage(host);
+               return false;
        }
-       return 0;
+
+       BUG_ON(!data->sg->length);
+
+       for (i = 0; i < host->blocksize / 4; i++)
+               *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA);
+
+       if (!sh_mmcif_next_block(host, p))
+               return false;
+
+       schedule_delayed_work(&host->timeout_work, host->timeout);
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
+
+       return true;
 }
 
-static int sh_mmcif_single_write(struct sh_mmcif_host *host,
+static void sh_mmcif_single_write(struct sh_mmcif_host *host,
                                        struct mmc_request *mrq)
 {
-       struct mmc_data *data = mrq->data;
-       long time;
-       u32 blocksize, i, *p = sg_virt(data->sg);
+       host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
+                          BLOCK_SIZE_MASK) + 3;
 
-       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+       host->wait_for = MMCIF_WAIT_FOR_WRITE;
+       schedule_delayed_work(&host->timeout_work, host->timeout);
 
        /* buf write enable */
-       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                       host->timeout);
-       if (time <= 0 || host->sd_error)
-               return sh_mmcif_error_manage(host);
-
-       blocksize = (BLOCK_SIZE_MASK &
-                       sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
-       for (i = 0; i < blocksize / 4; i++)
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+}
+
+static bool sh_mmcif_write_block(struct sh_mmcif_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+       u32 *p = sg_virt(data->sg);
+       int i;
+
+       if (host->sd_error) {
+               data->error = sh_mmcif_error_manage(host);
+               return false;
+       }
+
+       for (i = 0; i < host->blocksize / 4; i++)
                sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++);
 
        /* buffer write end */
        sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
+       host->wait_for = MMCIF_WAIT_FOR_WRITE_END;
 
-       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                       host->timeout);
-       if (time <= 0 || host->sd_error)
-               return sh_mmcif_error_manage(host);
-
-       return 0;
+       return true;
 }
 
-static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
-                                               struct mmc_request *mrq)
+static void sh_mmcif_multi_write(struct sh_mmcif_host *host,
+                               struct mmc_request *mrq)
 {
        struct mmc_data *data = mrq->data;
-       long time;
-       u32 i, sec, j, blocksize, *p;
 
-       blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr,
-                                                    MMCIF_CE_BLOCK_SET);
+       if (!data->sg_len || !data->sg->length)
+               return;
 
-       for (j = 0; j < data->sg_len; j++) {
-               p = sg_virt(data->sg);
-               for (sec = 0; sec < data->sg->length / blocksize; sec++) {
-                       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
-                       /* buf write enable*/
-                       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                               host->timeout);
+       host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
+               BLOCK_SIZE_MASK;
 
-                       if (time <= 0 || host->sd_error)
-                               return sh_mmcif_error_manage(host);
+       host->wait_for = MMCIF_WAIT_FOR_MWRITE;
+       host->sg_idx = 0;
+       host->sg_blkidx = 0;
+       host->pio_ptr = sg_virt(data->sg);
+       schedule_delayed_work(&host->timeout_work, host->timeout);
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+}
 
-                       for (i = 0; i < blocksize / 4; i++)
-                               sh_mmcif_writel(host->addr,
-                                               MMCIF_CE_DATA, *p++);
-               }
-               if (j < data->sg_len - 1)
-                       data->sg++;
+static bool sh_mmcif_mwrite_block(struct sh_mmcif_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+       u32 *p = host->pio_ptr;
+       int i;
+
+       if (host->sd_error) {
+               data->error = sh_mmcif_error_manage(host);
+               return false;
        }
-       return 0;
+
+       BUG_ON(!data->sg->length);
+
+       for (i = 0; i < host->blocksize / 4; i++)
+               sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++);
+
+       if (!sh_mmcif_next_block(host, p))
+               return false;
+
+       schedule_delayed_work(&host->timeout_work, host->timeout);
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+
+       return true;
 }
 
 static void sh_mmcif_get_response(struct sh_mmcif_host *host,
@@ -603,8 +714,11 @@ static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host,
 }
 
 static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
-               struct mmc_request *mrq, struct mmc_command *cmd, u32 opc)
+                           struct mmc_request *mrq)
 {
+       struct mmc_data *data = mrq->data;
+       struct mmc_command *cmd = mrq->cmd;
+       u32 opc = cmd->opcode;
        u32 tmp = 0;
 
        /* Response Type check */
@@ -636,7 +750,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
                break;
        }
        /* WDAT / DATW */
-       if (host->data) {
+       if (data) {
                tmp |= CMD_SET_WDAT;
                switch (host->bus_width) {
                case MMC_BUS_WIDTH_1:
@@ -660,7 +774,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
        if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) {
                tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
                sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET,
-                                       mrq->data->blocks << 16);
+                               data->blocks << 16);
        }
        /* RIDXC[1:0] check bits */
        if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID ||
@@ -674,68 +788,60 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
                opc == MMC_SEND_CSD || opc == MMC_SEND_CID)
                tmp |= CMD_SET_CRC7C_INTERNAL;
 
-       return opc = ((opc << 24) | tmp);
+       return (opc << 24) | tmp;
 }
 
 static int sh_mmcif_data_trans(struct sh_mmcif_host *host,
-                               struct mmc_request *mrq, u32 opc)
+                              struct mmc_request *mrq, u32 opc)
 {
-       int ret;
-
        switch (opc) {
        case MMC_READ_MULTIPLE_BLOCK:
-               ret = sh_mmcif_multi_read(host, mrq);
-               break;
+               sh_mmcif_multi_read(host, mrq);
+               return 0;
        case MMC_WRITE_MULTIPLE_BLOCK:
-               ret = sh_mmcif_multi_write(host, mrq);
-               break;
+               sh_mmcif_multi_write(host, mrq);
+               return 0;
        case MMC_WRITE_BLOCK:
-               ret = sh_mmcif_single_write(host, mrq);
-               break;
+               sh_mmcif_single_write(host, mrq);
+               return 0;
        case MMC_READ_SINGLE_BLOCK:
        case MMC_SEND_EXT_CSD:
-               ret = sh_mmcif_single_read(host, mrq);
-               break;
+               sh_mmcif_single_read(host, mrq);
+               return 0;
        default:
                dev_err(&host->pd->dev, "UNSUPPORTED CMD = d'%08d\n", opc);
-               ret = -EINVAL;
-               break;
+               return -EINVAL;
        }
-       return ret;
 }
 
 static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
-                       struct mmc_request *mrq, struct mmc_command *cmd)
+                              struct mmc_request *mrq)
 {
-       long time;
-       int ret = 0, mask = 0;
+       struct mmc_command *cmd = mrq->cmd;
        u32 opc = cmd->opcode;
+       u32 mask;
 
        switch (opc) {
-       /* respons busy check */
+       /* response busy check */
        case MMC_SWITCH:
        case MMC_STOP_TRANSMISSION:
        case MMC_SET_WRITE_PROT:
        case MMC_CLR_WRITE_PROT:
        case MMC_ERASE:
        case MMC_GEN_CMD:
-               mask = MASK_MRBSYE;
+               mask = MASK_START_CMD | MASK_MRBSYE;
                break;
        default:
-               mask = MASK_MCRSPE;
+               mask = MASK_START_CMD | MASK_MCRSPE;
                break;
        }
-       mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR |
-               MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR |
-               MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO |
-               MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO;
 
-       if (host->data) {
+       if (mrq->data) {
                sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0);
                sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET,
                                mrq->data->blksz);
        }
-       opc = sh_mmcif_set_cmd(host, mrq, cmd, opc);
+       opc = sh_mmcif_set_cmd(host, mrq);
 
        sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0);
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask);
@@ -744,80 +850,28 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
        /* set cmd */
        sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc);
 
-       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-               host->timeout);
-       if (time <= 0) {
-               cmd->error = sh_mmcif_error_manage(host);
-               return;
-       }
-       if (host->sd_error) {
-               switch (cmd->opcode) {
-               case MMC_ALL_SEND_CID:
-               case MMC_SELECT_CARD:
-               case MMC_APP_CMD:
-                       cmd->error = -ETIMEDOUT;
-                       break;
-               default:
-                       dev_dbg(&host->pd->dev, "Cmd(d'%d) err\n",
-                                       cmd->opcode);
-                       cmd->error = sh_mmcif_error_manage(host);
-                       break;
-               }
-               host->sd_error = false;
-               return;
-       }
-       if (!(cmd->flags & MMC_RSP_PRESENT)) {
-               cmd->error = 0;
-               return;
-       }
-       sh_mmcif_get_response(host, cmd);
-       if (host->data) {
-               if (!host->dma_active) {
-                       ret = sh_mmcif_data_trans(host, mrq, cmd->opcode);
-               } else {
-                       long time =
-                               wait_for_completion_interruptible_timeout(&host->dma_complete,
-                                                                         host->timeout);
-                       if (!time)
-                               ret = -ETIMEDOUT;
-                       else if (time < 0)
-                               ret = time;
-                       sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC,
-                                       BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
-                       host->dma_active = false;
-               }
-               if (ret < 0)
-                       mrq->data->bytes_xfered = 0;
-               else
-                       mrq->data->bytes_xfered =
-                               mrq->data->blocks * mrq->data->blksz;
-       }
-       cmd->error = ret;
+       host->wait_for = MMCIF_WAIT_FOR_CMD;
+       schedule_delayed_work(&host->timeout_work, host->timeout);
 }
 
 static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
-               struct mmc_request *mrq, struct mmc_command *cmd)
+                             struct mmc_request *mrq)
 {
-       long time;
-
-       if (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK)
+       switch (mrq->cmd->opcode) {
+       case MMC_READ_MULTIPLE_BLOCK:
                sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE);
-       else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
+               break;
+       case MMC_WRITE_MULTIPLE_BLOCK:
                sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
-       else {
+               break;
+       default:
                dev_err(&host->pd->dev, "unsupported stop cmd\n");
-               cmd->error = sh_mmcif_error_manage(host);
+               mrq->stop->error = sh_mmcif_error_manage(host);
                return;
        }
 
-       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                       host->timeout);
-       if (time <= 0 || host->sd_error) {
-               cmd->error = sh_mmcif_error_manage(host);
-               return;
-       }
-       sh_mmcif_get_cmd12response(host, cmd);
-       cmd->error = 0;
+       host->wait_for = MMCIF_WAIT_FOR_STOP;
+       schedule_delayed_work(&host->timeout_work, host->timeout);
 }
 
 static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
@@ -856,23 +910,10 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
        default:
                break;
        }
-       host->data = mrq->data;
-       if (mrq->data) {
-               if (mrq->data->flags & MMC_DATA_READ) {
-                       if (host->chan_rx)
-                               sh_mmcif_start_dma_rx(host);
-               } else {
-                       if (host->chan_tx)
-                               sh_mmcif_start_dma_tx(host);
-               }
-       }
-       sh_mmcif_start_cmd(host, mrq, mrq->cmd);
-       host->data = NULL;
 
-       if (!mrq->cmd->error && mrq->stop)
-               sh_mmcif_stop_cmd(host, mrq, mrq->stop);
-       host->state = STATE_IDLE;
-       mmc_request_done(mmc, mrq);
+       host->mrq = mrq;
+
+       sh_mmcif_start_cmd(host, mrq);
 }
 
 static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -947,9 +988,156 @@ static struct mmc_host_ops sh_mmcif_ops = {
        .get_cd         = sh_mmcif_get_cd,
 };
 
-static void sh_mmcif_detect(struct mmc_host *mmc)
+static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
 {
-       mmc_detect_change(mmc, 0);
+       struct mmc_command *cmd = host->mrq->cmd;
+       struct mmc_data *data = host->mrq->data;
+       long time;
+
+       if (host->sd_error) {
+               switch (cmd->opcode) {
+               case MMC_ALL_SEND_CID:
+               case MMC_SELECT_CARD:
+               case MMC_APP_CMD:
+                       cmd->error = -ETIMEDOUT;
+                       host->sd_error = false;
+                       break;
+               default:
+                       cmd->error = sh_mmcif_error_manage(host);
+                       dev_dbg(&host->pd->dev, "Cmd(d'%d) error %d\n",
+                               cmd->opcode, cmd->error);
+                       break;
+               }
+               return false;
+       }
+       if (!(cmd->flags & MMC_RSP_PRESENT)) {
+               cmd->error = 0;
+               return false;
+       }
+
+       sh_mmcif_get_response(host, cmd);
+
+       if (!data)
+               return false;
+
+       if (data->flags & MMC_DATA_READ) {
+               if (host->chan_rx)
+                       sh_mmcif_start_dma_rx(host);
+       } else {
+               if (host->chan_tx)
+                       sh_mmcif_start_dma_tx(host);
+       }
+
+       if (!host->dma_active) {
+               data->error = sh_mmcif_data_trans(host, host->mrq, cmd->opcode);
+               if (!data->error)
+                       return true;
+               return false;
+       }
+
+       /* Running in the IRQ thread, can sleep */
+       time = wait_for_completion_interruptible_timeout(&host->dma_complete,
+                                                        host->timeout);
+       if (host->sd_error) {
+               dev_err(host->mmc->parent,
+                       "Error IRQ while waiting for DMA completion!\n");
+               /* Woken up by an error IRQ: abort DMA */
+               if (data->flags & MMC_DATA_READ)
+                       dmaengine_terminate_all(host->chan_rx);
+               else
+                       dmaengine_terminate_all(host->chan_tx);
+               data->error = sh_mmcif_error_manage(host);
+       } else if (!time) {
+               data->error = -ETIMEDOUT;
+       } else if (time < 0) {
+               data->error = time;
+       }
+       sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC,
+                       BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
+       host->dma_active = false;
+
+       if (data->error)
+               data->bytes_xfered = 0;
+
+       return false;
+}
+
+static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
+{
+       struct sh_mmcif_host *host = dev_id;
+       struct mmc_request *mrq = host->mrq;
+       struct mmc_data *data = mrq->data;
+
+       cancel_delayed_work_sync(&host->timeout_work);
+
+       /*
+        * All handlers return true, if processing continues, and false, if the
+        * request has to be completed - successfully or not
+        */
+       switch (host->wait_for) {
+       case MMCIF_WAIT_FOR_REQUEST:
+               /* We're too late, the timeout has already kicked in */
+               return IRQ_HANDLED;
+       case MMCIF_WAIT_FOR_CMD:
+               if (sh_mmcif_end_cmd(host))
+                       /* Wait for data */
+                       return IRQ_HANDLED;
+               break;
+       case MMCIF_WAIT_FOR_MREAD:
+               if (sh_mmcif_mread_block(host))
+                       /* Wait for more data */
+                       return IRQ_HANDLED;
+               break;
+       case MMCIF_WAIT_FOR_READ:
+               if (sh_mmcif_read_block(host))
+                       /* Wait for data end */
+                       return IRQ_HANDLED;
+               break;
+       case MMCIF_WAIT_FOR_MWRITE:
+               if (sh_mmcif_mwrite_block(host))
+                       /* Wait data to write */
+                       return IRQ_HANDLED;
+               break;
+       case MMCIF_WAIT_FOR_WRITE:
+               if (sh_mmcif_write_block(host))
+                       /* Wait for data end */
+                       return IRQ_HANDLED;
+               break;
+       case MMCIF_WAIT_FOR_STOP:
+               if (host->sd_error) {
+                       mrq->stop->error = sh_mmcif_error_manage(host);
+                       break;
+               }
+               sh_mmcif_get_cmd12response(host, mrq->stop);
+               mrq->stop->error = 0;
+               break;
+       case MMCIF_WAIT_FOR_READ_END:
+       case MMCIF_WAIT_FOR_WRITE_END:
+               if (host->sd_error)
+                       data->error = sh_mmcif_error_manage(host);
+               break;
+       default:
+               BUG();
+       }
+
+       if (host->wait_for != MMCIF_WAIT_FOR_STOP) {
+               if (!mrq->cmd->error && data && !data->error)
+                       data->bytes_xfered =
+                               data->blocks * data->blksz;
+
+               if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) {
+                       sh_mmcif_stop_cmd(host, mrq);
+                       if (!mrq->stop->error)
+                               return IRQ_HANDLED;
+               }
+       }
+
+       host->wait_for = MMCIF_WAIT_FOR_REQUEST;
+       host->state = STATE_IDLE;
+       host->mrq = NULL;
+       mmc_request_done(host->mmc, mrq);
+
+       return IRQ_HANDLED;
 }
 
 static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
@@ -960,7 +1148,12 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
 
        state = sh_mmcif_readl(host->addr, MMCIF_CE_INT);
 
-       if (state & INT_RBSYE) {
+       if (state & INT_ERR_STS) {
+               /* error interrupts - process first */
+               sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
+               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
+               err = 1;
+       } else if (state & INT_RBSYE) {
                sh_mmcif_writel(host->addr, MMCIF_CE_INT,
                                ~(INT_RBSYE | INT_CRSPE));
                sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE);
@@ -988,11 +1181,6 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
                sh_mmcif_writel(host->addr, MMCIF_CE_INT,
                                ~(INT_CMD12RBE | INT_CMD12CRE));
                sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
-       } else if (state & INT_ERR_STS) {
-               /* err interrupts */
-               sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
-               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
-               err = 1;
        } else {
                dev_dbg(&host->pd->dev, "Unsupported interrupt: 0x%x\n", state);
                sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
@@ -1003,14 +1191,57 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
                host->sd_error = true;
                dev_dbg(&host->pd->dev, "int err state = %08x\n", state);
        }
-       if (state & ~(INT_CMD12RBE | INT_CMD12CRE))
-               complete(&host->intr_wait);
-       else
+       if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) {
+               if (!host->dma_active)
+                       return IRQ_WAKE_THREAD;
+               else if (host->sd_error)
+                       mmcif_dma_complete(host);
+       } else {
                dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state);
+       }
 
        return IRQ_HANDLED;
 }
 
+static void mmcif_timeout_work(struct work_struct *work)
+{
+       struct delayed_work *d = container_of(work, struct delayed_work, work);
+       struct sh_mmcif_host *host = container_of(d, struct sh_mmcif_host, timeout_work);
+       struct mmc_request *mrq = host->mrq;
+
+       if (host->dying)
+               /* Don't run after mmc_remove_host() */
+               return;
+
+       /*
+        * Handle races with cancel_delayed_work(), unless
+        * cancel_delayed_work_sync() is used
+        */
+       switch (host->wait_for) {
+       case MMCIF_WAIT_FOR_CMD:
+               mrq->cmd->error = sh_mmcif_error_manage(host);
+               break;
+       case MMCIF_WAIT_FOR_STOP:
+               mrq->stop->error = sh_mmcif_error_manage(host);
+               break;
+       case MMCIF_WAIT_FOR_MREAD:
+       case MMCIF_WAIT_FOR_MWRITE:
+       case MMCIF_WAIT_FOR_READ:
+       case MMCIF_WAIT_FOR_WRITE:
+       case MMCIF_WAIT_FOR_READ_END:
+       case MMCIF_WAIT_FOR_WRITE_END:
+               mrq->data->error = sh_mmcif_error_manage(host);
+               break;
+       default:
+               BUG();
+       }
+
+       host->state = STATE_IDLE;
+       host->wait_for = MMCIF_WAIT_FOR_REQUEST;
+       host->mrq = NULL;
+       mmc_request_done(host->mmc, mrq);
+}
+
 static int __devinit sh_mmcif_probe(struct platform_device *pdev)
 {
        int ret = 0, irq[2];
@@ -1064,7 +1295,6 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        host->clk = clk_get_rate(host->hclk);
        host->pd = pdev;
 
-       init_completion(&host->intr_wait);
        spin_lock_init(&host->lock);
 
        mmc->ops = &sh_mmcif_ops;
@@ -1101,19 +1331,21 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
 
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
 
-       ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host);
+       ret = request_threaded_irq(irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:error", host);
        if (ret) {
                dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n");
                goto clean_up3;
        }
-       ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host);
+       ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host);
        if (ret) {
                free_irq(irq[0], host);
                dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n");
                goto clean_up3;
        }
 
-       sh_mmcif_detect(host->mmc);
+       INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work);
+
+       mmc_detect_change(host->mmc, 0);
 
        dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
        dev_dbg(&pdev->dev, "chip ver H'%04x\n",
@@ -1139,11 +1371,19 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
        struct sh_mmcif_host *host = platform_get_drvdata(pdev);
        int irq[2];
 
+       host->dying = true;
        pm_runtime_get_sync(&pdev->dev);
 
        mmc_remove_host(host->mmc);
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
 
+       /*
+        * FIXME: cancel_delayed_work(_sync)() and free_irq() race with the
+        * mmc_remove_host() call above. But swapping order doesn't help either
+        * (a query on the linux-mmc mailing list didn't bring any replies).
+        */
+       cancel_delayed_work_sync(&host->timeout_work);
+
        if (host->addr)
                iounmap(host->addr);
 
@@ -1206,19 +1446,7 @@ static struct platform_driver sh_mmcif_driver = {
        },
 };
 
-static int __init sh_mmcif_init(void)
-{
-       return platform_driver_register(&sh_mmcif_driver);
-}
-
-static void __exit sh_mmcif_exit(void)
-{
-       platform_driver_unregister(&sh_mmcif_driver);
-}
-
-module_init(sh_mmcif_init);
-module_exit(sh_mmcif_exit);
-
+module_platform_driver(sh_mmcif_driver);
 
 MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver");
 MODULE_LICENSE("GPL");
index 41ae6466bd83e8b65b87d0da122afe54bdc93fb3..58da3c44acc5d129428198b7ec80f987fe73d68a 100644 (file)
@@ -282,18 +282,7 @@ static struct platform_driver sh_mobile_sdhi_driver = {
        .remove         = __devexit_p(sh_mobile_sdhi_remove),
 };
 
-static int __init sh_mobile_sdhi_init(void)
-{
-       return platform_driver_register(&sh_mobile_sdhi_driver);
-}
-
-static void __exit sh_mobile_sdhi_exit(void)
-{
-       platform_driver_unregister(&sh_mobile_sdhi_driver);
-}
-
-module_init(sh_mobile_sdhi_init);
-module_exit(sh_mobile_sdhi_exit);
+module_platform_driver(sh_mobile_sdhi_driver);
 
 MODULE_DESCRIPTION("SuperH Mobile SDHI driver");
 MODULE_AUTHOR("Magnus Damm");
index f70d04664cac8aff6223df5d2965e630db826044..43d962829f8ec60326a0c63f3b3274871f2904fd 100644 (file)
@@ -22,8 +22,8 @@
 #define DRIVER_NAME "tifm_sd"
 #define DRIVER_VERSION "0.8"
 
-static int no_dma = 0;
-static int fixed_timeout = 0;
+static bool no_dma = 0;
+static bool fixed_timeout = 0;
 module_param(no_dma, bool, 0644);
 module_param(fixed_timeout, bool, 0644);
 
@@ -118,7 +118,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
        unsigned char *buf;
        unsigned int pos = 0, val;
 
-       buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + off;
+       buf = kmap_atomic(pg) + off;
        if (host->cmd_flags & DATA_CARRY) {
                buf[pos++] = host->bounce_buf_data[0];
                host->cmd_flags &= ~DATA_CARRY;
@@ -134,7 +134,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
                }
                buf[pos++] = (val >> 8) & 0xff;
        }
-       kunmap_atomic(buf - off, KM_BIO_DST_IRQ);
+       kunmap_atomic(buf - off);
 }
 
 static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
@@ -144,7 +144,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
        unsigned char *buf;
        unsigned int pos = 0, val;
 
-       buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + off;
+       buf = kmap_atomic(pg) + off;
        if (host->cmd_flags & DATA_CARRY) {
                val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00);
                writel(val, sock->addr + SOCK_MMCSD_DATA);
@@ -161,7 +161,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
                val |= (buf[pos++] << 8) & 0xff00;
                writel(val, sock->addr + SOCK_MMCSD_DATA);
        }
-       kunmap_atomic(buf - off, KM_BIO_SRC_IRQ);
+       kunmap_atomic(buf - off);
 }
 
 static void tifm_sd_transfer_data(struct tifm_sd *host)
@@ -212,13 +212,13 @@ static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off,
                              struct page *src, unsigned int src_off,
                              unsigned int count)
 {
-       unsigned char *src_buf = kmap_atomic(src, KM_BIO_SRC_IRQ) + src_off;
-       unsigned char *dst_buf = kmap_atomic(dst, KM_BIO_DST_IRQ) + dst_off;
+       unsigned char *src_buf = kmap_atomic(src) + src_off;
+       unsigned char *dst_buf = kmap_atomic(dst) + dst_off;
 
        memcpy(dst_buf, src_buf, count);
 
-       kunmap_atomic(dst_buf - dst_off, KM_BIO_DST_IRQ);
-       kunmap_atomic(src_buf - src_off, KM_BIO_SRC_IRQ);
+       kunmap_atomic(dst_buf - dst_off);
+       kunmap_atomic(src_buf - src_off);
 }
 
 static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data)
index a4ea10242787465d21f99e93e11516d8090cdef1..113ce6c9cf3203d1ad71f445ce62b63be6f2eca5 100644 (file)
@@ -138,19 +138,7 @@ static struct platform_driver tmio_mmc_driver = {
        .resume = tmio_mmc_resume,
 };
 
-
-static int __init tmio_mmc_init(void)
-{
-       return platform_driver_register(&tmio_mmc_driver);
-}
-
-static void __exit tmio_mmc_exit(void)
-{
-       platform_driver_unregister(&tmio_mmc_driver);
-}
-
-module_init(tmio_mmc_init);
-module_exit(tmio_mmc_exit);
+module_platform_driver(tmio_mmc_driver);
 
 MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver");
 MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
index 3020f98218f0104d5082dd4d94a84a3c9a5160eb..a95e6d901726031275066ca7b394fc9be7b6a96c 100644 (file)
@@ -105,13 +105,13 @@ static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
                                         unsigned long *flags)
 {
        local_irq_save(*flags);
-       return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
+       return kmap_atomic(sg_page(sg)) + sg->offset;
 }
 
 static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg,
                                          unsigned long *flags, void *virt)
 {
-       kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ);
+       kunmap_atomic(virt - sg->offset);
        local_irq_restore(*flags);
 }
 
index 86f259cdfcbcbe620206cc1c479395759fb2b2ad..7a6e6cc8f8b842ddb065208aea07d093809bc79d 100644 (file)
@@ -77,7 +77,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
        ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE);
        if (ret > 0)
                desc = chan->device->device_prep_slave_sg(chan, sg, ret,
-                       DMA_FROM_DEVICE, DMA_CTRL_ACK);
+                       DMA_DEV_TO_MEM, DMA_CTRL_ACK);
 
        if (desc) {
                cookie = dmaengine_submit(desc);
@@ -158,7 +158,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
        ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
        if (ret > 0)
                desc = chan->device->device_prep_slave_sg(chan, sg, ret,
-                       DMA_TO_DEVICE, DMA_CTRL_ACK);
+                       DMA_MEM_TO_DEV, DMA_CTRL_ACK);
 
        if (desc) {
                cookie = dmaengine_submit(desc);
index 4208b3958069119e68e8da8ad03e3eadf5862b8c..abad01b37cfbbab50761cafda285d40e67346b3b 100644 (file)
@@ -800,8 +800,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        } else if (ios->power_mode != MMC_POWER_UP) {
                if (host->set_pwr && ios->power_mode == MMC_POWER_OFF)
                        host->set_pwr(host->pdev, 0);
-               if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) &&
-                   pdata->power) {
+               if (pdata->power) {
                        pdata->power = false;
                        pm_runtime_put(&host->pdev->dev);
                }
@@ -915,6 +914,23 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        if (ret < 0)
                goto pm_disable;
 
+       /*
+        * There are 4 different scenarios for the card detection:
+        *  1) an external gpio irq handles the cd (best for power savings)
+        *  2) internal sdhi irq handles the cd
+        *  3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL
+        *  4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE
+        *
+        *  While we increment the rtpm counter for all scenarios when the mmc
+        *  core activates us by calling an appropriate set_ios(), we must
+        *  additionally ensure that in case 2) the tmio mmc hardware stays
+        *  powered on during runtime for the card detection to work.
+        */
+       if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD
+               || mmc->caps & MMC_CAP_NEEDS_POLL
+               || mmc->caps & MMC_CAP_NONREMOVABLE))
+               pm_runtime_get_noresume(&pdev->dev);
+
        tmio_mmc_clk_stop(_host);
        tmio_mmc_reset(_host);
 
@@ -933,12 +949,6 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        /* See if we also get DMA */
        tmio_mmc_request_dma(_host, pdata);
 
-       /* We have to keep the device powered for its card detection to work */
-       if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD)) {
-               pdata->power = true;
-               pm_runtime_get_noresume(&pdev->dev);
-       }
-
        mmc_add_host(mmc);
 
        /* Unmask the IRQs we want to know about */
@@ -974,7 +984,9 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
         * the controller, the runtime PM is suspended and pdata->power == false,
         * so, our .runtime_resume() will not try to detect a card in the slot.
         */
-       if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD)
+       if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD
+               || host->mmc->caps & MMC_CAP_NEEDS_POLL
+               || host->mmc->caps & MMC_CAP_NONREMOVABLE)
                pm_runtime_get_sync(&pdev->dev);
 
        mmc_remove_host(host->mmc);
index 2ec978bc32ba47232b6618db96e2db1bebb25038..3135a1a5d75d004fda64cf0160f14481bc6af333 100644 (file)
@@ -223,25 +223,25 @@ enum SD_RESPONSE_TYPE {
 #define FUN(c) (0x000007 & (c->arg>>28))
 #define REG(c) (0x01FFFF & (c->arg>>9))
 
-static int limit_speed_to_24_MHz;
+static bool limit_speed_to_24_MHz;
 module_param(limit_speed_to_24_MHz, bool, 0644);
 MODULE_PARM_DESC(limit_speed_to_24_MHz, "Limit Max SDIO Clock Speed to 24 MHz");
 
-static int pad_input_to_usb_pkt;
+static bool pad_input_to_usb_pkt;
 module_param(pad_input_to_usb_pkt, bool, 0644);
 MODULE_PARM_DESC(pad_input_to_usb_pkt,
                 "Pad USB data input transfers to whole USB Packet");
 
-static int disable_offload_processing;
+static bool disable_offload_processing;
 module_param(disable_offload_processing, bool, 0644);
 MODULE_PARM_DESC(disable_offload_processing, "Disable Offload Processing");
 
-static int force_1_bit_data_xfers;
+static bool force_1_bit_data_xfers;
 module_param(force_1_bit_data_xfers, bool, 0644);
 MODULE_PARM_DESC(force_1_bit_data_xfers,
                 "Force SDIO Data Transfers to 1-bit Mode");
 
-static int force_polling_for_irqs;
+static bool force_polling_for_irqs;
 module_param(force_polling_for_irqs, bool, 0644);
 MODULE_PARM_DESC(force_polling_for_irqs, "Force Polling for SDIO interrupts");
 
index db8e8272d69b04d08aebbf99f6f668220e2b994a..3ce99e00a49e89f558796c5a426934bb97e91a84 100644 (file)
@@ -315,8 +315,7 @@ static void mtdoops_do_dump(struct kmsg_dumper *dumper,
        char *dst;
 
        if (reason != KMSG_DUMP_OOPS &&
-           reason != KMSG_DUMP_PANIC &&
-           reason != KMSG_DUMP_KEXEC)
+           reason != KMSG_DUMP_PANIC)
                return;
 
        /* Only dump oopses if dump_oops is set */
index 7dd3700f2303097f14747098031a41d66acc130a..73abbc3e093eced219347f93f9fefc5b31c2bd15 100644 (file)
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
 #include <asm/io.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1550nd.h>
 
-#ifdef CONFIG_MIPS_PB1550
-#include <asm/mach-pb1x00/pb1550.h>
-#elif defined(CONFIG_MIPS_DB1550)
-#include <asm/mach-db1x00/db1x00.h>
-#endif
-#include <asm/mach-db1x00/bcsr.h>
 
-/*
- * MTD structure for NAND controller
- */
-static struct mtd_info *au1550_mtd = NULL;
-static void __iomem *p_nand;
-static int nand_width = 1;     /* default x8 */
-static void (*au1550_write_byte)(struct mtd_info *, u_char);
+struct au1550nd_ctx {
+       struct mtd_info info;
+       struct nand_chip chip;
 
-/*
- * Define partitions for flash device
- */
-static const struct mtd_partition partition_info[] = {
-       {
-        .name = "NAND FS 0",
-        .offset = 0,
-        .size = 8 * 1024 * 1024},
-       {
-        .name = "NAND FS 1",
-        .offset = MTDPART_OFS_APPEND,
-        .size = MTDPART_SIZ_FULL}
+       int cs;
+       void __iomem *base;
+       void (*write_byte)(struct mtd_info *, u_char);
 };
 
 /**
@@ -259,24 +243,25 @@ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
 
 static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
 {
-       register struct nand_chip *this = mtd->priv;
+       struct au1550nd_ctx *ctx = container_of(mtd, struct au1550nd_ctx, info);
+       struct nand_chip *this = mtd->priv;
 
        switch (cmd) {
 
        case NAND_CTL_SETCLE:
-               this->IO_ADDR_W = p_nand + MEM_STNAND_CMD;
+               this->IO_ADDR_W = ctx->base + MEM_STNAND_CMD;
                break;
 
        case NAND_CTL_CLRCLE:
-               this->IO_ADDR_W = p_nand + MEM_STNAND_DATA;
+               this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
                break;
 
        case NAND_CTL_SETALE:
-               this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR;
+               this->IO_ADDR_W = ctx->base + MEM_STNAND_ADDR;
                break;
 
        case NAND_CTL_CLRALE:
-               this->IO_ADDR_W = p_nand + MEM_STNAND_DATA;
+               this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA;
                /* FIXME: Nobody knows why this is necessary,
                 * but it works only that way */
                udelay(1);
@@ -284,7 +269,7 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
 
        case NAND_CTL_SETNCE:
                /* assert (force assert) chip enable */
-               au_writel((1 << (4 + NAND_CS)), MEM_STNDCTL);
+               au_writel((1 << (4 + ctx->cs)), MEM_STNDCTL);
                break;
 
        case NAND_CTL_CLRNCE:
@@ -331,9 +316,10 @@ static void au1550_select_chip(struct mtd_info *mtd, int chip)
  */
 static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
 {
-       register struct nand_chip *this = mtd->priv;
+       struct au1550nd_ctx *ctx = container_of(mtd, struct au1550nd_ctx, info);
+       struct nand_chip *this = mtd->priv;
        int ce_override = 0, i;
-       ulong flags;
+       unsigned long flags = 0;
 
        /* Begin command latch cycle */
        au1550_hwcontrol(mtd, NAND_CTL_SETCLE);
@@ -354,9 +340,9 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
                        column -= 256;
                        readcmd = NAND_CMD_READ1;
                }
-               au1550_write_byte(mtd, readcmd);
+               ctx->write_byte(mtd, readcmd);
        }
-       au1550_write_byte(mtd, command);
+       ctx->write_byte(mtd, command);
 
        /* Set ALE and clear CLE to start address cycle */
        au1550_hwcontrol(mtd, NAND_CTL_CLRCLE);
@@ -369,10 +355,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
                        /* Adjust columns for 16 bit buswidth */
                        if (this->options & NAND_BUSWIDTH_16)
                                column >>= 1;
-                       au1550_write_byte(mtd, column);
+                       ctx->write_byte(mtd, column);
                }
                if (page_addr != -1) {
-                       au1550_write_byte(mtd, (u8)(page_addr & 0xff));
+                       ctx->write_byte(mtd, (u8)(page_addr & 0xff));
 
                        if (command == NAND_CMD_READ0 ||
                            command == NAND_CMD_READ1 ||
@@ -390,11 +376,12 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
                                au1550_hwcontrol(mtd, NAND_CTL_SETNCE);
                        }
 
-                       au1550_write_byte(mtd, (u8)(page_addr >> 8));
+                       ctx->write_byte(mtd, (u8)(page_addr >> 8));
 
                        /* One more address cycle for devices > 32MiB */
                        if (this->chipsize > (32 << 20))
-                               au1550_write_byte(mtd, (u8)((page_addr >> 16) & 0x0f));
+                               ctx->write_byte(mtd,
+                                               ((page_addr >> 16) & 0x0f));
                }
                /* Latch in address */
                au1550_hwcontrol(mtd, NAND_CTL_CLRALE);
@@ -440,121 +427,79 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
        while(!this->dev_ready(mtd));
 }
 
-
-/*
- * Main initialization routine
- */
-static int __init au1xxx_nand_init(void)
+static int __devinit find_nand_cs(unsigned long nand_base)
 {
-       struct nand_chip *this;
-       u16 boot_swapboot = 0;  /* default value */
-       int retval;
-       u32 mem_staddr;
-       u32 nand_phys;
-
-       /* Allocate memory for MTD device structure and private data */
-       au1550_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
-       if (!au1550_mtd) {
-               printk("Unable to allocate NAND MTD dev structure.\n");
-               return -ENOMEM;
-       }
-
-       /* Get pointer to private data */
-       this = (struct nand_chip *)(&au1550_mtd[1]);
-
-       /* Link the private data with the MTD structure */
-       au1550_mtd->priv = this;
-       au1550_mtd->owner = THIS_MODULE;
-
+       void __iomem *base =
+                       (void __iomem *)KSEG1ADDR(AU1000_STATIC_MEM_PHYS_ADDR);
+       unsigned long addr, staddr, start, mask, end;
+       int i;
 
-       /* MEM_STNDCTL: disable ints, disable nand boot */
-       au_writel(0, MEM_STNDCTL);
+       for (i = 0; i < 4; i++) {
+               addr = 0x1000 + (i * 0x10);                     /* CSx */
+               staddr = __raw_readl(base + addr + 0x08);       /* STADDRx */
+               /* figure out the decoded range of this CS */
+               start = (staddr << 4) & 0xfffc0000;
+               mask = (staddr << 18) & 0xfffc0000;
+               end = (start | (start - 1)) & ~(start ^ mask);
+               if ((nand_base >= start) && (nand_base < end))
+                       return i;
+       }
 
-#ifdef CONFIG_MIPS_PB1550
-       /* set gpio206 high */
-       gpio_direction_input(206);
+       return -ENODEV;
+}
 
-       boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr_read(BCSR_STATUS) >> 6) & 0x1);
+static int __devinit au1550nd_probe(struct platform_device *pdev)
+{
+       struct au1550nd_platdata *pd;
+       struct au1550nd_ctx *ctx;
+       struct nand_chip *this;
+       struct resource *r;
+       int ret, cs;
 
-       switch (boot_swapboot) {
-       case 0:
-       case 2:
-       case 8:
-       case 0xC:
-       case 0xD:
-               /* x16 NAND Flash */
-               nand_width = 0;
-               break;
-       case 1:
-       case 9:
-       case 3:
-       case 0xE:
-       case 0xF:
-               /* x8 NAND Flash */
-               nand_width = 1;
-               break;
-       default:
-               printk("Pb1550 NAND: bad boot:swap\n");
-               retval = -EINVAL;
-               goto outmem;
+       pd = pdev->dev.platform_data;
+       if (!pd) {
+               dev_err(&pdev->dev, "missing platform data\n");
+               return -ENODEV;
        }
-#endif
-
-       /* Configure chip-select; normally done by boot code, e.g. YAMON */
-#ifdef NAND_STCFG
-       if (NAND_CS == 0) {
-               au_writel(NAND_STCFG,  MEM_STCFG0);
-               au_writel(NAND_STTIME, MEM_STTIME0);
-               au_writel(NAND_STADDR, MEM_STADDR0);
-       }
-       if (NAND_CS == 1) {
-               au_writel(NAND_STCFG,  MEM_STCFG1);
-               au_writel(NAND_STTIME, MEM_STTIME1);
-               au_writel(NAND_STADDR, MEM_STADDR1);
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx) {
+               dev_err(&pdev->dev, "no memory for NAND context\n");
+               return -ENOMEM;
        }
-       if (NAND_CS == 2) {
-               au_writel(NAND_STCFG,  MEM_STCFG2);
-               au_writel(NAND_STTIME, MEM_STTIME2);
-               au_writel(NAND_STADDR, MEM_STADDR2);
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               dev_err(&pdev->dev, "no NAND memory resource\n");
+               ret = -ENODEV;
+               goto out1;
        }
-       if (NAND_CS == 3) {
-               au_writel(NAND_STCFG,  MEM_STCFG3);
-               au_writel(NAND_STTIME, MEM_STTIME3);
-               au_writel(NAND_STADDR, MEM_STADDR3);
+       if (request_mem_region(r->start, resource_size(r), "au1550-nand")) {
+               dev_err(&pdev->dev, "cannot claim NAND memory area\n");
+               ret = -ENOMEM;
+               goto out1;
        }
-#endif
-
-       /* Locate NAND chip-select in order to determine NAND phys address */
-       mem_staddr = 0x00000000;
-       if (((au_readl(MEM_STCFG0) & 0x7) == 0x5) && (NAND_CS == 0))
-               mem_staddr = au_readl(MEM_STADDR0);
-       else if (((au_readl(MEM_STCFG1) & 0x7) == 0x5) && (NAND_CS == 1))
-               mem_staddr = au_readl(MEM_STADDR1);
-       else if (((au_readl(MEM_STCFG2) & 0x7) == 0x5) && (NAND_CS == 2))
-               mem_staddr = au_readl(MEM_STADDR2);
-       else if (((au_readl(MEM_STCFG3) & 0x7) == 0x5) && (NAND_CS == 3))
-               mem_staddr = au_readl(MEM_STADDR3);
-
-       if (mem_staddr == 0x00000000) {
-               printk("Au1xxx NAND: ERROR WITH NAND CHIP-SELECT\n");
-               kfree(au1550_mtd);
-               return 1;
+
+       ctx->base = ioremap_nocache(r->start, 0x1000);
+       if (!ctx->base) {
+               dev_err(&pdev->dev, "cannot remap NAND memory area\n");
+               ret = -ENODEV;
+               goto out2;
        }
-       nand_phys = (mem_staddr << 4) & 0xFFFC0000;
 
-       p_nand = ioremap(nand_phys, 0x1000);
+       this = &ctx->chip;
+       ctx->info.priv = this;
+       ctx->info.owner = THIS_MODULE;
 
-       /* make controller and MTD agree */
-       if (NAND_CS == 0)
-               nand_width = au_readl(MEM_STCFG0) & (1 << 22);
-       if (NAND_CS == 1)
-               nand_width = au_readl(MEM_STCFG1) & (1 << 22);
-       if (NAND_CS == 2)
-               nand_width = au_readl(MEM_STCFG2) & (1 << 22);
-       if (NAND_CS == 3)
-               nand_width = au_readl(MEM_STCFG3) & (1 << 22);
+       /* figure out which CS# r->start belongs to */
+       cs = find_nand_cs(r->start);
+       if (cs < 0) {
+               dev_err(&pdev->dev, "cannot detect NAND chipselect\n");
+               ret = -ENODEV;
+               goto out3;
+       }
+       ctx->cs = cs;
 
-       /* Set address of hardware control function */
        this->dev_ready = au1550_device_ready;
        this->select_chip = au1550_select_chip;
        this->cmdfunc = au1550_command;
@@ -565,54 +510,57 @@ static int __init au1xxx_nand_init(void)
 
        this->options = NAND_NO_AUTOINCR;
 
-       if (!nand_width)
+       if (pd->devwidth)
                this->options |= NAND_BUSWIDTH_16;
 
-       this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte;
-       au1550_write_byte = (!nand_width) ? au_write_byte16 : au_write_byte;
+       this->read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte;
+       ctx->write_byte = (pd->devwidth) ? au_write_byte16 : au_write_byte;
        this->read_word = au_read_word;
-       this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf;
-       this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf;
-       this->verify_buf = (!nand_width) ? au_verify_buf16 : au_verify_buf;
-
-       /* Scan to find existence of the device */
-       if (nand_scan(au1550_mtd, 1)) {
-               retval = -ENXIO;
-               goto outio;
+       this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf;
+       this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf;
+       this->verify_buf = (pd->devwidth) ? au_verify_buf16 : au_verify_buf;
+
+       ret = nand_scan(&ctx->info, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "NAND scan failed with %d\n", ret);
+               goto out3;
        }
 
-       /* Register the partitions */
-       mtd_device_register(au1550_mtd, partition_info,
-                           ARRAY_SIZE(partition_info));
+       mtd_device_register(&ctx->info, pd->parts, pd->num_parts);
 
        return 0;
 
- outio:
-       iounmap(p_nand);
-
- outmem:
-       kfree(au1550_mtd);
-       return retval;
+out3:
+       iounmap(ctx->base);
+out2:
+       release_mem_region(r->start, resource_size(r));
+out1:
+       kfree(ctx);
+       return ret;
 }
 
-module_init(au1xxx_nand_init);
-
-/*
- * Clean up routine
- */
-static void __exit au1550_cleanup(void)
+static int __devexit au1550nd_remove(struct platform_device *pdev)
 {
-       /* Release resources, unregister device */
-       nand_release(au1550_mtd);
+       struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
+       struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-       /* Free the MTD device structure */
-       kfree(au1550_mtd);
-
-       /* Unmap */
-       iounmap(p_nand);
+       nand_release(&ctx->info);
+       iounmap(ctx->base);
+       release_mem_region(r->start, 0x1000);
+       kfree(ctx);
+       return 0;
 }
 
-module_exit(au1550_cleanup);
+static struct platform_driver au1550nd_driver = {
+       .driver = {
+               .name   = "au1550-nand",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = au1550nd_probe,
+       .remove         = __devexit_p(au1550nd_remove),
+};
+
+module_platform_driver(au1550nd_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Embedded Edge, LLC");
index 2a56fc6f399a871d2794445324a920eff5a0b228..7f680420bfab609f7490c7fa4237271f567cdf56 100644 (file)
@@ -827,7 +827,7 @@ int gpmi_send_command(struct gpmi_nand_data *this)
        pio[1] = pio[2] = 0;
        desc = channel->device->device_prep_slave_sg(channel,
                                        (struct scatterlist *)pio,
-                                       ARRAY_SIZE(pio), DMA_NONE, 0);
+                                       ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
        if (!desc) {
                pr_err("step 1 error\n");
                return -1;
@@ -839,7 +839,7 @@ int gpmi_send_command(struct gpmi_nand_data *this)
        sg_init_one(sgl, this->cmd_buffer, this->command_length);
        dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE);
        desc = channel->device->device_prep_slave_sg(channel,
-                                       sgl, 1, DMA_TO_DEVICE, 1);
+                                       sgl, 1, DMA_MEM_TO_DEV, 1);
        if (!desc) {
                pr_err("step 2 error\n");
                return -1;
@@ -872,7 +872,7 @@ int gpmi_send_data(struct gpmi_nand_data *this)
        pio[1] = 0;
        desc = channel->device->device_prep_slave_sg(channel,
                                        (struct scatterlist *)pio,
-                                       ARRAY_SIZE(pio), DMA_NONE, 0);
+                                       ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
        if (!desc) {
                pr_err("step 1 error\n");
                return -1;
@@ -881,7 +881,7 @@ int gpmi_send_data(struct gpmi_nand_data *this)
        /* [2] send DMA request */
        prepare_data_dma(this, DMA_TO_DEVICE);
        desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl,
-                                               1, DMA_TO_DEVICE, 1);
+                                               1, DMA_MEM_TO_DEV, 1);
        if (!desc) {
                pr_err("step 2 error\n");
                return -1;
@@ -908,7 +908,7 @@ int gpmi_read_data(struct gpmi_nand_data *this)
        pio[1] = 0;
        desc = channel->device->device_prep_slave_sg(channel,
                                        (struct scatterlist *)pio,
-                                       ARRAY_SIZE(pio), DMA_NONE, 0);
+                                       ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
        if (!desc) {
                pr_err("step 1 error\n");
                return -1;
@@ -917,7 +917,7 @@ int gpmi_read_data(struct gpmi_nand_data *this)
        /* [2] : send DMA request */
        prepare_data_dma(this, DMA_FROM_DEVICE);
        desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl,
-                                               1, DMA_FROM_DEVICE, 1);
+                                               1, DMA_DEV_TO_MEM, 1);
        if (!desc) {
                pr_err("step 2 error\n");
                return -1;
@@ -964,7 +964,7 @@ int gpmi_send_page(struct gpmi_nand_data *this,
 
        desc = channel->device->device_prep_slave_sg(channel,
                                        (struct scatterlist *)pio,
-                                       ARRAY_SIZE(pio), DMA_NONE, 0);
+                                       ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
        if (!desc) {
                pr_err("step 2 error\n");
                return -1;
@@ -998,7 +998,8 @@ int gpmi_read_page(struct gpmi_nand_data *this,
                | BF_GPMI_CTRL0_XFER_COUNT(0);
        pio[1] = 0;
        desc = channel->device->device_prep_slave_sg(channel,
-                               (struct scatterlist *)pio, 2, DMA_NONE, 0);
+                               (struct scatterlist *)pio, 2,
+                               DMA_TRANS_NONE, 0);
        if (!desc) {
                pr_err("step 1 error\n");
                return -1;
@@ -1027,7 +1028,7 @@ int gpmi_read_page(struct gpmi_nand_data *this,
        pio[5] = auxiliary;
        desc = channel->device->device_prep_slave_sg(channel,
                                        (struct scatterlist *)pio,
-                                       ARRAY_SIZE(pio), DMA_NONE, 1);
+                                       ARRAY_SIZE(pio), DMA_TRANS_NONE, 1);
        if (!desc) {
                pr_err("step 2 error\n");
                return -1;
@@ -1045,7 +1046,8 @@ int gpmi_read_page(struct gpmi_nand_data *this,
                | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size);
        pio[1] = 0;
        desc = channel->device->device_prep_slave_sg(channel,
-                               (struct scatterlist *)pio, 2, DMA_NONE, 1);
+                               (struct scatterlist *)pio, 2,
+                               DMA_TRANS_NONE, 1);
        if (!desc) {
                pr_err("step 3 error\n");
                return -1;
index 8544d6bf50a0ae837465d28e60bb2bf0e72edf73..5c3d719c37e6645d70385c3b75b71cf5992bdf7c 100644 (file)
@@ -185,7 +185,7 @@ struct pxa3xx_nand_info {
        uint32_t                ndcb2;
 };
 
-static int use_dma = 1;
+static bool use_dma = 1;
 module_param(use_dma, bool, 0444);
 MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW");
 
index f20f393bfda607d84408d5a072898124365f1490..769a4e096b3c6b8fc3ef036148bf78a609f289a1 100644 (file)
@@ -22,7 +22,7 @@
 #include "r852.h"
 
 
-static int r852_enable_dma = 1;
+static bool r852_enable_dma = 1;
 module_param(r852_enable_dma, bool, S_IRUGO);
 MODULE_PARM_DESC(r852_enable_dma, "Enable usage of the DMA (default)");
 
index 3320a50ba4f0c81f75e48154bd4202f50ead4fad..ad76592fb2f485479570097cb616757c6c4d905b 100644 (file)
@@ -632,6 +632,9 @@ static int verify_mkvol_req(const struct ubi_device *ubi,
        if (req->alignment != 1 && n)
                goto bad;
 
+       if (!req->name[0] || !req->name_len)
+               goto bad;
+
        if (req->name_len > UBI_VOL_NAME_MAX) {
                err = -ENAMETOOLONG;
                goto bad;
index 64fbb002182518310e56693cc88b294465cc2383..ead2cd16ba7588f7e1ea21866df9da6795ce3d5e 100644 (file)
        pr_debug("UBI DBG " type ": " fmt "\n", ##__VA_ARGS__)
 
 /* Just a debugging messages not related to any specific UBI subsystem */
-#define dbg_msg(fmt, ...) ubi_dbg_msg("msg", fmt, ##__VA_ARGS__)
+#define dbg_msg(fmt, ...)                                    \
+       printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
+              current->pid, __func__, ##__VA_ARGS__)
+
 /* General debugging messages */
 #define dbg_gen(fmt, ...) ubi_dbg_msg("gen", fmt, ##__VA_ARGS__)
 /* Messages from the eraseblock association sub-system */
index 9ad18da1891de31d2e792de57ede91626764e431..17cec0c0154448d85271a4422ac8907f9dedc00d 100644 (file)
@@ -306,7 +306,7 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
                       int copy, void *vtbl)
 {
        int err, tries = 0;
-       static struct ubi_vid_hdr *vid_hdr;
+       struct ubi_vid_hdr *vid_hdr;
        struct ubi_scan_leb *new_seb;
 
        ubi_msg("create volume table (copy #%d)", copy + 1);
@@ -322,7 +322,7 @@ retry:
                goto out_free;
        }
 
-       vid_hdr->vol_type = UBI_VID_DYNAMIC;
+       vid_hdr->vol_type = UBI_LAYOUT_VOLUME_TYPE;
        vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID);
        vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
        vid_hdr->data_size = vid_hdr->used_ebs =
@@ -632,7 +632,7 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
                return -ENOMEM;
 
        vol->reserved_pebs = UBI_LAYOUT_VOLUME_EBS;
-       vol->alignment = 1;
+       vol->alignment = UBI_LAYOUT_VOLUME_ALIGN;
        vol->vol_type = UBI_DYNAMIC_VOLUME;
        vol->name_len = sizeof(UBI_LAYOUT_VOLUME_NAME) - 1;
        memcpy(vol->name, UBI_LAYOUT_VOLUME_NAME, vol->name_len + 1);
index 106b88a04738fb25fa5bd850537653beaa5b4aa5..342626f4bc4641d197f1c322bbdfebb0619d289c 100644 (file)
@@ -99,16 +99,26 @@ static inline u8 _simple_hash(const u8 *hash_start, int hash_size)
 
 /*********************** tlb specific functions ***************************/
 
-static inline void _lock_tx_hashtbl(struct bonding *bond)
+static inline void _lock_tx_hashtbl_bh(struct bonding *bond)
 {
        spin_lock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
 }
 
-static inline void _unlock_tx_hashtbl(struct bonding *bond)
+static inline void _unlock_tx_hashtbl_bh(struct bonding *bond)
 {
        spin_unlock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
 }
 
+static inline void _lock_tx_hashtbl(struct bonding *bond)
+{
+       spin_lock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
+}
+
+static inline void _unlock_tx_hashtbl(struct bonding *bond)
+{
+       spin_unlock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
+}
+
 /* Caller must hold tx_hashtbl lock */
 static inline void tlb_init_table_entry(struct tlb_client_info *entry, int save_load)
 {
@@ -129,14 +139,13 @@ static inline void tlb_init_slave(struct slave *slave)
        SLAVE_TLB_INFO(slave).head = TLB_NULL_INDEX;
 }
 
-/* Caller must hold bond lock for read */
-static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_load)
+/* Caller must hold bond lock for read, BH disabled */
+static void __tlb_clear_slave(struct bonding *bond, struct slave *slave,
+                        int save_load)
 {
        struct tlb_client_info *tx_hash_table;
        u32 index;
 
-       _lock_tx_hashtbl(bond);
-
        /* clear slave from tx_hashtbl */
        tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl;
 
@@ -151,8 +160,15 @@ static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_
        }
 
        tlb_init_slave(slave);
+}
 
-       _unlock_tx_hashtbl(bond);
+/* Caller must hold bond lock for read */
+static void tlb_clear_slave(struct bonding *bond, struct slave *slave,
+                        int save_load)
+{
+       _lock_tx_hashtbl_bh(bond);
+       __tlb_clear_slave(bond, slave, save_load);
+       _unlock_tx_hashtbl_bh(bond);
 }
 
 /* Must be called before starting the monitor timer */
@@ -169,7 +185,7 @@ static int tlb_initialize(struct bonding *bond)
                       bond->dev->name);
                return -1;
        }
-       _lock_tx_hashtbl(bond);
+       _lock_tx_hashtbl_bh(bond);
 
        bond_info->tx_hashtbl = new_hashtbl;
 
@@ -177,7 +193,7 @@ static int tlb_initialize(struct bonding *bond)
                tlb_init_table_entry(&bond_info->tx_hashtbl[i], 0);
        }
 
-       _unlock_tx_hashtbl(bond);
+       _unlock_tx_hashtbl_bh(bond);
 
        return 0;
 }
@@ -187,12 +203,12 @@ static void tlb_deinitialize(struct bonding *bond)
 {
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
 
-       _lock_tx_hashtbl(bond);
+       _lock_tx_hashtbl_bh(bond);
 
        kfree(bond_info->tx_hashtbl);
        bond_info->tx_hashtbl = NULL;
 
-       _unlock_tx_hashtbl(bond);
+       _unlock_tx_hashtbl_bh(bond);
 }
 
 static long long compute_gap(struct slave *slave)
@@ -226,15 +242,13 @@ static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
        return least_loaded;
 }
 
-/* Caller must hold bond lock for read */
-static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len)
+static struct slave *__tlb_choose_channel(struct bonding *bond, u32 hash_index,
+                                               u32 skb_len)
 {
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
        struct tlb_client_info *hash_table;
        struct slave *assigned_slave;
 
-       _lock_tx_hashtbl(bond);
-
        hash_table = bond_info->tx_hashtbl;
        assigned_slave = hash_table[hash_index].tx_slave;
        if (!assigned_slave) {
@@ -263,22 +277,46 @@ static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u3
                hash_table[hash_index].tx_bytes += skb_len;
        }
 
-       _unlock_tx_hashtbl(bond);
-
        return assigned_slave;
 }
 
+/* Caller must hold bond lock for read */
+static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index,
+                                       u32 skb_len)
+{
+       struct slave *tx_slave;
+       /*
+        * We don't need to disable softirq here, becase
+        * tlb_choose_channel() is only called by bond_alb_xmit()
+        * which already has softirq disabled.
+        */
+       _lock_tx_hashtbl(bond);
+       tx_slave = __tlb_choose_channel(bond, hash_index, skb_len);
+       _unlock_tx_hashtbl(bond);
+       return tx_slave;
+}
+
 /*********************** rlb specific functions ***************************/
-static inline void _lock_rx_hashtbl(struct bonding *bond)
+static inline void _lock_rx_hashtbl_bh(struct bonding *bond)
 {
        spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
 }
 
-static inline void _unlock_rx_hashtbl(struct bonding *bond)
+static inline void _unlock_rx_hashtbl_bh(struct bonding *bond)
 {
        spin_unlock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
 }
 
+static inline void _lock_rx_hashtbl(struct bonding *bond)
+{
+       spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
+}
+
+static inline void _unlock_rx_hashtbl(struct bonding *bond)
+{
+       spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
+}
+
 /* when an ARP REPLY is received from a client update its info
  * in the rx_hashtbl
  */
@@ -288,7 +326,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
        struct rlb_client_info *client_info;
        u32 hash_index;
 
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        hash_index = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src));
        client_info = &(bond_info->rx_hashtbl[hash_index]);
@@ -303,7 +341,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
                bond_info->rx_ntt = 1;
        }
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 }
 
 static void rlb_arp_recv(struct sk_buff *skb, struct bonding *bond,
@@ -401,7 +439,7 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave)
        u32 index, next_index;
 
        /* clear slave from rx_hashtbl */
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        rx_hash_table = bond_info->rx_hashtbl;
        index = bond_info->rx_hashtbl_head;
@@ -432,7 +470,7 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave)
                }
        }
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 
        write_lock_bh(&bond->curr_slave_lock);
 
@@ -489,7 +527,7 @@ static void rlb_update_rx_clients(struct bonding *bond)
        struct rlb_client_info *client_info;
        u32 hash_index;
 
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        hash_index = bond_info->rx_hashtbl_head;
        for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
@@ -507,7 +545,7 @@ static void rlb_update_rx_clients(struct bonding *bond)
         */
        bond_info->rlb_update_delay_counter = RLB_UPDATE_DELAY;
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 }
 
 /* The slave was assigned a new mac address - update the clients */
@@ -518,7 +556,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla
        int ntt = 0;
        u32 hash_index;
 
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        hash_index = bond_info->rx_hashtbl_head;
        for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
@@ -538,7 +576,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla
                bond_info->rlb_update_retry_counter = RLB_UPDATE_RETRY;
        }
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 }
 
 /* mark all clients using src_ip to be updated */
@@ -709,7 +747,7 @@ static void rlb_rebalance(struct bonding *bond)
        int ntt;
        u32 hash_index;
 
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        ntt = 0;
        hash_index = bond_info->rx_hashtbl_head;
@@ -727,7 +765,7 @@ static void rlb_rebalance(struct bonding *bond)
        if (ntt) {
                bond_info->rx_ntt = 1;
        }
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 }
 
 /* Caller must hold rx_hashtbl lock */
@@ -751,7 +789,7 @@ static int rlb_initialize(struct bonding *bond)
                       bond->dev->name);
                return -1;
        }
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        bond_info->rx_hashtbl = new_hashtbl;
 
@@ -761,7 +799,7 @@ static int rlb_initialize(struct bonding *bond)
                rlb_init_table_entry(bond_info->rx_hashtbl + i);
        }
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 
        /* register to receive ARPs */
        bond->recv_probe = rlb_arp_recv;
@@ -773,13 +811,13 @@ static void rlb_deinitialize(struct bonding *bond)
 {
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
 
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        kfree(bond_info->rx_hashtbl);
        bond_info->rx_hashtbl = NULL;
        bond_info->rx_hashtbl_head = RLB_NULL_INDEX;
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 }
 
 static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
@@ -787,7 +825,7 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
        u32 curr_index;
 
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        curr_index = bond_info->rx_hashtbl_head;
        while (curr_index != RLB_NULL_INDEX) {
@@ -812,7 +850,7 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
                curr_index = next_index;
        }
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 }
 
 /*********************** tlb/rlb shared functions *********************/
@@ -1320,7 +1358,9 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
                res = bond_dev_queue_xmit(bond, skb, tx_slave->dev);
        } else {
                if (tx_slave) {
-                       tlb_clear_slave(bond, tx_slave, 0);
+                       _lock_tx_hashtbl(bond);
+                       __tlb_clear_slave(bond, tx_slave, 0);
+                       _unlock_tx_hashtbl(bond);
                }
        }
 
index 9e8ba4f5636bd71bcf2c9946450b76c587dbddb8..0f92e3567f687ea6e9107d7786cc808a792ab025 100644 (file)
@@ -623,7 +623,8 @@ static int ax_mii_init(struct net_device *dev)
 
        ax->mii_bus->name = "ax88796_mii_bus";
        ax->mii_bus->parent = dev->dev.parent;
-       snprintf(ax->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
+       snprintf(ax->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pdev->name, pdev->id);
 
        ax->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
        if (!ax->mii_bus->irq) {
index b6d69c91db96dcf89af8a3e414c91cd39a7b7664..d812a103e032788ee6b3456dc6bb29e33c0decdb 100644 (file)
@@ -1670,7 +1670,8 @@ static int __devinit bfin_mii_bus_probe(struct platform_device *pdev)
        miibus->name = "bfin_mii_bus";
        miibus->phy_mask = mii_bus_pd->phy_mask;
 
-       snprintf(miibus->id, MII_BUS_ID_SIZE, "0");
+       snprintf(miibus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pdev->name, pdev->id);
        miibus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
        if (!miibus->irq)
                goto out_err_irq_alloc;
index cc9262be69c86c68020f7f4568662f0068bb2f4c..8b95dd314253ab4e36bbbcb01b09a7c35d8e8585 100644 (file)
@@ -1171,7 +1171,8 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        aup->mii_bus->write = au1000_mdiobus_write;
        aup->mii_bus->reset = au1000_mdiobus_reset;
        aup->mii_bus->name = "au1000_eth_mii";
-       snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%x", aup->mac_id);
+       snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pdev->name, aup->mac_id);
        aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
        if (aup->mii_bus->irq == NULL)
                goto err_out;
index d44331eb07fef00dae3f8e42e1e43a40bf3672bf..986019b2c8490726f74ad31770aeece308117168 100644 (file)
@@ -1727,7 +1727,7 @@ static int __devinit bcm_enet_probe(struct platform_device *pdev)
                bus->priv = priv;
                bus->read = bcm_enet_mdio_read_phylib;
                bus->write = bcm_enet_mdio_write_phylib;
-               sprintf(bus->id, "%d", priv->mac_id);
+               sprintf(bus->id, "%s-%d", pdev->name, priv->mac_id);
 
                /* only probe bus where we think the PHY is, because
                 * the mdio read operation return 0 instead of 0xffff
index a688b9d975a2576f5285417d3a23ed53a5c3fb5b..f99c6e312a5d49a072a97354941a7547a19698ba 100644 (file)
@@ -365,13 +365,18 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        DP(NETIF_MSG_LINK, "cfg_idx = %x\n", cfg_idx);
 
        if (cmd->autoneg == AUTONEG_ENABLE) {
+               u32 an_supported_speed = bp->port.supported[cfg_idx];
+               if (bp->link_params.phy[EXT_PHY1].type ==
+                   PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
+                       an_supported_speed |= (SUPPORTED_100baseT_Half |
+                                              SUPPORTED_100baseT_Full);
                if (!(bp->port.supported[cfg_idx] & SUPPORTED_Autoneg)) {
                        DP(NETIF_MSG_LINK, "Autoneg not supported\n");
                        return -EINVAL;
                }
 
                /* advertise the requested speed and duplex if supported */
-               if (cmd->advertising & ~(bp->port.supported[cfg_idx])) {
+               if (cmd->advertising & ~an_supported_speed) {
                        DP(NETIF_MSG_LINK, "Advertisement parameters "
                                           "are not supported\n");
                        return -EINVAL;
index 4df9505b67b62e1d482460cc83fcfb6999a83746..2091e5dbbcdd9f50d0d0dec422cd2e1c3aac2d4f 100644 (file)
@@ -2502,7 +2502,7 @@ static void bnx2x_update_pfc_nig(struct link_params *params,
                struct bnx2x_nig_brb_pfc_port_params *nig_params)
 {
        u32 xcm_mask = 0, ppp_enable = 0, pause_enable = 0, llfc_out_en = 0;
-       u32 llfc_enable = 0, xcm0_out_en = 0, p0_hwpfc_enable = 0;
+       u32 llfc_enable = 0, xcm_out_en = 0, hwpfc_enable = 0;
        u32 pkt_priority_to_cos = 0;
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
@@ -2516,9 +2516,8 @@ static void bnx2x_update_pfc_nig(struct link_params *params,
         * MAC control frames (that are not pause packets)
         * will be forwarded to the XCM.
         */
-       xcm_mask = REG_RD(bp,
-                               port ? NIG_REG_LLH1_XCM_MASK :
-                               NIG_REG_LLH0_XCM_MASK);
+       xcm_mask = REG_RD(bp, port ? NIG_REG_LLH1_XCM_MASK :
+                         NIG_REG_LLH0_XCM_MASK);
        /*
         * nig params will override non PFC params, since it's possible to
         * do transition from PFC to SAFC
@@ -2533,8 +2532,8 @@ static void bnx2x_update_pfc_nig(struct link_params *params,
                ppp_enable = 1;
                xcm_mask &= ~(port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
                                     NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
-               xcm0_out_en = 0;
-               p0_hwpfc_enable = 1;
+               xcm_out_en = 0;
+               hwpfc_enable = 1;
        } else  {
                if (nig_params) {
                        llfc_out_en = nig_params->llfc_out_en;
@@ -2545,7 +2544,7 @@ static void bnx2x_update_pfc_nig(struct link_params *params,
 
                xcm_mask |= (port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN :
                        NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN);
-               xcm0_out_en = 1;
+               xcm_out_en = 1;
        }
 
        if (CHIP_IS_E3(bp))
@@ -2564,13 +2563,16 @@ static void bnx2x_update_pfc_nig(struct link_params *params,
        REG_WR(bp, port ? NIG_REG_LLH1_XCM_MASK :
               NIG_REG_LLH0_XCM_MASK, xcm_mask);
 
-       REG_WR(bp,  NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7);
+       REG_WR(bp, port ? NIG_REG_LLFC_EGRESS_SRC_ENABLE_1 :
+              NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7);
 
        /* output enable for RX_XCM # IF */
-       REG_WR(bp, NIG_REG_XCM0_OUT_EN, xcm0_out_en);
+       REG_WR(bp, port ? NIG_REG_XCM1_OUT_EN :
+              NIG_REG_XCM0_OUT_EN, xcm_out_en);
 
        /* HW PFC TX enable */
-       REG_WR(bp, NIG_REG_P0_HWPFC_ENABLE, p0_hwpfc_enable);
+       REG_WR(bp, port ? NIG_REG_P1_HWPFC_ENABLE :
+              NIG_REG_P0_HWPFC_ENABLE, hwpfc_enable);
 
        if (nig_params) {
                u8 i = 0;
@@ -3761,7 +3763,15 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
        /* Advertise pause */
        bnx2x_ext_phy_set_pause(params, phy, vars);
 
-       vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
+       /*
+        * Set KR Autoneg Work-Around flag for Warpcore version older than D108
+        */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_UC_INFO_B1_VERSION, &val16);
+       if (val16 < 0xd108) {
+               DP(NETIF_MSG_LINK, "Enable AN KR work-around\n");
+               vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
+       }
 
        bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
                        MDIO_WC_REG_DIGITAL5_MISC7, &val16);
@@ -9266,62 +9276,68 @@ static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
 /*             BCM8481/BCM84823/BCM84833 PHY SECTION             */
 /******************************************************************/
 static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
-                                          struct link_params *params)
+                                           struct bnx2x *bp,
+                                           u8 port)
 {
        u16 val, fw_ver1, fw_ver2, cnt;
-       u8 port;
-       struct bnx2x *bp = params->bp;
 
-       port = params->port;
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
+               bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, 0x400f, &fw_ver1);
+               bnx2x_save_spirom_version(bp, port,
+                               ((fw_ver1 & 0xf000)>>5) | (fw_ver1 & 0x7f),
+                               phy->ver_addr);
+       } else {
+               /* For 32-bit registers in 848xx, access via MDIO2ARM i/f. */
+               /* (1) set reg 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
+               bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
+               bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
+               bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
+               bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
+               bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
+
+               for (cnt = 0; cnt < 100; cnt++) {
+                       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
+                       if (val & 1)
+                               break;
+                       udelay(5);
+               }
+               if (cnt == 100) {
+                       DP(NETIF_MSG_LINK, "Unable to read 848xx "
+                                       "phy fw version(1)\n");
+                       bnx2x_save_spirom_version(bp, port, 0,
+                                                 phy->ver_addr);
+                       return;
+               }
 
-       /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
-       /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
 
-       for (cnt = 0; cnt < 100; cnt++) {
-               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
-               if (val & 1)
-                       break;
-               udelay(5);
-       }
-       if (cnt == 100) {
-               DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
-               bnx2x_save_spirom_version(bp, port, 0,
-                                         phy->ver_addr);
-               return;
-       }
+               /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
+               bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
+               bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
+               bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
+               for (cnt = 0; cnt < 100; cnt++) {
+                       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
+                       if (val & 1)
+                               break;
+                       udelay(5);
+               }
+               if (cnt == 100) {
+                       DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw "
+                                       "version(2)\n");
+                       bnx2x_save_spirom_version(bp, port, 0,
+                                                 phy->ver_addr);
+                       return;
+               }
 
+               /* lower 16 bits of the register SPI_FW_STATUS */
+               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
+               /* upper 16 bits of register SPI_FW_STATUS */
+               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
 
-       /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
-       for (cnt = 0; cnt < 100; cnt++) {
-               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
-               if (val & 1)
-                       break;
-               udelay(5);
-       }
-       if (cnt == 100) {
-               DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
-               bnx2x_save_spirom_version(bp, port, 0,
+               bnx2x_save_spirom_version(bp, port, (fw_ver2<<16) | fw_ver1,
                                          phy->ver_addr);
-               return;
        }
 
-       /* lower 16 bits of the register SPI_FW_STATUS */
-       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
-       /* upper 16 bits of register SPI_FW_STATUS */
-       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
-
-       bnx2x_save_spirom_version(bp, port, (fw_ver2<<16) | fw_ver1,
-                                 phy->ver_addr);
 }
-
 static void bnx2x_848xx_set_led(struct bnx2x *bp,
                                struct bnx2x_phy *phy)
 {
@@ -9392,10 +9408,13 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
        u16 tmp_req_line_speed;
 
        tmp_req_line_speed = phy->req_line_speed;
-       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
                if (phy->req_line_speed == SPEED_10000)
                        phy->req_line_speed = SPEED_AUTO_NEG;
-
+       } else {
+               /* Save spirom version */
+               bnx2x_save_848xx_spirom_version(phy, bp, params->port);
+       }
        /*
         * This phy uses the NIG latch mechanism since link indication
         * arrives through its LED4 and not via its LASI signal, so we
@@ -9443,13 +9462,10 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
                         an_1000_val);
 
        /* set 100 speed advertisement */
-       if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
+       if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
             (phy->speed_cap_mask &
              (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
-              PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) &&
-            (phy->supported &
-             (SUPPORTED_100baseT_Half |
-              SUPPORTED_100baseT_Full)))) {
+              PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF))) {
                an_10_100_val |= (1<<7);
                /* Enable autoneg and restart autoneg for legacy speeds */
                autoneg_val |= (1<<9 | 1<<12);
@@ -9539,9 +9555,6 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
                                 MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
                                 1);
 
-       /* Save spirom version */
-       bnx2x_save_848xx_spirom_version(phy, params);
-
        phy->req_line_speed = tmp_req_line_speed;
 
        return 0;
@@ -9749,17 +9762,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
 
        /* Wait for GPHY to come out of reset */
        msleep(50);
-       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
-               /* Bring PHY out of super isolate mode */
-               bnx2x_cl45_read(bp, phy,
-                               MDIO_CTL_DEVAD,
-                               MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val);
-               val &= ~MDIO_84833_SUPER_ISOLATE;
-               bnx2x_cl45_write(bp, phy,
-                               MDIO_CTL_DEVAD,
-                               MDIO_84833_TOP_CFG_XGPHY_STRAP1, val);
-               bnx2x_84833_pair_swap_cfg(phy, params, vars);
-       } else {
+       if (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
                /*
                 * BCM84823 requires that XGXS links up first @ 10G for normal
                 * behavior.
@@ -9816,24 +9819,23 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
        DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
                   params->multi_phy_config, val);
 
-       /* AutogrEEEn */
-       if (params->feature_config_flags &
-               FEATURE_CONFIG_AUTOGREEEN_ENABLED)
-               cmd_args[0] = 0x2;
-       else
-               cmd_args[0] = 0x0;
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
+               bnx2x_84833_pair_swap_cfg(phy, params, vars);
 
-       cmd_args[1] = 0x0;
-       cmd_args[2] = PHY84833_CONSTANT_LATENCY + 1;
-       cmd_args[3] = PHY84833_CONSTANT_LATENCY;
-       rc = bnx2x_84833_cmd_hdlr(phy, params,
-               PHY84833_CMD_SET_EEE_MODE, cmd_args);
-       if (rc != 0)
-               DP(NETIF_MSG_LINK, "Cfg AutogrEEEn failed.\n");
+               /* Keep AutogrEEEn disabled. */
+               cmd_args[0] = 0x0;
+               cmd_args[1] = 0x0;
+               cmd_args[2] = PHY84833_CONSTANT_LATENCY + 1;
+               cmd_args[3] = PHY84833_CONSTANT_LATENCY;
+               rc = bnx2x_84833_cmd_hdlr(phy, params,
+                       PHY84833_CMD_SET_EEE_MODE, cmd_args);
+               if (rc != 0)
+                       DP(NETIF_MSG_LINK, "Cfg AutogrEEEn failed.\n");
+       }
        if (initialize)
                rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
        else
-               bnx2x_save_848xx_spirom_version(phy, params);
+               bnx2x_save_848xx_spirom_version(phy, bp, params->port);
        /* 84833 PHY has a better feature and doesn't need to support this. */
        if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
                cms_enable = REG_RD(bp, params->shmem_base +
@@ -9851,6 +9853,16 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
                                 MDIO_CTL_REG_84823_USER_CTRL_REG, val);
        }
 
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
+               /* Bring PHY out of super isolate mode as the final step. */
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_CTL_DEVAD,
+                               MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val);
+               val &= ~MDIO_84833_SUPER_ISOLATE;
+               bnx2x_cl45_write(bp, phy,
+                               MDIO_CTL_DEVAD,
+                               MDIO_84833_TOP_CFG_XGPHY_STRAP1, val);
+       }
        return rc;
 }
 
@@ -9988,10 +10000,11 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
        } else {
                bnx2x_cl45_read(bp, phy,
                                MDIO_CTL_DEVAD,
-                               0x400f, &val16);
+                               MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val16);
+               val16 |= MDIO_84833_SUPER_ISOLATE;
                bnx2x_cl45_write(bp, phy,
-                               MDIO_PMA_DEVAD,
-                               MDIO_PMA_REG_CTRL, 0x800);
+                                MDIO_CTL_DEVAD,
+                                MDIO_84833_TOP_CFG_XGPHY_STRAP1, val16);
        }
 }
 
@@ -11516,6 +11529,19 @@ static int bnx2x_populate_ext_phy(struct bnx2x *bp,
        }
        phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
 
+       if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) &&
+           (phy->ver_addr)) {
+               /*
+                * Remove 100Mb link supported for BCM84833 when phy fw
+                * version lower than or equal to 1.39
+                */
+               u32 raw_ver = REG_RD(bp, phy->ver_addr);
+               if (((raw_ver & 0x7F) <= 39) &&
+                   (((raw_ver & 0xF80) >> 7) <= 1))
+                       phy->supported &= ~(SUPPORTED_100baseT_Half |
+                                           SUPPORTED_100baseT_Full);
+       }
+
        /*
         * In case mdc/mdio_access of the external phy is different than the
         * mdc/mdio access of the XGXS, a HW lock must be taken in each access
@@ -12333,55 +12359,69 @@ static int bnx2x_84833_common_init_phy(struct bnx2x *bp,
                                                u32 chip_id)
 {
        u8 reset_gpios;
-       struct bnx2x_phy phy;
-       u32 shmem_base, shmem2_base, cnt;
-       s8 port = 0;
-       u16 val;
-
        reset_gpios = bnx2x_84833_get_reset_gpios(bp, shmem_base_path, chip_id);
        bnx2x_set_mult_gpio(bp, reset_gpios, MISC_REGISTERS_GPIO_OUTPUT_LOW);
        udelay(10);
        bnx2x_set_mult_gpio(bp, reset_gpios, MISC_REGISTERS_GPIO_OUTPUT_HIGH);
        DP(NETIF_MSG_LINK, "84833 reset pulse on pin values 0x%x\n",
                reset_gpios);
-       for (port = PORT_MAX - 1; port >= PORT_0; port--) {
-               /* This PHY is for E2 and E3. */
-               shmem_base = shmem_base_path[port];
-               shmem2_base = shmem2_base_path[port];
-               /* Extract the ext phy address for the port */
-               if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
-                                      0, &phy) !=
-                   0) {
-                       DP(NETIF_MSG_LINK, "populate_phy failed\n");
-                       return -EINVAL;
-               }
+       return 0;
+}
 
-               /* Wait for FW completing its initialization. */
-               for (cnt = 0; cnt < 1000; cnt++) {
-                       bnx2x_cl45_read(bp, &phy,
+static int bnx2x_84833_pre_init_phy(struct bnx2x *bp,
+                                              struct bnx2x_phy *phy)
+{
+       u16 val, cnt;
+       /* Wait for FW completing its initialization. */
+       for (cnt = 0; cnt < 1500; cnt++) {
+               bnx2x_cl45_read(bp, phy,
                                MDIO_PMA_DEVAD,
                                MDIO_PMA_REG_CTRL, &val);
-                       if (!(val & (1<<15)))
-                               break;
-                       msleep(1);
-               }
-               if (cnt >= 1000)
-                       DP(NETIF_MSG_LINK,
-                               "84833 Cmn reset timeout (%d)\n", port);
-
-               /* Put the port in super isolate mode. */
-               bnx2x_cl45_read(bp, &phy,
-                               MDIO_CTL_DEVAD,
-                               MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val);
-               val |= MDIO_84833_SUPER_ISOLATE;
-               bnx2x_cl45_write(bp, &phy,
-                               MDIO_CTL_DEVAD,
-                               MDIO_84833_TOP_CFG_XGPHY_STRAP1, val);
+               if (!(val & (1<<15)))
+                       break;
+               msleep(1);
+       }
+       if (cnt >= 1500) {
+               DP(NETIF_MSG_LINK, "84833 reset timeout\n");
+               return -EINVAL;
        }
 
+       /* Put the port in super isolate mode. */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_CTL_DEVAD,
+                       MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val);
+       val |= MDIO_84833_SUPER_ISOLATE;
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_CTL_DEVAD,
+                        MDIO_84833_TOP_CFG_XGPHY_STRAP1, val);
+
+       /* Save spirom version */
+       bnx2x_save_848xx_spirom_version(phy, bp, PORT_0);
        return 0;
 }
 
+int bnx2x_pre_init_phy(struct bnx2x *bp,
+                                 u32 shmem_base,
+                                 u32 shmem2_base,
+                                 u32 chip_id)
+{
+       int rc = 0;
+       struct bnx2x_phy phy;
+       bnx2x_set_mdio_clk(bp, chip_id, PORT_0);
+       if (bnx2x_populate_phy(bp, EXT_PHY1, shmem_base, shmem2_base,
+                              PORT_0, &phy)) {
+               DP(NETIF_MSG_LINK, "populate_phy failed\n");
+               return -EINVAL;
+       }
+       switch (phy.type) {
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833:
+               rc = bnx2x_84833_pre_init_phy(bp, &phy);
+               break;
+       default:
+               break;
+       }
+       return rc;
+}
 
 static int bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
                                     u32 shmem2_base_path[], u8 phy_index,
index 44609de4e5dc59f7ecbe41d3ea8c0e01f17d837e..dddbcf6e154ec58d8d1f0720706df5ad0076c338 100644 (file)
  * set to 0x345678021. This is a new register (with 2_) added in E3 B0 to
  * accommodate the 9 input clients to ETS arbiter. */
 #define NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_MSB                  0x18684
+#define NIG_REG_P1_HWPFC_ENABLE                                         0x181d0
 #define NIG_REG_P1_MAC_IN_EN                                    0x185c0
 /* [RW 1] Output enable for TX MAC interface */
 #define NIG_REG_P1_MAC_OUT_EN                                   0x185c4
index 8fa7abc53ec69a38fce149dbf37acb5eca2a2cf1..084904ceaa301b4fd76f00a8411433ec1711b49e 100644 (file)
@@ -2259,7 +2259,8 @@ static int sbmac_init(struct platform_device *pldev, long long base)
        }
 
        sc->mii_bus->name = sbmac_mdio_string;
-       snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx);
+       snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pldev->name, idx);
        sc->mii_bus->priv = sc;
        sc->mii_bus->read = sbmac_mii_read;
        sc->mii_bus->write = sbmac_mii_write;
index 076e02a415a09d09878db3ea1c0071c03ac4a685..d529af99157dd6ce752fa6c3d22e0da572b2f7ae 100644 (file)
@@ -8846,9 +8846,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
        udelay(100);
 
-       if (tg3_flag(tp, USING_MSIX) && tp->irq_cnt > 1) {
+       if (tg3_flag(tp, USING_MSIX)) {
                val = tr32(MSGINT_MODE);
-               val |= MSGINT_MODE_MULTIVEC_EN | MSGINT_MODE_ENABLE;
+               val |= MSGINT_MODE_ENABLE;
+               if (tp->irq_cnt > 1)
+                       val |= MSGINT_MODE_MULTIVEC_EN;
                if (!tg3_flag(tp, 1SHOT_MSI))
                        val |= MSGINT_MODE_ONE_SHOT_DISABLE;
                tw32(MSGINT_MODE, val);
@@ -9548,19 +9550,18 @@ static int tg3_request_firmware(struct tg3 *tp)
 
 static bool tg3_enable_msix(struct tg3 *tp)
 {
-       int i, rc, cpus = num_online_cpus();
+       int i, rc;
        struct msix_entry msix_ent[tp->irq_max];
 
-       if (cpus == 1)
-               /* Just fallback to the simpler MSI mode. */
-               return false;
-
-       /*
-        * We want as many rx rings enabled as there are cpus.
-        * The first MSIX vector only deals with link interrupts, etc,
-        * so we add one to the number of vectors we are requesting.
-        */
-       tp->irq_cnt = min_t(unsigned, cpus + 1, tp->irq_max);
+       tp->irq_cnt = num_online_cpus();
+       if (tp->irq_cnt > 1) {
+               /* We want as many rx rings enabled as there are cpus.
+                * In multiqueue MSI-X mode, the first MSI-X vector
+                * only deals with link interrupts, etc, so we add
+                * one to the number of vectors we are requesting.
+                */
+               tp->irq_cnt = min_t(unsigned, tp->irq_cnt + 1, tp->irq_max);
+       }
 
        for (i = 0; i < tp->irq_max; i++) {
                msix_ent[i].entry  = i;
index f3d5c65d99cf20ae57f14fc9b7dd2007d81bba85..23200680d4c16e08ab0b384b93340e81fb12f04f 100644 (file)
@@ -243,7 +243,8 @@ static int macb_mii_init(struct macb *bp)
        bp->mii_bus->read = &macb_mdio_read;
        bp->mii_bus->write = &macb_mdio_write;
        bp->mii_bus->reset = &macb_mdio_reset;
-       snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", bp->pdev->id);
+       snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               bp->pdev->name, bp->pdev->id);
        bp->mii_bus->priv = bp;
        bp->mii_bus->parent = &bp->dev->dev;
        pdata = bp->pdev->dev.platform_data;
index ce88c0f399f68903333bbabdf546ea55abfed888..925c9bafc9b99519183eccc42b1b564a4bda3001 100644 (file)
@@ -325,7 +325,8 @@ static int dnet_mii_init(struct dnet *bp)
        bp->mii_bus->write = &dnet_mdio_write;
        bp->mii_bus->reset = &dnet_mdio_reset;
 
-       snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
+       snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               bp->pdev->name, bp->pdev->id);
 
        bp->mii_bus->priv = bp;
 
index ddcbbb34d1b910e07947622bf537d0478001cf20..7b25e9cf13f6ff5a6c141cd6c6bd478fe5e5c6fb 100644 (file)
@@ -476,6 +476,7 @@ fec_restart(struct net_device *ndev, int duplex)
        } else {
 #ifdef FEC_MIIGSK_ENR
                if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) {
+                       u32 cfgr;
                        /* disable the gasket and wait */
                        writel(0, fep->hwp + FEC_MIIGSK_ENR);
                        while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
@@ -486,9 +487,11 @@ fec_restart(struct net_device *ndev, int duplex)
                         *   RMII, 50 MHz, no loopback, no echo
                         *   MII, 25 MHz, no loopback, no echo
                         */
-                       writel((fep->phy_interface == PHY_INTERFACE_MODE_RMII) ?
-                                       1 : 0, fep->hwp + FEC_MIIGSK_CFGR);
-
+                       cfgr = (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
+                               ? BM_MIIGSK_CFGR_RMII : BM_MIIGSK_CFGR_MII;
+                       if (fep->phy_dev && fep->phy_dev->speed == SPEED_10)
+                               cfgr |= BM_MIIGSK_CFGR_FRCONT_10M;
+                       writel(cfgr, fep->hwp + FEC_MIIGSK_CFGR);
 
                        /* re-enable the gasket */
                        writel(2, fep->hwp + FEC_MIIGSK_ENR);
@@ -1077,7 +1080,8 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        fep->mii_bus->read = fec_enet_mdio_read;
        fep->mii_bus->write = fec_enet_mdio_write;
        fep->mii_bus->reset = fec_enet_mdio_reset;
-       snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%x", fep->dev_id + 1);
+       snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pdev->name, fep->dev_id + 1);
        fep->mii_bus->priv = fep;
        fep->mii_bus->parent = &pdev->dev;
 
index 8b2c6d797e6ddee6fe6dd165a22ba2ea9a8e8567..8408c627b1953a230c1f25d24b05217b0718d19f 100644 (file)
 #define FEC_MIIGSK_CFGR                0x300 /* MIIGSK Configuration reg */
 #define FEC_MIIGSK_ENR         0x308 /* MIIGSK Enable reg */
 
+#define BM_MIIGSK_CFGR_MII             0x00
+#define BM_MIIGSK_CFGR_RMII            0x01
+#define BM_MIIGSK_CFGR_FRCONT_10M      0x40
+
 #else
 
 #define FEC_ECNTRL             0x000 /* Ethernet control reg */
index e01cdaa722a977eac9b6c66513dfe13a44b97a44..39d160d353a41f3afbefcedb35f2397f5ec1ecb5 100644 (file)
@@ -1984,7 +1984,8 @@ static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb)
        return fcb;
 }
 
-static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
+static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb,
+               int fcb_length)
 {
        u8 flags = 0;
 
@@ -2006,7 +2007,7 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
         * frame (skb->data) and the start of the IP hdr.
         * l4os is the distance between the start of the
         * l3 hdr and the l4 hdr */
-       fcb->l3os = (u16)(skb_network_offset(skb) - GMAC_FCB_LEN);
+       fcb->l3os = (u16)(skb_network_offset(skb) - fcb_length);
        fcb->l4os = skb_network_header_len(skb);
 
        fcb->flags = flags;
@@ -2046,7 +2047,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        int i, rq = 0, do_tstamp = 0;
        u32 bufaddr;
        unsigned long flags;
-       unsigned int nr_frags, nr_txbds, length;
+       unsigned int nr_frags, nr_txbds, length, fcb_length = GMAC_FCB_LEN;
 
        /*
         * TOE=1 frames larger than 2500 bytes may see excess delays
@@ -2070,22 +2071,28 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* check if time stamp should be generated */
        if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
-                    priv->hwts_tx_en))
+                       priv->hwts_tx_en)) {
                do_tstamp = 1;
+               fcb_length = GMAC_FCB_LEN + GMAC_TXPAL_LEN;
+       }
 
        /* make space for additional header when fcb is needed */
        if (((skb->ip_summed == CHECKSUM_PARTIAL) ||
                        vlan_tx_tag_present(skb) ||
                        unlikely(do_tstamp)) &&
-                       (skb_headroom(skb) < GMAC_FCB_LEN)) {
+                       (skb_headroom(skb) < fcb_length)) {
                struct sk_buff *skb_new;
 
-               skb_new = skb_realloc_headroom(skb, GMAC_FCB_LEN);
+               skb_new = skb_realloc_headroom(skb, fcb_length);
                if (!skb_new) {
                        dev->stats.tx_errors++;
                        kfree_skb(skb);
                        return NETDEV_TX_OK;
                }
+
+               /* Steal sock reference for processing TX time stamps */
+               swap(skb_new->sk, skb->sk);
+               swap(skb_new->destructor, skb->destructor);
                kfree_skb(skb);
                skb = skb_new;
        }
@@ -2154,6 +2161,12 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
                lstatus = txbdp_start->lstatus;
        }
 
+       /* Add TxPAL between FCB and frame if required */
+       if (unlikely(do_tstamp)) {
+               skb_push(skb, GMAC_TXPAL_LEN);
+               memset(skb->data, 0, GMAC_TXPAL_LEN);
+       }
+
        /* Set up checksumming */
        if (CHECKSUM_PARTIAL == skb->ip_summed) {
                fcb = gfar_add_fcb(skb);
@@ -2164,7 +2177,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        skb_checksum_help(skb);
                } else {
                        lstatus |= BD_LFLAG(TXBD_TOE);
-                       gfar_tx_checksum(skb, fcb);
+                       gfar_tx_checksum(skb, fcb, fcb_length);
                }
        }
 
@@ -2196,9 +2209,9 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
         * the full frame length.
         */
        if (unlikely(do_tstamp)) {
-               txbdp_tstamp->bufPtr = txbdp_start->bufPtr + GMAC_FCB_LEN;
+               txbdp_tstamp->bufPtr = txbdp_start->bufPtr + fcb_length;
                txbdp_tstamp->lstatus |= BD_LFLAG(TXBD_READY) |
-                               (skb_headlen(skb) - GMAC_FCB_LEN);
+                               (skb_headlen(skb) - fcb_length);
                lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | GMAC_FCB_LEN;
        } else {
                lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb);
@@ -2490,7 +2503,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 
                if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
                        next = next_txbd(bdp, base, tx_ring_size);
-                       buflen = next->length + GMAC_FCB_LEN;
+                       buflen = next->length + GMAC_FCB_LEN + GMAC_TXPAL_LEN;
                } else
                        buflen = bdp->length;
 
@@ -2502,6 +2515,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
                        u64 *ns = (u64*) (((u32)skb->data + 0x10) & ~0x7);
                        memset(&shhwtstamps, 0, sizeof(shhwtstamps));
                        shhwtstamps.hwtstamp = ns_to_ktime(*ns);
+                       skb_pull(skb, GMAC_FCB_LEN + GMAC_TXPAL_LEN);
                        skb_tstamp_tx(skb, &shhwtstamps);
                        bdp->lstatus &= BD_LFLAG(TXBD_WRAP);
                        bdp = next;
index fe7ac3a83194d8407f191227e710fe19a699e13a..40c33a7554c057c01273062339f8e8f5836626a4 100644 (file)
@@ -63,6 +63,9 @@ struct ethtool_rx_list {
 /* Length for FCB */
 #define GMAC_FCB_LEN 8
 
+/* Length for TxPAL */
+#define GMAC_TXPAL_LEN 16
+
 /* Default padding amount */
 #define DEFAULT_PADDING 2
 
index 05b7359bde8da1931ac53ebc6fc95310bd398e11..6bdd8e36e564c4868eac9259b63a81c23f345337 100644 (file)
@@ -263,7 +263,7 @@ static void ehea_get_ethtool_stats(struct net_device *dev,
                data[i++] = atomic_read(&port->port_res[k].swqe_avail);
 }
 
-const struct ethtool_ops ehea_ethtool_ops = {
+static const struct ethtool_ops ehea_ethtool_ops = {
        .get_settings = ehea_get_settings,
        .get_drvinfo = ehea_get_drvinfo,
        .get_msglevel = ehea_get_msglevel,
index 3554414eb5e289287e3a9ab174320c7e9fa1bf30..5d5fb2627184f9b7f303d64c22875182c63d88e6 100644 (file)
@@ -94,8 +94,8 @@ static int port_name_cnt;
 static LIST_HEAD(adapter_list);
 static unsigned long ehea_driver_flags;
 static DEFINE_MUTEX(dlpar_mem_lock);
-struct ehea_fw_handle_array ehea_fw_handles;
-struct ehea_bcmc_reg_array ehea_bcmc_regs;
+static struct ehea_fw_handle_array ehea_fw_handles;
+static struct ehea_bcmc_reg_array ehea_bcmc_regs;
 
 
 static int __devinit ehea_probe_adapter(struct platform_device *dev,
@@ -133,7 +133,7 @@ void ehea_dump(void *adr, int len, char *msg)
        }
 }
 
-void ehea_schedule_port_reset(struct ehea_port *port)
+static void ehea_schedule_port_reset(struct ehea_port *port)
 {
        if (!test_bit(__EHEA_DISABLE_PORT_RESET, &port->flags))
                schedule_work(&port->reset_task);
@@ -1404,7 +1404,7 @@ out:
        return ret;
 }
 
-int ehea_gen_smrs(struct ehea_port_res *pr)
+static int ehea_gen_smrs(struct ehea_port_res *pr)
 {
        int ret;
        struct ehea_adapter *adapter = pr->port->adapter;
@@ -1426,7 +1426,7 @@ out:
        return -EIO;
 }
 
-int ehea_rem_smrs(struct ehea_port_res *pr)
+static int ehea_rem_smrs(struct ehea_port_res *pr)
 {
        if ((ehea_rem_mr(&pr->send_mr)) ||
            (ehea_rem_mr(&pr->recv_mr)))
@@ -2190,7 +2190,7 @@ out:
        return err;
 }
 
-int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
+static int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
 {
        int ret = -EIO;
        u64 hret;
@@ -2531,7 +2531,7 @@ static void ehea_flush_sq(struct ehea_port *port)
        }
 }
 
-int ehea_stop_qps(struct net_device *dev)
+static int ehea_stop_qps(struct net_device *dev)
 {
        struct ehea_port *port = netdev_priv(dev);
        struct ehea_adapter *adapter = port->adapter;
@@ -2600,7 +2600,7 @@ out:
        return ret;
 }
 
-void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res *pr)
+static void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res *pr)
 {
        struct ehea_qp qp = *orig_qp;
        struct ehea_qp_init_attr *init_attr = &qp.init_attr;
@@ -2633,7 +2633,7 @@ void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res *pr)
        }
 }
 
-int ehea_restart_qps(struct net_device *dev)
+static int ehea_restart_qps(struct net_device *dev)
 {
        struct ehea_port *port = netdev_priv(dev);
        struct ehea_adapter *adapter = port->adapter;
@@ -2824,7 +2824,7 @@ static void ehea_tx_watchdog(struct net_device *dev)
                ehea_schedule_port_reset(port);
 }
 
-int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
+static int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
 {
        struct hcp_query_ehea *cb;
        u64 hret;
@@ -2852,7 +2852,7 @@ out:
        return ret;
 }
 
-int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo)
+static int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo)
 {
        struct hcp_ehea_port_cb4 *cb4;
        u64 hret;
@@ -2966,7 +2966,7 @@ static const struct net_device_ops ehea_netdev_ops = {
        .ndo_tx_timeout         = ehea_tx_watchdog,
 };
 
-struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
+static struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
                                         u32 logical_port_id,
                                         struct device_node *dn)
 {
@@ -3237,7 +3237,7 @@ static ssize_t ehea_remove_port(struct device *dev,
 static DEVICE_ATTR(probe_port, S_IWUSR, NULL, ehea_probe_port);
 static DEVICE_ATTR(remove_port, S_IWUSR, NULL, ehea_remove_port);
 
-int ehea_create_device_sysfs(struct platform_device *dev)
+static int ehea_create_device_sysfs(struct platform_device *dev)
 {
        int ret = device_create_file(&dev->dev, &dev_attr_probe_port);
        if (ret)
@@ -3248,7 +3248,7 @@ out:
        return ret;
 }
 
-void ehea_remove_device_sysfs(struct platform_device *dev)
+static void ehea_remove_device_sysfs(struct platform_device *dev)
 {
        device_remove_file(&dev->dev, &dev_attr_probe_port);
        device_remove_file(&dev->dev, &dev_attr_remove_port);
@@ -3379,7 +3379,7 @@ static int __devexit ehea_remove(struct platform_device *dev)
        return 0;
 }
 
-void ehea_crash_handler(void)
+static void ehea_crash_handler(void)
 {
        int i;
 
@@ -3491,7 +3491,7 @@ static ssize_t ehea_show_capabilities(struct device_driver *drv,
 static DRIVER_ATTR(capabilities, S_IRUSR | S_IRGRP | S_IROTH,
                   ehea_show_capabilities, NULL);
 
-int __init ehea_module_init(void)
+static int __init ehea_module_init(void)
 {
        int ret;
 
index 95b9f4fa811e7102cc6db2248dbabf1af7e3d1e9..c25b05b94daae698e0b8640e40da8614ea9ad4f7 100644 (file)
@@ -34,9 +34,7 @@
 #include "ehea_phyp.h"
 #include "ehea_qmr.h"
 
-struct ehea_bmap *ehea_bmap = NULL;
-
-
+static struct ehea_bmap *ehea_bmap;
 
 static void *hw_qpageit_get_inc(struct hw_queue *queue)
 {
@@ -212,7 +210,7 @@ out_nomem:
        return NULL;
 }
 
-u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force)
+static u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force)
 {
        u64 hret;
        u64 adapter_handle = cq->adapter->handle;
@@ -337,7 +335,7 @@ struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq)
        return eqe;
 }
 
-u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force)
+static u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force)
 {
        u64 hret;
        unsigned long flags;
@@ -381,7 +379,7 @@ int ehea_destroy_eq(struct ehea_eq *eq)
 /**
  * allocates memory for a queue and registers pages in phyp
  */
-int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue,
+static int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue,
                           int nr_pages, int wqe_size, int act_nr_sges,
                           struct ehea_adapter *adapter, int h_call_q_selector)
 {
@@ -516,7 +514,7 @@ out_freemem:
        return NULL;
 }
 
-u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force)
+static u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force)
 {
        u64 hret;
        struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
@@ -976,7 +974,7 @@ int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
        return 0;
 }
 
-void print_error_data(u64 *data)
+static void print_error_data(u64 *data)
 {
        int length;
        u64 type = EHEA_BMASK_GET(ERROR_DATA_TYPE, data[2]);
index 0b3567ab812151f00210544cc805815b0953a90d..85e2c6cd9708b6a394f95dacc2a35e8d5e60fd9b 100644 (file)
@@ -98,6 +98,7 @@ struct ltq_etop_chan {
 
 struct ltq_etop_priv {
        struct net_device *netdev;
+       struct platform_device *pdev;
        struct ltq_eth_data *pldata;
        struct resource *res;
 
@@ -436,7 +437,8 @@ ltq_etop_mdio_init(struct net_device *dev)
        priv->mii_bus->read = ltq_etop_mdio_rd;
        priv->mii_bus->write = ltq_etop_mdio_wr;
        priv->mii_bus->name = "ltq_mii";
-       snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
+       snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               priv->pdev->name, priv->pdev->id);
        priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
        if (!priv->mii_bus->irq) {
                err = -ENOMEM;
@@ -734,6 +736,7 @@ ltq_etop_probe(struct platform_device *pdev)
        dev->ethtool_ops = &ltq_etop_ethtool_ops;
        priv = netdev_priv(dev);
        priv->res = res;
+       priv->pdev = pdev;
        priv->pldata = dev_get_platdata(&pdev->dev);
        priv->netdev = dev;
        spin_lock_init(&priv->lock);
index 80aab4e5d695351b4eec8f9267459f3b06c6bd34..9c049d2cb97d00142b1fbfaa6a1b14b6f8fac580 100644 (file)
@@ -2613,7 +2613,8 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
                msp->smi_bus->name = "mv643xx_eth smi";
                msp->smi_bus->read = smi_bus_read;
                msp->smi_bus->write = smi_bus_write,
-               snprintf(msp->smi_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id);
+               snprintf(msp->smi_bus->id, MII_BUS_ID_SIZE, "%s-%d",
+                       pdev->name, pdev->id);
                msp->smi_bus->parent = &pdev->dev;
                msp->smi_bus->phy_mask = 0xffffffff;
                if (mdiobus_register(msp->smi_bus) < 0)
index 5ec409e3da090d6657afb2bf45e5ffa6d4e339e4..953ba5851f7b44174f2800a163214409cc7ebb3a 100644 (file)
@@ -1552,7 +1552,8 @@ static int pxa168_eth_probe(struct platform_device *pdev)
        pep->smi_bus->name = "pxa168_eth smi";
        pep->smi_bus->read = pxa168_smi_read;
        pep->smi_bus->write = pxa168_smi_write;
-       snprintf(pep->smi_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id);
+       snprintf(pep->smi_bus->id, MII_BUS_ID_SIZE, "%s-%d",
+               pdev->name, pdev->id);
        pep->smi_bus->parent = &pdev->dev;
        pep->smi_bus->phy_mask = 0xffffffff;
        err = mdiobus_register(pep->smi_bus);
index 75ec87a822b8e2d1ee12486bc6cfcbf0f3e0a248..0a85690a1321ecc17cf24f2398f496d60dc8d175 100644 (file)
@@ -459,7 +459,7 @@ static int ks8842_tx_frame_dma(struct sk_buff *skb, struct net_device *netdev)
                sg_dma_len(&ctl->sg) += 4 - sg_dma_len(&ctl->sg) % 4;
 
        ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan,
-               &ctl->sg, 1, DMA_TO_DEVICE,
+               &ctl->sg, 1, DMA_MEM_TO_DEV,
                DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
        if (!ctl->adesc)
                return NETDEV_TX_BUSY;
@@ -571,7 +571,7 @@ static int __ks8842_start_new_rx_dma(struct net_device *netdev)
                sg_dma_len(sg) = DMA_BUFFER_SIZE;
 
                ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan,
-                       sg, 1, DMA_FROM_DEVICE,
+                       sg, 1, DMA_DEV_TO_MEM,
                        DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
 
                if (!ctl->adesc)
index 6ed09a85f03506ae7679e23ec5bc4425545cc5fd..e52cd310ae76147f0bbf54cc41f63da4e7f4013c 100644 (file)
 #define MAC_ADDR_ORDER(i)              (ETH_ALEN - 1 - (i))
 
 #define MAX_ETHERNET_BODY_SIZE         1500
-#define ETHERNET_HEADER_SIZE           14
+#define ETHERNET_HEADER_SIZE           (14 + VLAN_HLEN)
 
 #define MAX_ETHERNET_PACKET_SIZE       \
        (MAX_ETHERNET_BODY_SIZE + ETHERNET_HEADER_SIZE)
index fc9bda9bc36c841597b13e231941343ba9486ee2..813d41c4a845501bd37e772f094cc356ce029aab 100644 (file)
@@ -1702,7 +1702,8 @@ static int sh_mdio_init(struct net_device *ndev, int id,
        /* Hook up MII support for ethtool */
        mdp->mii_bus->name = "sh_mii";
        mdp->mii_bus->parent = &ndev->dev;
-       snprintf(mdp->mii_bus->id, MII_BUS_ID_SIZE, "%x", id);
+       snprintf(mdp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               mdp->pdev->name, id);
 
        /* PHY IRQ */
        mdp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
index a7ff8ea342b4329baae598c4f1b08a704e016356..22e9c0181ce84dca1742c6b563f50491f925dac2 100644 (file)
@@ -1004,7 +1004,7 @@ static int __devinit s6gmac_probe(struct platform_device *pdev)
        mb->write = s6mii_write;
        mb->reset = s6mii_reset;
        mb->priv = pd;
-       snprintf(mb->id, MII_BUS_ID_SIZE, "0");
+       snprintf(mb->id, MII_BUS_ID_SIZE, "%s-%x", pdev->name, pdev->id);
        mb->phy_mask = ~(1 << 0);
        mb->irq = &pd->mii.irq[0];
        for (i = 0; i < PHY_MAX_ADDR; i++) {
index 9d0b8ced0234b5ae7468abcf732af6b080618d8d..24d2df068d717dd2163742dd479c1a97db003235 100644 (file)
@@ -1044,7 +1044,8 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev,
        }
 
        pdata->mii_bus->name = SMSC_MDIONAME;
-       snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
+       snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pdev->name, pdev->id);
        pdata->mii_bus->priv = pdata;
        pdata->mii_bus->read = smsc911x_mii_read;
        pdata->mii_bus->write = smsc911x_mii_write;
index 41e6b33e1b084724132d11369442f43269c12108..c07cfe989f6ef35716c59d3b5e29cdeefa4f1f2a 100644 (file)
@@ -22,6 +22,7 @@
   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
+#include <linux/kernel.h>
 #include <linux/io.h>
 #include "mmc.h"
 
index 3738b47005489ef35afe054e868a7868a5d1c9b5..96fa2da307630f1e46df75441af10c91f0fd4c79 100644 (file)
@@ -307,7 +307,7 @@ static int stmmac_init_phy(struct net_device *dev)
        priv->speed = 0;
        priv->oldduplex = -1;
 
-       snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id);
+       snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", priv->plat->bus_id);
        snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
                 priv->plat->phy_addr);
        pr_debug("stmmac_init_phy:  trying to attach to %s\n", phy_id);
@@ -772,7 +772,7 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv)
                dwmac_mmc_ctrl(priv->ioaddr, mode);
                memset(&priv->mmc, 0, sizeof(struct stmmac_counters));
        } else
-               pr_info(" No MAC Management Counters available");
+               pr_info(" No MAC Management Counters available\n");
 }
 
 static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)
index 51f4412339627c4a09cbd1ac0fae90ddd1d4f40d..da4a1042523a633e5781f86df7ffe4e123c09910 100644 (file)
@@ -158,7 +158,8 @@ int stmmac_mdio_register(struct net_device *ndev)
        new_bus->read = &stmmac_mdio_read;
        new_bus->write = &stmmac_mdio_write;
        new_bus->reset = &stmmac_mdio_reset;
-       snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", mdio_bus_data->bus_id);
+       snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               new_bus->name, mdio_bus_data->bus_id);
        new_bus->priv = ndev;
        new_bus->irq = irqlist;
        new_bus->phy_mask = mdio_bus_data->phy_mask;
index 7b1594f4944e24f1005582be6511f1aa5167a773..1ac83243649a2d4c44ad4efa7fd0393c6869fbce 100644 (file)
@@ -62,7 +62,7 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
        priv = stmmac_dvr_probe(&(pdev->dev), plat_dat);
        if (!priv) {
                pr_err("%s: main drivr probe failed", __func__);
-               goto out_release_region;
+               goto out_unmap;
        }
 
        priv->ioaddr = addr;
index aaac0c7ad111192605075348264d1ddc38ceb2e6..4d9a28ffd3c3ac20d2764ea72ada7e70cadc04f0 100644 (file)
@@ -1269,7 +1269,7 @@ int __devinit cpmac_init(void)
        }
 
        cpmac_mii->phy_mask = ~(mask | 0x80000000);
-       snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "1");
+       snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "cpmac-1");
 
        res = mdiobus_register(cpmac_mii);
        if (res)
index 7615040df75621dda0684732017e4d21fac425eb..ef7c9c17bfffccbebd94ba0530fc1643e947812e 100644 (file)
@@ -313,7 +313,8 @@ static int __devinit davinci_mdio_probe(struct platform_device *pdev)
        data->bus->reset        = davinci_mdio_reset,
        data->bus->parent       = dev;
        data->bus->priv         = data;
-       snprintf(data->bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
+       snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pdev->name, pdev->id);
 
        data->clk = clk_get(dev, NULL);
        if (IS_ERR(data->clk)) {
index a9ce01bafd200c34265f33e4cff8d202719a5312..164fb775d7b333387cedacb80752c1c0b29bd566 100644 (file)
@@ -1604,7 +1604,7 @@ tsi108_init_one(struct platform_device *pdev)
        data->phyregs = ioremap(einfo->phyregs, 0x400);
        if (NULL == data->phyregs) {
                err = -ENOMEM;
-               goto regs_fail;
+               goto phyregs_fail;
        }
 /* MII setup */
        data->mii_if.dev = dev;
@@ -1663,9 +1663,11 @@ tsi108_init_one(struct platform_device *pdev)
        return 0;
 
 register_fail:
-       iounmap(data->regs);
        iounmap(data->phyregs);
 
+phyregs_fail:
+       iounmap(data->regs);
+
 regs_fail:
        free_netdev(dev);
        return err;
index 5c4983b2870a9c7a5dd7adefba08a8c054671a9b..10b18eb63d254834fc7a9b58f59eadd8078a75d9 100644 (file)
 
 /* A few user-configurable values.
    These may be modified when a driver module is loaded. */
-
-#define DEBUG
-static int debug = 1;  /* 1 normal messages, 0 quiet .. 7 verbose. */
-static int max_interrupt_work = 20;
+static int debug = 0;
+#define RHINE_MSG_DEFAULT \
+        (0x0000)
 
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
    Setting to > 1518 effectively disables this feature. */
@@ -128,12 +127,10 @@ MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver");
 MODULE_LICENSE("GPL");
 
-module_param(max_interrupt_work, int, 0);
 module_param(debug, int, 0);
 module_param(rx_copybreak, int, 0);
 module_param(avoid_D3, bool, 0);
-MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt");
-MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)");
+MODULE_PARM_DESC(debug, "VIA Rhine debug message flags");
 MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames");
 MODULE_PARM_DESC(avoid_D3, "Avoid power state D3 (work-around for broken BIOSes)");
 
@@ -351,16 +348,25 @@ static const int mmio_verify_registers[] = {
 
 /* Bits in the interrupt status/mask registers. */
 enum intr_status_bits {
-       IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020,
-       IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0210,
-       IntrPCIErr=0x0040,
-       IntrStatsMax=0x0080, IntrRxEarly=0x0100,
-       IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
-       IntrTxAborted=0x2000, IntrLinkChange=0x4000,
-       IntrRxWakeUp=0x8000,
-       IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260,
-       IntrTxDescRace=0x080000,        /* mapped from IntrStatus2 */
-       IntrTxErrSummary=0x082218,
+       IntrRxDone      = 0x0001,
+       IntrTxDone      = 0x0002,
+       IntrRxErr       = 0x0004,
+       IntrTxError     = 0x0008,
+       IntrRxEmpty     = 0x0020,
+       IntrPCIErr      = 0x0040,
+       IntrStatsMax    = 0x0080,
+       IntrRxEarly     = 0x0100,
+       IntrTxUnderrun  = 0x0210,
+       IntrRxOverflow  = 0x0400,
+       IntrRxDropped   = 0x0800,
+       IntrRxNoBuf     = 0x1000,
+       IntrTxAborted   = 0x2000,
+       IntrLinkChange  = 0x4000,
+       IntrRxWakeUp    = 0x8000,
+       IntrTxDescRace          = 0x080000,     /* mapped from IntrStatus2 */
+       IntrNormalSummary       = IntrRxDone | IntrTxDone,
+       IntrTxErrSummary        = IntrTxDescRace | IntrTxAborted | IntrTxError |
+                                 IntrTxUnderrun,
 };
 
 /* Bits in WOLcrSet/WOLcrClr and PwrcsrSet/PwrcsrClr */
@@ -439,8 +445,13 @@ struct rhine_private {
        struct net_device *dev;
        struct napi_struct napi;
        spinlock_t lock;
+       struct mutex task_lock;
+       bool task_enable;
+       struct work_struct slow_event_task;
        struct work_struct reset_task;
 
+       u32 msg_enable;
+
        /* Frequently used values: keep some adjacent for cache effect. */
        u32 quirks;
        struct rx_desc *rx_head_desc;
@@ -476,41 +487,50 @@ static int  mdio_read(struct net_device *dev, int phy_id, int location);
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
 static int  rhine_open(struct net_device *dev);
 static void rhine_reset_task(struct work_struct *work);
+static void rhine_slow_event_task(struct work_struct *work);
 static void rhine_tx_timeout(struct net_device *dev);
 static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
                                  struct net_device *dev);
 static irqreturn_t rhine_interrupt(int irq, void *dev_instance);
 static void rhine_tx(struct net_device *dev);
 static int rhine_rx(struct net_device *dev, int limit);
-static void rhine_error(struct net_device *dev, int intr_status);
 static void rhine_set_rx_mode(struct net_device *dev);
 static struct net_device_stats *rhine_get_stats(struct net_device *dev);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static const struct ethtool_ops netdev_ethtool_ops;
 static int  rhine_close(struct net_device *dev);
-static void rhine_shutdown (struct pci_dev *pdev);
 static int rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid);
 static int rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid);
-static void rhine_set_cam(void __iomem *ioaddr, int idx, u8 *addr);
-static void rhine_set_vlan_cam(void __iomem *ioaddr, int idx, u8 *addr);
-static void rhine_set_cam_mask(void __iomem *ioaddr, u32 mask);
-static void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask);
-static void rhine_init_cam_filter(struct net_device *dev);
-static void rhine_update_vcam(struct net_device *dev);
-
-#define RHINE_WAIT_FOR(condition)                              \
-do {                                                           \
-       int i = 1024;                                           \
-       while (!(condition) && --i)                             \
-               ;                                               \
-       if (debug > 1 && i < 512)                               \
-               pr_info("%4d cycles used @ %s:%d\n",            \
-                       1024 - i, __func__, __LINE__);          \
-} while (0)
-
-static inline u32 get_intr_status(struct net_device *dev)
+static void rhine_restart_tx(struct net_device *dev);
+
+static void rhine_wait_bit(struct rhine_private *rp, u8 reg, u8 mask, bool high)
+{
+       void __iomem *ioaddr = rp->base;
+       int i;
+
+       for (i = 0; i < 1024; i++) {
+               if (high ^ !!(ioread8(ioaddr + reg) & mask))
+                       break;
+               udelay(10);
+       }
+       if (i > 64) {
+               netif_dbg(rp, hw, rp->dev, "%s bit wait (%02x/%02x) cycle "
+                         "count: %04d\n", high ? "high" : "low", reg, mask, i);
+       }
+}
+
+static void rhine_wait_bit_high(struct rhine_private *rp, u8 reg, u8 mask)
+{
+       rhine_wait_bit(rp, reg, mask, true);
+}
+
+static void rhine_wait_bit_low(struct rhine_private *rp, u8 reg, u8 mask)
+{
+       rhine_wait_bit(rp, reg, mask, false);
+}
+
+static u32 rhine_get_events(struct rhine_private *rp)
 {
-       struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
        u32 intr_status;
 
@@ -521,6 +541,16 @@ static inline u32 get_intr_status(struct net_device *dev)
        return intr_status;
 }
 
+static void rhine_ack_events(struct rhine_private *rp, u32 mask)
+{
+       void __iomem *ioaddr = rp->base;
+
+       if (rp->quirks & rqStatusWBRace)
+               iowrite8(mask >> 16, ioaddr + IntrStatus2);
+       iowrite16(mask, ioaddr + IntrStatus);
+       mmiowb();
+}
+
 /*
  * Get power related registers into sane state.
  * Notify user about past WOL event.
@@ -585,6 +615,7 @@ static void rhine_chip_reset(struct net_device *dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
+       u8 cmd1;
 
        iowrite8(Cmd1Reset, ioaddr + ChipCmd1);
        IOSYNC;
@@ -597,13 +628,12 @@ static void rhine_chip_reset(struct net_device *dev)
                        iowrite8(0x40, ioaddr + MiscCmd);
 
                /* Reset can take somewhat longer (rare) */
-               RHINE_WAIT_FOR(!(ioread8(ioaddr + ChipCmd1) & Cmd1Reset));
+               rhine_wait_bit_low(rp, ChipCmd1, Cmd1Reset);
        }
 
-       if (debug > 1)
-               netdev_info(dev, "Reset %s\n",
-                           (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) ?
-                           "failed" : "succeeded");
+       cmd1 = ioread8(ioaddr + ChipCmd1);
+       netif_info(rp, hw, dev, "Reset %s\n", (cmd1 & Cmd1Reset) ?
+                  "failed" : "succeeded");
 }
 
 #ifdef USE_MMIO
@@ -629,9 +659,15 @@ static void __devinit rhine_reload_eeprom(long pioaddr, struct net_device *dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
+       int i;
 
        outb(0x20, pioaddr + MACRegEEcsr);
-       RHINE_WAIT_FOR(!(inb(pioaddr + MACRegEEcsr) & 0x20));
+       for (i = 0; i < 1024; i++) {
+               if (!(inb(pioaddr + MACRegEEcsr) & 0x20))
+                       break;
+       }
+       if (i > 512)
+               pr_info("%4d cycles used @ %s:%d\n", i, __func__, __LINE__);
 
 #ifdef USE_MMIO
        /*
@@ -657,23 +693,127 @@ static void rhine_poll(struct net_device *dev)
 }
 #endif
 
+static void rhine_kick_tx_threshold(struct rhine_private *rp)
+{
+       if (rp->tx_thresh < 0xe0) {
+               void __iomem *ioaddr = rp->base;
+
+               rp->tx_thresh += 0x20;
+               BYTE_REG_BITS_SET(rp->tx_thresh, 0x80, ioaddr + TxConfig);
+       }
+}
+
+static void rhine_tx_err(struct rhine_private *rp, u32 status)
+{
+       struct net_device *dev = rp->dev;
+
+       if (status & IntrTxAborted) {
+               netif_info(rp, tx_err, dev,
+                          "Abort %08x, frame dropped\n", status);
+       }
+
+       if (status & IntrTxUnderrun) {
+               rhine_kick_tx_threshold(rp);
+               netif_info(rp, tx_err ,dev, "Transmitter underrun, "
+                          "Tx threshold now %02x\n", rp->tx_thresh);
+       }
+
+       if (status & IntrTxDescRace)
+               netif_info(rp, tx_err, dev, "Tx descriptor write-back race\n");
+
+       if ((status & IntrTxError) &&
+           (status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace)) == 0) {
+               rhine_kick_tx_threshold(rp);
+               netif_info(rp, tx_err, dev, "Unspecified error. "
+                          "Tx threshold now %02x\n", rp->tx_thresh);
+       }
+
+       rhine_restart_tx(dev);
+}
+
+static void rhine_update_rx_crc_and_missed_errord(struct rhine_private *rp)
+{
+       void __iomem *ioaddr = rp->base;
+       struct net_device_stats *stats = &rp->dev->stats;
+
+       stats->rx_crc_errors    += ioread16(ioaddr + RxCRCErrs);
+       stats->rx_missed_errors += ioread16(ioaddr + RxMissed);
+
+       /*
+        * Clears the "tally counters" for CRC errors and missed frames(?).
+        * It has been reported that some chips need a write of 0 to clear
+        * these, for others the counters are set to 1 when written to and
+        * instead cleared when read. So we clear them both ways ...
+        */
+       iowrite32(0, ioaddr + RxMissed);
+       ioread16(ioaddr + RxCRCErrs);
+       ioread16(ioaddr + RxMissed);
+}
+
+#define RHINE_EVENT_NAPI_RX    (IntrRxDone | \
+                                IntrRxErr | \
+                                IntrRxEmpty | \
+                                IntrRxOverflow | \
+                                IntrRxDropped | \
+                                IntrRxNoBuf | \
+                                IntrRxWakeUp)
+
+#define RHINE_EVENT_NAPI_TX_ERR        (IntrTxError | \
+                                IntrTxAborted | \
+                                IntrTxUnderrun | \
+                                IntrTxDescRace)
+#define RHINE_EVENT_NAPI_TX    (IntrTxDone | RHINE_EVENT_NAPI_TX_ERR)
+
+#define RHINE_EVENT_NAPI       (RHINE_EVENT_NAPI_RX | \
+                                RHINE_EVENT_NAPI_TX | \
+                                IntrStatsMax)
+#define RHINE_EVENT_SLOW       (IntrPCIErr | IntrLinkChange)
+#define RHINE_EVENT            (RHINE_EVENT_NAPI | RHINE_EVENT_SLOW)
+
 static int rhine_napipoll(struct napi_struct *napi, int budget)
 {
        struct rhine_private *rp = container_of(napi, struct rhine_private, napi);
        struct net_device *dev = rp->dev;
        void __iomem *ioaddr = rp->base;
-       int work_done;
+       u16 enable_mask = RHINE_EVENT & 0xffff;
+       int work_done = 0;
+       u32 status;
+
+       status = rhine_get_events(rp);
+       rhine_ack_events(rp, status & ~RHINE_EVENT_SLOW);
+
+       if (status & RHINE_EVENT_NAPI_RX)
+               work_done += rhine_rx(dev, budget);
+
+       if (status & RHINE_EVENT_NAPI_TX) {
+               if (status & RHINE_EVENT_NAPI_TX_ERR) {
+                       /* Avoid scavenging before Tx engine turned off */
+                       rhine_wait_bit_low(rp, ChipCmd, CmdTxOn);
+                       if (ioread8(ioaddr + ChipCmd) & CmdTxOn)
+                               netif_warn(rp, tx_err, dev, "Tx still on\n");
+               }
 
-       work_done = rhine_rx(dev, budget);
+               rhine_tx(dev);
+
+               if (status & RHINE_EVENT_NAPI_TX_ERR)
+                       rhine_tx_err(rp, status);
+       }
+
+       if (status & IntrStatsMax) {
+               spin_lock(&rp->lock);
+               rhine_update_rx_crc_and_missed_errord(rp);
+               spin_unlock(&rp->lock);
+       }
+
+       if (status & RHINE_EVENT_SLOW) {
+               enable_mask &= ~RHINE_EVENT_SLOW;
+               schedule_work(&rp->slow_event_task);
+       }
 
        if (work_done < budget) {
                napi_complete(napi);
-
-               iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
-                         IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
-                         IntrTxDone | IntrTxError | IntrTxUnderrun |
-                         IntrPCIErr | IntrStatsMax | IntrLinkChange,
-                         ioaddr + IntrEnable);
+               iowrite16(enable_mask, ioaddr + IntrEnable);
+               mmiowb();
        }
        return work_done;
 }
@@ -797,6 +937,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
        rp->quirks = quirks;
        rp->pioaddr = pioaddr;
        rp->pdev = pdev;
+       rp->msg_enable = netif_msg_init(debug, RHINE_MSG_DEFAULT);
 
        rc = pci_request_regions(pdev, DRV_NAME);
        if (rc)
@@ -856,7 +997,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
        dev->irq = pdev->irq;
 
        spin_lock_init(&rp->lock);
+       mutex_init(&rp->task_lock);
        INIT_WORK(&rp->reset_task, rhine_reset_task);
+       INIT_WORK(&rp->slow_event_task, rhine_slow_event_task);
 
        rp->mii_if.dev = dev;
        rp->mii_if.mdio_read = mdio_read;
@@ -916,8 +1059,8 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
                }
        }
        rp->mii_if.phy_id = phy_id;
-       if (debug > 1 && avoid_D3)
-               netdev_info(dev, "No D3 power state at shutdown\n");
+       if (avoid_D3)
+               netif_info(rp, probe, dev, "No D3 power state at shutdown\n");
 
        return 0;
 
@@ -1093,7 +1236,7 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media)
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
 
-       mii_check_media(&rp->mii_if, debug, init_media);
+       mii_check_media(&rp->mii_if, netif_msg_link(rp), init_media);
 
        if (rp->mii_if.full_duplex)
            iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1FDuplex,
@@ -1101,24 +1244,26 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media)
        else
            iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex,
                   ioaddr + ChipCmd1);
-       if (debug > 1)
-               netdev_info(dev, "force_media %d, carrier %d\n",
-                           rp->mii_if.force_media, netif_carrier_ok(dev));
+
+       netif_info(rp, link, dev, "force_media %d, carrier %d\n",
+                  rp->mii_if.force_media, netif_carrier_ok(dev));
 }
 
 /* Called after status of force_media possibly changed */
 static void rhine_set_carrier(struct mii_if_info *mii)
 {
+       struct net_device *dev = mii->dev;
+       struct rhine_private *rp = netdev_priv(dev);
+
        if (mii->force_media) {
                /* autoneg is off: Link is always assumed to be up */
-               if (!netif_carrier_ok(mii->dev))
-                       netif_carrier_on(mii->dev);
-       }
-       else    /* Let MMI library update carrier status */
-               rhine_check_media(mii->dev, 0);
-       if (debug > 1)
-               netdev_info(mii->dev, "force_media %d, carrier %d\n",
-                           mii->force_media, netif_carrier_ok(mii->dev));
+               if (!netif_carrier_ok(dev))
+                       netif_carrier_on(dev);
+       } else  /* Let MMI library update carrier status */
+               rhine_check_media(dev, 0);
+
+       netif_info(rp, link, dev, "force_media %d, carrier %d\n",
+                  mii->force_media, netif_carrier_ok(dev));
 }
 
 /**
@@ -1266,10 +1411,10 @@ static int rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
 {
        struct rhine_private *rp = netdev_priv(dev);
 
-       spin_lock_irq(&rp->lock);
+       spin_lock_bh(&rp->lock);
        set_bit(vid, rp->active_vlans);
        rhine_update_vcam(dev);
-       spin_unlock_irq(&rp->lock);
+       spin_unlock_bh(&rp->lock);
        return 0;
 }
 
@@ -1277,10 +1422,10 @@ static int rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 {
        struct rhine_private *rp = netdev_priv(dev);
 
-       spin_lock_irq(&rp->lock);
+       spin_lock_bh(&rp->lock);
        clear_bit(vid, rp->active_vlans);
        rhine_update_vcam(dev);
-       spin_unlock_irq(&rp->lock);
+       spin_unlock_bh(&rp->lock);
        return 0;
 }
 
@@ -1310,12 +1455,7 @@ static void init_registers(struct net_device *dev)
 
        napi_enable(&rp->napi);
 
-       /* Enable interrupts by setting the interrupt mask. */
-       iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
-              IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
-              IntrTxDone | IntrTxError | IntrTxUnderrun |
-              IntrPCIErr | IntrStatsMax | IntrLinkChange,
-              ioaddr + IntrEnable);
+       iowrite16(RHINE_EVENT & 0xffff, ioaddr + IntrEnable);
 
        iowrite16(CmdStart | CmdTxOn | CmdRxOn | (Cmd1NoTxPoll << 8),
               ioaddr + ChipCmd);
@@ -1323,23 +1463,27 @@ static void init_registers(struct net_device *dev)
 }
 
 /* Enable MII link status auto-polling (required for IntrLinkChange) */
-static void rhine_enable_linkmon(void __iomem *ioaddr)
+static void rhine_enable_linkmon(struct rhine_private *rp)
 {
+       void __iomem *ioaddr = rp->base;
+
        iowrite8(0, ioaddr + MIICmd);
        iowrite8(MII_BMSR, ioaddr + MIIRegAddr);
        iowrite8(0x80, ioaddr + MIICmd);
 
-       RHINE_WAIT_FOR((ioread8(ioaddr + MIIRegAddr) & 0x20));
+       rhine_wait_bit_high(rp, MIIRegAddr, 0x20);
 
        iowrite8(MII_BMSR | 0x40, ioaddr + MIIRegAddr);
 }
 
 /* Disable MII link status auto-polling (required for MDIO access) */
-static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks)
+static void rhine_disable_linkmon(struct rhine_private *rp)
 {
+       void __iomem *ioaddr = rp->base;
+
        iowrite8(0, ioaddr + MIICmd);
 
-       if (quirks & rqRhineI) {
+       if (rp->quirks & rqRhineI) {
                iowrite8(0x01, ioaddr + MIIRegAddr);    // MII_BMSR
 
                /* Can be called from ISR. Evil. */
@@ -1348,13 +1492,13 @@ static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks)
                /* 0x80 must be set immediately before turning it off */
                iowrite8(0x80, ioaddr + MIICmd);
 
-               RHINE_WAIT_FOR(ioread8(ioaddr + MIIRegAddr) & 0x20);
+               rhine_wait_bit_high(rp, MIIRegAddr, 0x20);
 
                /* Heh. Now clear 0x80 again. */
                iowrite8(0, ioaddr + MIICmd);
        }
        else
-               RHINE_WAIT_FOR(ioread8(ioaddr + MIIRegAddr) & 0x80);
+               rhine_wait_bit_high(rp, MIIRegAddr, 0x80);
 }
 
 /* Read and write over the MII Management Data I/O (MDIO) interface. */
@@ -1365,16 +1509,16 @@ static int mdio_read(struct net_device *dev, int phy_id, int regnum)
        void __iomem *ioaddr = rp->base;
        int result;
 
-       rhine_disable_linkmon(ioaddr, rp->quirks);
+       rhine_disable_linkmon(rp);
 
        /* rhine_disable_linkmon already cleared MIICmd */
        iowrite8(phy_id, ioaddr + MIIPhyAddr);
        iowrite8(regnum, ioaddr + MIIRegAddr);
        iowrite8(0x40, ioaddr + MIICmd);                /* Trigger read */
-       RHINE_WAIT_FOR(!(ioread8(ioaddr + MIICmd) & 0x40));
+       rhine_wait_bit_low(rp, MIICmd, 0x40);
        result = ioread16(ioaddr + MIIData);
 
-       rhine_enable_linkmon(ioaddr);
+       rhine_enable_linkmon(rp);
        return result;
 }
 
@@ -1383,16 +1527,33 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
 
-       rhine_disable_linkmon(ioaddr, rp->quirks);
+       rhine_disable_linkmon(rp);
 
        /* rhine_disable_linkmon already cleared MIICmd */
        iowrite8(phy_id, ioaddr + MIIPhyAddr);
        iowrite8(regnum, ioaddr + MIIRegAddr);
        iowrite16(value, ioaddr + MIIData);
        iowrite8(0x20, ioaddr + MIICmd);                /* Trigger write */
-       RHINE_WAIT_FOR(!(ioread8(ioaddr + MIICmd) & 0x20));
+       rhine_wait_bit_low(rp, MIICmd, 0x20);
 
-       rhine_enable_linkmon(ioaddr);
+       rhine_enable_linkmon(rp);
+}
+
+static void rhine_task_disable(struct rhine_private *rp)
+{
+       mutex_lock(&rp->task_lock);
+       rp->task_enable = false;
+       mutex_unlock(&rp->task_lock);
+
+       cancel_work_sync(&rp->slow_event_task);
+       cancel_work_sync(&rp->reset_task);
+}
+
+static void rhine_task_enable(struct rhine_private *rp)
+{
+       mutex_lock(&rp->task_lock);
+       rp->task_enable = true;
+       mutex_unlock(&rp->task_lock);
 }
 
 static int rhine_open(struct net_device *dev)
@@ -1406,8 +1567,7 @@ static int rhine_open(struct net_device *dev)
        if (rc)
                return rc;
 
-       if (debug > 1)
-               netdev_dbg(dev, "%s() irq %d\n", __func__, rp->pdev->irq);
+       netif_dbg(rp, ifup, dev, "%s() irq %d\n", __func__, rp->pdev->irq);
 
        rc = alloc_ring(dev);
        if (rc) {
@@ -1417,11 +1577,12 @@ static int rhine_open(struct net_device *dev)
        alloc_rbufs(dev);
        alloc_tbufs(dev);
        rhine_chip_reset(dev);
+       rhine_task_enable(rp);
        init_registers(dev);
-       if (debug > 2)
-               netdev_dbg(dev, "%s() Done - status %04x MII status: %04x\n",
-                          __func__, ioread16(ioaddr + ChipCmd),
-                          mdio_read(dev, rp->mii_if.phy_id, MII_BMSR));
+
+       netif_dbg(rp, ifup, dev, "%s() Done - status %04x MII status: %04x\n",
+                 __func__, ioread16(ioaddr + ChipCmd),
+                 mdio_read(dev, rp->mii_if.phy_id, MII_BMSR));
 
        netif_start_queue(dev);
 
@@ -1434,11 +1595,12 @@ static void rhine_reset_task(struct work_struct *work)
                                                reset_task);
        struct net_device *dev = rp->dev;
 
-       /* protect against concurrent rx interrupts */
-       disable_irq(rp->pdev->irq);
+       mutex_lock(&rp->task_lock);
 
-       napi_disable(&rp->napi);
+       if (!rp->task_enable)
+               goto out_unlock;
 
+       napi_disable(&rp->napi);
        spin_lock_bh(&rp->lock);
 
        /* clear all descriptors */
@@ -1452,11 +1614,13 @@ static void rhine_reset_task(struct work_struct *work)
        init_registers(dev);
 
        spin_unlock_bh(&rp->lock);
-       enable_irq(rp->pdev->irq);
 
        dev->trans_start = jiffies; /* prevent tx timeout */
        dev->stats.tx_errors++;
        netif_wake_queue(dev);
+
+out_unlock:
+       mutex_unlock(&rp->task_lock);
 }
 
 static void rhine_tx_timeout(struct net_device *dev)
@@ -1477,7 +1641,6 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
        unsigned entry;
-       unsigned long flags;
 
        /* Caution: the write order is important here, set the field
           with the "ownership" bits last. */
@@ -1529,7 +1692,6 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
                rp->tx_ring[entry].tx_status = 0;
 
        /* lock eth irq */
-       spin_lock_irqsave(&rp->lock, flags);
        wmb();
        rp->tx_ring[entry].tx_status |= cpu_to_le32(DescOwn);
        wmb();
@@ -1550,78 +1712,43 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
        if (rp->cur_tx == rp->dirty_tx + TX_QUEUE_LEN)
                netif_stop_queue(dev);
 
-       spin_unlock_irqrestore(&rp->lock, flags);
+       netif_dbg(rp, tx_queued, dev, "Transmit frame #%d queued in slot %d\n",
+                 rp->cur_tx - 1, entry);
 
-       if (debug > 4) {
-               netdev_dbg(dev, "Transmit frame #%d queued in slot %d\n",
-                          rp->cur_tx-1, entry);
-       }
        return NETDEV_TX_OK;
 }
 
+static void rhine_irq_disable(struct rhine_private *rp)
+{
+       iowrite16(0x0000, rp->base + IntrEnable);
+       mmiowb();
+}
+
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
 static irqreturn_t rhine_interrupt(int irq, void *dev_instance)
 {
        struct net_device *dev = dev_instance;
        struct rhine_private *rp = netdev_priv(dev);
-       void __iomem *ioaddr = rp->base;
-       u32 intr_status;
-       int boguscnt = max_interrupt_work;
+       u32 status;
        int handled = 0;
 
-       while ((intr_status = get_intr_status(dev))) {
-               handled = 1;
-
-               /* Acknowledge all of the current interrupt sources ASAP. */
-               if (intr_status & IntrTxDescRace)
-                       iowrite8(0x08, ioaddr + IntrStatus2);
-               iowrite16(intr_status & 0xffff, ioaddr + IntrStatus);
-               IOSYNC;
+       status = rhine_get_events(rp);
 
-               if (debug > 4)
-                       netdev_dbg(dev, "Interrupt, status %08x\n",
-                                  intr_status);
-
-               if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped |
-                                  IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) {
-                       iowrite16(IntrTxAborted |
-                                 IntrTxDone | IntrTxError | IntrTxUnderrun |
-                                 IntrPCIErr | IntrStatsMax | IntrLinkChange,
-                                 ioaddr + IntrEnable);
-
-                       napi_schedule(&rp->napi);
-               }
+       netif_dbg(rp, intr, dev, "Interrupt, status %08x\n", status);
 
-               if (intr_status & (IntrTxErrSummary | IntrTxDone)) {
-                       if (intr_status & IntrTxErrSummary) {
-                               /* Avoid scavenging before Tx engine turned off */
-                               RHINE_WAIT_FOR(!(ioread8(ioaddr+ChipCmd) & CmdTxOn));
-                               if (debug > 2 &&
-                                   ioread8(ioaddr+ChipCmd) & CmdTxOn)
-                                       netdev_warn(dev,
-                                                   "%s: Tx engine still on\n",
-                                                   __func__);
-                       }
-                       rhine_tx(dev);
-               }
+       if (status & RHINE_EVENT) {
+               handled = 1;
 
-               /* Abnormal error summary/uncommon events handlers. */
-               if (intr_status & (IntrPCIErr | IntrLinkChange |
-                                  IntrStatsMax | IntrTxError | IntrTxAborted |
-                                  IntrTxUnderrun | IntrTxDescRace))
-                       rhine_error(dev, intr_status);
+               rhine_irq_disable(rp);
+               napi_schedule(&rp->napi);
+       }
 
-               if (--boguscnt < 0) {
-                       netdev_warn(dev, "Too much work at interrupt, status=%#08x\n",
-                                   intr_status);
-                       break;
-               }
+       if (status & ~(IntrLinkChange | IntrStatsMax | RHINE_EVENT_NAPI)) {
+               netif_err(rp, intr, dev, "Something Wicked happened! %08x\n",
+                         status);
        }
 
-       if (debug > 3)
-               netdev_dbg(dev, "exiting interrupt, status=%08x\n",
-                          ioread16(ioaddr + IntrStatus));
        return IRQ_RETVAL(handled);
 }
 
@@ -1632,20 +1759,16 @@ static void rhine_tx(struct net_device *dev)
        struct rhine_private *rp = netdev_priv(dev);
        int txstatus = 0, entry = rp->dirty_tx % TX_RING_SIZE;
 
-       spin_lock(&rp->lock);
-
        /* find and cleanup dirty tx descriptors */
        while (rp->dirty_tx != rp->cur_tx) {
                txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
-               if (debug > 6)
-                       netdev_dbg(dev, "Tx scavenge %d status %08x\n",
-                                  entry, txstatus);
+               netif_dbg(rp, tx_done, dev, "Tx scavenge %d status %08x\n",
+                         entry, txstatus);
                if (txstatus & DescOwn)
                        break;
                if (txstatus & 0x8000) {
-                       if (debug > 1)
-                               netdev_dbg(dev, "Transmit error, Tx status %08x\n",
-                                          txstatus);
+                       netif_dbg(rp, tx_done, dev,
+                                 "Transmit error, Tx status %08x\n", txstatus);
                        dev->stats.tx_errors++;
                        if (txstatus & 0x0400)
                                dev->stats.tx_carrier_errors++;
@@ -1667,10 +1790,8 @@ static void rhine_tx(struct net_device *dev)
                                dev->stats.collisions += (txstatus >> 3) & 0x0F;
                        else
                                dev->stats.collisions += txstatus & 0x0F;
-                       if (debug > 6)
-                               netdev_dbg(dev, "collisions: %1.1x:%1.1x\n",
-                                          (txstatus >> 3) & 0xF,
-                                          txstatus & 0xF);
+                       netif_dbg(rp, tx_done, dev, "collisions: %1.1x:%1.1x\n",
+                                 (txstatus >> 3) & 0xF, txstatus & 0xF);
                        dev->stats.tx_bytes += rp->tx_skbuff[entry]->len;
                        dev->stats.tx_packets++;
                }
@@ -1687,8 +1808,6 @@ static void rhine_tx(struct net_device *dev)
        }
        if ((rp->cur_tx - rp->dirty_tx) < TX_QUEUE_LEN - 4)
                netif_wake_queue(dev);
-
-       spin_unlock(&rp->lock);
 }
 
 /**
@@ -1713,11 +1832,8 @@ static int rhine_rx(struct net_device *dev, int limit)
        int count;
        int entry = rp->cur_rx % RX_RING_SIZE;
 
-       if (debug > 4) {
-               netdev_dbg(dev, "%s(), entry %d status %08x\n",
-                          __func__, entry,
-                          le32_to_cpu(rp->rx_head_desc->rx_status));
-       }
+       netif_dbg(rp, rx_status, dev, "%s(), entry %d status %08x\n", __func__,
+                 entry, le32_to_cpu(rp->rx_head_desc->rx_status));
 
        /* If EOP is set on the next entry, it's a new packet. Send it up. */
        for (count = 0; count < limit; ++count) {
@@ -1729,9 +1845,8 @@ static int rhine_rx(struct net_device *dev, int limit)
                if (desc_status & DescOwn)
                        break;
 
-               if (debug > 4)
-                       netdev_dbg(dev, "%s() status is %08x\n",
-                                  __func__, desc_status);
+               netif_dbg(rp, rx_status, dev, "%s() status %08x\n", __func__,
+                         desc_status);
 
                if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) {
                        if ((desc_status & RxWholePkt) != RxWholePkt) {
@@ -1747,9 +1862,9 @@ static int rhine_rx(struct net_device *dev, int limit)
                                dev->stats.rx_length_errors++;
                        } else if (desc_status & RxErr) {
                                /* There was a error. */
-                               if (debug > 2)
-                                       netdev_dbg(dev, "%s() Rx error was %08x\n",
-                                                  __func__, desc_status);
+                               netif_dbg(rp, rx_err, dev,
+                                         "%s() Rx error %08x\n", __func__,
+                                         desc_status);
                                dev->stats.rx_errors++;
                                if (desc_status & 0x0030)
                                        dev->stats.rx_length_errors++;
@@ -1839,19 +1954,6 @@ static int rhine_rx(struct net_device *dev, int limit)
        return count;
 }
 
-/*
- * Clears the "tally counters" for CRC errors and missed frames(?).
- * It has been reported that some chips need a write of 0 to clear
- * these, for others the counters are set to 1 when written to and
- * instead cleared when read. So we clear them both ways ...
- */
-static inline void clear_tally_counters(void __iomem *ioaddr)
-{
-       iowrite32(0, ioaddr + RxMissed);
-       ioread16(ioaddr + RxCRCErrs);
-       ioread16(ioaddr + RxMissed);
-}
-
 static void rhine_restart_tx(struct net_device *dev) {
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
@@ -1862,7 +1964,7 @@ static void rhine_restart_tx(struct net_device *dev) {
         * If new errors occurred, we need to sort them out before doing Tx.
         * In that case the ISR will be back here RSN anyway.
         */
-       intr_status = get_intr_status(dev);
+       intr_status = rhine_get_events(rp);
 
        if ((intr_status & IntrTxErrSummary) == 0) {
 
@@ -1883,79 +1985,50 @@ static void rhine_restart_tx(struct net_device *dev) {
        }
        else {
                /* This should never happen */
-               if (debug > 1)
-                       netdev_warn(dev, "%s() Another error occurred %08x\n",
-                                  __func__, intr_status);
+               netif_warn(rp, tx_err, dev, "another error occurred %08x\n",
+                          intr_status);
        }
 
 }
 
-static void rhine_error(struct net_device *dev, int intr_status)
+static void rhine_slow_event_task(struct work_struct *work)
 {
-       struct rhine_private *rp = netdev_priv(dev);
-       void __iomem *ioaddr = rp->base;
+       struct rhine_private *rp =
+               container_of(work, struct rhine_private, slow_event_task);
+       struct net_device *dev = rp->dev;
+       u32 intr_status;
 
-       spin_lock(&rp->lock);
+       mutex_lock(&rp->task_lock);
+
+       if (!rp->task_enable)
+               goto out_unlock;
+
+       intr_status = rhine_get_events(rp);
+       rhine_ack_events(rp, intr_status & RHINE_EVENT_SLOW);
 
        if (intr_status & IntrLinkChange)
                rhine_check_media(dev, 0);
-       if (intr_status & IntrStatsMax) {
-               dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
-               dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
-               clear_tally_counters(ioaddr);
-       }
-       if (intr_status & IntrTxAborted) {
-               if (debug > 1)
-                       netdev_info(dev, "Abort %08x, frame dropped\n",
-                                   intr_status);
-       }
-       if (intr_status & IntrTxUnderrun) {
-               if (rp->tx_thresh < 0xE0)
-                       BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig);
-               if (debug > 1)
-                       netdev_info(dev, "Transmitter underrun, Tx threshold now %02x\n",
-                                   rp->tx_thresh);
-       }
-       if (intr_status & IntrTxDescRace) {
-               if (debug > 2)
-                       netdev_info(dev, "Tx descriptor write-back race\n");
-       }
-       if ((intr_status & IntrTxError) &&
-           (intr_status & (IntrTxAborted |
-            IntrTxUnderrun | IntrTxDescRace)) == 0) {
-               if (rp->tx_thresh < 0xE0) {
-                       BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig);
-               }
-               if (debug > 1)
-                       netdev_info(dev, "Unspecified error. Tx threshold now %02x\n",
-                                   rp->tx_thresh);
-       }
-       if (intr_status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace |
-                          IntrTxError))
-               rhine_restart_tx(dev);
-
-       if (intr_status & ~(IntrLinkChange | IntrStatsMax | IntrTxUnderrun |
-                           IntrTxError | IntrTxAborted | IntrNormalSummary |
-                           IntrTxDescRace)) {
-               if (debug > 1)
-                       netdev_err(dev, "Something Wicked happened! %08x\n",
-                                  intr_status);
-       }
 
-       spin_unlock(&rp->lock);
+       if (intr_status & IntrPCIErr)
+               netif_warn(rp, hw, dev, "PCI error\n");
+
+       napi_disable(&rp->napi);
+       rhine_irq_disable(rp);
+       /* Slow and safe. Consider __napi_schedule as a replacement ? */
+       napi_enable(&rp->napi);
+       napi_schedule(&rp->napi);
+
+out_unlock:
+       mutex_unlock(&rp->task_lock);
 }
 
 static struct net_device_stats *rhine_get_stats(struct net_device *dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
-       void __iomem *ioaddr = rp->base;
-       unsigned long flags;
 
-       spin_lock_irqsave(&rp->lock, flags);
-       dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
-       dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
-       clear_tally_counters(ioaddr);
-       spin_unlock_irqrestore(&rp->lock, flags);
+       spin_lock_bh(&rp->lock);
+       rhine_update_rx_crc_and_missed_errord(rp);
+       spin_unlock_bh(&rp->lock);
 
        return &dev->stats;
 }
@@ -2022,9 +2095,9 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        struct rhine_private *rp = netdev_priv(dev);
        int rc;
 
-       spin_lock_irq(&rp->lock);
+       mutex_lock(&rp->task_lock);
        rc = mii_ethtool_gset(&rp->mii_if, cmd);
-       spin_unlock_irq(&rp->lock);
+       mutex_unlock(&rp->task_lock);
 
        return rc;
 }
@@ -2034,10 +2107,10 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        struct rhine_private *rp = netdev_priv(dev);
        int rc;
 
-       spin_lock_irq(&rp->lock);
+       mutex_lock(&rp->task_lock);
        rc = mii_ethtool_sset(&rp->mii_if, cmd);
-       spin_unlock_irq(&rp->lock);
        rhine_set_carrier(&rp->mii_if);
+       mutex_unlock(&rp->task_lock);
 
        return rc;
 }
@@ -2058,12 +2131,16 @@ static u32 netdev_get_link(struct net_device *dev)
 
 static u32 netdev_get_msglevel(struct net_device *dev)
 {
-       return debug;
+       struct rhine_private *rp = netdev_priv(dev);
+
+       return rp->msg_enable;
 }
 
 static void netdev_set_msglevel(struct net_device *dev, u32 value)
 {
-       debug = value;
+       struct rhine_private *rp = netdev_priv(dev);
+
+       rp->msg_enable = value;
 }
 
 static void rhine_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -2119,10 +2196,10 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        if (!netif_running(dev))
                return -EINVAL;
 
-       spin_lock_irq(&rp->lock);
+       mutex_lock(&rp->task_lock);
        rc = generic_mii_ioctl(&rp->mii_if, if_mii(rq), cmd, NULL);
-       spin_unlock_irq(&rp->lock);
        rhine_set_carrier(&rp->mii_if);
+       mutex_unlock(&rp->task_lock);
 
        return rc;
 }
@@ -2132,27 +2209,21 @@ static int rhine_close(struct net_device *dev)
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
 
+       rhine_task_disable(rp);
        napi_disable(&rp->napi);
-       cancel_work_sync(&rp->reset_task);
        netif_stop_queue(dev);
 
-       spin_lock_irq(&rp->lock);
-
-       if (debug > 1)
-               netdev_dbg(dev, "Shutting down ethercard, status was %04x\n",
-                          ioread16(ioaddr + ChipCmd));
+       netif_dbg(rp, ifdown, dev, "Shutting down ethercard, status was %04x\n",
+                 ioread16(ioaddr + ChipCmd));
 
        /* Switch to loopback mode to avoid hardware races. */
        iowrite8(rp->tx_thresh | 0x02, ioaddr + TxConfig);
 
-       /* Disable interrupts by clearing the interrupt mask. */
-       iowrite16(0x0000, ioaddr + IntrEnable);
+       rhine_irq_disable(rp);
 
        /* Stop the chip's Tx and Rx processes. */
        iowrite16(CmdStop, ioaddr + ChipCmd);
 
-       spin_unlock_irq(&rp->lock);
-
        free_irq(rp->pdev->irq, dev);
        free_rbufs(dev);
        free_tbufs(dev);
@@ -2192,6 +2263,8 @@ static void rhine_shutdown (struct pci_dev *pdev)
        if (rp->quirks & rq6patterns)
                iowrite8(0x04, ioaddr + WOLcgClr);
 
+       spin_lock(&rp->lock);
+
        if (rp->wolopts & WAKE_MAGIC) {
                iowrite8(WOLmagic, ioaddr + WOLcrSet);
                /*
@@ -2216,58 +2289,46 @@ static void rhine_shutdown (struct pci_dev *pdev)
                iowrite8(ioread8(ioaddr + StickyHW) | 0x04, ioaddr + StickyHW);
        }
 
-       /* Hit power state D3 (sleep) */
-       if (!avoid_D3)
-               iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW);
+       spin_unlock(&rp->lock);
 
-       /* TODO: Check use of pci_enable_wake() */
+       if (system_state == SYSTEM_POWER_OFF && !avoid_D3) {
+               iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW);
 
+               pci_wake_from_d3(pdev, true);
+               pci_set_power_state(pdev, PCI_D3hot);
+       }
 }
 
-#ifdef CONFIG_PM
-static int rhine_suspend(struct pci_dev *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int rhine_suspend(struct device *device)
 {
+       struct pci_dev *pdev = to_pci_dev(device);
        struct net_device *dev = pci_get_drvdata(pdev);
        struct rhine_private *rp = netdev_priv(dev);
-       unsigned long flags;
 
        if (!netif_running(dev))
                return 0;
 
+       rhine_task_disable(rp);
+       rhine_irq_disable(rp);
        napi_disable(&rp->napi);
 
        netif_device_detach(dev);
-       pci_save_state(pdev);
 
-       spin_lock_irqsave(&rp->lock, flags);
        rhine_shutdown(pdev);
-       spin_unlock_irqrestore(&rp->lock, flags);
 
-       free_irq(dev->irq, dev);
        return 0;
 }
 
-static int rhine_resume(struct pci_dev *pdev)
+static int rhine_resume(struct device *device)
 {
+       struct pci_dev *pdev = to_pci_dev(device);
        struct net_device *dev = pci_get_drvdata(pdev);
        struct rhine_private *rp = netdev_priv(dev);
-       unsigned long flags;
-       int ret;
 
        if (!netif_running(dev))
                return 0;
 
-       if (request_irq(dev->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev))
-               netdev_err(dev, "request_irq failed\n");
-
-       ret = pci_set_power_state(pdev, PCI_D0);
-       if (debug > 1)
-               netdev_info(dev, "Entering power state D0 %s (%d)\n",
-                           ret ? "failed" : "succeeded", ret);
-
-       pci_restore_state(pdev);
-
-       spin_lock_irqsave(&rp->lock, flags);
 #ifdef USE_MMIO
        enable_mmio(rp->pioaddr, rp->quirks);
 #endif
@@ -2276,25 +2337,32 @@ static int rhine_resume(struct pci_dev *pdev)
        free_rbufs(dev);
        alloc_tbufs(dev);
        alloc_rbufs(dev);
+       rhine_task_enable(rp);
+       spin_lock_bh(&rp->lock);
        init_registers(dev);
-       spin_unlock_irqrestore(&rp->lock, flags);
+       spin_unlock_bh(&rp->lock);
 
        netif_device_attach(dev);
 
        return 0;
 }
-#endif /* CONFIG_PM */
+
+static SIMPLE_DEV_PM_OPS(rhine_pm_ops, rhine_suspend, rhine_resume);
+#define RHINE_PM_OPS   (&rhine_pm_ops)
+
+#else
+
+#define RHINE_PM_OPS   NULL
+
+#endif /* !CONFIG_PM_SLEEP */
 
 static struct pci_driver rhine_driver = {
        .name           = DRV_NAME,
        .id_table       = rhine_pci_tbl,
        .probe          = rhine_init_one,
        .remove         = __devexit_p(rhine_remove_one),
-#ifdef CONFIG_PM
-       .suspend        = rhine_suspend,
-       .resume         = rhine_resume,
-#endif /* CONFIG_PM */
-       .shutdown =     rhine_shutdown,
+       .shutdown       = rhine_shutdown,
+       .driver.pm      = RHINE_PM_OPS,
 };
 
 static struct dmi_system_id __initdata rhine_dmi_table[] = {
index f45c85a8426125be667c80cd4e8408bb58fc7337..72a854f05bb8042cf8392c518377652e8af62daf 100644 (file)
@@ -529,7 +529,7 @@ static int ixp4xx_mdio_register(void)
        mdio_bus->name = "IXP4xx MII Bus";
        mdio_bus->read = &ixp4xx_mdio_read;
        mdio_bus->write = &ixp4xx_mdio_write;
-       strcpy(mdio_bus->id, "0");
+       snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "ixp4xx-eth-0");
 
        if ((err = mdiobus_register(mdio_bus)))
                mdiobus_free(mdio_bus);
index d423d18b4ad6a96574a39595632d4ea5b69179fb..e535137eb2d0fff40f1877bbcbcef94730e4dd12 100644 (file)
@@ -313,8 +313,12 @@ config TOSHIBA_FIR
          donauboe.
 
 config AU1000_FIR
-       tristate "Alchemy Au1000 SIR/FIR"
+       tristate "Alchemy IrDA SIR/FIR"
        depends on IRDA && MIPS_ALCHEMY
+       help
+         Say Y/M here to build suppor the the IrDA peripheral on the
+         Alchemy Au1000 and Au1100 SoCs.
+         Say M to build a module; it will be called au1k_ir.ko
 
 config SMC_IRCC_FIR
        tristate "SMSC IrCC (EXPERIMENTAL)"
diff --git a/drivers/net/irda/au1000_ircc.h b/drivers/net/irda/au1000_ircc.h
deleted file mode 100644 (file)
index c072c09..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- *     Au1000 IrDA driver.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *             ppopov@mvista.com or source@mvista.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  SOFTWARE  IS PROVIDED   ``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   THE AUTHOR  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.
- *
- *  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 AU1000_IRCC_H
-#define AU1000_IRCC_H
-
-#include <linux/time.h>
-
-#include <linux/spinlock.h>
-#include <linux/pm.h>
-#include <asm/io.h>
-
-#define NUM_IR_IFF          1
-#define NUM_IR_DESC        64
-#define RING_SIZE_4       0x0
-#define RING_SIZE_16      0x3
-#define RING_SIZE_64      0xF
-#define MAX_NUM_IR_DESC    64
-#define MAX_BUF_SIZE     2048
-
-#define BPS_115200          0
-#define BPS_57600           1
-#define BPS_38400           2
-#define BPS_19200           5
-#define BPS_9600           11
-#define BPS_2400           47
-
-/* Ring descriptor flags */
-#define AU_OWN           (1<<7) /* tx,rx */
-
-#define IR_DIS_CRC       (1<<6) /* tx */
-#define IR_BAD_CRC       (1<<5) /* tx */
-#define IR_NEED_PULSE    (1<<4) /* tx */
-#define IR_FORCE_UNDER   (1<<3) /* tx */
-#define IR_DISABLE_TX    (1<<2) /* tx */
-#define IR_HW_UNDER      (1<<0) /* tx */
-#define IR_TX_ERROR      (IR_DIS_CRC|IR_BAD_CRC|IR_HW_UNDER)
-
-#define IR_PHY_ERROR     (1<<6) /* rx */
-#define IR_CRC_ERROR     (1<<5) /* rx */
-#define IR_MAX_LEN       (1<<4) /* rx */
-#define IR_FIFO_OVER     (1<<3) /* rx */
-#define IR_SIR_ERROR     (1<<2) /* rx */
-#define IR_RX_ERROR      (IR_PHY_ERROR|IR_CRC_ERROR| \
-               IR_MAX_LEN|IR_FIFO_OVER|IR_SIR_ERROR)
-
-typedef struct db_dest {
-       struct db_dest *pnext;
-       volatile u32 *vaddr;
-       dma_addr_t dma_addr;
-} db_dest_t;
-
-
-typedef struct ring_desc {
-       u8 count_0;               /* 7:0  */
-       u8 count_1;               /* 12:8 */
-       u8 reserved;
-       u8 flags;
-       u8 addr_0;                /* 7:0   */
-       u8 addr_1;                /* 15:8  */
-       u8 addr_2;                /* 23:16 */
-       u8 addr_3;                /* 31:24 */
-} ring_dest_t;
-
-
-/* Private data for each instance */
-struct au1k_private {
-
-       db_dest_t *pDBfree;
-       db_dest_t db[2*NUM_IR_DESC];
-       volatile ring_dest_t *rx_ring[NUM_IR_DESC];
-       volatile ring_dest_t *tx_ring[NUM_IR_DESC];
-       db_dest_t *rx_db_inuse[NUM_IR_DESC];
-       db_dest_t *tx_db_inuse[NUM_IR_DESC];
-       u32 rx_head;
-       u32 tx_head;
-       u32 tx_tail;
-       u32 tx_full;
-
-       iobuff_t rx_buff;
-
-       struct net_device *netdev;
-       
-       struct timeval stamp;
-       struct timeval now;
-       struct qos_info         qos;
-       struct irlap_cb         *irlap;
-       
-       u8 open;
-       u32 speed;
-       u32 newspeed;
-       
-       u32 intr_work_done; /* number of Rx and Tx pkts processed in the isr */
-       struct timer_list timer;
-
-       spinlock_t lock;           /* For serializing operations */
-};
-#endif /* AU1000_IRCC_H */
index a3d696a9456a10a9d4f659cc70ad1982f2a7e58d..fc503aa5288e3f164843f754c6977abf4345705c 100644 (file)
  *  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/types.h>
+
 #include <linux/init.h>
-#include <linux/errno.h>
+#include <linux/module.h>
 #include <linux/netdevice.h>
-#include <linux/slab.h>
-#include <linux/rtnetlink.h>
 #include <linux/interrupt.h>
-#include <linux/pm.h>
-#include <linux/bitops.h>
-
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/au1000.h>
-#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100)
-#include <asm/pb1000.h>
-#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
-#include <asm/db1x00.h>
-#include <asm/mach-db1x00/bcsr.h>
-#else 
-#error au1k_ir: unsupported board
-#endif
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/types.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
 #include <net/irda/wrapper.h>
 #include <net/irda/irda_device.h>
-#include "au1000_ircc.h"
+#include <asm/mach-au1x00/au1000.h>
+
+/* registers */
+#define IR_RING_PTR_STATUS     0x00
+#define IR_RING_BASE_ADDR_H    0x04
+#define IR_RING_BASE_ADDR_L    0x08
+#define IR_RING_SIZE           0x0C
+#define IR_RING_PROMPT         0x10
+#define IR_RING_ADDR_CMPR      0x14
+#define IR_INT_CLEAR           0x18
+#define IR_CONFIG_1            0x20
+#define IR_SIR_FLAGS           0x24
+#define IR_STATUS              0x28
+#define IR_READ_PHY_CONFIG     0x2C
+#define IR_WRITE_PHY_CONFIG    0x30
+#define IR_MAX_PKT_LEN         0x34
+#define IR_RX_BYTE_CNT         0x38
+#define IR_CONFIG_2            0x3C
+#define IR_ENABLE              0x40
+
+/* Config1 */
+#define IR_RX_INVERT_LED       (1 << 0)
+#define IR_TX_INVERT_LED       (1 << 1)
+#define IR_ST                  (1 << 2)
+#define IR_SF                  (1 << 3)
+#define IR_SIR                 (1 << 4)
+#define IR_MIR                 (1 << 5)
+#define IR_FIR                 (1 << 6)
+#define IR_16CRC               (1 << 7)
+#define IR_TD                  (1 << 8)
+#define IR_RX_ALL              (1 << 9)
+#define IR_DMA_ENABLE          (1 << 10)
+#define IR_RX_ENABLE           (1 << 11)
+#define IR_TX_ENABLE           (1 << 12)
+#define IR_LOOPBACK            (1 << 14)
+#define IR_SIR_MODE            (IR_SIR | IR_DMA_ENABLE | \
+                                IR_RX_ALL | IR_RX_ENABLE | IR_SF | \
+                                IR_16CRC)
+
+/* ir_status */
+#define IR_RX_STATUS           (1 << 9)
+#define IR_TX_STATUS           (1 << 10)
+#define IR_PHYEN               (1 << 15)
+
+/* ir_write_phy_config */
+#define IR_BR(x)               (((x) & 0x3f) << 10)    /* baud rate */
+#define IR_PW(x)               (((x) & 0x1f) << 5)     /* pulse width */
+#define IR_P(x)                        ((x) & 0x1f)            /* preamble bits */
+
+/* Config2 */
+#define IR_MODE_INV            (1 << 0)
+#define IR_ONE_PIN             (1 << 1)
+#define IR_PHYCLK_40MHZ                (0 << 2)
+#define IR_PHYCLK_48MHZ                (1 << 2)
+#define IR_PHYCLK_56MHZ                (2 << 2)
+#define IR_PHYCLK_64MHZ                (3 << 2)
+#define IR_DP                  (1 << 4)
+#define IR_DA                  (1 << 5)
+#define IR_FLT_HIGH            (0 << 6)
+#define IR_FLT_MEDHI           (1 << 6)
+#define IR_FLT_MEDLO           (2 << 6)
+#define IR_FLT_LO              (3 << 6)
+#define IR_IEN                 (1 << 8)
+
+/* ir_enable */
+#define IR_HC                  (1 << 3)        /* divide SBUS clock by 2 */
+#define IR_CE                  (1 << 2)        /* clock enable */
+#define IR_C                   (1 << 1)        /* coherency bit */
+#define IR_BE                  (1 << 0)        /* set in big endian mode */
+
+#define NUM_IR_DESC    64
+#define RING_SIZE_4    0x0
+#define RING_SIZE_16   0x3
+#define RING_SIZE_64   0xF
+#define MAX_NUM_IR_DESC        64
+#define MAX_BUF_SIZE   2048
+
+/* Ring descriptor flags */
+#define AU_OWN         (1 << 7) /* tx,rx */
+#define IR_DIS_CRC     (1 << 6) /* tx */
+#define IR_BAD_CRC     (1 << 5) /* tx */
+#define IR_NEED_PULSE  (1 << 4) /* tx */
+#define IR_FORCE_UNDER (1 << 3) /* tx */
+#define IR_DISABLE_TX  (1 << 2) /* tx */
+#define IR_HW_UNDER    (1 << 0) /* tx */
+#define IR_TX_ERROR    (IR_DIS_CRC | IR_BAD_CRC | IR_HW_UNDER)
+
+#define IR_PHY_ERROR   (1 << 6) /* rx */
+#define IR_CRC_ERROR   (1 << 5) /* rx */
+#define IR_MAX_LEN     (1 << 4) /* rx */
+#define IR_FIFO_OVER   (1 << 3) /* rx */
+#define IR_SIR_ERROR   (1 << 2) /* rx */
+#define IR_RX_ERROR    (IR_PHY_ERROR | IR_CRC_ERROR | \
+                        IR_MAX_LEN | IR_FIFO_OVER | IR_SIR_ERROR)
+
+struct db_dest {
+       struct db_dest *pnext;
+       volatile u32 *vaddr;
+       dma_addr_t dma_addr;
+};
+
+struct ring_dest {
+       u8 count_0;     /* 7:0  */
+       u8 count_1;     /* 12:8 */
+       u8 reserved;
+       u8 flags;
+       u8 addr_0;      /* 7:0   */
+       u8 addr_1;      /* 15:8  */
+       u8 addr_2;      /* 23:16 */
+       u8 addr_3;      /* 31:24 */
+};
+
+/* Private data for each instance */
+struct au1k_private {
+       void __iomem *iobase;
+       int irq_rx, irq_tx;
+
+       struct db_dest *pDBfree;
+       struct db_dest db[2 * NUM_IR_DESC];
+       volatile struct ring_dest *rx_ring[NUM_IR_DESC];
+       volatile struct ring_dest *tx_ring[NUM_IR_DESC];
+       struct db_dest *rx_db_inuse[NUM_IR_DESC];
+       struct db_dest *tx_db_inuse[NUM_IR_DESC];
+       u32 rx_head;
+       u32 tx_head;
+       u32 tx_tail;
+       u32 tx_full;
+
+       iobuff_t rx_buff;
+
+       struct net_device *netdev;
+       struct timeval stamp;
+       struct timeval now;
+       struct qos_info qos;
+       struct irlap_cb *irlap;
+
+       u8 open;
+       u32 speed;
+       u32 newspeed;
 
-static int au1k_irda_net_init(struct net_device *);
-static int au1k_irda_start(struct net_device *);
-static int au1k_irda_stop(struct net_device *dev);
-static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *);
-static int au1k_irda_rx(struct net_device *);
-static void au1k_irda_interrupt(int, void *);
-static void au1k_tx_timeout(struct net_device *);
-static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int);
-static int au1k_irda_set_speed(struct net_device *dev, int speed);
+       struct timer_list timer;
 
-static void *dma_alloc(size_t, dma_addr_t *);
-static void dma_free(void *, size_t);
+       struct resource *ioarea;
+       struct au1k_irda_platform_data *platdata;
+};
 
 static int qos_mtt_bits = 0x07;  /* 1 ms or more */
-static struct net_device *ir_devs[NUM_IR_IFF];
-static char version[] __devinitdata =
-    "au1k_ircc:1.2 ppopov@mvista.com\n";
 
 #define RUN_AT(x) (jiffies + (x))
 
-static DEFINE_SPINLOCK(ir_lock);
+static void au1k_irda_plat_set_phy_mode(struct au1k_private *p, int mode)
+{
+       if (p->platdata && p->platdata->set_phy_mode)
+               p->platdata->set_phy_mode(mode);
+}
 
-/*
- * IrDA peripheral bug. You have to read the register
- * twice to get the right value.
- */
-u32 read_ir_reg(u32 addr) 
-{ 
-       readl(addr);
-       return readl(addr);
+static inline unsigned long irda_read(struct au1k_private *p,
+                                     unsigned long ofs)
+{
+       /*
+       * IrDA peripheral bug. You have to read the register
+       * twice to get the right value.
+       */
+       (void)__raw_readl(p->iobase + ofs);
+       return __raw_readl(p->iobase + ofs);
 }
 
+static inline void irda_write(struct au1k_private *p, unsigned long ofs,
+                             unsigned long val)
+{
+       __raw_writel(val, p->iobase + ofs);
+       wmb();
+}
 
 /*
  * Buffer allocation/deallocation routines. The buffer descriptor returned
- * has the virtual and dma address of a buffer suitable for 
+ * has the virtual and dma address of a buffer suitable for
  * both, receive and transmit operations.
  */
-static db_dest_t *GetFreeDB(struct au1k_private *aup)
+static struct db_dest *GetFreeDB(struct au1k_private *aup)
 {
-       db_dest_t *pDB;
-       pDB = aup->pDBfree;
-
-       if (pDB) {
-               aup->pDBfree = pDB->pnext;
-       }
-       return pDB;
-}
+       struct db_dest *db;
+       db = aup->pDBfree;
 
-static void ReleaseDB(struct au1k_private *aup, db_dest_t *pDB)
-{
-       db_dest_t *pDBfree = aup->pDBfree;
-       if (pDBfree)
-               pDBfree->pnext = pDB;
-       aup->pDBfree = pDB;
+       if (db)
+               aup->pDBfree = db->pnext;
+       return db;
 }
 
-
 /*
   DMA memory allocation, derived from pci_alloc_consistent.
   However, the Au1000 data cache is coherent (when programmed
   so), therefore we return KSEG0 address, not KSEG1.
 */
-static void *dma_alloc(size_t size, dma_addr_t * dma_handle)
+static void *dma_alloc(size_t size, dma_addr_t *dma_handle)
 {
        void *ret;
        int gfp = GFP_ATOMIC | GFP_DMA;
 
-       ret = (void *) __get_free_pages(gfp, get_order(size));
+       ret = (void *)__get_free_pages(gfp, get_order(size));
 
        if (ret != NULL) {
                memset(ret, 0, size);
@@ -125,7 +241,6 @@ static void *dma_alloc(size_t size, dma_addr_t * dma_handle)
        return ret;
 }
 
-
 static void dma_free(void *vaddr, size_t size)
 {
        vaddr = (void *)KSEG0ADDR(vaddr);
@@ -133,206 +248,306 @@ static void dma_free(void *vaddr, size_t size)
 }
 
 
-static void 
-setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base)
+static void setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base)
 {
        int i;
-       for (i=0; i<NUM_IR_DESC; i++) {
-               aup->rx_ring[i] = (volatile ring_dest_t *) 
-                       (rx_base + sizeof(ring_dest_t)*i);
+       for (i = 0; i < NUM_IR_DESC; i++) {
+               aup->rx_ring[i] = (volatile struct ring_dest *)
+                       (rx_base + sizeof(struct ring_dest) * i);
        }
-       for (i=0; i<NUM_IR_DESC; i++) {
-               aup->tx_ring[i] = (volatile ring_dest_t *) 
-                       (tx_base + sizeof(ring_dest_t)*i);
+       for (i = 0; i < NUM_IR_DESC; i++) {
+               aup->tx_ring[i] = (volatile struct ring_dest *)
+                       (tx_base + sizeof(struct ring_dest) * i);
        }
 }
 
-static int au1k_irda_init(void)
-{
-       static unsigned version_printed = 0;
-       struct au1k_private *aup;
-       struct net_device *dev;
-       int err;
-
-       if (version_printed++ == 0) printk(version);
-
-       dev = alloc_irdadev(sizeof(struct au1k_private));
-       if (!dev)
-               return -ENOMEM;
-
-       dev->irq = AU1000_IRDA_RX_INT; /* TX has its own interrupt */
-       err = au1k_irda_net_init(dev);
-       if (err)
-               goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       ir_devs[0] = dev;
-       printk(KERN_INFO "IrDA: Registered device %s\n", dev->name);
-       return 0;
-
-out1:
-       aup = netdev_priv(dev);
-       dma_free((void *)aup->db[0].vaddr,
-               MAX_BUF_SIZE * 2*NUM_IR_DESC);
-       dma_free((void *)aup->rx_ring[0],
-               2 * MAX_NUM_IR_DESC*(sizeof(ring_dest_t)));
-       kfree(aup->rx_buff.head);
-out:
-       free_netdev(dev);
-       return err;
-}
-
 static int au1k_irda_init_iobuf(iobuff_t *io, int size)
 {
        io->head = kmalloc(size, GFP_KERNEL);
        if (io->head != NULL) {
-               io->truesize = size;
-               io->in_frame = FALSE;
-               io->state    = OUTSIDE_FRAME;
-               io->data     = io->head;
+               io->truesize    = size;
+               io->in_frame    = FALSE;
+               io->state       = OUTSIDE_FRAME;
+               io->data        = io->head;
        }
        return io->head ? 0 : -ENOMEM;
 }
 
-static const struct net_device_ops au1k_irda_netdev_ops = {
-       .ndo_open               = au1k_irda_start,
-       .ndo_stop               = au1k_irda_stop,
-       .ndo_start_xmit         = au1k_irda_hard_xmit,
-       .ndo_tx_timeout         = au1k_tx_timeout,
-       .ndo_do_ioctl           = au1k_irda_ioctl,
-};
-
-static int au1k_irda_net_init(struct net_device *dev)
+/*
+ * Set the IrDA communications speed.
+ */
+static int au1k_irda_set_speed(struct net_device *dev, int speed)
 {
        struct au1k_private *aup = netdev_priv(dev);
-       int i, retval = 0, err;
-       db_dest_t *pDB, *pDBfree;
-       dma_addr_t temp;
+       volatile struct ring_dest *ptxd;
+       unsigned long control;
+       int ret = 0, timeout = 10, i;
 
-       err = au1k_irda_init_iobuf(&aup->rx_buff, 14384);
-       if (err)
-               goto out1;
+       if (speed == aup->speed)
+               return ret;
 
-       dev->netdev_ops = &au1k_irda_netdev_ops;
+       /* disable PHY first */
+       au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF);
+       irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) & ~IR_PHYEN);
 
-       irda_init_max_qos_capabilies(&aup->qos);
+       /* disable RX/TX */
+       irda_write(aup, IR_CONFIG_1,
+           irda_read(aup, IR_CONFIG_1) & ~(IR_RX_ENABLE | IR_TX_ENABLE));
+       msleep(20);
+       while (irda_read(aup, IR_STATUS) & (IR_RX_STATUS | IR_TX_STATUS)) {
+               msleep(20);
+               if (!timeout--) {
+                       printk(KERN_ERR "%s: rx/tx disable timeout\n",
+                                       dev->name);
+                       break;
+               }
+       }
 
-       /* The only value we must override it the baudrate */
-       aup->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
-               IR_115200|IR_576000 |(IR_4000000 << 8);
-       
-       aup->qos.min_turn_time.bits = qos_mtt_bits;
-       irda_qos_bits_to_value(&aup->qos);
+       /* disable DMA */
+       irda_write(aup, IR_CONFIG_1,
+                  irda_read(aup, IR_CONFIG_1) & ~IR_DMA_ENABLE);
+       msleep(20);
 
-       retval = -ENOMEM;
+       /* After we disable tx/rx. the index pointers go back to zero. */
+       aup->tx_head = aup->tx_tail = aup->rx_head = 0;
+       for (i = 0; i < NUM_IR_DESC; i++) {
+               ptxd = aup->tx_ring[i];
+               ptxd->flags = 0;
+               ptxd->count_0 = 0;
+               ptxd->count_1 = 0;
+       }
 
-       /* Tx ring follows rx ring + 512 bytes */
-       /* we need a 1k aligned buffer */
-       aup->rx_ring[0] = (ring_dest_t *)
-               dma_alloc(2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t)), &temp);
-       if (!aup->rx_ring[0])
-               goto out2;
+       for (i = 0; i < NUM_IR_DESC; i++) {
+               ptxd = aup->rx_ring[i];
+               ptxd->count_0 = 0;
+               ptxd->count_1 = 0;
+               ptxd->flags = AU_OWN;
+       }
 
-       /* allocate the data buffers */
-       aup->db[0].vaddr = 
-               (void *)dma_alloc(MAX_BUF_SIZE * 2*NUM_IR_DESC, &temp);
-       if (!aup->db[0].vaddr)
-               goto out3;
+       if (speed == 4000000)
+               au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_FIR);
+       else
+               au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_SIR);
 
-       setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512);
+       switch (speed) {
+       case 9600:
+               irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(11) | IR_PW(12));
+               irda_write(aup, IR_CONFIG_1, IR_SIR_MODE);
+               break;
+       case 19200:
+               irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(5) | IR_PW(12));
+               irda_write(aup, IR_CONFIG_1, IR_SIR_MODE);
+               break;
+       case 38400:
+               irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(2) | IR_PW(12));
+               irda_write(aup, IR_CONFIG_1, IR_SIR_MODE);
+               break;
+       case 57600:
+               irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(1) | IR_PW(12));
+               irda_write(aup, IR_CONFIG_1, IR_SIR_MODE);
+               break;
+       case 115200:
+               irda_write(aup, IR_WRITE_PHY_CONFIG, IR_PW(12));
+               irda_write(aup, IR_CONFIG_1, IR_SIR_MODE);
+               break;
+       case 4000000:
+               irda_write(aup, IR_WRITE_PHY_CONFIG, IR_P(15));
+               irda_write(aup, IR_CONFIG_1, IR_FIR | IR_DMA_ENABLE |
+                               IR_RX_ENABLE);
+               break;
+       default:
+               printk(KERN_ERR "%s unsupported speed %x\n", dev->name, speed);
+               ret = -EINVAL;
+               break;
+       }
 
-       pDBfree = NULL;
-       pDB = aup->db;
-       for (i=0; i<(2*NUM_IR_DESC); i++) {
-               pDB->pnext = pDBfree;
-               pDBfree = pDB;
-               pDB->vaddr = 
-                       (u32 *)((unsigned)aup->db[0].vaddr + MAX_BUF_SIZE*i);
-               pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr);
-               pDB++;
+       aup->speed = speed;
+       irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) | IR_PHYEN);
+
+       control = irda_read(aup, IR_STATUS);
+       irda_write(aup, IR_RING_PROMPT, 0);
+
+       if (control & (1 << 14)) {
+               printk(KERN_ERR "%s: configuration error\n", dev->name);
+       } else {
+               if (control & (1 << 11))
+                       printk(KERN_DEBUG "%s Valid SIR config\n", dev->name);
+               if (control & (1 << 12))
+                       printk(KERN_DEBUG "%s Valid MIR config\n", dev->name);
+               if (control & (1 << 13))
+                       printk(KERN_DEBUG "%s Valid FIR config\n", dev->name);
+               if (control & (1 << 10))
+                       printk(KERN_DEBUG "%s TX enabled\n", dev->name);
+               if (control & (1 << 9))
+                       printk(KERN_DEBUG "%s RX enabled\n", dev->name);
        }
-       aup->pDBfree = pDBfree;
 
-       /* attach a data buffer to each descriptor */
-       for (i=0; i<NUM_IR_DESC; i++) {
-               pDB = GetFreeDB(aup);
-               if (!pDB) goto out;
-               aup->rx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff);
-               aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff);
-               aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff);
-               aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff);
-               aup->rx_db_inuse[i] = pDB;
+       return ret;
+}
+
+static void update_rx_stats(struct net_device *dev, u32 status, u32 count)
+{
+       struct net_device_stats *ps = &dev->stats;
+
+       ps->rx_packets++;
+
+       if (status & IR_RX_ERROR) {
+               ps->rx_errors++;
+               if (status & (IR_PHY_ERROR | IR_FIFO_OVER))
+                       ps->rx_missed_errors++;
+               if (status & IR_MAX_LEN)
+                       ps->rx_length_errors++;
+               if (status & IR_CRC_ERROR)
+                       ps->rx_crc_errors++;
+       } else
+               ps->rx_bytes += count;
+}
+
+static void update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len)
+{
+       struct net_device_stats *ps = &dev->stats;
+
+       ps->tx_packets++;
+       ps->tx_bytes += pkt_len;
+
+       if (status & IR_TX_ERROR) {
+               ps->tx_errors++;
+               ps->tx_aborted_errors++;
        }
-       for (i=0; i<NUM_IR_DESC; i++) {
-               pDB = GetFreeDB(aup);
-               if (!pDB) goto out;
-               aup->tx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff);
-               aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff);
-               aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff);
-               aup->tx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff);
-               aup->tx_ring[i]->count_0 = 0;
-               aup->tx_ring[i]->count_1 = 0;
-               aup->tx_ring[i]->flags = 0;
-               aup->tx_db_inuse[i] = pDB;
+}
+
+static void au1k_tx_ack(struct net_device *dev)
+{
+       struct au1k_private *aup = netdev_priv(dev);
+       volatile struct ring_dest *ptxd;
+
+       ptxd = aup->tx_ring[aup->tx_tail];
+       while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) {
+               update_tx_stats(dev, ptxd->flags,
+                               (ptxd->count_1 << 8) | ptxd->count_0);
+               ptxd->count_0 = 0;
+               ptxd->count_1 = 0;
+               wmb();
+               aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1);
+               ptxd = aup->tx_ring[aup->tx_tail];
+
+               if (aup->tx_full) {
+                       aup->tx_full = 0;
+                       netif_wake_queue(dev);
+               }
        }
 
-#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
-       /* power on */
-       bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK,
-                             BCSR_RESETS_IRDA_MODE_FULL);
-#endif
+       if (aup->tx_tail == aup->tx_head) {
+               if (aup->newspeed) {
+                       au1k_irda_set_speed(dev, aup->newspeed);
+                       aup->newspeed = 0;
+               } else {
+                       irda_write(aup, IR_CONFIG_1,
+                           irda_read(aup, IR_CONFIG_1) & ~IR_TX_ENABLE);
+                       irda_write(aup, IR_CONFIG_1,
+                           irda_read(aup, IR_CONFIG_1) | IR_RX_ENABLE);
+                       irda_write(aup, IR_RING_PROMPT, 0);
+               }
+       }
+}
 
-       return 0;
+static int au1k_irda_rx(struct net_device *dev)
+{
+       struct au1k_private *aup = netdev_priv(dev);
+       volatile struct ring_dest *prxd;
+       struct sk_buff *skb;
+       struct db_dest *pDB;
+       u32 flags, count;
 
-out3:
-       dma_free((void *)aup->rx_ring[0],
-               2 * MAX_NUM_IR_DESC*(sizeof(ring_dest_t)));
-out2:
-       kfree(aup->rx_buff.head);
-out1:
-       printk(KERN_ERR "au1k_init_module failed.  Returns %d\n", retval);
-       return retval;
+       prxd = aup->rx_ring[aup->rx_head];
+       flags = prxd->flags;
+
+       while (!(flags & AU_OWN))  {
+               pDB = aup->rx_db_inuse[aup->rx_head];
+               count = (prxd->count_1 << 8) | prxd->count_0;
+               if (!(flags & IR_RX_ERROR)) {
+                       /* good frame */
+                       update_rx_stats(dev, flags, count);
+                       skb = alloc_skb(count + 1, GFP_ATOMIC);
+                       if (skb == NULL) {
+                               dev->stats.rx_dropped++;
+                               continue;
+                       }
+                       skb_reserve(skb, 1);
+                       if (aup->speed == 4000000)
+                               skb_put(skb, count);
+                       else
+                               skb_put(skb, count - 2);
+                       skb_copy_to_linear_data(skb, (void *)pDB->vaddr,
+                                               count - 2);
+                       skb->dev = dev;
+                       skb_reset_mac_header(skb);
+                       skb->protocol = htons(ETH_P_IRDA);
+                       netif_rx(skb);
+                       prxd->count_0 = 0;
+                       prxd->count_1 = 0;
+               }
+               prxd->flags |= AU_OWN;
+               aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1);
+               irda_write(aup, IR_RING_PROMPT, 0);
+
+               /* next descriptor */
+               prxd = aup->rx_ring[aup->rx_head];
+               flags = prxd->flags;
+
+       }
+       return 0;
 }
 
+static irqreturn_t au1k_irda_interrupt(int dummy, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct au1k_private *aup = netdev_priv(dev);
+
+       irda_write(aup, IR_INT_CLEAR, 0); /* ack irda interrupts */
+
+       au1k_irda_rx(dev);
+       au1k_tx_ack(dev);
+
+       return IRQ_HANDLED;
+}
 
 static int au1k_init(struct net_device *dev)
 {
        struct au1k_private *aup = netdev_priv(dev);
+       u32 enable, ring_address;
        int i;
-       u32 control;
-       u32 ring_address;
 
-       /* bring the device out of reset */
-       control = 0xe; /* coherent, clock enable, one half system clock */
-                         
+       enable = IR_HC | IR_CE | IR_C;
 #ifndef CONFIG_CPU_LITTLE_ENDIAN
-       control |= 1;
+       enable |= IR_BE;
 #endif
        aup->tx_head = 0;
        aup->tx_tail = 0;
        aup->rx_head = 0;
 
-       for (i=0; i<NUM_IR_DESC; i++) {
+       for (i = 0; i < NUM_IR_DESC; i++)
                aup->rx_ring[i]->flags = AU_OWN;
-       }
 
-       writel(control, IR_INTERFACE_CONFIG);
-       au_sync_delay(10);
+       irda_write(aup, IR_ENABLE, enable);
+       msleep(20);
 
-       writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE); /* disable PHY */
-       au_sync_delay(1);
+       /* disable PHY */
+       au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF);
+       irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) & ~IR_PHYEN);
+       msleep(20);
 
-       writel(MAX_BUF_SIZE, IR_MAX_PKT_LEN);
+       irda_write(aup, IR_MAX_PKT_LEN, MAX_BUF_SIZE);
 
        ring_address = (u32)virt_to_phys((void *)aup->rx_ring[0]);
-       writel(ring_address >> 26, IR_RING_BASE_ADDR_H);
-       writel((ring_address >> 10) & 0xffff, IR_RING_BASE_ADDR_L);
+       irda_write(aup, IR_RING_BASE_ADDR_H, ring_address >> 26);
+       irda_write(aup, IR_RING_BASE_ADDR_L, (ring_address >> 10) & 0xffff);
 
-       writel(RING_SIZE_64<<8 | RING_SIZE_64<<12, IR_RING_SIZE);
+       irda_write(aup, IR_RING_SIZE,
+                               (RING_SIZE_64 << 8) | (RING_SIZE_64 << 12));
 
-       writel(1<<2 | IR_ONE_PIN, IR_CONFIG_2); /* 48MHz */
-       writel(0, IR_RING_ADDR_CMPR);
+       irda_write(aup, IR_CONFIG_2, IR_PHYCLK_48MHZ | IR_ONE_PIN);
+       irda_write(aup, IR_RING_ADDR_CMPR, 0);
 
        au1k_irda_set_speed(dev, 9600);
        return 0;
@@ -340,25 +555,28 @@ static int au1k_init(struct net_device *dev)
 
 static int au1k_irda_start(struct net_device *dev)
 {
-       int retval;
-       char hwname[32];
        struct au1k_private *aup = netdev_priv(dev);
+       char hwname[32];
+       int retval;
 
-       if ((retval = au1k_init(dev))) {
+       retval = au1k_init(dev);
+       if (retval) {
                printk(KERN_ERR "%s: error in au1k_init\n", dev->name);
                return retval;
        }
 
-       if ((retval = request_irq(AU1000_IRDA_TX_INT, au1k_irda_interrupt, 
-                                       0, dev->name, dev))) {
-               printk(KERN_ERR "%s: unable to get IRQ %d\n", 
+       retval = request_irq(aup->irq_tx, &au1k_irda_interrupt, 0,
+                            dev->name, dev);
+       if (retval) {
+               printk(KERN_ERR "%s: unable to get IRQ %d\n",
                                dev->name, dev->irq);
                return retval;
        }
-       if ((retval = request_irq(AU1000_IRDA_RX_INT, au1k_irda_interrupt, 
-                                       0, dev->name, dev))) {
-               free_irq(AU1000_IRDA_TX_INT, dev);
-               printk(KERN_ERR "%s: unable to get IRQ %d\n", 
+       retval = request_irq(aup->irq_rx, &au1k_irda_interrupt, 0,
+                            dev->name, dev);
+       if (retval) {
+               free_irq(aup->irq_tx, dev);
+               printk(KERN_ERR "%s: unable to get IRQ %d\n",
                                dev->name, dev->irq);
                return retval;
        }
@@ -368,9 +586,13 @@ static int au1k_irda_start(struct net_device *dev)
        aup->irlap = irlap_open(dev, &aup->qos, hwname);
        netif_start_queue(dev);
 
-       writel(read_ir_reg(IR_CONFIG_2) | 1<<8, IR_CONFIG_2); /* int enable */
+       /* int enable */
+       irda_write(aup, IR_CONFIG_2, irda_read(aup, IR_CONFIG_2) | IR_IEN);
 
-       aup->timer.expires = RUN_AT((3*HZ)); 
+       /* power up */
+       au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_SIR);
+
+       aup->timer.expires = RUN_AT((3 * HZ));
        aup->timer.data = (unsigned long)dev;
        return 0;
 }
@@ -379,11 +601,12 @@ static int au1k_irda_stop(struct net_device *dev)
 {
        struct au1k_private *aup = netdev_priv(dev);
 
+       au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF);
+
        /* disable interrupts */
-       writel(read_ir_reg(IR_CONFIG_2) & ~(1<<8), IR_CONFIG_2);
-       writel(0, IR_CONFIG_1); 
-       writel(0, IR_INTERFACE_CONFIG); /* disable clock */
-       au_sync();
+       irda_write(aup, IR_CONFIG_2, irda_read(aup, IR_CONFIG_2) & ~IR_IEN);
+       irda_write(aup, IR_CONFIG_1, 0);
+       irda_write(aup, IR_ENABLE, 0); /* disable clock */
 
        if (aup->irlap) {
                irlap_close(aup->irlap);
@@ -394,83 +617,12 @@ static int au1k_irda_stop(struct net_device *dev)
        del_timer(&aup->timer);
 
        /* disable the interrupt */
-       free_irq(AU1000_IRDA_TX_INT, dev);
-       free_irq(AU1000_IRDA_RX_INT, dev);
-       return 0;
-}
-
-static void __exit au1k_irda_exit(void)
-{
-       struct net_device *dev = ir_devs[0];
-       struct au1k_private *aup = netdev_priv(dev);
-
-       unregister_netdev(dev);
-
-       dma_free((void *)aup->db[0].vaddr,
-               MAX_BUF_SIZE * 2*NUM_IR_DESC);
-       dma_free((void *)aup->rx_ring[0],
-               2 * MAX_NUM_IR_DESC*(sizeof(ring_dest_t)));
-       kfree(aup->rx_buff.head);
-       free_netdev(dev);
-}
-
-
-static inline void 
-update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len)
-{
-       struct au1k_private *aup = netdev_priv(dev);
-       struct net_device_stats *ps = &aup->stats;
-
-       ps->tx_packets++;
-       ps->tx_bytes += pkt_len;
-
-       if (status & IR_TX_ERROR) {
-               ps->tx_errors++;
-               ps->tx_aborted_errors++;
-       }
-}
-
-
-static void au1k_tx_ack(struct net_device *dev)
-{
-       struct au1k_private *aup = netdev_priv(dev);
-       volatile ring_dest_t *ptxd;
-
-       ptxd = aup->tx_ring[aup->tx_tail];
-       while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) {
-               update_tx_stats(dev, ptxd->flags, 
-                               ptxd->count_1<<8 | ptxd->count_0);
-               ptxd->count_0 = 0;
-               ptxd->count_1 = 0;
-               au_sync();
-
-               aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1);
-               ptxd = aup->tx_ring[aup->tx_tail];
-
-               if (aup->tx_full) {
-                       aup->tx_full = 0;
-                       netif_wake_queue(dev);
-               }
-       }
+       free_irq(aup->irq_tx, dev);
+       free_irq(aup->irq_rx, dev);
 
-       if (aup->tx_tail == aup->tx_head) {
-               if (aup->newspeed) {
-                       au1k_irda_set_speed(dev, aup->newspeed);
-                       aup->newspeed = 0;
-               }
-               else {
-                       writel(read_ir_reg(IR_CONFIG_1) & ~IR_TX_ENABLE, 
-                                       IR_CONFIG_1); 
-                       au_sync();
-                       writel(read_ir_reg(IR_CONFIG_1) | IR_RX_ENABLE, 
-                                       IR_CONFIG_1); 
-                       writel(0, IR_RING_PROMPT);
-                       au_sync();
-               }
-       }
+       return 0;
 }
 
-
 /*
  * Au1000 transmit routine.
  */
@@ -478,15 +630,12 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct au1k_private *aup = netdev_priv(dev);
        int speed = irda_get_next_speed(skb);
-       volatile ring_dest_t *ptxd;
-       u32 len;
-
-       u32 flags;
-       db_dest_t *pDB;
+       volatile struct ring_dest *ptxd;
+       struct db_dest *pDB;
+       u32 len, flags;
 
-       if (speed != aup->speed && speed != -1) {
+       if (speed != aup->speed && speed != -1)
                aup->newspeed = speed;
-       }
 
        if ((skb->len == 0) && (aup->newspeed)) {
                if (aup->tx_tail == aup->tx_head) {
@@ -504,138 +653,47 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
                printk(KERN_DEBUG "%s: tx_full\n", dev->name);
                netif_stop_queue(dev);
                aup->tx_full = 1;
-               return NETDEV_TX_BUSY;
-       }
-       else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) {
+               return 1;
+       } else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) {
                printk(KERN_DEBUG "%s: tx_full\n", dev->name);
                netif_stop_queue(dev);
                aup->tx_full = 1;
-               return NETDEV_TX_BUSY;
+               return 1;
        }
 
        pDB = aup->tx_db_inuse[aup->tx_head];
 
 #if 0
-       if (read_ir_reg(IR_RX_BYTE_CNT) != 0) {
-               printk("tx warning: rx byte cnt %x\n", 
-                               read_ir_reg(IR_RX_BYTE_CNT));
+       if (irda_read(aup, IR_RX_BYTE_CNT) != 0) {
+               printk(KERN_DEBUG "tx warning: rx byte cnt %x\n",
+                               irda_read(aup, IR_RX_BYTE_CNT));
        }
 #endif
-       
+
        if (aup->speed == 4000000) {
                /* FIR */
-               skb_copy_from_linear_data(skb, pDB->vaddr, skb->len);
+               skb_copy_from_linear_data(skb, (void *)pDB->vaddr, skb->len);
                ptxd->count_0 = skb->len & 0xff;
                ptxd->count_1 = (skb->len >> 8) & 0xff;
-
-       }
-       else {
+       } else {
                /* SIR */
                len = async_wrap_skb(skb, (u8 *)pDB->vaddr, MAX_BUF_SIZE);
                ptxd->count_0 = len & 0xff;
                ptxd->count_1 = (len >> 8) & 0xff;
                ptxd->flags |= IR_DIS_CRC;
-               au_writel(au_readl(0xae00000c) & ~(1<<13), 0xae00000c);
        }
        ptxd->flags |= AU_OWN;
-       au_sync();
+       wmb();
 
-       writel(read_ir_reg(IR_CONFIG_1) | IR_TX_ENABLE, IR_CONFIG_1); 
-       writel(0, IR_RING_PROMPT);
-       au_sync();
+       irda_write(aup, IR_CONFIG_1,
+                  irda_read(aup, IR_CONFIG_1) | IR_TX_ENABLE);
+       irda_write(aup, IR_RING_PROMPT, 0);
 
        dev_kfree_skb(skb);
        aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1);
        return NETDEV_TX_OK;
 }
 
-
-static inline void 
-update_rx_stats(struct net_device *dev, u32 status, u32 count)
-{
-       struct au1k_private *aup = netdev_priv(dev);
-       struct net_device_stats *ps = &aup->stats;
-
-       ps->rx_packets++;
-
-       if (status & IR_RX_ERROR) {
-               ps->rx_errors++;
-               if (status & (IR_PHY_ERROR|IR_FIFO_OVER))
-                       ps->rx_missed_errors++;
-               if (status & IR_MAX_LEN)
-                       ps->rx_length_errors++;
-               if (status & IR_CRC_ERROR)
-                       ps->rx_crc_errors++;
-       }
-       else 
-               ps->rx_bytes += count;
-}
-
-/*
- * Au1000 receive routine.
- */
-static int au1k_irda_rx(struct net_device *dev)
-{
-       struct au1k_private *aup = netdev_priv(dev);
-       struct sk_buff *skb;
-       volatile ring_dest_t *prxd;
-       u32 flags, count;
-       db_dest_t *pDB;
-
-       prxd = aup->rx_ring[aup->rx_head];
-       flags = prxd->flags;
-
-       while (!(flags & AU_OWN))  {
-               pDB = aup->rx_db_inuse[aup->rx_head];
-               count = prxd->count_1<<8 | prxd->count_0;
-               if (!(flags & IR_RX_ERROR))  {
-                       /* good frame */
-                       update_rx_stats(dev, flags, count);
-                       skb=alloc_skb(count+1,GFP_ATOMIC);
-                       if (skb == NULL) {
-                               aup->netdev->stats.rx_dropped++;
-                               continue;
-                       }
-                       skb_reserve(skb, 1);
-                       if (aup->speed == 4000000)
-                               skb_put(skb, count);
-                       else
-                               skb_put(skb, count-2);
-                       skb_copy_to_linear_data(skb, pDB->vaddr, count - 2);
-                       skb->dev = dev;
-                       skb_reset_mac_header(skb);
-                       skb->protocol = htons(ETH_P_IRDA);
-                       netif_rx(skb);
-                       prxd->count_0 = 0;
-                       prxd->count_1 = 0;
-               }
-               prxd->flags |= AU_OWN;
-               aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1);
-               writel(0, IR_RING_PROMPT);
-               au_sync();
-
-               /* next descriptor */
-               prxd = aup->rx_ring[aup->rx_head];
-               flags = prxd->flags;
-
-       }
-       return 0;
-}
-
-
-static irqreturn_t au1k_irda_interrupt(int dummy, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-
-       writel(0, IR_INT_CLEAR); /* ack irda interrupts */
-
-       au1k_irda_rx(dev);
-       au1k_tx_ack(dev);
-
-       return IRQ_HANDLED;
-}
-
-
 /*
  * The Tx ring has been full longer than the watchdog timeout
  * value. The transmitter must be hung?
@@ -653,142 +711,7 @@ static void au1k_tx_timeout(struct net_device *dev)
        netif_wake_queue(dev);
 }
 
-
-/*
- * Set the IrDA communications speed.
- */
-static int 
-au1k_irda_set_speed(struct net_device *dev, int speed)
-{
-       unsigned long flags;
-       struct au1k_private *aup = netdev_priv(dev);
-       u32 control;
-       int ret = 0, timeout = 10, i;
-       volatile ring_dest_t *ptxd;
-#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
-       unsigned long irda_resets;
-#endif
-
-       if (speed == aup->speed)
-               return ret;
-
-       spin_lock_irqsave(&ir_lock, flags);
-
-       /* disable PHY first */
-       writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE);
-
-       /* disable RX/TX */
-       writel(read_ir_reg(IR_CONFIG_1) & ~(IR_RX_ENABLE|IR_TX_ENABLE), 
-                       IR_CONFIG_1);
-       au_sync_delay(1);
-       while (read_ir_reg(IR_ENABLE) & (IR_RX_STATUS | IR_TX_STATUS)) {
-               mdelay(1);
-               if (!timeout--) {
-                       printk(KERN_ERR "%s: rx/tx disable timeout\n",
-                                       dev->name);
-                       break;
-               }
-       }
-
-       /* disable DMA */
-       writel(read_ir_reg(IR_CONFIG_1) & ~IR_DMA_ENABLE, IR_CONFIG_1);
-       au_sync_delay(1);
-
-       /* 
-        *  After we disable tx/rx. the index pointers
-        * go back to zero.
-        */
-       aup->tx_head = aup->tx_tail = aup->rx_head = 0;
-       for (i=0; i<NUM_IR_DESC; i++) {
-               ptxd = aup->tx_ring[i];
-               ptxd->flags = 0;
-               ptxd->count_0 = 0;
-               ptxd->count_1 = 0;
-       }
-
-       for (i=0; i<NUM_IR_DESC; i++) {
-               ptxd = aup->rx_ring[i];
-               ptxd->count_0 = 0;
-               ptxd->count_1 = 0;
-               ptxd->flags = AU_OWN;
-       }
-
-       if (speed == 4000000) {
-#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
-               bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_FIR_SEL);
-#else /* Pb1000 and Pb1100 */
-               writel(1<<13, CPLD_AUX1);
-#endif
-       }
-       else {
-#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
-               bcsr_mod(BCSR_RESETS, BCSR_RESETS_FIR_SEL, 0);
-#else /* Pb1000 and Pb1100 */
-               writel(readl(CPLD_AUX1) & ~(1<<13), CPLD_AUX1);
-#endif
-       }
-
-       switch (speed) {
-       case 9600:      
-               writel(11<<10 | 12<<5, IR_WRITE_PHY_CONFIG); 
-               writel(IR_SIR_MODE, IR_CONFIG_1); 
-               break;
-       case 19200:     
-               writel(5<<10 | 12<<5, IR_WRITE_PHY_CONFIG); 
-               writel(IR_SIR_MODE, IR_CONFIG_1); 
-               break;
-       case 38400:
-               writel(2<<10 | 12<<5, IR_WRITE_PHY_CONFIG); 
-               writel(IR_SIR_MODE, IR_CONFIG_1); 
-               break;
-       case 57600:     
-               writel(1<<10 | 12<<5, IR_WRITE_PHY_CONFIG); 
-               writel(IR_SIR_MODE, IR_CONFIG_1); 
-               break;
-       case 115200: 
-               writel(12<<5, IR_WRITE_PHY_CONFIG); 
-               writel(IR_SIR_MODE, IR_CONFIG_1); 
-               break;
-       case 4000000:
-               writel(0xF, IR_WRITE_PHY_CONFIG);
-               writel(IR_FIR|IR_DMA_ENABLE|IR_RX_ENABLE, IR_CONFIG_1); 
-               break;
-       default:
-               printk(KERN_ERR "%s unsupported speed %x\n", dev->name, speed);
-               ret = -EINVAL;
-               break;
-       }
-
-       aup->speed = speed;
-       writel(read_ir_reg(IR_ENABLE) | 0x8000, IR_ENABLE);
-       au_sync();
-
-       control = read_ir_reg(IR_ENABLE);
-       writel(0, IR_RING_PROMPT);
-       au_sync();
-
-       if (control & (1<<14)) {
-               printk(KERN_ERR "%s: configuration error\n", dev->name);
-       }
-       else {
-               if (control & (1<<11))
-                       printk(KERN_DEBUG "%s Valid SIR config\n", dev->name);
-               if (control & (1<<12))
-                       printk(KERN_DEBUG "%s Valid MIR config\n", dev->name);
-               if (control & (1<<13))
-                       printk(KERN_DEBUG "%s Valid FIR config\n", dev->name);
-               if (control & (1<<10))
-                       printk(KERN_DEBUG "%s TX enabled\n", dev->name);
-               if (control & (1<<9))
-                       printk(KERN_DEBUG "%s RX enabled\n", dev->name);
-       }
-
-       spin_unlock_irqrestore(&ir_lock, flags);
-       return ret;
-}
-
-static int 
-au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
+static int au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
 {
        struct if_irda_req *rq = (struct if_irda_req *)ifreq;
        struct au1k_private *aup = netdev_priv(dev);
@@ -829,8 +752,218 @@ au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
        return ret;
 }
 
+static const struct net_device_ops au1k_irda_netdev_ops = {
+       .ndo_open               = au1k_irda_start,
+       .ndo_stop               = au1k_irda_stop,
+       .ndo_start_xmit         = au1k_irda_hard_xmit,
+       .ndo_tx_timeout         = au1k_tx_timeout,
+       .ndo_do_ioctl           = au1k_irda_ioctl,
+};
+
+static int __devinit au1k_irda_net_init(struct net_device *dev)
+{
+       struct au1k_private *aup = netdev_priv(dev);
+       struct db_dest *pDB, *pDBfree;
+       int i, err, retval = 0;
+       dma_addr_t temp;
+
+       err = au1k_irda_init_iobuf(&aup->rx_buff, 14384);
+       if (err)
+               goto out1;
+
+       dev->netdev_ops = &au1k_irda_netdev_ops;
+
+       irda_init_max_qos_capabilies(&aup->qos);
+
+       /* The only value we must override it the baudrate */
+       aup->qos.baud_rate.bits = IR_9600 | IR_19200 | IR_38400 |
+               IR_57600 | IR_115200 | IR_576000 | (IR_4000000 << 8);
+
+       aup->qos.min_turn_time.bits = qos_mtt_bits;
+       irda_qos_bits_to_value(&aup->qos);
+
+       retval = -ENOMEM;
+
+       /* Tx ring follows rx ring + 512 bytes */
+       /* we need a 1k aligned buffer */
+       aup->rx_ring[0] = (struct ring_dest *)
+               dma_alloc(2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest)),
+                         &temp);
+       if (!aup->rx_ring[0])
+               goto out2;
+
+       /* allocate the data buffers */
+       aup->db[0].vaddr =
+               (void *)dma_alloc(MAX_BUF_SIZE * 2 * NUM_IR_DESC, &temp);
+       if (!aup->db[0].vaddr)
+               goto out3;
+
+       setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512);
+
+       pDBfree = NULL;
+       pDB = aup->db;
+       for (i = 0; i < (2 * NUM_IR_DESC); i++) {
+               pDB->pnext = pDBfree;
+               pDBfree = pDB;
+               pDB->vaddr =
+                      (u32 *)((unsigned)aup->db[0].vaddr + (MAX_BUF_SIZE * i));
+               pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr);
+               pDB++;
+       }
+       aup->pDBfree = pDBfree;
+
+       /* attach a data buffer to each descriptor */
+       for (i = 0; i < NUM_IR_DESC; i++) {
+               pDB = GetFreeDB(aup);
+               if (!pDB)
+                       goto out3;
+               aup->rx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff);
+               aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr >>  8) & 0xff);
+               aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr >> 16) & 0xff);
+               aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr >> 24) & 0xff);
+               aup->rx_db_inuse[i] = pDB;
+       }
+       for (i = 0; i < NUM_IR_DESC; i++) {
+               pDB = GetFreeDB(aup);
+               if (!pDB)
+                       goto out3;
+               aup->tx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff);
+               aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr >>  8) & 0xff);
+               aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr >> 16) & 0xff);
+               aup->tx_ring[i]->addr_3 = (u8)((pDB->dma_addr >> 24) & 0xff);
+               aup->tx_ring[i]->count_0 = 0;
+               aup->tx_ring[i]->count_1 = 0;
+               aup->tx_ring[i]->flags = 0;
+               aup->tx_db_inuse[i] = pDB;
+       }
+
+       return 0;
+
+out3:
+       dma_free((void *)aup->rx_ring[0],
+               2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest)));
+out2:
+       kfree(aup->rx_buff.head);
+out1:
+       printk(KERN_ERR "au1k_irda_net_init() failed.  Returns %d\n", retval);
+       return retval;
+}
+
+static int __devinit au1k_irda_probe(struct platform_device *pdev)
+{
+       struct au1k_private *aup;
+       struct net_device *dev;
+       struct resource *r;
+       int err;
+
+       dev = alloc_irdadev(sizeof(struct au1k_private));
+       if (!dev)
+               return -ENOMEM;
+
+       aup = netdev_priv(dev);
+
+       aup->platdata = pdev->dev.platform_data;
+
+       err = -EINVAL;
+       r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!r)
+               goto out;
+
+       aup->irq_tx = r->start;
+
+       r = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+       if (!r)
+               goto out;
+
+       aup->irq_rx = r->start;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r)
+               goto out;
+
+       err = -EBUSY;
+       aup->ioarea = request_mem_region(r->start, r->end - r->start + 1,
+                                        pdev->name);
+       if (!aup->ioarea)
+               goto out;
+
+       aup->iobase = ioremap_nocache(r->start, r->end - r->start + 1);
+       if (!aup->iobase)
+               goto out2;
+
+       dev->irq = aup->irq_rx;
+
+       err = au1k_irda_net_init(dev);
+       if (err)
+               goto out3;
+       err = register_netdev(dev);
+       if (err)
+               goto out4;
+
+       platform_set_drvdata(pdev, dev);
+
+       printk(KERN_INFO "IrDA: Registered device %s\n", dev->name);
+       return 0;
+
+out4:
+       dma_free((void *)aup->db[0].vaddr,
+               MAX_BUF_SIZE * 2 * NUM_IR_DESC);
+       dma_free((void *)aup->rx_ring[0],
+               2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest)));
+       kfree(aup->rx_buff.head);
+out3:
+       iounmap(aup->iobase);
+out2:
+       release_resource(aup->ioarea);
+       kfree(aup->ioarea);
+out:
+       free_netdev(dev);
+       return err;
+}
+
+static int __devexit au1k_irda_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct au1k_private *aup = netdev_priv(dev);
+
+       unregister_netdev(dev);
+
+       dma_free((void *)aup->db[0].vaddr,
+               MAX_BUF_SIZE * 2 * NUM_IR_DESC);
+       dma_free((void *)aup->rx_ring[0],
+               2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest)));
+       kfree(aup->rx_buff.head);
+
+       iounmap(aup->iobase);
+       release_resource(aup->ioarea);
+       kfree(aup->ioarea);
+
+       free_netdev(dev);
+
+       return 0;
+}
+
+static struct platform_driver au1k_irda_driver = {
+       .driver = {
+               .name   = "au1000-irda",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = au1k_irda_probe,
+       .remove         = __devexit_p(au1k_irda_remove),
+};
+
+static int __init au1k_irda_load(void)
+{
+       return platform_driver_register(&au1k_irda_driver);
+}
+
+static void __exit au1k_irda_unload(void)
+{
+       return platform_driver_unregister(&au1k_irda_driver);
+}
+
 MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>");
 MODULE_DESCRIPTION("Au1000 IrDA Device Driver");
 
-module_init(au1k_irda_init);
-module_exit(au1k_irda_exit);
+module_init(au1k_irda_load);
+module_exit(au1k_irda_unload);
index 9663e0ba60034d8edf1806c8bcd7eb928a7c4733..ba3c59147aa7eecda0e6cf1ff344caa498eb91fd 100644 (file)
@@ -1159,7 +1159,7 @@ static void rx_timestamp_work(struct work_struct *work)
                        }
                }
                spin_unlock_irqrestore(&dp83640->rx_lock, flags);
-               netif_rx(skb);
+               netif_rx_ni(skb);
        }
 
        /* Clear out expired time stamps. */
index 1fa4d73c3cca5e0d6ff4579abd986a910ab67305..633680d0828e64b2c96b2a335713eb17e62490bf 100644 (file)
@@ -220,7 +220,7 @@ static int __init fixed_mdio_bus_init(void)
                goto err_mdiobus_reg;
        }
 
-       snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "0");
+       snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
        fmb->mii_bus->name = "Fixed MDIO Bus";
        fmb->mii_bus->priv = fmb;
        fmb->mii_bus->parent = &pdev->dev;
index 89c5a3eccc12daa760fa0e1e6c73e392c0a81f3e..50e8e5e74465bc607dddda8126a8d960aa5268cb 100644 (file)
@@ -116,7 +116,7 @@ static struct mii_bus * __devinit mdio_gpio_bus_init(struct device *dev,
                if (!new_bus->irq[i])
                        new_bus->irq[i] = PHY_POLL;
 
-       snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", bus_id);
+       snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id);
 
        if (gpio_request(bitbang->mdc, "mdc"))
                goto out_free_bus;
index bd12ba941be51b9bb9dc4ee20e3dfb48e8bfae78..826d961f39f74ff7bbd2a9c839f36f3c5b2ed851 100644 (file)
@@ -118,7 +118,8 @@ static int __devinit octeon_mdiobus_probe(struct platform_device *pdev)
        bus->mii_bus->priv = bus;
        bus->mii_bus->irq = bus->phy_irq;
        bus->mii_bus->name = "mdio-octeon";
-       snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%x", bus->unit);
+       snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               bus->mii_bus->name, bus->unit);
        bus->mii_bus->parent = &pdev->dev;
 
        bus->mii_bus->read = octeon_mdiobus_read;
index 6c58da2b882c845e453ddd7b6bb0b544f4705b83..88cc5db9affd7a4923fe29de85c63cd98d80c3aa 100644 (file)
 #include <asm/uaccess.h>
 
 /**
- * mdiobus_alloc - allocate a mii_bus structure
+ * mdiobus_alloc_size - allocate a mii_bus structure
  *
  * Description: called by a bus driver to allocate an mii_bus
  * structure to fill in.
+ *
+ * 'size' is an an extra amount of memory to allocate for private storage.
+ * If non-zero, then bus->priv is points to that memory.
  */
-struct mii_bus *mdiobus_alloc(void)
+struct mii_bus *mdiobus_alloc_size(size_t size)
 {
        struct mii_bus *bus;
+       size_t aligned_size = ALIGN(sizeof(*bus), NETDEV_ALIGN);
+       size_t alloc_size;
+
+       /* If we alloc extra space, it should be aligned */
+       if (size)
+               alloc_size = aligned_size + size;
+       else
+               alloc_size = sizeof(*bus);
 
-       bus = kzalloc(sizeof(*bus), GFP_KERNEL);
-       if (bus != NULL)
+       bus = kzalloc(alloc_size, GFP_KERNEL);
+       if (bus) {
                bus->state = MDIOBUS_ALLOCATED;
+               if (size)
+                       bus->priv = (void *)bus + aligned_size;
+       }
 
        return bus;
 }
-EXPORT_SYMBOL(mdiobus_alloc);
+EXPORT_SYMBOL(mdiobus_alloc_size);
 
 /**
  * mdiobus_release - mii_bus device release callback
index c1c9293c2bbf1eecd638d8d6e428777951cdff9d..df884dde2a511c27b95db1edef5848886b6c9abd 100644 (file)
@@ -585,8 +585,8 @@ static int pptp_create(struct net *net, struct socket *sock)
        po = pppox_sk(sk);
        opt = &po->proto.pptp;
 
-       opt->seq_sent = 0; opt->seq_recv = 0;
-       opt->ack_recv = 0; opt->ack_sent = 0;
+       opt->seq_sent = 0; opt->seq_recv = 0xffffffff;
+       opt->ack_recv = 0; opt->ack_sent = 0xffffffff;
 
        error = 0;
 out:
index d0937c4634c9ef584f73023f73a144c673e4514a..8e84f5bdd6ca581a3f6d26cfe9a06eb1b27771b2 100644 (file)
@@ -978,6 +978,7 @@ static int ax88772_link_reset(struct usbnet *dev)
 
 static int ax88772_reset(struct usbnet *dev)
 {
+       struct asix_data *data = (struct asix_data *)&dev->data;
        int ret, embd_phy;
        u16 rx_ctl;
 
@@ -1055,6 +1056,13 @@ static int ax88772_reset(struct usbnet *dev)
                goto out;
        }
 
+       /* Rewrite MAC address */
+       memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
+       ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
+                                                       data->mac_addr);
+       if (ret < 0)
+               goto out;
+
        /* Set RX_CTL to default values with 2k buffer, and enable cactus */
        ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL);
        if (ret < 0)
@@ -1320,6 +1328,13 @@ static int ax88178_reset(struct usbnet *dev)
        if (ret < 0)
                return ret;
 
+       /* Rewrite MAC address */
+       memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
+       ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
+                                                       data->mac_addr);
+       if (ret < 0)
+               return ret;
+
        ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL);
        if (ret < 0)
                return ret;
index 76fe14efb2b52910c3e113dd0f8917f22c9661b6..4880aa8b4c28b4662446e8e56b2acc98958645e4 100644 (file)
@@ -370,7 +370,7 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)
 
        skb_to_sgvec(skb, vi->rx_sg + 1, 0, skb->len);
 
-       err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 2, skb, gfp);
+       err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 2, skb, gfp);
        if (err < 0)
                dev_kfree_skb(skb);
 
@@ -415,8 +415,8 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)
 
        /* chain first in list head */
        first->private = (unsigned long)list;
-       err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
-                                   first, gfp);
+       err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
+                               first, gfp);
        if (err < 0)
                give_pages(vi, first);
 
@@ -434,7 +434,7 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp)
 
        sg_init_one(vi->rx_sg, page_address(page), PAGE_SIZE);
 
-       err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 1, page, gfp);
+       err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 1, page, gfp);
        if (err < 0)
                give_pages(vi, page);
 
@@ -609,7 +609,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
 
        hdr->num_sg = skb_to_sgvec(skb, vi->tx_sg + 1, 0, skb->len) + 1;
        return virtqueue_add_buf(vi->svq, vi->tx_sg, hdr->num_sg,
-                                       0, skb);
+                                0, skb, GFP_ATOMIC);
 }
 
 static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -767,7 +767,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
                sg_set_buf(&sg[i + 1], sg_virt(s), s->length);
        sg_set_buf(&sg[out + in - 1], &status, sizeof(status));
 
-       BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi) < 0);
+       BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi, GFP_ATOMIC) < 0);
 
        virtqueue_kick(vi->cvq);
 
@@ -985,15 +985,38 @@ static void virtnet_config_changed(struct virtio_device *vdev)
        virtnet_update_status(vi);
 }
 
+static int init_vqs(struct virtnet_info *vi)
+{
+       struct virtqueue *vqs[3];
+       vq_callback_t *callbacks[] = { skb_recv_done, skb_xmit_done, NULL};
+       const char *names[] = { "input", "output", "control" };
+       int nvqs, err;
+
+       /* We expect two virtqueues, receive then send,
+        * and optionally control. */
+       nvqs = virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2;
+
+       err = vi->vdev->config->find_vqs(vi->vdev, nvqs, vqs, callbacks, names);
+       if (err)
+               return err;
+
+       vi->rvq = vqs[0];
+       vi->svq = vqs[1];
+
+       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
+               vi->cvq = vqs[2];
+
+               if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN))
+                       vi->dev->features |= NETIF_F_HW_VLAN_FILTER;
+       }
+       return 0;
+}
+
 static int virtnet_probe(struct virtio_device *vdev)
 {
        int err;
        struct net_device *dev;
        struct virtnet_info *vi;
-       struct virtqueue *vqs[3];
-       vq_callback_t *callbacks[] = { skb_recv_done, skb_xmit_done, NULL};
-       const char *names[] = { "input", "output", "control" };
-       int nvqs;
 
        /* Allocate ourselves a network device with room for our info */
        dev = alloc_etherdev(sizeof(struct virtnet_info));
@@ -1065,24 +1088,10 @@ static int virtnet_probe(struct virtio_device *vdev)
        if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
                vi->mergeable_rx_bufs = true;
 
-       /* We expect two virtqueues, receive then send,
-        * and optionally control. */
-       nvqs = virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2;
-
-       err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
+       err = init_vqs(vi);
        if (err)
                goto free_stats;
 
-       vi->rvq = vqs[0];
-       vi->svq = vqs[1];
-
-       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
-               vi->cvq = vqs[2];
-
-               if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN))
-                       dev->features |= NETIF_F_HW_VLAN_FILTER;
-       }
-
        err = register_netdev(dev);
        if (err) {
                pr_debug("virtio_net: registering device failed\n");
@@ -1144,27 +1153,73 @@ static void free_unused_bufs(struct virtnet_info *vi)
        BUG_ON(vi->num != 0);
 }
 
-static void __devexit virtnet_remove(struct virtio_device *vdev)
+static void remove_vq_common(struct virtnet_info *vi)
 {
-       struct virtnet_info *vi = vdev->priv;
-
-       /* Stop all the virtqueues. */
-       vdev->config->reset(vdev);
-
-       unregister_netdev(vi->dev);
+       vi->vdev->config->reset(vi->vdev);
 
        /* Free unused buffers in both send and recv, if any. */
        free_unused_bufs(vi);
 
-       vdev->config->del_vqs(vi->vdev);
+       vi->vdev->config->del_vqs(vi->vdev);
 
        while (vi->pages)
                __free_pages(get_a_page(vi, GFP_KERNEL), 0);
+}
+
+static void __devexit virtnet_remove(struct virtio_device *vdev)
+{
+       struct virtnet_info *vi = vdev->priv;
+
+       unregister_netdev(vi->dev);
+
+       remove_vq_common(vi);
 
        free_percpu(vi->stats);
        free_netdev(vi->dev);
 }
 
+#ifdef CONFIG_PM
+static int virtnet_freeze(struct virtio_device *vdev)
+{
+       struct virtnet_info *vi = vdev->priv;
+
+       virtqueue_disable_cb(vi->rvq);
+       virtqueue_disable_cb(vi->svq);
+       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
+               virtqueue_disable_cb(vi->cvq);
+
+       netif_device_detach(vi->dev);
+       cancel_delayed_work_sync(&vi->refill);
+
+       if (netif_running(vi->dev))
+               napi_disable(&vi->napi);
+
+       remove_vq_common(vi);
+
+       return 0;
+}
+
+static int virtnet_restore(struct virtio_device *vdev)
+{
+       struct virtnet_info *vi = vdev->priv;
+       int err;
+
+       err = init_vqs(vi);
+       if (err)
+               return err;
+
+       if (netif_running(vi->dev))
+               virtnet_napi_enable(vi);
+
+       netif_device_attach(vi->dev);
+
+       if (!try_fill_recv(vi, GFP_KERNEL))
+               queue_delayed_work(system_nrt_wq, &vi->refill, 0);
+
+       return 0;
+}
+#endif
+
 static struct virtio_device_id id_table[] = {
        { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID },
        { 0 },
@@ -1189,6 +1244,10 @@ static struct virtio_driver virtio_net_driver = {
        .probe =        virtnet_probe,
        .remove =       __devexit_p(virtnet_remove),
        .config_changed = virtnet_config_changed,
+#ifdef CONFIG_PM
+       .freeze =       virtnet_freeze,
+       .restore =      virtnet_restore,
+#endif
 };
 
 static int __init init(void)
index 88c81c5706b249a0e08a25c28217775463dd53dc..09b8c9dbf78f5e3267ebfadc2d4bed15f9562487 100644 (file)
@@ -557,10 +557,11 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
                        rxs->rs_status |= ATH9K_RXERR_DECRYPT;
                else if (rxsp->status11 & AR_MichaelErr)
                        rxs->rs_status |= ATH9K_RXERR_MIC;
-               if (rxsp->status11 & AR_KeyMiss)
-                       rxs->rs_status |= ATH9K_RXERR_KEYMISS;
        }
 
+       if (rxsp->status11 & AR_KeyMiss)
+               rxs->rs_status |= ATH9K_RXERR_KEYMISS;
+
        return 0;
 }
 EXPORT_SYMBOL(ath9k_hw_process_rxdesc_edma);
index 2589b38b689a82cdc3acbe7748ffa7bd33092906..2b0bfb8cca02d023da420b842f058b904807f646 100644 (file)
@@ -46,7 +46,7 @@ static const int m2ThreshExt_off = 127;
  * @chan:
  *
  * This is the function to change channel on single-chip devices, that is
- * all devices after ar9280.
+ * for AR9300 family of chipsets.
  *
  * This function takes the channel value in MHz and sets
  * hardware channel value. Assumes writes have been enabled to analog bus.
index b30e9fc6433f0b8c947ce4029ef7037d11fd7486..171ccf7c972ff1cc228dca2019122ff6e79bdc0c 100644 (file)
@@ -679,7 +679,6 @@ void ath9k_deinit_device(struct ath_softc *sc);
 void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
 void ath9k_reload_chainmask_settings(struct ath_softc *sc);
 
-void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
 bool ath9k_uses_beacons(int type);
 
 #ifdef CONFIG_ATH9K_PCI
index 172e33db7f4c49d2e9447636a380c34e5c15f3f6..2f4b48e6fb036648af5eb1cdf35bd217b97dc67f 100644 (file)
@@ -400,6 +400,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
        ah->noise = ath9k_hw_getchan_noise(ah, chan);
        return true;
 }
+EXPORT_SYMBOL(ath9k_hw_getnf);
 
 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
                                  struct ath9k_channel *chan)
index 05b9dbf818507535288360bfdff4379aa7bf9970..3b33996d97dfeb84c7ba71233ff2a214cec1585e 100644 (file)
@@ -19,7 +19,6 @@
 
 #include "hw.h"
 
-#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT     3
 #define AR_PHY_CCA_FILTERWINDOW_LENGTH          5
 
 #define NUM_NF_READINGS       6
index fd3f19c2e550e4e9991c4adc9b430a91799c9bd4..e196aba77acf568387d7a4b2b5852e316d801e4f 100644 (file)
@@ -618,10 +618,11 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
                        rs->rs_status |= ATH9K_RXERR_DECRYPT;
                else if (ads.ds_rxstatus8 & AR_MichaelErr)
                        rs->rs_status |= ATH9K_RXERR_MIC;
-               if (ads.ds_rxstatus8 & AR_KeyMiss)
-                       rs->rs_status |= ATH9K_RXERR_KEYMISS;
        }
 
+       if (ads.ds_rxstatus8 & AR_KeyMiss)
+               rs->rs_status |= ATH9K_RXERR_KEYMISS;
+
        return 0;
 }
 EXPORT_SYMBOL(ath9k_hw_rxprocdesc);
index e267c92dbfb8e22de58a0156771a461ccfada95a..4a00806e2852af4e88638076f8b60c85fb82426b 100644 (file)
@@ -1629,7 +1629,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
                struct ieee80211_channel *curchan = hw->conf.channel;
-               struct ath9k_channel old_chan;
                int pos = curchan->hw_value;
                int old_pos = -1;
                unsigned long flags;
@@ -1654,11 +1653,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                 * Preserve the current channel values, before updating
                 * the same channel
                 */
-               if (old_pos == pos) {
-                       memcpy(&old_chan, &sc->sc_ah->channels[pos],
-                               sizeof(struct ath9k_channel));
-                       ah->curchan = &old_chan;
-               }
+               if (ah->curchan && (old_pos == pos))
+                       ath9k_hw_getnf(ah, ah->curchan);
 
                ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
                                          curchan, conf->channel_type);
index 1c6f19393efa72037b7369993bf7af463a7bb51a..b91f28ef1032e40791f4d385d3e92e4646464a3f 100644 (file)
@@ -4852,6 +4852,9 @@ static void b43_op_stop(struct ieee80211_hw *hw)
 
        cancel_work_sync(&(wl->beacon_update_trigger));
 
+       if (!dev)
+               goto out;
+
        mutex_lock(&wl->mutex);
        if (b43_status(dev) >= B43_STAT_STARTED) {
                dev = b43_wireless_core_stop(dev);
@@ -4863,7 +4866,7 @@ static void b43_op_stop(struct ieee80211_hw *hw)
 
 out_unlock:
        mutex_unlock(&wl->mutex);
-
+out:
        cancel_work_sync(&(wl->txpower_adjust_work));
 }
 
index 5a002a21f108aa23895ee59139c8fcb6ac37e643..f7eeee1dcdb66a8b3a09c5534bb8f15a15f09e91 100644 (file)
@@ -3119,8 +3119,10 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
                /* Verify NVRAM bytes */
                brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize);
                nvram_ularray = kmalloc(varsize, GFP_ATOMIC);
-               if (!nvram_ularray)
+               if (!nvram_ularray) {
+                       kfree(vbuffer);
                        return -ENOMEM;
+               }
 
                /* Upload image to verify downloaded contents. */
                memset(nvram_ularray, 0xaa, varsize);
index f23b0c3e4ea3d94985cbdc4b61d6f2688ef52164..bf11850a20f11b1201179c7c7659a16397f2d4cc 100644 (file)
@@ -2475,7 +2475,7 @@ static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv)
        return err;
 }
 
-static void brcmf_delay(u32 ms)
+static __always_inline void brcmf_delay(u32 ms)
 {
        if (ms < 1000 / HZ) {
                cond_resched();
index d106576ce338980b4645ced6084139084f74fc21..448ab9c4eb47b00db5ff558db6a4ab978a4f4f77 100644 (file)
@@ -1128,14 +1128,7 @@ static int __devinit brcms_bcma_probe(struct bcma_device *pdev)
        return 0;
 }
 
-static int brcms_pci_suspend(struct pci_dev *pdev)
-{
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
-       return pci_set_power_state(pdev, PCI_D3hot);
-}
-
-static int brcms_suspend(struct bcma_device *pdev, pm_message_t state)
+static int brcms_suspend(struct bcma_device *pdev)
 {
        struct brcms_info *wl;
        struct ieee80211_hw *hw;
@@ -1153,40 +1146,15 @@ static int brcms_suspend(struct bcma_device *pdev, pm_message_t state)
        wl->pub->hw_up = false;
        spin_unlock_bh(&wl->lock);
 
-       /* temporarily do suspend ourselves */
-       return brcms_pci_suspend(pdev->bus->host_pci);
-}
-
-static int brcms_pci_resume(struct pci_dev *pdev)
-{
-       int err = 0;
-       uint val;
-
-       err = pci_set_power_state(pdev, PCI_D0);
-       if (err)
-               return err;
-
-       pci_restore_state(pdev);
-
-       err = pci_enable_device(pdev);
-       if (err)
-               return err;
-
-       pci_set_master(pdev);
-
-       pci_read_config_dword(pdev, 0x40, &val);
-       if ((val & 0x0000ff00) != 0)
-               pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+       pr_debug("brcms_suspend ok\n");
 
        return 0;
 }
 
 static int brcms_resume(struct bcma_device *pdev)
 {
-       /*
-       *  just do pci resume for now until bcma supports it.
-       */
-       return brcms_pci_resume(pdev->bus->host_pci);
+       pr_debug("brcms_resume ok\n");
+       return 0;
 }
 
 static struct bcma_driver brcms_bcma_driver = {
index 61092156755e0a77984736df7a1ac524bb074ef5..5637436430381a12d6322fbac9e9be1ec27de276 100644 (file)
@@ -763,6 +763,22 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
        }
 }
 
+/*
+ * The crc check is done on a little-endian array, we need
+ * to switch the bytes around before checking crc (and
+ * then switch it back).
+ */
+static int do_crc_check(u16 *buf, unsigned nwords)
+{
+       u8 crc;
+
+       cpu_to_le16_buf(buf, nwords);
+       crc = crc8(brcms_srom_crc8_table, (void *)buf, nwords << 1, CRC8_INIT_VALUE);
+       le16_to_cpu_buf(buf, nwords);
+
+       return crc == CRC8_GOOD_VALUE(brcms_srom_crc8_table);
+}
+
 /*
  * Read in and validate sprom.
  * Return 0 on success, nonzero on error.
@@ -772,8 +788,6 @@ sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc)
 {
        int err = 0;
        uint i;
-       u8 *bbuf = (u8 *)buf; /* byte buffer */
-       uint nbytes = nwords << 1;
        struct bcma_device *core;
        uint sprom_offset;
 
@@ -786,9 +800,9 @@ sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc)
                sprom_offset = CHIPCREGOFFS(sromotp);
        }
 
-       /* read the sprom in bytes */
-       for (i = 0; i < nbytes; i++)
-               bbuf[i] = bcma_read8(core, sprom_offset+i);
+       /* read the sprom */
+       for (i = 0; i < nwords; i++)
+               buf[i] = bcma_read16(core, sprom_offset+i*2);
 
        if (buf[0] == 0xffff)
                /*
@@ -798,13 +812,8 @@ sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc)
                 */
                return -ENODATA;
 
-       if (check_crc &&
-           crc8(brcms_srom_crc8_table, bbuf, nbytes, CRC8_INIT_VALUE) !=
-                CRC8_GOOD_VALUE(brcms_srom_crc8_table))
+       if (check_crc && !do_crc_check(buf, nwords))
                err = -EIO;
-       else
-               /* now correct the endianness of the byte array */
-               le16_to_cpu_buf(buf, nwords);
 
        return err;
 }
index 018a8deb88a83b5b2ab2febcc2487b89eeb4ba4f..4fcdac63a3007aff3822e8dd17ccd5db57ce69a6 100644 (file)
@@ -7848,7 +7848,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
         * more efficiently than we can parse it. ORDER MATTERS HERE */
        struct ipw_rt_hdr *ipw_rt;
 
-       short len = le16_to_cpu(pkt->u.frame.length);
+       unsigned short len = le16_to_cpu(pkt->u.frame.length);
 
        /* We received data from the HW, so stop the watchdog */
        dev->trans_start = jiffies;
@@ -8023,7 +8023,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
        s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM;
        s8 noise = (s8) le16_to_cpu(frame->noise);
        u8 rate = frame->rate;
-       short len = le16_to_cpu(pkt->u.frame.length);
+       unsigned short len = le16_to_cpu(pkt->u.frame.length);
        struct sk_buff *skb;
        int hdr_only = 0;
        u16 filter = priv->prom_priv->filter;
index 084aa2c4ccfb272dab28d57fbc9969644360f314..a6454726737e04b207d0c9ae710098f98cef6c63 100644 (file)
@@ -569,7 +569,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        struct iwl_scan_cmd *scan;
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        u32 rate_flags = 0;
-       u16 cmd_len;
+       u16 cmd_len = 0;
        u16 rx_chain = 0;
        enum ieee80211_band band;
        u8 n_probes = 0;
index 7becea3dec654de21ab5090fc55b8a5068b7703f..dd5aeaff44ba3483804df003bd5779cbf0138794 100644 (file)
@@ -2777,7 +2777,7 @@ static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw,
        else if (channel->band == IEEE80211_BAND_5GHZ)
                cmd->band = cpu_to_le16(0x4);
 
-       cmd->channel = channel->hw_value;
+       cmd->channel = cpu_to_le16(channel->hw_value);
 
        if (conf->channel_type == NL80211_CHAN_NO_HT ||
            conf->channel_type == NL80211_CHAN_HT20) {
@@ -4066,7 +4066,7 @@ static int mwl8k_cmd_encryption_remove_key(struct ieee80211_hw *hw,
                goto done;
 
        if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-                       WLAN_CIPHER_SUITE_WEP104)
+                       key->cipher == WLAN_CIPHER_SUITE_WEP104)
                mwl8k_vif->wep_key_conf[key->keyidx].enabled = 0;
 
        cmd->action = cpu_to_le32(MWL8K_ENCR_REMOVE_KEY);
index 4941a1a2321907fb93cc8a2fe08a3ce87d8ecf16..dc88baefa72e88bd2b2f60b3ea2e8f7174ff34ed 100644 (file)
@@ -422,7 +422,6 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev)
 static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
                                 enum dev_state state)
 {
-       int mask = (state == STATE_RADIO_IRQ_ON);
        u32 reg;
        unsigned long flags;
 
@@ -436,25 +435,14 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
        }
 
        spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
-       rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_RXDELAYINT, 0);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_TXDELAYINT, 0);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_RX_DONE, mask);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_AC0_DMA_DONE, 0);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_AC1_DMA_DONE, 0);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_AC2_DMA_DONE, 0);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_AC3_DMA_DONE, 0);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_HCCA_DMA_DONE, 0);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_MGMT_DMA_DONE, 0);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_MCU_COMMAND, 0);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_RXTX_COHERENT, 0);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_TBTT, mask);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_PRE_TBTT, mask);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, mask);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_AUTO_WAKEUP, mask);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_GPTIMER, 0);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_RX_COHERENT, 0);
-       rt2x00_set_field32(&reg, INT_MASK_CSR_TX_COHERENT, 0);
+       reg = 0;
+       if (state == STATE_RADIO_IRQ_ON) {
+               rt2x00_set_field32(&reg, INT_MASK_CSR_RX_DONE, 1);
+               rt2x00_set_field32(&reg, INT_MASK_CSR_TBTT, 1);
+               rt2x00_set_field32(&reg, INT_MASK_CSR_PRE_TBTT, 1);
+               rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, 1);
+               rt2x00_set_field32(&reg, INT_MASK_CSR_AUTO_WAKEUP, 1);
+       }
        rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
        spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
 
index 6f91a148c2220ad2f4694c21a4f47e52822912e2..3fda6b1dcf465ee3fcda52a5807d78dedb50c760 100644 (file)
@@ -196,6 +196,8 @@ static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw,
                /* Allocate skb buffer to contain firmware */
                /* info and tx descriptor info. */
                skb = dev_alloc_skb(frag_length);
+               if (!skb)
+                       return false;
                skb_reserve(skb, extra_descoffset);
                seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length -
                                        extra_descoffset));
@@ -573,6 +575,8 @@ static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd,
 
        len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len);
        skb = dev_alloc_skb(len);
+       if (!skb)
+               return false;
        cb_desc = (struct rtl_tcb_desc *)(skb->cb);
        cb_desc->queue_index = TXCMD_QUEUE;
        cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL;
index 72c33fbe451d6c31f1b50d0f38ced362d5258210..66d96f14c274e890d26d9435643210f48f7bdd35 100644 (file)
@@ -14,7 +14,7 @@
 static struct of_bus *of_match_bus(struct device_node *np);
 static int __of_address_to_resource(struct device_node *dev,
                const __be32 *addrp, u64 size, unsigned int flags,
-                                   struct resource *r);
+               const char *name, struct resource *r);
 
 /* Debug utility */
 #ifdef DEBUG
@@ -215,7 +215,7 @@ int of_pci_address_to_resource(struct device_node *dev, int bar,
        addrp = of_get_pci_address(dev, bar, &size, &flags);
        if (addrp == NULL)
                return -EINVAL;
-       return __of_address_to_resource(dev, addrp, size, flags, r);
+       return __of_address_to_resource(dev, addrp, size, flags, NULL, r);
 }
 EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
 #endif /* CONFIG_PCI */
@@ -529,7 +529,7 @@ EXPORT_SYMBOL(of_get_address);
 
 static int __of_address_to_resource(struct device_node *dev,
                const __be32 *addrp, u64 size, unsigned int flags,
-                                   struct resource *r)
+               const char *name, struct resource *r)
 {
        u64 taddr;
 
@@ -551,7 +551,8 @@ static int __of_address_to_resource(struct device_node *dev,
                r->end = taddr + size - 1;
        }
        r->flags = flags;
-       r->name = dev->full_name;
+       r->name = name ? name : dev->full_name;
+
        return 0;
 }
 
@@ -569,11 +570,16 @@ int of_address_to_resource(struct device_node *dev, int index,
        const __be32    *addrp;
        u64             size;
        unsigned int    flags;
+       const char      *name = NULL;
 
        addrp = of_get_address(dev, index, &size, &flags);
        if (addrp == NULL)
                return -EINVAL;
-       return __of_address_to_resource(dev, addrp, size, flags, r);
+
+       /* Get optional "reg-names" property to add a name to a resource */
+       of_property_read_string_index(dev, "reg-names", index, &name);
+
+       return __of_address_to_resource(dev, addrp, size, flags, name, r);
 }
 EXPORT_SYMBOL_GPL(of_address_to_resource);
 
index 0f0cfa3bca301e2d824ad64ebdaba23d6c617825..9cf00602f5665b289d1279666504af0010a3fa0f 100644 (file)
@@ -341,9 +341,18 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
        /* Only dereference the resource if both the
         * resource and the irq are valid. */
        if (r && irq) {
+               const char *name = NULL;
+
+               /*
+                * Get optional "interrupts-names" property to add a name
+                * to the resource.
+                */
+               of_property_read_string_index(dev, "interrupt-names", index,
+                                             &name);
+
                r->start = r->end = irq;
                r->flags = IORESOURCE_IRQ;
-               r->name = dev->full_name;
+               r->name = name ? name : dev->full_name;
        }
 
        return irq;
index 0dc34f12f92e5865f22ad503c582f8cf6ba4f88a..d4716273651eb4354a7834304bdf812e69f9c647 100644 (file)
 #define PARPORT_IP32_ENABLE_EPP        (1U << 3)
 #define PARPORT_IP32_ENABLE_ECP        (1U << 4)
 static unsigned int features = ~0U;
-static int verbose_probing =   DEFAULT_VERBOSE_PROBING;
+static bool verbose_probing =  DEFAULT_VERBOSE_PROBING;
 
 /* We do not support more than one port. */
 static struct parport *this_port = NULL;
index d0b597b503983a68f655971970d7392876c3b224..0cb64f50cecde58fc62340e5e457bedf04471b19 100644 (file)
@@ -3404,8 +3404,8 @@ static int __init parport_init_mode_setup(char *str)
 #endif
 
 #ifdef MODULE
-static const char *irq[PARPORT_PC_MAX_PORTS];
-static const char *dma[PARPORT_PC_MAX_PORTS];
+static char *irq[PARPORT_PC_MAX_PORTS];
+static char *dma[PARPORT_PC_MAX_PORTS];
 
 MODULE_PARM_DESC(io, "Base I/O address (SPP regs)");
 module_param_array(io, int, NULL, 0);
index 095f29e13734ad8e830e2614a42b7dc6c5d4a2b8..2a47e82821dacff72dd227950a6c3de828755053 100644 (file)
@@ -44,7 +44,7 @@
 #define        METHOD_NAME__SUN        "_SUN"
 #define        METHOD_NAME_OSHP        "OSHP"
 
-static int debug_acpi;
+static bool debug_acpi;
 
 static acpi_status
 decode_type0_hpx_record(union acpi_object *record, struct hotplug_params *hpx)
index efa9f2de51c1ff532a040037c851c425bf974153..aa41631e9e02139db31203f8b960bc3b46769207 100644 (file)
@@ -47,7 +47,7 @@
 /* name size which is used for entries in pcihpfs */
 #define SLOT_NAME_SIZE  21              /* {_SUN} */
 
-static int debug;
+static bool debug;
 int acpiphp_debug;
 
 /* local variables */
index e525263210ee7e1fa32ba8da010681c1a3863cd4..c35e8ad6db0142f0ddac2b4697cd4edef416cda7 100644 (file)
@@ -43,7 +43,7 @@
 #define DRIVER_AUTHOR  "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"
 #define DRIVER_DESC    "ACPI Hot Plug PCI Controller Driver IBM extension"
 
-static int debug;
+static bool debug;
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
index 41f6a8d79c810ff227a89546539faba754bb7a63..6bf8d2ab164f763739735f65f8e490e39edd787d 100644 (file)
@@ -57,8 +57,8 @@
 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
 
 /* local variables */
-static int debug;
-static int poll;
+static bool debug;
+static bool poll;
 static struct cpci_hp_controller_ops zt5550_hpc_ops;
 static struct cpci_hp_controller zt5550_hpc;
 
index f1ce99cceac60a2135cf8292da0013eebeadb2a1..187a199da93c46c7fe387328bff58f72f7f2b597 100644 (file)
@@ -57,8 +57,8 @@ struct irq_routing_table *cpqhp_routing_table;
 static void __iomem *smbios_table;
 static void __iomem *smbios_start;
 static void __iomem *cpqhp_rom_start;
-static int power_mode;
-static int debug;
+static bool power_mode;
+static bool debug;
 static int initialized;
 
 #define DRIVER_VERSION "0.9.8"
index d934dd4fa87320a6f6e8e1ac278047bc0dbcd572..5506e0e8fbc0055f354705c35bd2276419ba3917 100644 (file)
@@ -49,7 +49,7 @@
 
 int ibmphp_debug;
 
-static int debug;
+static bool debug;
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC (debug, "Debugging mode enabled or not");
 MODULE_LICENSE ("GPL");
index 6d2eea93298fbbcf31afb03cba64b262b228e313..202f4a969eb56614adf540b286844ca9f5a93832 100644 (file)
@@ -51,7 +51,7 @@
 
 
 /* local variables */
-static int debug;
+static bool debug;
 
 #define DRIVER_VERSION "0.5"
 #define DRIVER_AUTHOR  "Greg Kroah-Hartman <greg@kroah.com>, Scott Murray <scottm@somanetworks.com>"
index 9a33fdde2d1639ae5722eef34f37771d01bd6594..4b7cce1de6ec5a11372453399e1b6edcb63cfe66 100644 (file)
 
 #define MY_NAME        "pciehp"
 
-extern int pciehp_poll_mode;
+extern bool pciehp_poll_mode;
 extern int pciehp_poll_time;
-extern int pciehp_debug;
-extern int pciehp_force;
+extern bool pciehp_debug;
+extern bool pciehp_force;
 extern struct workqueue_struct *pciehp_wq;
 
 #define dbg(format, arg...)                                            \
index b8c99d35ac97af9aef83c5e46b9e9337bf7e9610..365c6b96c6421db4885d87fc4f4b5fa9ca607ab4 100644 (file)
 #include <linux/time.h>
 
 /* Global variables */
-int pciehp_debug;
-int pciehp_poll_mode;
+bool pciehp_debug;
+bool pciehp_poll_mode;
 int pciehp_poll_time;
-int pciehp_force;
+bool pciehp_force;
 struct workqueue_struct *pciehp_wq;
 
 #define DRIVER_VERSION "0.4"
index 5175d9b26f0b827f78b405b20bd04a71704a2ab7..b20ceaaa31f4854a4f50c8ebfc8fe7b1acb93e36 100644 (file)
@@ -59,7 +59,7 @@ static LIST_HEAD(slot_list);
 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
 
 /* local variables */
-static int debug;
+static bool debug;
 static int num_slots;
 
 #define DRIVER_VERSION "0.3"
index 419919a87b0fa1d923898728964de310ae4bedb2..df5677440a0844c76a251379a6c0259a839c4027 100644 (file)
@@ -46,7 +46,7 @@
 #define PRESENT         1      /* Card in slot */
 
 #define MY_NAME "rpaphp"
-extern int rpaphp_debug;
+extern bool rpaphp_debug;
 #define dbg(format, arg...)                                    \
        do {                                                    \
                if (rpaphp_debug)                                       \
index 758adb5f47fd9cd729bb96df0c8d19f21a5bb757..127d6e6001858e4955cae3afa92689ee1ac593b6 100644 (file)
@@ -37,7 +37,7 @@
                                /* and pci_do_scan_bus */
 #include "rpaphp.h"
 
-int rpaphp_debug;
+bool rpaphp_debug;
 LIST_HEAD(rpaphp_slot_head);
 
 #define DRIVER_VERSION "0.1"
index e0c90e643b5f457e0bb600aedd298fb1b27a6f8c..ca64932e658b0c5e981c5bb746663045da9cc7ce 100644 (file)
@@ -43,9 +43,9 @@
        #define MY_NAME THIS_MODULE->name
 #endif
 
-extern int shpchp_poll_mode;
+extern bool shpchp_poll_mode;
 extern int shpchp_poll_time;
-extern int shpchp_debug;
+extern bool shpchp_debug;
 extern struct workqueue_struct *shpchp_wq;
 extern struct workqueue_struct *shpchp_ordered_wq;
 
index dd7e0c51a33e5e5f79eb9f11b444fe4667d2ba2d..7414fd9ad1d2f7f46e2cb1436570ca67e33e8568 100644 (file)
@@ -36,8 +36,8 @@
 #include "shpchp.h"
 
 /* Global variables */
-int shpchp_debug;
-int shpchp_poll_mode;
+bool shpchp_debug;
+bool shpchp_poll_mode;
 int shpchp_poll_time;
 struct workqueue_struct *shpchp_wq;
 struct workqueue_struct *shpchp_ordered_wq;
index 106be0d08f81ff7b9306d0ad364b86786349a5fe..a3cd8cad532ac218c2b1055f21e27d6e2bec696e 100644 (file)
@@ -432,7 +432,7 @@ pci_read_config(struct file *filp, struct kobject *kobj,
        u8 *data = (u8*) buf;
 
        /* Several chips lock up trying to read undefined config space */
-       if (security_capable(&init_user_ns, filp->f_cred, CAP_SYS_ADMIN) == 0) {
+       if (security_capable(filp->f_cred, &init_user_ns, CAP_SYS_ADMIN) == 0) {
                size = dev->cfg_size;
        } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
                size = 128;
index 95489cd9a555b451fec790bf098ea279c55adda2..52229863e9fe799a2379ba9ef634837aaadc5a90 100644 (file)
@@ -28,7 +28,7 @@
 #include "aerdrv.h"
 
 /* Override the existing corrected and uncorrected error masks */
-static int aer_mask_override;
+static bool aer_mask_override;
 module_param(aer_mask_override, bool, 0);
 
 struct aer_error_inj {
index 9674e9f30d492671b94250e52dde1825eb1e3f5b..0ca053538146b92d9a80d7e306d05b52a5b3bfc3 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/kfifo.h>
 #include "aerdrv.h"
 
-static int forceload;
-static int nosourceid;
+static bool forceload;
+static bool nosourceid;
 module_param(forceload, bool, 0);
 module_param(nosourceid, bool, 0);
 
index 6e318ce411369176b7d43148656438806f2d316c..f9e3fb3a285b2ab06460542b0d5753e27d2a5dfa 100644 (file)
@@ -155,18 +155,14 @@ config PCMCIA_M8XX
 
          This driver is also available as a module called m8xx_pcmcia.
 
-config PCMCIA_AU1X00
-       tristate "Au1x00 pcmcia support"
-       depends on MIPS_ALCHEMY && PCMCIA
-
 config PCMCIA_ALCHEMY_DEVBOARD
        tristate "Alchemy Db/Pb1xxx PCMCIA socket services"
        depends on MIPS_ALCHEMY && PCMCIA
        select 64BIT_PHYS_ADDR
        help
          Enable this driver of you want PCMCIA support on your Alchemy
-         Db1000, Db/Pb1100, Db/Pb1500, Db/Pb1550, Db/Pb1200 board.
-         NOT suitable for the PB1000!
+         Db1000, Db/Pb1100, Db/Pb1500, Db/Pb1550, Db/Pb1200, DB1300
+         board.  NOT suitable for the PB1000!
 
          This driver is also available as a module called db1xxx_ss.ko
 
index 29935ea921df289e7eae7e5fb0a2e3fe88d261f0..ec543a4ff2e4a5db60113814d4c1fe0d111919d2 100644 (file)
@@ -29,7 +29,6 @@ obj-$(CONFIG_PCMCIA_SA1100)                   += sa11xx_base.o sa1100_cs.o
 obj-$(CONFIG_PCMCIA_SA1111)                    += sa11xx_base.o sa1111_cs.o
 obj-$(CONFIG_M32R_PCC)                         += m32r_pcc.o
 obj-$(CONFIG_M32R_CFC)                         += m32r_cfc.o
-obj-$(CONFIG_PCMCIA_AU1X00)                    += au1x00_ss.o
 obj-$(CONFIG_PCMCIA_BCM63XX)                   += bcm63xx_pcmcia.o
 obj-$(CONFIG_PCMCIA_VRC4171)                   += vrc4171_card.o
 obj-$(CONFIG_PCMCIA_VRC4173)                   += vrc4173_cardu.o
@@ -39,9 +38,6 @@ obj-$(CONFIG_AT91_CF)                         += at91_cf.o
 obj-$(CONFIG_ELECTRA_CF)                       += electra_cf.o
 obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD)          += db1xxx_ss.o
 
-au1x00_ss-y                                    += au1000_generic.o
-au1x00_ss-$(CONFIG_MIPS_PB1000)                        += au1000_pb1x00.o
-
 sa1111_cs-y                                    += sa1111_generic.o
 sa1111_cs-$(CONFIG_ASSABET_NEPONSET)           += sa1100_neponset.o
 sa1111_cs-$(CONFIG_SA1100_BADGE4)              += sa1100_badge4.o
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
deleted file mode 100644 (file)
index 95dd7c6..0000000
+++ /dev/null
@@ -1,545 +0,0 @@
-/*
- *
- * Alchemy Semi Au1000 pcmcia driver
- *
- * Copyright 2001-2003 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *             ppopov@embeddedalley.com or source@mvista.com
- *
- * Copyright 2004 Pete Popov, Embedded Alley Solutions, Inc.
- * Updated the driver to 2.6. Followed the sa11xx API and largely
- * copied many of the hardware independent functions.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- * 
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/notifier.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include <asm/mach-au1x00/au1000.h>
-#include "au1000_generic.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Pete Popov <ppopov@embeddedalley.com>");
-MODULE_DESCRIPTION("Linux PCMCIA Card Services: Au1x00 Socket Controller");
-
-#if 0
-#define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args)
-#else
-#define debug(x,args...)
-#endif
-
-#define MAP_SIZE 0x100000
-extern struct au1000_pcmcia_socket au1000_pcmcia_socket[];
-#define PCMCIA_SOCKET(x)       (au1000_pcmcia_socket + (x))
-#define to_au1000_socket(x)    container_of(x, struct au1000_pcmcia_socket, socket)
-
-/* Some boards like to support CF cards as IDE root devices, so they
- * grab pcmcia sockets directly.
- */
-u32 *pcmcia_base_vaddrs[2];
-extern const unsigned long mips_io_port_base;
-
-static DEFINE_MUTEX(pcmcia_sockets_lock);
-
-static int (*au1x00_pcmcia_hw_init[])(struct device *dev) = {
-       au1x_board_init,
-};
-
-static int
-au1x00_pcmcia_skt_state(struct au1000_pcmcia_socket *skt)
-{
-       struct pcmcia_state state;
-       unsigned int stat;
-
-       memset(&state, 0, sizeof(struct pcmcia_state));
-
-       skt->ops->socket_state(skt, &state);
-
-       stat = state.detect  ? SS_DETECT : 0;
-       stat |= state.ready  ? SS_READY  : 0;
-       stat |= state.wrprot ? SS_WRPROT : 0;
-       stat |= state.vs_3v  ? SS_3VCARD : 0;
-       stat |= state.vs_Xv  ? SS_XVCARD : 0;
-       stat |= skt->cs_state.Vcc ? SS_POWERON : 0;
-
-       if (skt->cs_state.flags & SS_IOCARD)
-               stat |= state.bvd1 ? SS_STSCHG : 0;
-       else {
-               if (state.bvd1 == 0)
-                       stat |= SS_BATDEAD;
-               else if (state.bvd2 == 0)
-                       stat |= SS_BATWARN;
-       }
-       return stat;
-}
-
-/*
- * au100_pcmcia_config_skt
- *
- * Convert PCMCIA socket state to our socket configure structure.
- */
-static int
-au1x00_pcmcia_config_skt(struct au1000_pcmcia_socket *skt, socket_state_t *state)
-{
-       int ret;
-
-       ret = skt->ops->configure_socket(skt, state);
-       if (ret == 0) {
-               skt->cs_state = *state;
-       }
-
-       if (ret < 0)
-               debug("unable to configure socket %d\n", skt->nr);
-
-       return ret;
-}
-
-/* au1x00_pcmcia_sock_init()
- *
- * (Re-)Initialise the socket, turning on status interrupts
- * and PCMCIA bus.  This must wait for power to stabilise
- * so that the card status signals report correctly.
- *
- * Returns: 0
- */
-static int au1x00_pcmcia_sock_init(struct pcmcia_socket *sock)
-{
-       struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
-
-       debug("initializing socket %u\n", skt->nr);
-
-       skt->ops->socket_init(skt);
-       return 0;
-}
-
-/*
- * au1x00_pcmcia_suspend()
- *
- * Remove power on the socket, disable IRQs from the card.
- * Turn off status interrupts, and disable the PCMCIA bus.
- *
- * Returns: 0
- */
-static int au1x00_pcmcia_suspend(struct pcmcia_socket *sock)
-{
-       struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
-
-       debug("suspending socket %u\n", skt->nr);
-
-       skt->ops->socket_suspend(skt);
-
-       return 0;
-}
-
-static DEFINE_SPINLOCK(status_lock);
-
-/*
- * au1x00_check_status()
- */
-static void au1x00_check_status(struct au1000_pcmcia_socket *skt)
-{
-       unsigned int events;
-
-       debug("entering PCMCIA monitoring thread\n");
-
-       do {
-               unsigned int status;
-               unsigned long flags;
-
-               status = au1x00_pcmcia_skt_state(skt);
-
-               spin_lock_irqsave(&status_lock, flags);
-               events = (status ^ skt->status) & skt->cs_state.csc_mask;
-               skt->status = status;
-               spin_unlock_irqrestore(&status_lock, flags);
-
-               debug("events: %s%s%s%s%s%s\n",
-                       events == 0         ? "<NONE>"   : "",
-                       events & SS_DETECT  ? "DETECT "  : "",
-                       events & SS_READY   ? "READY "   : "",
-                       events & SS_BATDEAD ? "BATDEAD " : "",
-                       events & SS_BATWARN ? "BATWARN " : "",
-                       events & SS_STSCHG  ? "STSCHG "  : "");
-
-               if (events)
-                       pcmcia_parse_events(&skt->socket, events);
-       } while (events);
-}
-
-/* 
- * au1x00_pcmcia_poll_event()
- * Let's poll for events in addition to IRQs since IRQ only is unreliable...
- */
-static void au1x00_pcmcia_poll_event(unsigned long dummy)
-{
-       struct au1000_pcmcia_socket *skt = (struct au1000_pcmcia_socket *)dummy;
-       debug("polling for events\n");
-
-       mod_timer(&skt->poll_timer, jiffies + AU1000_PCMCIA_POLL_PERIOD);
-
-       au1x00_check_status(skt);
-}
-
-/* au1x00_pcmcia_get_status()
- *
- * From the sa11xx_core.c:
- * Implements the get_status() operation for the in-kernel PCMCIA
- * service (formerly SS_GetStatus in Card Services). Essentially just
- * fills in bits in `status' according to internal driver state or
- * the value of the voltage detect chipselect register.
- *
- * As a debugging note, during card startup, the PCMCIA core issues
- * three set_socket() commands in a row the first with RESET deasserted,
- * the second with RESET asserted, and the last with RESET deasserted
- * again. Following the third set_socket(), a get_status() command will
- * be issued. The kernel is looking for the SS_READY flag (see
- * setup_socket(), reset_socket(), and unreset_socket() in cs.c).
- *
- * Returns: 0
- */
-static int
-au1x00_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status)
-{
-       struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
-
-       skt->status = au1x00_pcmcia_skt_state(skt);
-       *status = skt->status;
-
-       return 0;
-}
-
-/* au1x00_pcmcia_set_socket()
- * Implements the set_socket() operation for the in-kernel PCMCIA
- * service (formerly SS_SetSocket in Card Services). We more or
- * less punt all of this work and let the kernel handle the details
- * of power configuration, reset, &c. We also record the value of
- * `state' in order to regurgitate it to the PCMCIA core later.
- *
- * Returns: 0
- */
-static int
-au1x00_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
-{
-  struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
-
-  debug("for sock %u\n", skt->nr);
-
-  debug("\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n",
-       (state->csc_mask==0)?"<NONE>":"",
-       (state->csc_mask&SS_DETECT)?"DETECT ":"",
-       (state->csc_mask&SS_READY)?"READY ":"",
-       (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"",
-       (state->csc_mask&SS_BATWARN)?"BATWARN ":"",
-       (state->csc_mask&SS_STSCHG)?"STSCHG ":"",
-       (state->flags==0)?"<NONE>":"",
-       (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"",
-       (state->flags&SS_IOCARD)?"IOCARD ":"",
-       (state->flags&SS_RESET)?"RESET ":"",
-       (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
-       (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"");
-  debug("\tVcc %d  Vpp %d  irq %d\n",
-       state->Vcc, state->Vpp, state->io_irq);
-
-  return au1x00_pcmcia_config_skt(skt, state);
-}
-
-int 
-au1x00_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map)
-{
-       struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
-       unsigned int speed;
-
-       if(map->map>=MAX_IO_WIN){
-               debug("map (%d) out of range\n", map->map);
-               return -1;
-       }
-
-       if(map->flags&MAP_ACTIVE){
-               speed=(map->speed>0)?map->speed:AU1000_PCMCIA_IO_SPEED;
-               skt->spd_io[map->map] = speed;
-       }
-
-       map->start=(unsigned int)(u32)skt->virt_io;
-       map->stop=map->start+MAP_SIZE;
-       return 0;
-
-}  /* au1x00_pcmcia_set_io_map() */
-
-
-static int 
-au1x00_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map)
-{
-       struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
-       unsigned short speed = map->speed;
-
-       if(map->map>=MAX_WIN){
-               debug("map (%d) out of range\n", map->map);
-               return -1;
-       }
-
-       if (map->flags & MAP_ATTRIB) {
-               skt->spd_attr[map->map] = speed;
-               skt->spd_mem[map->map] = 0;
-       } else {
-               skt->spd_attr[map->map] = 0;
-               skt->spd_mem[map->map] = speed;
-       }
-
-       if (map->flags & MAP_ATTRIB) {
-               map->static_start = skt->phys_attr + map->card_start;
-       }
-       else {
-               map->static_start = skt->phys_mem + map->card_start;
-       }
-
-       debug("set_mem_map %d start %08lx card_start %08x\n",
-                       map->map, map->static_start, map->card_start);
-       return 0;
-
-}  /* au1x00_pcmcia_set_mem_map() */
-
-static struct pccard_operations au1x00_pcmcia_operations = {
-       .init                   = au1x00_pcmcia_sock_init,
-       .suspend                = au1x00_pcmcia_suspend,
-       .get_status             = au1x00_pcmcia_get_status,
-       .set_socket             = au1x00_pcmcia_set_socket,
-       .set_io_map             = au1x00_pcmcia_set_io_map,
-       .set_mem_map            = au1x00_pcmcia_set_mem_map,
-};
-
-static const char *skt_names[] = {
-       "PCMCIA socket 0",
-       "PCMCIA socket 1",
-};
-
-struct skt_dev_info {
-       int nskt;
-};
-
-int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr)
-{
-       struct skt_dev_info *sinfo;
-       struct au1000_pcmcia_socket *skt;
-       int ret, i;
-
-       sinfo = kzalloc(sizeof(struct skt_dev_info), GFP_KERNEL);
-       if (!sinfo) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       sinfo->nskt = nr;
-
-       /*
-        * Initialise the per-socket structure.
-        */
-       for (i = 0; i < nr; i++) {
-               skt = PCMCIA_SOCKET(i);
-               memset(skt, 0, sizeof(*skt));
-
-               skt->socket.resource_ops = &pccard_static_ops;
-               skt->socket.ops = &au1x00_pcmcia_operations;
-               skt->socket.owner = ops->owner;
-               skt->socket.dev.parent = dev;
-
-               init_timer(&skt->poll_timer);
-               skt->poll_timer.function = au1x00_pcmcia_poll_event;
-               skt->poll_timer.data = (unsigned long)skt;
-               skt->poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD;
-
-               skt->nr         = first + i;
-               skt->irq        = 255;
-               skt->dev        = dev;
-               skt->ops        = ops;
-
-               skt->res_skt.name       = skt_names[skt->nr];
-               skt->res_io.name        = "io";
-               skt->res_io.flags       = IORESOURCE_MEM | IORESOURCE_BUSY;
-               skt->res_mem.name       = "memory";
-               skt->res_mem.flags      = IORESOURCE_MEM;
-               skt->res_attr.name      = "attribute";
-               skt->res_attr.flags     = IORESOURCE_MEM;
-
-               /*
-                * PCMCIA client drivers use the inb/outb macros to access the
-                * IO registers. Since mips_io_port_base is added to the
-                * access address of the mips implementation of inb/outb,
-                * we need to subtract it here because we want to access the
-                * I/O or MEM address directly, without going through this
-                * "mips_io_port_base" mechanism.
-                */
-               if (i == 0) {
-                       skt->virt_io = (void *)
-                               (ioremap((phys_t)AU1X_SOCK0_IO, 0x1000) -
-                               (u32)mips_io_port_base);
-                       skt->phys_attr = AU1X_SOCK0_PHYS_ATTR;
-                       skt->phys_mem = AU1X_SOCK0_PHYS_MEM;
-               }
-               else  {
-                       skt->virt_io = (void *)
-                               (ioremap((phys_t)AU1X_SOCK1_IO, 0x1000) -
-                               (u32)mips_io_port_base);
-                       skt->phys_attr = AU1X_SOCK1_PHYS_ATTR;
-                       skt->phys_mem = AU1X_SOCK1_PHYS_MEM;
-               }
-               pcmcia_base_vaddrs[i] = (u32 *)skt->virt_io;
-               ret = ops->hw_init(skt);
-
-               skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD;
-               skt->socket.irq_mask = 0;
-               skt->socket.map_size = MAP_SIZE;
-               skt->socket.pci_irq = skt->irq;
-               skt->socket.io_offset = (unsigned long)skt->virt_io;
-
-               skt->status = au1x00_pcmcia_skt_state(skt);
-
-               ret = pcmcia_register_socket(&skt->socket);
-               if (ret)
-                       goto out_err;
-
-               WARN_ON(skt->socket.sock != i);
-
-               add_timer(&skt->poll_timer);
-       }
-
-       dev_set_drvdata(dev, sinfo);
-       return 0;
-
-
-out_err:
-       ops->hw_shutdown(skt);
-       while (i-- > 0) {
-               skt = PCMCIA_SOCKET(i);
-
-               del_timer_sync(&skt->poll_timer);
-               pcmcia_unregister_socket(&skt->socket);
-               if (i == 0) {
-                       iounmap(skt->virt_io + (u32)mips_io_port_base);
-                       skt->virt_io = NULL;
-               }
-#ifndef CONFIG_MIPS_XXS1500
-               else {
-                       iounmap(skt->virt_io + (u32)mips_io_port_base);
-                       skt->virt_io = NULL;
-               }
-#endif
-               ops->hw_shutdown(skt);
-
-       }
-       kfree(sinfo);
-out:
-       return ret;
-}
-
-int au1x00_drv_pcmcia_remove(struct platform_device *dev)
-{
-       struct skt_dev_info *sinfo = platform_get_drvdata(dev);
-       int i;
-
-       mutex_lock(&pcmcia_sockets_lock);
-       platform_set_drvdata(dev, NULL);
-
-       for (i = 0; i < sinfo->nskt; i++) {
-               struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i);
-
-               del_timer_sync(&skt->poll_timer);
-               pcmcia_unregister_socket(&skt->socket);
-               skt->ops->hw_shutdown(skt);
-               au1x00_pcmcia_config_skt(skt, &dead_socket);
-               iounmap(skt->virt_io + (u32)mips_io_port_base);
-               skt->virt_io = NULL;
-       }
-
-       kfree(sinfo);
-       mutex_unlock(&pcmcia_sockets_lock);
-       return 0;
-}
-
-
-/*
- * PCMCIA "Driver" API
- */
-
-static int au1x00_drv_pcmcia_probe(struct platform_device *dev)
-{
-       int i, ret = -ENODEV;
-
-       mutex_lock(&pcmcia_sockets_lock);
-       for (i=0; i < ARRAY_SIZE(au1x00_pcmcia_hw_init); i++) {
-               ret = au1x00_pcmcia_hw_init[i](&dev->dev);
-               if (ret == 0)
-                       break;
-       }
-       mutex_unlock(&pcmcia_sockets_lock);
-       return ret;
-}
-
-static struct platform_driver au1x00_pcmcia_driver = {
-       .driver = {
-               .name           = "au1x00-pcmcia",
-               .owner          = THIS_MODULE,
-       },
-       .probe          = au1x00_drv_pcmcia_probe,
-       .remove         = au1x00_drv_pcmcia_remove,
-};
-
-
-/* au1x00_pcmcia_init()
- *
- * This routine performs low-level PCMCIA initialization and then
- * registers this socket driver with Card Services.
- *
- * Returns: 0 on success, -ve error code on failure
- */
-static int __init au1x00_pcmcia_init(void)
-{
-       int error = 0;
-       error = platform_driver_register(&au1x00_pcmcia_driver);
-       return error;
-}
-
-/* au1x00_pcmcia_exit()
- * Invokes the low-level kernel service to free IRQs associated with this
- * socket controller and reset GPIO edge detection.
- */
-static void __exit au1x00_pcmcia_exit(void)
-{
-       platform_driver_unregister(&au1x00_pcmcia_driver);
-}
-
-module_init(au1x00_pcmcia_init);
-module_exit(au1x00_pcmcia_exit);
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h
deleted file mode 100644 (file)
index 5c36bda..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Alchemy Semi Au1000 pcmcia driver include file
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *             ppopov@mvista.com or source@mvista.com
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-#ifndef __ASM_AU1000_PCMCIA_H
-#define __ASM_AU1000_PCMCIA_H
-
-/* include the world */
-
-#include <pcmcia/ss.h>
-#include <pcmcia/cistpl.h>
-#include "cs_internal.h"
-
-#define AU1000_PCMCIA_POLL_PERIOD    (2*HZ)
-#define AU1000_PCMCIA_IO_SPEED       (255)
-#define AU1000_PCMCIA_MEM_SPEED      (300)
-
-#define AU1X_SOCK0_IO        0xF00000000ULL
-#define AU1X_SOCK0_PHYS_ATTR 0xF40000000ULL
-#define AU1X_SOCK0_PHYS_MEM  0xF80000000ULL
-
-/* pcmcia socket 1 needs external glue logic so the memory map
- * differs from board to board.
- */
-#if defined(CONFIG_MIPS_PB1000)
-#define AU1X_SOCK1_IO        0xF08000000ULL
-#define AU1X_SOCK1_PHYS_ATTR 0xF48000000ULL
-#define AU1X_SOCK1_PHYS_MEM  0xF88000000ULL
-#endif
-
-struct pcmcia_state {
-  unsigned detect: 1,
-            ready: 1,
-           wrprot: 1,
-            bvd1: 1,
-            bvd2: 1,
-            vs_3v: 1,
-            vs_Xv: 1;
-};
-
-struct pcmcia_configure {
-  unsigned sock: 8,
-            vcc: 8,
-            vpp: 8,
-         output: 1,
-        speaker: 1,
-          reset: 1;
-};
-
-struct pcmcia_irqs {
-       int sock;
-       int irq;
-       const char *str;
-};
-
-
-struct au1000_pcmcia_socket {
-       struct pcmcia_socket socket;
-
-       /*
-        * Info from low level handler
-        */
-       struct device           *dev;
-       unsigned int            nr;
-       unsigned int            irq;
-
-       /*
-        * Core PCMCIA state
-        */
-       struct pcmcia_low_level *ops;
-
-       unsigned int            status;
-       socket_state_t          cs_state;
-
-       unsigned short          spd_io[MAX_IO_WIN];
-       unsigned short          spd_mem[MAX_WIN];
-       unsigned short          spd_attr[MAX_WIN];
-
-       struct resource         res_skt;
-       struct resource         res_io;
-       struct resource         res_mem;
-       struct resource         res_attr;
-
-       void *                  virt_io;
-       unsigned int            phys_io;
-       unsigned int            phys_attr;
-       unsigned int            phys_mem;
-       unsigned short          speed_io, speed_attr, speed_mem;
-
-       unsigned int            irq_state;
-
-       struct timer_list       poll_timer;
-};
-
-struct pcmcia_low_level {
-       struct module *owner;
-
-       int (*hw_init)(struct au1000_pcmcia_socket *);
-       void (*hw_shutdown)(struct au1000_pcmcia_socket *);
-
-       void (*socket_state)(struct au1000_pcmcia_socket *, struct pcmcia_state *);
-       int (*configure_socket)(struct au1000_pcmcia_socket *, struct socket_state_t *);
-
-       /*
-        * Enable card status IRQs on (re-)initialisation.  This can
-        * be called at initialisation, power management event, or
-        * pcmcia event.
-        */
-       void (*socket_init)(struct au1000_pcmcia_socket *);
-
-       /*
-        * Disable card status IRQs and PCMCIA bus on suspend.
-        */
-       void (*socket_suspend)(struct au1000_pcmcia_socket *);
-};
-
-extern int au1x_board_init(struct device *dev);
-
-#endif /* __ASM_AU1000_PCMCIA_H */
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
deleted file mode 100644 (file)
index b239664..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- *
- * Alchemy Semi Pb1000 boards specific pcmcia routines.
- *
- * Copyright 2002 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *             ppopov@mvista.com or source@mvista.com
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/proc_fs.h>
-#include <linux/types.h>
-
-#include <pcmcia/ss.h>
-#include <pcmcia/cistpl.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include <asm/au1000.h>
-#include <asm/au1000_pcmcia.h>
-
-#define debug(fmt, arg...) do { } while (0)
-
-#include <asm/pb1000.h>
-#define PCMCIA_IRQ AU1000_GPIO_15
-
-static int pb1x00_pcmcia_init(struct pcmcia_init *init)
-{
-       u16 pcr;
-       pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
-
-       au_writel(0x8000, PB1000_MDR); /* clear pcmcia interrupt */
-       au_sync_delay(100);
-       au_writel(0x4000, PB1000_MDR); /* enable pcmcia interrupt */
-       au_sync();
-
-       pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0);
-       pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1);
-       au_writel(pcr, PB1000_PCR);
-       au_sync_delay(20);
-         
-       return PCMCIA_NUM_SOCKS;
-}
-
-static int pb1x00_pcmcia_shutdown(void)
-{
-       u16 pcr;
-       pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
-       pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0);
-       pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1);
-       au_writel(pcr, PB1000_PCR);
-       au_sync_delay(20);
-       return 0;
-}
-
-static int 
-pb1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
-{
-       u32 inserted0, inserted1;
-       u16 vs0, vs1;
-
-       vs0 = vs1 = (u16)au_readl(PB1000_ACR1);
-       inserted0 = !(vs0 & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2));
-       inserted1 = !(vs1 & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2));
-       vs0 = (vs0 >> 4) & 0x3;
-       vs1 = (vs1 >> 12) & 0x3;
-
-       state->ready = 0;
-       state->vs_Xv = 0;
-       state->vs_3v = 0;
-       state->detect = 0;
-
-       if (sock == 0) {
-               if (inserted0) {
-                       switch (vs0) {
-                               case 0:
-                               case 2:
-                                       state->vs_3v=1;
-                                       break;
-                               case 3: /* 5V */
-                                       break;
-                               default:
-                                       /* return without setting 'detect' */
-                                       printk(KERN_ERR "pb1x00 bad VS (%d)\n",
-                                                       vs0);
-                                       return 0;
-                       }
-                       state->detect = 1;
-               }
-       }
-       else  {
-               if (inserted1) {
-                       switch (vs1) {
-                               case 0:
-                               case 2:
-                                       state->vs_3v=1;
-                                       break;
-                               case 3: /* 5V */
-                                       break;
-                               default:
-                                       /* return without setting 'detect' */
-                                       printk(KERN_ERR "pb1x00 bad VS (%d)\n",
-                                                       vs1);
-                                       return 0;
-                       }
-                       state->detect = 1;
-               }
-       }
-
-       if (state->detect) {
-               state->ready = 1;
-       }
-
-       state->bvd1=1;
-       state->bvd2=1;
-       state->wrprot=0; 
-       return 1;
-}
-
-
-static int pb1x00_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
-{
-
-       if(info->sock > PCMCIA_MAX_SOCK) return -1;
-
-       /*
-        * Even in the case of the Pb1000, both sockets are connected
-        * to the same irq line.
-        */
-       info->irq = PCMCIA_IRQ;
-
-       return 0;
-}
-
-
-static int 
-pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
-{
-       u16 pcr;
-
-       if(configure->sock > PCMCIA_MAX_SOCK) return -1;
-
-       pcr = au_readl(PB1000_PCR);
-
-       if (configure->sock == 0) {
-               pcr &= ~(PCR_SLOT_0_VCC0 | PCR_SLOT_0_VCC1 | 
-                               PCR_SLOT_0_VPP0 | PCR_SLOT_0_VPP1);
-       }
-       else  {
-               pcr &= ~(PCR_SLOT_1_VCC0 | PCR_SLOT_1_VCC1 | 
-                               PCR_SLOT_1_VPP0 | PCR_SLOT_1_VPP1);
-       }
-
-       pcr &= ~PCR_SLOT_0_RST;
-       debug("Vcc %dV Vpp %dV, pcr %x\n", 
-                       configure->vcc, configure->vpp, pcr);
-       switch(configure->vcc){
-               case 0:  /* Vcc 0 */
-                       switch(configure->vpp) {
-                               case 0:
-                                       pcr |= SET_VCC_VPP(VCC_HIZ,VPP_GND,
-                                                       configure->sock);
-                                       break;
-                               case 12:
-                                       pcr |= SET_VCC_VPP(VCC_HIZ,VPP_12V,
-                                                       configure->sock);
-                                       break;
-                               case 50:
-                                       pcr |= SET_VCC_VPP(VCC_HIZ,VPP_5V,
-                                                       configure->sock);
-                                       break;
-                               case 33:
-                                       pcr |= SET_VCC_VPP(VCC_HIZ,VPP_3V,
-                                                       configure->sock);
-                                       break;
-                               default:
-                                       pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
-                                                       configure->sock);
-                                       printk("%s: bad Vcc/Vpp (%d:%d)\n", 
-                                                       __func__,
-                                                       configure->vcc, 
-                                                       configure->vpp);
-                                       break;
-                       }
-                       break;
-               case 50: /* Vcc 5V */
-                       switch(configure->vpp) {
-                               case 0:
-                                       pcr |= SET_VCC_VPP(VCC_5V,VPP_GND,
-                                                       configure->sock);
-                                       break;
-                               case 50:
-                                       pcr |= SET_VCC_VPP(VCC_5V,VPP_5V,
-                                                       configure->sock);
-                                       break;
-                               case 12:
-                                       pcr |= SET_VCC_VPP(VCC_5V,VPP_12V,
-                                                       configure->sock);
-                                       break;
-                               case 33:
-                                       pcr |= SET_VCC_VPP(VCC_5V,VPP_3V,
-                                                       configure->sock);
-                                       break;
-                               default:
-                                       pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
-                                                       configure->sock);
-                                       printk("%s: bad Vcc/Vpp (%d:%d)\n", 
-                                                       __func__,
-                                                       configure->vcc, 
-                                                       configure->vpp);
-                                       break;
-                       }
-                       break;
-               case 33: /* Vcc 3.3V */
-                       switch(configure->vpp) {
-                               case 0:
-                                       pcr |= SET_VCC_VPP(VCC_3V,VPP_GND,
-                                                       configure->sock);
-                                       break;
-                               case 50:
-                                       pcr |= SET_VCC_VPP(VCC_3V,VPP_5V,
-                                                       configure->sock);
-                                       break;
-                               case 12:
-                                       pcr |= SET_VCC_VPP(VCC_3V,VPP_12V,
-                                                       configure->sock);
-                                       break;
-                               case 33:
-                                       pcr |= SET_VCC_VPP(VCC_3V,VPP_3V,
-                                                       configure->sock);
-                                       break;
-                               default:
-                                       pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
-                                                       configure->sock);
-                                       printk("%s: bad Vcc/Vpp (%d:%d)\n", 
-                                                       __func__,
-                                                       configure->vcc, 
-                                                       configure->vpp);
-                                       break;
-                       }
-                       break;
-               default: /* what's this ? */
-                       pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock);
-                       printk(KERN_ERR "%s: bad Vcc %d\n", 
-                                       __func__, configure->vcc);
-                       break;
-       }
-
-       if (configure->sock == 0) {
-       pcr &= ~(PCR_SLOT_0_RST);
-               if (configure->reset)
-               pcr |= PCR_SLOT_0_RST;
-       }
-       else {
-               pcr &= ~(PCR_SLOT_1_RST);
-               if (configure->reset)
-                       pcr |= PCR_SLOT_1_RST;
-       }
-       au_writel(pcr, PB1000_PCR);
-       au_sync_delay(300);
-
-       return 0;
-}
-
-
-struct pcmcia_low_level pb1x00_pcmcia_ops = { 
-       pb1x00_pcmcia_init,
-       pb1x00_pcmcia_shutdown,
-       pb1x00_pcmcia_socket_state,
-       pb1x00_pcmcia_get_irq_info,
-       pb1x00_pcmcia_configure_socket
-};
index 3e49df6d5e3b0dec58ef7fab3ce0a74d0e37e965..5b7c22784aff9713054b5b3f34d3ff9bed9ad91d 100644 (file)
@@ -7,7 +7,7 @@
 
 /* This is a fairly generic PCMCIA socket driver suitable for the
  * following Alchemy Development boards:
- *  Db1000, Db/Pb1500, Db/Pb1100, Db/Pb1550, Db/Pb1200.
+ *  Db1000, Db/Pb1500, Db/Pb1100, Db/Pb1550, Db/Pb1200, Db1300
  *
  * The Db1000 is used as a reference:  Per-socket card-, carddetect- and
  *  statuschange IRQs connected to SoC GPIOs, control and status register
@@ -18,6 +18,7 @@
  *     - Pb1100/Pb1500:  single socket only; voltage key bits VS are
  *                       at STATUS[5:4] (instead of STATUS[1:0]).
  *     - Au1200-based:   additional card-eject irqs, irqs not gpios!
+ *     - Db1300:         Db1200-like, no pwr ctrl, single socket (#1).
  */
 
 #include <linux/delay.h>
@@ -59,11 +60,17 @@ struct db1x_pcmcia_sock {
 #define BOARD_TYPE_DEFAULT     0       /* most boards */
 #define BOARD_TYPE_DB1200      1       /* IRQs aren't gpios */
 #define BOARD_TYPE_PB1100      2       /* VS bits slightly different */
+#define BOARD_TYPE_DB1300      3       /* no power control */
        int     board_type;
 };
 
 #define to_db1x_socket(x) container_of(x, struct db1x_pcmcia_sock, socket)
 
+static int db1300_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+       return bcsr_read(BCSR_SIGSTAT) & (1 << 8);
+}
+
 /* DB/PB1200: check CPLD SIGSTATUS register bit 10/12 */
 static int db1200_card_inserted(struct db1x_pcmcia_sock *sock)
 {
@@ -84,6 +91,8 @@ static int db1x_card_inserted(struct db1x_pcmcia_sock *sock)
        switch (sock->board_type) {
        case BOARD_TYPE_DB1200:
                return db1200_card_inserted(sock);
+       case BOARD_TYPE_DB1300:
+               return db1300_card_inserted(sock);
        default:
                return db1000_card_inserted(sock);
        }
@@ -160,7 +169,8 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
         * ejection handler have been registered and the currently
         * active one disabled.
         */
-       if (sock->board_type == BOARD_TYPE_DB1200) {
+       if ((sock->board_type == BOARD_TYPE_DB1200) ||
+           (sock->board_type == BOARD_TYPE_DB1300)) {
                ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq,
                                  IRQF_DISABLED, "pcmcia_insert", sock);
                if (ret)
@@ -174,7 +184,7 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
                }
 
                /* enable the currently silent one */
-               if (db1200_card_inserted(sock))
+               if (db1x_card_inserted(sock))
                        enable_irq(sock->eject_irq);
                else
                        enable_irq(sock->insert_irq);
@@ -270,7 +280,8 @@ static int db1x_pcmcia_configure(struct pcmcia_socket *skt,
        }
 
        /* create new voltage code */
-       cr_set |= ((v << 2) | p) << (sock->nr * 8);
+       if (sock->board_type != BOARD_TYPE_DB1300)
+               cr_set |= ((v << 2) | p) << (sock->nr * 8);
 
        changed = state->flags ^ sock->old_flags;
 
@@ -343,6 +354,10 @@ static int db1x_pcmcia_get_status(struct pcmcia_socket *skt,
        /* if Vcc is not zero, we have applied power to a card */
        status |= GET_VCC(cr, sock->nr) ? SS_POWERON : 0;
 
+       /* DB1300: power always on, but don't tell when no card present */
+       if ((sock->board_type == BOARD_TYPE_DB1300) && (status & SS_DETECT))
+               status = SS_POWERON | SS_3VCARD | SS_DETECT;
+
        /* reset de-asserted? then we're ready */
        status |= (GET_RESET(cr, sock->nr)) ? SS_READY : SS_RESET;
 
@@ -419,6 +434,9 @@ static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev)
        case BCSR_WHOAMI_PB1200 ... BCSR_WHOAMI_DB1200:
                sock->board_type = BOARD_TYPE_DB1200;
                break;
+       case BCSR_WHOAMI_DB1300:
+               sock->board_type = BOARD_TYPE_DB1300;
+               break;
        default:
                printk(KERN_INFO "db1xxx-ss: unknown board %d!\n", bid);
                ret = -ENODEV;
index 9dc565c615bdf3cd7117a929281a636ce3285cf4..849c0c11d2af84797ca686d6cf3f85cf3ba5de89 100644 (file)
 #include "yenta_socket.h"
 #include "i82365.h"
 
-static int disable_clkrun;
+static bool disable_clkrun;
 module_param(disable_clkrun, bool, 0444);
 MODULE_PARM_DESC(disable_clkrun, "If PC card doesn't function properly, please try this option");
 
-static int isa_probe = 1;
+static bool isa_probe = 1;
 module_param(isa_probe, bool, 0444);
 MODULE_PARM_DESC(isa_probe, "If set ISA interrupts are probed (default). Set to N to disable probing");
 
-static int pwr_irqs_off;
+static bool pwr_irqs_off;
 module_param(pwr_irqs_off, bool, 0644);
 MODULE_PARM_DESC(pwr_irqs_off, "Force IRQs off during power-on of slot. Use only when seeing IRQ storms!");
 
index 8877b836d27cf4bde02014d9a37763a3672bb4a0..d96734478324b77d28a314858fa1c889a70977b7 100644 (file)
@@ -189,7 +189,7 @@ struct compal_data{
 /* =============== */
 /* General globals */
 /* =============== */
-static int force;
+static bool force;
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
 
index 7f88c7923fc6ab18ad8bc674da4ee96411bbf2fc..6ee0b5c909330849836c7c22dfd6713da62e25ab 100644 (file)
@@ -95,7 +95,7 @@
 #define OT_EC_BL_CONTROL_ON_DATA       0x1A
 
 
-static int force;
+static bool force;
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
 
index f204643c5052640908063b07e0288263ca8f8548..bb5132128b339235f599969d75a692bd4099dfce 100644 (file)
@@ -89,7 +89,7 @@ static int msi_laptop_resume(struct platform_device *device);
 
 #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
 
-static int force;
+static bool force;
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
 
index 09e26bfd464343766a3bfcff39d4b6e0a306f179..fd73ea89b857872df7526c5c756872b3b9402f64 100644 (file)
@@ -228,12 +228,12 @@ static struct platform_device *sdev;
 static struct rfkill *rfk;
 static bool has_stepping_quirk;
 
-static int force;
+static bool force;
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force,
                "Disable the DMI check and forces the driver to be loaded");
 
-static int debug;
+static bool debug;
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
index 62533c105da40369d7d940b0deba4115f5f6bf7c..ea0c6075b72012458f099bfd6fb013415e7d85e1 100644 (file)
@@ -378,13 +378,13 @@ static unsigned int bright_maxlvl;        /* 0 = unknown */
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
 static int dbg_wlswemul;
-static int tpacpi_wlsw_emulstate;
+static bool tpacpi_wlsw_emulstate;
 static int dbg_bluetoothemul;
-static int tpacpi_bluetooth_emulstate;
+static bool tpacpi_bluetooth_emulstate;
 static int dbg_wwanemul;
-static int tpacpi_wwan_emulstate;
+static bool tpacpi_wwan_emulstate;
 static int dbg_uwbemul;
-static int tpacpi_uwb_emulstate;
+static bool tpacpi_uwb_emulstate;
 #endif
 
 
@@ -6444,7 +6444,7 @@ static struct ibm_struct brightness_driver_data = {
 
 static int alsa_index = ~((1 << (SNDRV_CARDS - 3)) - 1); /* last three slots */
 static char *alsa_id = "ThinkPadEC";
-static int alsa_enable = SNDRV_DEFAULT_ENABLE1;
+static bool alsa_enable = SNDRV_DEFAULT_ENABLE1;
 
 struct tpacpi_alsa_data {
        struct snd_card *card;
@@ -6487,7 +6487,7 @@ static enum tpacpi_volume_access_mode volume_mode =
        TPACPI_VOL_MODE_MAX;
 
 static enum tpacpi_volume_capabilities volume_capabilities;
-static int volume_control_allowed;
+static bool volume_control_allowed;
 
 /*
  * Used to syncronize writers to TP_EC_AUDIO and
@@ -7265,7 +7265,7 @@ enum fan_control_commands {
                                                 * and also watchdog cmd */
 };
 
-static int fan_control_allowed;
+static bool fan_control_allowed;
 
 static enum fan_status_access_mode fan_status_access_mode;
 static enum fan_control_access_mode fan_control_access_mode;
@@ -8437,7 +8437,7 @@ static struct proc_dir_entry *proc_dir;
  * Module and infrastructure proble, init and exit handling
  */
 
-static int force_load;
+static bool force_load;
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUG
 static const char * __init str_supported(int is_supported)
index a134c26870b0d048929fc9eb6fe07e1e7172e35c..42a4dcc25f92ae0cfacc127b6310594bda477e25 100644 (file)
@@ -82,12 +82,12 @@ struct wmi_block {
 #define ACPI_WMI_STRING      0x4       /* GUID takes & returns a string */
 #define ACPI_WMI_EVENT       0x8       /* GUID is an event */
 
-static int debug_event;
+static bool debug_event;
 module_param(debug_event, bool, 0444);
 MODULE_PARM_DESC(debug_event,
                 "Log WMI Events [0/1]");
 
-static int debug_dump_wdg;
+static bool debug_dump_wdg;
 module_param(debug_dump_wdg, bool, 0444);
 MODULE_PARM_DESC(debug_dump_wdg,
                 "Dump available WMI interfaces [0/1]");
index 545874b1df9ebfa4d14bdb2b4b04f07f274cb77e..076e211a40b7111e864d591cba0400ff7042b6ad 100644 (file)
@@ -64,7 +64,7 @@ static unsigned int cache_time = 1000;
 module_param(cache_time, uint, 0644);
 MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
 
-static unsigned int pmod_enabled;
+static bool pmod_enabled;
 module_param(pmod_enabled, bool, 0644);
 MODULE_PARM_DESC(pmod_enabled, "PMOD enable bit");
 
index e91b8ddc2793120b9e4e3697aa6912ab4358d2e2..c9b92531ae601a75e4dd54f9f206d00b6fd11e54 100644 (file)
@@ -16,8 +16,8 @@
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/ab8500.h>
 #include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/ab8500.h>
index a0a9810adf0b91646aeed789020575c4d00f214e..4bcf9ca2818ae740eadd016df48cc0461da23f6e 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/rtc.h>
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/delay.h>
 
 #define AB8500_RTC_SOFF_STAT_REG       0x00
index 4a5529346b47465528e1cddcce6bb9007d0ff4bd..2d71943bc436ad9719d364d99361dd62f92268eb 100644 (file)
@@ -261,6 +261,8 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev)
        /* XXX - isn't this redundant? */
        platform_set_drvdata(pdev, info);
 
+       device_init_wakeup(&pdev->dev, 1);
+
        info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev,
                                        &max8925_rtc_ops, THIS_MODULE);
        ret = PTR_ERR(info->rtc_dev);
@@ -290,10 +292,34 @@ static int __devexit max8925_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int max8925_rtc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+       if (device_may_wakeup(dev))
+               chip->wakeup_flag |= 1 << MAX8925_IRQ_RTC_ALARM0;
+       return 0;
+}
+static int max8925_rtc_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+       if (device_may_wakeup(dev))
+               chip->wakeup_flag &= ~(1 << MAX8925_IRQ_RTC_ALARM0);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max8925_rtc_pm_ops, max8925_rtc_suspend, max8925_rtc_resume);
+
 static struct platform_driver max8925_rtc_driver = {
        .driver         = {
                .name   = "max8925-rtc",
                .owner  = THIS_MODULE,
+               .pm     = &max8925_rtc_pm_ops,
        },
        .probe          = max8925_rtc_probe,
        .remove         = __devexit_p(max8925_rtc_remove),
index e5cb9248a442a5d67f574302aa76aa8904d1812a..f3b8bb84faf295013c03c1d4e539ee967015fa2a 100644 (file)
@@ -75,7 +75,7 @@ static LIST_HEAD(raw3270_devices);
 static int raw3270_registered;
 
 /* Module parameters */
-static int tubxcorrect = 0;
+static bool tubxcorrect = 0;
 module_param(tubxcorrect, bool, 0);
 
 /*
index 11312f401c704823832060fc93019a0c061e20d7..2211277a10793201936b3c7253958149972723ec 100644 (file)
@@ -28,9 +28,9 @@
 #define MAX_CMDLEN 240
 #define MIN_INTERVAL 15
 static char vmwdt_cmd[MAX_CMDLEN] = "IPL";
-static int vmwdt_conceal;
+static bool vmwdt_conceal;
 
-static int vmwdt_nowayout = WATCHDOG_NOWAYOUT;
+static bool vmwdt_nowayout = WATCHDOG_NOWAYOUT;
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
index 2985eb43948512bc11cc95ec701c4b25537cd8c3..204ca728e7fd8c097591f1b81541238a57681814 100644 (file)
@@ -98,7 +98,7 @@ enum cmb_format {
  * enum cmb_format.
  */
 static int format = CMF_AUTODETECT;
-module_param(format, bool, 0444);
+module_param(format, bint, 0444);
 
 /**
  * struct cmb_operations - functions to use depending on cmb_format
index 8af868bab20b52f9e2c11d4266a977c79ff99c01..7bc1955337ead5eecac17adc14021f9f5f843cd6 100644 (file)
@@ -198,7 +198,7 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
                goto out;
 
        vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN,
-                                vdev, (void *) config->address,
+                                vdev, true, (void *) config->address,
                                 kvm_notify, callback, name);
        if (!vq) {
                err = -ENOMEM;
index 06ea3bcfdd2a3064f462592bbed67ca4b24e9c7e..16570aa84aac0e1e420a541d7224ecfd0e567bbc 100644 (file)
@@ -830,16 +830,11 @@ config SCSI_ISCI
        tristate "Intel(R) C600 Series Chipset SAS Controller"
        depends on PCI && SCSI
        depends on X86
-       # (temporary): known alpha quality driver
-       depends on EXPERIMENTAL
        select SCSI_SAS_LIBSAS
-       select SCSI_SAS_HOST_SMP
        ---help---
          This driver supports the 6Gb/s SAS capabilities of the storage
          control unit found in the Intel(R) C600 series chipset.
 
-         The experimental tag will be removed after the driver exits alpha
-
 config SCSI_GENERIC_NCR5380
        tristate "Generic NCR5380/53c400 SCSI PIO support"
        depends on ISA && SCSI
index 195823a51aab5292e6ec43183d0e0829b6d9ff93..ed119cedaae008354128e6a2cbe9fc129ad736b2 100644 (file)
@@ -102,7 +102,7 @@ static int setup_dmaspeed[MAXBOARDS] __initdata = { -1, -1, -1, -1 };
  */
 
 #if defined(MODULE)
-static int isapnp = 0;
+static bool isapnp = 0;
 static int aha1542[] = {0x330, 11, 4, -1};
 module_param_array(aha1542, int, NULL, 0);
 module_param(isapnp, bool, 0);
index 78963be2c4fb308f09df6f38b3cf5097b3bb5f53..cb07c628b2f1856a3a26dadba052e2587edd3ae7 100644 (file)
@@ -673,12 +673,7 @@ struct bfa_itnim_iostats_s {
        u32     tm_iocdowns;            /*  TM cleaned-up due to IOC down   */
        u32     tm_cleanups;            /*  TM cleanup requests */
        u32     tm_cleanup_comps;       /*  TM cleanup completions      */
-       u32     lm_lun_across_sg;       /*  LM lun is across sg data buf */
-       u32     lm_lun_not_sup;         /*  LM lun not supported */
-       u32     lm_rpl_data_changed;    /*  LM report-lun data changed */
-       u32     lm_wire_residue_changed; /* LM report-lun rsp residue changed */
-       u32     lm_small_buf_addresidue; /* LM buf smaller than reported cnt */
-       u32     lm_lun_not_rdy;         /* LM lun not ready */
+       u32     rsvd[6];
 };
 
 /* Modify char* port_stt[] in bfal_port.c if a new state was added */
index 50b6a1c86195ac6d6c394295fcdd8150dbd43852..8d0b88f67a382e3582c40382d7dfe3892a19f3c8 100644 (file)
@@ -56,161 +56,6 @@ struct scsi_cdb_s {
 
 #define SCSI_MAX_ALLOC_LEN      0xFF    /* maximum allocarion length */
 
-#define SCSI_SENSE_CUR_ERR     0x70
-#define SCSI_SENSE_DEF_ERR     0x71
-
-/*
- * SCSI additional sense codes
- */
-#define SCSI_ASC_LUN_NOT_READY         0x04
-#define SCSI_ASC_LUN_NOT_SUPPORTED     0x25
-#define SCSI_ASC_TOCC                  0x3F
-
-/*
- * SCSI additional sense code qualifiers
- */
-#define SCSI_ASCQ_MAN_INTR_REQ         0x03    /* manual intervention req */
-#define SCSI_ASCQ_RL_DATA_CHANGED      0x0E    /* report luns data changed */
-
-/*
- * Methods of reporting informational exceptions
- */
-#define SCSI_MP_IEC_UNIT_ATTN          0x2     /* generate unit attention */
-
-struct scsi_report_luns_data_s {
-       u32             lun_list_length;        /* length of LUN list length */
-       u32             reserved;
-       struct scsi_lun lun[1];                 /* first LUN in lun list */
-};
-
-struct scsi_inquiry_vendor_s {
-       u8      vendor_id[8];
-};
-
-struct scsi_inquiry_prodid_s {
-       u8      product_id[16];
-};
-
-struct scsi_inquiry_prodrev_s {
-       u8      product_rev[4];
-};
-
-struct scsi_inquiry_data_s {
-#ifdef __BIG_ENDIAN
-       u8              peripheral_qual:3;      /* peripheral qualifier */
-       u8              device_type:5;          /* peripheral device type */
-       u8              rmb:1;                  /* removable medium bit */
-       u8              device_type_mod:7;      /* device type modifier */
-       u8              version;
-       u8              aenc:1;         /* async evt notification capability */
-       u8              trm_iop:1;      /* terminate I/O process */
-       u8              norm_aca:1;     /* normal ACA supported */
-       u8              hi_support:1;   /* SCSI-3: supports REPORT LUNS */
-       u8              rsp_data_format:4;
-       u8              additional_len;
-       u8              sccs:1;
-       u8              reserved1:7;
-       u8              reserved2:1;
-       u8              enc_serv:1;     /* enclosure service component */
-       u8              reserved3:1;
-       u8              multi_port:1;   /* multi-port device */
-       u8              m_chngr:1;      /* device in medium transport element */
-       u8              ack_req_q:1;    /* SIP specific bit */
-       u8              addr32:1;       /* SIP specific bit */
-       u8              addr16:1;       /* SIP specific bit */
-       u8              rel_adr:1;      /* relative address */
-       u8              w_bus32:1;
-       u8              w_bus16:1;
-       u8              synchronous:1;
-       u8              linked_commands:1;
-       u8              trans_dis:1;
-       u8              cmd_queue:1;    /* command queueing supported */
-       u8              soft_reset:1;   /* soft reset alternative (VS) */
-#else
-       u8              device_type:5;  /* peripheral device type */
-       u8              peripheral_qual:3; /* peripheral qualifier */
-       u8              device_type_mod:7; /* device type modifier */
-       u8              rmb:1;          /* removable medium bit */
-       u8              version;
-       u8              rsp_data_format:4;
-       u8              hi_support:1;   /* SCSI-3: supports REPORT LUNS */
-       u8              norm_aca:1;     /* normal ACA supported */
-       u8              terminate_iop:1;/* terminate I/O process */
-       u8              aenc:1;         /* async evt notification capability */
-       u8              additional_len;
-       u8              reserved1:7;
-       u8              sccs:1;
-       u8              addr16:1;       /* SIP specific bit */
-       u8              addr32:1;       /* SIP specific bit */
-       u8              ack_req_q:1;    /* SIP specific bit */
-       u8              m_chngr:1;      /* device in medium transport element */
-       u8              multi_port:1;   /* multi-port device */
-       u8              reserved3:1;    /* TBD - Vendor Specific */
-       u8              enc_serv:1;     /* enclosure service component */
-       u8              reserved2:1;
-       u8              soft_seset:1;   /* soft reset alternative (VS) */
-       u8              cmd_queue:1;    /* command queueing supported */
-       u8              trans_dis:1;
-       u8              linked_commands:1;
-       u8              synchronous:1;
-       u8              w_bus16:1;
-       u8              w_bus32:1;
-       u8              rel_adr:1;      /* relative address */
-#endif
-       struct scsi_inquiry_vendor_s    vendor_id;
-       struct scsi_inquiry_prodid_s    product_id;
-       struct scsi_inquiry_prodrev_s   product_rev;
-       u8              vendor_specific[20];
-       u8              reserved4[40];
-};
-
-/*
- *     SCSI sense data format
- */
-struct scsi_sense_s {
-#ifdef __BIG_ENDIAN
-       u8              valid:1;
-       u8              rsp_code:7;
-#else
-       u8              rsp_code:7;
-       u8              valid:1;
-#endif
-       u8              seg_num;
-#ifdef __BIG_ENDIAN
-       u8              file_mark:1;
-       u8              eom:1;          /* end of media */
-       u8              ili:1;          /* incorrect length indicator */
-       u8              reserved:1;
-       u8              sense_key:4;
-#else
-       u8              sense_key:4;
-       u8              reserved:1;
-       u8              ili:1;          /* incorrect length indicator */
-       u8              eom:1;          /* end of media */
-       u8              file_mark:1;
-#endif
-       u8              information[4]; /* device-type or cmd specific info */
-       u8              add_sense_length; /* additional sense length */
-       u8              command_info[4];/* command specific information */
-       u8              asc;            /* additional sense code */
-       u8              ascq;           /* additional sense code qualifier */
-       u8              fru_code;       /* field replaceable unit code */
-#ifdef __BIG_ENDIAN
-       u8              sksv:1;         /* sense key specific valid */
-       u8              c_d:1;          /* command/data bit */
-       u8              res1:2;
-       u8              bpv:1;          /* bit pointer valid */
-       u8              bpointer:3;     /* bit pointer */
-#else
-       u8              bpointer:3;     /* bit pointer */
-       u8              bpv:1;          /* bit pointer valid */
-       u8              res1:2;
-       u8              c_d:1;          /* command/data bit */
-       u8              sksv:1;         /* sense key specific valid */
-#endif
-       u8              fpointer[2];    /* field pointer */
-};
-
 /*
  * Fibre Channel Header Structure (FCHS) definition
  */
index e07bd4745d8ba5b968ded24e81785096c1535b84..f0f80e282e39cc023a72dacef7ee23b09c06a79e 100644 (file)
@@ -24,8 +24,6 @@ BFA_TRC_FILE(HAL, FCPIM);
  *  BFA ITNIM Related definitions
  */
 static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim);
-static bfa_boolean_t bfa_ioim_lm_proc_rpl_data(struct bfa_ioim_s *ioim);
-static bfa_boolean_t bfa_ioim_lm_proc_inq_data(struct bfa_ioim_s *ioim);
 static void bfa_ioim_lm_init(struct bfa_s *bfa);
 
 #define BFA_ITNIM_FROM_TAG(_fcpim, _tag)                                \
@@ -60,14 +58,6 @@ static void bfa_ioim_lm_init(struct bfa_s *bfa);
        }                                                               \
 } while (0)
 
-#define bfa_ioim_rp_wwn(__ioim)                                                \
-       (((struct bfa_fcs_rport_s *)                                    \
-        (__ioim)->itnim->rport->rport_drv)->pwwn)
-
-#define bfa_ioim_lp_wwn(__ioim)                                                \
-       ((BFA_LPS_FROM_TAG(BFA_LPS_MOD((__ioim)->bfa),                  \
-       (__ioim)->itnim->rport->rport_info.lp_tag))->pwwn)              \
-
 #define bfa_itnim_sler_cb(__itnim) do {                                        \
        if ((__itnim)->bfa->fcs)                                        \
                bfa_cb_itnim_sler((__itnim)->ditn);      \
@@ -77,13 +67,6 @@ static void bfa_ioim_lm_init(struct bfa_s *bfa);
        }                                                               \
 } while (0)
 
-enum bfa_ioim_lm_status {
-       BFA_IOIM_LM_PRESENT = 1,
-       BFA_IOIM_LM_LUN_NOT_SUP = 2,
-       BFA_IOIM_LM_RPL_DATA_CHANGED = 3,
-       BFA_IOIM_LM_LUN_NOT_RDY = 4,
-};
-
 enum bfa_ioim_lm_ua_status {
        BFA_IOIM_LM_UA_RESET = 0,
        BFA_IOIM_LM_UA_SET = 1,
@@ -145,9 +128,6 @@ enum bfa_ioim_event {
        BFA_IOIM_SM_TMDONE      = 16,   /*  IO cleanup from tskim */
        BFA_IOIM_SM_HWFAIL      = 17,   /*  IOC h/w failure event */
        BFA_IOIM_SM_IOTOV       = 18,   /*  ITN offline TOV */
-       BFA_IOIM_SM_LM_LUN_NOT_SUP = 19,/*  lunmask lun not supported */
-       BFA_IOIM_SM_LM_RPL_DC = 20,     /*  lunmask report-lun data changed */
-       BFA_IOIM_SM_LM_LUN_NOT_RDY = 21,/*  lunmask lun not ready */
 };
 
 
@@ -245,9 +225,6 @@ static void __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete);
 static void __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete);
 static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete);
 static bfa_boolean_t    bfa_ioim_is_abortable(struct bfa_ioim_s *ioim);
-static void __bfa_cb_ioim_lm_lun_not_sup(void *cbarg, bfa_boolean_t complete);
-static void __bfa_cb_ioim_lm_rpl_dc(void *cbarg, bfa_boolean_t complete);
-static void __bfa_cb_ioim_lm_lun_not_rdy(void *cbarg, bfa_boolean_t complete);
 
 /*
  * forward declaration of BFA IO state machine
@@ -445,12 +422,6 @@ bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *lstats,
        bfa_fcpim_add_iostats(lstats, rstats, output_reqs);
        bfa_fcpim_add_iostats(lstats, rstats, rd_throughput);
        bfa_fcpim_add_iostats(lstats, rstats, wr_throughput);
-       bfa_fcpim_add_iostats(lstats, rstats, lm_lun_across_sg);
-       bfa_fcpim_add_iostats(lstats, rstats, lm_lun_not_sup);
-       bfa_fcpim_add_iostats(lstats, rstats, lm_rpl_data_changed);
-       bfa_fcpim_add_iostats(lstats, rstats, lm_wire_residue_changed);
-       bfa_fcpim_add_iostats(lstats, rstats, lm_small_buf_addresidue);
-       bfa_fcpim_add_iostats(lstats, rstats, lm_lun_not_rdy);
 }
 
 bfa_status_t
@@ -1580,27 +1551,6 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                        __bfa_cb_ioim_abort, ioim);
                break;
 
-       case BFA_IOIM_SM_LM_LUN_NOT_SUP:
-               bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
-               bfa_ioim_move_to_comp_q(ioim);
-               bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
-                       __bfa_cb_ioim_lm_lun_not_sup, ioim);
-               break;
-
-       case BFA_IOIM_SM_LM_RPL_DC:
-               bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
-               bfa_ioim_move_to_comp_q(ioim);
-               bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
-                               __bfa_cb_ioim_lm_rpl_dc, ioim);
-               break;
-
-       case BFA_IOIM_SM_LM_LUN_NOT_RDY:
-               bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
-               bfa_ioim_move_to_comp_q(ioim);
-               bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
-                       __bfa_cb_ioim_lm_lun_not_rdy, ioim);
-               break;
-
        default:
                bfa_sm_fault(ioim->bfa, event);
        }
@@ -2160,243 +2110,6 @@ bfa_ioim_lm_init(struct bfa_s *bfa)
        }
 }
 
-/*
- * Validate LUN for LUN masking
- */
-static enum bfa_ioim_lm_status
-bfa_ioim_lm_check(struct bfa_ioim_s *ioim, struct bfa_lps_s *lps,
-               struct bfa_rport_s *rp, struct scsi_lun lun)
-{
-       u8 i;
-       struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa);
-       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio;
-       struct scsi_cdb_s *cdb = (struct scsi_cdb_s *)cmnd->cmnd;
-
-       if ((cdb->scsi_cdb[0] == REPORT_LUNS) &&
-           (scsilun_to_int((struct scsi_lun *)&lun) == 0)) {
-               ioim->proc_rsp_data = bfa_ioim_lm_proc_rpl_data;
-               return BFA_IOIM_LM_PRESENT;
-       }
-
-       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
-
-               if (lun_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE)
-                       continue;
-
-               if ((scsilun_to_int((struct scsi_lun *)&lun_list[i].lun) ==
-                   scsilun_to_int((struct scsi_lun *)&lun))
-                   && (rp->rport_tag == lun_list[i].rp_tag)
-                   && ((u8)ioim->itnim->rport->rport_info.lp_tag ==
-                                               lun_list[i].lp_tag)) {
-                       bfa_trc(ioim->bfa, lun_list[i].rp_tag);
-                       bfa_trc(ioim->bfa, lun_list[i].lp_tag);
-                       bfa_trc(ioim->bfa, scsilun_to_int(
-                               (struct scsi_lun *)&lun_list[i].lun));
-
-                       if ((lun_list[i].ua == BFA_IOIM_LM_UA_SET) &&
-                           ((cdb->scsi_cdb[0] != INQUIRY) ||
-                           (cdb->scsi_cdb[0] != REPORT_LUNS))) {
-                               lun_list[i].ua = BFA_IOIM_LM_UA_RESET;
-                               return BFA_IOIM_LM_RPL_DATA_CHANGED;
-                       }
-
-                       if (cdb->scsi_cdb[0] == REPORT_LUNS)
-                               ioim->proc_rsp_data = bfa_ioim_lm_proc_rpl_data;
-
-                       return BFA_IOIM_LM_PRESENT;
-               }
-       }
-
-       if ((cdb->scsi_cdb[0] == INQUIRY) &&
-           (scsilun_to_int((struct scsi_lun *)&lun) == 0)) {
-               ioim->proc_rsp_data = bfa_ioim_lm_proc_inq_data;
-               return BFA_IOIM_LM_PRESENT;
-       }
-
-       if (cdb->scsi_cdb[0] == TEST_UNIT_READY)
-               return BFA_IOIM_LM_LUN_NOT_RDY;
-
-       return BFA_IOIM_LM_LUN_NOT_SUP;
-}
-
-static bfa_boolean_t
-bfa_ioim_lm_proc_rsp_data_dummy(struct bfa_ioim_s *ioim)
-{
-       return BFA_TRUE;
-}
-
-static void
-bfa_ioim_lm_fetch_lun(struct bfa_ioim_s *ioim, u8 *rl_data, int offset,
-               int buf_lun_cnt)
-{
-       struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa);
-       struct scsi_lun *lun_data = (struct scsi_lun *)(rl_data + offset);
-       struct scsi_lun lun;
-       int i, j;
-
-       bfa_trc(ioim->bfa, buf_lun_cnt);
-       for (j = 0; j < buf_lun_cnt; j++) {
-               lun = *((struct scsi_lun *)(lun_data + j));
-               for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
-                       if (lun_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE)
-                               continue;
-                       if ((lun_list[i].rp_wwn == bfa_ioim_rp_wwn(ioim)) &&
-                           (lun_list[i].lp_wwn == bfa_ioim_lp_wwn(ioim)) &&
-                           (scsilun_to_int((struct scsi_lun *)&lun_list[i].lun)
-                               == scsilun_to_int((struct scsi_lun *)&lun))) {
-                               lun_list[i].state = BFA_IOIM_LUN_MASK_FETCHED;
-                               break;
-                       }
-               } /* next lun in mask DB */
-       } /* next lun in buf */
-}
-
-static int
-bfa_ioim_lm_update_lun_sg(struct bfa_ioim_s *ioim, u32 *pgdlen,
-               struct scsi_report_luns_data_s *rl)
-{
-       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio;
-       struct scatterlist *sg = scsi_sglist(cmnd);
-       struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa);
-       struct scsi_lun *prev_rl_data = NULL, *base_rl_data;
-       int i, j, sgeid, lun_fetched_cnt = 0, prev_sg_len = 0, base_count;
-       int lun_across_sg_bytes, bytes_from_next_buf;
-       u64     last_lun, temp_last_lun;
-
-       /* fetch luns from the first sg element */
-       bfa_ioim_lm_fetch_lun(ioim, (u8 *)(rl->lun), 0,
-                       (sg_dma_len(sg) / sizeof(struct scsi_lun)) - 1);
-
-       /* fetch luns from multiple sg elements */
-       scsi_for_each_sg(cmnd, sg, scsi_sg_count(cmnd), sgeid) {
-               if (sgeid == 0) {
-                       prev_sg_len = sg_dma_len(sg);
-                       prev_rl_data = (struct scsi_lun *)
-                                       phys_to_virt(sg_dma_address(sg));
-                       continue;
-               }
-
-               /* if the buf is having more data */
-               lun_across_sg_bytes = prev_sg_len % sizeof(struct scsi_lun);
-               if (lun_across_sg_bytes) {
-                       bfa_trc(ioim->bfa, lun_across_sg_bytes);
-                       bfa_stats(ioim->itnim, lm_lun_across_sg);
-                       bytes_from_next_buf = sizeof(struct scsi_lun) -
-                                             lun_across_sg_bytes;
-
-                       /* from next buf take higher bytes */
-                       temp_last_lun = *((u64 *)
-                                         phys_to_virt(sg_dma_address(sg)));
-                       last_lun |= temp_last_lun >>
-                                   (lun_across_sg_bytes * BITS_PER_BYTE);
-
-                       /* from prev buf take higher bytes */
-                       temp_last_lun = *((u64 *)(prev_rl_data +
-                                         (prev_sg_len - lun_across_sg_bytes)));
-                       temp_last_lun >>= bytes_from_next_buf * BITS_PER_BYTE;
-                       last_lun = last_lun | (temp_last_lun <<
-                                  (bytes_from_next_buf * BITS_PER_BYTE));
-
-                       bfa_ioim_lm_fetch_lun(ioim, (u8 *)&last_lun, 0, 1);
-               } else
-                       bytes_from_next_buf = 0;
-
-               *pgdlen += sg_dma_len(sg);
-               prev_sg_len = sg_dma_len(sg);
-               prev_rl_data = (struct scsi_lun *)
-                               phys_to_virt(sg_dma_address(sg));
-               bfa_ioim_lm_fetch_lun(ioim, (u8 *)prev_rl_data,
-                               bytes_from_next_buf,
-                               sg_dma_len(sg) / sizeof(struct scsi_lun));
-       }
-
-       /* update the report luns data - based on fetched luns */
-       sg = scsi_sglist(cmnd);
-       base_rl_data = (struct scsi_lun *)rl->lun;
-       base_count = (sg_dma_len(sg) / sizeof(struct scsi_lun)) - 1;
-       for (i = 0, j = 0; i < MAX_LUN_MASK_CFG; i++) {
-               if (lun_list[i].state == BFA_IOIM_LUN_MASK_FETCHED) {
-                       base_rl_data[j] = lun_list[i].lun;
-                       lun_list[i].state = BFA_IOIM_LUN_MASK_ACTIVE;
-                       j++;
-                       lun_fetched_cnt++;
-               }
-
-               if (j > base_count) {
-                       j = 0;
-                       sg = sg_next(sg);
-                       base_rl_data = (struct scsi_lun *)
-                                       phys_to_virt(sg_dma_address(sg));
-                       base_count = sg_dma_len(sg) / sizeof(struct scsi_lun);
-               }
-       }
-
-       bfa_trc(ioim->bfa, lun_fetched_cnt);
-       return lun_fetched_cnt;
-}
-
-static bfa_boolean_t
-bfa_ioim_lm_proc_inq_data(struct bfa_ioim_s *ioim)
-{
-       struct scsi_inquiry_data_s *inq;
-       struct scatterlist *sg = scsi_sglist((struct scsi_cmnd *)ioim->dio);
-
-       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
-       inq = (struct scsi_inquiry_data_s *)phys_to_virt(sg_dma_address(sg));
-
-       bfa_trc(ioim->bfa, inq->device_type);
-       inq->peripheral_qual = SCSI_INQ_PQ_NOT_CON;
-       return 0;
-}
-
-static bfa_boolean_t
-bfa_ioim_lm_proc_rpl_data(struct bfa_ioim_s *ioim)
-{
-       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio;
-       struct scatterlist *sg = scsi_sglist(cmnd);
-       struct bfi_ioim_rsp_s *m;
-       struct scsi_report_luns_data_s *rl = NULL;
-       int lun_count = 0, lun_fetched_cnt = 0;
-       u32 residue, pgdlen = 0;
-
-       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
-       if (bfa_get_lun_mask_status(ioim->bfa) != BFA_LUNMASK_ENABLED)
-               return BFA_TRUE;
-
-       m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg;
-       if (m->scsi_status == SCSI_STATUS_CHECK_CONDITION)
-               return BFA_TRUE;
-
-       pgdlen = sg_dma_len(sg);
-       bfa_trc(ioim->bfa, pgdlen);
-       rl = (struct scsi_report_luns_data_s *)phys_to_virt(sg_dma_address(sg));
-       lun_count = cpu_to_be32(rl->lun_list_length) / sizeof(struct scsi_lun);
-       lun_fetched_cnt = bfa_ioim_lm_update_lun_sg(ioim, &pgdlen, rl);
-
-       if (lun_count == lun_fetched_cnt)
-               return BFA_TRUE;
-
-       bfa_trc(ioim->bfa, lun_count);
-       bfa_trc(ioim->bfa, lun_fetched_cnt);
-       bfa_trc(ioim->bfa, be32_to_cpu(rl->lun_list_length));
-
-       if (be32_to_cpu(rl->lun_list_length) <= pgdlen)
-               rl->lun_list_length = be32_to_cpu(lun_fetched_cnt) *
-                                     sizeof(struct scsi_lun);
-       else
-               bfa_stats(ioim->itnim, lm_small_buf_addresidue);
-
-       bfa_trc(ioim->bfa, be32_to_cpu(rl->lun_list_length));
-       bfa_trc(ioim->bfa, be32_to_cpu(m->residue));
-
-       residue = be32_to_cpu(m->residue);
-       residue += (lun_count - lun_fetched_cnt) * sizeof(struct scsi_lun);
-       bfa_stats(ioim->itnim, lm_wire_residue_changed);
-       m->residue = be32_to_cpu(residue);
-       bfa_trc(ioim->bfa, ioim->nsges);
-       return BFA_FALSE;
-}
-
 static void
 __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete)
 {
@@ -2454,83 +2167,6 @@ __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete)
                          m->scsi_status, sns_len, snsinfo, residue);
 }
 
-static void
-__bfa_cb_ioim_lm_lun_not_sup(void *cbarg, bfa_boolean_t complete)
-{
-       struct bfa_ioim_s *ioim = cbarg;
-       int sns_len = 0xD;
-       u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio);
-       struct scsi_sense_s *snsinfo;
-
-       if (!complete) {
-               bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
-               return;
-       }
-
-       snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG(
-                                       ioim->fcpim->fcp, ioim->iotag);
-       snsinfo->rsp_code = SCSI_SENSE_CUR_ERR;
-       snsinfo->add_sense_length = 0xa;
-       snsinfo->asc = SCSI_ASC_LUN_NOT_SUPPORTED;
-       snsinfo->sense_key = ILLEGAL_REQUEST;
-       bfa_trc(ioim->bfa, residue);
-       bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK,
-                       SCSI_STATUS_CHECK_CONDITION, sns_len,
-                       (u8 *)snsinfo, residue);
-}
-
-static void
-__bfa_cb_ioim_lm_rpl_dc(void *cbarg, bfa_boolean_t complete)
-{
-       struct bfa_ioim_s *ioim = cbarg;
-       int sns_len = 0xD;
-       u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio);
-       struct scsi_sense_s *snsinfo;
-
-       if (!complete) {
-               bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
-               return;
-       }
-
-       snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG(ioim->fcpim->fcp,
-                                                      ioim->iotag);
-       snsinfo->rsp_code = SCSI_SENSE_CUR_ERR;
-       snsinfo->sense_key = SCSI_MP_IEC_UNIT_ATTN;
-       snsinfo->asc = SCSI_ASC_TOCC;
-       snsinfo->add_sense_length = 0x6;
-       snsinfo->ascq = SCSI_ASCQ_RL_DATA_CHANGED;
-       bfa_trc(ioim->bfa, residue);
-       bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK,
-                       SCSI_STATUS_CHECK_CONDITION, sns_len,
-                       (u8 *)snsinfo, residue);
-}
-
-static void
-__bfa_cb_ioim_lm_lun_not_rdy(void *cbarg, bfa_boolean_t complete)
-{
-       struct bfa_ioim_s *ioim = cbarg;
-       int sns_len = 0xD;
-       u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio);
-       struct scsi_sense_s *snsinfo;
-
-       if (!complete) {
-               bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
-               return;
-       }
-
-       snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG(
-                                       ioim->fcpim->fcp, ioim->iotag);
-       snsinfo->rsp_code = SCSI_SENSE_CUR_ERR;
-       snsinfo->add_sense_length = 0xa;
-       snsinfo->sense_key = NOT_READY;
-       snsinfo->asc = SCSI_ASC_LUN_NOT_READY;
-       snsinfo->ascq = SCSI_ASCQ_MAN_INTR_REQ;
-       bfa_trc(ioim->bfa, residue);
-       bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK,
-                       SCSI_STATUS_CHECK_CONDITION, sns_len,
-                       (u8 *)snsinfo, residue);
-}
-
 void
 bfa_fcpim_lunmask_rp_update(struct bfa_s *bfa, wwn_t lp_wwn, wwn_t rp_wwn,
                        u16 rp_tag, u8 lp_tag)
@@ -2647,7 +2283,8 @@ bfa_fcpim_lunmask_add(struct bfa_s *bfa, u16 vf_id, wwn_t *pwwn,
        if (port) {
                *pwwn = port->port_cfg.pwwn;
                rp_fcs = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn);
-               rp = rp_fcs->bfa_rport;
+               if (rp_fcs)
+                       rp = rp_fcs->bfa_rport;
        }
 
        lunm_list = bfa_get_lun_mask_list(bfa);
@@ -2715,7 +2352,8 @@ bfa_fcpim_lunmask_delete(struct bfa_s *bfa, u16 vf_id, wwn_t *pwwn,
                if (port) {
                        *pwwn = port->port_cfg.pwwn;
                        rp_fcs = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn);
-                       rp = rp_fcs->bfa_rport;
+                       if (rp_fcs)
+                               rp = rp_fcs->bfa_rport;
                }
        }
 
@@ -2757,7 +2395,6 @@ __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete)
                return;
        }
 
-       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
        bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_ABORTED,
                          0, 0, NULL, 0);
 }
@@ -2773,7 +2410,6 @@ __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete)
                return;
        }
 
-       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
        bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_PATHTOV,
                          0, 0, NULL, 0);
 }
@@ -2788,7 +2424,6 @@ __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete)
                return;
        }
 
-       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
        bfa_cb_ioim_abort(ioim->bfa->bfad, ioim->dio);
 }
 
@@ -3132,7 +2767,6 @@ bfa_ioim_attach(struct bfa_fcpim_s *fcpim)
                ioim->bfa     = fcpim->bfa;
                ioim->fcpim   = fcpim;
                ioim->iosp    = iosp;
-               ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
                INIT_LIST_HEAD(&ioim->sgpg_q);
                bfa_reqq_winit(&ioim->iosp->reqq_wait,
                                   bfa_ioim_qresume, ioim);
@@ -3170,7 +2804,6 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
                        evt = BFA_IOIM_SM_DONE;
                else
                        evt = BFA_IOIM_SM_COMP;
-               ioim->proc_rsp_data(ioim);
                break;
 
        case BFI_IOIM_STS_TIMEDOUT:
@@ -3206,7 +2839,6 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
                if (rsp->abort_tag != ioim->abort_tag) {
                        bfa_trc(ioim->bfa, rsp->abort_tag);
                        bfa_trc(ioim->bfa, ioim->abort_tag);
-                       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
                        return;
                }
 
@@ -3225,7 +2857,6 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
                WARN_ON(1);
        }
 
-       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
        bfa_sm_send_event(ioim, evt);
 }
 
@@ -3244,15 +2875,7 @@ bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
 
        bfa_ioim_cb_profile_comp(fcpim, ioim);
 
-       if (bfa_get_lun_mask_status(bfa) != BFA_LUNMASK_ENABLED)  {
-               bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
-               return;
-       }
-
-       if (ioim->proc_rsp_data(ioim) == BFA_TRUE)
-               bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
-       else
-               bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP);
+       bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
 }
 
 /*
@@ -3364,35 +2987,6 @@ bfa_ioim_free(struct bfa_ioim_s *ioim)
 void
 bfa_ioim_start(struct bfa_ioim_s *ioim)
 {
-       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio;
-       struct bfa_lps_s        *lps;
-       enum bfa_ioim_lm_status status;
-       struct scsi_lun scsilun;
-
-       if (bfa_get_lun_mask_status(ioim->bfa) == BFA_LUNMASK_ENABLED) {
-               lps = BFA_IOIM_TO_LPS(ioim);
-               int_to_scsilun(cmnd->device->lun, &scsilun);
-               status = bfa_ioim_lm_check(ioim, lps,
-                               ioim->itnim->rport, scsilun);
-               if (status == BFA_IOIM_LM_LUN_NOT_RDY) {
-                       bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_LUN_NOT_RDY);
-                       bfa_stats(ioim->itnim, lm_lun_not_rdy);
-                       return;
-               }
-
-               if (status == BFA_IOIM_LM_LUN_NOT_SUP) {
-                       bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_LUN_NOT_SUP);
-                       bfa_stats(ioim->itnim, lm_lun_not_sup);
-                       return;
-               }
-
-               if (status == BFA_IOIM_LM_RPL_DATA_CHANGED) {
-                       bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_RPL_DC);
-                       bfa_stats(ioim->itnim, lm_rpl_data_changed);
-                       return;
-               }
-       }
-
        bfa_ioim_cb_profile_start(ioim->fcpim, ioim);
 
        /*
index 1080bcb81cb73a2caf409d800da3b78deed8234f..36f26da80f76c1c496ec20bc1e42ae93e878df11 100644 (file)
@@ -110,7 +110,6 @@ struct bfad_ioim_s;
 struct bfad_tskim_s;
 
 typedef void    (*bfa_fcpim_profile_t) (struct bfa_ioim_s *ioim);
-typedef bfa_boolean_t (*bfa_ioim_lm_proc_rsp_data_t) (struct bfa_ioim_s *ioim);
 
 struct bfa_fcpim_s {
        struct bfa_s            *bfa;
@@ -124,7 +123,6 @@ struct bfa_fcpim_s {
        u32                     path_tov;
        u16                     q_depth;
        u8                      reqq;           /*  Request queue to be used */
-       u8                      lun_masking_pending;
        struct list_head        itnim_q;        /*  queue of active itnim */
        struct list_head        ioim_resfree_q; /*  IOs waiting for f/w */
        struct list_head        ioim_comp_q;    /*  IO global comp Q    */
@@ -181,7 +179,6 @@ struct bfa_ioim_s {
        u8                      reqq;           /*  Request queue for I/O */
        u8                      mode;           /*  IO is passthrough or not */
        u64                     start_time;     /*  IO's Profile start val */
-       bfa_ioim_lm_proc_rsp_data_t proc_rsp_data; /* RSP data adjust */
 };
 
 struct bfa_ioim_sp_s {
@@ -261,10 +258,6 @@ struct bfa_itnim_s {
        (__ioim)->iotag |= k << BFA_IOIM_RETRY_TAG_OFFSET;              \
 } while (0)
 
-#define BFA_IOIM_TO_LPS(__ioim)                \
-       BFA_LPS_FROM_TAG(BFA_LPS_MOD(__ioim->bfa),      \
-               __ioim->itnim->rport->rport_info.lp_tag)
-
 static inline bfa_boolean_t
 bfa_ioim_maxretry_reached(struct bfa_ioim_s *ioim)
 {
index 95adb86d3769d477bdbf0b652aa704621eca665b..b52cbb6bcd5a3b6b4c7623753df79630892686ea 100644 (file)
@@ -582,11 +582,6 @@ void bfa_cb_rport_qos_scn_prio(void *rport,
 #define BFA_LP_TAG_INVALID     0xff
 void   bfa_rport_set_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp);
 void   bfa_rport_unset_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp);
-bfa_boolean_t  bfa_rport_lunmask_active(struct bfa_rport_s *rp);
-wwn_t  bfa_rport_get_pwwn(struct bfa_s *bfa, struct bfa_rport_s *rp);
-struct bfa_rport_s *bfa_rport_get_by_wwn(struct bfa_s *bfa, u16 vf_id,
-                                        wwn_t *lpwwn, wwn_t rpwwn);
-void *bfa_cb_get_rp_by_wwn(void *arg, u16 vf_id, wwn_t *lpwwn, wwn_t rpwwn);
 
 /*
  * bfa fcxp API functions
index 66fb72531b34caab0323797761d68ac2ab0e6fbc..404fd10ddb21cd6b89821694807e402d30e3bf21 100644 (file)
@@ -674,6 +674,7 @@ bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
 
        spin_lock_irqsave(&bfad->bfad_lock, flags);
        bfa_fcs_vport_start(&vport->fcs_vport);
+       list_add_tail(&vport->list_entry, &bfad->vport_list);
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 
        return BFA_STATUS_OK;
@@ -1404,6 +1405,7 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
        bfad->ref_count = 0;
        bfad->pport.bfad = bfad;
        INIT_LIST_HEAD(&bfad->pbc_vport_list);
+       INIT_LIST_HEAD(&bfad->vport_list);
 
        /* Setup the debugfs node for this bfad */
        if (bfa_debugfs_enable)
index 9d95844ab463ededc29b22e417d413e912b7cc48..1938fe0473e99b9aa24a5ee6e50a4e6fe9e9ac4d 100644 (file)
@@ -491,7 +491,7 @@ bfad_im_vport_delete(struct fc_vport *fc_vport)
 
 free_scsi_host:
        bfad_scsi_host_free(bfad, im_port);
-
+       list_del(&vport->list_entry);
        kfree(vport);
 
        return 0;
index 06fc00caeb41f725750a1ddafd44b5731e7eaa4a..530de2b1200a20c58b0e88a49c299ed97c2d1126 100644 (file)
@@ -2394,6 +2394,21 @@ out:
        return 0;
 }
 
+/* Function to reset the LUN SCAN mode */
+static void
+bfad_iocmd_lunmask_reset_lunscan_mode(struct bfad_s *bfad, int lunmask_cfg)
+{
+       struct bfad_im_port_s *pport_im = bfad->pport.im_port;
+       struct bfad_vport_s *vport = NULL;
+
+       /* Set the scsi device LUN SCAN flags for base port */
+       bfad_reset_sdev_bflags(pport_im, lunmask_cfg);
+
+       /* Set the scsi device LUN SCAN flags for the vports */
+       list_for_each_entry(vport, &bfad->vport_list, list_entry)
+               bfad_reset_sdev_bflags(vport->drv_port.im_port, lunmask_cfg);
+}
+
 int
 bfad_iocmd_lunmask(struct bfad_s *bfad, void *pcmd, unsigned int v_cmd)
 {
@@ -2401,11 +2416,17 @@ bfad_iocmd_lunmask(struct bfad_s *bfad, void *pcmd, unsigned int v_cmd)
        unsigned long   flags;
 
        spin_lock_irqsave(&bfad->bfad_lock, flags);
-       if (v_cmd == IOCMD_FCPIM_LUNMASK_ENABLE)
+       if (v_cmd == IOCMD_FCPIM_LUNMASK_ENABLE) {
                iocmd->status = bfa_fcpim_lunmask_update(&bfad->bfa, BFA_TRUE);
-       else if (v_cmd == IOCMD_FCPIM_LUNMASK_DISABLE)
+               /* Set the LUN Scanning mode to be Sequential scan */
+               if (iocmd->status == BFA_STATUS_OK)
+                       bfad_iocmd_lunmask_reset_lunscan_mode(bfad, BFA_TRUE);
+       } else if (v_cmd == IOCMD_FCPIM_LUNMASK_DISABLE) {
                iocmd->status = bfa_fcpim_lunmask_update(&bfad->bfa, BFA_FALSE);
-       else if (v_cmd == IOCMD_FCPIM_LUNMASK_CLEAR)
+               /* Set the LUN Scanning mode to default REPORT_LUNS scan */
+               if (iocmd->status == BFA_STATUS_OK)
+                       bfad_iocmd_lunmask_reset_lunscan_mode(bfad, BFA_FALSE);
+       } else if (v_cmd == IOCMD_FCPIM_LUNMASK_CLEAR)
                iocmd->status = bfa_fcpim_lunmask_clear(&bfad->bfa);
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
        return 0;
index 5e19a5f820ec6d515773ec942ff4ba1d9184608e..dc5b9d99c4505f1356f7e0bed16d05bd992285ef 100644 (file)
@@ -43,6 +43,7 @@
 #include <scsi/scsi_transport_fc.h>
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_bsg_fc.h>
+#include <scsi/scsi_devinfo.h>
 
 #include "bfa_modules.h"
 #include "bfa_fcs.h"
@@ -227,6 +228,7 @@ struct bfad_s {
        struct list_head        active_aen_q;
        struct bfa_aen_entry_s  aen_list[BFA_AEN_MAX_ENTRY];
        spinlock_t              bfad_aen_spinlock;
+       struct list_head        vport_list;
 };
 
 /* BFAD state machine events */
index e5db649e8eb757dbe79241645c024734d76dd21a..3153923f5b6027f1c16d806e14092e1df5356218 100644 (file)
@@ -917,6 +917,37 @@ bfad_get_itnim(struct bfad_im_port_s *im_port, int id)
        return NULL;
 }
 
+/*
+ * Function is invoked from the SCSI Host Template slave_alloc() entry point.
+ * Has the logic to query the LUN Mask database to check if this LUN needs to
+ * be made visible to the SCSI mid-layer or not.
+ *
+ * Returns BFA_STATUS_OK if this LUN needs to be added to the OS stack.
+ * Returns -ENXIO to notify SCSI mid-layer to not add this LUN to the OS stack.
+ */
+static int
+bfad_im_check_if_make_lun_visible(struct scsi_device *sdev,
+                                 struct fc_rport *rport)
+{
+       struct bfad_itnim_data_s *itnim_data =
+                               (struct bfad_itnim_data_s *) rport->dd_data;
+       struct bfa_s *bfa = itnim_data->itnim->bfa_itnim->bfa;
+       struct bfa_rport_s *bfa_rport = itnim_data->itnim->bfa_itnim->rport;
+       struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(bfa);
+       int i = 0, ret = -ENXIO;
+
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if (lun_list[i].state == BFA_IOIM_LUN_MASK_ACTIVE &&
+                   scsilun_to_int(&lun_list[i].lun) == sdev->lun &&
+                   lun_list[i].rp_tag == bfa_rport->rport_tag &&
+                   lun_list[i].lp_tag == (u8)bfa_rport->rport_info.lp_tag) {
+                       ret = BFA_STATUS_OK;
+                       break;
+               }
+       }
+       return ret;
+}
+
 /*
  * Scsi_Host template entry slave_alloc
  */
@@ -924,10 +955,33 @@ static int
 bfad_im_slave_alloc(struct scsi_device *sdev)
 {
        struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
+       struct bfad_itnim_data_s *itnim_data =
+                               (struct bfad_itnim_data_s *) rport->dd_data;
+       struct bfa_s *bfa = itnim_data->itnim->bfa_itnim->bfa;
 
        if (!rport || fc_remote_port_chkready(rport))
                return -ENXIO;
 
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_ENABLED) {
+               /*
+                * We should not mask LUN 0 - since this will translate
+                * to no LUN / TARGET for SCSI ml resulting no scan.
+                */
+               if (sdev->lun == 0) {
+                       sdev->sdev_bflags |= BLIST_NOREPORTLUN |
+                                            BLIST_SPARSELUN;
+                       goto done;
+               }
+
+               /*
+                * Query LUN Mask configuration - to expose this LUN
+                * to the SCSI mid-layer or to mask it.
+                */
+               if (bfad_im_check_if_make_lun_visible(sdev, rport) !=
+                                                       BFA_STATUS_OK)
+                       return -ENXIO;
+       }
+done:
        sdev->hostdata = rport->dd_data;
 
        return 0;
@@ -1037,6 +1091,8 @@ bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim)
            && (fc_rport->scsi_target_id < MAX_FCP_TARGET))
                itnim->scsi_tgt_id = fc_rport->scsi_target_id;
 
+       itnim->channel = fc_rport->channel;
+
        return;
 }
 
index 004b6cf848d943288934452237c1cfa2ef8b8cfd..0814367ef101a1c075c0cfd4f5a52bc34dea920d 100644 (file)
@@ -91,6 +91,7 @@ struct bfad_itnim_s {
        struct fc_rport *fc_rport;
        struct bfa_itnim_s *bfa_itnim;
        u16        scsi_tgt_id;
+       u16        channel;
        u16        queue_work;
        unsigned long   last_ramp_up_time;
        unsigned long   last_queue_full_time;
@@ -166,4 +167,30 @@ irqreturn_t bfad_intx(int irq, void *dev_id);
 int bfad_im_bsg_request(struct fc_bsg_job *job);
 int bfad_im_bsg_timeout(struct fc_bsg_job *job);
 
+/*
+ * Macro to set the SCSI device sdev_bflags - sdev_bflags are used by the
+ * SCSI mid-layer to choose LUN Scanning mode REPORT_LUNS vs. Sequential Scan
+ *
+ * Internally iterate's over all the ITNIM's part of the im_port & set's the
+ * sdev_bflags for the scsi_device associated with LUN #0.
+ */
+#define bfad_reset_sdev_bflags(__im_port, __lunmask_cfg) do {          \
+       struct scsi_device *__sdev = NULL;                              \
+       struct bfad_itnim_s *__itnim = NULL;                            \
+       u32 scan_flags = BLIST_NOREPORTLUN | BLIST_SPARSELUN;           \
+       list_for_each_entry(__itnim, &((__im_port)->itnim_mapped_list), \
+                           list_entry) {                               \
+               __sdev = scsi_device_lookup((__im_port)->shost,         \
+                                           __itnim->channel,           \
+                                           __itnim->scsi_tgt_id, 0);   \
+               if (__sdev) {                                           \
+                       if ((__lunmask_cfg) == BFA_TRUE)                \
+                               __sdev->sdev_bflags |= scan_flags;      \
+                       else                                            \
+                               __sdev->sdev_bflags &= ~scan_flags;     \
+                       scsi_device_put(__sdev);                        \
+               }                                                       \
+       }                                                               \
+} while (0)
+
 #endif
index c5360ffb4bed35ae9bd06fa1a0195f2517b82778..d3ff9cd40234f5d5ea478020ecbf0a04bac1503e 100644 (file)
@@ -1868,8 +1868,9 @@ int cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 opcode)
 
        tdata->skb = alloc_skb(cdev->skb_tx_rsvd + headroom, GFP_ATOMIC);
        if (!tdata->skb) {
-               pr_warn("alloc skb %u+%u, opcode 0x%x failed.\n",
-                       cdev->skb_tx_rsvd, headroom, opcode);
+               struct cxgbi_sock *csk = cconn->cep->csk;
+               struct net_device *ndev = cdev->ports[csk->port_id];
+               ndev->stats.tx_dropped++;
                return -ENOMEM;
        }
 
index f5b718d3c31be53f860912ce9f833f4534190ffb..13aeca3d51f24919ddf10406e941fd04b25c00bc 100644 (file)
@@ -546,7 +546,7 @@ static struct ParameterData __devinitdata cfg_data[] = {
  * command line overrides will be used. If set to 1 then safe and
  * slow settings will be used.
  */
-static int use_safe_settings = 0;
+static bool use_safe_settings = 0;
 module_param_named(safe, use_safe_settings, bool, 0);
 MODULE_PARM_DESC(safe, "Use safe and slow settings only. Default: false");
 
index 4ef021291a4d06d2ecd4340f5ba1c35658a5c9d1..04c5cea47a2258a2156f692a6441253db31a8506 100644 (file)
@@ -466,6 +466,11 @@ static int alua_check_sense(struct scsi_device *sdev,
                         * Power On, Reset, or Bus Device Reset, just retry.
                         */
                        return ADD_TO_MLQUEUE;
+               if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01)
+                       /*
+                        * Mode Parameters Changed
+                        */
+                       return ADD_TO_MLQUEUE;
                if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06)
                        /*
                         * ALUA state changed
index 841ebf4a6788fc3895d5ddd31b8a67f7ce49ab55..53a31c753cb1e682ead92268901bc966845a1996 100644 (file)
@@ -953,6 +953,8 @@ static int __init rdac_init(void)
        if (!kmpath_rdacd) {
                scsi_unregister_device_handler(&rdac_dh);
                printk(KERN_ERR "kmpath_rdacd creation failed.\n");
+
+               r = -EINVAL;
        }
 done:
        return r;
index 8d67467dd9cec100f52b51803fbe943192421a58..e9599600aa230b8b6315c405730352f99e6a7d9a 100644 (file)
@@ -58,7 +58,11 @@ module_param_named(ddp_min, fcoe_ddp_min, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for "     \
                 "Direct Data Placement (DDP).");
 
-DEFINE_MUTEX(fcoe_config_mutex);
+unsigned int fcoe_debug_logging;
+module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
+
+static DEFINE_MUTEX(fcoe_config_mutex);
 
 static struct workqueue_struct *fcoe_wq;
 
@@ -67,8 +71,8 @@ static DECLARE_COMPLETION(fcoe_flush_completion);
 
 /* fcoe host list */
 /* must only by accessed under the RTNL mutex */
-LIST_HEAD(fcoe_hostlist);
-DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu);
+static LIST_HEAD(fcoe_hostlist);
+static DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu);
 
 /* Function Prototypes */
 static int fcoe_reset(struct Scsi_Host *);
@@ -157,7 +161,7 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = {
        .lport_set_port_id = fcoe_set_port_id,
 };
 
-struct fc_function_template fcoe_nport_fc_functions = {
+static struct fc_function_template fcoe_nport_fc_functions = {
        .show_host_node_name = 1,
        .show_host_port_name = 1,
        .show_host_supported_classes = 1,
@@ -197,7 +201,7 @@ struct fc_function_template fcoe_nport_fc_functions = {
        .bsg_request = fc_lport_bsg_request,
 };
 
-struct fc_function_template fcoe_vport_fc_functions = {
+static struct fc_function_template fcoe_vport_fc_functions = {
        .show_host_node_name = 1,
        .show_host_port_name = 1,
        .show_host_supported_classes = 1,
@@ -433,7 +437,7 @@ static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
  *
  * Caller must be holding the RTNL mutex
  */
-void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
+static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
 {
        struct net_device *netdev = fcoe->netdev;
        struct fcoe_ctlr *fip = &fcoe->ctlr;
@@ -748,7 +752,7 @@ static int fcoe_shost_config(struct fc_lport *lport, struct device *dev)
  *
  * Returns: True for read types I/O, otherwise returns false.
  */
-bool fcoe_oem_match(struct fc_frame *fp)
+static bool fcoe_oem_match(struct fc_frame *fp)
 {
        struct fc_frame_header *fh = fc_frame_header_get(fp);
        struct fcp_cmnd *fcp;
@@ -756,11 +760,12 @@ bool fcoe_oem_match(struct fc_frame *fp)
        if (fc_fcp_is_read(fr_fsp(fp)) &&
            (fr_fsp(fp)->data_len > fcoe_ddp_min))
                return true;
-       else if (!(ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX)) {
+       else if ((fr_fsp(fp) == NULL) &&
+                (fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD) &&
+                (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN)) {
                fcp = fc_frame_payload_get(fp, sizeof(*fcp));
-               if (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN &&
-                   fcp && (ntohl(fcp->fc_dl) > fcoe_ddp_min) &&
-                   (fcp->fc_flags & FCP_CFL_WRDATA))
+               if ((fcp->fc_flags & FCP_CFL_WRDATA) &&
+                   (ntohl(fcp->fc_dl) > fcoe_ddp_min))
                        return true;
        }
        return false;
@@ -1106,7 +1111,7 @@ static int __init fcoe_if_init(void)
  *
  * Returns: 0 on success
  */
-int __exit fcoe_if_exit(void)
+static int __exit fcoe_if_exit(void)
 {
        fc_release_transport(fcoe_nport_scsi_transport);
        fc_release_transport(fcoe_vport_scsi_transport);
@@ -1295,7 +1300,7 @@ static inline unsigned int fcoe_select_cpu(void)
  *
  * Returns: 0 for success
  */
-int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
+static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
             struct packet_type *ptype, struct net_device *olddev)
 {
        struct fc_lport *lport;
@@ -1451,7 +1456,7 @@ static int fcoe_alloc_paged_crc_eof(struct sk_buff *skb, int tlen)
  *
  * Return: 0 for success
  */
-int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
+static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
 {
        int wlen;
        u32 crc;
@@ -1671,8 +1676,7 @@ static void fcoe_recv_frame(struct sk_buff *skb)
                        skb->dev ? skb->dev->name : "<NULL>");
 
        port = lport_priv(lport);
-       if (skb_is_nonlinear(skb))
-               skb_linearize(skb);     /* not ideal */
+       skb_linearize(skb); /* check for skb_is_nonlinear is within skb_linearize */
 
        /*
         * Frame length checks and setting up the header pointers
@@ -1728,7 +1732,7 @@ drop:
  *
  * Return: 0 for success
  */
-int fcoe_percpu_receive_thread(void *arg)
+static int fcoe_percpu_receive_thread(void *arg)
 {
        struct fcoe_percpu_s *p = arg;
        struct sk_buff *skb;
@@ -2146,7 +2150,7 @@ out_nortnl:
  * Returns: 0 if the ethtool query was successful
  *          -1 if the ethtool query failed
  */
-int fcoe_link_speed_update(struct fc_lport *lport)
+static int fcoe_link_speed_update(struct fc_lport *lport)
 {
        struct net_device *netdev = fcoe_netdev(lport);
        struct ethtool_cmd ecmd;
@@ -2180,7 +2184,7 @@ int fcoe_link_speed_update(struct fc_lport *lport)
  * Returns: 0 if link is UP and OK, -1 if not
  *
  */
-int fcoe_link_ok(struct fc_lport *lport)
+static int fcoe_link_ok(struct fc_lport *lport)
 {
        struct net_device *netdev = fcoe_netdev(lport);
 
@@ -2200,7 +2204,7 @@ int fcoe_link_ok(struct fc_lport *lport)
  * there no packets that will be handled by the lport, but also that any
  * threads already handling packet have returned.
  */
-void fcoe_percpu_clean(struct fc_lport *lport)
+static void fcoe_percpu_clean(struct fc_lport *lport)
 {
        struct fcoe_percpu_s *pp;
        struct fcoe_rcv_info *fr;
@@ -2251,7 +2255,7 @@ void fcoe_percpu_clean(struct fc_lport *lport)
  *
  * Returns: Always 0 (return value required by FC transport template)
  */
-int fcoe_reset(struct Scsi_Host *shost)
+static int fcoe_reset(struct Scsi_Host *shost)
 {
        struct fc_lport *lport = shost_priv(shost);
        struct fcoe_port *port = lport_priv(lport);
index 6c6884bcf84004e7f792ccccc71bf9728cc24095..bcc89e63949573173e20fac339765d72633b96de 100644 (file)
@@ -40,9 +40,7 @@
 #define FCOE_MIN_XID           0x0000  /* the min xid supported by fcoe_sw */
 #define FCOE_MAX_XID           0x0FFF  /* the max xid supported by fcoe_sw */
 
-unsigned int fcoe_debug_logging;
-module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
+extern unsigned int fcoe_debug_logging;
 
 #define FCOE_LOGGING       0x01 /* General logging, not categorized */
 #define FCOE_NETDEV_LOGGING 0x02 /* Netdevice logging */
index 5140f5d0fd6be610f5038368fdec6627be4e9cea..b96962c394492604cd2fc2a73ce80731db28882d 100644 (file)
@@ -4271,7 +4271,9 @@ static void stop_controller_lockup_detector(struct ctlr_info *h)
        remove_ctlr_from_lockup_detector_list(h);
        /* If the list of ctlr's to monitor is empty, stop the thread */
        if (list_empty(&hpsa_ctlr_list)) {
+               spin_unlock_irqrestore(&lockup_detector_lock, flags);
                kthread_stop(hpsa_lockup_detector);
+               spin_lock_irqsave(&lockup_detector_lock, flags);
                hpsa_lockup_detector = NULL;
        }
        spin_unlock_irqrestore(&lockup_detector_lock, flags);
diff --git a/drivers/scsi/isci/firmware/Makefile b/drivers/scsi/isci/firmware/Makefile
deleted file mode 100644 (file)
index 5f54461..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-# Makefile for create_fw
-#
-CC=gcc
-CFLAGS=-c -Wall -O2 -g
-LDFLAGS=
-SOURCES=create_fw.c
-OBJECTS=$(SOURCES:.cpp=.o)
-EXECUTABLE=create_fw
-
-all: $(SOURCES) $(EXECUTABLE)
-
-$(EXECUTABLE): $(OBJECTS)
-       $(CC) $(LDFLAGS) $(OBJECTS) -o $@
-
-.c.o:
-       $(CC) $(CFLAGS) $< -O $@
-
-clean:
-       rm -f *.o $(EXECUTABLE)
diff --git a/drivers/scsi/isci/firmware/README b/drivers/scsi/isci/firmware/README
deleted file mode 100644 (file)
index 8056d2b..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-This defines the temporary binary blow we are to pass to the SCU
-driver to emulate the binary firmware that we will eventually be
-able to access via NVRAM on the SCU controller.
-
-The current size of the binary blob is expected to be 149 bytes or larger
-
-Header Types:
-0x1: Phy Masks
-0x2: Phy Gens
-0x3: SAS Addrs
-0xff: End of Data
-
-ID string - u8[12]: "#SCU MAGIC#\0"
-Version - u8: 1
-SubVersion - u8: 0
-
-Header Type - u8: 0x1
-Size - u8: 8
-Phy Mask - u32[8]
-
-Header Type - u8: 0x2
-Size - u8: 8
-Phy Gen - u32[8]
-
-Header Type - u8: 0x3
-Size - u8: 8
-Sas Addr - u64[8]
-
-Header Type - u8: 0xf
-
-
-==============================================================================
-
-Place isci_firmware.bin in /lib/firmware
-Be sure to recreate the initramfs image to include the firmware.
-
diff --git a/drivers/scsi/isci/firmware/create_fw.c b/drivers/scsi/isci/firmware/create_fw.c
deleted file mode 100644 (file)
index c7a2887..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include <asm/types.h>
-#include <strings.h>
-#include <stdint.h>
-
-#include "create_fw.h"
-#include "../probe_roms.h"
-
-int write_blob(struct isci_orom *isci_orom)
-{
-       FILE *fd;
-       int err;
-       size_t count;
-
-       fd = fopen(blob_name, "w+");
-       if (!fd) {
-               perror("Open file for write failed");
-               fclose(fd);
-               return -EIO;
-       }
-
-       count = fwrite(isci_orom, sizeof(struct isci_orom), 1, fd);
-       if (count != 1) {
-               perror("Write data failed");
-               fclose(fd);
-               return -EIO;
-       }
-
-       fclose(fd);
-
-       return 0;
-}
-
-void set_binary_values(struct isci_orom *isci_orom)
-{
-       int ctrl_idx, phy_idx, port_idx;
-
-       /* setting OROM signature */
-       strncpy(isci_orom->hdr.signature, sig, strlen(sig));
-       isci_orom->hdr.version = version;
-       isci_orom->hdr.total_block_length = sizeof(struct isci_orom);
-       isci_orom->hdr.hdr_length = sizeof(struct sci_bios_oem_param_block_hdr);
-       isci_orom->hdr.num_elements = num_elements;
-
-       for (ctrl_idx = 0; ctrl_idx < 2; ctrl_idx++) {
-               isci_orom->ctrl[ctrl_idx].controller.mode_type = mode_type;
-               isci_orom->ctrl[ctrl_idx].controller.max_concurrent_dev_spin_up =
-                       max_num_concurrent_dev_spin_up;
-               isci_orom->ctrl[ctrl_idx].controller.do_enable_ssc =
-                       enable_ssc;
-
-               for (port_idx = 0; port_idx < 4; port_idx++)
-                       isci_orom->ctrl[ctrl_idx].ports[port_idx].phy_mask =
-                               phy_mask[ctrl_idx][port_idx];
-
-               for (phy_idx = 0; phy_idx < 4; phy_idx++) {
-                       isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.high =
-                               (__u32)(sas_addr[ctrl_idx][phy_idx] >> 32);
-                       isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.low =
-                               (__u32)(sas_addr[ctrl_idx][phy_idx]);
-
-                       isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control0 =
-                               afe_tx_amp_control0;
-                       isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control1 =
-                               afe_tx_amp_control1;
-                       isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control2 =
-                               afe_tx_amp_control2;
-                       isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control3 =
-                               afe_tx_amp_control3;
-               }
-       }
-}
-
-int main(void)
-{
-       int err;
-       struct isci_orom *isci_orom;
-
-       isci_orom = malloc(sizeof(struct isci_orom));
-       memset(isci_orom, 0, sizeof(struct isci_orom));
-
-       set_binary_values(isci_orom);
-
-       err = write_blob(isci_orom);
-       if (err < 0) {
-               free(isci_orom);
-               return err;
-       }
-
-       free(isci_orom);
-       return 0;
-}
diff --git a/drivers/scsi/isci/firmware/create_fw.h b/drivers/scsi/isci/firmware/create_fw.h
deleted file mode 100644 (file)
index 5f29882..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef _CREATE_FW_H_
-#define _CREATE_FW_H_
-#include "../probe_roms.h"
-
-
-/* we are configuring for 2 SCUs */
-static const int num_elements = 2;
-
-/*
- * For all defined arrays:
- * elements 0-3 are for SCU0, ports 0-3
- * elements 4-7 are for SCU1, ports 0-3
- *
- * valid configurations for one SCU are:
- *  P0  P1  P2  P3
- * ----------------
- * 0xF,0x0,0x0,0x0 # 1 x4 port
- * 0x3,0x0,0x4,0x8 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are each x1
- *                 # ports
- * 0x1,0x2,0xC,0x0 # Phys 0 and 1 are each x1 ports, phy 2 and phy 3 are a x2
- *                 # port
- * 0x3,0x0,0xC,0x0 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are a x2 port
- * 0x1,0x2,0x4,0x8 # Each phy is a x1 port (this is the default configuration)
- *
- * if there is a port/phy on which you do not wish to override the default
- * values, use the value assigned to UNINIT_PARAM (255).
- */
-
-/* discovery mode type (port auto config mode by default ) */
-
-/*
- * if there is a port/phy on which you do not wish to override the default
- * values, use the value "0000000000000000". SAS address of zero's is
- * considered invalid and will not be used.
- */
-#ifdef MPC
-static const int mode_type = SCIC_PORT_MANUAL_CONFIGURATION_MODE;
-static const __u8 phy_mask[2][4] = { {1, 2, 4, 8},
-                                    {1, 2, 4, 8} };
-static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFFF0000001ULL,
-                                                    0x5FCFFFFFF0000002ULL,
-                                                    0x5FCFFFFFF0000003ULL,
-                                                    0x5FCFFFFFF0000004ULL },
-                                                  { 0x5FCFFFFFF0000005ULL,
-                                                    0x5FCFFFFFF0000006ULL,
-                                                    0x5FCFFFFFF0000007ULL,
-                                                    0x5FCFFFFFF0000008ULL } };
-#else  /* APC (default) */
-static const int mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
-static const __u8 phy_mask[2][4];
-static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFF00000001ULL,
-                                                    0x5FCFFFFF00000001ULL,
-                                                    0x5FCFFFFF00000001ULL,
-                                                    0x5FCFFFFF00000001ULL },
-                                                  { 0x5FCFFFFF00000002ULL,
-                                                    0x5FCFFFFF00000002ULL,
-                                                    0x5FCFFFFF00000002ULL,
-                                                    0x5FCFFFFF00000002ULL } };
-#endif
-
-/* Maximum number of concurrent device spin up */
-static const int max_num_concurrent_dev_spin_up = 1;
-
-/* enable of ssc operation */
-static const int enable_ssc;
-
-/* AFE_TX_AMP_CONTROL */
-static const unsigned int afe_tx_amp_control0 = 0x000bdd08;
-static const unsigned int afe_tx_amp_control1 = 0x000ffc00;
-static const unsigned int afe_tx_amp_control2 = 0x000b7c09;
-static const unsigned int afe_tx_amp_control3 = 0x000afc6e;
-
-static const char blob_name[] = "isci_firmware.bin";
-static const char sig[] = "ISCUOEMB";
-static const unsigned char version = 0x10;
-
-#endif
index e7fe9c4c85b84d7098850eb16288caaae8b20578..1a65d6514237dd59ac24c8deb89f1afce27a4e3d 100644 (file)
@@ -899,7 +899,8 @@ static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost)
                         */
                        if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) ||
                            (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) ||
-                           (iphy->is_in_link_training == true && is_phy_starting(iphy))) {
+                           (iphy->is_in_link_training == true && is_phy_starting(iphy)) ||
+                           (ihost->port_agent.phy_ready_mask != ihost->port_agent.phy_configured_mask)) {
                                is_controller_start_complete = false;
                                break;
                        }
@@ -1666,6 +1667,9 @@ static void sci_controller_set_default_config_parameters(struct isci_host *ihost
        /* Default to no SSC operation. */
        ihost->oem_parameters.controller.do_enable_ssc = false;
 
+       /* Default to short cables on all phys. */
+       ihost->oem_parameters.controller.cable_selection_mask = 0;
+
        /* Initialize all of the port parameter information to narrow ports. */
        for (index = 0; index < SCI_MAX_PORTS; index++) {
                ihost->oem_parameters.ports[index].phy_mask = 0;
@@ -1673,8 +1677,9 @@ static void sci_controller_set_default_config_parameters(struct isci_host *ihost
 
        /* Initialize all of the phy parameter information. */
        for (index = 0; index < SCI_MAX_PHYS; index++) {
-               /* Default to 6G (i.e. Gen 3) for now. */
-               ihost->user_parameters.phys[index].max_speed_generation = 3;
+               /* Default to 3G (i.e. Gen 2). */
+               ihost->user_parameters.phys[index].max_speed_generation =
+                       SCIC_SDS_PARM_GEN2_SPEED;
 
                /* the frequencies cannot be 0 */
                ihost->user_parameters.phys[index].align_insertion_frequency = 0x7f;
@@ -1694,7 +1699,7 @@ static void sci_controller_set_default_config_parameters(struct isci_host *ihost
        ihost->user_parameters.ssp_inactivity_timeout = 5;
        ihost->user_parameters.stp_max_occupancy_timeout = 5;
        ihost->user_parameters.ssp_max_occupancy_timeout = 20;
-       ihost->user_parameters.no_outbound_task_timeout = 20;
+       ihost->user_parameters.no_outbound_task_timeout = 2;
 }
 
 static void controller_timeout(unsigned long data)
@@ -1759,7 +1764,7 @@ static enum sci_status sci_controller_construct(struct isci_host *ihost,
        return sci_controller_reset(ihost);
 }
 
-int sci_oem_parameters_validate(struct sci_oem_params *oem)
+int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version)
 {
        int i;
 
@@ -1791,18 +1796,61 @@ int sci_oem_parameters_validate(struct sci_oem_params *oem)
            oem->controller.max_concurr_spin_up < 1)
                return -EINVAL;
 
+       if (oem->controller.do_enable_ssc) {
+               if (version < ISCI_ROM_VER_1_1 && oem->controller.do_enable_ssc != 1)
+                       return -EINVAL;
+
+               if (version >= ISCI_ROM_VER_1_1) {
+                       u8 test = oem->controller.ssc_sata_tx_spread_level;
+
+                       switch (test) {
+                       case 0:
+                       case 2:
+                       case 3:
+                       case 6:
+                       case 7:
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+
+                       test = oem->controller.ssc_sas_tx_spread_level;
+                       if (oem->controller.ssc_sas_tx_type == 0) {
+                               switch (test) {
+                               case 0:
+                               case 2:
+                               case 3:
+                                       break;
+                               default:
+                                       return -EINVAL;
+                               }
+                       } else if (oem->controller.ssc_sas_tx_type == 1) {
+                               switch (test) {
+                               case 0:
+                               case 3:
+                               case 6:
+                                       break;
+                               default:
+                                       return -EINVAL;
+                               }
+                       }
+               }
+       }
+
        return 0;
 }
 
 static enum sci_status sci_oem_parameters_set(struct isci_host *ihost)
 {
        u32 state = ihost->sm.current_state_id;
+       struct isci_pci_info *pci_info = to_pci_info(ihost->pdev);
 
        if (state == SCIC_RESET ||
            state == SCIC_INITIALIZING ||
            state == SCIC_INITIALIZED) {
 
-               if (sci_oem_parameters_validate(&ihost->oem_parameters))
+               if (sci_oem_parameters_validate(&ihost->oem_parameters,
+                                               pci_info->orom->hdr.version))
                        return SCI_FAILURE_INVALID_PARAMETER_VALUE;
 
                return SCI_SUCCESS;
@@ -1857,6 +1905,31 @@ static void power_control_timeout(unsigned long data)
                ihost->power_control.phys_waiting--;
                ihost->power_control.phys_granted_power++;
                sci_phy_consume_power_handler(iphy);
+
+               if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) {
+                       u8 j;
+
+                       for (j = 0; j < SCI_MAX_PHYS; j++) {
+                               struct isci_phy *requester = ihost->power_control.requesters[j];
+
+                               /*
+                                * Search the power_control queue to see if there are other phys
+                                * attached to the same remote device. If found, take all of
+                                * them out of await_sas_power state.
+                                */
+                               if (requester != NULL && requester != iphy) {
+                                       u8 other = memcmp(requester->frame_rcvd.iaf.sas_addr,
+                                                         iphy->frame_rcvd.iaf.sas_addr,
+                                                         sizeof(requester->frame_rcvd.iaf.sas_addr));
+
+                                       if (other == 0) {
+                                               ihost->power_control.requesters[j] = NULL;
+                                               ihost->power_control.phys_waiting--;
+                                               sci_phy_consume_power_handler(requester);
+                                       }
+                               }
+                       }
+               }
        }
 
        /*
@@ -1891,9 +1964,34 @@ void sci_controller_power_control_queue_insert(struct isci_host *ihost,
                ihost->power_control.timer_started = true;
 
        } else {
-               /* Add the phy in the waiting list */
-               ihost->power_control.requesters[iphy->phy_index] = iphy;
-               ihost->power_control.phys_waiting++;
+               /*
+                * There are phys, attached to the same sas address as this phy, are
+                * already in READY state, this phy don't need wait.
+                */
+               u8 i;
+               struct isci_phy *current_phy;
+
+               for (i = 0; i < SCI_MAX_PHYS; i++) {
+                       u8 other;
+                       current_phy = &ihost->phys[i];
+
+                       other = memcmp(current_phy->frame_rcvd.iaf.sas_addr,
+                                      iphy->frame_rcvd.iaf.sas_addr,
+                                      sizeof(current_phy->frame_rcvd.iaf.sas_addr));
+
+                       if (current_phy->sm.current_state_id == SCI_PHY_READY &&
+                           current_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS &&
+                           other == 0) {
+                               sci_phy_consume_power_handler(iphy);
+                               break;
+                       }
+               }
+
+               if (i == SCI_MAX_PHYS) {
+                       /* Add the phy in the waiting list */
+                       ihost->power_control.requesters[iphy->phy_index] = iphy;
+                       ihost->power_control.phys_waiting++;
+               }
        }
 }
 
@@ -1908,162 +2006,250 @@ void sci_controller_power_control_queue_remove(struct isci_host *ihost,
        ihost->power_control.requesters[iphy->phy_index] = NULL;
 }
 
+static int is_long_cable(int phy, unsigned char selection_byte)
+{
+       return !!(selection_byte & (1 << phy));
+}
+
+static int is_medium_cable(int phy, unsigned char selection_byte)
+{
+       return !!(selection_byte & (1 << (phy + 4)));
+}
+
+static enum cable_selections decode_selection_byte(
+       int phy,
+       unsigned char selection_byte)
+{
+       return ((selection_byte & (1 << phy)) ? 1 : 0)
+               + (selection_byte & (1 << (phy + 4)) ? 2 : 0);
+}
+
+static unsigned char *to_cable_select(struct isci_host *ihost)
+{
+       if (is_cable_select_overridden())
+               return ((unsigned char *)&cable_selection_override)
+                       + ihost->id;
+       else
+               return &ihost->oem_parameters.controller.cable_selection_mask;
+}
+
+enum cable_selections decode_cable_selection(struct isci_host *ihost, int phy)
+{
+       return decode_selection_byte(phy, *to_cable_select(ihost));
+}
+
+char *lookup_cable_names(enum cable_selections selection)
+{
+       static char *cable_names[] = {
+               [short_cable]     = "short",
+               [long_cable]      = "long",
+               [medium_cable]    = "medium",
+               [undefined_cable] = "<undefined, assumed long>" /* bit 0==1 */
+       };
+       return (selection <= undefined_cable) ? cable_names[selection]
+                                             : cable_names[undefined_cable];
+}
+
 #define AFE_REGISTER_WRITE_DELAY 10
 
-/* Initialize the AFE for this phy index. We need to read the AFE setup from
- * the OEM parameters
- */
 static void sci_controller_afe_initialization(struct isci_host *ihost)
 {
+       struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe;
        const struct sci_oem_params *oem = &ihost->oem_parameters;
        struct pci_dev *pdev = ihost->pdev;
        u32 afe_status;
        u32 phy_id;
+       unsigned char cable_selection_mask = *to_cable_select(ihost);
 
        /* Clear DFX Status registers */
-       writel(0x0081000f, &ihost->scu_registers->afe.afe_dfx_master_control0);
+       writel(0x0081000f, &afe->afe_dfx_master_control0);
        udelay(AFE_REGISTER_WRITE_DELAY);
 
-       if (is_b0(pdev)) {
+       if (is_b0(pdev) || is_c0(pdev) || is_c1(pdev)) {
                /* PM Rx Equalization Save, PM SPhy Rx Acknowledgement
-                * Timer, PM Stagger Timer */
-               writel(0x0007BFFF, &ihost->scu_registers->afe.afe_pmsn_master_control2);
+                * Timer, PM Stagger Timer
+                */
+               writel(0x0007FFFF, &afe->afe_pmsn_master_control2);
                udelay(AFE_REGISTER_WRITE_DELAY);
        }
 
        /* Configure bias currents to normal */
        if (is_a2(pdev))
-               writel(0x00005A00, &ihost->scu_registers->afe.afe_bias_control);
+               writel(0x00005A00, &afe->afe_bias_control);
        else if (is_b0(pdev) || is_c0(pdev))
-               writel(0x00005F00, &ihost->scu_registers->afe.afe_bias_control);
+               writel(0x00005F00, &afe->afe_bias_control);
+       else if (is_c1(pdev))
+               writel(0x00005500, &afe->afe_bias_control);
 
        udelay(AFE_REGISTER_WRITE_DELAY);
 
        /* Enable PLL */
-       if (is_b0(pdev) || is_c0(pdev))
-               writel(0x80040A08, &ihost->scu_registers->afe.afe_pll_control0);
-       else
-               writel(0x80040908, &ihost->scu_registers->afe.afe_pll_control0);
+       if (is_a2(pdev))
+               writel(0x80040908, &afe->afe_pll_control0);
+       else if (is_b0(pdev) || is_c0(pdev))
+               writel(0x80040A08, &afe->afe_pll_control0);
+       else if (is_c1(pdev)) {
+               writel(0x80000B08, &afe->afe_pll_control0);
+               udelay(AFE_REGISTER_WRITE_DELAY);
+               writel(0x00000B08, &afe->afe_pll_control0);
+               udelay(AFE_REGISTER_WRITE_DELAY);
+               writel(0x80000B08, &afe->afe_pll_control0);
+       }
 
        udelay(AFE_REGISTER_WRITE_DELAY);
 
        /* Wait for the PLL to lock */
        do {
-               afe_status = readl(&ihost->scu_registers->afe.afe_common_block_status);
+               afe_status = readl(&afe->afe_common_block_status);
                udelay(AFE_REGISTER_WRITE_DELAY);
        } while ((afe_status & 0x00001000) == 0);
 
        if (is_a2(pdev)) {
-               /* Shorten SAS SNW lock time (RxLock timer value from 76 us to 50 us) */
-               writel(0x7bcc96ad, &ihost->scu_registers->afe.afe_pmsn_master_control0);
+               /* Shorten SAS SNW lock time (RxLock timer value from 76
+                * us to 50 us)
+                */
+               writel(0x7bcc96ad, &afe->afe_pmsn_master_control0);
                udelay(AFE_REGISTER_WRITE_DELAY);
        }
 
        for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) {
+               struct scu_afe_transceiver *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);
+               int cable_length_medium =
+                       is_medium_cable(phy_id, cable_selection_mask);
 
-               if (is_b0(pdev)) {
-                        /* Configure transmitter SSC parameters */
-                       writel(0x00030000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_ssc_control);
+               if (is_a2(pdev)) {
+                       /* All defaults, except the Receive Word
+                        * Alignament/Comma Detect Enable....(0xe800)
+                        */
+                       writel(0x00004512, &xcvr->afe_xcvr_control0);
+                       udelay(AFE_REGISTER_WRITE_DELAY);
+
+                       writel(0x0050100F, &xcvr->afe_xcvr_control1);
+                       udelay(AFE_REGISTER_WRITE_DELAY);
+               } else if (is_b0(pdev)) {
+                       /* Configure transmitter SSC parameters */
+                       writel(0x00030000, &xcvr->afe_tx_ssc_control);
                        udelay(AFE_REGISTER_WRITE_DELAY);
                } else if (is_c0(pdev)) {
-                        /* Configure transmitter SSC parameters */
-                       writel(0x0003000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_ssc_control);
+                       /* Configure transmitter SSC parameters */
+                       writel(0x00010202, &xcvr->afe_tx_ssc_control);
                        udelay(AFE_REGISTER_WRITE_DELAY);
 
-                       /*
-                        * All defaults, except the Receive Word Alignament/Comma Detect
-                        * Enable....(0xe800) */
-                       writel(0x00004500, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control0);
+                       /* All defaults, except the Receive Word
+                        * Alignament/Comma Detect Enable....(0xe800)
+                        */
+                       writel(0x00014500, &xcvr->afe_xcvr_control0);
                        udelay(AFE_REGISTER_WRITE_DELAY);
-               } else {
-                       /*
-                        * All defaults, except the Receive Word Alignament/Comma Detect
-                        * Enable....(0xe800) */
-                       writel(0x00004512, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control0);
+               } else if (is_c1(pdev)) {
+                       /* Configure transmitter SSC parameters */
+                       writel(0x00010202, &xcvr->afe_tx_ssc_control);
                        udelay(AFE_REGISTER_WRITE_DELAY);
 
-                       writel(0x0050100F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control1);
+                       /* All defaults, except the Receive Word
+                        * Alignament/Comma Detect Enable....(0xe800)
+                        */
+                       writel(0x0001C500, &xcvr->afe_xcvr_control0);
                        udelay(AFE_REGISTER_WRITE_DELAY);
                }
 
-               /*
-                * Power up TX and RX out from power down (PWRDNTX and PWRDNRX)
-                * & increase TX int & ext bias 20%....(0xe85c) */
+               /* Power up TX and RX out from power down (PWRDNTX and
+                * PWRDNRX) & increase TX int & ext bias 20%....(0xe85c)
+                */
                if (is_a2(pdev))
-                       writel(0x000003F0, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control);
+                       writel(0x000003F0, &xcvr->afe_channel_control);
                else if (is_b0(pdev)) {
-                        /* Power down TX and RX (PWRDNTX and PWRDNRX) */
-                       writel(0x000003D7, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control);
+                       writel(0x000003D7, &xcvr->afe_channel_control);
                        udelay(AFE_REGISTER_WRITE_DELAY);
 
-                       /*
-                        * Power up TX and RX out from power down (PWRDNTX and PWRDNRX)
-                        * & increase TX int & ext bias 20%....(0xe85c) */
-                       writel(0x000003D4, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control);
-               } else {
-                       writel(0x000001E7, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control);
+                       writel(0x000003D4, &xcvr->afe_channel_control);
+               } else if (is_c0(pdev)) {
+                       writel(0x000001E7, &xcvr->afe_channel_control);
                        udelay(AFE_REGISTER_WRITE_DELAY);
 
-                       /*
-                        * Power up TX and RX out from power down (PWRDNTX and PWRDNRX)
-                        * & increase TX int & ext bias 20%....(0xe85c) */
-                       writel(0x000001E4, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control);
+                       writel(0x000001E4, &xcvr->afe_channel_control);
+               } else if (is_c1(pdev)) {
+                       writel(cable_length_long ? 0x000002F7 : 0x000001F7,
+                              &xcvr->afe_channel_control);
+                       udelay(AFE_REGISTER_WRITE_DELAY);
+
+                       writel(cable_length_long ? 0x000002F4 : 0x000001F4,
+                              &xcvr->afe_channel_control);
                }
                udelay(AFE_REGISTER_WRITE_DELAY);
 
                if (is_a2(pdev)) {
                        /* Enable TX equalization (0xe824) */
-                       writel(0x00040000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_control);
+                       writel(0x00040000, &xcvr->afe_tx_control);
                        udelay(AFE_REGISTER_WRITE_DELAY);
                }
 
-               /*
-                * RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0, TPD=0x0(TX Power On),
-                * RDD=0x0(RX Detect Enabled) ....(0xe800) */
-               writel(0x00004100, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control0);
+               if (is_a2(pdev) || is_b0(pdev))
+                       /* RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0,
+                        * TPD=0x0(TX Power On), RDD=0x0(RX Detect
+                        * Enabled) ....(0xe800)
+                        */
+                       writel(0x00004100, &xcvr->afe_xcvr_control0);
+               else if (is_c0(pdev))
+                       writel(0x00014100, &xcvr->afe_xcvr_control0);
+               else if (is_c1(pdev))
+                       writel(0x0001C100, &xcvr->afe_xcvr_control0);
                udelay(AFE_REGISTER_WRITE_DELAY);
 
                /* Leave DFE/FFE on */
                if (is_a2(pdev))
-                       writel(0x3F11103F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control0);
+                       writel(0x3F11103F, &xcvr->afe_rx_ssc_control0);
                else if (is_b0(pdev)) {
-                       writel(0x3F11103F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control0);
+                       writel(0x3F11103F, &xcvr->afe_rx_ssc_control0);
                        udelay(AFE_REGISTER_WRITE_DELAY);
                        /* Enable TX equalization (0xe824) */
-                       writel(0x00040000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_control);
-               } else {
-                       writel(0x0140DF0F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control1);
+                       writel(0x00040000, &xcvr->afe_tx_control);
+               } else if (is_c0(pdev)) {
+                       writel(0x01400C0F, &xcvr->afe_rx_ssc_control1);
+                       udelay(AFE_REGISTER_WRITE_DELAY);
+
+                       writel(0x3F6F103F, &xcvr->afe_rx_ssc_control0);
+                       udelay(AFE_REGISTER_WRITE_DELAY);
+
+                       /* Enable TX equalization (0xe824) */
+                       writel(0x00040000, &xcvr->afe_tx_control);
+               } else if (is_c1(pdev)) {
+                       writel(cable_length_long ? 0x01500C0C :
+                              cable_length_medium ? 0x01400C0D : 0x02400C0D,
+                              &xcvr->afe_xcvr_control1);
+                       udelay(AFE_REGISTER_WRITE_DELAY);
+
+                       writel(0x000003E0, &xcvr->afe_dfx_rx_control1);
                        udelay(AFE_REGISTER_WRITE_DELAY);
 
-                       writel(0x3F6F103F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control0);
+                       writel(cable_length_long ? 0x33091C1F :
+                              cable_length_medium ? 0x3315181F : 0x2B17161F,
+                              &xcvr->afe_rx_ssc_control0);
                        udelay(AFE_REGISTER_WRITE_DELAY);
 
                        /* Enable TX equalization (0xe824) */
-                       writel(0x00040000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_control);
+                       writel(0x00040000, &xcvr->afe_tx_control);
                }
 
                udelay(AFE_REGISTER_WRITE_DELAY);
 
-               writel(oem_phy->afe_tx_amp_control0,
-                       &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control0);
+               writel(oem_phy->afe_tx_amp_control0, &xcvr->afe_tx_amp_control0);
                udelay(AFE_REGISTER_WRITE_DELAY);
 
-               writel(oem_phy->afe_tx_amp_control1,
-                       &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control1);
+               writel(oem_phy->afe_tx_amp_control1, &xcvr->afe_tx_amp_control1);
                udelay(AFE_REGISTER_WRITE_DELAY);
 
-               writel(oem_phy->afe_tx_amp_control2,
-                       &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control2);
+               writel(oem_phy->afe_tx_amp_control2, &xcvr->afe_tx_amp_control2);
                udelay(AFE_REGISTER_WRITE_DELAY);
 
-               writel(oem_phy->afe_tx_amp_control3,
-                       &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control3);
+               writel(oem_phy->afe_tx_amp_control3, &xcvr->afe_tx_amp_control3);
                udelay(AFE_REGISTER_WRITE_DELAY);
        }
 
        /* Transfer control to the PEs */
-       writel(0x00010f00, &ihost->scu_registers->afe.afe_dfx_master_control0);
+       writel(0x00010f00, &afe->afe_dfx_master_control0);
        udelay(AFE_REGISTER_WRITE_DELAY);
 }
 
index 646051afd3cbd07e2ab6761a18edef7355cf39f6..5477f0fa8233198e691945a08c14eba074be2f21 100644 (file)
@@ -435,11 +435,36 @@ static inline bool is_b0(struct pci_dev *pdev)
 
 static inline bool is_c0(struct pci_dev *pdev)
 {
-       if (pdev->revision >= 5)
+       if (pdev->revision == 5)
                return true;
        return false;
 }
 
+static inline bool is_c1(struct pci_dev *pdev)
+{
+       if (pdev->revision >= 6)
+               return true;
+       return false;
+}
+
+enum cable_selections {
+       short_cable     = 0,
+       long_cable      = 1,
+       medium_cable    = 2,
+       undefined_cable = 3
+};
+
+#define CABLE_OVERRIDE_DISABLED (0x10000)
+
+static inline int is_cable_select_overridden(void)
+{
+       return cable_selection_override < CABLE_OVERRIDE_DISABLED;
+}
+
+enum cable_selections decode_cable_selection(struct isci_host *ihost, int phy);
+void validate_cable_selections(struct isci_host *ihost);
+char *lookup_cable_names(enum cable_selections);
+
 /* set hw control for 'activity', even though active enclosures seem to drive
  * the activity led on their own.  Skip setting FSENG control on 'status' due
  * to unexpected operation and 'error' due to not being a supported automatic
index a97edabcb85a29e96e1741171fcce2ea4c7cb4c0..17c4c2c89c2e5d9fe56f7e3b08010fc5ded3d71b 100644 (file)
@@ -65,7 +65,7 @@
 #include "probe_roms.h"
 
 #define MAJ 1
-#define MIN 0
+#define MIN 1
 #define BUILD 0
 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
        __stringify(BUILD)
@@ -94,7 +94,7 @@ MODULE_DEVICE_TABLE(pci, isci_id_table);
 
 /* linux isci specific settings */
 
-unsigned char no_outbound_task_to = 20;
+unsigned char no_outbound_task_to = 2;
 module_param(no_outbound_task_to, byte, 0);
 MODULE_PARM_DESC(no_outbound_task_to, "No Outbound Task Timeout (1us incr)");
 
@@ -114,7 +114,7 @@ u16 stp_inactive_to = 5;
 module_param(stp_inactive_to, ushort, 0);
 MODULE_PARM_DESC(stp_inactive_to, "STP inactivity timeout (100us incr)");
 
-unsigned char phy_gen = 3;
+unsigned char phy_gen = SCIC_SDS_PARM_GEN2_SPEED;
 module_param(phy_gen, byte, 0);
 MODULE_PARM_DESC(phy_gen, "PHY generation (1: 1.5Gbps 2: 3.0Gbps 3: 6.0Gbps)");
 
@@ -122,6 +122,14 @@ unsigned char max_concurr_spinup;
 module_param(max_concurr_spinup, byte, 0);
 MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup");
 
+uint cable_selection_override = CABLE_OVERRIDE_DISABLED;
+module_param(cable_selection_override, uint, 0);
+
+MODULE_PARM_DESC(cable_selection_override,
+                "This field indicates length of the SAS/SATA cable between "
+                "host and device. If any bits > 15 are set (default) "
+                "indicates \"use platform defaults\"");
+
 static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct Scsi_Host *shost = container_of(dev, typeof(*shost), shost_dev);
@@ -412,6 +420,14 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
                return NULL;
        isci_host->shost = shost;
 
+       dev_info(&pdev->dev, "%sSCU controller %d: phy 3-0 cables: "
+                "{%s, %s, %s, %s}\n",
+                (is_cable_select_overridden() ? "* " : ""), isci_host->id,
+                lookup_cable_names(decode_cable_selection(isci_host, 3)),
+                lookup_cable_names(decode_cable_selection(isci_host, 2)),
+                lookup_cable_names(decode_cable_selection(isci_host, 1)),
+                lookup_cable_names(decode_cable_selection(isci_host, 0)));
+
        err = isci_host_init(isci_host);
        if (err)
                goto err_shost;
@@ -466,7 +482,8 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
                orom = isci_request_oprom(pdev);
 
        for (i = 0; orom && i < ARRAY_SIZE(orom->ctrl); i++) {
-               if (sci_oem_parameters_validate(&orom->ctrl[i])) {
+               if (sci_oem_parameters_validate(&orom->ctrl[i],
+                                               orom->hdr.version)) {
                        dev_warn(&pdev->dev,
                                 "[%d]: invalid oem parameters detected, falling back to firmware\n", i);
                        devm_kfree(&pdev->dev, orom);
index 8efeb6b083213bb20d15ca3a9ca0a954515ec23f..234ab46fce3346948300d9ae95364e33103792ee 100644 (file)
@@ -480,6 +480,7 @@ extern u16 ssp_inactive_to;
 extern u16 stp_inactive_to;
 extern unsigned char phy_gen;
 extern unsigned char max_concurr_spinup;
+extern uint cable_selection_override;
 
 irqreturn_t isci_msix_isr(int vec, void *data);
 irqreturn_t isci_intx_isr(int vec, void *data);
index 35f50c2183e18a4c6460b07db081bb7d82ff6beb..fe18acfd6eb3ad9b62a775665a1dbedecb32e011 100644 (file)
@@ -91,22 +91,23 @@ sci_phy_transport_layer_initialization(struct isci_phy *iphy,
 
 static enum sci_status
 sci_phy_link_layer_initialization(struct isci_phy *iphy,
-                                 struct scu_link_layer_registers __iomem *reg)
+                                 struct scu_link_layer_registers __iomem *llr)
 {
        struct isci_host *ihost = iphy->owning_port->owning_controller;
+       struct sci_phy_user_params *phy_user;
+       struct sci_phy_oem_params *phy_oem;
        int phy_idx = iphy->phy_index;
-       struct sci_phy_user_params *phy_user = &ihost->user_parameters.phys[phy_idx];
-       struct sci_phy_oem_params *phy_oem =
-               &ihost->oem_parameters.phys[phy_idx];
-       u32 phy_configuration;
        struct sci_phy_cap phy_cap;
+       u32 phy_configuration;
        u32 parity_check = 0;
        u32 parity_count = 0;
        u32 llctl, link_rate;
        u32 clksm_value = 0;
        u32 sp_timeouts = 0;
 
-       iphy->link_layer_registers = reg;
+       phy_user = &ihost->user_parameters.phys[phy_idx];
+       phy_oem = &ihost->oem_parameters.phys[phy_idx];
+       iphy->link_layer_registers = llr;
 
        /* Set our IDENTIFY frame data */
        #define SCI_END_DEVICE 0x01
@@ -116,32 +117,26 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy,
               SCU_SAS_TIID_GEN_BIT(STP_INITIATOR) |
               SCU_SAS_TIID_GEN_BIT(DA_SATA_HOST) |
               SCU_SAS_TIID_GEN_VAL(DEVICE_TYPE, SCI_END_DEVICE),
-              &iphy->link_layer_registers->transmit_identification);
+              &llr->transmit_identification);
 
        /* Write the device SAS Address */
-       writel(0xFEDCBA98,
-              &iphy->link_layer_registers->sas_device_name_high);
-       writel(phy_idx, &iphy->link_layer_registers->sas_device_name_low);
+       writel(0xFEDCBA98, &llr->sas_device_name_high);
+       writel(phy_idx, &llr->sas_device_name_low);
 
        /* Write the source SAS Address */
-       writel(phy_oem->sas_address.high,
-               &iphy->link_layer_registers->source_sas_address_high);
-       writel(phy_oem->sas_address.low,
-               &iphy->link_layer_registers->source_sas_address_low);
+       writel(phy_oem->sas_address.high, &llr->source_sas_address_high);
+       writel(phy_oem->sas_address.low, &llr->source_sas_address_low);
 
        /* Clear and Set the PHY Identifier */
-       writel(0, &iphy->link_layer_registers->identify_frame_phy_id);
-       writel(SCU_SAS_TIPID_GEN_VALUE(ID, phy_idx),
-               &iphy->link_layer_registers->identify_frame_phy_id);
+       writel(0, &llr->identify_frame_phy_id);
+       writel(SCU_SAS_TIPID_GEN_VALUE(ID, phy_idx), &llr->identify_frame_phy_id);
 
        /* Change the initial state of the phy configuration register */
-       phy_configuration =
-               readl(&iphy->link_layer_registers->phy_configuration);
+       phy_configuration = readl(&llr->phy_configuration);
 
        /* Hold OOB state machine in reset */
        phy_configuration |=  SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
-       writel(phy_configuration,
-               &iphy->link_layer_registers->phy_configuration);
+       writel(phy_configuration, &llr->phy_configuration);
 
        /* Configure the SNW capabilities */
        phy_cap.all = 0;
@@ -149,15 +144,64 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy,
        phy_cap.gen3_no_ssc = 1;
        phy_cap.gen2_no_ssc = 1;
        phy_cap.gen1_no_ssc = 1;
-       if (ihost->oem_parameters.controller.do_enable_ssc == true) {
+       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 isci_pci_info *pci_info = to_pci_info(ihost->pdev);
+               bool en_sas = false;
+               bool en_sata = false;
+               u32 sas_type = 0;
+               u32 sata_spread = 0x2;
+               u32 sas_spread = 0x2;
+
                phy_cap.gen3_ssc = 1;
                phy_cap.gen2_ssc = 1;
                phy_cap.gen1_ssc = 1;
+
+               if (pci_info->orom->hdr.version < ISCI_ROM_VER_1_1)
+                       en_sas = en_sata = true;
+               else {
+                       sata_spread = ihost->oem_parameters.controller.ssc_sata_tx_spread_level;
+                       sas_spread = ihost->oem_parameters.controller.ssc_sas_tx_spread_level;
+
+                       if (sata_spread)
+                               en_sata = true;
+
+                       if (sas_spread) {
+                               en_sas = true;
+                               sas_type = ihost->oem_parameters.controller.ssc_sas_tx_type;
+                       }
+
+               }
+
+               if (en_sas) {
+                       u32 reg;
+
+                       reg = readl(&xcvr->afe_xcvr_control0);
+                       reg |= (0x00100000 | (sas_type << 19));
+                       writel(reg, &xcvr->afe_xcvr_control0);
+
+                       reg = readl(&xcvr->afe_tx_ssc_control);
+                       reg |= sas_spread << 8;
+                       writel(reg, &xcvr->afe_tx_ssc_control);
+               }
+
+               if (en_sata) {
+                       u32 reg;
+
+                       reg = readl(&xcvr->afe_tx_ssc_control);
+                       reg |= sata_spread;
+                       writel(reg, &xcvr->afe_tx_ssc_control);
+
+                       reg = readl(&llr->stp_control);
+                       reg |= 1 << 12;
+                       writel(reg, &llr->stp_control);
+               }
        }
 
-       /*
-        * The SAS specification indicates that the phy_capabilities that
-        * are transmitted shall have an even parity.  Calculate the parity. */
+       /* The SAS specification indicates that the phy_capabilities that
+        * are transmitted shall have an even parity.  Calculate the parity.
+        */
        parity_check = phy_cap.all;
        while (parity_check != 0) {
                if (parity_check & 0x1)
@@ -165,20 +209,20 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy,
                parity_check >>= 1;
        }
 
-       /*
-        * If parity indicates there are an odd number of bits set, then
-        * set the parity bit to 1 in the phy capabilities. */
+       /* If parity indicates there are an odd number of bits set, then
+        * set the parity bit to 1 in the phy capabilities.
+        */
        if ((parity_count % 2) != 0)
                phy_cap.parity = 1;
 
-       writel(phy_cap.all, &iphy->link_layer_registers->phy_capabilities);
+       writel(phy_cap.all, &llr->phy_capabilities);
 
        /* Set the enable spinup period but disable the ability to send
         * notify enable spinup
         */
        writel(SCU_ENSPINUP_GEN_VAL(COUNT,
                        phy_user->notify_enable_spin_up_insertion_frequency),
-               &iphy->link_layer_registers->notify_enable_spinup_control);
+               &llr->notify_enable_spinup_control);
 
        /* Write the ALIGN Insertion Ferequency for connected phy and
         * inpendent of connected state
@@ -189,11 +233,13 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy,
        clksm_value |= SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL(GENERAL,
                        phy_user->align_insertion_frequency);
 
-       writel(clksm_value, &iphy->link_layer_registers->clock_skew_management);
+       writel(clksm_value, &llr->clock_skew_management);
 
-       /* @todo Provide a way to write this register correctly */
-       writel(0x02108421,
-               &iphy->link_layer_registers->afe_lookup_table_control);
+       if (is_c0(ihost->pdev) || is_c1(ihost->pdev)) {
+               writel(0x04210400, &llr->afe_lookup_table_control);
+               writel(0x020A7C05, &llr->sas_primitive_timeout);
+       } else
+               writel(0x02108421, &llr->afe_lookup_table_control);
 
        llctl = SCU_SAS_LLCTL_GEN_VAL(NO_OUTBOUND_TASK_TIMEOUT,
                (u8)ihost->user_parameters.no_outbound_task_timeout);
@@ -210,9 +256,9 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy,
                break;
        }
        llctl |= SCU_SAS_LLCTL_GEN_VAL(MAX_LINK_RATE, link_rate);
-       writel(llctl, &iphy->link_layer_registers->link_layer_control);
+       writel(llctl, &llr->link_layer_control);
 
-       sp_timeouts = readl(&iphy->link_layer_registers->sas_phy_timeouts);
+       sp_timeouts = readl(&llr->sas_phy_timeouts);
 
        /* Clear the default 0x36 (54us) RATE_CHANGE timeout value. */
        sp_timeouts &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF);
@@ -222,20 +268,23 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy,
         */
        sp_timeouts |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B);
 
-       writel(sp_timeouts, &iphy->link_layer_registers->sas_phy_timeouts);
+       writel(sp_timeouts, &llr->sas_phy_timeouts);
 
        if (is_a2(ihost->pdev)) {
-               /* Program the max ARB time for the PHY to 700us so we inter-operate with
-                * the PMC expander which shuts down PHYs if the expander PHY generates too
-                * many breaks.  This time value will guarantee that the initiator PHY will
-                * generate the break.
+               /* Program the max ARB time for the PHY to 700us so we
+                * inter-operate with the PMC expander which shuts down
+                * PHYs if the expander PHY generates too many breaks.
+                * This time value will guarantee that the initiator PHY
+                * will generate the break.
                 */
                writel(SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME,
-                       &iphy->link_layer_registers->maximum_arbitration_wait_timer_timeout);
+                      &llr->maximum_arbitration_wait_timer_timeout);
        }
 
-       /* Disable link layer hang detection, rely on the OS timeout for I/O timeouts. */
-       writel(0, &iphy->link_layer_registers->link_layer_hang_detection_timeout);
+       /* Disable link layer hang detection, rely on the OS timeout for
+        * I/O timeouts.
+        */
+       writel(0, &llr->link_layer_hang_detection_timeout);
 
        /* We can exit the initial state to the stopped state */
        sci_change_state(&iphy->sm, SCI_PHY_STOPPED);
@@ -1049,24 +1098,25 @@ static void scu_link_layer_stop_protocol_engine(
        writel(enable_spinup_value, &iphy->link_layer_registers->notify_enable_spinup_control);
 }
 
-/**
- *
- *
- * This method will start the OOB/SN state machine for this struct isci_phy object.
- */
-static void scu_link_layer_start_oob(
-       struct isci_phy *iphy)
+static void scu_link_layer_start_oob(struct isci_phy *iphy)
 {
-       u32 scu_sas_pcfg_value;
-
-       scu_sas_pcfg_value =
-               readl(&iphy->link_layer_registers->phy_configuration);
-       scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
-       scu_sas_pcfg_value &=
-               ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) |
-               SCU_SAS_PCFG_GEN_BIT(HARD_RESET));
-       writel(scu_sas_pcfg_value,
-              &iphy->link_layer_registers->phy_configuration);
+       struct scu_link_layer_registers __iomem *ll = iphy->link_layer_registers;
+       u32 val;
+
+       /** Reset OOB sequence - start */
+       val = readl(&ll->phy_configuration);
+       val &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) |
+                SCU_SAS_PCFG_GEN_BIT(HARD_RESET));
+       writel(val, &ll->phy_configuration);
+       readl(&ll->phy_configuration); /* flush */
+       /** Reset OOB sequence - end */
+
+       /** Start OOB sequence - start */
+       val = readl(&ll->phy_configuration);
+       val |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
+       writel(val, &ll->phy_configuration);
+       readl(&ll->phy_configuration); /* flush */
+       /** Start OOB sequence - end */
 }
 
 /**
index ac7f27749f975761a1beefc7f1b1741a5c02e0bc..7c6ac58a5c4c45c37af504f8e10bfa84cb7df3ee 100644 (file)
@@ -114,7 +114,7 @@ static u32 sci_port_get_phys(struct isci_port *iport)
  * value is returned if the specified port is not valid.  When this value is
  * returned, no data is copied to the properties output parameter.
  */
-static enum sci_status sci_port_get_properties(struct isci_port *iport,
+enum sci_status sci_port_get_properties(struct isci_port *iport,
                                                struct sci_port_properties *prop)
 {
        if (!iport || iport->logical_port_index == SCIC_SDS_DUMMY_PORT)
@@ -647,19 +647,26 @@ void sci_port_setup_transports(struct isci_port *iport, u32 device_id)
        }
 }
 
-static void sci_port_activate_phy(struct isci_port *iport, struct isci_phy *iphy,
-                                 bool do_notify_user)
+static void sci_port_resume_phy(struct isci_port *iport, struct isci_phy *iphy)
+{
+       sci_phy_resume(iphy);
+       iport->enabled_phy_mask |= 1 << iphy->phy_index;
+}
+
+static void sci_port_activate_phy(struct isci_port *iport,
+                                 struct isci_phy *iphy,
+                                 u8 flags)
 {
        struct isci_host *ihost = iport->owning_controller;
 
-       if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA)
+       if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA && (flags & PF_RESUME))
                sci_phy_resume(iphy);
 
        iport->active_phy_mask |= 1 << iphy->phy_index;
 
        sci_controller_clear_invalid_phy(ihost, iphy);
 
-       if (do_notify_user == true)
+       if (flags & PF_NOTIFY)
                isci_port_link_up(ihost, iport, iphy);
 }
 
@@ -669,14 +676,19 @@ void sci_port_deactivate_phy(struct isci_port *iport, struct isci_phy *iphy,
        struct isci_host *ihost = iport->owning_controller;
 
        iport->active_phy_mask &= ~(1 << iphy->phy_index);
+       iport->enabled_phy_mask &= ~(1 << iphy->phy_index);
        if (!iport->active_phy_mask)
                iport->last_active_phy = iphy->phy_index;
 
        iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN;
 
-       /* Re-assign the phy back to the LP as if it were a narrow port */
-       writel(iphy->phy_index,
-               &iport->port_pe_configuration_register[iphy->phy_index]);
+       /* Re-assign the phy back to the LP as if it were a narrow port for APC
+        * mode. For MPC mode, the phy will remain in the port.
+        */
+       if (iport->owning_controller->oem_parameters.controller.mode_type ==
+               SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE)
+               writel(iphy->phy_index,
+                       &iport->port_pe_configuration_register[iphy->phy_index]);
 
        if (do_notify_user == true)
                isci_port_link_down(ihost, iphy, iport);
@@ -701,18 +713,16 @@ static void sci_port_invalid_link_up(struct isci_port *iport, struct isci_phy *i
  * sci_port_general_link_up_handler - phy can be assigned to port?
  * @sci_port: sci_port object for which has a phy that has gone link up.
  * @sci_phy: This is the struct isci_phy object that has gone link up.
- * @do_notify_user: This parameter specifies whether to inform the user (via
- *    sci_port_link_up()) as to the fact that a new phy as become ready.
+ * @flags: PF_RESUME, PF_NOTIFY to sci_port_activate_phy
  *
- * Determine if this phy can be assigned to this
- * port . If the phy is not a valid PHY for
- * this port then the function will notify the user. A PHY can only be
- * part of a port if it's attached SAS ADDRESS is the same as all other PHYs in
- * the same port. none
+ * Determine if this phy can be assigned to this port . If the phy is
+ * not a valid PHY for this port then the function will notify the user.
+ * A PHY can only be part of a port if it's attached SAS ADDRESS is the
+ * same as all other PHYs in the same port.
  */
 static void sci_port_general_link_up_handler(struct isci_port *iport,
-                                                 struct isci_phy *iphy,
-                                                 bool do_notify_user)
+                                            struct isci_phy *iphy,
+                                            u8 flags)
 {
        struct sci_sas_address port_sas_address;
        struct sci_sas_address phy_sas_address;
@@ -730,7 +740,7 @@ static void sci_port_general_link_up_handler(struct isci_port *iport,
            iport->active_phy_mask == 0) {
                struct sci_base_state_machine *sm = &iport->sm;
 
-               sci_port_activate_phy(iport, iphy, do_notify_user);
+               sci_port_activate_phy(iport, iphy, flags);
                if (sm->current_state_id == SCI_PORT_RESETTING)
                        port_state_machine_change(iport, SCI_PORT_READY);
        } else
@@ -781,11 +791,16 @@ bool sci_port_link_detected(
        struct isci_phy *iphy)
 {
        if ((iport->logical_port_index != SCIC_SDS_DUMMY_PORT) &&
-           (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) &&
-           sci_port_is_wide(iport)) {
-               sci_port_invalid_link_up(iport, iphy);
-
-               return false;
+           (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA)) {
+               if (sci_port_is_wide(iport)) {
+                       sci_port_invalid_link_up(iport, iphy);
+                       return false;
+               } else {
+                       struct isci_host *ihost = iport->owning_controller;
+                       struct isci_port *dst_port = &(ihost->ports[iphy->phy_index]);
+                       writel(iphy->phy_index,
+                              &dst_port->port_pe_configuration_register[iphy->phy_index]);
+               }
        }
 
        return true;
@@ -975,6 +990,13 @@ static void sci_port_ready_substate_waiting_enter(struct sci_base_state_machine
        }
 }
 
+static void scic_sds_port_ready_substate_waiting_exit(
+                                       struct sci_base_state_machine *sm)
+{
+       struct isci_port *iport = container_of(sm, typeof(*iport), sm);
+       sci_port_resume_port_task_scheduler(iport);
+}
+
 static void sci_port_ready_substate_operational_enter(struct sci_base_state_machine *sm)
 {
        u32 index;
@@ -988,13 +1010,13 @@ static void sci_port_ready_substate_operational_enter(struct sci_base_state_mach
                        writel(iport->physical_port_index,
                                &iport->port_pe_configuration_register[
                                        iport->phy_table[index]->phy_index]);
+                       if (((iport->active_phy_mask^iport->enabled_phy_mask) & (1 << index)) != 0)
+                               sci_port_resume_phy(iport, iport->phy_table[index]);
                }
        }
 
        sci_port_update_viit_entry(iport);
 
-       sci_port_resume_port_task_scheduler(iport);
-
        /*
         * Post the dummy task for the port so the hardware can schedule
         * io correctly
@@ -1061,20 +1083,9 @@ static void sci_port_ready_substate_configuring_enter(struct sci_base_state_mach
        if (iport->active_phy_mask == 0) {
                isci_port_not_ready(ihost, iport);
 
-               port_state_machine_change(iport,
-                                         SCI_PORT_SUB_WAITING);
-       } else if (iport->started_request_count == 0)
-               port_state_machine_change(iport,
-                                         SCI_PORT_SUB_OPERATIONAL);
-}
-
-static void sci_port_ready_substate_configuring_exit(struct sci_base_state_machine *sm)
-{
-       struct isci_port *iport = container_of(sm, typeof(*iport), sm);
-
-       sci_port_suspend_port_task_scheduler(iport);
-       if (iport->ready_exit)
-               sci_port_invalidate_dummy_remote_node(iport);
+               port_state_machine_change(iport, SCI_PORT_SUB_WAITING);
+       } else
+               port_state_machine_change(iport, SCI_PORT_SUB_OPERATIONAL);
 }
 
 enum sci_status sci_port_start(struct isci_port *iport)
@@ -1252,7 +1263,7 @@ enum sci_status sci_port_add_phy(struct isci_port *iport,
                if (status != SCI_SUCCESS)
                        return status;
 
-               sci_port_general_link_up_handler(iport, iphy, true);
+               sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY|PF_RESUME);
                iport->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING;
                port_state_machine_change(iport, SCI_PORT_SUB_CONFIGURING);
 
@@ -1262,7 +1273,7 @@ enum sci_status sci_port_add_phy(struct isci_port *iport,
 
                if (status != SCI_SUCCESS)
                        return status;
-               sci_port_general_link_up_handler(iport, iphy, true);
+               sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY);
 
                /* Re-enter the configuring state since this may be the last phy in
                 * the port.
@@ -1338,13 +1349,13 @@ enum sci_status sci_port_link_up(struct isci_port *iport,
                /* Since this is the first phy going link up for the port we
                 * can just enable it and continue
                 */
-               sci_port_activate_phy(iport, iphy, true);
+               sci_port_activate_phy(iport, iphy, PF_NOTIFY|PF_RESUME);
 
                port_state_machine_change(iport,
                                          SCI_PORT_SUB_OPERATIONAL);
                return SCI_SUCCESS;
        case SCI_PORT_SUB_OPERATIONAL:
-               sci_port_general_link_up_handler(iport, iphy, true);
+               sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY|PF_RESUME);
                return SCI_SUCCESS;
        case SCI_PORT_RESETTING:
                /* TODO We should  make  sure  that  the phy  that  has gone
@@ -1361,7 +1372,7 @@ enum sci_status sci_port_link_up(struct isci_port *iport,
                /* In the resetting state we don't notify the user regarding
                 * link up and link down notifications.
                 */
-               sci_port_general_link_up_handler(iport, iphy, false);
+               sci_port_general_link_up_handler(iport, iphy, PF_RESUME);
                return SCI_SUCCESS;
        default:
                dev_warn(sciport_to_dev(iport),
@@ -1584,14 +1595,14 @@ static const struct sci_base_state sci_port_state_table[] = {
        },
        [SCI_PORT_SUB_WAITING] = {
                .enter_state = sci_port_ready_substate_waiting_enter,
+               .exit_state  = scic_sds_port_ready_substate_waiting_exit,
        },
        [SCI_PORT_SUB_OPERATIONAL] = {
                .enter_state = sci_port_ready_substate_operational_enter,
                .exit_state  = sci_port_ready_substate_operational_exit
        },
        [SCI_PORT_SUB_CONFIGURING] = {
-               .enter_state = sci_port_ready_substate_configuring_enter,
-               .exit_state  = sci_port_ready_substate_configuring_exit
+               .enter_state = sci_port_ready_substate_configuring_enter
        },
        [SCI_PORT_RESETTING] = {
                .exit_state  = sci_port_resetting_state_exit
@@ -1609,6 +1620,7 @@ void sci_port_construct(struct isci_port *iport, u8 index,
        iport->logical_port_index  = SCIC_SDS_DUMMY_PORT;
        iport->physical_port_index = index;
        iport->active_phy_mask     = 0;
+       iport->enabled_phy_mask    = 0;
        iport->last_active_phy     = 0;
        iport->ready_exit          = false;
 
index cb5ffbc386038136812da1e596ca5059ff391615..08116090eb7015dbe7c4b3862748a20601e6d765 100644 (file)
@@ -63,6 +63,9 @@
 
 #define SCIC_SDS_DUMMY_PORT   0xFF
 
+#define PF_NOTIFY (1 << 0)
+#define PF_RESUME (1 << 1)
+
 struct isci_phy;
 struct isci_host;
 
@@ -83,6 +86,8 @@ enum isci_status {
  * @logical_port_index: software port index
  * @physical_port_index: hardware port index
  * @active_phy_mask: identifies phy members
+ * @enabled_phy_mask: phy mask for the port
+ *                    that are already part of the port
  * @reserved_tag:
  * @reserved_rni: reserver for port task scheduler workaround
  * @started_request_count: reference count for outstanding commands
@@ -104,6 +109,7 @@ struct isci_port {
        u8 logical_port_index;
        u8 physical_port_index;
        u8 active_phy_mask;
+       u8 enabled_phy_mask;
        u8 last_active_phy;
        u16 reserved_rni;
        u16 reserved_tag;
@@ -250,6 +256,10 @@ bool sci_port_link_detected(
        struct isci_port *iport,
        struct isci_phy *iphy);
 
+enum sci_status sci_port_get_properties(
+       struct isci_port *iport,
+       struct sci_port_properties *prop);
+
 enum sci_status sci_port_link_up(struct isci_port *iport,
                                      struct isci_phy *iphy);
 enum sci_status sci_port_link_down(struct isci_port *iport,
index 38a99d2811411d102220a96bdf918579fb47546b..6d1e9544cbe5c03b7f84059b7651c1b9d560ffb2 100644 (file)
@@ -57,7 +57,7 @@
 
 #define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT    (10)
 #define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT    (10)
-#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION  (100)
+#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION  (250)
 
 enum SCIC_SDS_APC_ACTIVITY {
        SCIC_SDS_APC_SKIP_PHY,
@@ -466,6 +466,23 @@ sci_apc_agent_validate_phy_configuration(struct isci_host *ihost,
        return sci_port_configuration_agent_validate_ports(ihost, port_agent);
 }
 
+/*
+ * This routine will restart the automatic port configuration timeout
+ * timer for the next time period. This could be caused by either a link
+ * down event or a link up event where we can not yet tell to which a phy
+ * belongs.
+ */
+static void sci_apc_agent_start_timer(
+       struct sci_port_configuration_agent *port_agent,
+       u32 timeout)
+{
+       if (port_agent->timer_pending)
+               sci_del_timer(&port_agent->timer);
+
+       port_agent->timer_pending = true;
+       sci_mod_timer(&port_agent->timer, timeout);
+}
+
 static void sci_apc_agent_configure_ports(struct isci_host *ihost,
                                               struct sci_port_configuration_agent *port_agent,
                                               struct isci_phy *iphy,
@@ -565,17 +582,8 @@ static void sci_apc_agent_configure_ports(struct isci_host *ihost,
                break;
 
        case SCIC_SDS_APC_START_TIMER:
-               /*
-                * This can occur for either a link down event, or a link
-                * up event where we cannot yet tell the port to which a
-                * phy belongs.
-                */
-               if (port_agent->timer_pending)
-                       sci_del_timer(&port_agent->timer);
-
-               port_agent->timer_pending = true;
-               sci_mod_timer(&port_agent->timer,
-                             SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION);
+               sci_apc_agent_start_timer(port_agent,
+                                         SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION);
                break;
 
        case SCIC_SDS_APC_SKIP_PHY:
@@ -607,7 +615,8 @@ static void sci_apc_agent_link_up(struct isci_host *ihost,
        if (!iport) {
                /* the phy is not the part of this port */
                port_agent->phy_ready_mask |= 1 << phy_index;
-               sci_apc_agent_configure_ports(ihost, port_agent, iphy, true);
+               sci_apc_agent_start_timer(port_agent,
+                                         SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION);
        } else {
                /* the phy is already the part of the port */
                u32 port_state = iport->sm.current_state_id;
index b5f4341de2434ead30763b4228e49ff5ee2edc67..9b8117b9d7569e7a8bda7623ec2aa3a07fcfffb6 100644 (file)
@@ -147,7 +147,7 @@ struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmw
 
        memcpy(orom, fw->data, fw->size);
 
-       if (is_c0(pdev))
+       if (is_c0(pdev) || is_c1(pdev))
                goto out;
 
        /*
index 2c75248ca326ea38e3a9256da8e966fddd516d41..bb0e9d4d97c9a8f0437e51aee3440c8ff0060004 100644 (file)
@@ -152,7 +152,7 @@ struct sci_user_parameters {
 #define MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT 4
 
 struct sci_oem_params;
-int sci_oem_parameters_validate(struct sci_oem_params *oem);
+int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version);
 
 struct isci_orom;
 struct isci_orom *isci_request_oprom(struct pci_dev *pdev);
@@ -191,6 +191,11 @@ struct isci_oem_hdr {
                        0x1a, 0x04, 0xc6)
 #define ISCI_EFI_VAR_NAME      "RstScuO"
 
+#define ISCI_ROM_VER_1_0       0x10
+#define ISCI_ROM_VER_1_1       0x11
+#define ISCI_ROM_VER_1_3       0x13
+#define ISCI_ROM_VER_LATEST    ISCI_ROM_VER_1_3
+
 /* Allowed PORT configuration modes APC Automatic PORT configuration mode is
  * defined by the OEM configuration parameters providing no PHY_MASK parameters
  * for any PORT. i.e. There are no phys assigned to any of the ports at start.
@@ -220,8 +225,86 @@ struct sci_oem_params {
        struct {
                uint8_t mode_type;
                uint8_t max_concurr_spin_up;
-               uint8_t do_enable_ssc;
-               uint8_t reserved;
+               /*
+                * This bitfield indicates the OEM's desired default Tx
+                * Spread Spectrum Clocking (SSC) settings for SATA and SAS.
+                * NOTE: Default SSC Modulation Frequency is 31.5KHz.
+                */
+               union {
+                       struct {
+                       /*
+                        * NOTE: Max spread for SATA is +0 / -5000 PPM.
+                        * Down-spreading SSC (only method allowed for SATA):
+                        *  SATA SSC Tx Disabled                    = 0x0
+                        *  SATA SSC Tx at +0 / -1419 PPM Spread    = 0x2
+                        *  SATA SSC Tx at +0 / -2129 PPM Spread    = 0x3
+                        *  SATA SSC Tx at +0 / -4257 PPM Spread    = 0x6
+                        *  SATA SSC Tx at +0 / -4967 PPM Spread    = 0x7
+                        */
+                               uint8_t ssc_sata_tx_spread_level:4;
+                       /*
+                        * SAS SSC Tx Disabled                     = 0x0
+                        *
+                        * NOTE: Max spread for SAS down-spreading +0 /
+                        *       -2300 PPM
+                        * Down-spreading SSC:
+                        *  SAS SSC Tx at +0 / -1419 PPM Spread     = 0x2
+                        *  SAS SSC Tx at +0 / -2129 PPM Spread     = 0x3
+                        *
+                        * NOTE: Max spread for SAS center-spreading +2300 /
+                        *       -2300 PPM
+                        * Center-spreading SSC:
+                        *  SAS SSC Tx at +1064 / -1064 PPM Spread  = 0x3
+                        *  SAS SSC Tx at +2129 / -2129 PPM Spread  = 0x6
+                        */
+                               uint8_t ssc_sas_tx_spread_level:3;
+                       /*
+                        * NOTE: Refer to the SSC section of the SAS 2.x
+                        * Specification for proper setting of this field.
+                        * For standard SAS Initiator SAS PHY operation it
+                        * should be 0 for Down-spreading.
+                        * SAS SSC Tx spread type:
+                        *  Down-spreading SSC      = 0
+                        *  Center-spreading SSC    = 1
+                        */
+                               uint8_t ssc_sas_tx_type:1;
+                       };
+                       uint8_t do_enable_ssc;
+               };
+               /*
+                * This field indicates length of the SAS/SATA cable between
+                * host and device.
+                * This field is used make relationship between analog
+                * parameters of the phy in the silicon and length of the cable.
+                * Supported cable attenuation levels:
+                * "short"- up to 3m, "medium"-3m to 6m, and "long"- more than
+                * 6m.
+                *
+                * This is bit mask field:
+                *
+                * BIT:      (MSB) 7     6     5     4
+                * ASSIGNMENT:   <phy3><phy2><phy1><phy0>  - Medium cable
+                *                                           length assignment
+                * BIT:            3     2     1     0  (LSB)
+                * ASSIGNMENT:   <phy3><phy2><phy1><phy0>  - Long cable length
+                *                                           assignment
+                *
+                * BITS 7-4 are set when the cable length is assigned to medium
+                * BITS 3-0 are set when the cable length is assigned to long
+                *
+                * The BIT positions are clear when the cable length is
+                * assigned to short.
+                *
+                * Setting the bits for both long and medium cable length is
+                * undefined.
+                *
+                * A value of 0x84 would assign
+                *    phy3 - medium
+                *    phy2 - long
+                *    phy1 - short
+                *    phy0 - short
+                */
+               uint8_t cable_selection_mask;
        } controller;
 
        struct {
index b207cd3b15a0514da4579e9e869556d6b95dc961..dd74b6ceeb823df92bd69e69a0964069f1b5011a 100644 (file)
@@ -53,6 +53,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include <scsi/sas.h>
+#include <linux/bitops.h>
 #include "isci.h"
 #include "port.h"
 #include "remote_device.h"
@@ -1101,6 +1102,7 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport,
                                                       struct isci_remote_device *idev)
 {
        enum sci_status status;
+       struct sci_port_properties properties;
        struct domain_device *dev = idev->domain_dev;
 
        sci_remote_device_construct(iport, idev);
@@ -1110,6 +1112,11 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport,
         * entries will be needed to store the remote node.
         */
        idev->is_direct_attached = true;
+
+       sci_port_get_properties(iport, &properties);
+       /* Get accurate port width from port's phy mask for a DA device. */
+       idev->device_port_width = hweight32(properties.phy_mask);
+
        status = sci_controller_allocate_remote_node_context(iport->owning_controller,
                                                                  idev,
                                                                  &idev->rnc.remote_node_index);
@@ -1125,9 +1132,6 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport,
 
        idev->connection_rate = sci_port_get_max_allowed_speed(iport);
 
-       /* / @todo Should I assign the port width by reading all of the phys on the port? */
-       idev->device_port_width = 1;
-
        return SCI_SUCCESS;
 }
 
index 66ad3dc89498a3ab305de95bc179ecaf42afa2f3..f5a3f7d2bdab29059af48d4b333d39b91c57d3d0 100644 (file)
@@ -496,7 +496,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
                }
        }
 
-       isci_print_tmf(tmf);
+       isci_print_tmf(ihost, tmf);
 
        if (tmf->status == SCI_SUCCESS)
                ret =  TMF_RESP_FUNC_COMPLETE;
index bc78c0a41d5cac86df69d6a23af08e6dac949552..1b27b3797c6c9cce8c1160c11d43240ccc4a52fe 100644 (file)
@@ -106,7 +106,6 @@ struct isci_tmf {
        } resp;
        unsigned char lun[8];
        u16 io_tag;
-       struct isci_remote_device *device;
        enum isci_tmf_function_codes tmf_code;
        int status;
 
@@ -120,10 +119,10 @@ struct isci_tmf {
 
 };
 
-static inline void isci_print_tmf(struct isci_tmf *tmf)
+static inline void isci_print_tmf(struct isci_host *ihost, struct isci_tmf *tmf)
 {
        if (SAS_PROTOCOL_SATA == tmf->proto)
-               dev_dbg(&tmf->device->isci_port->isci_host->pdev->dev,
+               dev_dbg(&ihost->pdev->dev,
                        "%s: status = %x\n"
                        "tmf->resp.d2h_fis.status = %x\n"
                        "tmf->resp.d2h_fis.error = %x\n",
@@ -132,7 +131,7 @@ static inline void isci_print_tmf(struct isci_tmf *tmf)
                        tmf->resp.d2h_fis.status,
                        tmf->resp.d2h_fis.error);
        else
-               dev_dbg(&tmf->device->isci_port->isci_host->pdev->dev,
+               dev_dbg(&ihost->pdev->dev,
                        "%s: status = %x\n"
                        "tmf->resp.resp_iu.data_present = %x\n"
                        "tmf->resp.resp_iu.status = %x\n"
index 7269e928824a07f93efb1e570eb136f6cbedfbeb..1d1b0c9da29ba684100515b337431ccfb8be2b08 100644 (file)
@@ -61,7 +61,7 @@ static void fc_disc_restart(struct fc_disc *);
  * Locking Note: This function expects that the lport mutex is locked before
  * calling it.
  */
-void fc_disc_stop_rports(struct fc_disc *disc)
+static void fc_disc_stop_rports(struct fc_disc *disc)
 {
        struct fc_lport *lport;
        struct fc_rport_priv *rdata;
@@ -682,7 +682,7 @@ static int fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp)
  * fc_disc_stop() - Stop discovery for a given lport
  * @lport: The local port that discovery should stop on
  */
-void fc_disc_stop(struct fc_lport *lport)
+static void fc_disc_stop(struct fc_lport *lport)
 {
        struct fc_disc *disc = &lport->disc;
 
@@ -698,7 +698,7 @@ void fc_disc_stop(struct fc_lport *lport)
  * This function will block until discovery has been
  * completely stopped and all rports have been deleted.
  */
-void fc_disc_stop_final(struct fc_lport *lport)
+static void fc_disc_stop_final(struct fc_lport *lport)
 {
        fc_disc_stop(lport);
        lport->tt.rport_flush_queue();
index fb9161dc4ca67411f07413018562286fcaeff017..e17a28d324d04ccdf903043ae4549e04c94ccb85 100644 (file)
@@ -28,6 +28,7 @@
 #include <scsi/fc/fc_els.h>
 #include <scsi/libfc.h>
 #include <scsi/fc_encode.h>
+#include "fc_libfc.h"
 
 /**
  * fc_elsct_send() - Send an ELS or CT frame
index 9de9db27e87401b1f5cf244a15e9320011faa276..4d70d96fa5dc5730016a00a3c1753370ca5e980e 100644 (file)
@@ -91,7 +91,7 @@ struct fc_exch_pool {
  * It manages the allocation of exchange IDs.
  */
 struct fc_exch_mgr {
-       struct fc_exch_pool *pool;
+       struct fc_exch_pool __percpu *pool;
        mempool_t       *ep_pool;
        enum fc_class   class;
        struct kref     kref;
index 221875ec3d7c64de19c4f6404961be441fb16f34..f607314810accf03b38bee7b1f36fde6d4c2da9f 100644 (file)
@@ -155,6 +155,7 @@ static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lport, gfp_t gfp)
                fsp->xfer_ddp = FC_XID_UNKNOWN;
                atomic_set(&fsp->ref_cnt, 1);
                init_timer(&fsp->timer);
+               fsp->timer.data = (unsigned long)fsp;
                INIT_LIST_HEAD(&fsp->list);
                spin_lock_init(&fsp->scsi_pkt_lock);
        }
@@ -1850,9 +1851,6 @@ int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd)
        }
        put_cpu();
 
-       init_timer(&fsp->timer);
-       fsp->timer.data = (unsigned long)fsp;
-
        /*
         * send it to the lower layer
         * if we get -1 return then put the request in the pending
index e77094a587ed62aa17e1c1479d6a1ba04ad2af06..83750ebb527f5e2841f26a06d70a063658d8603f 100644 (file)
@@ -677,7 +677,8 @@ EXPORT_SYMBOL(fc_set_mfs);
  * @lport: The local port receiving the event
  * @event: The discovery event
  */
-void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event)
+static void fc_lport_disc_callback(struct fc_lport *lport,
+                                  enum fc_disc_event event)
 {
        switch (event) {
        case DISC_EV_SUCCESS:
@@ -1568,7 +1569,7 @@ EXPORT_SYMBOL(fc_lport_flogi_resp);
  * Locking Note: The lport lock is expected to be held before calling
  * this routine.
  */
-void fc_lport_enter_flogi(struct fc_lport *lport)
+static void fc_lport_enter_flogi(struct fc_lport *lport)
 {
        struct fc_frame *fp;
 
index b9e434844a69bb93fe12e153896973a1c8df2968..83aa1efec875999d5c980ab27dcb93cfc71e734c 100644 (file)
@@ -391,7 +391,7 @@ static void fc_rport_work(struct work_struct *work)
  * If it appears we are already logged in, ADISC is used to verify
  * the setup.
  */
-int fc_rport_login(struct fc_rport_priv *rdata)
+static int fc_rport_login(struct fc_rport_priv *rdata)
 {
        mutex_lock(&rdata->rp_mutex);
 
@@ -451,7 +451,7 @@ static void fc_rport_enter_delete(struct fc_rport_priv *rdata,
  * function will hold the rport lock, call an _enter_*
  * function and then unlock the rport.
  */
-int fc_rport_logoff(struct fc_rport_priv *rdata)
+static int fc_rport_logoff(struct fc_rport_priv *rdata)
 {
        mutex_lock(&rdata->rp_mutex);
 
@@ -653,8 +653,8 @@ static int fc_rport_login_complete(struct fc_rport_priv *rdata,
  * @fp:            The FLOGI response frame
  * @rp_arg: The remote port that received the FLOGI response
  */
-void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
-                        void *rp_arg)
+static void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
+                               void *rp_arg)
 {
        struct fc_rport_priv *rdata = rp_arg;
        struct fc_lport *lport = rdata->local_port;
@@ -1520,7 +1520,7 @@ reject:
  *
  * Locking Note: Called with the lport lock held.
  */
-void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
+static void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
 {
        struct fc_seq_els_data els_data;
 
index 5c1776406c963f996e16aac4781fe4540112d250..15eefa1d61fd8dfbd25d696bb519a28570005454 100644 (file)
@@ -306,19 +306,22 @@ mega_query_adapter(adapter_t *adapter)
        adapter->host->sg_tablesize = adapter->sglen;
 
 
-       /* use HP firmware and bios version encoding */
+       /* use HP firmware and bios version encoding
+          Note: fw_version[0|1] and bios_version[0|1] were originally shifted
+          right 8 bits making them zero. This 0 value was hardcoded to fix
+          sparse warnings. */
        if (adapter->product_info.subsysvid == HP_SUBSYS_VID) {
                sprintf (adapter->fw_version, "%c%d%d.%d%d",
                         adapter->product_info.fw_version[2],
-                        adapter->product_info.fw_version[1] >> 8,
+                        0,
                         adapter->product_info.fw_version[1] & 0x0f,
-                        adapter->product_info.fw_version[0] >> 8,
+                        0,
                         adapter->product_info.fw_version[0] & 0x0f);
                sprintf (adapter->bios_version, "%c%d%d.%d%d",
                         adapter->product_info.bios_version[2],
-                        adapter->product_info.bios_version[1] >> 8,
+                        0,
                         adapter->product_info.bios_version[1] & 0x0f,
-                        adapter->product_info.bios_version[0] >> 8,
+                        0,
                         adapter->product_info.bios_version[0] & 0x0f);
        } else {
                memcpy(adapter->fw_version,
index dd94c7d574fb8b8027f574657cbdc43b46fa906f..e5f416f8042d45620cab8ced05fc56738cc8764a 100644 (file)
@@ -33,9 +33,9 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION                                "00.00.06.12-rc1"
-#define MEGASAS_RELDATE                                "Oct. 5, 2011"
-#define MEGASAS_EXT_VERSION                    "Wed. Oct. 5 17:00:00 PDT 2011"
+#define MEGASAS_VERSION                                "00.00.06.14-rc1"
+#define MEGASAS_RELDATE                                "Jan. 6, 2012"
+#define MEGASAS_EXT_VERSION                    "Fri. Jan. 6 17:00:00 PDT 2012"
 
 /*
  * Device IDs
@@ -773,7 +773,6 @@ struct megasas_ctrl_info {
 
 #define MFI_OB_INTR_STATUS_MASK                        0x00000002
 #define MFI_POLL_TIMEOUT_SECS                  60
-#define MEGASAS_COMPLETION_TIMER_INTERVAL      (HZ/10)
 
 #define MFI_REPLY_1078_MESSAGE_INTERRUPT       0x80000000
 #define MFI_REPLY_GEN2_MESSAGE_INTERRUPT       0x00000001
@@ -1353,7 +1352,6 @@ struct megasas_instance {
        u32 mfiStatus;
        u32 last_seq_num;
 
-       struct timer_list io_completion_timer;
        struct list_head internal_reset_pending_q;
 
        /* Ptr to hba specific information */
index 29a994f9c4f1e6a9c0973ecd3cebe413f4937c7b..8b300be442849336d296768c69a44e126e24a40d 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.12-rc1
+ *  Version : v00.00.06.14-rc1
  *
  *  Authors: LSI Corporation
  *           Sreenivas Bagalkote
 #include "megaraid_sas_fusion.h"
 #include "megaraid_sas.h"
 
-/*
- * poll_mode_io:1- schedule complete completion from q cmd
- */
-static unsigned int poll_mode_io;
-module_param_named(poll_mode_io, poll_mode_io, int, 0);
-MODULE_PARM_DESC(poll_mode_io,
-       "Complete cmds from IO path, (default=0)");
-
 /*
  * Number of sectors per IO command
  * Will be set in megasas_init_mfi if user does not provide
@@ -1439,11 +1431,6 @@ megasas_build_and_issue_cmd(struct megasas_instance *instance,
 
        instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
                                cmd->frame_count-1, instance->reg_set);
-       /*
-        * Check if we have pend cmds to be completed
-        */
-       if (poll_mode_io && atomic_read(&instance->fw_outstanding))
-               tasklet_schedule(&instance->isr_tasklet);
 
        return 0;
 out_return_cmd:
@@ -3370,47 +3357,6 @@ fail_fw_init:
        return -EINVAL;
 }
 
-/**
- * megasas_start_timer - Initializes a timer object
- * @instance:          Adapter soft state
- * @timer:             timer object to be initialized
- * @fn:                        timer function
- * @interval:          time interval between timer function call
- */
-static inline void
-megasas_start_timer(struct megasas_instance *instance,
-                       struct timer_list *timer,
-                       void *fn, unsigned long interval)
-{
-       init_timer(timer);
-       timer->expires = jiffies + interval;
-       timer->data = (unsigned long)instance;
-       timer->function = fn;
-       add_timer(timer);
-}
-
-/**
- * megasas_io_completion_timer - Timer fn
- * @instance_addr:     Address of adapter soft state
- *
- * Schedules tasklet for cmd completion
- * if poll_mode_io is set
- */
-static void
-megasas_io_completion_timer(unsigned long instance_addr)
-{
-       struct megasas_instance *instance =
-                       (struct megasas_instance *)instance_addr;
-
-       if (atomic_read(&instance->fw_outstanding))
-               tasklet_schedule(&instance->isr_tasklet);
-
-       /* Restart timer */
-       if (poll_mode_io)
-               mod_timer(&instance->io_completion_timer,
-                       jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL);
-}
-
 static u32
 megasas_init_adapter_mfi(struct megasas_instance *instance)
 {
@@ -3638,11 +3584,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
        tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
                (unsigned long)instance);
 
-       /* Initialize the cmd completion timer */
-       if (poll_mode_io)
-               megasas_start_timer(instance, &instance->io_completion_timer,
-                               megasas_io_completion_timer,
-                               MEGASAS_COMPLETION_TIMER_INTERVAL);
        return 0;
 
 fail_init_adapter:
@@ -4369,9 +4310,6 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
        host = instance->host;
        instance->unload = 1;
 
-       if (poll_mode_io)
-               del_timer_sync(&instance->io_completion_timer);
-
        megasas_flush_cache(instance);
        megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
 
@@ -4511,12 +4449,6 @@ megasas_resume(struct pci_dev *pdev)
        }
 
        instance->instancet->enable_intr(instance->reg_set);
-
-       /* Initialize the cmd completion timer */
-       if (poll_mode_io)
-               megasas_start_timer(instance, &instance->io_completion_timer,
-                               megasas_io_completion_timer,
-                               MEGASAS_COMPLETION_TIMER_INTERVAL);
        instance->unload = 0;
 
        /*
@@ -4570,9 +4502,6 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
        host = instance->host;
        fusion = instance->ctrl_context;
 
-       if (poll_mode_io)
-               del_timer_sync(&instance->io_completion_timer);
-
        scsi_remove_host(instance->host);
        megasas_flush_cache(instance);
        megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
@@ -4773,6 +4702,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
        memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
        cmd->frame->hdr.context = cmd->index;
        cmd->frame->hdr.pad_0 = 0;
+       cmd->frame->hdr.flags &= ~(MFI_FRAME_IEEE | MFI_FRAME_SGL64 |
+                                  MFI_FRAME_SENSE64);
 
        /*
         * The management interface between applications and the fw uses
@@ -5219,60 +5150,6 @@ megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t coun
 static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUSR, megasas_sysfs_show_dbg_lvl,
                megasas_sysfs_set_dbg_lvl);
 
-static ssize_t
-megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf)
-{
-       return sprintf(buf, "%u\n", poll_mode_io);
-}
-
-static ssize_t
-megasas_sysfs_set_poll_mode_io(struct device_driver *dd,
-                               const char *buf, size_t count)
-{
-       int retval = count;
-       int tmp = poll_mode_io;
-       int i;
-       struct megasas_instance *instance;
-
-       if (sscanf(buf, "%u", &poll_mode_io) < 1) {
-               printk(KERN_ERR "megasas: could not set poll_mode_io\n");
-               retval = -EINVAL;
-       }
-
-       /*
-        * Check if poll_mode_io is already set or is same as previous value
-        */
-       if ((tmp && poll_mode_io) || (tmp == poll_mode_io))
-               goto out;
-
-       if (poll_mode_io) {
-               /*
-                * Start timers for all adapters
-                */
-               for (i = 0; i < megasas_mgmt_info.max_index; i++) {
-                       instance = megasas_mgmt_info.instance[i];
-                       if (instance) {
-                               megasas_start_timer(instance,
-                                       &instance->io_completion_timer,
-                                       megasas_io_completion_timer,
-                                       MEGASAS_COMPLETION_TIMER_INTERVAL);
-                       }
-               }
-       } else {
-               /*
-                * Delete timers for all adapters
-                */
-               for (i = 0; i < megasas_mgmt_info.max_index; i++) {
-                       instance = megasas_mgmt_info.instance[i];
-                       if (instance)
-                               del_timer_sync(&instance->io_completion_timer);
-               }
-       }
-
-out:
-       return retval;
-}
-
 static void
 megasas_aen_polling(struct work_struct *work)
 {
@@ -5502,11 +5379,6 @@ megasas_aen_polling(struct work_struct *work)
        kfree(ev);
 }
 
-
-static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUSR,
-               megasas_sysfs_show_poll_mode_io,
-               megasas_sysfs_set_poll_mode_io);
-
 /**
  * megasas_init - Driver load entry point
  */
@@ -5565,11 +5437,6 @@ static int __init megasas_init(void)
                                  &driver_attr_dbg_lvl);
        if (rval)
                goto err_dcf_dbg_lvl;
-       rval = driver_create_file(&megasas_pci_driver.driver,
-                                 &driver_attr_poll_mode_io);
-       if (rval)
-               goto err_dcf_poll_mode_io;
-
        rval = driver_create_file(&megasas_pci_driver.driver,
                                &driver_attr_support_device_change);
        if (rval)
@@ -5578,10 +5445,6 @@ static int __init megasas_init(void)
        return rval;
 
 err_dcf_support_device_change:
-       driver_remove_file(&megasas_pci_driver.driver,
-                 &driver_attr_poll_mode_io);
-
-err_dcf_poll_mode_io:
        driver_remove_file(&megasas_pci_driver.driver,
                           &driver_attr_dbg_lvl);
 err_dcf_dbg_lvl:
@@ -5606,8 +5469,6 @@ err_pcidrv:
  */
 static void __exit megasas_exit(void)
 {
-       driver_remove_file(&megasas_pci_driver.driver,
-                          &driver_attr_poll_mode_io);
        driver_remove_file(&megasas_pci_driver.driver,
                           &driver_attr_dbg_lvl);
        driver_remove_file(&megasas_pci_driver.driver,
index 5255dd688aca49b807f430ffa26dd80a41fcf42e..294abb0defa66e4b34bb8eacf9d91d534bfe144f 100644 (file)
@@ -282,7 +282,9 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
        else {
                *pDevHandle = MR_PD_INVALID; /* set dev handle as invalid. */
                if ((raid->level >= 5) &&
-                   (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER))
+                   ((instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) ||
+                    (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER &&
+                     raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))
                        pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
                else if (raid->level == 1) {
                        /* Get alternate Pd. */
index f6a50c98c36fa46f15ef82474d55fd633efbaf36..002924963cd89aa0af5e4588ae2827aefed95b2b 100644 (file)
@@ -59,11 +59,11 @@ MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS(default) 1: Async 2: Ultra2
 #define ASYNC_MODE    1
 #define ULTRA20M_MODE 2
 
-static int       auto_param = 0;       /* default: ON */
+static bool      auto_param = 0;       /* default: ON */
 module_param     (auto_param, bool, 0);
 MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON(default) 1: OFF)");
 
-static int       disc_priv  = 1;       /* default: OFF */
+static bool      disc_priv  = 1;       /* default: OFF */
 module_param     (disc_priv, bool, 0);
 MODULE_PARM_DESC(disc_priv,  "disconnection privilege mode (0: ON 1: OFF(default))");
 
index ca86721a71b94730b995b99a7c3e7aded4b1951f..b61a753eb8960c19659a53fc18cf35d35c2e70f1 100644 (file)
@@ -70,7 +70,7 @@ module_param(nsp_burst_mode, int, 0);
 MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))");
 
 /* Release IO ports after configuration? */
-static int       free_ports = 0;
+static bool       free_ports = 0;
 module_param(free_ports, bool, 0);
 MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
 
index 22a3ff02e48a419d0e9353d72e53f8d13a3e41f0..bfe68545203ff9123a58f1f9ae896b3b59293811 100644 (file)
 #define QL4_SESS_RECOVERY_TMO          120     /* iSCSI session */
                                                /* recovery timeout */
 
+#define MSB(x) ((uint8_t)((uint16_t)(x) >> 8))
+#define LSW(x) ((uint16_t)(x))
 #define LSDW(x) ((u32)((u64)(x)))
 #define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16))
 
@@ -671,6 +673,7 @@ struct scsi_qla_host {
        uint16_t pri_ddb_idx;
        uint16_t sec_ddb_idx;
        int is_reset;
+       uint16_t temperature;
 };
 
 struct ql4_task_data {
index 1bdfa8120ac888c65c304c28dc3f3aba806ea403..90614f38b55d54541bba90d114d37e1ae4c553d7 100644 (file)
@@ -697,6 +697,9 @@ int qla4xxx_start_firmware(struct scsi_qla_host *ha)
                        writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
                               &ha->reg->ctrl_status);
                        readl(&ha->reg->ctrl_status);
+                       writel(set_rmask(CSR_SCSI_COMPLETION_INTR),
+                              &ha->reg->ctrl_status);
+                       readl(&ha->reg->ctrl_status);
                        spin_unlock_irqrestore(&ha->hardware_lock, flags);
                        if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) {
                                DEBUG2(printk("scsi%ld: %s: Get firmware "
index c2593782fbbef8c203148b1661c92a3e1dbe35f6..e1e66a45e4d06f59ab7e35a4b46999d3bba90106 100644 (file)
@@ -219,6 +219,13 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
                ha->mailbox_timeout_count++;
                mbx_sts[0] = (-1);
                set_bit(DPC_RESET_HA, &ha->dpc_flags);
+               if (is_qla8022(ha)) {
+                       ql4_printk(KERN_INFO, ha,
+                                  "disabling pause transmit on port 0 & 1.\n");
+                       qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
+                                       CRB_NIU_XG_PAUSE_CTL_P0 |
+                                       CRB_NIU_XG_PAUSE_CTL_P1);
+               }
                goto mbox_exit;
        }
 
index 8d6bc1b2ff17266a45d66dfb923f5c7757cf1493..78f1111158d75379d4d1c1ef04a139889c280d3d 100644 (file)
@@ -1875,6 +1875,11 @@ exit:
 int qla4_8xxx_load_risc(struct scsi_qla_host *ha)
 {
        int retval;
+
+       /* clear the interrupt */
+       writel(0, &ha->qla4_8xxx_reg->host_int);
+       readl(&ha->qla4_8xxx_reg->host_int);
+
        retval = qla4_8xxx_device_state_handler(ha);
 
        if (retval == QLA_SUCCESS && !test_bit(AF_INIT_DONE, &ha->flags))
index 35376a1c3f1bc109fb8bea9deb54cec9b7acf0c8..dc45ac92369150eea7821fac2bacc24c8fe11311 100644 (file)
 #define PHAN_PEG_RCV_INITIALIZED       0xff01
 
 /*CRB_RELATED*/
-#define QLA82XX_CRB_BASE       QLA82XX_CAM_RAM(0x200)
-#define QLA82XX_REG(X)         (QLA82XX_CRB_BASE+(X))
-
+#define QLA82XX_CRB_BASE               (QLA82XX_CAM_RAM(0x200))
+#define QLA82XX_REG(X)                 (QLA82XX_CRB_BASE+(X))
 #define CRB_CMDPEG_STATE               QLA82XX_REG(0x50)
 #define CRB_RCVPEG_STATE               QLA82XX_REG(0x13c)
 #define CRB_DMA_SHIFT                  QLA82XX_REG(0xcc)
+#define CRB_TEMP_STATE                 QLA82XX_REG(0x1b4)
+
+#define qla82xx_get_temp_val(x)                ((x) >> 16)
+#define qla82xx_get_temp_state(x)      ((x) & 0xffff)
+#define qla82xx_encode_temp(val, state)        (((val) << 16) | (state))
+
+/*
+ * Temperature control.
+ */
+enum {
+       QLA82XX_TEMP_NORMAL = 0x1,      /* Normal operating range */
+       QLA82XX_TEMP_WARN,      /* Sound alert, temperature getting high */
+       QLA82XX_TEMP_PANIC      /* Fatal error, hardware has shut down. */
+};
+
+#define CRB_NIU_XG_PAUSE_CTL_P0                0x1
+#define CRB_NIU_XG_PAUSE_CTL_P1                0x8
 
 #define QLA82XX_HW_H0_CH_HUB_ADR       0x05
 #define QLA82XX_HW_H1_CH_HUB_ADR       0x0E
index ec393a00c03816f52515fc7e294187a2527e2bf0..ce6d3b7f0c616a3adc14677c27996e99711d4f75 100644 (file)
@@ -35,43 +35,44 @@ static struct kmem_cache *srb_cachep;
 int ql4xdisablesysfsboot = 1;
 module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ql4xdisablesysfsboot,
-               "Set to disable exporting boot targets to sysfs\n"
-               " 0 - Export boot targets\n"
-               " 1 - Do not export boot targets (Default)");
+                " Set to disable exporting boot targets to sysfs.\n"
+                "\t\t  0 - Export boot targets\n"
+                "\t\t  1 - Do not export boot targets (Default)");
 
 int ql4xdontresethba = 0;
 module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ql4xdontresethba,
-               "Don't reset the HBA for driver recovery \n"
-               " 0 - It will reset HBA (Default)\n"
-               " 1 - It will NOT reset HBA");
+                " Don't reset the HBA for driver recovery.\n"
+                "\t\t  0 - It will reset HBA (Default)\n"
+                "\t\t  1 - It will NOT reset HBA");
 
-int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */
+int ql4xextended_error_logging;
 module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ql4xextended_error_logging,
-                "Option to enable extended error logging, "
-                "Default is 0 - no logging, 1 - debug logging");
+                " Option to enable extended error logging.\n"
+                "\t\t  0 - no logging (Default)\n"
+                "\t\t  2 - debug logging");
 
 int ql4xenablemsix = 1;
 module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql4xenablemsix,
-               "Set to enable MSI or MSI-X interrupt mechanism.\n"
-               " 0 = enable INTx interrupt mechanism.\n"
-               " 1 = enable MSI-X interrupt mechanism (Default).\n"
-               " 2 = enable MSI interrupt mechanism.");
+                " Set to enable MSI or MSI-X interrupt mechanism.\n"
+                "\t\t  0 = enable INTx interrupt mechanism.\n"
+                "\t\t  1 = enable MSI-X interrupt mechanism (Default).\n"
+                "\t\t  2 = enable MSI interrupt mechanism.");
 
 #define QL4_DEF_QDEPTH 32
 static int ql4xmaxqdepth = QL4_DEF_QDEPTH;
 module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ql4xmaxqdepth,
-               "Maximum queue depth to report for target devices.\n"
-               " Default: 32.");
+                " Maximum queue depth to report for target devices.\n"
+                "\t\t  Default: 32.");
 
 static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO;
 module_param(ql4xsess_recovery_tmo, int, S_IRUGO);
 MODULE_PARM_DESC(ql4xsess_recovery_tmo,
                "Target Session Recovery Timeout.\n"
-               " Default: 120 sec.");
+               "\t\t  Default: 120 sec.");
 
 static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha);
 /*
@@ -1630,7 +1631,9 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha,
 
        /* Update timers after login */
        ddb_entry->default_relogin_timeout =
-                               le16_to_cpu(fw_ddb_entry->def_timeout);
+               (le16_to_cpu(fw_ddb_entry->def_timeout) > LOGIN_TOV) &&
+                (le16_to_cpu(fw_ddb_entry->def_timeout) < LOGIN_TOV * 10) ?
+                le16_to_cpu(fw_ddb_entry->def_timeout) : LOGIN_TOV;
        ddb_entry->default_time2wait =
                                le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
 
@@ -1969,6 +1972,42 @@ mem_alloc_error_exit:
        return QLA_ERROR;
 }
 
+/**
+ * qla4_8xxx_check_temp - Check the ISP82XX temperature.
+ * @ha: adapter block pointer.
+ *
+ * Note: The caller should not hold the idc lock.
+ **/
+static int qla4_8xxx_check_temp(struct scsi_qla_host *ha)
+{
+       uint32_t temp, temp_state, temp_val;
+       int status = QLA_SUCCESS;
+
+       temp = qla4_8xxx_rd_32(ha, CRB_TEMP_STATE);
+
+       temp_state = qla82xx_get_temp_state(temp);
+       temp_val = qla82xx_get_temp_val(temp);
+
+       if (temp_state == QLA82XX_TEMP_PANIC) {
+               ql4_printk(KERN_WARNING, ha, "Device temperature %d degrees C"
+                          " exceeds maximum allowed. Hardware has been shut"
+                          " down.\n", temp_val);
+               status = QLA_ERROR;
+       } else if (temp_state == QLA82XX_TEMP_WARN) {
+               if (ha->temperature == QLA82XX_TEMP_NORMAL)
+                       ql4_printk(KERN_WARNING, ha, "Device temperature %d"
+                                  " degrees C exceeds operating range."
+                                  " Immediate action needed.\n", temp_val);
+       } else {
+               if (ha->temperature == QLA82XX_TEMP_WARN)
+                       ql4_printk(KERN_INFO, ha, "Device temperature is"
+                                  " now %d degrees C in normal range.\n",
+                                  temp_val);
+       }
+       ha->temperature = temp_state;
+       return status;
+}
+
 /**
  * qla4_8xxx_check_fw_alive  - Check firmware health
  * @ha: Pointer to host adapter structure.
@@ -2040,7 +2079,16 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
            test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
            test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) {
                dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
-               if (dev_state == QLA82XX_DEV_NEED_RESET &&
+
+               if (qla4_8xxx_check_temp(ha)) {
+                       ql4_printk(KERN_INFO, ha, "disabling pause"
+                                  " transmit on port 0 & 1.\n");
+                       qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
+                                       CRB_NIU_XG_PAUSE_CTL_P0 |
+                                       CRB_NIU_XG_PAUSE_CTL_P1);
+                       set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
+                       qla4xxx_wake_dpc(ha);
+               } else if (dev_state == QLA82XX_DEV_NEED_RESET &&
                    !test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
                        if (!ql4xdontresethba) {
                                ql4_printk(KERN_INFO, ha, "%s: HW State: "
@@ -2057,9 +2105,21 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
                } else  {
                        /* Check firmware health */
                        if (qla4_8xxx_check_fw_alive(ha)) {
+                               ql4_printk(KERN_INFO, ha, "disabling pause"
+                                          " transmit on port 0 & 1.\n");
+                               qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
+                                               CRB_NIU_XG_PAUSE_CTL_P0 |
+                                               CRB_NIU_XG_PAUSE_CTL_P1);
                                halt_status = qla4_8xxx_rd_32(ha,
                                                QLA82XX_PEG_HALT_STATUS1);
 
+                               if (LSW(MSB(halt_status)) == 0x67)
+                                       ql4_printk(KERN_ERR, ha, "%s:"
+                                                  " Firmware aborted with"
+                                                  " error code 0x00006700."
+                                                  " Device is being reset\n",
+                                                  __func__);
+
                                /* Since we cannot change dev_state in interrupt
                                 * context, set appropriate DPC flag then wakeup
                                 * DPC */
@@ -2078,7 +2138,7 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
        }
 }
 
-void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess)
+static void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess)
 {
        struct iscsi_session *sess;
        struct ddb_entry *ddb_entry;
@@ -3826,16 +3886,14 @@ exit_check:
        return ret;
 }
 
-static void qla4xxx_free_nt_list(struct list_head *list_nt)
+static void qla4xxx_free_ddb_list(struct list_head *list_ddb)
 {
-       struct qla_ddb_index  *nt_ddb_idx, *nt_ddb_idx_tmp;
+       struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
 
-       /* Free up the normaltargets list */
-       list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
-               list_del_init(&nt_ddb_idx->list);
-               vfree(nt_ddb_idx);
+       list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
+               list_del_init(&ddb_idx->list);
+               vfree(ddb_idx);
        }
-
 }
 
 static struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha,
@@ -3884,6 +3942,8 @@ static int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx)
 static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha,
                                          struct ddb_entry *ddb_entry)
 {
+       uint16_t def_timeout;
+
        ddb_entry->ddb_type = FLASH_DDB;
        ddb_entry->fw_ddb_index = INVALID_ENTRY;
        ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE;
@@ -3894,9 +3954,10 @@ static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha,
        atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
        atomic_set(&ddb_entry->relogin_timer, 0);
        atomic_set(&ddb_entry->relogin_retry_count, 0);
-
+       def_timeout = le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout);
        ddb_entry->default_relogin_timeout =
-               le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout);
+               (def_timeout > LOGIN_TOV) && (def_timeout < LOGIN_TOV * 10) ?
+               def_timeout : LOGIN_TOV;
        ddb_entry->default_time2wait =
                le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait);
 }
@@ -3934,7 +3995,6 @@ static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha)
                            ip_state == IP_ADDRSTATE_DEPRICATED ||
                            ip_state == IP_ADDRSTATE_DISABLING)
                                ip_idx[idx] = -1;
-
                }
 
                /* Break if all IP states checked */
@@ -3947,58 +4007,37 @@ static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha)
        } while (time_after(wtime, jiffies));
 }
 
-void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset)
+static void qla4xxx_build_st_list(struct scsi_qla_host *ha,
+                                 struct list_head *list_st)
 {
+       struct qla_ddb_index  *st_ddb_idx;
        int max_ddbs;
+       int fw_idx_size;
+       struct dev_db_entry *fw_ddb_entry;
+       dma_addr_t fw_ddb_dma;
        int ret;
        uint32_t idx = 0, next_idx = 0;
        uint32_t state = 0, conn_err = 0;
-       uint16_t conn_id;
-       struct dev_db_entry *fw_ddb_entry;
-       struct ddb_entry *ddb_entry = NULL;
-       dma_addr_t fw_ddb_dma;
-       struct iscsi_cls_session *cls_sess;
-       struct iscsi_session *sess;
-       struct iscsi_cls_conn *cls_conn;
-       struct iscsi_endpoint *ep;
-       uint16_t cmds_max = 32, tmo = 0;
-       uint32_t initial_cmdsn = 0;
-       struct list_head list_st, list_nt; /* List of sendtargets */
-       struct qla_ddb_index  *st_ddb_idx, *st_ddb_idx_tmp;
-       int fw_idx_size;
-       unsigned long wtime;
-       struct qla_ddb_index  *nt_ddb_idx;
-
-       if (!test_bit(AF_LINK_UP, &ha->flags)) {
-               set_bit(AF_BUILD_DDB_LIST, &ha->flags);
-               ha->is_reset = is_reset;
-               return;
-       }
-       max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
-                                    MAX_DEV_DB_ENTRIES;
+       uint16_t conn_id = 0;
 
        fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
                                      &fw_ddb_dma);
        if (fw_ddb_entry == NULL) {
                DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
-               goto exit_ddb_list;
+               goto exit_st_list;
        }
 
-       INIT_LIST_HEAD(&list_st);
-       INIT_LIST_HEAD(&list_nt);
+       max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
+                                    MAX_DEV_DB_ENTRIES;
        fw_idx_size = sizeof(struct qla_ddb_index);
 
        for (idx = 0; idx < max_ddbs; idx = next_idx) {
-               ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry,
-                                             fw_ddb_dma, NULL,
-                                             &next_idx, &state, &conn_err,
-                                             NULL, &conn_id);
+               ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
+                                             NULL, &next_idx, &state,
+                                             &conn_err, NULL, &conn_id);
                if (ret == QLA_ERROR)
                        break;
 
-               if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS)
-                       goto continue_next_st;
-
                /* Check if ST, add to the list_st */
                if (strlen((char *) fw_ddb_entry->iscsi_name) != 0)
                        goto continue_next_st;
@@ -4009,59 +4048,155 @@ void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset)
 
                st_ddb_idx->fw_ddb_idx = idx;
 
-               list_add_tail(&st_ddb_idx->list, &list_st);
+               list_add_tail(&st_ddb_idx->list, list_st);
 continue_next_st:
                if (next_idx == 0)
                        break;
        }
 
-       /* Before issuing conn open mbox, ensure all IPs states are configured
-        * Note, conn open fails if IPs are not configured
+exit_st_list:
+       if (fw_ddb_entry)
+               dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
+}
+
+/**
+ * qla4xxx_remove_failed_ddb - Remove inactive or failed ddb from list
+ * @ha: pointer to adapter structure
+ * @list_ddb: List from which failed ddb to be removed
+ *
+ * Iterate over the list of DDBs and find and remove DDBs that are either in
+ * no connection active state or failed state
+ **/
+static void qla4xxx_remove_failed_ddb(struct scsi_qla_host *ha,
+                                     struct list_head *list_ddb)
+{
+       struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
+       uint32_t next_idx = 0;
+       uint32_t state = 0, conn_err = 0;
+       int ret;
+
+       list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
+               ret = qla4xxx_get_fwddb_entry(ha, ddb_idx->fw_ddb_idx,
+                                             NULL, 0, NULL, &next_idx, &state,
+                                             &conn_err, NULL, NULL);
+               if (ret == QLA_ERROR)
+                       continue;
+
+               if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
+                   state == DDB_DS_SESSION_FAILED) {
+                       list_del_init(&ddb_idx->list);
+                       vfree(ddb_idx);
+               }
+       }
+}
+
+static int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha,
+                                  struct dev_db_entry *fw_ddb_entry,
+                                  int is_reset)
+{
+       struct iscsi_cls_session *cls_sess;
+       struct iscsi_session *sess;
+       struct iscsi_cls_conn *cls_conn;
+       struct iscsi_endpoint *ep;
+       uint16_t cmds_max = 32;
+       uint16_t conn_id = 0;
+       uint32_t initial_cmdsn = 0;
+       int ret = QLA_SUCCESS;
+
+       struct ddb_entry *ddb_entry = NULL;
+
+       /* Create session object, with INVALID_ENTRY,
+        * the targer_id would get set when we issue the login
         */
-       qla4xxx_wait_for_ip_configuration(ha);
+       cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, ha->host,
+                                      cmds_max, sizeof(struct ddb_entry),
+                                      sizeof(struct ql4_task_data),
+                                      initial_cmdsn, INVALID_ENTRY);
+       if (!cls_sess) {
+               ret = QLA_ERROR;
+               goto exit_setup;
+       }
 
-       /* Go thru the STs and fire the sendtargets by issuing conn open mbx */
-       list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) {
-               qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx);
+       /*
+        * so calling module_put function to decrement the
+        * reference count.
+        **/
+       module_put(qla4xxx_iscsi_transport.owner);
+       sess = cls_sess->dd_data;
+       ddb_entry = sess->dd_data;
+       ddb_entry->sess = cls_sess;
+
+       cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
+       memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry,
+              sizeof(struct dev_db_entry));
+
+       qla4xxx_setup_flash_ddb_entry(ha, ddb_entry);
+
+       cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_id);
+
+       if (!cls_conn) {
+               ret = QLA_ERROR;
+               goto exit_setup;
        }
 
-       /* Wait to ensure all sendtargets are done for min 12 sec wait */
-       tmo = ((ha->def_timeout < LOGIN_TOV) ? LOGIN_TOV : ha->def_timeout);
-       DEBUG2(ql4_printk(KERN_INFO, ha,
-                         "Default time to wait for build ddb %d\n", tmo));
+       ddb_entry->conn = cls_conn;
 
-       wtime = jiffies + (HZ * tmo);
-       do {
-               list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st,
-                                        list) {
-                       ret = qla4xxx_get_fwddb_entry(ha,
-                                                     st_ddb_idx->fw_ddb_idx,
-                                                     NULL, 0, NULL, &next_idx,
-                                                     &state, &conn_err, NULL,
-                                                     NULL);
-                       if (ret == QLA_ERROR)
-                               continue;
+       /* Setup ep, for displaying attributes in sysfs */
+       ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry);
+       if (ep) {
+               ep->conn = cls_conn;
+               cls_conn->ep = ep;
+       } else {
+               DEBUG2(ql4_printk(KERN_ERR, ha, "Unable to get ep\n"));
+               ret = QLA_ERROR;
+               goto exit_setup;
+       }
 
-                       if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
-                           state == DDB_DS_SESSION_FAILED) {
-                               list_del_init(&st_ddb_idx->list);
-                               vfree(st_ddb_idx);
-                       }
-               }
-               schedule_timeout_uninterruptible(HZ / 10);
-       } while (time_after(wtime, jiffies));
+       /* Update sess/conn params */
+       qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn);
 
-       /* Free up the sendtargets list */
-       list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) {
-               list_del_init(&st_ddb_idx->list);
-               vfree(st_ddb_idx);
+       if (is_reset == RESET_ADAPTER) {
+               iscsi_block_session(cls_sess);
+               /* Use the relogin path to discover new devices
+                *  by short-circuting the logic of setting
+                *  timer to relogin - instead set the flags
+                *  to initiate login right away.
+                */
+               set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
+               set_bit(DF_RELOGIN, &ddb_entry->flags);
        }
 
+exit_setup:
+       return ret;
+}
+
+static void qla4xxx_build_nt_list(struct scsi_qla_host *ha,
+                                 struct list_head *list_nt, int is_reset)
+{
+       struct dev_db_entry *fw_ddb_entry;
+       dma_addr_t fw_ddb_dma;
+       int max_ddbs;
+       int fw_idx_size;
+       int ret;
+       uint32_t idx = 0, next_idx = 0;
+       uint32_t state = 0, conn_err = 0;
+       uint16_t conn_id = 0;
+       struct qla_ddb_index  *nt_ddb_idx;
+
+       fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
+                                     &fw_ddb_dma);
+       if (fw_ddb_entry == NULL) {
+               DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
+               goto exit_nt_list;
+       }
+       max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
+                                    MAX_DEV_DB_ENTRIES;
+       fw_idx_size = sizeof(struct qla_ddb_index);
+
        for (idx = 0; idx < max_ddbs; idx = next_idx) {
-               ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry,
-                                             fw_ddb_dma, NULL,
-                                             &next_idx, &state, &conn_err,
-                                             NULL, &conn_id);
+               ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
+                                             NULL, &next_idx, &state,
+                                             &conn_err, NULL, &conn_id);
                if (ret == QLA_ERROR)
                        break;
 
@@ -4072,107 +4207,113 @@ continue_next_st:
                if (strlen((char *) fw_ddb_entry->iscsi_name) == 0)
                        goto continue_next_nt;
 
-               if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
-                   state == DDB_DS_SESSION_FAILED) {
-                       DEBUG2(ql4_printk(KERN_INFO, ha,
-                                         "Adding  DDB to session = 0x%x\n",
-                                         idx));
-                       if (is_reset == INIT_ADAPTER) {
-                               nt_ddb_idx = vmalloc(fw_idx_size);
-                               if (!nt_ddb_idx)
-                                       break;
-
-                               nt_ddb_idx->fw_ddb_idx = idx;
-
-                               memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry,
-                                      sizeof(struct dev_db_entry));
-
-                               if (qla4xxx_is_flash_ddb_exists(ha, &list_nt,
-                                               fw_ddb_entry) == QLA_SUCCESS) {
-                                       vfree(nt_ddb_idx);
-                                       goto continue_next_nt;
-                               }
-                               list_add_tail(&nt_ddb_idx->list, &list_nt);
-                       } else if (is_reset == RESET_ADAPTER) {
-                               if (qla4xxx_is_session_exists(ha,
-                                                  fw_ddb_entry) == QLA_SUCCESS)
-                                       goto continue_next_nt;
-                       }
+               if (!(state == DDB_DS_NO_CONNECTION_ACTIVE ||
+                   state == DDB_DS_SESSION_FAILED))
+                       goto continue_next_nt;
 
-                       /* Create session object, with INVALID_ENTRY,
-                        * the targer_id would get set when we issue the login
-                        */
-                       cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport,
-                                               ha->host, cmds_max,
-                                               sizeof(struct ddb_entry),
-                                               sizeof(struct ql4_task_data),
-                                               initial_cmdsn, INVALID_ENTRY);
-                       if (!cls_sess)
-                               goto exit_ddb_list;
+               DEBUG2(ql4_printk(KERN_INFO, ha,
+                                 "Adding  DDB to session = 0x%x\n", idx));
+               if (is_reset == INIT_ADAPTER) {
+                       nt_ddb_idx = vmalloc(fw_idx_size);
+                       if (!nt_ddb_idx)
+                               break;
 
-                       /*
-                        * iscsi_session_setup increments the driver reference
-                        * count which wouldn't let the driver to be unloaded.
-                        * so calling module_put function to decrement the
-                        * reference count.
-                        **/
-                       module_put(qla4xxx_iscsi_transport.owner);
-                       sess = cls_sess->dd_data;
-                       ddb_entry = sess->dd_data;
-                       ddb_entry->sess = cls_sess;
+                       nt_ddb_idx->fw_ddb_idx = idx;
 
-                       cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
-                       memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry,
+                       memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry,
                               sizeof(struct dev_db_entry));
 
-                       qla4xxx_setup_flash_ddb_entry(ha, ddb_entry);
-
-                       cls_conn = iscsi_conn_setup(cls_sess,
-                                                   sizeof(struct qla_conn),
-                                                   conn_id);
-                       if (!cls_conn)
-                               goto exit_ddb_list;
-
-                       ddb_entry->conn = cls_conn;
-
-                       /* Setup ep, for displaying attributes in sysfs */
-                       ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry);
-                       if (ep) {
-                               ep->conn = cls_conn;
-                               cls_conn->ep = ep;
-                       } else {
-                               DEBUG2(ql4_printk(KERN_ERR, ha,
-                                                 "Unable to get ep\n"));
-                       }
-
-                       /* Update sess/conn params */
-                       qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess,
-                                                cls_conn);
-
-                       if (is_reset == RESET_ADAPTER) {
-                               iscsi_block_session(cls_sess);
-                               /* Use the relogin path to discover new devices
-                                *  by short-circuting the logic of setting
-                                *  timer to relogin - instead set the flags
-                                *  to initiate login right away.
-                                */
-                               set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
-                               set_bit(DF_RELOGIN, &ddb_entry->flags);
+                       if (qla4xxx_is_flash_ddb_exists(ha, list_nt,
+                                       fw_ddb_entry) == QLA_SUCCESS) {
+                               vfree(nt_ddb_idx);
+                               goto continue_next_nt;
                        }
+                       list_add_tail(&nt_ddb_idx->list, list_nt);
+               } else if (is_reset == RESET_ADAPTER) {
+                       if (qla4xxx_is_session_exists(ha, fw_ddb_entry) ==
+                                                               QLA_SUCCESS)
+                               goto continue_next_nt;
                }
+
+               ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset);
+               if (ret == QLA_ERROR)
+                       goto exit_nt_list;
+
 continue_next_nt:
                if (next_idx == 0)
                        break;
        }
-exit_ddb_list:
-       qla4xxx_free_nt_list(&list_nt);
+
+exit_nt_list:
        if (fw_ddb_entry)
                dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
+}
+
+/**
+ * qla4xxx_build_ddb_list - Build ddb list and setup sessions
+ * @ha: pointer to adapter structure
+ * @is_reset: Is this init path or reset path
+ *
+ * Create a list of sendtargets (st) from firmware DDBs, issue send targets
+ * using connection open, then create the list of normal targets (nt)
+ * from firmware DDBs. Based on the list of nt setup session and connection
+ * objects.
+ **/
+void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset)
+{
+       uint16_t tmo = 0;
+       struct list_head list_st, list_nt;
+       struct qla_ddb_index  *st_ddb_idx, *st_ddb_idx_tmp;
+       unsigned long wtime;
+
+       if (!test_bit(AF_LINK_UP, &ha->flags)) {
+               set_bit(AF_BUILD_DDB_LIST, &ha->flags);
+               ha->is_reset = is_reset;
+               return;
+       }
+
+       INIT_LIST_HEAD(&list_st);
+       INIT_LIST_HEAD(&list_nt);
+
+       qla4xxx_build_st_list(ha, &list_st);
+
+       /* Before issuing conn open mbox, ensure all IPs states are configured
+        * Note, conn open fails if IPs are not configured
+        */
+       qla4xxx_wait_for_ip_configuration(ha);
+
+       /* Go thru the STs and fire the sendtargets by issuing conn open mbx */
+       list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) {
+               qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx);
+       }
+
+       /* Wait to ensure all sendtargets are done for min 12 sec wait */
+       tmo = ((ha->def_timeout > LOGIN_TOV) &&
+              (ha->def_timeout < LOGIN_TOV * 10) ?
+              ha->def_timeout : LOGIN_TOV);
+
+       DEBUG2(ql4_printk(KERN_INFO, ha,
+                         "Default time to wait for build ddb %d\n", tmo));
+
+       wtime = jiffies + (HZ * tmo);
+       do {
+               if (list_empty(&list_st))
+                       break;
+
+               qla4xxx_remove_failed_ddb(ha, &list_st);
+               schedule_timeout_uninterruptible(HZ / 10);
+       } while (time_after(wtime, jiffies));
+
+       /* Free up the sendtargets list */
+       qla4xxx_free_ddb_list(&list_st);
+
+       qla4xxx_build_nt_list(ha, &list_nt, is_reset);
+
+       qla4xxx_free_ddb_list(&list_nt);
 
        qla4xxx_free_ddb_index(ha);
 }
 
-
 /**
  * qla4xxx_probe_adapter - callback function to probe HBA
  * @pdev: pointer to pci_dev structure
index 26a3fa34a33c0594c3dfd4fa78f73c75db0fb28c..133989b3a9f4da0d7deed83682c6924c3a654330 100644 (file)
@@ -5,4 +5,4 @@
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
 
-#define QLA4XXX_DRIVER_VERSION "5.02.00-k10"
+#define QLA4XXX_DRIVER_VERSION "5.02.00-k12"
index f85cfa6c47b5212982bcbfcd9065936c27360f3d..b2c95dbe9d651d3a82b9e7a269ec3b5bd7e7c167 100644 (file)
@@ -1316,15 +1316,10 @@ static inline int scsi_target_queue_ready(struct Scsi_Host *shost,
        }
 
        if (scsi_target_is_busy(starget)) {
-               if (list_empty(&sdev->starved_entry))
-                       list_add_tail(&sdev->starved_entry,
-                                     &shost->starved_list);
+               list_move_tail(&sdev->starved_entry, &shost->starved_list);
                return 0;
        }
 
-       /* We're OK to process the command, so we can't be starved */
-       if (!list_empty(&sdev->starved_entry))
-               list_del_init(&sdev->starved_entry);
        return 1;
 }
 
index 44f76e8b58af62a13467e9dc4e080c9e21584e68..c77628afbf9f3e4dbb53c76e6ccf30b054b0f28a 100644 (file)
@@ -112,7 +112,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
                        goto next_msg;
                }
 
-               if (security_netlink_recv(skb, CAP_SYS_ADMIN)) {
+               if (!capable(CAP_SYS_ADMIN)) {
                        err = -EPERM;
                        goto next_msg;
                }
index b3c6d957fbd8aa587dcd039547eaa82bd67b6476..89da43f73c00ca209b816ecc68b70a95fbfc0888 100644 (file)
@@ -297,7 +297,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
                kfree(sdev);
                goto out;
        }
-       blk_get_queue(sdev->request_queue);
+       WARN_ON_ONCE(!blk_get_queue(sdev->request_queue));
        sdev->request_queue->queuedata = sdev;
        scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
 
index 1b214910b71414804f6d0c6dee0932ead1f98156..f59d4a05ecd74168910790d2051673508d3a40e4 100644 (file)
@@ -3048,7 +3048,8 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
 
                spin_lock_irqsave(shost->host_lock, flags);
                rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT |
-                                 FC_RPORT_DEVLOSS_PENDING);
+                                 FC_RPORT_DEVLOSS_PENDING |
+                                 FC_RPORT_DEVLOSS_CALLBK_DONE);
                spin_unlock_irqrestore(shost->host_lock, flags);
 
                /* ensure any stgt delete functions are done */
index 7b3f8075e2a5d9f53e8f4d322ff5756fd496b51b..c691fb50e6cbfe75deceddcdf744dc1301cc7d08 100644 (file)
@@ -1075,6 +1075,10 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
        SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, "
                                    "cmd=0x%x\n", disk->disk_name, cmd));
 
+       error = scsi_verify_blk_ioctl(bdev, cmd);
+       if (error < 0)
+               return error;
+
        /*
         * If we are in the middle of error recovery, don't let anyone
         * else try and use this device.  Also, if error recovery fails, it
@@ -1097,7 +1101,7 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
                        error = scsi_ioctl(sdp, cmd, p);
                        break;
                default:
-                       error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p);
+                       error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p);
                        if (error != -ENOTTY)
                                break;
                        error = scsi_ioctl(sdp, cmd, p);
@@ -1267,6 +1271,11 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
                           unsigned int cmd, unsigned long arg)
 {
        struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device;
+       int ret;
+
+       ret = scsi_verify_blk_ioctl(bdev, cmd);
+       if (ret < 0)
+               return ret;
 
        /*
         * If we are in the middle of error recovery, don't let anyone
@@ -1278,8 +1287,6 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
                return -ENODEV;
               
        if (sdev->host->hostt->compat_ioctl) {
-               int ret;
-
                ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
 
                return ret;
index 02d99982a74d9048edfb73359ed2e38d08b163f8..eacd46bb36b95fe2b5caf6e82f3940427a250910 100644 (file)
@@ -2368,16 +2368,15 @@ static ssize_t
 sg_proc_write_adio(struct file *filp, const char __user *buffer,
                   size_t count, loff_t *off)
 {
-       int num;
-       char buff[11];
+       int err;
+       unsigned long num;
 
        if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
                return -EACCES;
-       num = (count < 10) ? count : 10;
-       if (copy_from_user(buff, buffer, num))
-               return -EFAULT;
-       buff[num] = '\0';
-       sg_allow_dio = simple_strtoul(buff, NULL, 10) ? 1 : 0;
+       err = kstrtoul_from_user(buffer, count, 0, &num);
+       if (err)
+               return err;
+       sg_allow_dio = num ? 1 : 0;
        return count;
 }
 
@@ -2390,17 +2389,15 @@ static ssize_t
 sg_proc_write_dressz(struct file *filp, const char __user *buffer,
                     size_t count, loff_t *off)
 {
-       int num;
+       int err;
        unsigned long k = ULONG_MAX;
-       char buff[11];
 
        if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
                return -EACCES;
-       num = (count < 10) ? count : 10;
-       if (copy_from_user(buff, buffer, num))
-               return -EFAULT;
-       buff[num] = '\0';
-       k = simple_strtoul(buff, NULL, 10);
+
+       err = kstrtoul_from_user(buffer, count, 0, &k);
+       if (err)
+               return err;
        if (k <= 1048576) {     /* limit "big buff" to 1 MB */
                sg_big_buff = k;
                return count;
index b4543f575f466fc3c7fed5f3edad05be9595d0cd..36d1ed7817ebf9d52631c970023d31b31ff494e0 100644 (file)
@@ -839,6 +839,10 @@ static void sym53c8xx_slave_destroy(struct scsi_device *sdev)
        struct sym_lcb *lp = sym_lp(tp, sdev->lun);
        unsigned long flags;
 
+       /* if slave_alloc returned before allocating a sym_lcb, return */
+       if (!lp)
+               return;
+
        spin_lock_irqsave(np->s.host->host_lock, flags);
 
        if (lp->busy_itlq || lp->busy_itl) {
index 56abf55e49da28178c8048f72aeb60187c0e6fe7..3f9a47ec67dc814764bbee0d22bdd03f7680400a 100644 (file)
@@ -87,12 +87,12 @@ config SPI_BFIN_SPORT
          Enable support for a SPI bus via the Blackfin SPORT peripheral.
 
 config SPI_AU1550
-       tristate "Au1550/Au12x0 SPI Controller"
+       tristate "Au1550/Au1200/Au1300 SPI Controller"
        depends on MIPS_ALCHEMY && EXPERIMENTAL
        select SPI_BITBANG
        help
          If you say yes to this option, support will be included for the
-         Au1550 SPI controller (may also work with Au1200,Au1210,Au1250).
+         PSC SPI controller found on Au1550, Au1200 and Au1300 series.
 
 config SPI_BITBANG
        tristate "Utilities for Bitbanging SPI masters"
@@ -332,8 +332,7 @@ config SPI_STMP3XXX
 
 config SPI_TEGRA
        tristate "Nvidia Tegra SPI controller"
-       depends on ARCH_TEGRA
-       select TEGRA_SYSTEM_DMA
+       depends on ARCH_TEGRA && TEGRA_SYSTEM_DMA
        help
          SPI driver for NVidia Tegra SoCs
 
index e743a45ee92c265bd8a2e13ecec9f98cf3eb926c..8418eb03665121db4a6caf809ea8efc4f12b170c 100644 (file)
@@ -131,7 +131,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
        rxchan = dws->rxchan;
 
        /* 2. Prepare the TX dma transfer */
-       txconf.direction = DMA_TO_DEVICE;
+       txconf.direction = DMA_MEM_TO_DEV;
        txconf.dst_addr = dws->dma_addr;
        txconf.dst_maxburst = LNW_DMA_MSIZE_16;
        txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -147,13 +147,13 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
        txdesc = txchan->device->device_prep_slave_sg(txchan,
                                &dws->tx_sgl,
                                1,
-                               DMA_TO_DEVICE,
+                               DMA_MEM_TO_DEV,
                                DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
        txdesc->callback = dw_spi_dma_done;
        txdesc->callback_param = dws;
 
        /* 3. Prepare the RX dma transfer */
-       rxconf.direction = DMA_FROM_DEVICE;
+       rxconf.direction = DMA_DEV_TO_MEM;
        rxconf.src_addr = dws->dma_addr;
        rxconf.src_maxburst = LNW_DMA_MSIZE_16;
        rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -169,7 +169,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
        rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
                                &dws->rx_sgl,
                                1,
-                               DMA_FROM_DEVICE,
+                               DMA_DEV_TO_MEM,
                                DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
        rxdesc->callback = dw_spi_dma_done;
        rxdesc->callback_param = dws;
index 0a282e5fcc9c3fe4931a871acd6d89708162bd0d..d46e55c720b7f71717d5772b034c5b7f3e159dc4 100644 (file)
@@ -551,6 +551,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir)
        struct dma_async_tx_descriptor *txd;
        enum dma_slave_buswidth buswidth;
        struct dma_slave_config conf;
+       enum dma_transfer_direction slave_dirn;
        struct scatterlist *sg;
        struct sg_table *sgt;
        struct dma_chan *chan;
@@ -573,6 +574,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir)
 
                conf.src_addr = espi->sspdr_phys;
                conf.src_addr_width = buswidth;
+               slave_dirn = DMA_DEV_TO_MEM;
        } else {
                chan = espi->dma_tx;
                buf = t->tx_buf;
@@ -580,6 +582,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir)
 
                conf.dst_addr = espi->sspdr_phys;
                conf.dst_addr_width = buswidth;
+               slave_dirn = DMA_MEM_TO_DEV;
        }
 
        ret = dmaengine_slave_config(chan, &conf);
@@ -631,7 +634,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir)
                return ERR_PTR(-ENOMEM);
 
        txd = chan->device->device_prep_slave_sg(chan, sgt->sgl, nents,
-                                                dir, DMA_CTRL_ACK);
+                                                slave_dirn, DMA_CTRL_ACK);
        if (!txd) {
                dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir);
                return ERR_PTR(-ENOMEM);
@@ -979,7 +982,7 @@ static int ep93xx_spi_setup_dma(struct ep93xx_spi *espi)
        dma_cap_set(DMA_SLAVE, mask);
 
        espi->dma_rx_data.port = EP93XX_DMA_SSP;
-       espi->dma_rx_data.direction = DMA_FROM_DEVICE;
+       espi->dma_rx_data.direction = DMA_DEV_TO_MEM;
        espi->dma_rx_data.name = "ep93xx-spi-rx";
 
        espi->dma_rx = dma_request_channel(mask, ep93xx_spi_dma_filter,
@@ -990,7 +993,7 @@ static int ep93xx_spi_setup_dma(struct ep93xx_spi *espi)
        }
 
        espi->dma_tx_data.port = EP93XX_DMA_SSP;
-       espi->dma_tx_data.direction = DMA_TO_DEVICE;
+       espi->dma_tx_data.direction = DMA_MEM_TO_DEV;
        espi->dma_tx_data.name = "ep93xx-spi-tx";
 
        espi->dma_tx = dma_request_channel(mask, ep93xx_spi_dma_filter,
index f1f5efbc3404aefc4aa68dba8ded5a4c72275bdc..2f9cb43a239870b6db396b8507fb6a67893f1f37 100644 (file)
@@ -900,11 +900,11 @@ static int configure_dma(struct pl022 *pl022)
 {
        struct dma_slave_config rx_conf = {
                .src_addr = SSP_DR(pl022->phybase),
-               .direction = DMA_FROM_DEVICE,
+               .direction = DMA_DEV_TO_MEM,
        };
        struct dma_slave_config tx_conf = {
                .dst_addr = SSP_DR(pl022->phybase),
-               .direction = DMA_TO_DEVICE,
+               .direction = DMA_MEM_TO_DEV,
        };
        unsigned int pages;
        int ret;
@@ -1041,7 +1041,7 @@ static int configure_dma(struct pl022 *pl022)
        rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
                                      pl022->sgt_rx.sgl,
                                      rx_sglen,
-                                     DMA_FROM_DEVICE,
+                                     DMA_DEV_TO_MEM,
                                      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!rxdesc)
                goto err_rxdesc;
@@ -1049,7 +1049,7 @@ static int configure_dma(struct pl022 *pl022)
        txdesc = txchan->device->device_prep_slave_sg(txchan,
                                      pl022->sgt_tx.sgl,
                                      tx_sglen,
-                                     DMA_TO_DEVICE,
+                                     DMA_MEM_TO_DEV,
                                      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!txdesc)
                goto err_txdesc;
index 7086583b910708e80cf1b133187eb9be236ee4ff..2a6429d8c363e52b73430b9943716e273dc31438 100644 (file)
@@ -1079,7 +1079,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
        }
        sg = dma->sg_rx_p;
        desc_rx = dma->chan_rx->device->device_prep_slave_sg(dma->chan_rx, sg,
-                                       num, DMA_FROM_DEVICE,
+                                       num, DMA_DEV_TO_MEM,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc_rx) {
                dev_err(&data->master->dev, "%s:device_prep_slave_sg Failed\n",
@@ -1124,7 +1124,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
        }
        sg = dma->sg_tx_p;
        desc_tx = dma->chan_tx->device->device_prep_slave_sg(dma->chan_tx,
-                                       sg, num, DMA_TO_DEVICE,
+                                       sg, num, DMA_MEM_TO_DEV,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc_tx) {
                dev_err(&data->master->dev, "%s:device_prep_slave_sg Failed\n",
index 0d18d80bcd25ce9c5f6acd1dec213cd7a76c4498..9bcf87ae4c008eab0b1e93dcec65e67b6a9f3ea9 100644 (file)
@@ -61,7 +61,7 @@ EXPORT_SYMBOL(comedi_debug);
 module_param(comedi_debug, int, 0644);
 #endif
 
-int comedi_autoconfig = 1;
+bool comedi_autoconfig = 1;
 module_param(comedi_autoconfig, bool, 0444);
 
 static int comedi_num_legacy_minors;
index da4b4f5553f590c0f7a07f80993e7f35626636c0..006cf14c577a041e4c7768b1bcb364a53158d091 100644 (file)
@@ -1,10 +1,11 @@
 
 #ifndef _COMEDI_FOPS_H
 #define _COMEDI_FOPS_H
+#include <linux/types.h>
 
 extern struct class *comedi_class;
 extern const struct file_operations comedi_fops;
-extern int comedi_autoconfig;
+extern bool comedi_autoconfig;
 extern struct comedi_driver *comedi_drivers;
 
 #endif /* _COMEDI_FOPS_H */
index 5865029db0f67999404c6789b087de4f46612045..28aba00dc6295c5742551813fbf792033412c6ca 100644 (file)
@@ -1,6 +1,7 @@
 config DVB_AS102
        tristate "Abilis AS102 DVB receiver"
        depends on DVB_CORE && USB && I2C && INPUT
+       select FW_LOADER
        help
          Choose Y or M here if you have a device containing an AS102
 
index e7dbb6f814d53c62a24d21bcc83f7ad221d1c6e1..1bca43e847c7c0c301e6d711ea128e96e7db58c5 100644 (file)
@@ -3,4 +3,4 @@ dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \
 
 obj-$(CONFIG_DVB_AS102) += dvb-as102.o
 
-EXTRA_CFLAGS += -DCONFIG_AS102_USB -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
index 828526d4c28985221e6b6ebba019053e1a137d21..aae0505a36c4ada7cedaafa28074971f42cb76f7 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/kref.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/usb.h>
 
 /* header file for Usb device driver*/
@@ -56,13 +56,11 @@ int elna_enable = 1;
 module_param_named(elna_enable, elna_enable, int, 0644);
 MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)");
 
-#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-#endif
 
 static void as102_stop_stream(struct as102_dev_t *dev)
 {
-       struct as102_bus_adapter_t *bus_adap;
+       struct as10x_bus_adapter_t *bus_adap;
 
        if (dev != NULL)
                bus_adap = &dev->bus_adap;
@@ -85,7 +83,7 @@ static void as102_stop_stream(struct as102_dev_t *dev)
 
 static int as102_start_stream(struct as102_dev_t *dev)
 {
-       struct as102_bus_adapter_t *bus_adap;
+       struct as10x_bus_adapter_t *bus_adap;
        int ret = -EFAULT;
 
        if (dev != NULL)
@@ -111,7 +109,7 @@ static int as102_start_stream(struct as102_dev_t *dev)
 static int as10x_pid_filter(struct as102_dev_t *dev,
                            int index, u16 pid, int onoff) {
 
-       struct as102_bus_adapter_t *bus_adap = &dev->bus_adap;
+       struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap;
        int ret = -EFAULT;
 
        ENTER();
@@ -123,22 +121,22 @@ static int as10x_pid_filter(struct as102_dev_t *dev,
 
        switch (onoff) {
        case 0:
-           ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid);
-           dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n",
-                   index, pid, ret);
-           break;
+               ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid);
+               dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n",
+                       index, pid, ret);
+               break;
        case 1:
        {
-           struct as10x_ts_filter filter;
+               struct as10x_ts_filter filter;
 
-           filter.type = TS_PID_TYPE_TS;
-           filter.idx = 0xFF;
-           filter.pid = pid;
+               filter.type = TS_PID_TYPE_TS;
+               filter.idx = 0xFF;
+               filter.pid = pid;
 
-           ret = as10x_cmd_add_PID_filter(bus_adap, &filter);
-           dprintk(debug, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n",
-                   index, filter.idx, filter.pid, ret);
-           break;
+               ret = as10x_cmd_add_PID_filter(bus_adap, &filter);
+               dprintk(debug, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n",
+                       index, filter.idx, filter.pid, ret);
+               break;
        }
        }
 
@@ -159,10 +157,9 @@ static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
        if (mutex_lock_interruptible(&as102_dev->sem))
                return -ERESTARTSYS;
 
-       if (pid_filtering) {
-               as10x_pid_filter(as102_dev,
-                               dvbdmxfeed->index, dvbdmxfeed->pid, 1);
-       }
+       if (pid_filtering)
+               as10x_pid_filter(as102_dev, dvbdmxfeed->index,
+                                dvbdmxfeed->pid, 1);
 
        if (as102_dev->streaming++ == 0)
                ret = as102_start_stream(as102_dev);
@@ -185,10 +182,9 @@ static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
        if (--as102_dev->streaming == 0)
                as102_stop_stream(as102_dev);
 
-       if (pid_filtering) {
-               as10x_pid_filter(as102_dev,
-                               dvbdmxfeed->index, dvbdmxfeed->pid, 0);
-       }
+       if (pid_filtering)
+               as10x_pid_filter(as102_dev, dvbdmxfeed->index,
+                                dvbdmxfeed->pid, 0);
 
        mutex_unlock(&as102_dev->sem);
        LEAVE();
@@ -197,27 +193,16 @@ static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 
 int as102_dvb_register(struct as102_dev_t *as102_dev)
 {
-       int ret = 0;
-       ENTER();
+       struct device *dev = &as102_dev->bus_adap.usb_dev->dev;
+       int ret;
 
        ret = dvb_register_adapter(&as102_dev->dvb_adap,
-                                  as102_dev->name,
-                                  THIS_MODULE,
-#if defined(CONFIG_AS102_USB)
-                                  &as102_dev->bus_adap.usb_dev->dev
-#elif defined(CONFIG_AS102_SPI)
-                                  &as102_dev->bus_adap.spi_dev->dev
-#else
-#error >>> dvb_register_adapter <<<
-#endif
-#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR
-                                  , adapter_nr
-#endif
-                                  );
+                          as102_dev->name, THIS_MODULE,
+                          dev, adapter_nr);
        if (ret < 0) {
-               err("%s: dvb_register_adapter() failed (errno = %d)",
-                   __func__, ret);
-               goto failed;
+               dev_err(dev, "%s: dvb_register_adapter() failed: %d\n",
+                       __func__, ret);
+               return ret;
        }
 
        as102_dev->dvb_dmx.priv = as102_dev;
@@ -235,22 +220,22 @@ int as102_dvb_register(struct as102_dev_t *as102_dev)
 
        ret = dvb_dmx_init(&as102_dev->dvb_dmx);
        if (ret < 0) {
-               err("%s: dvb_dmx_init() failed (errno = %d)", __func__, ret);
-               goto failed;
+               dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret);
+               goto edmxinit;
        }
 
        ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap);
        if (ret < 0) {
-               err("%s: dvb_dmxdev_init() failed (errno = %d)", __func__,
-                   ret);
-               goto failed;
+               dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n",
+                       __func__, ret);
+               goto edmxdinit;
        }
 
        ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe);
        if (ret < 0) {
-               err("%s: as102_dvb_register_frontend() failed (errno = %d)",
+               dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d",
                    __func__, ret);
-               goto failed;
+               goto efereg;
        }
 
        /* init bus mutex for token locking */
@@ -259,7 +244,6 @@ int as102_dvb_register(struct as102_dev_t *as102_dev)
        /* init start / stop stream mutex */
        mutex_init(&as102_dev->sem);
 
-#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
        /*
         * try to load as102 firmware. If firmware upload failed, we'll be
         * able to upload it later.
@@ -267,18 +251,21 @@ int as102_dvb_register(struct as102_dev_t *as102_dev)
        if (fw_upload)
                try_then_request_module(as102_fw_upload(&as102_dev->bus_adap),
                                "firmware_class");
-#endif
 
-failed:
-       LEAVE();
-       /* FIXME: free dvb_XXX */
+       pr_info("Registered device %s", as102_dev->name);
+       return 0;
+
+efereg:
+       dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
+edmxdinit:
+       dvb_dmx_release(&as102_dev->dvb_dmx);
+edmxinit:
+       dvb_unregister_adapter(&as102_dev->dvb_adap);
        return ret;
 }
 
 void as102_dvb_unregister(struct as102_dev_t *as102_dev)
 {
-       ENTER();
-
        /* unregister as102 frontend */
        as102_dvb_unregister_fe(&as102_dev->dvb_fe);
 
@@ -289,28 +276,18 @@ void as102_dvb_unregister(struct as102_dev_t *as102_dev)
        /* unregister dvb adapter */
        dvb_unregister_adapter(&as102_dev->dvb_adap);
 
-       LEAVE();
+       pr_info("Unregistered device %s", as102_dev->name);
 }
 
 static int __init as102_driver_init(void)
 {
-       int ret = 0;
-
-       ENTER();
+       int ret;
 
        /* register this driver with the low level subsystem */
-#if defined(CONFIG_AS102_USB)
        ret = usb_register(&as102_usb_driver);
        if (ret)
                err("usb_register failed (ret = %d)", ret);
-#endif
-#if defined(CONFIG_AS102_SPI)
-       ret = spi_register_driver(&as102_spi_driver);
-       if (ret)
-               printk(KERN_ERR "spi_register failed (ret = %d)", ret);
-#endif
 
-       LEAVE();
        return ret;
 }
 
@@ -327,15 +304,8 @@ module_init(as102_driver_init);
  */
 static void __exit as102_driver_exit(void)
 {
-       ENTER();
        /* deregister this driver with the low level bus subsystem */
-#if defined(CONFIG_AS102_USB)
        usb_deregister(&as102_usb_driver);
-#endif
-#if defined(CONFIG_AS102_SPI)
-       spi_unregister_driver(&as102_spi_driver);
-#endif
-       LEAVE();
 }
 
 /*
@@ -347,5 +317,3 @@ module_exit(as102_driver_exit);
 MODULE_DESCRIPTION(DRIVER_FULL_NAME);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");
-
-/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
index fd33f5a12dcc2167cf9dada508b13521f7159b8f..957f0ed0d81aae7c8d587dbca4b853cf862b3814 100644 (file)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#if defined(CONFIG_AS102_USB)
 #include <linux/usb.h>
-extern struct usb_driver as102_usb_driver;
-#endif
-
-#if defined(CONFIG_AS102_SPI)
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/cdev.h>
-
-extern struct spi_driver as102_spi_driver;
-#endif
-
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-#include "dmxdev.h"
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
+#include <dmxdev.h>
+#include "as10x_cmd.h"
+#include "as102_usb_drv.h"
 
 #define DRIVER_FULL_NAME "Abilis Systems as10x usb driver"
 #define DRIVER_NAME "as10x_usb"
 
 extern int as102_debug;
 #define debug  as102_debug
+extern struct usb_driver as102_usb_driver;
+extern int elna_enable;
 
 #define dprintk(debug, args...) \
        do { if (debug) {       \
-               printk(KERN_DEBUG "%s: ",__FUNCTION__); \
+               pr_debug("%s: ", __func__);     \
                printk(args);   \
        } } while (0)
 
 #ifdef TRACE
-#define ENTER()                 printk(">> enter %s\n", __FUNCTION__)
-#define LEAVE()                 printk("<< leave %s\n", __FUNCTION__)
+#define ENTER()        pr_debug(">> enter %s\n", __func__)
+#define LEAVE()        pr_debug("<< leave %s\n", __func__)
 #else
 #define ENTER()
 #define LEAVE()
@@ -59,39 +51,14 @@ extern int as102_debug;
 #define AS102_USB_BUF_SIZE     512
 #define MAX_STREAM_URB         32
 
-#include "as10x_cmd.h"
-
-#if defined(CONFIG_AS102_USB)
-#include "as102_usb_drv.h"
-#endif
-
-#if defined(CONFIG_AS102_SPI)
-#include "as10x_spi_drv.h"
-#endif
-
-
-struct as102_bus_adapter_t {
-#if defined(CONFIG_AS102_USB)
+struct as10x_bus_adapter_t {
        struct usb_device *usb_dev;
-#elif defined(CONFIG_AS102_SPI)
-       struct spi_device *spi_dev;
-       struct cdev cdev; /* spidev raw device */
-
-       struct timer_list timer;
-       struct completion xfer_done;
-#endif
        /* bus token lock */
        struct mutex lock;
        /* low level interface for bus adapter */
        union as10x_bus_token_t {
-#if defined(CONFIG_AS102_USB)
                /* usb token */
                struct as10x_usb_token_cmd_t usb;
-#endif
-#if defined(CONFIG_AS102_SPI)
-               /* spi token */
-               struct as10x_spi_token_cmd_t spi;
-#endif
        } token;
 
        /* token cmd xfer id */
@@ -106,7 +73,7 @@ struct as102_bus_adapter_t {
 
 struct as102_dev_t {
        const char *name;
-       struct as102_bus_adapter_t bus_adap;
+       struct as10x_bus_adapter_t bus_adap;
        struct list_head device_entry;
        struct kref kref;
        unsigned long minor;
@@ -138,5 +105,3 @@ void as102_dvb_unregister(struct as102_dev_t *dev);
 
 int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe);
 int as102_dvb_unregister_fe(struct dvb_frontend *dev);
-
-/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
index 3550f905367e611d2d210619ad63733220588772..bdc5a38cddf7d3668c25a9e7a6e9683c18829957 100644 (file)
 #include "as10x_types.h"
 #include "as10x_cmd.h"
 
-extern int elna_enable;
-
-static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst,
+static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *dst,
                                         struct as10x_tps *src);
 
 static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst,
-                                         struct dvb_frontend_parameters *src);
+                                         struct dtv_frontend_properties *src);
 
-static int as102_fe_set_frontend(struct dvb_frontend *fe,
-                                struct dvb_frontend_parameters *params)
+static int as102_fe_set_frontend(struct dvb_frontend *fe)
 {
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        int ret = 0;
        struct as102_dev_t *dev;
        struct as10x_tune_args tune_args = { 0 };
@@ -47,7 +45,7 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe,
        if (mutex_lock_interruptible(&dev->bus_adap.lock))
                return -EBUSY;
 
-       as102_fe_copy_tune_parameters(&tune_args, params);
+       as102_fe_copy_tune_parameters(&tune_args, p);
 
        /* send abilis command: SET_TUNE */
        ret =  as10x_cmd_set_tune(&dev->bus_adap, &tune_args);
@@ -60,8 +58,9 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe,
        return (ret < 0) ? -EINVAL : 0;
 }
 
-static int as102_fe_get_frontend(struct dvb_frontend *fe,
-                                struct dvb_frontend_parameters *p) {
+static int as102_fe_get_frontend(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
        int ret = 0;
        struct as102_dev_t *dev;
        struct as10x_tps tps = { 0 };
@@ -280,9 +279,9 @@ static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
 }
 
 static struct dvb_frontend_ops as102_fe_ops = {
+       .delsys = { SYS_DVBT },
        .info = {
                .name                   = "Unknown AS102 device",
-               .type                   = FE_OFDM,
                .frequency_min          = 174000000,
                .frequency_max          = 862000000,
                .frequency_stepsize     = 166667,
@@ -346,38 +345,36 @@ int as102_dvb_register_fe(struct as102_dev_t *as102_dev,
        return errno;
 }
 
-static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst,
+static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *fe_tps,
                                         struct as10x_tps *as10x_tps)
 {
 
-       struct dvb_ofdm_parameters *fe_tps = &dst->u.ofdm;
-
        /* extract consteallation */
-       switch (as10x_tps->constellation) {
+       switch (as10x_tps->modulation) {
        case CONST_QPSK:
-               fe_tps->constellation = QPSK;
+               fe_tps->modulation = QPSK;
                break;
        case CONST_QAM16:
-               fe_tps->constellation = QAM_16;
+               fe_tps->modulation = QAM_16;
                break;
        case CONST_QAM64:
-               fe_tps->constellation = QAM_64;
+               fe_tps->modulation = QAM_64;
                break;
        }
 
        /* extract hierarchy */
        switch (as10x_tps->hierarchy) {
        case HIER_NONE:
-               fe_tps->hierarchy_information = HIERARCHY_NONE;
+               fe_tps->hierarchy = HIERARCHY_NONE;
                break;
        case HIER_ALPHA_1:
-               fe_tps->hierarchy_information = HIERARCHY_1;
+               fe_tps->hierarchy = HIERARCHY_1;
                break;
        case HIER_ALPHA_2:
-               fe_tps->hierarchy_information = HIERARCHY_2;
+               fe_tps->hierarchy = HIERARCHY_2;
                break;
        case HIER_ALPHA_4:
-               fe_tps->hierarchy_information = HIERARCHY_4;
+               fe_tps->hierarchy = HIERARCHY_4;
                break;
        }
 
@@ -475,7 +472,7 @@ static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg)
 }
 
 static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args,
-                         struct dvb_frontend_parameters *params)
+                         struct dtv_frontend_properties *params)
 {
 
        /* set frequency */
@@ -484,21 +481,21 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args,
        /* fix interleaving_mode */
        tune_args->interleaving_mode = INTLV_NATIVE;
 
-       switch (params->u.ofdm.bandwidth) {
-       case BANDWIDTH_8_MHZ:
+       switch (params->bandwidth_hz) {
+       case 8000000:
                tune_args->bandwidth = BW_8_MHZ;
                break;
-       case BANDWIDTH_7_MHZ:
+       case 7000000:
                tune_args->bandwidth = BW_7_MHZ;
                break;
-       case BANDWIDTH_6_MHZ:
+       case 6000000:
                tune_args->bandwidth = BW_6_MHZ;
                break;
        default:
                tune_args->bandwidth = BW_8_MHZ;
        }
 
-       switch (params->u.ofdm.guard_interval) {
+       switch (params->guard_interval) {
        case GUARD_INTERVAL_1_32:
                tune_args->guard_interval = GUARD_INT_1_32;
                break;
@@ -517,22 +514,22 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args,
                break;
        }
 
-       switch (params->u.ofdm.constellation) {
+       switch (params->modulation) {
        case QPSK:
-               tune_args->constellation = CONST_QPSK;
+               tune_args->modulation = CONST_QPSK;
                break;
        case QAM_16:
-               tune_args->constellation = CONST_QAM16;
+               tune_args->modulation = CONST_QAM16;
                break;
        case QAM_64:
-               tune_args->constellation = CONST_QAM64;
+               tune_args->modulation = CONST_QAM64;
                break;
        default:
-               tune_args->constellation = CONST_UNKNOWN;
+               tune_args->modulation = CONST_UNKNOWN;
                break;
        }
 
-       switch (params->u.ofdm.transmission_mode) {
+       switch (params->transmission_mode) {
        case TRANSMISSION_MODE_2K:
                tune_args->transmission_mode = TRANS_MODE_2K;
                break;
@@ -543,7 +540,7 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args,
                tune_args->transmission_mode = TRANS_MODE_UNKNOWN;
        }
 
-       switch (params->u.ofdm.hierarchy_information) {
+       switch (params->hierarchy) {
        case HIERARCHY_NONE:
                tune_args->hierarchy = HIER_NONE;
                break;
@@ -571,19 +568,19 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args,
         * if HP/LP are both set to FEC_NONE, HP will be selected.
         */
        if ((tune_args->hierarchy != HIER_NONE) &&
-                      ((params->u.ofdm.code_rate_LP == FEC_NONE) ||
-                       (params->u.ofdm.code_rate_HP == FEC_NONE))) {
+                      ((params->code_rate_LP == FEC_NONE) ||
+                       (params->code_rate_HP == FEC_NONE))) {
 
-               if (params->u.ofdm.code_rate_LP == FEC_NONE) {
+               if (params->code_rate_LP == FEC_NONE) {
                        tune_args->hier_select = HIER_HIGH_PRIORITY;
                        tune_args->code_rate =
-                          as102_fe_get_code_rate(params->u.ofdm.code_rate_HP);
+                          as102_fe_get_code_rate(params->code_rate_HP);
                }
 
-               if (params->u.ofdm.code_rate_HP == FEC_NONE) {
+               if (params->code_rate_HP == FEC_NONE) {
                        tune_args->hier_select = HIER_LOW_PRIORITY;
                        tune_args->code_rate =
-                          as102_fe_get_code_rate(params->u.ofdm.code_rate_LP);
+                          as102_fe_get_code_rate(params->code_rate_LP);
                }
 
                dprintk(debug, "\thierarchy: 0x%02x  "
@@ -596,8 +593,6 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args,
                        tune_args->code_rate);
        } else {
                tune_args->code_rate =
-                       as102_fe_get_code_rate(params->u.ofdm.code_rate_HP);
+                       as102_fe_get_code_rate(params->code_rate_HP);
        }
 }
-
-/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
index c019df933cc988891dc1a28f80dc53ce9794e9a7..43ebc43e6b9a1e1841fcb3dc87e4811216359311 100644 (file)
@@ -26,7 +26,6 @@
 #include "as102_drv.h"
 #include "as102_fw.h"
 
-#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
 char as102_st_fw1[] = "as102_data1_st.hex";
 char as102_st_fw2[] = "as102_data2_st.hex";
 char as102_dt_fw1[] = "as102_data1_dt.hex";
@@ -59,7 +58,7 @@ static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
        unsigned char *src, dst;
 
        if (*fw_data++ != ':') {
-               printk(KERN_ERR "invalid firmware file\n");
+               pr_err("invalid firmware file\n");
                return -EFAULT;
        }
 
@@ -102,7 +101,7 @@ static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
        return (count * 2) + 2;
 }
 
-static int as102_firmware_upload(struct as102_bus_adapter_t *bus_adap,
+static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
                                 unsigned char *cmd,
                                 const struct firmware *firmware) {
 
@@ -163,19 +162,14 @@ error:
        return (errno == 0) ? total_read_bytes : errno;
 }
 
-int as102_fw_upload(struct as102_bus_adapter_t *bus_adap)
+int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
 {
        int errno = -EFAULT;
        const struct firmware *firmware;
        unsigned char *cmd_buf = NULL;
        char *fw1, *fw2;
-
-#if defined(CONFIG_AS102_USB)
        struct usb_device *dev = bus_adap->usb_dev;
-#endif
-#if defined(CONFIG_AS102_SPI)
-       struct spi_device *dev = bus_adap->spi_dev;
-#endif
+
        ENTER();
 
        /* select fw file to upload */
@@ -187,7 +181,6 @@ int as102_fw_upload(struct as102_bus_adapter_t *bus_adap)
                fw2 = as102_st_fw2;
        }
 
-#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
        /* allocate buffer to store firmware upload command and data */
        cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
        if (cmd_buf == NULL) {
@@ -198,21 +191,21 @@ int as102_fw_upload(struct as102_bus_adapter_t *bus_adap)
        /* request kernel to locate firmware file: part1 */
        errno = request_firmware(&firmware, fw1, &dev->dev);
        if (errno < 0) {
-               printk(KERN_ERR "%s: unable to locate firmware file: %s\n",
-                                DRIVER_NAME, fw1);
+               pr_err("%s: unable to locate firmware file: %s\n",
+                      DRIVER_NAME, fw1);
                goto error;
        }
 
        /* initiate firmware upload */
        errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
        if (errno < 0) {
-               printk(KERN_ERR "%s: error during firmware upload part1\n",
-                                DRIVER_NAME);
+               pr_err("%s: error during firmware upload part1\n",
+                      DRIVER_NAME);
                goto error;
        }
 
-       printk(KERN_INFO "%s: fimrware: %s loaded with success\n",
-                        DRIVER_NAME, fw1);
+       pr_info("%s: firmware: %s loaded with success\n",
+               DRIVER_NAME, fw1);
        release_firmware(firmware);
 
        /* wait for boot to complete */
@@ -221,31 +214,28 @@ int as102_fw_upload(struct as102_bus_adapter_t *bus_adap)
        /* request kernel to locate firmware file: part2 */
        errno = request_firmware(&firmware, fw2, &dev->dev);
        if (errno < 0) {
-               printk(KERN_ERR "%s: unable to locate firmware file: %s\n",
-                                DRIVER_NAME, fw2);
+               pr_err("%s: unable to locate firmware file: %s\n",
+                      DRIVER_NAME, fw2);
                goto error;
        }
 
        /* initiate firmware upload */
        errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
        if (errno < 0) {
-               printk(KERN_ERR "%s: error during firmware upload part2\n",
-                                DRIVER_NAME);
+               pr_err("%s: error during firmware upload part2\n",
+                      DRIVER_NAME);
                goto error;
        }
 
-       printk(KERN_INFO "%s: fimrware: %s loaded with success\n",
-                       DRIVER_NAME, fw2);
+       pr_info("%s: firmware: %s loaded with success\n",
+               DRIVER_NAME, fw2);
 error:
        /* free data buffer */
        kfree(cmd_buf);
        /* release firmware if needed */
        if (firmware != NULL)
                release_firmware(firmware);
-#endif
+
        LEAVE();
        return errno;
 }
-#endif
-
-/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
index 27e5347e2e19472a4c52b118f651c47db726ffd4..bd21f0554392bba3f860ce4661740c954da3bbe3 100644 (file)
 
 extern int dual_tuner;
 
-#pragma pack(1)
 struct as10x_raw_fw_pkt {
        unsigned char address[4];
        unsigned char data[MAX_FW_PKT_SIZE - 6];
-};
+} __packed;
 
 struct as10x_fw_pkt_t {
        union {
@@ -32,11 +31,8 @@ struct as10x_fw_pkt_t {
                unsigned char length[2];
        } u;
        struct as10x_raw_fw_pkt raw;
-};
-#pragma pack()
+} __packed;
 
 #ifdef __KERNEL__
-int as102_fw_upload(struct as102_bus_adapter_t *bus_adap);
+int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap);
 #endif
-
-/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
index 264be2dbd2a41c98fd2d1861ede5a57716328879..d775be0173eaff3d2276bfb1f36b052843af8c87 100644 (file)
@@ -42,30 +42,32 @@ static struct usb_device_id as102_usb_id_table[] = {
        { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) },
        { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) },
        { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) },
+       { USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) },
        { } /* Terminating entry */
 };
 
 /* Note that this table must always have the same number of entries as the
    as102_usb_id_table struct */
-static const char *as102_device_names[] = {
+static const char * const as102_device_names[] = {
        AS102_REFERENCE_DESIGN,
        AS102_PCTV_74E,
        AS102_ELGATO_EYETV_DTT_NAME,
        AS102_NBOX_DVBT_DONGLE_NAME,
+       AS102_SKY_IT_DIGITAL_KEY_NAME,
        NULL /* Terminating entry */
 };
 
 struct usb_driver as102_usb_driver = {
-       .name        DRIVER_FULL_NAME,
-       .probe       as102_usb_probe,
-       .disconnect  as102_usb_disconnect,
-       .id_table    as102_usb_id_table
+       .name           = DRIVER_FULL_NAME,
+       .probe          = as102_usb_probe,
+       .disconnect     = as102_usb_disconnect,
+       .id_table       = as102_usb_id_table
 };
 
 static const struct file_operations as102_dev_fops = {
-       .owner   = THIS_MODULE,
-       .open    = as102_open,
-       .release = as102_release,
+       .owner          = THIS_MODULE,
+       .open           = as102_open,
+       .release        = as102_release,
 };
 
 static struct usb_class_driver as102_usb_class_driver = {
@@ -74,7 +76,7 @@ static struct usb_class_driver as102_usb_class_driver = {
        .minor_base     = AS102_DEVICE_MAJOR,
 };
 
-static int as102_usb_xfer_cmd(struct as102_bus_adapter_t *bus_adap,
+static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap,
                              unsigned char *send_buf, int send_buf_len,
                              unsigned char *recv_buf, int recv_buf_len)
 {
@@ -131,7 +133,7 @@ static int as102_usb_xfer_cmd(struct as102_bus_adapter_t *bus_adap,
        return ret;
 }
 
-static int as102_send_ep1(struct as102_bus_adapter_t *bus_adap,
+static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap,
                          unsigned char *send_buf,
                          int send_buf_len,
                          int swap32)
@@ -154,7 +156,7 @@ static int as102_send_ep1(struct as102_bus_adapter_t *bus_adap,
        return ret ? ret : actual_len;
 }
 
-static int as102_read_ep2(struct as102_bus_adapter_t *bus_adap,
+static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap,
                   unsigned char *recv_buf, int recv_buf_len)
 {
        int ret = 0, actual_len;
@@ -337,7 +339,7 @@ static void as102_usb_disconnect(struct usb_interface *intf)
        /* decrement usage counter */
        kref_put(&as102_dev->kref, as102_usb_release);
 
-       printk(KERN_INFO "%s: device has been disconnected\n", DRIVER_NAME);
+       pr_info("%s: device has been disconnected\n", DRIVER_NAME);
 
        LEAVE();
 }
@@ -351,19 +353,19 @@ static int as102_usb_probe(struct usb_interface *intf,
 
        ENTER();
 
-       as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL);
-       if (as102_dev == NULL) {
-               err("%s: kzalloc failed", __func__);
-               return -ENOMEM;
-       }
-
        /* This should never actually happen */
        if ((sizeof(as102_usb_id_table) / sizeof(struct usb_device_id)) !=
            (sizeof(as102_device_names) / sizeof(const char *))) {
-               printk(KERN_ERR "Device names table invalid size");
+               pr_err("Device names table invalid size");
                return -EINVAL;
        }
 
+       as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL);
+       if (as102_dev == NULL) {
+               err("%s: kzalloc failed", __func__);
+               return -ENOMEM;
+       }
+
        /* Assign the user-friendly device name */
        for (i = 0; i < (sizeof(as102_usb_id_table) /
                         sizeof(struct usb_device_id)); i++) {
@@ -399,7 +401,7 @@ static int as102_usb_probe(struct usb_interface *intf,
                goto failed;
        }
 
-       printk(KERN_INFO "%s: device has been detected\n", DRIVER_NAME);
+       pr_info("%s: device has been detected\n", DRIVER_NAME);
 
        /* request buffer allocation for streaming */
        ret = as102_alloc_usb_stream_buffer(as102_dev);
@@ -432,8 +434,8 @@ static int as102_open(struct inode *inode, struct file *file)
        /* fetch device from usb interface */
        intf = usb_find_interface(&as102_usb_driver, minor);
        if (intf == NULL) {
-               printk(KERN_ERR "%s: can't find device for minor %d\n",
-                               __func__, minor);
+               pr_err("%s: can't find device for minor %d\n",
+                      __func__, minor);
                ret = -ENODEV;
                goto exit;
        }
@@ -474,5 +476,3 @@ static int as102_release(struct inode *inode, struct file *file)
 }
 
 MODULE_DEVICE_TABLE(usb, as102_usb_id_table);
-
-/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
index fb1fc41dcd7968f4ab9ec80998e7853a811d558f..fc2884ab02a280520aa755aa493bc3229c8aab71 100644 (file)
 #define NBOX_DVBT_DONGLE_USB_VID       0x0b89
 #define NBOX_DVBT_DONGLE_USB_PID       0x0007
 
+/* Sky Italia: Digital Key (green led) */
+#define AS102_SKY_IT_DIGITAL_KEY_NAME  "Sky IT Digital Key (green led)"
+#define SKY_IT_DIGITAL_KEY_USB_VID     0x2137
+#define SKY_IT_DIGITAL_KEY_USB_PID     0x0001
+
 void as102_urb_stream_irq(struct urb *urb);
 
 struct as10x_usb_token_cmd_t {
@@ -56,4 +61,3 @@ struct as10x_usb_token_cmd_t {
        struct as10x_cmd_t r;
 };
 #endif
-/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
index 0dcba806578065637532657438aeedd0a858da4c..262bb94ad27e5d422231a5074ab2c94f57d30663 100644 (file)
 
 /**
  * as10x_cmd_turn_on - send turn on command to AS10x
- * @phandle:   pointer to AS10x handle
+ * @adap:   pointer to AS10x bus adapter
  *
  * Return 0 when no error, < 0 in case of error.
  */
-int as10x_cmd_turn_on(as10x_handle_t *phandle)
+int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap)
 {
        int error;
        struct as10x_cmd_t *pcmd, *prsp;
 
        ENTER();
 
-       pcmd = phandle->cmd;
-       prsp = phandle->rsp;
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(pcmd, (++phandle->cmd_xid),
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
                        sizeof(pcmd->body.turn_on.req));
 
        /* fill command */
        pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON);
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd,
-                                              sizeof(pcmd->body.turn_on.req) +
-                                              HEADER_SIZE,
-                                              (uint8_t *) prsp,
-                                              sizeof(prsp->body.turn_on.rsp) +
-                                              HEADER_SIZE);
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+                                           sizeof(pcmd->body.turn_on.req) +
+                                           HEADER_SIZE,
+                                           (uint8_t *) prsp,
+                                           sizeof(prsp->body.turn_on.rsp) +
+                                           HEADER_SIZE);
        } else {
                error = AS10X_CMD_ERROR;
        }
@@ -71,31 +71,31 @@ out:
 
 /**
  * as10x_cmd_turn_off - send turn off command to AS10x
- * @phandle:   pointer to AS10x handle
+ * @adap:   pointer to AS10x bus adapter
  *
  * Return 0 on success or negative value in case of error.
  */
-int as10x_cmd_turn_off(as10x_handle_t *phandle)
+int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap)
 {
        int error;
        struct as10x_cmd_t *pcmd, *prsp;
 
        ENTER();
 
-       pcmd = phandle->cmd;
-       prsp = phandle->rsp;
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(pcmd, (++phandle->cmd_xid),
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
                        sizeof(pcmd->body.turn_off.req));
 
        /* fill command */
        pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF);
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error = phandle->ops->xfer_cmd(
-                       phandle, (uint8_t *) pcmd,
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(
+                       adap, (uint8_t *) pcmd,
                        sizeof(pcmd->body.turn_off.req) + HEADER_SIZE,
                        (uint8_t *) prsp,
                        sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE);
@@ -116,23 +116,24 @@ out:
 
 /**
  * as10x_cmd_set_tune - send set tune command to AS10x
- * @phandle: pointer to AS10x handle
+ * @adap:    pointer to AS10x bus adapter
  * @ptune:   tune parameters
  *
  * Return 0 on success or negative value in case of error.
  */
-int as10x_cmd_set_tune(as10x_handle_t *phandle, struct as10x_tune_args *ptune)
+int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
+                      struct as10x_tune_args *ptune)
 {
        int error;
        struct as10x_cmd_t *preq, *prsp;
 
        ENTER();
 
-       preq = phandle->cmd;
-       prsp = phandle->rsp;
+       preq = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(preq, (++phandle->cmd_xid),
+       as10x_cmd_build(preq, (++adap->cmd_xid),
                        sizeof(preq->body.set_tune.req));
 
        /* fill command */
@@ -140,7 +141,7 @@ int as10x_cmd_set_tune(as10x_handle_t *phandle, struct as10x_tune_args *ptune)
        preq->body.set_tune.req.args.freq = cpu_to_le32(ptune->freq);
        preq->body.set_tune.req.args.bandwidth = ptune->bandwidth;
        preq->body.set_tune.req.args.hier_select = ptune->hier_select;
-       preq->body.set_tune.req.args.constellation = ptune->constellation;
+       preq->body.set_tune.req.args.modulation = ptune->modulation;
        preq->body.set_tune.req.args.hierarchy = ptune->hierarchy;
        preq->body.set_tune.req.args.interleaving_mode  =
                ptune->interleaving_mode;
@@ -150,14 +151,14 @@ int as10x_cmd_set_tune(as10x_handle_t *phandle, struct as10x_tune_args *ptune)
                ptune->transmission_mode;
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error = phandle->ops->xfer_cmd(phandle,
-                                              (uint8_t *) preq,
-                                              sizeof(preq->body.set_tune.req)
-                                              + HEADER_SIZE,
-                                              (uint8_t *) prsp,
-                                              sizeof(prsp->body.set_tune.rsp)
-                                              + HEADER_SIZE);
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap,
+                                           (uint8_t *) preq,
+                                           sizeof(preq->body.set_tune.req)
+                                           + HEADER_SIZE,
+                                           (uint8_t *) prsp,
+                                           sizeof(prsp->body.set_tune.rsp)
+                                           + HEADER_SIZE);
        } else {
                error = AS10X_CMD_ERROR;
        }
@@ -175,12 +176,12 @@ out:
 
 /**
  * as10x_cmd_get_tune_status - send get tune status command to AS10x
- * @phandle: pointer to AS10x handle
+ * @adap: pointer to AS10x bus adapter
  * @pstatus: pointer to updated status structure of the current tune
  *
  * Return 0 on success or negative value in case of error.
  */
-int as10x_cmd_get_tune_status(as10x_handle_t *phandle,
+int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
                              struct as10x_tune_status *pstatus)
 {
        int error;
@@ -188,11 +189,11 @@ int as10x_cmd_get_tune_status(as10x_handle_t *phandle,
 
        ENTER();
 
-       preq = phandle->cmd;
-       prsp = phandle->rsp;
+       preq = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(preq, (++phandle->cmd_xid),
+       as10x_cmd_build(preq, (++adap->cmd_xid),
                        sizeof(preq->body.get_tune_status.req));
 
        /* fill command */
@@ -200,9 +201,9 @@ int as10x_cmd_get_tune_status(as10x_handle_t *phandle,
                cpu_to_le16(CONTROL_PROC_GETTUNESTAT);
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error = phandle->ops->xfer_cmd(
-                       phandle,
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(
+                       adap,
                        (uint8_t *) preq,
                        sizeof(preq->body.get_tune_status.req) + HEADER_SIZE,
                        (uint8_t *) prsp,
@@ -232,24 +233,24 @@ out:
 }
 
 /**
- * send get TPS command to AS10x
- * @phandle:   pointer to AS10x handle
+ * as10x_cmd_get_tps - send get TPS command to AS10x
+ * @adap:      pointer to AS10x handle
  * @ptps:      pointer to TPS parameters structure
  *
  * Return 0 on success or negative value in case of error.
  */
-int as10x_cmd_get_tps(as10x_handle_t *phandle, struct as10x_tps *ptps)
+int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps)
 {
        int error;
        struct as10x_cmd_t *pcmd, *prsp;
 
        ENTER();
 
-       pcmd = phandle->cmd;
-       prsp = phandle->rsp;
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(pcmd, (++phandle->cmd_xid),
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
                        sizeof(pcmd->body.get_tps.req));
 
        /* fill command */
@@ -257,14 +258,14 @@ int as10x_cmd_get_tps(as10x_handle_t *phandle, struct as10x_tps *ptps)
                cpu_to_le16(CONTROL_PROC_GETTPS);
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error = phandle->ops->xfer_cmd(phandle,
-                                              (uint8_t *) pcmd,
-                                              sizeof(pcmd->body.get_tps.req) +
-                                              HEADER_SIZE,
-                                              (uint8_t *) prsp,
-                                              sizeof(prsp->body.get_tps.rsp) +
-                                              HEADER_SIZE);
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap,
+                                           (uint8_t *) pcmd,
+                                           sizeof(pcmd->body.get_tps.req) +
+                                           HEADER_SIZE,
+                                           (uint8_t *) prsp,
+                                           sizeof(prsp->body.get_tps.rsp) +
+                                           HEADER_SIZE);
        } else {
                error = AS10X_CMD_ERROR;
        }
@@ -278,7 +279,7 @@ int as10x_cmd_get_tps(as10x_handle_t *phandle, struct as10x_tps *ptps)
                goto out;
 
        /* Response OK -> get response data */
-       ptps->constellation = prsp->body.get_tps.rsp.tps.constellation;
+       ptps->modulation = prsp->body.get_tps.rsp.tps.modulation;
        ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy;
        ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode;
        ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP;
@@ -296,12 +297,12 @@ out:
 
 /**
  * as10x_cmd_get_demod_stats - send get demod stats command to AS10x
- * @phandle:       pointer to AS10x handle
+ * @adap:          pointer to AS10x bus adapter
  * @pdemod_stats:  pointer to demod stats parameters structure
  *
  * Return 0 on success or negative value in case of error.
  */
-int as10x_cmd_get_demod_stats(as10x_handle_t  *phandle,
+int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap,
                              struct as10x_demod_stats *pdemod_stats)
 {
        int error;
@@ -309,11 +310,11 @@ int as10x_cmd_get_demod_stats(as10x_handle_t  *phandle,
 
        ENTER();
 
-       pcmd = phandle->cmd;
-       prsp = phandle->rsp;
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(pcmd, (++phandle->cmd_xid),
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
                        sizeof(pcmd->body.get_demod_stats.req));
 
        /* fill command */
@@ -321,8 +322,8 @@ int as10x_cmd_get_demod_stats(as10x_handle_t  *phandle,
                cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS);
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error = phandle->ops->xfer_cmd(phandle,
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap,
                                (uint8_t *) pcmd,
                                sizeof(pcmd->body.get_demod_stats.req)
                                + HEADER_SIZE,
@@ -360,13 +361,13 @@ out:
 
 /**
  * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x
- * @phandle:  pointer to AS10x handle
+ * @adap:     pointer to AS10x bus adapter
  * @is_ready: pointer to value indicating when impulse
  *           response data is ready
  *
  * Return 0 on success or negative value in case of error.
  */
-int as10x_cmd_get_impulse_resp(as10x_handle_t     *phandle,
+int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
                               uint8_t *is_ready)
 {
        int error;
@@ -374,11 +375,11 @@ int as10x_cmd_get_impulse_resp(as10x_handle_t     *phandle,
 
        ENTER();
 
-       pcmd = phandle->cmd;
-       prsp = phandle->rsp;
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(pcmd, (++phandle->cmd_xid),
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
                        sizeof(pcmd->body.get_impulse_rsp.req));
 
        /* fill command */
@@ -386,8 +387,8 @@ int as10x_cmd_get_impulse_resp(as10x_handle_t     *phandle,
                cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP);
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error = phandle->ops->xfer_cmd(phandle,
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap,
                                        (uint8_t *) pcmd,
                                        sizeof(pcmd->body.get_impulse_rsp.req)
                                        + HEADER_SIZE,
index 01a716380e0a702350770ceea2121bdc9211a4e7..4ea249e7adab947c27488f9c57427d04a504ab0b 100644 (file)
 /*********************************/
 /*       MACRO DEFINITIONS       */
 /*********************************/
-#define AS10X_CMD_ERROR -1
+#define AS10X_CMD_ERROR                -1
 
-#define SERVICE_PROG_ID        0x0002
-#define SERVICE_PROG_VERSION   0x0001
+#define SERVICE_PROG_ID                0x0002
+#define SERVICE_PROG_VERSION   0x0001
 
-#define HIER_NONE              0x00
-#define HIER_LOW_PRIORITY      0x01
+#define HIER_NONE              0x00
+#define HIER_LOW_PRIORITY      0x01
 
 #define HEADER_SIZE (sizeof(struct as10x_cmd_header_t))
 
 /* context request types */
-#define GET_CONTEXT_DATA        1
-#define SET_CONTEXT_DATA        2
+#define GET_CONTEXT_DATA       1
+#define SET_CONTEXT_DATA       2
 
 /* ODSP suspend modes */
-#define CFG_MODE_ODSP_RESUME  0
-#define CFG_MODE_ODSP_SUSPEND 1
+#define CFG_MODE_ODSP_RESUME   0
+#define CFG_MODE_ODSP_SUSPEND  1
 
 /* Dump memory size */
-#define DUMP_BLOCK_SIZE_MAX   0x20
+#define DUMP_BLOCK_SIZE_MAX    0x20
 
 /*********************************/
 /*     TYPE DEFINITION           */
 /*********************************/
-typedef enum {
-   CONTROL_PROC_TURNON               = 0x0001,
-   CONTROL_PROC_TURNON_RSP           = 0x0100,
-   CONTROL_PROC_SET_REGISTER         = 0x0002,
-   CONTROL_PROC_SET_REGISTER_RSP     = 0x0200,
-   CONTROL_PROC_GET_REGISTER         = 0x0003,
-   CONTROL_PROC_GET_REGISTER_RSP     = 0x0300,
-   CONTROL_PROC_SETTUNE              = 0x000A,
-   CONTROL_PROC_SETTUNE_RSP          = 0x0A00,
-   CONTROL_PROC_GETTUNESTAT          = 0x000B,
-   CONTROL_PROC_GETTUNESTAT_RSP      = 0x0B00,
-   CONTROL_PROC_GETTPS               = 0x000D,
-   CONTROL_PROC_GETTPS_RSP           = 0x0D00,
-   CONTROL_PROC_SETFILTER            = 0x000E,
-   CONTROL_PROC_SETFILTER_RSP        = 0x0E00,
-   CONTROL_PROC_REMOVEFILTER         = 0x000F,
-   CONTROL_PROC_REMOVEFILTER_RSP     = 0x0F00,
-   CONTROL_PROC_GET_IMPULSE_RESP     = 0x0012,
-   CONTROL_PROC_GET_IMPULSE_RESP_RSP = 0x1200,
-   CONTROL_PROC_START_STREAMING      = 0x0013,
-   CONTROL_PROC_START_STREAMING_RSP  = 0x1300,
-   CONTROL_PROC_STOP_STREAMING       = 0x0014,
-   CONTROL_PROC_STOP_STREAMING_RSP   = 0x1400,
-   CONTROL_PROC_GET_DEMOD_STATS      = 0x0015,
-   CONTROL_PROC_GET_DEMOD_STATS_RSP  = 0x1500,
-   CONTROL_PROC_ELNA_CHANGE_MODE     = 0x0016,
-   CONTROL_PROC_ELNA_CHANGE_MODE_RSP = 0x1600,
-   CONTROL_PROC_ODSP_CHANGE_MODE     = 0x0017,
-   CONTROL_PROC_ODSP_CHANGE_MODE_RSP = 0x1700,
-   CONTROL_PROC_AGC_CHANGE_MODE      = 0x0018,
-   CONTROL_PROC_AGC_CHANGE_MODE_RSP  = 0x1800,
-
-   CONTROL_PROC_CONTEXT              = 0x00FC,
-   CONTROL_PROC_CONTEXT_RSP          = 0xFC00,
-   CONTROL_PROC_DUMP_MEMORY          = 0x00FD,
-   CONTROL_PROC_DUMP_MEMORY_RSP      = 0xFD00,
-   CONTROL_PROC_DUMPLOG_MEMORY       = 0x00FE,
-   CONTROL_PROC_DUMPLOG_MEMORY_RSP   = 0xFE00,
-   CONTROL_PROC_TURNOFF              = 0x00FF,
-   CONTROL_PROC_TURNOFF_RSP          = 0xFF00
-} control_proc;
-
-
-#pragma pack(1)
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* error */
-      uint8_t error;
-   } rsp;
-} TURN_ON;
-
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* error */
-      uint8_t err;
-   } rsp;
-} TURN_OFF;
-
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-      /* tune params */
-      struct as10x_tune_args args;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* response error */
-      uint8_t error;
-   } rsp;
-} SET_TUNE;
-
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* response error */
-      uint8_t error;
-      /* tune status */
-      struct as10x_tune_status sts;
-   } rsp;
-} GET_TUNE_STATUS;
-
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* response error */
-      uint8_t error;
-      /* tps details */
-      struct as10x_tps tps;
-   } rsp;
-} GET_TPS;
-
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t  proc_id;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* response error */
-      uint8_t error;
-   } rsp;
-} COMMON;
-
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t  proc_id;
-      /* PID to filter */
-      uint16_t  pid;
-      /* stream type (MPE, PSI/SI or PES )*/
-      uint8_t stream_type;
-      /* PID index in filter table */
-      uint8_t idx;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* response error */
-      uint8_t error;
-      /* Filter id */
-      uint8_t filter_id;
-   } rsp;
-} ADD_PID_FILTER;
-
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t  proc_id;
-      /* PID to remove */
-      uint16_t  pid;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* response error */
-      uint8_t error;
-   } rsp;
-} DEL_PID_FILTER;
-
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* error */
-      uint8_t error;
-   } rsp;
-} START_STREAMING;
-
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* error */
-      uint8_t error;
-   } rsp;
-} STOP_STREAMING;
-
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* error */
-      uint8_t error;
-      /* demod stats */
-      struct as10x_demod_stats stats;
-   } rsp;
-} GET_DEMOD_STATS;
-
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* error */
-      uint8_t error;
-      /* impulse response ready */
-      uint8_t is_ready;
-   } rsp;
-} GET_IMPULSE_RESP;
-
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-      /* value to write (for set context)*/
-      struct as10x_register_value reg_val;
-      /* context tag */
-      uint16_t tag;
-      /* context request type */
-      uint16_t type;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* value read (for get context) */
-      struct as10x_register_value reg_val;
-      /* context request type */
-      uint16_t type;
-      /* error */
-      uint8_t error;
-   } rsp;
-} FW_CONTEXT;
-
-typedef union {
-   /* request */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* register description */
-      struct as10x_register_addr reg_addr;
-      /* register content */
-      struct as10x_register_value reg_val;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* error */
-      uint8_t error;
-   } rsp;
-} SET_REGISTER;
-
-typedef union {
-   /* request */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* register description */
-      struct as10x_register_addr reg_addr;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* error */
-      uint8_t error;
-      /* register content */
-      struct as10x_register_value reg_val;
-   } rsp;
-} GET_REGISTER;
-
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-      /* mode */
-      uint8_t mode;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* error */
-      uint8_t error;
-   } rsp;
-} CFG_CHANGE_MODE;
+enum control_proc {
+       CONTROL_PROC_TURNON                     = 0x0001,
+       CONTROL_PROC_TURNON_RSP                 = 0x0100,
+       CONTROL_PROC_SET_REGISTER               = 0x0002,
+       CONTROL_PROC_SET_REGISTER_RSP           = 0x0200,
+       CONTROL_PROC_GET_REGISTER               = 0x0003,
+       CONTROL_PROC_GET_REGISTER_RSP           = 0x0300,
+       CONTROL_PROC_SETTUNE                    = 0x000A,
+       CONTROL_PROC_SETTUNE_RSP                = 0x0A00,
+       CONTROL_PROC_GETTUNESTAT                = 0x000B,
+       CONTROL_PROC_GETTUNESTAT_RSP            = 0x0B00,
+       CONTROL_PROC_GETTPS                     = 0x000D,
+       CONTROL_PROC_GETTPS_RSP                 = 0x0D00,
+       CONTROL_PROC_SETFILTER                  = 0x000E,
+       CONTROL_PROC_SETFILTER_RSP              = 0x0E00,
+       CONTROL_PROC_REMOVEFILTER               = 0x000F,
+       CONTROL_PROC_REMOVEFILTER_RSP           = 0x0F00,
+       CONTROL_PROC_GET_IMPULSE_RESP           = 0x0012,
+       CONTROL_PROC_GET_IMPULSE_RESP_RSP       = 0x1200,
+       CONTROL_PROC_START_STREAMING            = 0x0013,
+       CONTROL_PROC_START_STREAMING_RSP        = 0x1300,
+       CONTROL_PROC_STOP_STREAMING             = 0x0014,
+       CONTROL_PROC_STOP_STREAMING_RSP         = 0x1400,
+       CONTROL_PROC_GET_DEMOD_STATS            = 0x0015,
+       CONTROL_PROC_GET_DEMOD_STATS_RSP        = 0x1500,
+       CONTROL_PROC_ELNA_CHANGE_MODE           = 0x0016,
+       CONTROL_PROC_ELNA_CHANGE_MODE_RSP       = 0x1600,
+       CONTROL_PROC_ODSP_CHANGE_MODE           = 0x0017,
+       CONTROL_PROC_ODSP_CHANGE_MODE_RSP       = 0x1700,
+       CONTROL_PROC_AGC_CHANGE_MODE            = 0x0018,
+       CONTROL_PROC_AGC_CHANGE_MODE_RSP        = 0x1800,
+
+       CONTROL_PROC_CONTEXT                    = 0x00FC,
+       CONTROL_PROC_CONTEXT_RSP                = 0xFC00,
+       CONTROL_PROC_DUMP_MEMORY                = 0x00FD,
+       CONTROL_PROC_DUMP_MEMORY_RSP            = 0xFD00,
+       CONTROL_PROC_DUMPLOG_MEMORY             = 0x00FE,
+       CONTROL_PROC_DUMPLOG_MEMORY_RSP         = 0xFE00,
+       CONTROL_PROC_TURNOFF                    = 0x00FF,
+       CONTROL_PROC_TURNOFF_RSP                = 0xFF00
+};
+
+union as10x_turn_on {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* error */
+               uint8_t error;
+       } rsp;
+} __packed;
+
+union as10x_turn_off {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* error */
+               uint8_t err;
+       } rsp;
+} __packed;
+
+union as10x_set_tune {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+               /* tune params */
+               struct as10x_tune_args args;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* response error */
+               uint8_t error;
+       } rsp;
+} __packed;
+
+union as10x_get_tune_status {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* response error */
+               uint8_t error;
+               /* tune status */
+               struct as10x_tune_status sts;
+       } rsp;
+} __packed;
+
+union as10x_get_tps {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* response error */
+               uint8_t error;
+               /* tps details */
+               struct as10x_tps tps;
+       } rsp;
+} __packed;
+
+union as10x_common {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t  proc_id;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* response error */
+               uint8_t error;
+       } rsp;
+} __packed;
+
+union as10x_add_pid_filter {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t  proc_id;
+               /* PID to filter */
+               uint16_t  pid;
+               /* stream type (MPE, PSI/SI or PES )*/
+               uint8_t stream_type;
+               /* PID index in filter table */
+               uint8_t idx;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* response error */
+               uint8_t error;
+               /* Filter id */
+               uint8_t filter_id;
+       } rsp;
+} __packed;
+
+union as10x_del_pid_filter {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t  proc_id;
+               /* PID to remove */
+               uint16_t  pid;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* response error */
+               uint8_t error;
+       } rsp;
+} __packed;
+
+union as10x_start_streaming {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* error */
+               uint8_t error;
+       } rsp;
+} __packed;
+
+union as10x_stop_streaming {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* error */
+               uint8_t error;
+       } rsp;
+} __packed;
+
+union as10x_get_demod_stats {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* error */
+               uint8_t error;
+               /* demod stats */
+               struct as10x_demod_stats stats;
+       } rsp;
+} __packed;
+
+union as10x_get_impulse_resp {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* error */
+               uint8_t error;
+               /* impulse response ready */
+               uint8_t is_ready;
+       } rsp;
+} __packed;
+
+union as10x_fw_context {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+               /* value to write (for set context)*/
+               struct as10x_register_value reg_val;
+               /* context tag */
+               uint16_t tag;
+               /* context request type */
+               uint16_t type;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* value read (for get context) */
+               struct as10x_register_value reg_val;
+               /* context request type */
+               uint16_t type;
+               /* error */
+               uint8_t error;
+       } rsp;
+} __packed;
+
+union as10x_set_register {
+       /* request */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* register description */
+               struct as10x_register_addr reg_addr;
+               /* register content */
+               struct as10x_register_value reg_val;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* error */
+               uint8_t error;
+       } rsp;
+} __packed;
+
+union as10x_get_register {
+       /* request */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* register description */
+               struct as10x_register_addr reg_addr;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* error */
+               uint8_t error;
+               /* register content */
+               struct as10x_register_value reg_val;
+       } rsp;
+} __packed;
+
+union as10x_cfg_change_mode {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+               /* mode */
+               uint8_t mode;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* error */
+               uint8_t error;
+       } rsp;
+} __packed;
 
 struct as10x_cmd_header_t {
-   uint16_t req_id;
-   uint16_t prog;
-   uint16_t version;
-   uint16_t data_len;
-};
+       uint16_t req_id;
+       uint16_t prog;
+       uint16_t version;
+       uint16_t data_len;
+} __packed;
 
 #define DUMP_BLOCK_SIZE 16
-typedef union {
-   /* request */
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-      /* dump memory type request */
-      uint8_t dump_req;
-      /* register description */
-      struct as10x_register_addr reg_addr;
-      /* nb blocks to read */
-      uint16_t num_blocks;
-   } req;
-   /* response */
-   struct {
-      /* response identifier */
-      uint16_t proc_id;
-      /* error */
-      uint8_t error;
-      /* dump response */
-      uint8_t dump_rsp;
-      /* data */
-      union {
-        uint8_t  data8[DUMP_BLOCK_SIZE];
-        uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)];
-        uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)];
-      } u;
-   } rsp;
-} DUMP_MEMORY;
-
-typedef union {
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-      /* dump memory type request */
-      uint8_t dump_req;
-   } req;
-   struct {
-      /* request identifier */
-      uint16_t proc_id;
-      /* error */
-      uint8_t error;
-      /* dump response */
-      uint8_t dump_rsp;
-      /* dump data */
-      uint8_t data[DUMP_BLOCK_SIZE];
-   } rsp;
-} DUMPLOG_MEMORY;
-
-typedef union {
-   /* request */
-   struct {
-      uint16_t proc_id;
-      uint8_t data[64 - sizeof(struct as10x_cmd_header_t) -2 /* proc_id */];
-   } req;
-   /* response */
-   struct {
-      uint16_t proc_id;
-      uint8_t error;
-      uint8_t data[64 - sizeof(struct as10x_cmd_header_t) /* header */
-                     - 2 /* proc_id */ - 1 /* rc */];
-   } rsp;
-} RAW_DATA;
+
+union as10x_dump_memory {
+       /* request */
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+               /* dump memory type request */
+               uint8_t dump_req;
+               /* register description */
+               struct as10x_register_addr reg_addr;
+               /* nb blocks to read */
+               uint16_t num_blocks;
+       } req;
+       /* response */
+       struct {
+               /* response identifier */
+               uint16_t proc_id;
+               /* error */
+               uint8_t error;
+               /* dump response */
+               uint8_t dump_rsp;
+               /* data */
+               union {
+                       uint8_t  data8[DUMP_BLOCK_SIZE];
+                       uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)];
+                       uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)];
+               } u;
+       } rsp;
+} __packed;
+
+union as10x_dumplog_memory {
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+               /* dump memory type request */
+               uint8_t dump_req;
+       } req;
+       struct {
+               /* request identifier */
+               uint16_t proc_id;
+               /* error */
+               uint8_t error;
+               /* dump response */
+               uint8_t dump_rsp;
+               /* dump data */
+               uint8_t data[DUMP_BLOCK_SIZE];
+       } rsp;
+} __packed;
+
+union as10x_raw_data {
+       /* request */
+       struct {
+               uint16_t proc_id;
+               uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
+                            - 2 /* proc_id */];
+       } req;
+       /* response */
+       struct {
+               uint16_t proc_id;
+               uint8_t error;
+               uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
+                            - 2 /* proc_id */ - 1 /* rc */];
+       } rsp;
+} __packed;
 
 struct as10x_cmd_t {
-   /* header */
-   struct as10x_cmd_header_t header;
-   /* body */
-   union {
-      TURN_ON           turn_on;
-      TURN_OFF          turn_off;
-      SET_TUNE          set_tune;
-      GET_TUNE_STATUS   get_tune_status;
-      GET_TPS           get_tps;
-      COMMON            common;
-      ADD_PID_FILTER    add_pid_filter;
-      DEL_PID_FILTER    del_pid_filter;
-      START_STREAMING   start_streaming;
-      STOP_STREAMING    stop_streaming;
-      GET_DEMOD_STATS   get_demod_stats;
-      GET_IMPULSE_RESP  get_impulse_rsp;
-      FW_CONTEXT        context;
-      SET_REGISTER      set_register;
-      GET_REGISTER      get_register;
-      CFG_CHANGE_MODE   cfg_change_mode;
-      DUMP_MEMORY       dump_memory;
-      DUMPLOG_MEMORY    dumplog_memory;
-      RAW_DATA          raw_data;
-   } body;
-};
+       struct as10x_cmd_header_t header;
+       union {
+               union as10x_turn_on             turn_on;
+               union as10x_turn_off            turn_off;
+               union as10x_set_tune            set_tune;
+               union as10x_get_tune_status     get_tune_status;
+               union as10x_get_tps             get_tps;
+               union as10x_common              common;
+               union as10x_add_pid_filter      add_pid_filter;
+               union as10x_del_pid_filter      del_pid_filter;
+               union as10x_start_streaming     start_streaming;
+               union as10x_stop_streaming      stop_streaming;
+               union as10x_get_demod_stats     get_demod_stats;
+               union as10x_get_impulse_resp    get_impulse_rsp;
+               union as10x_fw_context          context;
+               union as10x_set_register        set_register;
+               union as10x_get_register        get_register;
+               union as10x_cfg_change_mode     cfg_change_mode;
+               union as10x_dump_memory         dump_memory;
+               union as10x_dumplog_memory      dumplog_memory;
+               union as10x_raw_data            raw_data;
+       } body;
+} __packed;
 
 struct as10x_token_cmd_t {
-   /* token cmd */
-   struct as10x_cmd_t c;
-   /* token response */
-   struct as10x_cmd_t r;
-};
-#pragma pack()
+       /* token cmd */
+       struct as10x_cmd_t c;
+       /* token response */
+       struct as10x_cmd_t r;
+} __packed;
 
 
 /**************************/
@@ -491,50 +488,42 @@ void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t proc_id,
                      uint16_t cmd_len);
 int as10x_rsp_parse(struct as10x_cmd_t *r, uint16_t proc_id);
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* as10x cmd */
-int as10x_cmd_turn_on(as10x_handle_t *phandle);
-int as10x_cmd_turn_off(as10x_handle_t *phandle);
+int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap);
+int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap);
 
-int as10x_cmd_set_tune(as10x_handle_t *phandle,
+int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
                       struct as10x_tune_args *ptune);
 
-int as10x_cmd_get_tune_status(as10x_handle_t *phandle,
+int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
                              struct as10x_tune_status *pstatus);
 
-int as10x_cmd_get_tps(as10x_handle_t *phandle,
+int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap,
                      struct as10x_tps *ptps);
 
-int as10x_cmd_get_demod_stats(as10x_handle_t  *phandle,
+int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t  *adap,
                              struct as10x_demod_stats *pdemod_stats);
 
-int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle,
+int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
                               uint8_t *is_ready);
 
 /* as10x cmd stream */
-int as10x_cmd_add_PID_filter(as10x_handle_t *phandle,
+int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
                             struct as10x_ts_filter *filter);
-int as10x_cmd_del_PID_filter(as10x_handle_t *phandle,
+int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
                             uint16_t pid_value);
 
-int as10x_cmd_start_streaming(as10x_handle_t *phandle);
-int as10x_cmd_stop_streaming(as10x_handle_t *phandle);
+int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap);
+int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap);
 
 /* as10x cmd cfg */
-int as10x_cmd_set_context(as10x_handle_t *phandle,
+int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap,
                          uint16_t tag,
                          uint32_t value);
-int as10x_cmd_get_context(as10x_handle_t *phandle,
+int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap,
                          uint16_t tag,
                          uint32_t *pvalue);
 
-int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode);
+int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode);
 int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id);
-#ifdef __cplusplus
-}
-#endif
 #endif
-/* EOF - vim: set textwidth=80 ts=3 sw=3 sts=3 et: */
index ec6f69fcf399593e219f5f2770ea1281fdde2a64..d2a4bce896231f13985fcde28e8b1e8fcec26eca 100644 (file)
 
 /**
  * as10x_cmd_get_context - Send get context command to AS10x
- * @phandle:   pointer to AS10x handle
+ * @adap:      pointer to AS10x bus adapter
  * @tag:       context tag
  * @pvalue:    pointer where to store context value read
  *
  * Return 0 on success or negative value in case of error.
  */
-int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag,
+int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
                          uint32_t *pvalue)
 {
        int  error;
@@ -42,11 +42,11 @@ int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag,
 
        ENTER();
 
-       pcmd = phandle->cmd;
-       prsp = phandle->rsp;
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(pcmd, (++phandle->cmd_xid),
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
                        sizeof(pcmd->body.context.req));
 
        /* fill command */
@@ -55,14 +55,14 @@ int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag,
        pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA);
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error  = phandle->ops->xfer_cmd(phandle,
-                                               (uint8_t *) pcmd,
-                                               sizeof(pcmd->body.context.req)
-                                               + HEADER_SIZE,
-                                               (uint8_t *) prsp,
-                                               sizeof(prsp->body.context.rsp)
-                                               + HEADER_SIZE);
+       if (adap->ops->xfer_cmd) {
+               error  = adap->ops->xfer_cmd(adap,
+                                            (uint8_t *) pcmd,
+                                            sizeof(pcmd->body.context.req)
+                                            + HEADER_SIZE,
+                                            (uint8_t *) prsp,
+                                            sizeof(prsp->body.context.rsp)
+                                            + HEADER_SIZE);
        } else {
                error = AS10X_CMD_ERROR;
        }
@@ -87,13 +87,13 @@ out:
 
 /**
  * as10x_cmd_set_context - send set context command to AS10x
- * @phandle:   pointer to AS10x handle
+ * @adap:      pointer to AS10x bus adapter
  * @tag:       context tag
  * @value:     value to set in context
  *
  * Return 0 on success or negative value in case of error.
  */
-int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag,
+int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
                          uint32_t value)
 {
        int error;
@@ -101,11 +101,11 @@ int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag,
 
        ENTER();
 
-       pcmd = phandle->cmd;
-       prsp = phandle->rsp;
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(pcmd, (++phandle->cmd_xid),
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
                        sizeof(pcmd->body.context.req));
 
        /* fill command */
@@ -116,14 +116,14 @@ int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag,
        pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA);
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error  = phandle->ops->xfer_cmd(phandle,
-                                               (uint8_t *) pcmd,
-                                               sizeof(pcmd->body.context.req)
-                                               + HEADER_SIZE,
-                                               (uint8_t *) prsp,
-                                               sizeof(prsp->body.context.rsp)
-                                               + HEADER_SIZE);
+       if (adap->ops->xfer_cmd) {
+               error  = adap->ops->xfer_cmd(adap,
+                                            (uint8_t *) pcmd,
+                                            sizeof(pcmd->body.context.req)
+                                            + HEADER_SIZE,
+                                            (uint8_t *) prsp,
+                                            sizeof(prsp->body.context.rsp)
+                                            + HEADER_SIZE);
        } else {
                error = AS10X_CMD_ERROR;
        }
@@ -142,7 +142,7 @@ out:
 
 /**
  * as10x_cmd_eLNA_change_mode - send eLNA change mode command to AS10x
- * @phandle:   pointer to AS10x handle
+ * @adap:      pointer to AS10x bus adapter
  * @mode:      mode selected:
  *             - ON    : 0x0 => eLNA always ON
  *             - OFF   : 0x1 => eLNA always OFF
@@ -151,18 +151,18 @@ out:
  *
  * Return 0 on success or negative value in case of error.
  */
-int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode)
+int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode)
 {
        int error;
        struct as10x_cmd_t *pcmd, *prsp;
 
        ENTER();
 
-       pcmd = phandle->cmd;
-       prsp = phandle->rsp;
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(pcmd, (++phandle->cmd_xid),
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
                        sizeof(pcmd->body.cfg_change_mode.req));
 
        /* fill command */
@@ -171,8 +171,8 @@ int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode)
        pcmd->body.cfg_change_mode.req.mode = mode;
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error  = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd,
+       if (adap->ops->xfer_cmd) {
+               error  = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
                                sizeof(pcmd->body.cfg_change_mode.req)
                                + HEADER_SIZE, (uint8_t *) prsp,
                                sizeof(prsp->body.cfg_change_mode.rsp)
index 045c706831935f87b8c3a6ec3d6fdf338187bf50..6d000f60fb0e9650fe10d0aefc7cd986dfe38b73 100644 (file)
 
 /**
  * as10x_cmd_add_PID_filter - send add filter command to AS10x
- * @phandle:   pointer to AS10x handle
+ * @adap:      pointer to AS10x bus adapter
  * @filter:    TSFilter filter for DVB-T
  *
  * Return 0 on success or negative value in case of error.
  */
-int as10x_cmd_add_PID_filter(as10x_handle_t *phandle,
+int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
                             struct as10x_ts_filter *filter)
 {
        int error;
@@ -36,11 +36,11 @@ int as10x_cmd_add_PID_filter(as10x_handle_t *phandle,
 
        ENTER();
 
-       pcmd = phandle->cmd;
-       prsp = phandle->rsp;
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(pcmd, (++phandle->cmd_xid),
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
                        sizeof(pcmd->body.add_pid_filter.req));
 
        /* fill command */
@@ -55,8 +55,8 @@ int as10x_cmd_add_PID_filter(as10x_handle_t *phandle,
                pcmd->body.add_pid_filter.req.idx = 0xFF;
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd,
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
                                sizeof(pcmd->body.add_pid_filter.req)
                                + HEADER_SIZE, (uint8_t *) prsp,
                                sizeof(prsp->body.add_pid_filter.rsp)
@@ -83,12 +83,12 @@ out:
 
 /**
  * as10x_cmd_del_PID_filter - Send delete filter command to AS10x
- * @phandle:      pointer to AS10x handle
+ * @adap:         pointer to AS10x bus adapte
  * @pid_value:    PID to delete
  *
  * Return 0 on success or negative value in case of error.
  */
-int as10x_cmd_del_PID_filter(as10x_handle_t *phandle,
+int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
                             uint16_t pid_value)
 {
        int error;
@@ -96,11 +96,11 @@ int as10x_cmd_del_PID_filter(as10x_handle_t *phandle,
 
        ENTER();
 
-       pcmd = phandle->cmd;
-       prsp = phandle->rsp;
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(pcmd, (++phandle->cmd_xid),
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
                        sizeof(pcmd->body.del_pid_filter.req));
 
        /* fill command */
@@ -109,8 +109,8 @@ int as10x_cmd_del_PID_filter(as10x_handle_t *phandle,
        pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value);
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd,
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
                                sizeof(pcmd->body.del_pid_filter.req)
                                + HEADER_SIZE, (uint8_t *) prsp,
                                sizeof(prsp->body.del_pid_filter.rsp)
@@ -132,22 +132,22 @@ out:
 
 /**
  * as10x_cmd_start_streaming - Send start streaming command to AS10x
- * @phandle:   pointer to AS10x handle
+ * @adap:   pointer to AS10x bus adapter
  *
  * Return 0 on success or negative value in case of error.
  */
-int as10x_cmd_start_streaming(as10x_handle_t *phandle)
+int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap)
 {
        int error;
        struct as10x_cmd_t *pcmd, *prsp;
 
        ENTER();
 
-       pcmd = phandle->cmd;
-       prsp = phandle->rsp;
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(pcmd, (++phandle->cmd_xid),
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
                        sizeof(pcmd->body.start_streaming.req));
 
        /* fill command */
@@ -155,8 +155,8 @@ int as10x_cmd_start_streaming(as10x_handle_t *phandle)
                cpu_to_le16(CONTROL_PROC_START_STREAMING);
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd,
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
                                sizeof(pcmd->body.start_streaming.req)
                                + HEADER_SIZE, (uint8_t *) prsp,
                                sizeof(prsp->body.start_streaming.rsp)
@@ -178,22 +178,22 @@ out:
 
 /**
  * as10x_cmd_stop_streaming - Send stop streaming command to AS10x
- * @phandle:   pointer to AS10x handle
+ * @adap:   pointer to AS10x bus adapter
  *
  * Return 0 on success or negative value in case of error.
  */
-int as10x_cmd_stop_streaming(as10x_handle_t *phandle)
+int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap)
 {
        int8_t error;
        struct as10x_cmd_t *pcmd, *prsp;
 
        ENTER();
 
-       pcmd = phandle->cmd;
-       prsp = phandle->rsp;
+       pcmd = adap->cmd;
+       prsp = adap->rsp;
 
        /* prepare command */
-       as10x_cmd_build(pcmd, (++phandle->cmd_xid),
+       as10x_cmd_build(pcmd, (++adap->cmd_xid),
                        sizeof(pcmd->body.stop_streaming.req));
 
        /* fill command */
@@ -201,8 +201,8 @@ int as10x_cmd_stop_streaming(as10x_handle_t *phandle)
                cpu_to_le16(CONTROL_PROC_STOP_STREAMING);
 
        /* send command */
-       if (phandle->ops->xfer_cmd) {
-               error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd,
+       if (adap->ops->xfer_cmd) {
+               error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
                                sizeof(pcmd->body.stop_streaming.req)
                                + HEADER_SIZE, (uint8_t *) prsp,
                                sizeof(prsp->body.stop_streaming.rsp)
index 4f01a76e98291cb26d72f91244f96c57a83f4df5..62b9795ee424de77a142f284ef3f26860afa043d 100644 (file)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 #ifdef __KERNEL__
-struct as102_bus_adapter_t;
+struct as10x_bus_adapter_t;
 struct as102_dev_t;
 
-#define as10x_handle_t struct as102_bus_adapter_t
 #include "as10x_cmd.h"
 
 /* values for "mode" field */
-#define REGMODE8         8
-#define REGMODE16        16
-#define REGMODE32        32
+#define REGMODE8       8
+#define REGMODE16      16
+#define REGMODE32      32
 
 struct as102_priv_ops_t {
-       int (*upload_fw_pkt) (struct as102_bus_adapter_t *bus_adap,
+       int (*upload_fw_pkt) (struct as10x_bus_adapter_t *bus_adap,
                              unsigned char *buf, int buflen, int swap32);
 
-       int (*send_cmd) (struct as102_bus_adapter_t *bus_adap,
+       int (*send_cmd) (struct as10x_bus_adapter_t *bus_adap,
                         unsigned char *buf, int buflen);
 
-       int (*xfer_cmd) (struct as102_bus_adapter_t *bus_adap,
+       int (*xfer_cmd) (struct as10x_bus_adapter_t *bus_adap,
                         unsigned char *send_buf, int send_buf_len,
                         unsigned char *recv_buf, int recv_buf_len);
-/*
-       int (*pid_filter) (struct as102_bus_adapter_t *bus_adap,
-                          int index, u16 pid, int onoff);
-*/
+
        int (*start_stream) (struct as102_dev_t *dev);
        void (*stop_stream) (struct as102_dev_t *dev);
 
-       int (*reset_target) (struct as102_bus_adapter_t *bus_adap);
+       int (*reset_target) (struct as10x_bus_adapter_t *bus_adap);
 
-       int (*read_write)(struct as102_bus_adapter_t *bus_adap, uint8_t mode,
+       int (*read_write)(struct as10x_bus_adapter_t *bus_adap, uint8_t mode,
                          uint32_t rd_addr, uint16_t rd_len,
                          uint32_t wr_addr, uint16_t wr_len);
 
-       int (*as102_read_ep2) (struct as102_bus_adapter_t *bus_adap,
+       int (*as102_read_ep2) (struct as10x_bus_adapter_t *bus_adap,
                               unsigned char *recv_buf,
                               int recv_buf_len);
 };
index 3dedb3c1420a24308a5ae07b588d05b5ec8e9aaf..fde8140ae88b9406080b400e8ecb0ad609ae5e4b 100644 (file)
 /*********************************/
 
 /* bandwidth constant values */
-#define BW_5_MHZ           0x00
-#define BW_6_MHZ           0x01
-#define BW_7_MHZ           0x02
-#define BW_8_MHZ           0x03
+#define BW_5_MHZ               0x00
+#define BW_6_MHZ               0x01
+#define BW_7_MHZ               0x02
+#define BW_8_MHZ               0x03
 
 /* hierarchy priority selection values */
-#define HIER_NO_PRIORITY   0x00
-#define HIER_LOW_PRIORITY  0x01
-#define HIER_HIGH_PRIORITY 0x02
+#define HIER_NO_PRIORITY       0x00
+#define HIER_LOW_PRIORITY      0x01
+#define HIER_HIGH_PRIORITY     0x02
 
 /* constellation available values */
-#define CONST_QPSK         0x00
-#define CONST_QAM16        0x01
-#define CONST_QAM64        0x02
-#define CONST_UNKNOWN      0xFF
+#define CONST_QPSK             0x00
+#define CONST_QAM16            0x01
+#define CONST_QAM64            0x02
+#define CONST_UNKNOWN          0xFF
 
 /* hierarchy available values */
-#define HIER_NONE         0x00
-#define HIER_ALPHA_1      0x01
-#define HIER_ALPHA_2      0x02
-#define HIER_ALPHA_4      0x03
-#define HIER_UNKNOWN      0xFF
+#define HIER_NONE              0x00
+#define HIER_ALPHA_1           0x01
+#define HIER_ALPHA_2           0x02
+#define HIER_ALPHA_4           0x03
+#define HIER_UNKNOWN           0xFF
 
 /* interleaving available values */
-#define INTLV_NATIVE      0x00
-#define INTLV_IN_DEPTH    0x01
-#define INTLV_UNKNOWN     0xFF
+#define INTLV_NATIVE           0x00
+#define INTLV_IN_DEPTH         0x01
+#define INTLV_UNKNOWN          0xFF
 
 /* code rate available values */
-#define CODE_RATE_1_2     0x00
-#define CODE_RATE_2_3     0x01
-#define CODE_RATE_3_4     0x02
-#define CODE_RATE_5_6     0x03
-#define CODE_RATE_7_8     0x04
-#define CODE_RATE_UNKNOWN 0xFF
+#define CODE_RATE_1_2          0x00
+#define CODE_RATE_2_3          0x01
+#define CODE_RATE_3_4          0x02
+#define CODE_RATE_5_6          0x03
+#define CODE_RATE_7_8          0x04
+#define CODE_RATE_UNKNOWN      0xFF
 
 /* guard interval available values */
-#define GUARD_INT_1_32    0x00
-#define GUARD_INT_1_16    0x01
-#define GUARD_INT_1_8     0x02
-#define GUARD_INT_1_4     0x03
-#define GUARD_UNKNOWN     0xFF
+#define GUARD_INT_1_32         0x00
+#define GUARD_INT_1_16         0x01
+#define GUARD_INT_1_8          0x02
+#define GUARD_INT_1_4          0x03
+#define GUARD_UNKNOWN          0xFF
 
 /* transmission mode available values */
-#define TRANS_MODE_2K      0x00
-#define TRANS_MODE_8K      0x01
-#define TRANS_MODE_4K      0x02
-#define TRANS_MODE_UNKNOWN 0xFF
+#define TRANS_MODE_2K          0x00
+#define TRANS_MODE_8K          0x01
+#define TRANS_MODE_4K          0x02
+#define TRANS_MODE_UNKNOWN     0xFF
 
 /* DVBH signalling available values */
-#define TIMESLICING_PRESENT   0x01
-#define MPE_FEC_PRESENT       0x02
+#define TIMESLICING_PRESENT    0x01
+#define MPE_FEC_PRESENT                0x02
 
 /* tune state available */
-#define TUNE_STATUS_NOT_TUNED       0x00
-#define TUNE_STATUS_IDLE            0x01
-#define TUNE_STATUS_LOCKING         0x02
-#define TUNE_STATUS_SIGNAL_DVB_OK   0x03
-#define TUNE_STATUS_STREAM_DETECTED 0x04
-#define TUNE_STATUS_STREAM_TUNED    0x05
-#define TUNE_STATUS_ERROR           0xFF
+#define TUNE_STATUS_NOT_TUNED          0x00
+#define TUNE_STATUS_IDLE               0x01
+#define TUNE_STATUS_LOCKING            0x02
+#define TUNE_STATUS_SIGNAL_DVB_OK      0x03
+#define TUNE_STATUS_STREAM_DETECTED    0x04
+#define TUNE_STATUS_STREAM_TUNED       0x05
+#define TUNE_STATUS_ERROR              0xFF
 
 /* available TS FID filter types */
-#define TS_PID_TYPE_TS       0
-#define TS_PID_TYPE_PSI_SI   1
-#define TS_PID_TYPE_MPE      2
+#define TS_PID_TYPE_TS         0
+#define TS_PID_TYPE_PSI_SI     1
+#define TS_PID_TYPE_MPE                2
 
 /* number of echos available */
-#define MAX_ECHOS   15
+#define MAX_ECHOS      15
 
 /* Context types */
-#define CONTEXT_LNA                   1010
-#define CONTEXT_ELNA_HYSTERESIS       4003
-#define CONTEXT_ELNA_GAIN             4004
-#define CONTEXT_MER_THRESHOLD         5005
-#define CONTEXT_MER_OFFSET            5006
-#define CONTEXT_IR_STATE              7000
-#define CONTEXT_TSOUT_MSB_FIRST       7004
-#define CONTEXT_TSOUT_FALLING_EDGE    7005
+#define CONTEXT_LNA                    1010
+#define CONTEXT_ELNA_HYSTERESIS                4003
+#define CONTEXT_ELNA_GAIN              4004
+#define CONTEXT_MER_THRESHOLD          5005
+#define CONTEXT_MER_OFFSET             5006
+#define CONTEXT_IR_STATE               7000
+#define CONTEXT_TSOUT_MSB_FIRST                7004
+#define CONTEXT_TSOUT_FALLING_EDGE     7005
 
 /* Configuration modes */
-#define CFG_MODE_ON     0
-#define CFG_MODE_OFF    1
-#define CFG_MODE_AUTO   2
+#define CFG_MODE_ON    0
+#define CFG_MODE_OFF   1
+#define CFG_MODE_AUTO  2
 
-#pragma pack(1)
 struct as10x_tps {
-   uint8_t constellation;
-   uint8_t hierarchy;
-   uint8_t interleaving_mode;
-   uint8_t code_rate_HP;
-   uint8_t code_rate_LP;
-   uint8_t guard_interval;
-   uint8_t transmission_mode;
-   uint8_t DVBH_mask_HP;
-   uint8_t DVBH_mask_LP;
-   uint16_t cell_ID;
-};
+       uint8_t modulation;
+       uint8_t hierarchy;
+       uint8_t interleaving_mode;
+       uint8_t code_rate_HP;
+       uint8_t code_rate_LP;
+       uint8_t guard_interval;
+       uint8_t transmission_mode;
+       uint8_t DVBH_mask_HP;
+       uint8_t DVBH_mask_LP;
+       uint16_t cell_ID;
+} __packed;
 
 struct as10x_tune_args {
-   /* frequency */
-   uint32_t freq;
-   /* bandwidth */
-   uint8_t bandwidth;
-   /* hierarchy selection */
-   uint8_t hier_select;
-   /* constellation */
-   uint8_t constellation;
-   /* hierarchy */
-   uint8_t hierarchy;
-   /* interleaving mode */
-   uint8_t interleaving_mode;
-   /* code rate */
-   uint8_t code_rate;
-   /* guard interval */
-   uint8_t guard_interval;
-   /* transmission mode */
-   uint8_t transmission_mode;
-};
+       /* frequency */
+       uint32_t freq;
+       /* bandwidth */
+       uint8_t bandwidth;
+       /* hierarchy selection */
+       uint8_t hier_select;
+       /* constellation */
+       uint8_t modulation;
+       /* hierarchy */
+       uint8_t hierarchy;
+       /* interleaving mode */
+       uint8_t interleaving_mode;
+       /* code rate */
+       uint8_t code_rate;
+       /* guard interval */
+       uint8_t guard_interval;
+       /* transmission mode */
+       uint8_t transmission_mode;
+} __packed;
 
 struct as10x_tune_status {
-   /* tune status */
-   uint8_t tune_state;
-   /* signal strength */
-   int16_t signal_strength;
-   /* packet error rate 10^-4 */
-   uint16_t PER;
-   /* bit error rate 10^-4 */
-   uint16_t BER;
-};
+       /* tune status */
+       uint8_t tune_state;
+       /* signal strength */
+       int16_t signal_strength;
+       /* packet error rate 10^-4 */
+       uint16_t PER;
+       /* bit error rate 10^-4 */
+       uint16_t BER;
+} __packed;
 
 struct as10x_demod_stats {
-   /* frame counter */
-   uint32_t frame_count;
-   /* Bad frame counter */
-   uint32_t bad_frame_count;
-   /* Number of wrong bytes fixed by Reed-Solomon */
-   uint32_t bytes_fixed_by_rs;
-   /* Averaged MER */
-   uint16_t mer;
-   /* statistics calculation state indicator (started or not) */
-   uint8_t has_started;
-};
+       /* frame counter */
+       uint32_t frame_count;
+       /* Bad frame counter */
+       uint32_t bad_frame_count;
+       /* Number of wrong bytes fixed by Reed-Solomon */
+       uint32_t bytes_fixed_by_rs;
+       /* Averaged MER */
+       uint16_t mer;
+       /* statistics calculation state indicator (started or not) */
+       uint8_t has_started;
+} __packed;
 
 struct as10x_ts_filter {
-   uint16_t pid;  /** valid PID value 0x00 : 0x2000 */
-   uint8_t  type; /** Red TS_PID_TYPE_<N> values */
-   uint8_t  idx;  /** index in filtering table */
-};
+       uint16_t pid;  /* valid PID value 0x00 : 0x2000 */
+       uint8_t  type; /* Red TS_PID_TYPE_<N> values */
+       uint8_t  idx;  /* index in filtering table */
+} __packed;
 
 struct as10x_register_value {
-   uint8_t       mode;
-   union {
-      uint8_t    value8;    /* 8 bit value */
-      uint16_t   value16;   /* 16 bit value */
-      uint32_t   value32;   /* 32 bit value */
-   }u;
-};
-
-#pragma pack()
+       uint8_t mode;
+       union {
+               uint8_t  value8;   /* 8 bit value */
+               uint16_t value16;  /* 16 bit value */
+               uint32_t value32;  /* 32 bit value */
+       } u;
+} __packed;
 
 struct as10x_register_addr {
-   /* register addr */
-   uint32_t addr;
-   /* register mode access */
-   uint8_t mode;
+       /* register addr */
+       uint32_t addr;
+       /* register mode access */
+       uint8_t mode;
 };
 
-
 #endif
index 04e93c49f03a88af2d9b716fa70488461526189a..280c84ec4cc2c0ece47161f69547b03e62759ab6 100644 (file)
@@ -218,9 +218,10 @@ dt3155_start_acq(struct dt3155_priv *pd)
  *     driver-specific callbacks (vb2_ops)
  */
 static int
-dt3155_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
-                       unsigned int *num_planes, unsigned long sizes[],
-                                               void *alloc_ctxs[])
+dt3155_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+               unsigned int *num_buffers, unsigned int *num_planes,
+               unsigned int sizes[], void *alloc_ctxs[])
+
 {
        struct dt3155_priv *pd = vb2_get_drv_priv(q);
        void *ret;
@@ -261,12 +262,6 @@ dt3155_buf_prepare(struct vb2_buffer *vb)
        return 0;
 }
 
-static int
-dt3155_start_streaming(struct vb2_queue *q)
-{
-       return 0;
-}
-
 static int
 dt3155_stop_streaming(struct vb2_queue *q)
 {
@@ -308,7 +303,6 @@ const struct vb2_ops q_ops = {
        .wait_prepare = dt3155_wait_prepare,
        .wait_finish = dt3155_wait_finish,
        .buf_prepare = dt3155_buf_prepare,
-       .start_streaming = dt3155_start_streaming,
        .stop_streaming = dt3155_stop_streaming,
        .buf_queue = dt3155_buf_queue,
 };
@@ -914,9 +908,10 @@ dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (err)
                goto err_req_region;
        pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0));
-       if (!pd->regs)
+       if (!pd->regs) {
                err = -ENOMEM;
                goto err_pci_iomap;
+       }
        err = dt3155_init_board(pdev);
        if (err)
                goto err_init_board;
index 7b256a948c2758246d9983bab460c754d1c971b4..a007e7442be87d9a2d3b9bcff31726aae17b109f 100644 (file)
@@ -98,7 +98,6 @@
 #define EASYCAP_DRIVER_VERSION "0.9.01"
 #define EASYCAP_DRIVER_DESCRIPTION "easycapdc60"
 
-#define USB_SKEL_MINOR_BASE     192
 #define DONGLE_MANY 8
 #define INPUT_MANY 6
 /*---------------------------------------------------------------------------*/
@@ -324,8 +323,6 @@ struct easycap {
        int lost[INPUT_MANY];
        int merit[180];
 
-       long long int dnbydt;
-
        int    video_interface;
        int    video_altsetting_on;
        int    video_altsetting_off;
@@ -353,7 +350,6 @@ struct easycap {
        u8 *pcache;
        int video_mt;
        int audio_mt;
-       long long audio_bytes;
        u32 isequence;
 
        int vma_many;
@@ -450,9 +446,6 @@ struct easycap {
  *  SOUND PROPERTIES
  */
 /*---------------------------------------------------------------------------*/
-
-       int audio_buffer_many;
-
        int allocation_audio_urb;
        int allocation_audio_page;
        int allocation_audio_struct;
@@ -469,72 +462,53 @@ struct easycap {
  *  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_dqbuf(struct easycap *, int);
-int              submit_video_urbs(struct easycap *);
-int              kill_video_urbs(struct easycap *);
-int              field2frame(struct easycap *);
-int              redaub(struct easycap *, void *, void *,
-                                               int, int, u8, u8, bool);
-void             easycap_testcard(struct easycap *, int);
-int              fillin_formats(void);
-int              newinput(struct easycap *, int);
-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);
-int              adjust_volume(struct easycap *, int);
+
+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 *);
-void            easycap_alsa_complete(struct urb *);
-
-int              easycap_sound_setup(struct easycap *);
-int              submit_audio_urbs(struct easycap *);
-int              kill_audio_urbs(struct easycap *);
-void             easyoss_testtone(struct easycap *, int);
-int              audio_setup(struct easycap *);
+int easycap_alsa_probe(struct easycap *);
+int easycap_audio_kill_urbs(struct easycap *);
+void easycap_alsa_complete(struct urb *);
 /*---------------------------------------------------------------------------*/
 /*
  *  LOW-LEVEL FUNCTION PROTOTYPES
  */
 /*---------------------------------------------------------------------------*/
-int              audio_gainget(struct usb_device *);
-int              audio_gainset(struct usb_device *, s8);
+int easycap_audio_gainset(struct usb_device *, s8);
+int easycap_audio_setup(struct easycap *);
 
-int              set_interface(struct usb_device *, u16);
-int              wakeup_device(struct usb_device *);
-int              confirm_resolution(struct usb_device *);
-int              confirm_stream(struct usb_device *);
+int easycap_wakeup_device(struct usb_device *);
 
-int              setup_stk(struct usb_device *, bool);
-int              setup_saa(struct usb_device *, bool);
-int              setup_vt(struct usb_device *);
-int              check_stk(struct usb_device *, bool);
-int              check_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 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              read_stk(struct usb_device *, u32);
-int              write_saa(struct usb_device *, u16, u16);
-int              write_000(struct usb_device *, u16, u16);
-int              start_100(struct usb_device *);
-int              stop_100(struct usb_device *);
-int              write_300(struct usb_device *);
-int              read_vt(struct usb_device *, u16);
-int              write_vt(struct usb_device *, u16, u16);
-int            isdongle(struct easycap *);
+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 *);
 /*---------------------------------------------------------------------------*/
 
 
@@ -588,7 +562,6 @@ 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 usb_driver easycap_usb_driver;
 extern struct easycap_dongle easycapdc60_dongle[];
 
 #endif /* !__EASYCAP_H__  */
index c99addfb62428888bd089de3a96b43b6e20a8500..9413b37490c2f2468e726d8056cddf6b9a33293f 100644 (file)
@@ -25,7 +25,6 @@
 */
 /*****************************************************************************/
 
-#include <linux/version.h>
 #include "easycap.h"
 
 /*--------------------------------------------------------------------------*/
@@ -125,7 +124,7 @@ int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id)
        }
        if (peasycap->video_isoc_streaming) {
                resubmit = true;
-               kill_video_urbs(peasycap);
+               easycap_video_kill_urbs(peasycap);
        } else
                resubmit = false;
 /*--------------------------------------------------------------------------*/
@@ -331,7 +330,7 @@ int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id)
                            "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
        }
        if (resubmit)
-               submit_video_urbs(peasycap);
+               easycap_video_submit_urbs(peasycap);
        return 0;
 }
 /*****************************************************************************/
@@ -558,7 +557,7 @@ int adjust_format(struct easycap *peasycap,
                peasycap->bytesperpixel * peasycap->width * peasycap->height;
        if (peasycap->video_isoc_streaming) {
                resubmit = true;
-               kill_video_urbs(peasycap);
+               easycap_video_kill_urbs(peasycap);
        } else
                resubmit = false;
 /*---------------------------------------------------------------------------*/
@@ -622,7 +621,7 @@ int adjust_format(struct easycap *peasycap,
        }
 /*---------------------------------------------------------------------------*/
        if (resubmit)
-               submit_video_urbs(peasycap);
+               easycap_video_submit_urbs(peasycap);
 
        return peasycap_best_format - easycap_format;
 }
@@ -667,16 +666,15 @@ int adjust_brightness(struct easycap *peasycap, int value)
                                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("adjusting brightness to  0x%02X\n", mood);
-                               return 0;
-                       } else {
+                       if (write_saa(peasycap->pusb_device, 0x0A, mood)) {
                                SAM("WARNING: failed to adjust brightness "
                                    "to 0x%02X\n", mood);
                                return -ENOENT;
                        }
-                       break;
+                       SAM("adjusting brightness to  0x%02X\n", mood);
+                       return 0;
                }
                i1++;
        }
@@ -726,15 +724,13 @@ int adjust_contrast(struct easycap *peasycap, int value)
                                JOM(8, "%i=peasycap->input\n", peasycap->input);
 
                        mood = 0x00FF & (unsigned int) (peasycap->contrast - 128);
-                       if (!write_saa(peasycap->pusb_device, 0x0B, mood)) {
-                               SAM("adjusting contrast to  0x%02X\n", mood);
-                               return 0;
-                       } else {
+                       if (write_saa(peasycap->pusb_device, 0x0B, mood)) {
                                SAM("WARNING: failed to adjust contrast to "
                                    "0x%02X\n", mood);
                                return -ENOENT;
                        }
-                       break;
+                       SAM("adjusting contrast to  0x%02X\n", mood);
+                       return 0;
                }
                i1++;
        }
@@ -784,14 +780,13 @@ int adjust_saturation(struct easycap *peasycap, int value)
                        } 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("adjusting saturation to  0x%02X\n", mood);
-                               return 0;
-                       } else {
+                       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++;
@@ -839,13 +834,12 @@ int adjust_hue(struct easycap *peasycap, int value)
                                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("adjusting hue to  0x%02X\n", mood);
-                               return 0;
-                       } else {
+                       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++;
@@ -854,7 +848,7 @@ int adjust_hue(struct easycap *peasycap, int value)
        return -ENOENT;
 }
 /*****************************************************************************/
-int adjust_volume(struct easycap *peasycap, int value)
+static int adjust_volume(struct easycap *peasycap, int value)
 {
        s8 mood;
        int i1;
@@ -885,15 +879,13 @@ int adjust_volume(struct easycap *peasycap, int value)
                        mood = (16 > peasycap->volume) ? 16 :
                                ((31 < peasycap->volume) ? 31 :
                                  (s8) peasycap->volume);
-                       if (!audio_gainset(peasycap->pusb_device, mood)) {
-                               SAM("adjusting volume to 0x%02X\n", mood);
-                               return 0;
-                       } else {
+                       if (!easycap_audio_gainset(peasycap->pusb_device, mood)) {
                                SAM("WARNING: failed to adjust volume to "
                                    "0x%2X\n", mood);
                                return -ENOENT;
                        }
-                       break;
+                       SAM("adjusting volume to 0x%02X\n", mood);
+                       return 0;
                }
                i1++;
        }
@@ -971,7 +963,7 @@ long easycap_unlocked_ioctl(struct file *file,
                SAM("ERROR: peasycap->pusb_device is NULL\n");
                return -EFAULT;
        }
-       kd = isdongle(peasycap);
+       kd = easycap_isdongle(peasycap);
        if (0 <= kd && DONGLE_MANY > kd) {
                if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
                        SAY("ERROR: cannot lock "
@@ -986,7 +978,7 @@ long easycap_unlocked_ioctl(struct file *file,
  *  IF NECESSARY, BAIL OUT.
  */
 /*---------------------------------------------------------------------------*/
-               if (kd != isdongle(peasycap))
+               if (kd != easycap_isdongle(peasycap))
                        return -ERESTARTSYS;
                if (!file) {
                        SAY("ERROR:  file is NULL\n");
@@ -1226,7 +1218,7 @@ long easycap_unlocked_ioctl(struct file *file,
                        return -EINVAL;
                }
 
-               rc = newinput(peasycap, (int)index);
+               rc = easycap_newinput(peasycap, (int)index);
                if (0 == rc) {
                        JOM(8, "newinput(.,%i) OK\n", (int)index);
                } else {
@@ -2209,7 +2201,7 @@ long easycap_unlocked_ioctl(struct file *file,
 
                if (!peasycap->polled) {
                        do {
-                               rcdq = easycap_dqbuf(peasycap, 0);
+                               rcdq = easycap_video_dqbuf(peasycap, 0);
                                if (-EIO == rcdq) {
                                        JOM(8, "returning -EIO because "
                                            "dqbuf() returned -EIO\n");
@@ -2313,7 +2305,7 @@ long easycap_unlocked_ioctl(struct file *file,
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                        return -EFAULT;
                }
-               submit_video_urbs(peasycap);
+               easycap_video_submit_urbs(peasycap);
                peasycap->video_idle = 0;
                peasycap->audio_idle = 0;
                peasycap->video_eof = 0;
index 0385735ac6df8a56d0a0a7f306941afdce47f6fb..0380babed22c02b62db3c8f7ceb1096ad24d4190 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "easycap.h"
 
+
 #define GET(X, Y, Z) do { \
        int __rc; \
        *(Z) = (u16)0; \
@@ -59,9 +60,9 @@
 
 /*--------------------------------------------------------------------------*/
 static const struct stk1160config {
-       int reg;
-       int set;
-} stk1160configPAL[256] = {
+       u16 reg;
+       u16 set;
+} stk1160configPAL[] = {
                {0x000, 0x0098},
                {0x002, 0x0093},
 
@@ -103,7 +104,7 @@ static const struct stk1160config {
                {0xFFF, 0xFFFF}
 };
 /*--------------------------------------------------------------------------*/
-static const struct stk1160config stk1160configNTSC[256] = {
+static const struct stk1160config stk1160configNTSC[] = {
                {0x000, 0x0098},
                {0x002, 0x0093},
 
@@ -146,9 +147,9 @@ static const struct stk1160config stk1160configNTSC[256] = {
 };
 /*--------------------------------------------------------------------------*/
 static const struct saa7113config {
-       int reg;
-       int set;
-} saa7113configPAL[256] = {
+       u8 reg;
+       u8 set;
+} saa7113configPAL[] = {
                {0x01, 0x08},
                {0x02, 0x80},
                {0x03, 0x33},
@@ -202,7 +203,7 @@ static const struct saa7113config {
                {0xFF, 0xFF}
 };
 /*--------------------------------------------------------------------------*/
-static const struct saa7113config saa7113configNTSC[256] = {
+static const struct saa7113config saa7113configNTSC[] = {
                {0x01, 0x08},
                {0x02, 0x80},
                {0x03, 0x33},
@@ -354,101 +355,6 @@ static int wait_i2c(struct usb_device *p)
        return -1;
 }
 
-/****************************************************************************/
-int confirm_resolution(struct usb_device *p)
-{
-       u8 get0, get1, get2, get3, get4, get5, get6, get7;
-
-       if (!p)
-               return -ENODEV;
-       GET(p, 0x0110, &get0);
-       GET(p, 0x0111, &get1);
-       GET(p, 0x0112, &get2);
-       GET(p, 0x0113, &get3);
-       GET(p, 0x0114, &get4);
-       GET(p, 0x0115, &get5);
-       GET(p, 0x0116, &get6);
-       GET(p, 0x0117, &get7);
-       JOT(8,  "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X\n",
-               get0, get1, get2, get3, get4, get5, get6, get7);
-       JOT(8,  "....cf PAL_720x526: "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X\n",
-               0x000, 0x000, 0x001, 0x000, 0x5A0, 0x005, 0x121, 0x001);
-       JOT(8,  "....cf PAL_704x526: "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X\n",
-               0x004, 0x000, 0x001, 0x000, 0x584, 0x005, 0x121, 0x001);
-       JOT(8,  "....cf VGA_640x480: "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X\n",
-               0x008, 0x000, 0x020, 0x000, 0x508, 0x005, 0x110, 0x001);
-       return 0;
-}
-/****************************************************************************/
-int confirm_stream(struct usb_device *p)
-{
-       u16 get2;
-       u8 igot;
-
-       if (!p)
-               return -ENODEV;
-       GET(p, 0x0100, &igot);  get2 = 0x80 & igot;
-       if (0x80 == get2)
-               JOT(8, "confirm_stream:  OK\n");
-       else
-               JOT(8, "confirm_stream:  STUCK\n");
-       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, ir;
-       const struct saa7113config *cfg;
-       if (!p)
-               return -ENODEV;
-       cfg = (ntsc) ?  saa7113configNTSC : saa7113configPAL;
-       for (i = 0; cfg[i].reg != 0xFF; i++)
-               ir = write_saa(p, cfg[i].reg, cfg[i].set);
-       return 0;
-}
-/****************************************************************************/
-int write_000(struct usb_device *p, u16 set2, u16 set0)
-{
-       u8 igot0, igot2;
-
-       if (!p)
-               return -ENODEV;
-       GET(p, 0x0002, &igot2);
-       GET(p, 0x0000, &igot0);
-       SET(p, 0x0002, set2);
-       SET(p, 0x0000, set0);
-       return 0;
-}
 /****************************************************************************/
 int write_saa(struct usb_device *p, u16 reg0, u16 set0)
 {
@@ -470,8 +376,7 @@ int write_saa(struct usb_device *p, u16 reg0, u16 set0)
  *  REGISTER 504:  TARGET ADDRESS ON VT1612A
  */
 /*--------------------------------------------------------------------------*/
-int
-write_vt(struct usb_device *p, u16 reg0, u16 set0)
+static int write_vt(struct usb_device *p, u16 reg0, u16 set0)
 {
        u8 igot;
        u16 got502, got503;
@@ -508,7 +413,7 @@ write_vt(struct usb_device *p, u16 reg0, u16 set0)
  *  REGISTER 504:  TARGET ADDRESS ON VT1612A
  */
 /*--------------------------------------------------------------------------*/
-int read_vt(struct usb_device *p, u16 reg0)
+static int read_vt(struct usb_device *p, u16 reg0)
 {
        u8 igot;
        u16 got502, got503;
@@ -532,7 +437,7 @@ int read_vt(struct usb_device *p, u16 reg0)
  *  THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO.
  */
 /*--------------------------------------------------------------------------*/
-int write_300(struct usb_device *p)
+static int write_300(struct usb_device *p)
 {
        if (!p)
                return -ENODEV;
@@ -545,32 +450,36 @@ int write_300(struct usb_device *p)
        return 0;
 }
 /****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  NOTE: THE FOLLOWING IS NOT CHECKED:
- *  REGISTER 0x0F, WHICH IS INVOLVED IN CHROMINANCE AUTOMATIC GAIN CONTROL.
- */
-/*--------------------------------------------------------------------------*/
-int check_saa(struct usb_device *p, bool ntsc)
+/****************************************************************************/
+int setup_stk(struct usb_device *p, bool ntsc)
 {
-       int i, ir, rc = 0;
-       struct saa7113config const *cfg;
+       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);
 
-       cfg = (ntsc) ? saa7113configNTSC : saa7113configPAL;
+       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++) {
-               if (0x0F == cfg[i].reg)
-                       continue;
-               ir = read_saa(p, cfg[i].reg);
-               if (ir != cfg[i].set) {
-                       SAY("SAA register 0x%02X has 0x%02X, expected 0x%02X\n",
-                               cfg[i].reg, ir, cfg[i].set);
-                               rc--;
-               }
+               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 (rc < -8) ? rc : 0;
+       return 0;
 }
 /****************************************************************************/
 int merit_saa(struct usb_device *p)
@@ -609,60 +518,22 @@ int ready_saa(struct usb_device *p)
                msleep(marktime);
                j++;
        }
+
        if (max == j)
                return -1;
-       else {
-               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;
-}
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  NOTE: THE FOLLOWING ARE NOT CHECKED:
- *  REGISTERS 0x000, 0x002:  FUNCTIONALITY IS NOT KNOWN
- *  REGISTER  0x100:  ACCEPT ALSO (0x80 | stk1160config....[.].set)
- */
-/*--------------------------------------------------------------------------*/
-int check_stk(struct usb_device *p, bool ntsc)
-{
-       int i, ir;
-       const struct stk1160config *cfg;
-
-       if (!p)
-               return -ENODEV;
-       cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL;
-
-       for (i = 0; 0xFFF != cfg[i].reg; i++) {
-               if (0x000 == cfg[i].reg || 0x002 == cfg[i].reg)
-                       continue;
 
-
-               ir = read_stk(p, cfg[i].reg);
-               if (0x100 == cfg[i].reg) {
-                       if ((ir != (0xFF & cfg[i].set)) &&
-                           (ir != (0x80 | (0xFF & cfg[i].set))) &&
-                           (0xFFFF != cfg[i].set)) {
-                               SAY("STK reg[0x%03X]=0x%02X expected 0x%02X\n",
-                                       cfg[i].reg, ir, cfg[i].set);
-                       }
-                       continue;
-               }
-               if ((ir != (0xFF & cfg[i].set)) && (0xFFFF != cfg[i].set))
-                       SAY("STK register 0x%03X has 0x%02X,expected 0x%02X\n",
-                               cfg[i].reg, ir, cfg[i].set);
+       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;
 }
@@ -682,7 +553,7 @@ int read_saa(struct usb_device *p, u16 reg0)
        return igot;
 }
 /****************************************************************************/
-int read_stk(struct usb_device *p, u32 reg0)
+static int read_stk(struct usb_device *p, u32 reg0)
 {
        u8 igot;
 
@@ -692,27 +563,7 @@ int read_stk(struct usb_device *p, u32 reg0)
        GET(p, reg0, &igot);
        return igot;
 }
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *    HARDWARE    USERSPACE INPUT NUMBER   PHYSICAL INPUT   DRIVER input VALUE
- *
- *  CVBS+S-VIDEO           0 or 1              CVBS                 1
- *   FOUR-CVBS             0 or 1              CVBS1                1
- *   FOUR-CVBS                2                CVBS2                2
- *   FOUR-CVBS                3                CVBS3                3
- *   FOUR-CVBS                4                CVBS4                4
- *  CVBS+S-VIDEO              5               S-VIDEO               5
- *
- *  WHEN 5==input THE ARGUMENT mode MUST ALSO BE SUPPLIED:
- *
- *     mode  7   => GAIN TO BE SET EXPLICITLY USING REGISTER 0x05 (UNTESTED)
- *     mode  9   => USE AUTOMATIC GAIN CONTROL (DEFAULT)
- *
-*/
-/*---------------------------------------------------------------------------*/
-int
-select_input(struct usb_device *p, int input, int mode)
+int select_input(struct usb_device *p, int input, int mode)
 {
        int ir;
 
@@ -877,10 +728,11 @@ int stop_100(struct usb_device *p)
 /****************************************************************************/
 /****************************************************************************/
 /*****************************************************************************/
-int wakeup_device(struct usb_device *pusb_device)
+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,
@@ -888,8 +740,7 @@ int wakeup_device(struct usb_device *pusb_device)
                        0, NULL, 0, 50000);
 }
 /*****************************************************************************/
-int
-audio_setup(struct easycap *peasycap)
+int easycap_audio_setup(struct easycap *peasycap)
 {
        struct usb_device *pusb_device;
        u8 buffer[1];
@@ -970,7 +821,7 @@ audio_setup(struct easycap *peasycap)
  *  SELECT AUDIO SOURCE "LINE IN" AND SET THE AUDIO GAIN.
 */
 /*---------------------------------------------------------------------------*/
-       if (0 != audio_gainset(pusb_device, peasycap->gain))
+       if (easycap_audio_gainset(pusb_device, peasycap->gain))
                SAY("ERROR: audio_gainset() failed\n");
        check_vt(pusb_device);
        return 0;
@@ -1047,7 +898,7 @@ int check_vt(struct usb_device *pusb_device)
  *        31                12.0                  22.5            34.5
 */
 /*---------------------------------------------------------------------------*/
-int audio_gainset(struct usb_device *pusb_device, s8 loud)
+int easycap_audio_gainset(struct usb_device *pusb_device, s8 loud)
 {
        int igot;
        u8 tmp;
@@ -1115,15 +966,3 @@ int audio_gainset(struct usb_device *pusb_device, s8 loud)
        return 0;
 }
 /*****************************************************************************/
-int audio_gainget(struct usb_device *pusb_device)
-{
-       int igot;
-
-       if (!pusb_device)
-               return -ENODEV;
-       igot = read_vt(pusb_device, 0x001C);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x1C\n");
-       return igot;
-}
-/*****************************************************************************/
index a45c0b5070678785196fa1c9e2fd04ed77f964dd..8ff5f38ea1964302af28c1d6d47fba5ffa5f4376 100644 (file)
@@ -66,6 +66,10 @@ 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)
 {
@@ -109,23 +113,13 @@ const char *strerror(int err)
 #undef ERRNOSTR
 }
 
-/*---------------------------------------------------------------------------*/
-/*
- *  PARAMETERS USED WHEN REGISTERING THE VIDEO INTERFACE
- *
- *  NOTE: SOME KERNELS IGNORE usb_class_driver.minor_base, AS MENTIONED BY
- *        CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGE 253.
- *        THIS IS THE CASE FOR OpenSUSE.
- */
-/*---------------------------------------------------------------------------*/
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
 /****************************************************************************/
 /*---------------------------------------------------------------------------*/
 /*
  *  THIS ROUTINE DOES NOT DETECT DUPLICATE OCCURRENCES OF POINTER peasycap
 */
 /*---------------------------------------------------------------------------*/
-int isdongle(struct easycap *peasycap)
+int easycap_isdongle(struct easycap *peasycap)
 {
        int k;
        if (!peasycap)
@@ -161,14 +155,13 @@ static int easycap_open(struct inode *inode, struct file *file)
        if (!peasycap->pusb_device) {
                SAM("ERROR: peasycap->pusb_device is NULL\n");
                return -EFAULT;
-       } else {
-               JOM(16, "peasycap->pusb_device=%p\n", peasycap->pusb_device);
        }
+
+       JOM(16, "peasycap->pusb_device=%p\n", peasycap->pusb_device);
+
        file->private_data = peasycap;
-       rc = wakeup_device(peasycap->pusb_device);
-       if (0 == rc)
-               JOM(8, "wakeup_device() OK\n");
-       else {
+       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");
@@ -176,6 +169,7 @@ static int easycap_open(struct inode *inode, struct file *file)
                        SAM("ERROR: wakeup_device() rc = %i\n", rc);
                return rc;
        }
+       JOM(8, "wakeup_device() OK\n");
        peasycap->input = 0;
        rc = reset(peasycap);
        if (rc) {
@@ -303,7 +297,7 @@ static int reset(struct easycap *peasycap)
        peasycap->saturation = -8192;
        peasycap->hue = -8192;
 
-       rc = newinput(peasycap, input);
+       rc = easycap_newinput(peasycap, input);
 
        if (rc) {
                SAM("ERROR: newinput(.,%i) rc = %i\n", rc, input);
@@ -364,8 +358,7 @@ static int reset(struct easycap *peasycap)
  *      SO IT SHOULD WRITE ONLY SPARINGLY TO THE LOGFILE.
 */
 /*---------------------------------------------------------------------------*/
-int
-newinput(struct easycap *peasycap, int input)
+int easycap_newinput(struct easycap *peasycap, int input)
 {
        int rc, k, m, mood, off;
        int inputnow, video_idlenow, audio_idlenow;
@@ -397,7 +390,7 @@ newinput(struct easycap *peasycap, int input)
        peasycap->audio_idle = 1;
        if (peasycap->video_isoc_streaming) {
                resubmit = true;
-               kill_video_urbs(peasycap);
+               easycap_video_kill_urbs(peasycap);
        } else {
                resubmit = false;
        }
@@ -532,7 +525,7 @@ newinput(struct easycap *peasycap, int input)
                return -EFAULT;
        }
        if (resubmit)
-               submit_video_urbs(peasycap);
+               easycap_video_submit_urbs(peasycap);
 
        peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1;
        peasycap->video_idle = video_idlenow;
@@ -542,7 +535,7 @@ newinput(struct easycap *peasycap, int input)
        return 0;
 }
 /*****************************************************************************/
-int submit_video_urbs(struct easycap *peasycap)
+int easycap_video_submit_urbs(struct easycap *peasycap)
 {
        struct data_urb *pdata_urb;
        struct urb *purb;
@@ -616,43 +609,53 @@ int submit_video_urbs(struct easycap *peasycap)
                        peasycap->video_eof = 1;
                }
 
-               if (isbad) {
-                       JOM(4, "attempting cleanup instead of submitting\n");
-                       list_for_each(plist_head, (peasycap->purb_video_head)) {
-                               pdata_urb = list_entry(plist_head,
-                                               struct data_urb, list_head);
-                               if (pdata_urb) {
-                                       purb = pdata_urb->purb;
-                                       if (purb)
-                                               usb_kill_urb(purb);
-                               }
-                       }
-                       peasycap->video_isoc_streaming = 0;
-               } else {
+               if (isbad)
+                       easycap_video_kill_urbs(peasycap);
+               else
                        peasycap->video_isoc_streaming = 1;
-                       JOM(4, "submitted %i video urbs\n", m);
-               }
        } else {
                JOM(4, "already streaming video urbs\n");
        }
        return 0;
 }
 /*****************************************************************************/
-int kill_video_urbs(struct easycap *peasycap)
+int easycap_audio_kill_urbs(struct easycap *peasycap)
 {
        int m;
        struct list_head *plist_head;
        struct data_urb *pdata_urb;
 
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
+       if (!peasycap->audio_isoc_streaming)
+               return 0;
+
+       if (!peasycap->purb_audio_head) {
+               SAM("ERROR: peasycap->purb_audio_head is NULL\n");
                return -EFAULT;
        }
-       if (!peasycap->video_isoc_streaming) {
-               JOM(8, "%i=video_isoc_streaming, no video urbs killed\n",
-                       peasycap->video_isoc_streaming);
-               return 0;
+
+       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;
@@ -690,8 +693,8 @@ static int videodev_release(struct video_device *pvideo_device)
                SAY("ending unsuccessfully\n");
                return -EFAULT;
        }
-       if (0 != kill_video_urbs(peasycap)) {
-               SAM("ERROR: kill_video_urbs() failed\n");
+       if (easycap_video_kill_urbs(peasycap)) {
+               SAM("ERROR: easycap_video_kill_urbs() failed\n");
                return -EFAULT;
        }
        JOM(4, "ending successfully\n");
@@ -727,27 +730,22 @@ static void easycap_delete(struct kref *pkref)
                SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
                return;
        }
-       kd = isdongle(peasycap);
+       kd = easycap_isdongle(peasycap);
 /*---------------------------------------------------------------------------*/
 /*
  *  FREE VIDEO.
  */
 /*---------------------------------------------------------------------------*/
        if (peasycap->purb_video_head) {
-               JOM(4, "freeing video urbs\n");
                m = 0;
-               list_for_each(plist_head, (peasycap->purb_video_head)) {
+               list_for_each(plist_head, peasycap->purb_video_head) {
                        pdata_urb = list_entry(plist_head,
                                                struct data_urb, list_head);
-                       if (!pdata_urb) {
-                               JOM(4, "ERROR: pdata_urb is NULL\n");
-                       } else {
-                               if (pdata_urb->purb) {
-                                       usb_free_urb(pdata_urb->purb);
-                                       pdata_urb->purb = NULL;
-                                       peasycap->allocation_video_urb -= 1;
-                                       m++;
-                               }
+                       if (pdata_urb && pdata_urb->purb) {
+                               usb_free_urb(pdata_urb->purb);
+                               pdata_urb->purb = NULL;
+                               peasycap->allocation_video_urb--;
+                               m++;
                        }
                }
 
@@ -763,7 +761,6 @@ static void easycap_delete(struct kref *pkref)
                                peasycap->allocation_video_struct -=
                                                sizeof(struct data_urb);
                                kfree(pdata_urb);
-                               pdata_urb = NULL;
                                m++;
                        }
                }
@@ -828,15 +825,11 @@ static void easycap_delete(struct kref *pkref)
                list_for_each(plist_head, (peasycap->purb_audio_head)) {
                        pdata_urb = list_entry(plist_head,
                                        struct data_urb, list_head);
-                       if (!pdata_urb)
-                               JOM(4, "ERROR: pdata_urb is NULL\n");
-                       else {
-                               if (pdata_urb->purb) {
-                                       usb_free_urb(pdata_urb->purb);
-                                       pdata_urb->purb = NULL;
-                                       peasycap->allocation_audio_urb -= 1;
-                                       m++;
-                               }
+                       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);
@@ -851,7 +844,6 @@ static void easycap_delete(struct kref *pkref)
                                peasycap->allocation_audio_struct -=
                                                        sizeof(struct data_urb);
                                kfree(pdata_urb);
-                               pdata_urb = NULL;
                                m++;
                        }
                }
@@ -940,7 +932,7 @@ static unsigned int easycap_poll(struct file *file, poll_table *wait)
                return -EFAULT;
        }
 /*---------------------------------------------------------------------------*/
-       kd = isdongle(peasycap);
+       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);
@@ -952,7 +944,7 @@ static unsigned int easycap_poll(struct file *file, poll_table *wait)
         *  peasycap, IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
         *  IF NECESSARY, BAIL OUT.
         */
-               if (kd != isdongle(peasycap)) {
+               if (kd != easycap_isdongle(peasycap)) {
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                        return -ERESTARTSYS;
                }
@@ -980,21 +972,21 @@ static unsigned int easycap_poll(struct file *file, poll_table *wait)
        */
                return -ERESTARTSYS;
 /*---------------------------------------------------------------------------*/
-       rc = easycap_dqbuf(peasycap, 0);
+       rc = easycap_video_dqbuf(peasycap, 0);
        peasycap->polled = 1;
        mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-       if (0 == rc)
-               return POLLIN | POLLRDNORM;
-       else
+       if (rc)
                return POLLERR;
-       }
+
+       return POLLIN | POLLRDNORM;
+}
 /*****************************************************************************/
 /*---------------------------------------------------------------------------*/
 /*
  *  IF mode IS NONZERO THIS ROUTINE RETURNS -EAGAIN RATHER THAN BLOCKING.
  */
 /*---------------------------------------------------------------------------*/
-int easycap_dqbuf(struct easycap *peasycap, int mode)
+int easycap_video_dqbuf(struct easycap *peasycap, int mode)
 {
        int input, ifield, miss, rc;
 
@@ -1080,7 +1072,7 @@ int easycap_dqbuf(struct easycap *peasycap, int mode)
                                        JOM(8, " ... failed  returning -EIO\n");
                                        peasycap->video_eof = 1;
                                        peasycap->audio_eof = 1;
-                                       kill_video_urbs(peasycap);
+                                       easycap_video_kill_urbs(peasycap);
                                        return -EIO;
                                }
                                peasycap->status = 0;
@@ -1090,7 +1082,7 @@ int easycap_dqbuf(struct easycap *peasycap, int mode)
                        #endif /*PERSEVERE*/
                        peasycap->video_eof = 1;
                        peasycap->audio_eof = 1;
-                       kill_video_urbs(peasycap);
+                       easycap_video_kill_urbs(peasycap);
                        JOM(8, "returning -EIO\n");
                        return -EIO;
                }
@@ -1143,7 +1135,7 @@ int easycap_dqbuf(struct easycap *peasycap, int mode)
                                        JOM(8, " ... failed returning -EIO\n");
                                        peasycap->video_eof = 1;
                                        peasycap->audio_eof = 1;
-                                       kill_video_urbs(peasycap);
+                                       easycap_video_kill_urbs(peasycap);
                                        return -EIO;
                                }
                                peasycap->status = 0;
@@ -1153,7 +1145,7 @@ int easycap_dqbuf(struct easycap *peasycap, int mode)
 #endif /*PERSEVERE*/
                        peasycap->video_eof = 1;
                        peasycap->audio_eof = 1;
-                       kill_video_urbs(peasycap);
+                       easycap_video_kill_urbs(peasycap);
                        JOM(8, "returning -EIO\n");
                        return -EIO;
                }
@@ -1207,12 +1199,9 @@ int easycap_dqbuf(struct easycap *peasycap, int mode)
  *  WHEN BOOLEAN PARAMETER decimatepixel IS true, ONLY THE FIELD FOR WHICH
  *  odd==false IS TRANSFERRED TO THE FRAME BUFFER.
  *
- *  THE BOOLEAN PARAMETER offerfields IS true ONLY WHEN THE USER PROGRAM
- *  CHOOSES THE OPTION V4L2_FIELD_INTERLACED.
  */
 /*---------------------------------------------------------------------------*/
-int
-field2frame(struct easycap *peasycap)
+static int field2frame(struct easycap *peasycap)
 {
 
        void *pex, *pad;
@@ -1221,7 +1210,7 @@ field2frame(struct easycap *peasycap)
        int rc, bytesperpixel, multiplier;
        int  much, more, over, rump, caches, input;
        u8 mask, margin;
-       bool odd, isuy, decimatepixel, offerfields, badinput;
+       bool odd, isuy, decimatepixel, badinput;
 
        if (!peasycap) {
                SAY("ERROR: peasycap is NULL\n");
@@ -1237,8 +1226,6 @@ field2frame(struct easycap *peasycap)
                        peasycap->field_buffer[peasycap->field_read][0].input,
                        peasycap->field_read, peasycap->frame_fill);
        JOM(8, "=====  %i=bytesperpixel\n", peasycap->bytesperpixel);
-       if (peasycap->offerfields)
-               JOM(8, "===== offerfields\n");
 
 /*---------------------------------------------------------------------------*/
 /*
@@ -1260,7 +1247,6 @@ field2frame(struct easycap *peasycap)
 #endif /*EASYCAP_TESTCARD*/
 /*---------------------------------------------------------------------------*/
 
-       offerfields = peasycap->offerfields;
        bytesperpixel = peasycap->bytesperpixel;
        decimatepixel = peasycap->decimatepixel;
 
@@ -1601,9 +1587,9 @@ field2frame(struct easycap *peasycap)
  *  REDUCE CODE LENGTH WILL GENERALLY IMPAIR RUNTIME PERFORMANCE.  BEWARE.
  */
 /*---------------------------------------------------------------------------*/
-int
-redaub(struct easycap *peasycap, void *pad, void *pex, int much, int more,
-                                       u8 mask, u8 margin, bool isuy)
+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;
@@ -2855,20 +2841,7 @@ static void easycap_complete(struct urb *purb)
        }
        return;
 }
-static const struct file_operations easycap_fops = {
-       .owner          = THIS_MODULE,
-       .open           = easycap_open,
-       .unlocked_ioctl = easycap_unlocked_ioctl,
-       .poll           = easycap_poll,
-       .mmap           = easycap_mmap,
-       .llseek         = no_llseek,
-};
-static const struct usb_class_driver easycap_class = {
-       .name = "usb/easycap%d",
-       .fops = &easycap_fops,
-       .minor_base = USB_SKEL_MINOR_BASE,
-};
-/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+
 static const struct v4l2_file_operations v4l2_fops = {
        .owner          = THIS_MODULE,
        .open           = easycap_open_noinode,
@@ -2917,6 +2890,7 @@ static int easycap_usb_probe(struct usb_interface *intf,
                SAY("ERROR: usb_host_interface not found\n");
                return -EFAULT;
        }
+
        interface = &alt->desc;
        if (!interface) {
                SAY("ERROR: intf_descriptor is NULL\n");
@@ -2976,44 +2950,31 @@ static int easycap_usb_probe(struct usb_interface *intf,
                if (mutex_lock_interruptible(&mutex_dongle)) {
                        SAY("ERROR: cannot down mutex_dongle\n");
                        return -ERESTARTSYS;
-               } else {
-/*---------------------------------------------------------------------------*/
-               /*
-                *  FOR INTERFACES 1 AND 2 THE POINTER peasycap WILL NEED TO
-                *  TO BE THE SAME AS THAT ALLOCATED NOW FOR INTERFACE 0.
-                *
-                *  NORMALLY ndong WILL NOT HAVE CHANGED SINCE INTERFACE 0 WAS
-                *  PROBED, BUT THIS MAY NOT BE THE CASE IF, FOR EXAMPLE, TWO
-                *  EASYCAPs ARE PLUGGED IN SIMULTANEOUSLY.
-               */
-/*---------------------------------------------------------------------------*/
-                       for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
-                               if ((!easycapdc60_dongle[ndong].peasycap) &&
-                                               (!mutex_is_locked(&easycapdc60_dongle
-                                                       [ndong].mutex_video)) &&
-                                               (!mutex_is_locked(&easycapdc60_dongle
-                                                       [ndong].mutex_audio))) {
-                                       easycapdc60_dongle[ndong].peasycap = peasycap;
-                                       peasycap->isdongle = ndong;
-                                       JOM(8, "intf[%i]: peasycap-->easycap"
-                                                       "_dongle[%i].peasycap\n",
-                                                       bInterfaceNumber, ndong);
-                                       break;
-                               }
-                       }
-                       if (DONGLE_MANY <= ndong) {
-                               SAM("ERROR: too many dongles\n");
-                               mutex_unlock(&mutex_dongle);
-                               return -ENOMEM;
+               }
+
+               for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
+                       if ((!easycapdc60_dongle[ndong].peasycap) &&
+                                       (!mutex_is_locked(&easycapdc60_dongle
+                                               [ndong].mutex_video)) &&
+                                       (!mutex_is_locked(&easycapdc60_dongle
+                                               [ndong].mutex_audio))) {
+                               easycapdc60_dongle[ndong].peasycap = peasycap;
+                               peasycap->isdongle = ndong;
+                               JOM(8, "intf[%i]: peasycap-->easycap"
+                                               "_dongle[%i].peasycap\n",
+                                               bInterfaceNumber, ndong);
+                               break;
                        }
+               }
+
+               if (DONGLE_MANY <= ndong) {
+                       SAM("ERROR: too many dongles\n");
                        mutex_unlock(&mutex_dongle);
+                       return -ENOMEM;
                }
+               mutex_unlock(&mutex_dongle);
+
                peasycap->allocation_video_struct = sizeof(struct easycap);
-               peasycap->allocation_video_page = 0;
-               peasycap->allocation_video_urb = 0;
-               peasycap->allocation_audio_struct = 0;
-               peasycap->allocation_audio_page = 0;
-               peasycap->allocation_audio_urb = 0;
 
 /*---------------------------------------------------------------------------*/
 /*
@@ -3023,7 +2984,6 @@ static int easycap_usb_probe(struct usb_interface *intf,
                peasycap->pusb_device = usbdev;
                peasycap->pusb_interface = intf;
 
-               peasycap->ilk = 0;
                peasycap->microphone = false;
 
                peasycap->video_interface = -1;
@@ -3042,38 +3002,21 @@ static int easycap_usb_probe(struct usb_interface *intf,
 
                peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
 
-               for (k = 0; k < INPUT_MANY; k++)
-                       peasycap->lost[k] = 0;
-               peasycap->skip = 0;
-               peasycap->skipped = 0;
-               peasycap->offerfields = 0;
 /*---------------------------------------------------------------------------*/
 /*
  *  DYNAMICALLY FILL IN THE AVAILABLE FORMATS ...
  */
 /*---------------------------------------------------------------------------*/
-               rc = fillin_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);
-/*---------------------------------------------------------------------------*/
-/*
- *  ... AND POPULATE easycap.inputset[]
-*/
-/*---------------------------------------------------------------------------*/
-               /* FIXME: maybe we just use memset 0 */
+
+               /*  ... AND POPULATE easycap.inputset[] */
+
                inputset = peasycap->inputset;
-               for (k = 0; k < INPUT_MANY; k++) {
-                       inputset[k].input_ok = 0;
-                       inputset[k].standard_offset_ok = 0;
-                       inputset[k].format_offset_ok = 0;
-                       inputset[k].brightness_ok = 0;
-                       inputset[k].contrast_ok = 0;
-                       inputset[k].saturation_ok = 0;
-                       inputset[k].hue_ok = 0;
-               }
 
                fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
                m = 0;
@@ -3390,11 +3333,10 @@ static int easycap_usb_probe(struct usb_interface *intf,
                if (!isokalt) {
                        SAM("ERROR:  no viable video_altsetting_on\n");
                        return -ENOENT;
-               } else {
-                       peasycap->video_altsetting_on = okalt[isokalt - 1];
-                       JOM(4, "%i=video_altsetting_on <====\n",
-                                               peasycap->video_altsetting_on);
                }
+               peasycap->video_altsetting_on = okalt[isokalt - 1];
+               JOM(4, "%i=video_altsetting_on <====\n",
+                                       peasycap->video_altsetting_on);
 /*---------------------------------------------------------------------------*/
 /*
  *  DECIDE THE VIDEO STREAMING PARAMETERS
@@ -3480,8 +3422,9 @@ static int easycap_usb_probe(struct usb_interface *intf,
                                                SAM("ERROR: Could not allocate frame "
                                                        "buffer %i page %i\n", k, m);
                                                return -ENOMEM;
-                                       } else
-                                               peasycap->allocation_video_page += 1;
+                                       }
+
+                                       peasycap->allocation_video_page += 1;
                                        peasycap->frame_buffer[k][m].pgo = pbuf;
                                }
                                peasycap->frame_buffer[k][m].pto =
@@ -3510,11 +3453,11 @@ static int easycap_usb_probe(struct usb_interface *intf,
                                                SAM("ERROR: Could not allocate field"
                                                        " buffer %i page %i\n", k, m);
                                                return -ENOMEM;
-                                               }
-                                       else
-                                               peasycap->allocation_video_page += 1;
-                                       peasycap->field_buffer[k][m].pgo = pbuf;
                                        }
+
+                                       peasycap->allocation_video_page += 1;
+                                       peasycap->field_buffer[k][m].pgo = pbuf;
+                               }
                                peasycap->field_buffer[k][m].pto =
                                                peasycap->field_buffer[k][m].pgo;
                        }
@@ -3538,9 +3481,9 @@ static int easycap_usb_probe(struct usb_interface *intf,
                                SAM("ERROR: Could not allocate isoc video buffer "
                                                                        "%i\n", k);
                                return -ENOMEM;
-                       } else
-                               peasycap->allocation_video_page +=
-                                       BIT(VIDEO_ISOC_ORDER);
+                       }
+                       peasycap->allocation_video_page +=
+                                               BIT(VIDEO_ISOC_ORDER);
 
                        peasycap->video_isoc_buffer[k].pgo = pbuf;
                        peasycap->video_isoc_buffer[k].pto =
@@ -3569,15 +3512,17 @@ static int easycap_usb_probe(struct usb_interface *intf,
                                SAM("ERROR: usb_alloc_urb returned NULL for buffer "
                                                                        "%i\n", k);
                                return -ENOMEM;
-                       } else
-                               peasycap->allocation_video_urb += 1;
+                       }
+
+                       peasycap->allocation_video_urb += 1;
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
                        pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
                        if (!pdata_urb) {
                                SAM("ERROR: Could not allocate struct data_urb.\n");
                                return -ENOMEM;
-                       } else
-                               peasycap->allocation_video_struct +=
+                       }
+
+                       peasycap->allocation_video_struct +=
                                                        sizeof(struct data_urb);
 
                        pdata_urb->purb = purb;
@@ -3694,13 +3639,12 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        err("Not able to register with videodev");
                        videodev_release(&(peasycap->video_device));
                        return -ENODEV;
-               } else {
-                       (peasycap->registered_video)++;
-                       SAM("registered with videodev: %i=minor\n",
-                                                       peasycap->video_device.minor);
-                       peasycap->minor = peasycap->video_device.minor;
                }
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+
+               peasycap->registered_video++;
+               SAM("registered with videodev: %i=minor\n",
+                                               peasycap->video_device.minor);
+               peasycap->minor = peasycap->video_device.minor;
 
                break;
        }
@@ -3734,11 +3678,10 @@ static int easycap_usb_probe(struct usb_interface *intf,
                if (!isokalt) {
                        SAM("ERROR:  no viable audio_altsetting_on\n");
                        return -ENOENT;
-               } else {
-                       peasycap->audio_altsetting_on = okalt[isokalt - 1];
-                       JOM(4, "%i=audio_altsetting_on <====\n",
-                                                       peasycap->audio_altsetting_on);
                }
+               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);
@@ -3847,8 +3790,8 @@ static int easycap_usb_probe(struct usb_interface *intf,
                                SAM("ERROR: Could not allocate isoc audio buffer "
                                                                "%i\n", k);
                                return -ENOMEM;
-                       } else
-                               peasycap->allocation_audio_page +=
+                       }
+                       peasycap->allocation_audio_page +=
                                                BIT(AUDIO_ISOC_ORDER);
 
                        peasycap->audio_isoc_buffer[k].pgo = pbuf;
@@ -3996,12 +3939,9 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
 {
        struct usb_host_interface *pusb_host_interface;
        struct usb_interface_descriptor *pusb_interface_descriptor;
-       u8 bInterfaceNumber;
        struct easycap *peasycap;
-
-       struct list_head *plist_head;
-       struct data_urb *pdata_urb;
-       int minor, m, kd;
+       int minor, kd;
+       u8 bInterfaceNumber;
 
        JOT(4, "\n");
 
@@ -4036,45 +3976,14 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
        peasycap->audio_eof = 1;
        wake_up_interruptible(&(peasycap->wq_video));
        wake_up_interruptible(&(peasycap->wq_audio));
-/*---------------------------------------------------------------------------*/
+
        switch (bInterfaceNumber) {
-       case 0: {
-               if (peasycap->purb_video_head) {
-                       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) {
-                                       if (pdata_urb->purb) {
-                                               usb_kill_urb(pdata_urb->purb);
-                                               m++;
-                                       }
-                               }
-                       }
-                       JOM(4, "%i video urbs killed\n", m);
-               }
+       case 0:
+               easycap_video_kill_urbs(peasycap);
                break;
-       }
-/*---------------------------------------------------------------------------*/
-       case 2: {
-               if (peasycap->purb_audio_head) {
-                       JOM(4, "killing 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) {
-                                       if (pdata_urb->purb) {
-                                               usb_kill_urb(pdata_urb->purb);
-                                               m++;
-                                       }
-                               }
-                       }
-                       JOM(4, "%i audio urbs killed\n", m);
-               }
+       case 2:
+               easycap_audio_kill_urbs(peasycap);
                break;
-       }
        default:
                break;
        }
@@ -4087,7 +3996,7 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
  *  AN EasyCAP IS UNPLUGGED WHILE THE URBS ARE RUNNING.  BEWARE.
  */
 /*--------------------------------------------------------------------------*/
-       kd = isdongle(peasycap);
+       kd = easycap_isdongle(peasycap);
        switch (bInterfaceNumber) {
        case 0: {
                if (0 <= kd && DONGLE_MANY > kd) {
@@ -4212,7 +4121,7 @@ static struct usb_device_id easycap_usb_device_id_table[] = {
 };
 
 MODULE_DEVICE_TABLE(usb, easycap_usb_device_id_table);
-struct usb_driver easycap_usb_driver = {
+static struct usb_driver easycap_usb_driver = {
        .name = "easycap",
        .id_table = easycap_usb_device_id_table,
        .probe = easycap_usb_probe,
index 70f59b13c34d7a1a5e5403e6b5ff2da22719f899..3f5f5b3e5a359b94f5839cc1f5ff1cde9d59d9c0 100644 (file)
@@ -313,7 +313,7 @@ const struct easycap_standard easycap_standard[] = {
 
 struct easycap_format easycap_format[1 + SETTINGS_MANY];
 
-int fillin_formats(void)
+int easycap_video_fillin_formats(void)
 {
        const char *name1, *name2, *name3, *name4;
        struct v4l2_format *fmt;
index b22bb39b5f69294882cdb82ca4b8f6c2b65f63c2..8c8bcae8ded8470886f81fac6599d88f67fb251c 100644 (file)
@@ -56,6 +56,141 @@ static const struct snd_pcm_hardware alsa_hardware = {
 };
 
 
+/*---------------------------------------------------------------------------*/
+/*
+ *  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;
+}
 /*****************************************************************************/
 /*---------------------------------------------------------------------------*/
 /*
@@ -64,8 +199,7 @@ static const struct snd_pcm_hardware alsa_hardware = {
  *  IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
  */
 /*---------------------------------------------------------------------------*/
-void
-easycap_alsa_complete(struct urb *purb)
+void easycap_alsa_complete(struct urb *purb)
 {
        struct easycap *peasycap;
        struct snd_pcm_substream *pss;
@@ -458,7 +592,6 @@ static int easycap_alsa_ack(struct snd_pcm_substream *pss)
 static int easycap_alsa_trigger(struct snd_pcm_substream *pss, int cmd)
 {
        struct easycap *peasycap;
-       int retval;
 
        JOT(4, "%i=cmd cf %i=START %i=STOP\n", cmd, SNDRV_PCM_TRIGGER_START,
            SNDRV_PCM_TRIGGER_STOP);
@@ -481,7 +614,7 @@ static int easycap_alsa_trigger(struct snd_pcm_substream *pss, int cmd)
                break;
        }
        default:
-               retval = -EINVAL;
+               return -EINVAL;
        }
        return 0;
 }
@@ -615,202 +748,3 @@ int easycap_alsa_probe(struct easycap *peasycap)
        return 0;
 }
 
-/*****************************************************************************/
-/*****************************************************************************/
-/*****************************************************************************/
-/*****************************************************************************/
-/*****************************************************************************/
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  COMMON AUDIO INITIALIZATION
- */
-/*---------------------------------------------------------------------------*/
-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 = 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 = wakeup_device(peasycap->pusb_device);
-       JOM(8, "wakeup_device() returned %i\n", rc);
-
-       peasycap->audio_eof = 0;
-       peasycap->audio_idle = 0;
-
-       submit_audio_urbs(peasycap);
-
-       JOM(4, "finished initialization\n");
-       return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  SUBMIT ALL AUDIO URBS.
- */
-/*---------------------------------------------------------------------------*/
-int
-submit_audio_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_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) {
-               JOM(4, "attempting cleanup instead of submitting\n");
-               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);
-               }
-               peasycap->audio_isoc_streaming = 0;
-       } else {
-               peasycap->audio_isoc_streaming = m;
-               JOM(4, "submitted %i audio urbs\n", m);
-       }
-
-       return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  KILL ALL AUDIO URBS.
- */
-/*---------------------------------------------------------------------------*/
-int
-kill_audio_urbs(struct easycap *peasycap)
-{
-       int m;
-       struct list_head *plist_head;
-       struct data_urb *pdata_urb;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-
-       if (!peasycap->audio_isoc_streaming) {
-               JOM(8, "%i=audio_isoc_streaming, no audio urbs killed\n",
-                   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;
-       JOM(4, "killing 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_kill_urb(pdata_urb->purb);
-                       m++;
-               }
-       }
-       JOM(4, "%i audio urbs killed\n", m);
-
-       return 0;
-}
-/*****************************************************************************/
index b7175fe1b15f9c6331f16971cf0dbaf8e7681d3f..70e006b50f292259025b50a5b03a2aa26a9c2b5f 100644 (file)
@@ -1054,7 +1054,13 @@ static int go7007_usb_probe(struct usb_interface *intf,
        else
                go->hpi_ops = &go7007_usb_onboard_hpi_ops;
        go->hpi_context = usb;
-       usb_fill_int_urb(usb->intr_urb, usb->usbdev,
+       if (go->board_id == GO7007_BOARDID_SENSORAY_2250)
+               usb_fill_bulk_urb(usb->intr_urb, usb->usbdev,
+                       usb_rcvbulkpipe(usb->usbdev, 4),
+                       usb->intr_urb->transfer_buffer, 2*sizeof(u16),
+                       go7007_usb_readinterrupt_complete, go);
+       else
+               usb_fill_int_urb(usb->intr_urb, usb->usbdev,
                        usb_rcvintpipe(usb->usbdev, 4),
                        usb->intr_urb->transfer_buffer, 2*sizeof(u16),
                        go7007_usb_readinterrupt_complete, go, 8);
index deac938d850535b367cf35d0f5a3c195b5faa96c..d071c838ac2a3b7ce1fff2574fca926dcadcdea7 100644 (file)
@@ -38,7 +38,7 @@
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 module_param_array(index, int, NULL, 0444);
 module_param_array(id, charp, NULL, 0444);
index c5a0d27a02dca0a0881d3e4551e97716fa73b898..4d20e9f741187460dee46dc23707d9f86882744a 100644 (file)
@@ -53,7 +53,7 @@ static unsigned char do_get_bits(void);
 
 #define DRIVER_NAME "lirc_bt829"
 
-static int debug;
+static bool debug;
 #define dprintk(fmt, args...)                                           \
        do {                                                             \
                if (debug)                                               \
index 6cd4cd67a1ddcf1b6f7252fc0973e4b6030598eb..7a25017766790598f88622aa57e776581a505ea7 100644 (file)
@@ -62,9 +62,9 @@
 
 /* debugging support */
 #ifdef CONFIG_USB_DEBUG
-static int debug = 1;
+static bool debug = 1;
 #else
-static int debug;
+static bool debug;
 #endif
 
 #define dprintk(fmt, args...)                                  \
index f68218012f231aab1f5fbe33953d140a8ff6a177..5f7f8cd3a66148bed7b5dfae551f6919d96c7454 100644 (file)
@@ -63,7 +63,7 @@ static int display_open(struct inode *inode, struct file *file);
 static int display_close(struct inode *inode, struct file *file);
 
 /* VFD write operation */
-static ssize_t vfd_write(struct file *file, const char *buf,
+static ssize_t vfd_write(struct file *file, const char __user *buf,
                         size_t n_bytes, loff_t *pos);
 
 /* LIRC driver function prototypes */
@@ -369,7 +369,7 @@ static int send_packet(struct imon_context *context)
  * than 32 bytes are provided spaces will be appended to
  * generate a full screen.
  */
-static ssize_t vfd_write(struct file *file, const char *buf,
+static ssize_t vfd_write(struct file *file, const char __user *buf,
                         size_t n_bytes, loff_t *pos)
 {
        int i;
index 792aac0a8e7b94f353afd76bb0f831dbad1fab28..dd2bca7b56faf4b09afa5f3f6a1207d940507f6a 100644 (file)
@@ -63,8 +63,8 @@
 
 /*** Global Variables ***/
 
-static int debug;
-static int check_pselecd;
+static bool debug;
+static bool check_pselecd;
 
 unsigned int irq = LIRC_IRQ;
 unsigned int io = LIRC_PORT;
@@ -752,4 +752,4 @@ module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Enable debugging messages");
 
 module_param(check_pselecd, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Check for printer (default: 0)");
+MODULE_PARM_DESC(check_pselecd, "Check for printer (default: 0)");
index 8a060a8a7224fbcb1dbe72eb6e0a89d8e6ef9d78..8dd8897ad86028da33ce68991fed3c302c4dcc2a 100644 (file)
@@ -107,13 +107,13 @@ struct lirc_serial {
 static int type;
 static int io;
 static int irq;
-static int iommap;
+static bool iommap;
 static int ioshift;
-static int softcarrier = 1;
-static int share_irq;
-static int debug;
+static bool softcarrier = 1;
+static bool share_irq;
+static bool debug;
 static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */
-static int txsense;    /* 0 = active high, 1 = active low */
+static bool txsense;   /* 0 = active high, 1 = active low */
 
 #define dprintk(fmt, args...)                                  \
        do {                                                    \
@@ -773,7 +773,7 @@ static int hardware_init_port(void)
                /* we fail, there's nothing here */
                printk(KERN_ERR LIRC_DRIVER_NAME ": port existence test "
                       "failed, cannot continue\n");
-               return -EINVAL;
+               return -ENODEV;
        }
 
 
@@ -836,25 +836,22 @@ static int hardware_init_port(void)
        return 0;
 }
 
-static int init_port(void)
+static int __devinit lirc_serial_probe(struct platform_device *dev)
 {
        int i, nlow, nhigh, result;
 
        result = request_irq(irq, irq_handler,
                             (share_irq ? IRQF_SHARED : 0),
                             LIRC_DRIVER_NAME, (void *)&hardware);
-
-       switch (result) {
-       case -EBUSY:
-               printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq);
-               return -EBUSY;
-       case -EINVAL:
-               printk(KERN_ERR LIRC_DRIVER_NAME
-                      ": Bad irq number or handler\n");
-               return -EINVAL;
-       default:
-               break;
-       };
+       if (result < 0) {
+               if (result == -EBUSY)
+                       printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n",
+                              irq);
+               else if (result == -EINVAL)
+                       printk(KERN_ERR LIRC_DRIVER_NAME
+                              ": Bad irq number or handler\n");
+               return result;
+       }
 
        /* Reserve io region. */
        /*
@@ -875,11 +872,13 @@ static int init_port(void)
                       ": or compile the serial port driver as module and\n");
                printk(KERN_WARNING LIRC_DRIVER_NAME
                       ": make sure this module is loaded first\n");
-               return -EBUSY;
+               result = -EBUSY;
+               goto exit_free_irq;
        }
 
-       if (hardware_init_port() < 0)
-               return -EINVAL;
+       result = hardware_init_port();
+       if (result < 0)
+               goto exit_release_region;
 
        /* Initialize pulse/space widths */
        init_timing_params(duty_cycle, freq);
@@ -911,6 +910,28 @@ static int init_port(void)
 
        dprintk("Interrupt %d, port %04x obtained\n", irq, io);
        return 0;
+
+exit_release_region:
+       if (iommap != 0)
+               release_mem_region(iommap, 8 << ioshift);
+       else
+               release_region(io, 8);
+exit_free_irq:
+       free_irq(irq, (void *)&hardware);
+
+       return result;
+}
+
+static int __devexit lirc_serial_remove(struct platform_device *dev)
+{
+       free_irq(irq, (void *)&hardware);
+
+       if (iommap != 0)
+               release_mem_region(iommap, 8 << ioshift);
+       else
+               release_region(io, 8);
+
+       return 0;
 }
 
 static int set_use_inc(void *data)
@@ -955,7 +976,7 @@ static ssize_t lirc_write(struct file *file, const char *buf,
        int *wbuf;
 
        if (!(hardware[type].features & LIRC_CAN_SEND_PULSE))
-               return -EBADF;
+               return -EPERM;
 
        count = n / sizeof(int);
        if (n % sizeof(int) || count % 2 == 0)
@@ -1006,11 +1027,11 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
                        return result;
                /* only LIRC_MODE_PULSE supported */
                if (value != LIRC_MODE_PULSE)
-                       return -ENOSYS;
+                       return -EINVAL;
                break;
 
        case LIRC_GET_LENGTH:
-               return -ENOSYS;
+               return -ENOIOCTLCMD;
                break;
 
        case LIRC_SET_SEND_DUTY_CYCLE:
@@ -1076,16 +1097,6 @@ static struct lirc_driver driver = {
 
 static struct platform_device *lirc_serial_dev;
 
-static int __devinit lirc_serial_probe(struct platform_device *dev)
-{
-       return 0;
-}
-
-static int __devexit lirc_serial_remove(struct platform_device *dev)
-{
-       return 0;
-}
-
 static int lirc_serial_suspend(struct platform_device *dev,
                               pm_message_t state)
 {
@@ -1111,11 +1122,11 @@ static void lirc_serial_exit(void);
 static int lirc_serial_resume(struct platform_device *dev)
 {
        unsigned long flags;
+       int result;
 
-       if (hardware_init_port() < 0) {
-               lirc_serial_exit();
-               return -EINVAL;
-       }
+       result = hardware_init_port();
+       if (result < 0)
+               return result;
 
        spin_lock_irqsave(&hardware[type].lock, flags);
        /* Enable Interrupt */
@@ -1148,7 +1159,7 @@ static int __init lirc_serial_init(void)
        /* Init read buffer. */
        result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN);
        if (result < 0)
-               return -ENOMEM;
+               return result;
 
        result = platform_driver_register(&lirc_serial_driver);
        if (result) {
@@ -1188,10 +1199,6 @@ static int __init lirc_serial_init_module(void)
 {
        int result;
 
-       result = lirc_serial_init();
-       if (result)
-               return result;
-
        switch (type) {
        case LIRC_HOMEBREW:
        case LIRC_IRDEO:
@@ -1211,8 +1218,7 @@ static int __init lirc_serial_init_module(void)
                break;
 #endif
        default:
-               result = -EINVAL;
-               goto exit_serial_exit;
+               return -EINVAL;
        }
        if (!softcarrier) {
                switch (type) {
@@ -1228,37 +1234,26 @@ static int __init lirc_serial_init_module(void)
                }
        }
 
-       result = init_port();
-       if (result < 0)
-               goto exit_serial_exit;
+       result = lirc_serial_init();
+       if (result)
+               return result;
+
        driver.features = hardware[type].features;
        driver.dev = &lirc_serial_dev->dev;
        driver.minor = lirc_register_driver(&driver);
        if (driver.minor < 0) {
                printk(KERN_ERR  LIRC_DRIVER_NAME
                       ": register_chrdev failed!\n");
-               result = -EIO;
-               goto exit_release;
+               lirc_serial_exit();
+               return driver.minor;
        }
        return 0;
-exit_release:
-       release_region(io, 8);
-exit_serial_exit:
-       lirc_serial_exit();
-       return result;
 }
 
 static void __exit lirc_serial_exit_module(void)
 {
-       lirc_serial_exit();
-
-       free_irq(irq, (void *)&hardware);
-
-       if (iommap != 0)
-               release_mem_region(iommap, 8 << ioshift);
-       else
-               release_region(io, 8);
        lirc_unregister_driver(driver.minor);
+       lirc_serial_exit();
        dprintk("cleaned up module\n");
 }
 
index 6903d3992eca02e48f541f90fbca57bb567dbf02..c94382b917aca0b49057b8c3b57ad0e1166b327f 100644 (file)
@@ -173,7 +173,7 @@ static DEFINE_SPINLOCK(hardware_lock);
 static int rx_buf[RBUF_LEN];
 static unsigned int rx_tail, rx_head;
 
-static int debug;
+static bool debug;
 #define dprintk(fmt, args...)                                          \
        do {                                                            \
                if (debug)                                              \
index 0302d82a12f79b7595d74604a826febff08377a6..76ea4a8f2c751a865bce422d50da43dbf940880c 100644 (file)
@@ -155,8 +155,8 @@ static struct mutex tx_data_lock;
 #define zilog_info(s, args...) printk(KERN_INFO KBUILD_MODNAME ": " s, ## args)
 
 /* module parameters */
-static int debug;      /* debug output */
-static int tx_only;    /* only handle the IR Tx function */
+static bool debug;     /* debug output */
+static bool tx_only;   /* only handle the IR Tx function */
 static int minor = -1; /* minor number */
 
 #define dprintk(fmt, args...)                                          \
index 72816cf167041afaac21099f47005eca975d2019..337e38c3a0f02c85904cbd9e4fd51525c8d1f34d 100644 (file)
@@ -1,3 +1,3 @@
 solo6x10-y := core.o i2c.o p2m.o v4l2.o tw28.o gpio.o disp.o enc.o v4l2-enc.o g723.o
 
-obj-$(CONFIG_SOLO6X10) := solo6x10.o
+obj-$(CONFIG_SOLO6X10) += solo6x10.o
index bee7280bbed985c59b4e919f229e22834d4aced7..f8f0da952288d127963bdd3c19887864c141f494 100644 (file)
@@ -26,7 +26,7 @@
 #include <media/videobuf-dma-sg.h>
 #include "solo6x10.h"
 #include "tw28.h"
-#include "jpeg.h"
+#include "solo6x10-jpeg.h"
 
 #define MIN_VID_BUFFERS                4
 #define FRAME_BUF_SIZE         (128 * 1024)
index fc850bac88c152f37ce4d05682d7c3e77f71d851..9012dee0c348325a4d25668ff54610d6c1aac52d 100644 (file)
@@ -20,9 +20,4 @@ octeon-ethernet-y += ethernet-sgmii.o
 octeon-ethernet-y += ethernet-spi.o
 octeon-ethernet-y += ethernet-tx.o
 octeon-ethernet-y += ethernet-xaui.o
-octeon-ethernet-y += cvmx-pko.o cvmx-spi.o cvmx-cmd-queue.o \
-       cvmx-helper-board.o cvmx-helper.o cvmx-helper-xaui.o \
-       cvmx-helper-rgmii.o cvmx-helper-sgmii.o cvmx-helper-npi.o \
-       cvmx-helper-loop.o cvmx-helper-spi.o cvmx-helper-util.o \
-       cvmx-interrupt-decodes.o cvmx-interrupt-rsl.o
 
diff --git a/drivers/staging/octeon/cvmx-packet.h b/drivers/staging/octeon/cvmx-packet.h
deleted file mode 100644 (file)
index 62ffe78..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/***********************license start***************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2008 Cavium Networks
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, Version 2, as
- * published by the Free Software Foundation.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
- ***********************license end**************************************/
-
-/**
- *
- * Packet buffer defines.
- */
-
-#ifndef __CVMX_PACKET_H__
-#define __CVMX_PACKET_H__
-
-/**
- * This structure defines a buffer pointer on Octeon
- */
-union cvmx_buf_ptr {
-       void *ptr;
-       uint64_t u64;
-       struct {
-               /*
-                * if set, invert the "free" pick of the overall
-                * packet. HW always sets this bit to 0 on inbound
-                * packet
-                */
-               uint64_t i:1;
-               /*
-                * Indicates the amount to back up to get to the
-                * buffer start in cache lines. In most cases this is
-                * less than one complete cache line, so the value is
-                * zero.
-                */
-               uint64_t back:4;
-               /* The pool that the buffer came from / goes to */
-               uint64_t pool:3;
-               /* The size of the segment pointed to by addr (in bytes) */
-               uint64_t size:16;
-               /* Pointer to the first byte of the data, NOT buffer */
-               uint64_t addr:40;
-       } s;
-};
-
-#endif /*  __CVMX_PACKET_H__ */
diff --git a/drivers/staging/octeon/cvmx-smix-defs.h b/drivers/staging/octeon/cvmx-smix-defs.h
deleted file mode 100644 (file)
index 9ae45fc..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/***********************license start***************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2008 Cavium Networks
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, Version 2, as
- * published by the Free Software Foundation.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
- ***********************license end**************************************/
-
-#ifndef __CVMX_SMIX_DEFS_H__
-#define __CVMX_SMIX_DEFS_H__
-
-#define CVMX_SMIX_CLK(offset) \
-        CVMX_ADD_IO_SEG(0x0001180000001818ull + (((offset) & 1) * 256))
-#define CVMX_SMIX_CMD(offset) \
-        CVMX_ADD_IO_SEG(0x0001180000001800ull + (((offset) & 1) * 256))
-#define CVMX_SMIX_EN(offset) \
-        CVMX_ADD_IO_SEG(0x0001180000001820ull + (((offset) & 1) * 256))
-#define CVMX_SMIX_RD_DAT(offset) \
-        CVMX_ADD_IO_SEG(0x0001180000001810ull + (((offset) & 1) * 256))
-#define CVMX_SMIX_WR_DAT(offset) \
-        CVMX_ADD_IO_SEG(0x0001180000001808ull + (((offset) & 1) * 256))
-
-union cvmx_smix_clk {
-       uint64_t u64;
-       struct cvmx_smix_clk_s {
-               uint64_t reserved_25_63:39;
-               uint64_t mode:1;
-               uint64_t reserved_21_23:3;
-               uint64_t sample_hi:5;
-               uint64_t sample_mode:1;
-               uint64_t reserved_14_14:1;
-               uint64_t clk_idle:1;
-               uint64_t preamble:1;
-               uint64_t sample:4;
-               uint64_t phase:8;
-       } s;
-       struct cvmx_smix_clk_cn30xx {
-               uint64_t reserved_21_63:43;
-               uint64_t sample_hi:5;
-               uint64_t reserved_14_15:2;
-               uint64_t clk_idle:1;
-               uint64_t preamble:1;
-               uint64_t sample:4;
-               uint64_t phase:8;
-       } cn30xx;
-       struct cvmx_smix_clk_cn30xx cn31xx;
-       struct cvmx_smix_clk_cn30xx cn38xx;
-       struct cvmx_smix_clk_cn30xx cn38xxp2;
-       struct cvmx_smix_clk_cn50xx {
-               uint64_t reserved_25_63:39;
-               uint64_t mode:1;
-               uint64_t reserved_21_23:3;
-               uint64_t sample_hi:5;
-               uint64_t reserved_14_15:2;
-               uint64_t clk_idle:1;
-               uint64_t preamble:1;
-               uint64_t sample:4;
-               uint64_t phase:8;
-       } cn50xx;
-       struct cvmx_smix_clk_s cn52xx;
-       struct cvmx_smix_clk_cn50xx cn52xxp1;
-       struct cvmx_smix_clk_s cn56xx;
-       struct cvmx_smix_clk_cn50xx cn56xxp1;
-       struct cvmx_smix_clk_cn30xx cn58xx;
-       struct cvmx_smix_clk_cn30xx cn58xxp1;
-};
-
-union cvmx_smix_cmd {
-       uint64_t u64;
-       struct cvmx_smix_cmd_s {
-               uint64_t reserved_18_63:46;
-               uint64_t phy_op:2;
-               uint64_t reserved_13_15:3;
-               uint64_t phy_adr:5;
-               uint64_t reserved_5_7:3;
-               uint64_t reg_adr:5;
-       } s;
-       struct cvmx_smix_cmd_cn30xx {
-               uint64_t reserved_17_63:47;
-               uint64_t phy_op:1;
-               uint64_t reserved_13_15:3;
-               uint64_t phy_adr:5;
-               uint64_t reserved_5_7:3;
-               uint64_t reg_adr:5;
-       } cn30xx;
-       struct cvmx_smix_cmd_cn30xx cn31xx;
-       struct cvmx_smix_cmd_cn30xx cn38xx;
-       struct cvmx_smix_cmd_cn30xx cn38xxp2;
-       struct cvmx_smix_cmd_s cn50xx;
-       struct cvmx_smix_cmd_s cn52xx;
-       struct cvmx_smix_cmd_s cn52xxp1;
-       struct cvmx_smix_cmd_s cn56xx;
-       struct cvmx_smix_cmd_s cn56xxp1;
-       struct cvmx_smix_cmd_cn30xx cn58xx;
-       struct cvmx_smix_cmd_cn30xx cn58xxp1;
-};
-
-union cvmx_smix_en {
-       uint64_t u64;
-       struct cvmx_smix_en_s {
-               uint64_t reserved_1_63:63;
-               uint64_t en:1;
-       } s;
-       struct cvmx_smix_en_s cn30xx;
-       struct cvmx_smix_en_s cn31xx;
-       struct cvmx_smix_en_s cn38xx;
-       struct cvmx_smix_en_s cn38xxp2;
-       struct cvmx_smix_en_s cn50xx;
-       struct cvmx_smix_en_s cn52xx;
-       struct cvmx_smix_en_s cn52xxp1;
-       struct cvmx_smix_en_s cn56xx;
-       struct cvmx_smix_en_s cn56xxp1;
-       struct cvmx_smix_en_s cn58xx;
-       struct cvmx_smix_en_s cn58xxp1;
-};
-
-union cvmx_smix_rd_dat {
-       uint64_t u64;
-       struct cvmx_smix_rd_dat_s {
-               uint64_t reserved_18_63:46;
-               uint64_t pending:1;
-               uint64_t val:1;
-               uint64_t dat:16;
-       } s;
-       struct cvmx_smix_rd_dat_s cn30xx;
-       struct cvmx_smix_rd_dat_s cn31xx;
-       struct cvmx_smix_rd_dat_s cn38xx;
-       struct cvmx_smix_rd_dat_s cn38xxp2;
-       struct cvmx_smix_rd_dat_s cn50xx;
-       struct cvmx_smix_rd_dat_s cn52xx;
-       struct cvmx_smix_rd_dat_s cn52xxp1;
-       struct cvmx_smix_rd_dat_s cn56xx;
-       struct cvmx_smix_rd_dat_s cn56xxp1;
-       struct cvmx_smix_rd_dat_s cn58xx;
-       struct cvmx_smix_rd_dat_s cn58xxp1;
-};
-
-union cvmx_smix_wr_dat {
-       uint64_t u64;
-       struct cvmx_smix_wr_dat_s {
-               uint64_t reserved_18_63:46;
-               uint64_t pending:1;
-               uint64_t val:1;
-               uint64_t dat:16;
-       } s;
-       struct cvmx_smix_wr_dat_s cn30xx;
-       struct cvmx_smix_wr_dat_s cn31xx;
-       struct cvmx_smix_wr_dat_s cn38xx;
-       struct cvmx_smix_wr_dat_s cn38xxp2;
-       struct cvmx_smix_wr_dat_s cn50xx;
-       struct cvmx_smix_wr_dat_s cn52xx;
-       struct cvmx_smix_wr_dat_s cn52xxp1;
-       struct cvmx_smix_wr_dat_s cn56xx;
-       struct cvmx_smix_wr_dat_s cn56xxp1;
-       struct cvmx_smix_wr_dat_s cn58xx;
-       struct cvmx_smix_wr_dat_s cn58xxp1;
-};
-
-#endif
index 6a2cd50a17dfe0e4f76747ea67d10f6285c597c2..bdaec8d2ca0c18f0562c76fb8fbaaa8e45d4aa2e 100644 (file)
@@ -59,7 +59,7 @@
 #ifndef __ETHERNET_DEFINES_H__
 #define __ETHERNET_DEFINES_H__
 
-#include "cvmx-config.h"
+#include <asm/octeon/cvmx-config.h>
 
 
 #define OCTEON_ETHERNET_VERSION "1.9"
index f18e3e140413c4a0a5b5a48197c5a1e08557c134..63800ba71d06534f4ff7ff8cc8bfa064738e96ee 100644 (file)
@@ -38,9 +38,9 @@
 #include "ethernet-mdio.h"
 #include "ethernet-util.h"
 
-#include "cvmx-helper-board.h"
+#include <asm/octeon/cvmx-helper-board.h>
 
-#include "cvmx-smix-defs.h"
+#include <asm/octeon/cvmx-smix-defs.h>
 
 static void cvm_oct_get_drvinfo(struct net_device *dev,
                                struct ethtool_drvinfo *info)
index 635bb86cdcff38297e7d9a2201f3b35544977c20..78b6cb7437695a2f36a3d04adcb338346596b37c 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "ethernet-defines.h"
 
-#include "cvmx-fpa.h"
+#include <asm/octeon/cvmx-fpa.h>
 
 /**
  * cvm_oct_fill_hw_skbuff - fill the supplied hardware pool with skbuffs
index c3d73f8431ae88f3cc7604ac603aabd36ae26a29..d8f5f694ec35532055781ff48b6edd79f4e502cd 100644 (file)
 #include "octeon-ethernet.h"
 #include "ethernet-util.h"
 
-#include "cvmx-helper.h"
+#include <asm/octeon/cvmx-helper.h>
 
 #include <asm/octeon/cvmx-ipd-defs.h>
 #include <asm/octeon/cvmx-npi-defs.h>
-#include "cvmx-gmxx-defs.h"
+#include <asm/octeon/cvmx-gmxx-defs.h>
 
 DEFINE_SPINLOCK(global_register_lock);
 
index 8b307b428791915799f06298ce746b5ce002ecf5..400df8cbee538b55a50e7baa92ceb18cae9e28c5 100644 (file)
 #include "octeon-ethernet.h"
 #include "ethernet-util.h"
 
-#include "cvmx-helper.h"
-#include "cvmx-wqe.h"
-#include "cvmx-fau.h"
-#include "cvmx-pow.h"
-#include "cvmx-pip.h"
-#include "cvmx-scratch.h"
-
-#include "cvmx-gmxx-defs.h"
+#include <asm/octeon/cvmx-helper.h>
+#include <asm/octeon/cvmx-wqe.h>
+#include <asm/octeon/cvmx-fau.h>
+#include <asm/octeon/cvmx-pow.h>
+#include <asm/octeon/cvmx-pip.h>
+#include <asm/octeon/cvmx-scratch.h>
+
+#include <asm/octeon/cvmx-gmxx-defs.h>
 
 struct cvm_napi_wrapper {
        struct napi_struct napi;
index a0743b85d54e754aa05014645f2f1e55678da7e2..9240c85ce24178e5a6d7f0199ac503f0e32af8c1 100644 (file)
@@ -24,7 +24,7 @@
  * This file may also be available under a different license from Cavium.
  * Contact Cavium Networks for more information
 *********************************************************************/
-#include "cvmx-fau.h"
+#include <asm/octeon/cvmx-fau.h>
 
 void cvm_oct_poll_controller(struct net_device *dev);
 void cvm_oct_rx_initialize(void);
index 5e148b512c97590ece781be25c61801731a18696..d3e82430eba6e081f9b19348fb8363cec41c911b 100644 (file)
@@ -35,9 +35,9 @@
 #include "octeon-ethernet.h"
 #include "ethernet-util.h"
 
-#include "cvmx-helper.h"
+#include <asm/octeon/cvmx-helper.h>
 
-#include "cvmx-gmxx-defs.h"
+#include <asm/octeon/cvmx-gmxx-defs.h>
 
 int cvm_oct_sgmii_open(struct net_device *dev)
 {
index d0e2d514968a6f864f5fbda312a854e2a1cc414c..af8d62818f13b56e05ada09aedd9f64c4d1da1f0 100644 (file)
 #include "octeon-ethernet.h"
 #include "ethernet-util.h"
 
-#include "cvmx-spi.h"
+#include <asm/octeon/cvmx-spi.h>
 
 #include <asm/octeon/cvmx-npi-defs.h>
-#include "cvmx-spxx-defs.h"
-#include "cvmx-stxx-defs.h"
+#include <asm/octeon/cvmx-spxx-defs.h>
+#include <asm/octeon/cvmx-stxx-defs.h>
 
 static int number_spi_ports;
 static int need_retrain[2] = { 0, 0 };
index 2542c37439049e8e878f29600b8d08c7f6635cd3..56d74dc2fbd5b5f3b7122371554d51647b5effb9 100644 (file)
 #include "ethernet-tx.h"
 #include "ethernet-util.h"
 
-#include "cvmx-wqe.h"
-#include "cvmx-fau.h"
-#include "cvmx-pip.h"
-#include "cvmx-pko.h"
-#include "cvmx-helper.h"
+#include <asm/octeon/cvmx-wqe.h>
+#include <asm/octeon/cvmx-fau.h>
+#include <asm/octeon/cvmx-pip.h>
+#include <asm/octeon/cvmx-pko.h>
+#include <asm/octeon/cvmx-helper.h>
 
-#include "cvmx-gmxx-defs.h"
+#include <asm/octeon/cvmx-gmxx-defs.h>
 
 #define CVM_OCT_SKB_CB(skb)    ((u64 *)((skb)->cb))
 
index 861a4b3fe8576db59088fe0d4f8191a6c43f80b4..419f8c34ecdf1cbbba2a33431d827656867d64dd 100644 (file)
@@ -35,9 +35,9 @@
 #include "octeon-ethernet.h"
 #include "ethernet-util.h"
 
-#include "cvmx-helper.h"
+#include <asm/octeon/cvmx-helper.h>
 
-#include "cvmx-gmxx-defs.h"
+#include <asm/octeon/cvmx-gmxx-defs.h>
 
 int cvm_oct_xaui_open(struct net_device *dev)
 {
index 076f86675ce68878d61acae0271ff76f0c380186..9112cd8821540f692acfd5559183ad125459f73c 100644 (file)
 #include "ethernet-mdio.h"
 #include "ethernet-util.h"
 
-#include "cvmx-pip.h"
-#include "cvmx-pko.h"
-#include "cvmx-fau.h"
-#include "cvmx-ipd.h"
-#include "cvmx-helper.h"
-
-#include "cvmx-gmxx-defs.h"
-#include "cvmx-smix-defs.h"
+#include <asm/octeon/cvmx-pip.h>
+#include <asm/octeon/cvmx-pko.h>
+#include <asm/octeon/cvmx-fau.h>
+#include <asm/octeon/cvmx-ipd.h>
+#include <asm/octeon/cvmx-helper.h>
+
+#include <asm/octeon/cvmx-gmxx-defs.h>
+#include <asm/octeon/cvmx-smix-defs.h>
 
 #if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) \
        && CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS
index 02fafecd47738a23dc9bf40de76e59b374653e4b..897a3a99c794466ef636a1691f15ffeb719579b8 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/usb/serial.h>
 #include <linux/uaccess.h>
 
-static int debug;
+static bool debug;
 
 /* Version Information */
 #define DRIVER_VERSION "v2.00"
index c44e41af28809ae0e7963e4a2c264c281053b7ff..1c5780f1571b3defb1b8b6d49245de70bf0fdeea 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/usb/serial.h>
 #include <linux/uaccess.h>
 
-static int debug;
+static bool debug;
 
 /* Version Information */
 #define DRIVER_VERSION "v2.14"
index 412b87947f667e3bd7e530a0c607b8894107b551..e66579e6147a5faa063ca0b0d74204b20e7de2a0 100644 (file)
@@ -116,7 +116,7 @@ extern int bleep_time, bell_pos;
 extern int spell_delay, key_echo;
 extern short punc_mask;
 extern short pitch_shift, synth_flags;
-extern int quiet_boot;
+extern bool quiet_boot;
 extern char *synth_name;
 extern struct bleep unprocessed_sound;
 
index c241074a4b5e7104c3516928851a4e3ca9e39d1a..2222d6919ef58d820afbee1ef4ab97307771527d 100644 (file)
@@ -22,7 +22,7 @@ static struct spk_synth *synths[MAXSYNTHS];
 struct spk_synth *synth;
 char pitch_buff[32] = "";
 static int module_status;
-int quiet_boot;
+bool quiet_boot;
 
 struct speakup_info_t speakup_info = {
        .spinlock = __SPIN_LOCK_UNLOCKED(speakup_info.spinlock),
index 08a449b4abf9d11f694feb2bcb5b176ca8f39e35..f50582169b244caf21d0b9aede30b125b951b142 100644 (file)
@@ -41,7 +41,7 @@ static void __exit tsi148_exit(void);
 
 
 /* Module parameter */
-static int err_chk;
+static bool err_chk;
 static int geoid;
 
 static const char driver_name[] = "vme_tsi148";
index 8599545cdf9e6d6c90a07510844f6290ab0a1be6..ac44af165b275ab35ea572abff39b5578d41ae53 100644 (file)
@@ -27,8 +27,7 @@
 #include <scsi/scsi_device.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
-#include <target/target_core_tmr.h>
-#include <target/target_core_transport.h>
+#include <target/target_core_fabric.h>
 
 #include "iscsi_target_core.h"
 #include "iscsi_target_parameters.h"
@@ -284,8 +283,8 @@ static struct iscsi_np *iscsit_get_np(
                        sock_in6 = (struct sockaddr_in6 *)sockaddr;
                        sock_in6_e = (struct sockaddr_in6 *)&np->np_sockaddr;
 
-                       if (!memcmp((void *)&sock_in6->sin6_addr.in6_u,
-                                   (void *)&sock_in6_e->sin6_addr.in6_u,
+                       if (!memcmp(&sock_in6->sin6_addr.in6_u,
+                                   &sock_in6_e->sin6_addr.in6_u,
                                    sizeof(struct in6_addr)))
                                ip_match = 1;
 
@@ -1225,7 +1224,7 @@ static void iscsit_do_crypto_hash_buf(
 
        crypto_hash_init(hash);
 
-       sg_init_one(&sg, (u8 *)buf, payload_length);
+       sg_init_one(&sg, buf, payload_length);
        crypto_hash_update(hash, &sg, payload_length);
 
        if (padding) {
@@ -1603,7 +1602,7 @@ static int iscsit_handle_nop_out(
                /*
                 * Attach ping data to struct iscsi_cmd->buf_ptr.
                 */
-               cmd->buf_ptr = (void *)ping_data;
+               cmd->buf_ptr = ping_data;
                cmd->buf_ptr_size = payload_length;
 
                pr_debug("Got %u bytes of NOPOUT ping"
@@ -3197,7 +3196,7 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
                        end_of_buf = 1;
                        goto eob;
                }
-               memcpy((void *)payload + payload_len, buf, len);
+               memcpy(payload + payload_len, buf, len);
                payload_len += len;
 
                spin_lock(&tiqn->tiqn_tpg_lock);
@@ -3229,7 +3228,7 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
                                        end_of_buf = 1;
                                        goto eob;
                                }
-                               memcpy((void *)payload + payload_len, buf, len);
+                               memcpy(payload + payload_len, buf, len);
                                payload_len += len;
                        }
                        spin_unlock(&tpg->tpg_np_lock);
@@ -3486,7 +3485,7 @@ int iscsi_target_tx_thread(void *arg)
        struct iscsi_conn *conn;
        struct iscsi_queue_req *qr = NULL;
        struct se_cmd *se_cmd;
-       struct iscsi_thread_set *ts = (struct iscsi_thread_set *)arg;
+       struct iscsi_thread_set *ts = arg;
        /*
         * Allow ourselves to be interrupted by SIGINT so that a
         * connection recovery / failure event can be triggered externally.
@@ -3775,7 +3774,7 @@ int iscsi_target_rx_thread(void *arg)
        u8 buffer[ISCSI_HDR_LEN], opcode;
        u32 checksum = 0, digest = 0;
        struct iscsi_conn *conn = NULL;
-       struct iscsi_thread_set *ts = (struct iscsi_thread_set *)arg;
+       struct iscsi_thread_set *ts = arg;
        struct kvec iov;
        /*
         * Allow ourselves to be interrupted by SIGINT so that a
index 1cd6ce373b83508fd396f82b80290b91372c9e96..db0cf7c8adde04db2b272660a6047297fa848a78 100644 (file)
@@ -82,7 +82,7 @@ static void chap_gen_challenge(
        unsigned int *c_len)
 {
        unsigned char challenge_asciihex[CHAP_CHALLENGE_LENGTH * 2 + 1];
-       struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol;
+       struct iscsi_chap *chap = conn->auth_protocol;
 
        memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1);
 
@@ -120,7 +120,7 @@ static struct iscsi_chap *chap_server_open(
        if (!conn->auth_protocol)
                return NULL;
 
-       chap = (struct iscsi_chap *) conn->auth_protocol;
+       chap = conn->auth_protocol;
        /*
         * We only support MD5 MDA presently.
         */
@@ -165,14 +165,15 @@ static int chap_server_compute_md5(
        unsigned int *nr_out_len)
 {
        char *endptr;
-       unsigned char id, digest[MD5_SIGNATURE_SIZE];
+       unsigned long id;
+       unsigned char digest[MD5_SIGNATURE_SIZE];
        unsigned char type, response[MD5_SIGNATURE_SIZE * 2 + 2];
        unsigned char identifier[10], *challenge = NULL;
        unsigned char *challenge_binhex = NULL;
        unsigned char client_digest[MD5_SIGNATURE_SIZE];
        unsigned char server_digest[MD5_SIGNATURE_SIZE];
        unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH];
-       struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol;
+       struct iscsi_chap *chap = conn->auth_protocol;
        struct crypto_hash *tfm;
        struct hash_desc desc;
        struct scatterlist sg;
@@ -246,7 +247,7 @@ static int chap_server_compute_md5(
                goto out;
        }
 
-       sg_init_one(&sg, (void *)&chap->id, 1);
+       sg_init_one(&sg, &chap->id, 1);
        ret = crypto_hash_update(&desc, &sg, 1);
        if (ret < 0) {
                pr_err("crypto_hash_update() failed for id\n");
@@ -254,7 +255,7 @@ static int chap_server_compute_md5(
                goto out;
        }
 
-       sg_init_one(&sg, (void *)&auth->password, strlen(auth->password));
+       sg_init_one(&sg, &auth->password, strlen(auth->password));
        ret = crypto_hash_update(&desc, &sg, strlen(auth->password));
        if (ret < 0) {
                pr_err("crypto_hash_update() failed for password\n");
@@ -262,7 +263,7 @@ static int chap_server_compute_md5(
                goto out;
        }
 
-       sg_init_one(&sg, (void *)chap->challenge, CHAP_CHALLENGE_LENGTH);
+       sg_init_one(&sg, chap->challenge, CHAP_CHALLENGE_LENGTH);
        ret = crypto_hash_update(&desc, &sg, CHAP_CHALLENGE_LENGTH);
        if (ret < 0) {
                pr_err("crypto_hash_update() failed for challenge\n");
@@ -305,14 +306,17 @@ static int chap_server_compute_md5(
        }
 
        if (type == HEX)
-               id = (unsigned char)simple_strtoul((char *)&identifier[2],
-                                       &endptr, 0);
+               id = simple_strtoul(&identifier[2], &endptr, 0);
        else
-               id = (unsigned char)simple_strtoul(identifier, &endptr, 0);
+               id = simple_strtoul(identifier, &endptr, 0);
+       if (id > 255) {
+               pr_err("chap identifier: %lu greater than 255\n", id);
+               goto out;
+       }
        /*
         * RFC 1994 says Identifier is no more than octet (8 bits).
         */
-       pr_debug("[server] Got CHAP_I=%d\n", id);
+       pr_debug("[server] Got CHAP_I=%lu\n", id);
        /*
         * Get CHAP_C.
         */
@@ -351,7 +355,7 @@ static int chap_server_compute_md5(
                goto out;
        }
 
-       sg_init_one(&sg, (void *)&id, 1);
+       sg_init_one(&sg, &id, 1);
        ret = crypto_hash_update(&desc, &sg, 1);
        if (ret < 0) {
                pr_err("crypto_hash_update() failed for id\n");
@@ -359,7 +363,7 @@ static int chap_server_compute_md5(
                goto out;
        }
 
-       sg_init_one(&sg, (void *)auth->password_mutual,
+       sg_init_one(&sg, auth->password_mutual,
                                strlen(auth->password_mutual));
        ret = crypto_hash_update(&desc, &sg, strlen(auth->password_mutual));
        if (ret < 0) {
@@ -371,7 +375,7 @@ static int chap_server_compute_md5(
        /*
         * Convert received challenge to binary hex.
         */
-       sg_init_one(&sg, (void *)challenge_binhex, challenge_len);
+       sg_init_one(&sg, challenge_binhex, challenge_len);
        ret = crypto_hash_update(&desc, &sg, challenge_len);
        if (ret < 0) {
                pr_err("crypto_hash_update() failed for ma challenge\n");
@@ -414,7 +418,7 @@ static int chap_got_response(
        char *nr_out_ptr,
        unsigned int *nr_out_len)
 {
-       struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol;
+       struct iscsi_chap *chap = conn->auth_protocol;
 
        switch (chap->digest_type) {
        case CHAP_DIGEST_MD5:
@@ -437,7 +441,7 @@ u32 chap_main_loop(
        int *in_len,
        int *out_len)
 {
-       struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol;
+       struct iscsi_chap *chap = conn->auth_protocol;
 
        if (!chap) {
                chap = chap_server_open(conn, auth, in_text, out_text, out_len);
index db327845e46b46fc04d6f2be7a21d68d9aa53d53..3468caab47a24f494d99247c109780f7f9218785 100644 (file)
 #include <linux/configfs.h>
 #include <linux/export.h>
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_fabric_configfs.h>
-#include <target/target_core_fabric_lib.h>
-#include <target/target_core_device.h>
-#include <target/target_core_tpg.h>
 #include <target/target_core_configfs.h>
 #include <target/configfs_macros.h>
 
@@ -56,8 +52,7 @@ struct iscsi_portal_group *lio_get_tpg_from_tpg_item(
 {
        struct se_portal_group *se_tpg = container_of(to_config_group(item),
                                        struct se_portal_group, tpg_group);
-       struct iscsi_portal_group *tpg =
-                       (struct iscsi_portal_group *)se_tpg->se_tpg_fabric_ptr;
+       struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
        int ret;
 
        if (!tpg) {
@@ -1225,7 +1220,7 @@ struct se_portal_group *lio_target_tiqn_addtpg(
 
        ret = core_tpg_register(
                        &lio_target_fabric_configfs->tf_ops,
-                       wwn, &tpg->tpg_se_tpg, (void *)tpg,
+                       wwn, &tpg->tpg_se_tpg, tpg,
                        TRANSPORT_TPG_TYPE_NORMAL);
        if (ret < 0)
                return NULL;
index a19fa5eea88e8edcd3db9ab57bc399ad150dd15d..f63ea35bc4ae7737c7ad16b443b2a6ea9c017e2e 100644 (file)
@@ -21,8 +21,7 @@
 
 #include <scsi/scsi_device.h>
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_transport.h>
+#include <target/target_core_fabric.h>
 
 #include "iscsi_target_core.h"
 #include "iscsi_target_device.h"
index b7ffc3cd40cca0141ac02441894a1bd018fc2f0e..478451167b62b4c1b3b443e08b1bb6c06ff10cad 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
+#include <target/target_core_fabric.h>
 
 #include "iscsi_target_core.h"
 #include "iscsi_target_seq_pdu_list.h"
index 101b1beb3bca205aed7611ec4424f54cc5b20671..255c0d67e8983d00894e8a348f84d7dffc0367db 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/list.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
+#include <target/target_core_fabric.h>
 
 #include "iscsi_target_core.h"
 #include "iscsi_target_seq_pdu_list.h"
index 0b8404c30125256a99bff82082516c324ff16364..1af1f21af21fd01735eab9cec3f2369246e69bd4 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
+#include <target/target_core_fabric.h>
 
 #include "iscsi_target_core.h"
 #include "iscsi_target_datain_values.h"
index d734bdec24f9cf2b451a7f905b07fab421a19b3b..373b0cc6abd8d8a10def91be9ba6328f96fc67dd 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/crypto.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
+#include <target/target_core_fabric.h>
 
 #include "iscsi_target_core.h"
 #include "iscsi_target_tq.h"
@@ -143,7 +143,7 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)
        list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list,
                        sess_list) {
 
-               sess_p = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               sess_p = se_sess->fabric_sess_ptr;
                spin_lock(&sess_p->conn_lock);
                if (atomic_read(&sess_p->session_fall_back_to_erl0) ||
                    atomic_read(&sess_p->session_logout) ||
@@ -151,9 +151,9 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)
                        spin_unlock(&sess_p->conn_lock);
                        continue;
                }
-               if (!memcmp((void *)sess_p->isid, (void *)conn->sess->isid, 6) &&
-                  (!strcmp((void *)sess_p->sess_ops->InitiatorName,
-                           (void *)initiatorname_param->value) &&
+               if (!memcmp(sess_p->isid, conn->sess->isid, 6) &&
+                  (!strcmp(sess_p->sess_ops->InitiatorName,
+                           initiatorname_param->value) &&
                   (sess_p->sess_ops->SessionType == sessiontype))) {
                        atomic_set(&sess_p->session_reinstatement, 1);
                        spin_unlock(&sess_p->conn_lock);
@@ -229,7 +229,7 @@ static int iscsi_login_zero_tsih_s1(
 
        iscsi_login_set_conn_values(sess, conn, pdu->cid);
        sess->init_task_tag     = pdu->itt;
-       memcpy((void *)&sess->isid, (void *)pdu->isid, 6);
+       memcpy(&sess->isid, pdu->isid, 6);
        sess->exp_cmd_sn        = pdu->cmdsn;
        INIT_LIST_HEAD(&sess->sess_conn_list);
        INIT_LIST_HEAD(&sess->sess_ooo_cmdsn_list);
@@ -440,8 +440,7 @@ static int iscsi_login_non_zero_tsih_s2(
                    atomic_read(&sess_p->session_logout) ||
                   (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED))
                        continue;
-               if (!memcmp((const void *)sess_p->isid,
-                    (const void *)pdu->isid, 6) &&
+               if (!memcmp(sess_p->isid, pdu->isid, 6) &&
                     (sess_p->tsih == pdu->tsih)) {
                        iscsit_inc_session_usage_count(sess_p);
                        iscsit_stop_time2retain_timer(sess_p);
@@ -654,7 +653,7 @@ static int iscsi_post_login_handler(
 
        spin_lock_bh(&se_tpg->session_lock);
        __transport_register_session(&sess->tpg->tpg_se_tpg,
-                       se_sess->se_node_acl, se_sess, (void *)sess);
+                       se_sess->se_node_acl, se_sess, sess);
        pr_debug("Moving to TARG_SESS_STATE_LOGGED_IN.\n");
        sess->session_state = TARG_SESS_STATE_LOGGED_IN;
 
@@ -811,7 +810,7 @@ int iscsi_target_setup_login_socket(
         * Setup the np->np_sockaddr from the passed sockaddr setup
         * in iscsi_target_configfs.c code..
         */
-       memcpy((void *)&np->np_sockaddr, (void *)sockaddr,
+       memcpy(&np->np_sockaddr, sockaddr,
                        sizeof(struct __kernel_sockaddr_storage));
 
        if (sockaddr->ss_family == AF_INET6)
@@ -821,6 +820,7 @@ int iscsi_target_setup_login_socket(
        /*
         * Set SO_REUSEADDR, and disable Nagel Algorithm with TCP_NODELAY.
         */
+       /* FIXME: Someone please explain why this is endian-safe */
        opt = 1;
        if (np->np_network_transport == ISCSI_TCP) {
                ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
@@ -832,6 +832,7 @@ int iscsi_target_setup_login_socket(
                }
        }
 
+       /* FIXME: Someone please explain why this is endian-safe */
        ret = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                        (char *)&opt, sizeof(opt));
        if (ret < 0) {
@@ -1206,7 +1207,7 @@ out:
 
 int iscsi_target_login_thread(void *arg)
 {
-       struct iscsi_np *np = (struct iscsi_np *)arg;
+       struct iscsi_np *np = arg;
        int ret;
 
        allow_signal(SIGINT);
index 98936cb7c2947ceb0edbaa41dda91d6641a9b892..e89fa7457254d6f44fde426dceaab84de0a99fa2 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/ctype.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
-#include <target/target_core_tpg.h>
+#include <target/target_core_fabric.h>
 
 #include "iscsi_target_core.h"
 #include "iscsi_target_parameters.h"
@@ -732,7 +732,7 @@ static void iscsi_initiatorname_tolower(
        u32 iqn_size = strlen(param_buf), i;
 
        for (i = 0; i < iqn_size; i++) {
-               c = (char *)&param_buf[i];
+               c = &param_buf[i];
                if (!isupper(*c))
                        continue;
 
index aeafbe0cd7d11b294053f1424e5d91cb3c7336ac..b3c699c4fe8ceb8b9dc2fe35a3eb0e94abfc1126 100644 (file)
@@ -19,7 +19,6 @@
  ******************************************************************************/
 
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
 
 #include "iscsi_target_core.h"
 #include "iscsi_target_device.h"
@@ -135,7 +134,7 @@ extern int iscsit_na_nopin_timeout(
                spin_lock_bh(&se_nacl->nacl_sess_lock);
                se_sess = se_nacl->nacl_sess;
                if (se_sess) {
-                       sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+                       sess = se_sess->fabric_sess_ptr;
 
                        spin_lock(&sess->conn_lock);
                        list_for_each_entry(conn, &sess->sess_conn_list,
index f1db83077e0a8418d448a7d9b210cc63014b1d3c..421d6947dc64247c2bc02a1136f8bb2e0489c64a 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/export.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
 #include <target/configfs_macros.h>
 
 #include "iscsi_target_core.h"
@@ -746,7 +745,7 @@ static ssize_t iscsi_stat_sess_show_attr_node(
        spin_lock_bh(&se_nacl->nacl_sess_lock);
        se_sess = se_nacl->nacl_sess;
        if (se_sess) {
-               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               sess = se_sess->fabric_sess_ptr;
                if (sess)
                        ret = snprintf(page, PAGE_SIZE, "%u\n",
                                sess->sess_ops->SessionType ? 0 : ISCSI_NODE_INDEX);
@@ -770,7 +769,7 @@ static ssize_t iscsi_stat_sess_show_attr_indx(
        spin_lock_bh(&se_nacl->nacl_sess_lock);
        se_sess = se_nacl->nacl_sess;
        if (se_sess) {
-               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               sess = se_sess->fabric_sess_ptr;
                if (sess)
                        ret = snprintf(page, PAGE_SIZE, "%u\n",
                                        sess->session_index);
@@ -794,7 +793,7 @@ static ssize_t iscsi_stat_sess_show_attr_cmd_pdus(
        spin_lock_bh(&se_nacl->nacl_sess_lock);
        se_sess = se_nacl->nacl_sess;
        if (se_sess) {
-               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               sess = se_sess->fabric_sess_ptr;
                if (sess)
                        ret = snprintf(page, PAGE_SIZE, "%u\n", sess->cmd_pdus);
        }
@@ -817,7 +816,7 @@ static ssize_t iscsi_stat_sess_show_attr_rsp_pdus(
        spin_lock_bh(&se_nacl->nacl_sess_lock);
        se_sess = se_nacl->nacl_sess;
        if (se_sess) {
-               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               sess = se_sess->fabric_sess_ptr;
                if (sess)
                        ret = snprintf(page, PAGE_SIZE, "%u\n", sess->rsp_pdus);
        }
@@ -840,7 +839,7 @@ static ssize_t iscsi_stat_sess_show_attr_txdata_octs(
        spin_lock_bh(&se_nacl->nacl_sess_lock);
        se_sess = se_nacl->nacl_sess;
        if (se_sess) {
-               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               sess = se_sess->fabric_sess_ptr;
                if (sess)
                        ret = snprintf(page, PAGE_SIZE, "%llu\n",
                                (unsigned long long)sess->tx_data_octets);
@@ -864,7 +863,7 @@ static ssize_t iscsi_stat_sess_show_attr_rxdata_octs(
        spin_lock_bh(&se_nacl->nacl_sess_lock);
        se_sess = se_nacl->nacl_sess;
        if (se_sess) {
-               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               sess = se_sess->fabric_sess_ptr;
                if (sess)
                        ret = snprintf(page, PAGE_SIZE, "%llu\n",
                                (unsigned long long)sess->rx_data_octets);
@@ -888,7 +887,7 @@ static ssize_t iscsi_stat_sess_show_attr_conn_digest_errors(
        spin_lock_bh(&se_nacl->nacl_sess_lock);
        se_sess = se_nacl->nacl_sess;
        if (se_sess) {
-               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               sess = se_sess->fabric_sess_ptr;
                if (sess)
                        ret = snprintf(page, PAGE_SIZE, "%u\n",
                                        sess->conn_digest_errors);
@@ -912,7 +911,7 @@ static ssize_t iscsi_stat_sess_show_attr_conn_timeout_errors(
        spin_lock_bh(&se_nacl->nacl_sess_lock);
        se_sess = se_nacl->nacl_sess;
        if (se_sess) {
-               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               sess = se_sess->fabric_sess_ptr;
                if (sess)
                        ret = snprintf(page, PAGE_SIZE, "%u\n",
                                        sess->conn_timeout_errors);
index 490207eacde976a179f1197d21f3901afd1c78e0..255ed35da815e3059c1930683255575b51ff58d7 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/unaligned.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
+#include <target/target_core_fabric.h>
 
 #include "iscsi_target_core.h"
 #include "iscsi_target_seq_pdu_list.h"
index d4cf2cd25c447f8ac109f7dcdc20fca572d96abc..879d8d0fa3feb38e061c911887e50a91a286c30f 100644 (file)
  ******************************************************************************/
 
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_configfs.h>
-#include <target/target_core_tpg.h>
 
 #include "iscsi_target_core.h"
 #include "iscsi_target_erl0.h"
@@ -72,7 +70,7 @@ int iscsit_load_discovery_tpg(void)
 
        ret = core_tpg_register(
                        &lio_target_fabric_configfs->tf_ops,
-                       NULL, &tpg->tpg_se_tpg, (void *)tpg,
+                       NULL, &tpg->tpg_se_tpg, tpg,
                        TRANSPORT_TPG_TYPE_DISCOVERY);
        if (ret < 0) {
                kfree(tpg);
index 02348f727bd4ddaaa4ef4b70e3499fc135001dad..a05ca1c4f01c3c724992f07baa2a7505977b94f2 100644 (file)
@@ -22,9 +22,7 @@
 #include <scsi/scsi_tcq.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_tmr.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_configfs.h>
 
 #include "iscsi_target_core.h"
@@ -289,7 +287,7 @@ struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr(
        }
 
        se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd,
-                               (void *)cmd->tmr_req, tcm_function,
+                               cmd->tmr_req, tcm_function,
                                GFP_KERNEL);
        if (!se_cmd->se_tmr_req)
                goto out;
@@ -1066,7 +1064,7 @@ static void iscsit_handle_nopin_response_timeout(unsigned long data)
        if (tiqn) {
                spin_lock_bh(&tiqn->sess_err_stats.lock);
                strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name,
-                               (void *)conn->sess->sess_ops->InitiatorName);
+                               conn->sess->sess_ops->InitiatorName);
                tiqn->sess_err_stats.last_sess_failure_type =
                                ISCSI_SESS_ERR_CXN_TIMEOUT;
                tiqn->sess_err_stats.cxn_timeout_errors++;
index 81d5832fbbd537e7bbffe2c21b1792c1e7a2acde..c47ff7f59e5733226702004617327a28b566f7f1 100644 (file)
 #include <scsi/scsi_cmnd.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_fabric_configfs.h>
-#include <target/target_core_fabric_lib.h>
 #include <target/target_core_configfs.h>
-#include <target/target_core_device.h>
-#include <target/target_core_tpg.h>
-#include <target/target_core_tmr.h>
 
 #include "tcm_loop.h"
 
@@ -421,11 +416,11 @@ static struct scsi_host_template tcm_loop_driver_template = {
        .queuecommand           = tcm_loop_queuecommand,
        .change_queue_depth     = tcm_loop_change_queue_depth,
        .eh_device_reset_handler = tcm_loop_device_reset,
-       .can_queue              = TL_SCSI_CAN_QUEUE,
+       .can_queue              = 1024,
        .this_id                = -1,
-       .sg_tablesize           = TL_SCSI_SG_TABLESIZE,
-       .cmd_per_lun            = TL_SCSI_CMD_PER_LUN,
-       .max_sectors            = TL_SCSI_MAX_SECTORS,
+       .sg_tablesize           = 256,
+       .cmd_per_lun            = 1024,
+       .max_sectors            = 0xFFFF,
        .use_clustering         = DISABLE_CLUSTERING,
        .slave_alloc            = tcm_loop_slave_alloc,
        .slave_configure        = tcm_loop_slave_configure,
@@ -564,8 +559,7 @@ static char *tcm_loop_get_fabric_name(void)
 
 static u8 tcm_loop_get_fabric_proto_ident(struct se_portal_group *se_tpg)
 {
-       struct tcm_loop_tpg *tl_tpg =
-                       (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr;
+       struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr;
        struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
        /*
         * tl_proto_id is set at tcm_loop_configfs.c:tcm_loop_make_scsi_hba()
@@ -592,8 +586,7 @@ static u8 tcm_loop_get_fabric_proto_ident(struct se_portal_group *se_tpg)
 
 static char *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg)
 {
-       struct tcm_loop_tpg *tl_tpg =
-               (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr;
+       struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr;
        /*
         * Return the passed NAA identifier for the SAS Target Port
         */
@@ -602,8 +595,7 @@ static char *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg)
 
 static u16 tcm_loop_get_tag(struct se_portal_group *se_tpg)
 {
-       struct tcm_loop_tpg *tl_tpg =
-               (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr;
+       struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr;
        /*
         * This Tag is used when forming SCSI Name identifier in EVPD=1 0x83
         * to represent the SCSI Target Port.
@@ -623,8 +615,7 @@ static u32 tcm_loop_get_pr_transport_id(
        int *format_code,
        unsigned char *buf)
 {
-       struct tcm_loop_tpg *tl_tpg =
-                       (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr;
+       struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr;
        struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
 
        switch (tl_hba->tl_proto_id) {
@@ -653,8 +644,7 @@ static u32 tcm_loop_get_pr_transport_id_len(
        struct t10_pr_registration *pr_reg,
        int *format_code)
 {
-       struct tcm_loop_tpg *tl_tpg =
-                       (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr;
+       struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr;
        struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
 
        switch (tl_hba->tl_proto_id) {
@@ -687,8 +677,7 @@ static char *tcm_loop_parse_pr_out_transport_id(
        u32 *out_tid_len,
        char **port_nexus_ptr)
 {
-       struct tcm_loop_tpg *tl_tpg =
-                       (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr;
+       struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr;
        struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
 
        switch (tl_hba->tl_proto_id) {
index 6b76c7a22bb062fa692a89e89d903b747e67e157..15a036441471d3aca51624e903ea19f8b7ca8941 100644 (file)
@@ -1,16 +1,7 @@
 #define TCM_LOOP_VERSION               "v2.1-rc1"
 #define TL_WWN_ADDR_LEN                        256
 #define TL_TPGS_PER_HBA                        32
-/*
- * Defaults for struct scsi_host_template tcm_loop_driver_template
- *
- * We use large can_queue and cmd_per_lun here and let TCM enforce
- * the underlying se_device_t->queue_depth.
- */
-#define TL_SCSI_CAN_QUEUE              1024
-#define TL_SCSI_CMD_PER_LUN            1024
-#define TL_SCSI_MAX_SECTORS            1024
-#define TL_SCSI_SG_TABLESIZE           256
+
 /*
  * Used in tcm_loop_driver_probe() for struct Scsi_Host->max_cmd_len
  */
index 1dcbef499d6a09f2add951dee10c955f3541ccb8..1b1edd14f4bff4629427725a19239508d8ee2279 100644 (file)
 #include <scsi/scsi_cmnd.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_configfs.h>
 
+#include "target_core_internal.h"
 #include "target_core_alua.h"
-#include "target_core_hba.h"
 #include "target_core_ua.h"
 
 static int core_alua_check_transition(int state, int *primary);
index 831468b3163d777f3eb5c982fc05819d37dea3e6..2f2235edefffce7f99873b0bd4ece1ce87ebe6e7 100644 (file)
 #include <scsi/scsi.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
+
+#include "target_core_internal.h"
 #include "target_core_ua.h"
-#include "target_core_cdb.h"
 
 static void
 target_fill_alua_data(struct se_port *port, unsigned char *buf)
@@ -93,6 +94,18 @@ target_emulate_inquiry_std(struct se_cmd *cmd)
        }
        buf[2] = dev->transport->get_device_rev(dev);
 
+       /*
+        * NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2
+        *
+        * SPC4 says:
+        *   A RESPONSE DATA FORMAT field set to 2h indicates that the
+        *   standard INQUIRY data is in the format defined in this
+        *   standard. Response data format values less than 2h are
+        *   obsolete. Response data format values greater than 2h are
+        *   reserved.
+        */
+       buf[3] = 2;
+
        /*
         * Enable SCCS and TPGS fields for Emulated ALUA
         */
@@ -115,11 +128,9 @@ target_emulate_inquiry_std(struct se_cmd *cmd)
                goto out;
        }
 
-       snprintf((unsigned char *)&buf[8], 8, "LIO-ORG");
-       snprintf((unsigned char *)&buf[16], 16, "%s",
-                &dev->se_sub_dev->t10_wwn.model[0]);
-       snprintf((unsigned char *)&buf[32], 4, "%s",
-                &dev->se_sub_dev->t10_wwn.revision[0]);
+       snprintf(&buf[8], 8, "LIO-ORG");
+       snprintf(&buf[16], 16, "%s", dev->se_sub_dev->t10_wwn.model);
+       snprintf(&buf[32], 4, "%s", dev->se_sub_dev->t10_wwn.revision);
        buf[4] = 31; /* Set additional length to 31 */
 
 out:
@@ -138,8 +149,7 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
                        SDF_EMULATED_VPD_UNIT_SERIAL) {
                u32 unit_serial_len;
 
-               unit_serial_len =
-                       strlen(&dev->se_sub_dev->t10_wwn.unit_serial[0]);
+               unit_serial_len = strlen(dev->se_sub_dev->t10_wwn.unit_serial);
                unit_serial_len++; /* For NULL Terminator */
 
                if (((len + 4) + unit_serial_len) > cmd->data_length) {
@@ -148,8 +158,8 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
                        buf[3] = (len & 0xff);
                        return 0;
                }
-               len += sprintf((unsigned char *)&buf[4], "%s",
-                       &dev->se_sub_dev->t10_wwn.unit_serial[0]);
+               len += sprintf(&buf[4], "%s",
+                       dev->se_sub_dev->t10_wwn.unit_serial);
                len++; /* Extra Byte for NULL Terminator */
                buf[3] = len;
        }
@@ -279,14 +289,13 @@ check_t10_vend_desc:
                        len += (prod_len + unit_serial_len);
                        goto check_port;
                }
-               id_len += sprintf((unsigned char *)&buf[off+12],
-                               "%s:%s", prod,
+               id_len += sprintf(&buf[off+12], "%s:%s", prod,
                                &dev->se_sub_dev->t10_wwn.unit_serial[0]);
        }
        buf[off] = 0x2; /* ASCII */
        buf[off+1] = 0x1; /* T10 Vendor ID */
        buf[off+2] = 0x0;
-       memcpy((unsigned char *)&buf[off+4], "LIO-ORG", 8);
+       memcpy(&buf[off+4], "LIO-ORG", 8);
        /* Extra Byte for NULL Terminator */
        id_len++;
        /* Identifier Length */
diff --git a/drivers/target/target_core_cdb.h b/drivers/target/target_core_cdb.h
deleted file mode 100644 (file)
index ad6b1e3..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef TARGET_CORE_CDB_H
-#define TARGET_CORE_CDB_H
-
-int target_emulate_inquiry(struct se_task *task);
-int target_emulate_readcapacity(struct se_task *task);
-int target_emulate_readcapacity_16(struct se_task *task);
-int target_emulate_modesense(struct se_task *task);
-int target_emulate_request_sense(struct se_task *task);
-int target_emulate_unmap(struct se_task *task);
-int target_emulate_write_same(struct se_task *task);
-int target_emulate_synchronize_cache(struct se_task *task);
-int target_emulate_noop(struct se_task *task);
-
-#endif /* TARGET_CORE_CDB_H */
index 93d4f6a1b7980c597c119ae7f7f0506d57846993..0955bb8979fb6f77dc54bf500810db4c83615f91 100644 (file)
 #include <linux/spinlock.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_backend.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 "target_core_internal.h"
 #include "target_core_alua.h"
-#include "target_core_hba.h"
 #include "target_core_pr.h"
 #include "target_core_rd.h"
-#include "target_core_stat.h"
 
 extern struct t10_alua_lu_gp *default_lu_gp;
 
@@ -1452,7 +1450,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
                return -ENOMEM;
 
        orig = opts;
-       while ((ptr = strsep(&opts, ",")) != NULL) {
+       while ((ptr = strsep(&opts, ",\n")) != NULL) {
                if (!*ptr)
                        continue;
 
@@ -1631,7 +1629,7 @@ static struct config_item_type target_core_dev_pr_cit = {
 
 static ssize_t target_core_show_dev_info(void *p, char *page)
 {
-       struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+       struct se_subsystem_dev *se_dev = p;
        struct se_hba *hba = se_dev->se_dev_hba;
        struct se_subsystem_api *t = hba->transport;
        int bl = 0;
@@ -1659,7 +1657,7 @@ static ssize_t target_core_store_dev_control(
        const char *page,
        size_t count)
 {
-       struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+       struct se_subsystem_dev *se_dev = p;
        struct se_hba *hba = se_dev->se_dev_hba;
        struct se_subsystem_api *t = hba->transport;
 
@@ -1682,7 +1680,7 @@ static struct target_core_configfs_attribute target_core_attr_dev_control = {
 
 static ssize_t target_core_show_dev_alias(void *p, char *page)
 {
-       struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+       struct se_subsystem_dev *se_dev = p;
 
        if (!(se_dev->su_dev_flags & SDF_USING_ALIAS))
                return 0;
@@ -1695,7 +1693,7 @@ static ssize_t target_core_store_dev_alias(
        const char *page,
        size_t count)
 {
-       struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+       struct se_subsystem_dev *se_dev = p;
        struct se_hba *hba = se_dev->se_dev_hba;
        ssize_t read_bytes;
 
@@ -1710,6 +1708,9 @@ static ssize_t target_core_store_dev_alias(
        read_bytes = snprintf(&se_dev->se_dev_alias[0], SE_DEV_ALIAS_LEN,
                        "%s", page);
 
+       if (se_dev->se_dev_alias[read_bytes - 1] == '\n')
+               se_dev->se_dev_alias[read_bytes - 1] = '\0';
+
        pr_debug("Target_Core_ConfigFS: %s/%s set alias: %s\n",
                config_item_name(&hba->hba_group.cg_item),
                config_item_name(&se_dev->se_dev_group.cg_item),
@@ -1728,7 +1729,7 @@ static struct target_core_configfs_attribute target_core_attr_dev_alias = {
 
 static ssize_t target_core_show_dev_udev_path(void *p, char *page)
 {
-       struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+       struct se_subsystem_dev *se_dev = p;
 
        if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH))
                return 0;
@@ -1741,7 +1742,7 @@ static ssize_t target_core_store_dev_udev_path(
        const char *page,
        size_t count)
 {
-       struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+       struct se_subsystem_dev *se_dev = p;
        struct se_hba *hba = se_dev->se_dev_hba;
        ssize_t read_bytes;
 
@@ -1756,6 +1757,9 @@ static ssize_t target_core_store_dev_udev_path(
        read_bytes = snprintf(&se_dev->se_dev_udev_path[0], SE_UDEV_PATH_LEN,
                        "%s", page);
 
+       if (se_dev->se_dev_udev_path[read_bytes - 1] == '\n')
+               se_dev->se_dev_udev_path[read_bytes - 1] = '\0';
+
        pr_debug("Target_Core_ConfigFS: %s/%s set udev_path: %s\n",
                config_item_name(&hba->hba_group.cg_item),
                config_item_name(&se_dev->se_dev_group.cg_item),
@@ -1777,7 +1781,7 @@ static ssize_t target_core_store_dev_enable(
        const char *page,
        size_t count)
 {
-       struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+       struct se_subsystem_dev *se_dev = p;
        struct se_device *dev;
        struct se_hba *hba = se_dev->se_dev_hba;
        struct se_subsystem_api *t = hba->transport;
@@ -1822,7 +1826,7 @@ static struct target_core_configfs_attribute target_core_attr_dev_enable = {
 static ssize_t target_core_show_alua_lu_gp(void *p, char *page)
 {
        struct se_device *dev;
-       struct se_subsystem_dev *su_dev = (struct se_subsystem_dev *)p;
+       struct se_subsystem_dev *su_dev = p;
        struct config_item *lu_ci;
        struct t10_alua_lu_gp *lu_gp;
        struct t10_alua_lu_gp_member *lu_gp_mem;
@@ -1860,7 +1864,7 @@ static ssize_t target_core_store_alua_lu_gp(
        size_t count)
 {
        struct se_device *dev;
-       struct se_subsystem_dev *su_dev = (struct se_subsystem_dev *)p;
+       struct se_subsystem_dev *su_dev = p;
        struct se_hba *hba = su_dev->se_dev_hba;
        struct t10_alua_lu_gp *lu_gp = NULL, *lu_gp_new = NULL;
        struct t10_alua_lu_gp_member *lu_gp_mem;
index 9b8639425472d8322aab749c6ae03fb56ea2a377..0c5992f0d9469cd1c34f63ef22296aa7519498e8 100644 (file)
 #include <scsi/scsi_device.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_tpg.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
 
+#include "target_core_internal.h"
 #include "target_core_alua.h"
-#include "target_core_hba.h"
 #include "target_core_pr.h"
 #include "target_core_ua.h"
 
@@ -1134,8 +1132,6 @@ int se_dev_set_emulate_rest_reord(struct se_device *dev, int flag)
  */
 int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth)
 {
-       u32 orig_queue_depth = dev->queue_depth;
-
        if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
                pr_err("dev[%p]: Unable to change SE Device TCQ while"
                        " dev_export_obj: %d count exists\n", dev,
@@ -1169,11 +1165,6 @@ int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth)
        }
 
        dev->se_sub_dev->se_dev_attrib.queue_depth = dev->queue_depth = queue_depth;
-       if (queue_depth > orig_queue_depth)
-               atomic_add(queue_depth - orig_queue_depth, &dev->depth_left);
-       else if (queue_depth < orig_queue_depth)
-               atomic_sub(orig_queue_depth - queue_depth, &dev->depth_left);
-
        pr_debug("dev[%p]: SE Device TCQ Depth changed to: %u\n",
                        dev, queue_depth);
        return 0;
index 09b6f8729f918edbcd913770ef73c16485594839..4f77cce22646df958e05c7cf66d37be813f4757f 100644 (file)
 #include <linux/configfs.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_tpg.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.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 "target_core_internal.h"
 #include "target_core_alua.h"
-#include "target_core_hba.h"
 #include "target_core_pr.h"
-#include "target_core_stat.h"
 
 #define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs)             \
 static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \
index ec4249be617e348aaed580cfa027df1fc5174bbf..283a36e464e65ee5e55e9dded0037262a8203a9a 100644 (file)
 #include <scsi/scsi_cmnd.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_lib.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_configfs.h>
 
-#include "target_core_hba.h"
+#include "target_core_internal.h"
 #include "target_core_pr.h"
 
 /*
@@ -402,7 +399,7 @@ char *iscsi_parse_pr_out_transport_id(
                add_len = ((buf[2] >> 8) & 0xff);
                add_len |= (buf[3] & 0xff);
 
-               tid_len = strlen((char *)&buf[4]);
+               tid_len = strlen(&buf[4]);
                tid_len += 4; /* Add four bytes for iSCSI Transport ID header */
                tid_len += 1; /* Add one byte for NULL terminator */
                padding = ((-tid_len) & 3);
@@ -423,11 +420,11 @@ char *iscsi_parse_pr_out_transport_id(
         * format.
         */
        if (format_code == 0x40) {
-               p = strstr((char *)&buf[4], ",i,0x");
+               p = strstr(&buf[4], ",i,0x");
                if (!p) {
                        pr_err("Unable to locate \",i,0x\" seperator"
                                " for Initiator port identifier: %s\n",
-                               (char *)&buf[4]);
+                               &buf[4]);
                        return NULL;
                }
                *p = '\0'; /* Terminate iSCSI Name */
index b4864fba4ef0d511758916a8debac60ee9f43674..7ed58e2df7914176cb8c9bd8e8bad187b5218131 100644 (file)
@@ -37,8 +37,7 @@
 #include <scsi/scsi_host.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_transport.h>
+#include <target/target_core_backend.h>
 
 #include "target_core_file.h"
 
@@ -86,7 +85,7 @@ static void fd_detach_hba(struct se_hba *hba)
 static void *fd_allocate_virtdevice(struct se_hba *hba, const char *name)
 {
        struct fd_dev *fd_dev;
-       struct fd_host *fd_host = (struct fd_host *) hba->hba_ptr;
+       struct fd_host *fd_host = hba->hba_ptr;
 
        fd_dev = kzalloc(sizeof(struct fd_dev), GFP_KERNEL);
        if (!fd_dev) {
@@ -114,8 +113,8 @@ static struct se_device *fd_create_virtdevice(
        struct se_device *dev;
        struct se_dev_limits dev_limits;
        struct queue_limits *limits;
-       struct fd_dev *fd_dev = (struct fd_dev *) p;
-       struct fd_host *fd_host = (struct fd_host *) hba->hba_ptr;
+       struct fd_dev *fd_dev = p;
+       struct fd_host *fd_host = hba->hba_ptr;
        mm_segment_t old_fs;
        struct file *file;
        struct inode *inode = NULL;
@@ -240,7 +239,7 @@ fail:
  */
 static void fd_free_device(void *p)
 {
-       struct fd_dev *fd_dev = (struct fd_dev *) p;
+       struct fd_dev *fd_dev = p;
 
        if (fd_dev->fd_file) {
                filp_close(fd_dev->fd_file, NULL);
@@ -498,7 +497,7 @@ static ssize_t fd_set_configfs_dev_params(
 
        orig = opts;
 
-       while ((ptr = strsep(&opts, ",")) != NULL) {
+       while ((ptr = strsep(&opts, ",\n")) != NULL) {
                if (!*ptr)
                        continue;
 
@@ -559,7 +558,7 @@ out:
 
 static ssize_t fd_check_configfs_dev_params(struct se_hba *hba, struct se_subsystem_dev *se_dev)
 {
-       struct fd_dev *fd_dev = (struct fd_dev *) se_dev->se_dev_su_ptr;
+       struct fd_dev *fd_dev = se_dev->se_dev_su_ptr;
 
        if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) {
                pr_err("Missing fd_dev_name=\n");
index c68019d6c406292335522d536760fb8bb5904629..3dd1bd4b6f71c712eb10770ebf976a9a7fa67cfc 100644 (file)
 #include <net/tcp.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_tpg.h>
-#include <target/target_core_transport.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
 
-#include "target_core_hba.h"
+#include "target_core_internal.h"
 
 static LIST_HEAD(subsystem_list);
 static DEFINE_MUTEX(subsystem_mutex);
diff --git a/drivers/target/target_core_hba.h b/drivers/target/target_core_hba.h
deleted file mode 100644 (file)
index bb0fea5..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef TARGET_CORE_HBA_H
-#define TARGET_CORE_HBA_H
-
-extern struct se_hba *core_alloc_hba(const char *, u32, u32);
-extern int core_delete_hba(struct se_hba *);
-
-#endif /* TARGET_CORE_HBA_H */
index 4aa9922044382628fc21e12d8df3ab67840c23ae..cc8e6b58ef20b4d5cc5d7fa5561b73fa81c26eaf 100644 (file)
@@ -42,8 +42,7 @@
 #include <scsi/scsi_host.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_transport.h>
+#include <target/target_core_backend.h>
 
 #include "target_core_iblock.h"
 
@@ -391,7 +390,7 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba,
 
        orig = opts;
 
-       while ((ptr = strsep(&opts, ",")) != NULL) {
+       while ((ptr = strsep(&opts, ",\n")) != NULL) {
                if (!*ptr)
                        continue;
 
@@ -465,7 +464,7 @@ static ssize_t iblock_show_configfs_dev_params(
        if (bd) {
                bl += sprintf(b + bl, "Major: %d Minor: %d  %s\n",
                        MAJOR(bd->bd_dev), MINOR(bd->bd_dev), (!bd->bd_contains) ?
-                       "" : (bd->bd_holder == (struct iblock_dev *)ibd) ?
+                       "" : (bd->bd_holder == ibd) ?
                        "CLAIMED: IBLOCK" : "CLAIMED: OS");
        } else {
                bl += sprintf(b + bl, "Major: 0 Minor: 0\n");
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
new file mode 100644 (file)
index 0000000..26f135e
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef TARGET_CORE_INTERNAL_H
+#define TARGET_CORE_INTERNAL_H
+
+/* target_core_alua.c */
+extern struct t10_alua_lu_gp *default_lu_gp;
+
+/* target_core_cdb.c */
+int    target_emulate_inquiry(struct se_task *task);
+int    target_emulate_readcapacity(struct se_task *task);
+int    target_emulate_readcapacity_16(struct se_task *task);
+int    target_emulate_modesense(struct se_task *task);
+int    target_emulate_request_sense(struct se_task *task);
+int    target_emulate_unmap(struct se_task *task);
+int    target_emulate_write_same(struct se_task *task);
+int    target_emulate_synchronize_cache(struct se_task *task);
+int    target_emulate_noop(struct se_task *task);
+
+/* target_core_device.c */
+struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16);
+int    core_free_device_list_for_node(struct se_node_acl *,
+               struct se_portal_group *);
+void   core_dec_lacl_count(struct se_node_acl *, struct se_cmd *);
+void   core_update_device_list_access(u32, u32, struct se_node_acl *);
+int    core_update_device_list_for_node(struct se_lun *, struct se_lun_acl *,
+               u32, u32, struct se_node_acl *, struct se_portal_group *, int);
+void   core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *);
+int    core_dev_export(struct se_device *, struct se_portal_group *,
+               struct se_lun *);
+void   core_dev_unexport(struct se_device *, struct se_portal_group *,
+               struct se_lun *);
+int    target_report_luns(struct se_task *);
+void   se_release_device_for_hba(struct se_device *);
+void   se_release_vpd_for_dev(struct se_device *);
+int    se_free_virtual_device(struct se_device *, struct se_hba *);
+int    se_dev_check_online(struct se_device *);
+int    se_dev_check_shutdown(struct se_device *);
+void   se_dev_set_default_attribs(struct se_device *, struct se_dev_limits *);
+int    se_dev_set_task_timeout(struct se_device *, u32);
+int    se_dev_set_max_unmap_lba_count(struct se_device *, u32);
+int    se_dev_set_max_unmap_block_desc_count(struct se_device *, u32);
+int    se_dev_set_unmap_granularity(struct se_device *, u32);
+int    se_dev_set_unmap_granularity_alignment(struct se_device *, u32);
+int    se_dev_set_emulate_dpo(struct se_device *, int);
+int    se_dev_set_emulate_fua_write(struct se_device *, int);
+int    se_dev_set_emulate_fua_read(struct se_device *, int);
+int    se_dev_set_emulate_write_cache(struct se_device *, int);
+int    se_dev_set_emulate_ua_intlck_ctrl(struct se_device *, int);
+int    se_dev_set_emulate_tas(struct se_device *, int);
+int    se_dev_set_emulate_tpu(struct se_device *, int);
+int    se_dev_set_emulate_tpws(struct se_device *, int);
+int    se_dev_set_enforce_pr_isids(struct se_device *, int);
+int    se_dev_set_is_nonrot(struct se_device *, int);
+int    se_dev_set_emulate_rest_reord(struct se_device *dev, int);
+int    se_dev_set_queue_depth(struct se_device *, u32);
+int    se_dev_set_max_sectors(struct se_device *, u32);
+int    se_dev_set_optimal_sectors(struct se_device *, u32);
+int    se_dev_set_block_size(struct se_device *, u32);
+struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_hba *,
+               struct se_device *, u32);
+int    core_dev_del_lun(struct se_portal_group *, u32);
+struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32);
+struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *,
+               u32, char *, int *);
+int    core_dev_add_initiator_node_lun_acl(struct se_portal_group *,
+               struct se_lun_acl *, u32, u32);
+int    core_dev_del_initiator_node_lun_acl(struct se_portal_group *,
+               struct se_lun *, struct se_lun_acl *);
+void   core_dev_free_initiator_node_lun_acl(struct se_portal_group *,
+               struct se_lun_acl *lacl);
+int    core_dev_setup_virtual_lun0(void);
+void   core_dev_release_virtual_lun0(void);
+
+/* target_core_hba.c */
+struct se_hba *core_alloc_hba(const char *, u32, u32);
+int    core_delete_hba(struct se_hba *);
+
+/* target_core_tmr.c */
+int    core_tmr_lun_reset(struct se_device *, struct se_tmr_req *,
+               struct list_head *, struct se_cmd *);
+
+/* target_core_tpg.c */
+extern struct se_device *g_lun0_dev;
+
+struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tpg,
+               const char *);
+struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg,
+               unsigned char *);
+void   core_tpg_add_node_to_devs(struct se_node_acl *, struct se_portal_group *);
+void   core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *);
+struct se_lun *core_tpg_pre_addlun(struct se_portal_group *, u32);
+int    core_tpg_post_addlun(struct se_portal_group *, struct se_lun *,
+               u32, void *);
+struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32, int *);
+int    core_tpg_post_dellun(struct se_portal_group *, struct se_lun *);
+
+/* target_core_transport.c */
+extern struct kmem_cache *se_tmr_req_cache;
+
+int    init_se_kmem_caches(void);
+void   release_se_kmem_caches(void);
+u32    scsi_get_new_index(scsi_index_t);
+void   transport_subsystem_check_init(void);
+void   transport_cmd_finish_abort(struct se_cmd *, int);
+void   __transport_remove_task_from_execute_queue(struct se_task *,
+               struct se_device *);
+unsigned char *transport_dump_cmd_direction(struct se_cmd *);
+void   transport_dump_dev_state(struct se_device *, char *, int *);
+void   transport_dump_dev_info(struct se_device *, struct se_lun *,
+               unsigned long long, char *, int *);
+void   transport_dump_vpd_proto_id(struct t10_vpd *, unsigned char *, int);
+int    transport_dump_vpd_assoc(struct t10_vpd *, unsigned char *, int);
+int    transport_dump_vpd_ident_type(struct t10_vpd *, unsigned char *, int);
+int    transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int);
+bool   target_stop_task(struct se_task *task, unsigned long *flags);
+int    transport_clear_lun_from_sessions(struct se_lun *);
+void   transport_send_task_abort(struct se_cmd *);
+
+/* target_core_stat.c */
+void   target_stat_setup_dev_default_groups(struct se_subsystem_dev *);
+void   target_stat_setup_port_default_groups(struct se_lun *);
+void   target_stat_setup_mappedlun_default_groups(struct se_lun_acl *);
+
+#endif /* TARGET_CORE_INTERNAL_H */
index 95dee7074aeb5eb05f630fdded543e948ac206b3..429ad7291664382dc0f73c38a833fa29ab132632 100644 (file)
 #include <asm/unaligned.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_tmr.h>
-#include <target/target_core_tpg.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_configfs.h>
 
-#include "target_core_hba.h"
+#include "target_core_internal.h"
 #include "target_core_pr.h"
 #include "target_core_ua.h"
 
@@ -2984,21 +2981,6 @@ static void core_scsi3_release_preempt_and_abort(
        }
 }
 
-int core_scsi3_check_cdb_abort_and_preempt(
-       struct list_head *preempt_and_abort_list,
-       struct se_cmd *cmd)
-{
-       struct t10_pr_registration *pr_reg, *pr_reg_tmp;
-
-       list_for_each_entry_safe(pr_reg, pr_reg_tmp, preempt_and_abort_list,
-                               pr_reg_abort_list) {
-               if (pr_reg->pr_res_key == cmd->pr_res_key)
-                       return 0;
-       }
-
-       return 1;
-}
-
 static int core_scsi3_pro_preempt(
        struct se_cmd *cmd,
        int type,
index b97f6940dd051a9e6c18e1842d0626af3a60ebbc..7a233feb7e992a30502ea4b43368214eb8f269ff 100644 (file)
@@ -60,8 +60,6 @@ extern void core_scsi3_free_pr_reg_from_nacl(struct se_device *,
                                             struct se_node_acl *);
 extern void core_scsi3_free_all_registrations(struct se_device *);
 extern unsigned char *core_scsi3_pr_dump_type(int);
-extern int core_scsi3_check_cdb_abort_and_preempt(struct list_head *,
-                                                 struct se_cmd *);
 
 extern int target_scsi3_emulate_pr_in(struct se_task *task);
 extern int target_scsi3_emulate_pr_out(struct se_task *task);
index 8b15e56b038461169872d964055316c0318e7e31..d35467d42e12da52a7ac28d28cb01b78f741d129 100644 (file)
@@ -44,8 +44,7 @@
 #include <scsi/scsi_tcq.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_transport.h>
+#include <target/target_core_backend.h>
 
 #include "target_core_pscsi.h"
 
@@ -105,7 +104,7 @@ static void pscsi_detach_hba(struct se_hba *hba)
 
 static int pscsi_pmode_enable_hba(struct se_hba *hba, unsigned long mode_flag)
 {
-       struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)hba->hba_ptr;
+       struct pscsi_hba_virt *phv = hba->hba_ptr;
        struct Scsi_Host *sh = phv->phv_lld_host;
        /*
         * Release the struct Scsi_Host
@@ -351,7 +350,6 @@ static struct se_device *pscsi_add_device_to_list(
         * scsi_device_put() and the pdv->pdv_sd cleared.
         */
        pdv->pdv_sd = sd;
-
        dev = transport_add_device_to_core_hba(hba, &pscsi_template,
                                se_dev, dev_flags, pdv,
                                &dev_limits, NULL, NULL);
@@ -406,7 +404,7 @@ static struct se_device *pscsi_create_type_disk(
        __releases(sh->host_lock)
 {
        struct se_device *dev;
-       struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr;
+       struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr;
        struct Scsi_Host *sh = sd->host;
        struct block_device *bd;
        u32 dev_flags = 0;
@@ -454,7 +452,7 @@ static struct se_device *pscsi_create_type_rom(
        __releases(sh->host_lock)
 {
        struct se_device *dev;
-       struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr;
+       struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr;
        struct Scsi_Host *sh = sd->host;
        u32 dev_flags = 0;
 
@@ -489,7 +487,7 @@ static struct se_device *pscsi_create_type_other(
        __releases(sh->host_lock)
 {
        struct se_device *dev;
-       struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr;
+       struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr;
        struct Scsi_Host *sh = sd->host;
        u32 dev_flags = 0;
 
@@ -510,10 +508,10 @@ static struct se_device *pscsi_create_virtdevice(
        struct se_subsystem_dev *se_dev,
        void *p)
 {
-       struct pscsi_dev_virt *pdv = (struct pscsi_dev_virt *)p;
+       struct pscsi_dev_virt *pdv = p;
        struct se_device *dev;
        struct scsi_device *sd;
-       struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)hba->hba_ptr;
+       struct pscsi_hba_virt *phv = hba->hba_ptr;
        struct Scsi_Host *sh = phv->phv_lld_host;
        int legacy_mode_enable = 0;
 
@@ -818,7 +816,7 @@ static ssize_t pscsi_set_configfs_dev_params(struct se_hba *hba,
 
        orig = opts;
 
-       while ((ptr = strsep(&opts, ",")) != NULL) {
+       while ((ptr = strsep(&opts, ",\n")) != NULL) {
                if (!*ptr)
                        continue;
 
@@ -1144,7 +1142,7 @@ static unsigned char *pscsi_get_sense_buffer(struct se_task *task)
 {
        struct pscsi_plugin_task *pt = PSCSI_TASK(task);
 
-       return (unsigned char *)&pt->pscsi_sense[0];
+       return pt->pscsi_sense;
 }
 
 /*     pscsi_get_device_rev():
index 02e51faa2f4ea168f0a6139c8e303fc9fca81c28..8b68f7b82631ea8e0993da09228882820366067b 100644 (file)
@@ -37,9 +37,7 @@
 #include <scsi/scsi_host.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_backend.h>
 
 #include "target_core_rd.h"
 
@@ -474,7 +472,7 @@ static ssize_t rd_set_configfs_dev_params(
 
        orig = opts;
 
-       while ((ptr = strsep(&opts, ",")) != NULL) {
+       while ((ptr = strsep(&opts, ",\n")) != NULL) {
                if (!*ptr)
                        continue;
 
index 874152aed94af013de0bc5762f0959ea25281e05..f8c2d2cc34310041323d2614c3dfb09902a1f1db 100644 (file)
 #include <scsi/scsi_host.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_configfs.h>
 #include <target/configfs_macros.h>
 
-#include "target_core_hba.h"
+#include "target_core_internal.h"
 
 #ifndef INITIAL_JIFFIES
 #define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))
@@ -1755,8 +1755,7 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_port_ident(
        /* scsiAttIntrPortName+scsiAttIntrPortIdentifier */
        memset(buf, 0, 64);
        if (tpg->se_tpg_tfo->sess_get_initiator_sid != NULL)
-               tpg->se_tpg_tfo->sess_get_initiator_sid(se_sess,
-                               (unsigned char *)&buf[0], 64);
+               tpg->se_tpg_tfo->sess_get_initiator_sid(se_sess, buf, 64);
 
        ret = snprintf(page, PAGE_SIZE, "%s+i+%s\n", nacl->initiatorname, buf);
        spin_unlock_irq(&nacl->nacl_sess_lock);
diff --git a/drivers/target/target_core_stat.h b/drivers/target/target_core_stat.h
deleted file mode 100644 (file)
index 86c252f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef TARGET_CORE_STAT_H
-#define TARGET_CORE_STAT_H
-
-extern void target_stat_setup_dev_default_groups(struct se_subsystem_dev *);
-extern void target_stat_setup_port_default_groups(struct se_lun *);
-extern void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *);
-
-#endif   /*** TARGET_CORE_STAT_H ***/
index 684522805a1f370a99a5745c2fa3815a9c722912..dcb0618c9388a9e41341b7abef159d18a2eed259 100644 (file)
 #include <scsi/scsi_cmnd.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_tmr.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_configfs.h>
 
+#include "target_core_internal.h"
 #include "target_core_alua.h"
 #include "target_core_pr.h"
 
@@ -101,6 +100,21 @@ static void core_tmr_handle_tas_abort(
        transport_cmd_finish_abort(cmd, 0);
 }
 
+static int target_check_cdb_and_preempt(struct list_head *list,
+               struct se_cmd *cmd)
+{
+       struct t10_pr_registration *reg;
+
+       if (!list)
+               return 0;
+       list_for_each_entry(reg, list, pr_reg_abort_list) {
+               if (reg->pr_res_key == cmd->pr_res_key)
+                       return 0;
+       }
+
+       return 1;
+}
+
 static void core_tmr_drain_tmr_list(
        struct se_device *dev,
        struct se_tmr_req *tmr,
@@ -132,9 +146,7 @@ static void core_tmr_drain_tmr_list(
                 * parameter (eg: for PROUT PREEMPT_AND_ABORT service action
                 * skip non regisration key matching TMRs.
                 */
-               if (preempt_and_abort_list &&
-                   (core_scsi3_check_cdb_abort_and_preempt(
-                                       preempt_and_abort_list, cmd) != 0))
+               if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd))
                        continue;
 
                spin_lock(&cmd->t_state_lock);
@@ -211,9 +223,7 @@ static void core_tmr_drain_task_list(
                 * For PREEMPT_AND_ABORT usage, only process commands
                 * with a matching reservation key.
                 */
-               if (preempt_and_abort_list &&
-                   (core_scsi3_check_cdb_abort_and_preempt(
-                                       preempt_and_abort_list, cmd) != 0))
+               if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd))
                        continue;
                /*
                 * Not aborting PROUT PREEMPT_AND_ABORT CDB..
@@ -222,7 +232,7 @@ static void core_tmr_drain_task_list(
                        continue;
 
                list_move_tail(&task->t_state_list, &drain_task_list);
-               atomic_set(&task->task_state_active, 0);
+               task->t_state_active = false;
                /*
                 * Remove from task execute list before processing drain_task_list
                 */
@@ -321,9 +331,7 @@ static void core_tmr_drain_cmd_list(
                 * For PREEMPT_AND_ABORT usage, only process commands
                 * with a matching reservation key.
                 */
-               if (preempt_and_abort_list &&
-                   (core_scsi3_check_cdb_abort_and_preempt(
-                                       preempt_and_abort_list, cmd) != 0))
+               if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd))
                        continue;
                /*
                 * Not aborting PROUT PREEMPT_AND_ABORT CDB..
index 8ddd133025b932a98a5968bfeb4f30b0d396a3d2..b7668029bb311d77820613bdaf2b5b0c0ba04d28 100644 (file)
 #include <scsi/scsi_cmnd.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_tpg.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
 
-#include "target_core_hba.h"
-#include "target_core_stat.h"
+#include "target_core_internal.h"
 
 extern struct se_device *g_lun0_dev;
 
index 0257658e2e3ea8a75642ae0dcabc77547ac2379b..d3ddd13619492d87f680258149f80987988bb9e4 100644 (file)
 #include <scsi/scsi_tcq.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_tmr.h>
-#include <target/target_core_tpg.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_configfs.h>
 
+#include "target_core_internal.h"
 #include "target_core_alua.h"
-#include "target_core_cdb.h"
-#include "target_core_hba.h"
 #include "target_core_pr.h"
 #include "target_core_ua.h"
 
@@ -72,7 +68,7 @@ struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
 
 static int transport_generic_write_pending(struct se_cmd *);
 static int transport_processing_thread(void *param);
-static int __transport_execute_tasks(struct se_device *dev);
+static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *);
 static void transport_complete_task_attr(struct se_cmd *cmd);
 static void transport_handle_queue_full(struct se_cmd *cmd,
                struct se_device *dev);
@@ -212,14 +208,13 @@ u32 scsi_get_new_index(scsi_index_t type)
        return new_index;
 }
 
-void transport_init_queue_obj(struct se_queue_obj *qobj)
+static void transport_init_queue_obj(struct se_queue_obj *qobj)
 {
        atomic_set(&qobj->queue_cnt, 0);
        INIT_LIST_HEAD(&qobj->qobj_list);
        init_waitqueue_head(&qobj->thread_wq);
        spin_lock_init(&qobj->cmd_queue_lock);
 }
-EXPORT_SYMBOL(transport_init_queue_obj);
 
 void transport_subsystem_check_init(void)
 {
@@ -426,18 +421,18 @@ static void transport_all_task_dev_remove_state(struct se_cmd *cmd)
                if (task->task_flags & TF_ACTIVE)
                        continue;
 
-               if (!atomic_read(&task->task_state_active))
-                       continue;
-
                spin_lock_irqsave(&dev->execute_task_lock, flags);
-               list_del(&task->t_state_list);
-               pr_debug("Removed ITT: 0x%08x dev: %p task[%p]\n",
-                       cmd->se_tfo->get_task_tag(cmd), dev, task);
-               spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+               if (task->t_state_active) {
+                       pr_debug("Removed ITT: 0x%08x dev: %p task[%p]\n",
+                               cmd->se_tfo->get_task_tag(cmd), dev, task);
 
-               atomic_set(&task->task_state_active, 0);
-               atomic_dec(&cmd->t_task_cdbs_ex_left);
+                       list_del(&task->t_state_list);
+                       atomic_dec(&cmd->t_task_cdbs_ex_left);
+                       task->t_state_active = false;
+               }
+               spin_unlock_irqrestore(&dev->execute_task_lock, flags);
        }
+
 }
 
 /*     transport_cmd_check_stop():
@@ -696,12 +691,6 @@ void transport_complete_task(struct se_task *task, int success)
        struct se_cmd *cmd = task->task_se_cmd;
        struct se_device *dev = cmd->se_dev;
        unsigned long flags;
-#if 0
-       pr_debug("task: %p CDB: 0x%02x obj_ptr: %p\n", task,
-                       cmd->t_task_cdb[0], dev);
-#endif
-       if (dev)
-               atomic_inc(&dev->depth_left);
 
        spin_lock_irqsave(&cmd->t_state_lock, flags);
        task->task_flags &= ~TF_ACTIVE;
@@ -714,7 +703,7 @@ void transport_complete_task(struct se_task *task, int success)
        if (dev && dev->transport->transport_complete) {
                if (dev->transport->transport_complete(task) != 0) {
                        cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE;
-                       task->task_sense = 1;
+                       task->task_flags |= TF_HAS_SENSE;
                        success = 1;
                }
        }
@@ -743,13 +732,7 @@ void transport_complete_task(struct se_task *task, int success)
        }
 
        if (cmd->t_tasks_failed) {
-               if (!task->task_error_status) {
-                       task->task_error_status =
-                               TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-                       cmd->scsi_sense_reason =
-                               TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-               }
-
+               cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
                INIT_WORK(&cmd->work, target_complete_failure_work);
        } else {
                atomic_set(&cmd->t_transport_complete, 1);
@@ -824,7 +807,7 @@ static void __transport_add_task_to_execute_queue(
        head_of_queue = transport_add_task_check_sam_attr(task, task_prev, dev);
        atomic_inc(&dev->execute_tasks);
 
-       if (atomic_read(&task->task_state_active))
+       if (task->t_state_active)
                return;
        /*
         * Determine if this task needs to go to HEAD_OF_QUEUE for the
@@ -838,7 +821,7 @@ static void __transport_add_task_to_execute_queue(
        else
                list_add_tail(&task->t_state_list, &dev->state_task_list);
 
-       atomic_set(&task->task_state_active, 1);
+       task->t_state_active = true;
 
        pr_debug("Added ITT: 0x%08x task[%p] to dev: %p\n",
                task->task_se_cmd->se_tfo->get_task_tag(task->task_se_cmd),
@@ -853,29 +836,26 @@ static void transport_add_tasks_to_state_queue(struct se_cmd *cmd)
 
        spin_lock_irqsave(&cmd->t_state_lock, flags);
        list_for_each_entry(task, &cmd->t_task_list, t_list) {
-               if (atomic_read(&task->task_state_active))
-                       continue;
-
                spin_lock(&dev->execute_task_lock);
-               list_add_tail(&task->t_state_list, &dev->state_task_list);
-               atomic_set(&task->task_state_active, 1);
-
-               pr_debug("Added ITT: 0x%08x task[%p] to dev: %p\n",
-                       task->task_se_cmd->se_tfo->get_task_tag(
-                       task->task_se_cmd), task, dev);
-
+               if (!task->t_state_active) {
+                       list_add_tail(&task->t_state_list,
+                                     &dev->state_task_list);
+                       task->t_state_active = true;
+
+                       pr_debug("Added ITT: 0x%08x task[%p] to dev: %p\n",
+                               task->task_se_cmd->se_tfo->get_task_tag(
+                               task->task_se_cmd), task, dev);
+               }
                spin_unlock(&dev->execute_task_lock);
        }
        spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 }
 
-static void transport_add_tasks_from_cmd(struct se_cmd *cmd)
+static void __transport_add_tasks_from_cmd(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
        struct se_task *task, *task_prev = NULL;
-       unsigned long flags;
 
-       spin_lock_irqsave(&dev->execute_task_lock, flags);
        list_for_each_entry(task, &cmd->t_task_list, t_list) {
                if (!list_empty(&task->t_execute_list))
                        continue;
@@ -886,6 +866,15 @@ static void transport_add_tasks_from_cmd(struct se_cmd *cmd)
                __transport_add_task_to_execute_queue(task, task_prev, dev);
                task_prev = task;
        }
+}
+
+static void transport_add_tasks_from_cmd(struct se_cmd *cmd)
+{
+       unsigned long flags;
+       struct se_device *dev = cmd->se_dev;
+
+       spin_lock_irqsave(&dev->execute_task_lock, flags);
+       __transport_add_tasks_from_cmd(cmd);
        spin_unlock_irqrestore(&dev->execute_task_lock, flags);
 }
 
@@ -896,7 +885,7 @@ void __transport_remove_task_from_execute_queue(struct se_task *task,
        atomic_dec(&dev->execute_tasks);
 }
 
-void transport_remove_task_from_execute_queue(
+static void transport_remove_task_from_execute_queue(
        struct se_task *task,
        struct se_device *dev)
 {
@@ -983,9 +972,8 @@ void transport_dump_dev_state(
                break;
        }
 
-       *bl += sprintf(b + *bl, "  Execute/Left/Max Queue Depth: %d/%d/%d",
-               atomic_read(&dev->execute_tasks), atomic_read(&dev->depth_left),
-               dev->queue_depth);
+       *bl += sprintf(b + *bl, "  Execute/Max Queue Depth: %d/%d",
+               atomic_read(&dev->execute_tasks), dev->queue_depth);
        *bl += sprintf(b + *bl, "  SectorSize: %u  MaxSectors: %u\n",
                dev->se_sub_dev->se_dev_attrib.block_size, dev->se_sub_dev->se_dev_attrib.max_sectors);
        *bl += sprintf(b + *bl, "        ");
@@ -1340,9 +1328,6 @@ struct se_device *transport_add_device_to_core_hba(
        spin_lock_init(&dev->se_port_lock);
        spin_lock_init(&dev->se_tmr_lock);
        spin_lock_init(&dev->qf_cmd_lock);
-
-       dev->queue_depth        = dev_limits->queue_depth;
-       atomic_set(&dev->depth_left, dev->queue_depth);
        atomic_set(&dev->dev_ordered_id, 0);
 
        se_dev_set_default_attribs(dev, dev_limits);
@@ -1654,6 +1639,80 @@ int transport_handle_cdb_direct(
 }
 EXPORT_SYMBOL(transport_handle_cdb_direct);
 
+/**
+ * target_submit_cmd - lookup unpacked lun and submit uninitialized se_cmd
+ *
+ * @se_cmd: command descriptor to submit
+ * @se_sess: associated se_sess for endpoint
+ * @cdb: pointer to SCSI CDB
+ * @sense: pointer to SCSI sense buffer
+ * @unpacked_lun: unpacked LUN to reference for struct se_lun
+ * @data_length: fabric expected data transfer length
+ * @task_addr: SAM task attribute
+ * @data_dir: DMA data direction
+ * @flags: flags for command submission from target_sc_flags_tables
+ *
+ * This may only be called from process context, and also currently
+ * assumes internal allocation of fabric payload buffer by target-core.
+ **/
+int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
+               unsigned char *cdb, unsigned char *sense, u32 unpacked_lun,
+               u32 data_length, int task_attr, int data_dir, int flags)
+{
+       struct se_portal_group *se_tpg;
+       int rc;
+
+       se_tpg = se_sess->se_tpg;
+       BUG_ON(!se_tpg);
+       BUG_ON(se_cmd->se_tfo || se_cmd->se_sess);
+       BUG_ON(in_interrupt());
+       /*
+        * Initialize se_cmd for target operation.  From this point
+        * exceptions are handled by sending exception status via
+        * target_core_fabric_ops->queue_status() callback
+        */
+       transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess,
+                               data_length, data_dir, task_attr, sense);
+       /*
+        * Obtain struct se_cmd->cmd_kref reference and add new cmd to
+        * se_sess->sess_cmd_list.  A second kref_get here is necessary
+        * for fabrics using TARGET_SCF_ACK_KREF that expect a second
+        * kref_put() to happen during fabric packet acknowledgement.
+        */
+       target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF));
+       /*
+        * Signal bidirectional data payloads to target-core
+        */
+       if (flags & TARGET_SCF_BIDI_OP)
+               se_cmd->se_cmd_flags |= SCF_BIDI;
+       /*
+        * Locate se_lun pointer and attach it to struct se_cmd
+        */
+       if (transport_lookup_cmd_lun(se_cmd, unpacked_lun) < 0)
+               goto out_check_cond;
+       /*
+        * Sanitize CDBs via transport_generic_cmd_sequencer() and
+        * allocate the necessary tasks to complete the received CDB+data
+        */
+       rc = transport_generic_allocate_tasks(se_cmd, cdb);
+       if (rc != 0)
+               goto out_check_cond;
+       /*
+        * Dispatch se_cmd descriptor to se_lun->lun_se_dev backend
+        * for immediate execution of READs, otherwise wait for
+        * transport_generic_handle_data() to be called for WRITEs
+        * when fabric has filled the incoming buffer.
+        */
+       transport_handle_cdb_direct(se_cmd);
+       return 0;
+
+out_check_cond:
+       transport_send_check_condition_and_sense(se_cmd,
+                               se_cmd->scsi_sense_reason, 0);
+       return 0;
+}
+EXPORT_SYMBOL(target_submit_cmd);
+
 /*
  * Used by fabric module frontends defining a TFO->new_cmd_map() caller
  * to  queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD_MAP in order to
@@ -1920,18 +1979,6 @@ static void transport_set_supported_SAM_opcode(struct se_cmd *se_cmd)
        spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
 }
 
-static inline int transport_tcq_window_closed(struct se_device *dev)
-{
-       if (dev->dev_tcq_window_closed++ <
-                       PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD) {
-               msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT);
-       } else
-               msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_LONG);
-
-       wake_up_interruptible(&dev->dev_queue_obj.thread_wq);
-       return 0;
-}
-
 /*
  * Called from Fabric Module context from transport_execute_tasks()
  *
@@ -2014,13 +2061,7 @@ static inline int transport_execute_task_attr(struct se_cmd *cmd)
 static int transport_execute_tasks(struct se_cmd *cmd)
 {
        int add_tasks;
-
-       if (se_dev_check_online(cmd->se_dev) != 0) {
-               cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-               transport_generic_request_failure(cmd);
-               return 0;
-       }
-
+       struct se_device *se_dev = cmd->se_dev;
        /*
         * Call transport_cmd_check_stop() to see if a fabric exception
         * has occurred that prevents execution.
@@ -2034,19 +2075,16 @@ static int transport_execute_tasks(struct se_cmd *cmd)
                if (!add_tasks)
                        goto execute_tasks;
                /*
-                * This calls transport_add_tasks_from_cmd() to handle
-                * HEAD_OF_QUEUE ordering for SAM Task Attribute emulation
-                * (if enabled) in __transport_add_task_to_execute_queue() and
-                * transport_add_task_check_sam_attr().
+                * __transport_execute_tasks() -> __transport_add_tasks_from_cmd()
+                * adds associated se_tasks while holding dev->execute_task_lock
+                * before I/O dispath to avoid a double spinlock access.
                 */
-               transport_add_tasks_from_cmd(cmd);
+               __transport_execute_tasks(se_dev, cmd);
+               return 0;
        }
-       /*
-        * Kick the execution queue for the cmd associated struct se_device
-        * storage object.
-        */
+
 execute_tasks:
-       __transport_execute_tasks(cmd->se_dev);
+       __transport_execute_tasks(se_dev, NULL);
        return 0;
 }
 
@@ -2056,24 +2094,18 @@ execute_tasks:
  *
  * Called from transport_processing_thread()
  */
-static int __transport_execute_tasks(struct se_device *dev)
+static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *new_cmd)
 {
        int error;
        struct se_cmd *cmd = NULL;
        struct se_task *task = NULL;
        unsigned long flags;
 
-       /*
-        * Check if there is enough room in the device and HBA queue to send
-        * struct se_tasks to the selected transport.
-        */
 check_depth:
-       if (!atomic_read(&dev->depth_left))
-               return transport_tcq_window_closed(dev);
-
-       dev->dev_tcq_window_closed = 0;
-
        spin_lock_irq(&dev->execute_task_lock);
+       if (new_cmd != NULL)
+               __transport_add_tasks_from_cmd(new_cmd);
+
        if (list_empty(&dev->execute_task_list)) {
                spin_unlock_irq(&dev->execute_task_lock);
                return 0;
@@ -2083,10 +2115,7 @@ check_depth:
        __transport_remove_task_from_execute_queue(task, dev);
        spin_unlock_irq(&dev->execute_task_lock);
 
-       atomic_dec(&dev->depth_left);
-
        cmd = task->task_se_cmd;
-
        spin_lock_irqsave(&cmd->t_state_lock, flags);
        task->task_flags |= (TF_ACTIVE | TF_SENT);
        atomic_inc(&cmd->t_task_cdbs_sent);
@@ -2107,10 +2136,10 @@ check_depth:
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
                atomic_set(&cmd->t_transport_sent, 0);
                transport_stop_tasks_for_cmd(cmd);
-               atomic_inc(&dev->depth_left);
                transport_generic_request_failure(cmd);
        }
 
+       new_cmd = NULL;
        goto check_depth;
 
        return 0;
@@ -2351,7 +2380,7 @@ static int transport_get_sense_data(struct se_cmd *cmd)
 
        list_for_each_entry_safe(task, task_tmp,
                                &cmd->t_task_list, t_list) {
-               if (!task->task_sense)
+               if (!(task->task_flags & TF_HAS_SENSE))
                        continue;
 
                if (!dev->transport->get_sense_buffer) {
@@ -3345,6 +3374,32 @@ static inline void transport_free_pages(struct se_cmd *cmd)
        cmd->t_bidi_data_nents = 0;
 }
 
+/**
+ * transport_release_cmd - free a command
+ * @cmd:       command to free
+ *
+ * This routine unconditionally frees a command, and reference counting
+ * or list removal must be done in the caller.
+ */
+static void transport_release_cmd(struct se_cmd *cmd)
+{
+       BUG_ON(!cmd->se_tfo);
+
+       if (cmd->se_tmr_req)
+               core_tmr_release_req(cmd->se_tmr_req);
+       if (cmd->t_task_cdb != cmd->__t_task_cdb)
+               kfree(cmd->t_task_cdb);
+       /*
+        * If this cmd has been setup with target_get_sess_cmd(), drop
+        * the kref and call ->release_cmd() in kref callback.
+        */
+        if (cmd->check_release != 0) {
+               target_put_sess_cmd(cmd->se_sess, cmd);
+               return;
+       }
+       cmd->se_tfo->release_cmd(cmd);
+}
+
 /**
  * transport_put_cmd - release a reference to a command
  * @cmd:       command to release
@@ -3870,33 +3925,6 @@ queue_full:
        return 0;
 }
 
-/**
- * transport_release_cmd - free a command
- * @cmd:       command to free
- *
- * This routine unconditionally frees a command, and reference counting
- * or list removal must be done in the caller.
- */
-void transport_release_cmd(struct se_cmd *cmd)
-{
-       BUG_ON(!cmd->se_tfo);
-
-       if (cmd->se_tmr_req)
-               core_tmr_release_req(cmd->se_tmr_req);
-       if (cmd->t_task_cdb != cmd->__t_task_cdb)
-               kfree(cmd->t_task_cdb);
-       /*
-        * Check if target_wait_for_sess_cmds() is expecting to
-        * release se_cmd directly here..
-        */
-       if (cmd->check_release != 0 && cmd->se_tfo->check_release_cmd)
-               if (cmd->se_tfo->check_release_cmd(cmd) != 0)
-                       return;
-
-       cmd->se_tfo->release_cmd(cmd);
-}
-EXPORT_SYMBOL(transport_release_cmd);
-
 void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
 {
        if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
@@ -3923,11 +3951,22 @@ EXPORT_SYMBOL(transport_generic_free_cmd);
 /* target_get_sess_cmd - Add command to active ->sess_cmd_list
  * @se_sess:   session to reference
  * @se_cmd:    command descriptor to add
+ * @ack_kref:  Signal that fabric will perform an ack target_put_sess_cmd()
  */
-void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
+void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
+                       bool ack_kref)
 {
        unsigned long flags;
 
+       kref_init(&se_cmd->cmd_kref);
+       /*
+        * Add a second kref if the fabric caller is expecting to handle
+        * fabric acknowledgement that requires two target_put_sess_cmd()
+        * invocations before se_cmd descriptor release.
+        */
+       if (ack_kref == true)
+               kref_get(&se_cmd->cmd_kref);
+
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
        list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
        se_cmd->check_release = 1;
@@ -3935,30 +3974,36 @@ void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
 }
 EXPORT_SYMBOL(target_get_sess_cmd);
 
-/* target_put_sess_cmd - Check for active I/O shutdown or list delete
- * @se_sess:   session to reference
- * @se_cmd:    command descriptor to drop
- */
-int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
+static void target_release_cmd_kref(struct kref *kref)
 {
+       struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
+       struct se_session *se_sess = se_cmd->se_sess;
        unsigned long flags;
 
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
        if (list_empty(&se_cmd->se_cmd_list)) {
                spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
                WARN_ON(1);
-               return 0;
+               return;
        }
-
        if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
                spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
                complete(&se_cmd->cmd_wait_comp);
-               return 1;
+               return;
        }
        list_del(&se_cmd->se_cmd_list);
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 
-       return 0;
+       se_cmd->se_tfo->release_cmd(se_cmd);
+}
+
+/* target_put_sess_cmd - Check for active I/O shutdown via kref_put
+ * @se_sess:   session to reference
+ * @se_cmd:    command descriptor to drop
+ */
+int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
+{
+       return kref_put(&se_cmd->cmd_kref, target_release_cmd_kref);
 }
 EXPORT_SYMBOL(target_put_sess_cmd);
 
@@ -4174,7 +4219,7 @@ check_cond:
 
 static int transport_clear_lun_thread(void *p)
 {
-       struct se_lun *lun = (struct se_lun *)p;
+       struct se_lun *lun = p;
 
        __transport_clear_lun_from_sessions(lun);
        complete(&lun->lun_shutdown_comp);
@@ -4353,6 +4398,7 @@ int transport_send_check_condition_and_sense(
        case TCM_NON_EXISTENT_LUN:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ILLEGAL REQUEST */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
                /* LOGICAL UNIT NOT SUPPORTED */
@@ -4362,6 +4408,7 @@ int transport_send_check_condition_and_sense(
        case TCM_SECTOR_COUNT_TOO_MANY:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ILLEGAL REQUEST */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
                /* INVALID COMMAND OPERATION CODE */
@@ -4370,6 +4417,7 @@ int transport_send_check_condition_and_sense(
        case TCM_UNKNOWN_MODE_PAGE:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ILLEGAL REQUEST */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
                /* INVALID FIELD IN CDB */
@@ -4378,6 +4426,7 @@ int transport_send_check_condition_and_sense(
        case TCM_CHECK_CONDITION_ABORT_CMD:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ABORTED COMMAND */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
                /* BUS DEVICE RESET FUNCTION OCCURRED */
@@ -4387,6 +4436,7 @@ int transport_send_check_condition_and_sense(
        case TCM_INCORRECT_AMOUNT_OF_DATA:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ABORTED COMMAND */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
                /* WRITE ERROR */
@@ -4397,6 +4447,7 @@ int transport_send_check_condition_and_sense(
        case TCM_INVALID_CDB_FIELD:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ABORTED COMMAND */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
                /* INVALID FIELD IN CDB */
@@ -4405,6 +4456,7 @@ int transport_send_check_condition_and_sense(
        case TCM_INVALID_PARAMETER_LIST:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ABORTED COMMAND */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
                /* INVALID FIELD IN PARAMETER LIST */
@@ -4413,6 +4465,7 @@ int transport_send_check_condition_and_sense(
        case TCM_UNEXPECTED_UNSOLICITED_DATA:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ABORTED COMMAND */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
                /* WRITE ERROR */
@@ -4423,6 +4476,7 @@ int transport_send_check_condition_and_sense(
        case TCM_SERVICE_CRC_ERROR:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ABORTED COMMAND */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
                /* PROTOCOL SERVICE CRC ERROR */
@@ -4433,6 +4487,7 @@ int transport_send_check_condition_and_sense(
        case TCM_SNACK_REJECTED:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ABORTED COMMAND */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
                /* READ ERROR */
@@ -4443,6 +4498,7 @@ int transport_send_check_condition_and_sense(
        case TCM_WRITE_PROTECTED:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* DATA PROTECT */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = DATA_PROTECT;
                /* WRITE PROTECTED */
@@ -4451,6 +4507,7 @@ int transport_send_check_condition_and_sense(
        case TCM_CHECK_CONDITION_UNIT_ATTENTION:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* UNIT ATTENTION */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
                core_scsi3_ua_for_check_condition(cmd, &asc, &ascq);
@@ -4460,6 +4517,7 @@ int transport_send_check_condition_and_sense(
        case TCM_CHECK_CONDITION_NOT_READY:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* Not Ready */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = NOT_READY;
                transport_get_sense_codes(cmd, &asc, &ascq);
@@ -4470,6 +4528,7 @@ int transport_send_check_condition_and_sense(
        default:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
                /* ILLEGAL REQUEST */
                buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
                /* LOGICAL UNIT COMMUNICATION FAILURE */
@@ -4545,11 +4604,7 @@ void transport_send_task_abort(struct se_cmd *cmd)
        cmd->se_tfo->queue_status(cmd);
 }
 
-/*     transport_generic_do_tmr():
- *
- *
- */
-int transport_generic_do_tmr(struct se_cmd *cmd)
+static int transport_generic_do_tmr(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
        struct se_tmr_req *tmr = cmd->se_tmr_req;
@@ -4597,7 +4652,7 @@ static int transport_processing_thread(void *param)
 {
        int ret;
        struct se_cmd *cmd;
-       struct se_device *dev = (struct se_device *) param;
+       struct se_device *dev = param;
 
        while (!kthread_should_stop()) {
                ret = wait_event_interruptible(dev->dev_queue_obj.thread_wq,
@@ -4607,8 +4662,6 @@ static int transport_processing_thread(void *param)
                        goto out;
 
 get_cmd:
-               __transport_execute_tasks(dev);
-
                cmd = transport_get_cmd_from_queue(&dev->dev_queue_obj);
                if (!cmd)
                        continue;
index 50a480db7a66df3d619e103060ca6c1be301f9b4..3e12f6bcfa10ba6d502aab352a6ea474839a1dd0 100644 (file)
 #include <scsi/scsi_cmnd.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_device.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_configfs.h>
 
+#include "target_core_internal.h"
 #include "target_core_alua.h"
-#include "target_core_hba.h"
 #include "target_core_pr.h"
 #include "target_core_ua.h"
 
index 71fc9cea5dc9ba120b725a4e0f6bf94c879d1340..addc18f727ea442c47c1e78aab5343bf592cf6b2 100644 (file)
 #include <scsi/fc_encode.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
-#include <target/target_core_device.h>
-#include <target/target_core_tpg.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_configfs.h>
-#include <target/target_core_tmr.h>
 #include <target/configfs_macros.h>
 
 #include "tcm_fc.h"
@@ -367,6 +363,11 @@ static void ft_send_tm(struct ft_cmd *cmd)
        struct ft_sess *sess;
        u8 tm_func;
 
+       transport_init_se_cmd(&cmd->se_cmd, &ft_configfs->tf_ops,
+                       cmd->sess->se_sess, 0, DMA_NONE, 0,
+                       &cmd->ft_sense_buffer[0]);
+       target_get_sess_cmd(cmd->sess->se_sess, &cmd->se_cmd, false);
+
        fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp));
 
        switch (fcp->fc_tm_flags) {
@@ -420,7 +421,6 @@ static void ft_send_tm(struct ft_cmd *cmd)
                        sess = cmd->sess;
                        transport_send_check_condition_and_sense(&cmd->se_cmd,
                                cmd->se_cmd.scsi_sense_reason, 0);
-                       transport_generic_free_cmd(&cmd->se_cmd, 0);
                        ft_sess_put(sess);
                        return;
                }
@@ -536,7 +536,6 @@ static void ft_send_work(struct work_struct *work)
 {
        struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
        struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame);
-       struct se_cmd *se_cmd;
        struct fcp_cmnd *fcp;
        int data_dir = 0;
        u32 data_len;
@@ -591,15 +590,6 @@ static void ft_send_work(struct work_struct *work)
                data_len = ntohl(fcp->fc_dl);
                cmd->cdb = fcp->fc_cdb;
        }
-
-       se_cmd = &cmd->se_cmd;
-       /*
-        * Initialize struct se_cmd descriptor from target_core_mod
-        * infrastructure
-        */
-       transport_init_se_cmd(se_cmd, &ft_configfs->tf_ops, cmd->sess->se_sess,
-                             data_len, data_dir, task_attr,
-                             &cmd->ft_sense_buffer[0]);
        /*
         * Check for FCP task management flags
         */
@@ -607,39 +597,20 @@ static void ft_send_work(struct work_struct *work)
                ft_send_tm(cmd);
                return;
        }
-
        fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd);
-
        cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun);
-       ret = transport_lookup_cmd_lun(&cmd->se_cmd, cmd->lun);
+       /*
+        * Use a single se_cmd->cmd_kref as we expect to release se_cmd
+        * directly from ft_check_stop_free callback in response path.
+        */
+       ret = target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, cmd->cdb,
+                               &cmd->ft_sense_buffer[0], cmd->lun, data_len,
+                               task_attr, data_dir, 0);
+       pr_debug("r_ctl %x alloc target_submit_cmd %d\n", fh->fh_r_ctl, ret);
        if (ret < 0) {
                ft_dump_cmd(cmd, __func__);
-               transport_send_check_condition_and_sense(&cmd->se_cmd,
-                       cmd->se_cmd.scsi_sense_reason, 0);
-               return;
-       }
-
-       ret = transport_generic_allocate_tasks(se_cmd, cmd->cdb);
-
-       pr_debug("r_ctl %x alloc task ret %d\n", fh->fh_r_ctl, ret);
-       ft_dump_cmd(cmd, __func__);
-
-       if (ret == -ENOMEM) {
-               transport_send_check_condition_and_sense(se_cmd,
-                               TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
-               transport_generic_free_cmd(se_cmd, 0);
-               return;
-       }
-       if (ret == -EINVAL) {
-               if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
-                       ft_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;
        }
-       transport_handle_cdb_direct(se_cmd);
        return;
 
 err:
index 9402b7387cac570d91ff6001a885daed3bbd8b6d..73852fbc857b4b5aee0622ee7b55fb5c0880291b 100644 (file)
 #include <scsi/libfc.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_fabric_configfs.h>
-#include <target/target_core_fabric_lib.h>
-#include <target/target_core_device.h>
-#include <target/target_core_tpg.h>
 #include <target/target_core_configfs.h>
 #include <target/configfs_macros.h>
 
index 1369b1cb103d7d1e0ad4053322e599713445e9b7..d8cabc21036d3ec1040168b9940ab013c55b4a0b 100644 (file)
 #include <scsi/fc_encode.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
-#include <target/target_core_device.h>
-#include <target/target_core_tpg.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_configfs.h>
 #include <target/configfs_macros.h>
 
index 326921385aff973c17ce4f8598ba791c0fa94fc2..4c0507cf808c08662609765b41488a35c461add7 100644 (file)
 #include <scsi/libfc.h>
 
 #include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
-#include <target/target_core_device.h>
-#include <target/target_core_tpg.h>
+#include <target/target_core_fabric.h>
 #include <target/target_core_configfs.h>
 #include <target/configfs_macros.h>
 
index 6a1241c7f841762dceb4d564305ffffe1bddc69a..de88aa5566e5eeb5176ebc910b2a1d37cb055637 100644 (file)
@@ -118,7 +118,7 @@ static unsigned long board2;
 static unsigned long board3;
 static unsigned long board4;
 static unsigned long controller;
-static int support_low_speed;
+static bool support_low_speed;
 static unsigned long modem1;
 static unsigned long modem2;
 static unsigned long modem3;
index f32a2ea701007f7b4aa4234bcbd9dd68d7b79d4b..aca2386c5ef10261e74bfb66b2461546c8206150 100644 (file)
@@ -1605,4 +1605,27 @@ config SERIAL_XILINX_PS_UART_CONSOLE
        help
          Enable a Xilinx PS UART port to be the system console.
 
+config SERIAL_AR933X
+       bool "AR933X serial port support"
+       depends on SOC_AR933X
+       select SERIAL_CORE
+       help
+         If you have an Atheros AR933X SOC based board and want to use the
+         built-in UART of the SoC, say Y to this option.
+
+config SERIAL_AR933X_CONSOLE
+       bool "Console on AR933X serial port"
+       depends on SERIAL_AR933X=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Enable a built-in UART port of the AR933X to be the system console.
+
+config SERIAL_AR933X_NR_UARTS
+       int "Maximum number of AR933X serial ports"
+       depends on SERIAL_AR933X
+       default "2"
+       help
+         Set this to the number of serial ports you want the driver
+         to support.
+
 endmenu
index 07e0494c68307b25406fb753c4369456c1d031e3..f5b01f2ce525da8df92d1972529fefb70c98ae23 100644 (file)
@@ -91,3 +91,4 @@ obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
 obj-$(CONFIG_SERIAL_LANTIQ)    += lantiq.o
 obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
 obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
+obj-$(CONFIG_SERIAL_AR933X)   += ar933x_uart.o
index 6958594f2fc09a4c35eb65ce6037f937b323251e..9ae024025ff356618221717d3fae6b5d296e32db 100644 (file)
@@ -268,7 +268,7 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
        struct dma_slave_config tx_conf = {
                .dst_addr = uap->port.mapbase + UART01x_DR,
                .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
-               .direction = DMA_TO_DEVICE,
+               .direction = DMA_MEM_TO_DEV,
                .dst_maxburst = uap->fifosize >> 1,
        };
        struct dma_chan *chan;
@@ -301,7 +301,7 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
                struct dma_slave_config rx_conf = {
                        .src_addr = uap->port.mapbase + UART01x_DR,
                        .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
-                       .direction = DMA_FROM_DEVICE,
+                       .direction = DMA_DEV_TO_MEM,
                        .src_maxburst = uap->fifosize >> 1,
                };
 
@@ -480,7 +480,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
                return -EBUSY;
        }
 
-       desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE,
+       desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_MEM_TO_DEV,
                                             DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc) {
                dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE);
@@ -676,7 +676,7 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
                &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
        dma_dev = rxchan->device;
        desc = rxchan->device->device_prep_slave_sg(rxchan, &sgbuf->sg, 1,
-                                       DMA_FROM_DEVICE,
+                                       DMA_DEV_TO_MEM,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        /*
         * If the DMA engine is busy and cannot prepare a
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
new file mode 100644 (file)
index 0000000..e4f60e2
--- /dev/null
@@ -0,0 +1,688 @@
+/*
+ *  Atheros AR933X SoC built-in UART driver
+ *
+ *  Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/mach-ath79/ar933x_uart.h>
+#include <asm/mach-ath79/ar933x_uart_platform.h>
+
+#define DRIVER_NAME "ar933x-uart"
+
+#define AR933X_DUMMY_STATUS_RD 0x01
+
+static struct uart_driver ar933x_uart_driver;
+
+struct ar933x_uart_port {
+       struct uart_port        port;
+       unsigned int            ier;    /* shadow Interrupt Enable Register */
+};
+
+static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
+                                           int offset)
+{
+       return readl(up->port.membase + offset);
+}
+
+static inline void ar933x_uart_write(struct ar933x_uart_port *up,
+                                    int offset, unsigned int value)
+{
+       writel(value, up->port.membase + offset);
+}
+
+static inline void ar933x_uart_rmw(struct ar933x_uart_port *up,
+                                 unsigned int offset,
+                                 unsigned int mask,
+                                 unsigned int val)
+{
+       unsigned int t;
+
+       t = ar933x_uart_read(up, offset);
+       t &= ~mask;
+       t |= val;
+       ar933x_uart_write(up, offset, t);
+}
+
+static inline void ar933x_uart_rmw_set(struct ar933x_uart_port *up,
+                                      unsigned int offset,
+                                      unsigned int val)
+{
+       ar933x_uart_rmw(up, offset, 0, val);
+}
+
+static inline void ar933x_uart_rmw_clear(struct ar933x_uart_port *up,
+                                        unsigned int offset,
+                                        unsigned int val)
+{
+       ar933x_uart_rmw(up, offset, val, 0);
+}
+
+static inline void ar933x_uart_start_tx_interrupt(struct ar933x_uart_port *up)
+{
+       up->ier |= AR933X_UART_INT_TX_EMPTY;
+       ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
+}
+
+static inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up)
+{
+       up->ier &= ~AR933X_UART_INT_TX_EMPTY;
+       ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
+}
+
+static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch)
+{
+       unsigned int rdata;
+
+       rdata = ch & AR933X_UART_DATA_TX_RX_MASK;
+       rdata |= AR933X_UART_DATA_TX_CSR;
+       ar933x_uart_write(up, AR933X_UART_DATA_REG, rdata);
+}
+
+static unsigned int ar933x_uart_tx_empty(struct uart_port *port)
+{
+       struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
+       unsigned long flags;
+       unsigned int rdata;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return (rdata & AR933X_UART_DATA_TX_CSR) ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int ar933x_uart_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CAR;
+}
+
+static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void ar933x_uart_start_tx(struct uart_port *port)
+{
+       struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
+
+       ar933x_uart_start_tx_interrupt(up);
+}
+
+static void ar933x_uart_stop_tx(struct uart_port *port)
+{
+       struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
+
+       ar933x_uart_stop_tx_interrupt(up);
+}
+
+static void ar933x_uart_stop_rx(struct uart_port *port)
+{
+       struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
+
+       up->ier &= ~AR933X_UART_INT_RX_VALID;
+       ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
+}
+
+static void ar933x_uart_break_ctl(struct uart_port *port, int break_state)
+{
+       struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       if (break_state == -1)
+               ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
+                                   AR933X_UART_CS_TX_BREAK);
+       else
+               ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
+                                     AR933X_UART_CS_TX_BREAK);
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void ar933x_uart_enable_ms(struct uart_port *port)
+{
+}
+
+static void ar933x_uart_set_termios(struct uart_port *port,
+                                   struct ktermios *new,
+                                   struct ktermios *old)
+{
+       struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
+       unsigned int cs;
+       unsigned long flags;
+       unsigned int baud, scale;
+
+       /* Only CS8 is supported */
+       new->c_cflag &= ~CSIZE;
+       new->c_cflag |= CS8;
+
+       /* Only one stop bit is supported */
+       new->c_cflag &= ~CSTOPB;
+
+       cs = 0;
+       if (new->c_cflag & PARENB) {
+               if (!(new->c_cflag & PARODD))
+                       cs |= AR933X_UART_CS_PARITY_EVEN;
+               else
+                       cs |= AR933X_UART_CS_PARITY_ODD;
+       } else {
+               cs |= AR933X_UART_CS_PARITY_NONE;
+       }
+
+       /* Mark/space parity is not supported */
+       new->c_cflag &= ~CMSPAR;
+
+       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
+       scale = (port->uartclk / (16 * baud)) - 1;
+
+       /*
+        * Ok, we're now changing the port state. Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /* Update the per-port timeout. */
+       uart_update_timeout(port, new->c_cflag, baud);
+
+       up->port.ignore_status_mask = 0;
+
+       /* ignore all characters if CREAD is not set */
+       if ((new->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD;
+
+       ar933x_uart_write(up, AR933X_UART_CLOCK_REG,
+                         scale << AR933X_UART_CLOCK_SCALE_S | 8192);
+
+       /* setup configuration register */
+       ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs);
+
+       /* enable host interrupt */
+       ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
+                           AR933X_UART_CS_HOST_INT_EN);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       if (tty_termios_baud_rate(new))
+               tty_termios_encode_baud_rate(new, baud, baud);
+}
+
+static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
+{
+       struct tty_struct *tty;
+       int max_count = 256;
+
+       tty = tty_port_tty_get(&up->port.state->port);
+       do {
+               unsigned int rdata;
+               unsigned char ch;
+
+               rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG);
+               if ((rdata & AR933X_UART_DATA_RX_CSR) == 0)
+                       break;
+
+               /* remove the character from the FIFO */
+               ar933x_uart_write(up, AR933X_UART_DATA_REG,
+                                 AR933X_UART_DATA_RX_CSR);
+
+               if (!tty) {
+                       /* discard the data if no tty available */
+                       continue;
+               }
+
+               up->port.icount.rx++;
+               ch = rdata & AR933X_UART_DATA_TX_RX_MASK;
+
+               if (uart_handle_sysrq_char(&up->port, ch))
+                       continue;
+
+               if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0)
+                       tty_insert_flip_char(tty, ch, TTY_NORMAL);
+       } while (max_count-- > 0);
+
+       if (tty) {
+               tty_flip_buffer_push(tty);
+               tty_kref_put(tty);
+       }
+}
+
+static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
+{
+       struct circ_buf *xmit = &up->port.state->xmit;
+       int count;
+
+       if (uart_tx_stopped(&up->port))
+               return;
+
+       count = up->port.fifosize;
+       do {
+               unsigned int rdata;
+
+               rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG);
+               if ((rdata & AR933X_UART_DATA_TX_CSR) == 0)
+                       break;
+
+               if (up->port.x_char) {
+                       ar933x_uart_putc(up, up->port.x_char);
+                       up->port.icount.tx++;
+                       up->port.x_char = 0;
+                       continue;
+               }
+
+               if (uart_circ_empty(xmit))
+                       break;
+
+               ar933x_uart_putc(up, xmit->buf[xmit->tail]);
+
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       if (!uart_circ_empty(xmit))
+               ar933x_uart_start_tx_interrupt(up);
+}
+
+static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id)
+{
+       struct ar933x_uart_port *up = dev_id;
+       unsigned int status;
+
+       status = ar933x_uart_read(up, AR933X_UART_CS_REG);
+       if ((status & AR933X_UART_CS_HOST_INT) == 0)
+               return IRQ_NONE;
+
+       spin_lock(&up->port.lock);
+
+       status = ar933x_uart_read(up, AR933X_UART_INT_REG);
+       status &= ar933x_uart_read(up, AR933X_UART_INT_EN_REG);
+
+       if (status & AR933X_UART_INT_RX_VALID) {
+               ar933x_uart_write(up, AR933X_UART_INT_REG,
+                                 AR933X_UART_INT_RX_VALID);
+               ar933x_uart_rx_chars(up);
+       }
+
+       if (status & AR933X_UART_INT_TX_EMPTY) {
+               ar933x_uart_write(up, AR933X_UART_INT_REG,
+                                 AR933X_UART_INT_TX_EMPTY);
+               ar933x_uart_stop_tx_interrupt(up);
+               ar933x_uart_tx_chars(up);
+       }
+
+       spin_unlock(&up->port.lock);
+
+       return IRQ_HANDLED;
+}
+
+static int ar933x_uart_startup(struct uart_port *port)
+{
+       struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
+       unsigned long flags;
+       int ret;
+
+       ret = request_irq(up->port.irq, ar933x_uart_interrupt,
+                         up->port.irqflags, dev_name(up->port.dev), up);
+       if (ret)
+               return ret;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       /* Enable HOST interrupts */
+       ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
+                           AR933X_UART_CS_HOST_INT_EN);
+
+       /* Enable RX interrupts */
+       up->ier = AR933X_UART_INT_RX_VALID;
+       ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return 0;
+}
+
+static void ar933x_uart_shutdown(struct uart_port *port)
+{
+       struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
+
+       /* Disable all interrupts */
+       up->ier = 0;
+       ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
+
+       /* Disable break condition */
+       ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
+                             AR933X_UART_CS_TX_BREAK);
+
+       free_irq(up->port.irq, up);
+}
+
+static const char *ar933x_uart_type(struct uart_port *port)
+{
+       return (port->type == PORT_AR933X) ? "AR933X UART" : NULL;
+}
+
+static void ar933x_uart_release_port(struct uart_port *port)
+{
+       /* Nothing to release ... */
+}
+
+static int ar933x_uart_request_port(struct uart_port *port)
+{
+       /* UARTs always present */
+       return 0;
+}
+
+static void ar933x_uart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE)
+               port->type = PORT_AR933X;
+}
+
+static int ar933x_uart_verify_port(struct uart_port *port,
+                                  struct serial_struct *ser)
+{
+       if (ser->type != PORT_UNKNOWN &&
+           ser->type != PORT_AR933X)
+               return -EINVAL;
+
+       if (ser->irq < 0 || ser->irq >= NR_IRQS)
+               return -EINVAL;
+
+       if (ser->baud_base < 28800)
+               return -EINVAL;
+
+       return 0;
+}
+
+static struct uart_ops ar933x_uart_ops = {
+       .tx_empty       = ar933x_uart_tx_empty,
+       .set_mctrl      = ar933x_uart_set_mctrl,
+       .get_mctrl      = ar933x_uart_get_mctrl,
+       .stop_tx        = ar933x_uart_stop_tx,
+       .start_tx       = ar933x_uart_start_tx,
+       .stop_rx        = ar933x_uart_stop_rx,
+       .enable_ms      = ar933x_uart_enable_ms,
+       .break_ctl      = ar933x_uart_break_ctl,
+       .startup        = ar933x_uart_startup,
+       .shutdown       = ar933x_uart_shutdown,
+       .set_termios    = ar933x_uart_set_termios,
+       .type           = ar933x_uart_type,
+       .release_port   = ar933x_uart_release_port,
+       .request_port   = ar933x_uart_request_port,
+       .config_port    = ar933x_uart_config_port,
+       .verify_port    = ar933x_uart_verify_port,
+};
+
+#ifdef CONFIG_SERIAL_AR933X_CONSOLE
+
+static struct ar933x_uart_port *
+ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS];
+
+static void ar933x_uart_wait_xmitr(struct ar933x_uart_port *up)
+{
+       unsigned int status;
+       unsigned int timeout = 60000;
+
+       /* Wait up to 60ms for the character(s) to be sent. */
+       do {
+               status = ar933x_uart_read(up, AR933X_UART_DATA_REG);
+               if (--timeout == 0)
+                       break;
+               udelay(1);
+       } while ((status & AR933X_UART_DATA_TX_CSR) == 0);
+}
+
+static void ar933x_uart_console_putchar(struct uart_port *port, int ch)
+{
+       struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
+
+       ar933x_uart_wait_xmitr(up);
+       ar933x_uart_putc(up, ch);
+}
+
+static void ar933x_uart_console_write(struct console *co, const char *s,
+                                     unsigned int count)
+{
+       struct ar933x_uart_port *up = ar933x_console_ports[co->index];
+       unsigned long flags;
+       unsigned int int_en;
+       int locked = 1;
+
+       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
+        */
+       int_en = ar933x_uart_read(up, AR933X_UART_INT_EN_REG);
+       ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0);
+
+       uart_console_write(&up->port, s, count, ar933x_uart_console_putchar);
+
+       /*
+        * Finally, wait for transmitter to become empty
+        * and restore the IER
+        */
+       ar933x_uart_wait_xmitr(up);
+       ar933x_uart_write(up, AR933X_UART_INT_EN_REG, int_en);
+
+       ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+
+       local_irq_restore(flags);
+}
+
+static int ar933x_uart_console_setup(struct console *co, char *options)
+{
+       struct ar933x_uart_port *up;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index < 0 || co->index >= CONFIG_SERIAL_AR933X_NR_UARTS)
+               return -EINVAL;
+
+       up = ar933x_console_ports[co->index];
+       if (!up)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(&up->port, co, baud, parity, bits, flow);
+}
+
+static struct console ar933x_uart_console = {
+       .name           = "ttyATH",
+       .write          = ar933x_uart_console_write,
+       .device         = uart_console_device,
+       .setup          = ar933x_uart_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &ar933x_uart_driver,
+};
+
+static void ar933x_uart_add_console_port(struct ar933x_uart_port *up)
+{
+       ar933x_console_ports[up->port.line] = up;
+}
+
+#define AR933X_SERIAL_CONSOLE  (&ar933x_uart_console)
+
+#else
+
+static inline void ar933x_uart_add_console_port(struct ar933x_uart_port *up) {}
+
+#define AR933X_SERIAL_CONSOLE  NULL
+
+#endif /* CONFIG_SERIAL_AR933X_CONSOLE */
+
+static struct uart_driver ar933x_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = DRIVER_NAME,
+       .dev_name       = "ttyATH",
+       .nr             = CONFIG_SERIAL_AR933X_NR_UARTS,
+       .cons           = AR933X_SERIAL_CONSOLE,
+};
+
+static int __devinit ar933x_uart_probe(struct platform_device *pdev)
+{
+       struct ar933x_uart_platform_data *pdata;
+       struct ar933x_uart_port *up;
+       struct uart_port *port;
+       struct resource *mem_res;
+       struct resource *irq_res;
+       int id;
+       int ret;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata)
+               return -EINVAL;
+
+       id = pdev->id;
+       if (id == -1)
+               id = 0;
+
+       if (id > CONFIG_SERIAL_AR933X_NR_UARTS)
+               return -EINVAL;
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_res) {
+               dev_err(&pdev->dev, "no MEM resource\n");
+               return -EINVAL;
+       }
+
+       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq_res) {
+               dev_err(&pdev->dev, "no IRQ resource\n");
+               return -EINVAL;
+       }
+
+       up = kzalloc(sizeof(struct ar933x_uart_port), GFP_KERNEL);
+       if (!up)
+               return -ENOMEM;
+
+       port = &up->port;
+       port->mapbase = mem_res->start;
+
+       port->membase = ioremap(mem_res->start, AR933X_UART_REGS_SIZE);
+       if (!port->membase) {
+               ret = -ENOMEM;
+               goto err_free_up;
+       }
+
+       port->line = id;
+       port->irq = irq_res->start;
+       port->dev = &pdev->dev;
+       port->type = PORT_AR933X;
+       port->iotype = UPIO_MEM32;
+       port->uartclk = pdata->uartclk;
+
+       port->regshift = 2;
+       port->fifosize = AR933X_UART_FIFO_SIZE;
+       port->ops = &ar933x_uart_ops;
+
+       ar933x_uart_add_console_port(up);
+
+       ret = uart_add_one_port(&ar933x_uart_driver, &up->port);
+       if (ret)
+               goto err_unmap;
+
+       platform_set_drvdata(pdev, up);
+       return 0;
+
+err_unmap:
+       iounmap(up->port.membase);
+err_free_up:
+       kfree(up);
+       return ret;
+}
+
+static int __devexit ar933x_uart_remove(struct platform_device *pdev)
+{
+       struct ar933x_uart_port *up;
+
+       up = platform_get_drvdata(pdev);
+       platform_set_drvdata(pdev, NULL);
+
+       if (up) {
+               uart_remove_one_port(&ar933x_uart_driver, &up->port);
+               iounmap(up->port.membase);
+               kfree(up);
+       }
+
+       return 0;
+}
+
+static struct platform_driver ar933x_uart_platform_driver = {
+       .probe          = ar933x_uart_probe,
+       .remove         = __devexit_p(ar933x_uart_remove),
+       .driver         = {
+               .name           = DRIVER_NAME,
+               .owner          = THIS_MODULE,
+       },
+};
+
+static int __init ar933x_uart_init(void)
+{
+       int ret;
+
+       ar933x_uart_driver.nr = CONFIG_SERIAL_AR933X_NR_UARTS;
+       ret = uart_register_driver(&ar933x_uart_driver);
+       if (ret)
+               goto err_out;
+
+       ret = platform_driver_register(&ar933x_uart_platform_driver);
+       if (ret)
+               goto err_unregister_uart_driver;
+
+       return 0;
+
+err_unregister_uart_driver:
+       uart_unregister_driver(&ar933x_uart_driver);
+err_out:
+       return ret;
+}
+
+static void __exit ar933x_uart_exit(void)
+{
+       platform_driver_unregister(&ar933x_uart_platform_driver);
+       uart_unregister_driver(&ar933x_uart_driver);
+}
+
+module_init(ar933x_uart_init);
+module_exit(ar933x_uart_exit);
+
+MODULE_DESCRIPTION("Atheros AR933X UART driver");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
index de0f613ed6f56051df309abc3ad25ea804081006..17ae65762d1a465f83ae92d9e64128419c2e077c 100644 (file)
@@ -764,7 +764,7 @@ static int dma_handle_rx(struct eg20t_port *priv)
        sg_dma_address(sg) = priv->rx_buf_dma;
 
        desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx,
-                       sg, 1, DMA_FROM_DEVICE,
+                       sg, 1, DMA_DEV_TO_MEM,
                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 
        if (!desc)
@@ -923,7 +923,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
        }
 
        desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx,
-                                       priv->sg_tx_p, nent, DMA_TO_DEVICE,
+                                       priv->sg_tx_p, nent, DMA_MEM_TO_DEV,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc) {
                dev_err(priv->port.dev, "%s:device_prep_slave_sg Failed\n",
index 9e62349b3d9f22cfeb59d2fcea49da4b068aac34..75085795528edd172568dedd2a82f5b160246029 100644 (file)
@@ -1339,7 +1339,7 @@ static void sci_submit_rx(struct sci_port *s)
                struct dma_async_tx_descriptor *desc;
 
                desc = chan->device->device_prep_slave_sg(chan,
-                       sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT);
+                       sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
 
                if (desc) {
                        s->desc_rx[i] = desc;
@@ -1454,7 +1454,7 @@ static void work_fn_tx(struct work_struct *work)
        BUG_ON(!sg_dma_len(sg));
 
        desc = chan->device->device_prep_slave_sg(chan,
-                       sg, s->sg_len_tx, DMA_TO_DEVICE,
+                       sg, s->sg_len_tx, DMA_MEM_TO_DEV,
                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc) {
                /* switch to PIO */
index e67fb20490d257ddf02a4df8811daf98d0760264..ff8017f87914ce777a7d3ec5a0ab7abf8c9f0785 100644 (file)
@@ -850,7 +850,7 @@ static int mgsl_device_count;
  * .text section address and breakpoint on module load.
  * This is useful for use with gdb and add-symbol-file command.
  */
-static int break_on_load;
+static bool break_on_load;
 
 /*
  * Driver major number, defaults to zero to get auto
index 0f6b796c95c55015442f9ac1b02ecd89673527f6..a7efe538df000e3c005717cd464ae4ed6a80d538 100644 (file)
@@ -456,7 +456,7 @@ static int synclinkmp_device_count = 0;
  * .text section address and breakpoint on module load.
  * This is useful for use with gdb and add-symbol-file command.
  */
-static int break_on_load = 0;
+static bool break_on_load = 0;
 
 /*
  * Driver major number, defaults to zero to get auto
index b42092e1f1643c580bc09414111867279926b840..98dd9e49b684be5ef56b2960b52bc031a536331f 100644 (file)
@@ -73,9 +73,9 @@ static const char speedtch_driver_name[] = "speedtch";
 #define DEFAULT_SW_BUFFERING   0
 
 static unsigned int altsetting = 0; /* zero means: use the default */
-static int dl_512_first = DEFAULT_DL_512_FIRST;
-static int enable_isoc = DEFAULT_ENABLE_ISOC;
-static int sw_buffering = DEFAULT_SW_BUFFERING;
+static bool dl_512_first = DEFAULT_DL_512_FIRST;
+static bool enable_isoc = DEFAULT_ENABLE_ISOC;
+static bool sw_buffering = DEFAULT_SW_BUFFERING;
 
 #define DEFAULT_B_MAX_DSL      8128
 #define DEFAULT_MODEM_MODE     11
index 00f171a7a8a01f91f5d58ebc4d1e51851e3e5b55..01ea5d7421d47a5c02c5993b30802345cf0c11fe 100644 (file)
@@ -542,7 +542,7 @@ static int modem_index;
 static unsigned int debug;
 static unsigned int altsetting[NB_MODEM] = {
                                [0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};
-static int sync_wait[NB_MODEM];
+static bool sync_wait[NB_MODEM];
 static char *cmv_file[NB_MODEM];
 static int annex[NB_MODEM];
 
index 3af5e2dd1d82743b1a6d92786401caab7fc8989c..8df4b76465ac7d0b5eb0617b6ca2b6d7aec70c06 100644 (file)
@@ -93,7 +93,7 @@ struct async {
        u8 bulk_status;
 };
 
-static int usbfs_snoop;
+static bool usbfs_snoop;
 module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
 
index 79d339e2e700589b0f91c6b2935ba09989dd1ff5..a0613d8f9be785bf0a52827acf2522b109bce1b2 100644 (file)
@@ -102,7 +102,7 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
 static struct task_struct *khubd_task;
 
 /* cycle leds on hubs that aren't blinking for attention */
-static int blinkenlights = 0;
+static bool blinkenlights = 0;
 module_param (blinkenlights, bool, S_IRUGO);
 MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs");
 
@@ -131,12 +131,12 @@ MODULE_PARM_DESC(initial_descriptor_timeout,
  * otherwise the new scheme is used.  If that fails and "use_both_schemes"
  * is set, then the driver will make another attempt, using the other scheme.
  */
-static int old_scheme_first = 0;
+static bool old_scheme_first = 0;
 module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(old_scheme_first,
                 "start with the old device initialization scheme");
 
-static int use_both_schemes = 1;
+static bool use_both_schemes = 1;
 module_param(use_both_schemes, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(use_both_schemes,
                "try the other device initialization scheme if the "
@@ -2026,7 +2026,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
 #define SET_ADDRESS_TRIES      2
 #define GET_DESCRIPTOR_TRIES   2
 #define SET_CONFIG_TRIES       (2 * (use_both_schemes + 1))
-#define USE_NEW_SCHEME(i)      ((i) / 2 == old_scheme_first)
+#define USE_NEW_SCHEME(i)      ((i) / 2 == (int)old_scheme_first)
 
 #define HUB_ROOT_RESET_TIME    50      /* times are in msec */
 #define HUB_SHORT_RESET_TIME   10
index 1382c90d0834859c946c272d93859b4b1185a96c..8ca9f994a280c625096f8f227d830cb5af6febad 100644 (file)
@@ -47,7 +47,7 @@
 
 const char *usbcore_name = "usbcore";
 
-static int nousb;      /* Disable USB when built into kernel image */
+static bool nousb;     /* Disable USB when built into kernel image */
 
 #ifdef CONFIG_USB_SUSPEND
 static int usb_autosuspend_delay = 2;          /* Default delay value,
index e9a2c5c44454f18eb89a1608dccaee0136ba9f1a..c16ff55a74e84696ec26afe376547c5af42a9dd8 100644 (file)
@@ -152,15 +152,15 @@ static const char *ep_string[] = {
 };
 
 /* DMA usage flag */
-static int use_dma = 1;
+static bool use_dma = 1;
 /* packet per buffer dma */
-static int use_dma_ppb = 1;
+static bool use_dma_ppb = 1;
 /* with per descr. update */
-static int use_dma_ppb_du;
+static bool use_dma_ppb_du;
 /* buffer fill mode */
 static int use_dma_bufferfill_mode;
 /* full speed only mode */
-static int use_fullspeed;
+static bool use_fullspeed;
 /* tx buffer size for high speed */
 static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
 
index 0cd764d59351e3331b8f25ee5a6399f0dace245a..a28f6ffcd0f31683d701bfd527ba1c110c92be4a 100644 (file)
@@ -250,9 +250,9 @@ static struct usb_configuration rndis_config_driver = {
 /*-------------------------------------------------------------------------*/
 
 #ifdef CONFIG_USB_ETH_EEM
-static int use_eem = 1;
+static bool use_eem = 1;
 #else
-static int use_eem;
+static bool use_eem;
 #endif
 module_param(use_eem, bool, 0);
 MODULE_PARM_DESC(use_eem, "use CDC EEM mode");
index e0f30fc70e45b8e787f46b86fd91e75415052fe6..47766f0e7caa320796f7894d8144a3933ff1393f 100644 (file)
@@ -303,16 +303,16 @@ MODULE_LICENSE("Dual BSD/GPL");
 static struct {
        char            *file[FSG_MAX_LUNS];
        char            *serial;
-       int             ro[FSG_MAX_LUNS];
-       int             nofua[FSG_MAX_LUNS];
+       bool            ro[FSG_MAX_LUNS];
+       bool            nofua[FSG_MAX_LUNS];
        unsigned int    num_filenames;
        unsigned int    num_ros;
        unsigned int    num_nofuas;
        unsigned int    nluns;
 
-       int             removable;
-       int             can_stall;
-       int             cdrom;
+       bool            removable;
+       bool            can_stall;
+       bool            cdrom;
 
        char            *transport_parm;
        char            *protocol_parm;
index 4c81d540bc2696529a2c4a090ab0ed86037fbecd..7322d293213e142e2f469d6366eceaa5c32b4017 100644 (file)
@@ -69,7 +69,7 @@ static const char * const ep_name[] = {
  *
  * If use_dma is disabled, pio will be used instead.
  */
-static int use_dma = 0;
+static bool use_dma = 0;
 module_param(use_dma, bool, 0644);
 
 /*
index cf1f36454d0860fee87933281bb1e5cfaed168b2..cdedd1336745ae5d1a822a1dbbad25d410d54f27 100644 (file)
@@ -90,8 +90,8 @@ static const char *const ep_name [] = {
  * Some gadget drivers work better with the dma support here than others.
  * These two parameters let you use PIO or more aggressive DMA.
  */
-static int use_dma = 1;
-static int use_dma_chaining = 0;
+static bool use_dma = 1;
+static bool use_dma_chaining = 0;
 
 /* "modprobe net2280 use_dma=n" etc */
 module_param (use_dma, bool, S_IRUGO);
@@ -112,7 +112,7 @@ module_param (fifo_mode, ushort, 0644);
  * USB suspend requests will be ignored.  This is acceptable for
  * self-powered devices
  */
-static int enable_suspend = 0;
+static bool enable_suspend = 0;
 
 /* "modprobe net2280 enable_suspend=1" etc */
 module_param (enable_suspend, bool, S_IRUGO);
index 7db5bbe6251b2f02422af9dc48225ede0714b881..576cd8578b452eac99a1bd15cdb81031c34da090 100644 (file)
@@ -98,7 +98,7 @@ module_param (fifo_mode, uint, 0);
 MODULE_PARM_DESC (fifo_mode, "endpoint configuration");
 
 #ifdef USE_DMA
-static unsigned use_dma = 1;
+static bool use_dma = 1;
 
 /* "modprobe omap_udc use_dma=y", or else as a kernel
  * boot parameter "omap_udc:use_dma=y"
index dd2313cce1d35b8d5db8d67903db41202f7fff71..a3fcaae4bc2ade69ec74838f3596ecb8e00faa38 100644 (file)
@@ -359,7 +359,7 @@ struct pch_udc_dev {
 static const char      ep0_string[] = "ep0in";
 static DEFINE_SPINLOCK(udc_stall_spinlock);    /* stall spin lock */
 struct pch_udc_dev *pch_udc;           /* pointer to device object */
-static int speed_fs;
+static bool speed_fs;
 module_param_named(speed_fs, speed_fs, bool, S_IRUGO);
 MODULE_PARM_DESC(speed_fs, "true for Full speed operation");
 
index ed1b816e58d86291ecd81e6163f9c7bf5a3409d0..ad9e5b2df64267d9b18af3b770351a04069dd0e1 100644 (file)
@@ -123,11 +123,11 @@ MODULE_AUTHOR("Al Borchers");
 MODULE_AUTHOR("David Brownell");
 MODULE_LICENSE("GPL");
 
-static int use_acm = true;
+static bool use_acm = true;
 module_param(use_acm, bool, 0);
 MODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes");
 
-static int use_obex = false;
+static bool use_obex = false;
 module_param(use_obex, bool, 0);
 MODULE_PARM_DESC(use_obex, "Use CDC OBEX, default=no");
 
index 20697cc132d1bdbcb7c24e75f160e675123b2321..31d34832907e44e48f91e7a937e2a18df556f3f9 100644 (file)
@@ -81,7 +81,7 @@ module_param(buflen, uint, 0);
  * work better with hosts where config changes are problematic or
  * controllers (like original superh) that only support one config.
  */
-static int loopdefault = 0;
+static bool loopdefault = 0;
 module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
 
 /*-------------------------------------------------------------------------*/
index 4c0c9734251d20b463b46dbac9515a358303eb0e..91413cac97beec3d17c20aff307c4236f2a5a192 100644 (file)
@@ -219,7 +219,7 @@ config USB_CNS3XXX_EHCI
 
 config USB_EHCI_ATH79
        bool "EHCI support for AR7XXX/AR9XXX SoCs"
-       depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X)
+       depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X)
        select USB_EHCI_ROOT_HUB_TT
        default y
        ---help---
index b4192c964d0df6b4c9936b389316e50aec8ecc51..936af8359fb2007f024b0dfa6b0499afe6983241 100644 (file)
                                 USBCFG_EBE | USBCFG_EME | USBCFG_OBE |        \
                                 USBCFG_OME)
 
+/* Au1300 USB config registers */
+#define USB_DWC_CTRL1          0x00
+#define USB_DWC_CTRL2          0x04
+#define USB_VBUS_TIMER         0x10
+#define USB_SBUS_CTRL          0x14
+#define USB_MSR_ERR            0x18
+#define USB_DWC_CTRL3          0x1C
+#define USB_DWC_CTRL4          0x20
+#define USB_OTG_STATUS         0x28
+#define USB_DWC_CTRL5          0x2C
+#define USB_DWC_CTRL6          0x30
+#define USB_DWC_CTRL7          0x34
+#define USB_PHY_STATUS         0xC0
+#define USB_INT_STATUS         0xC4
+#define USB_INT_ENABLE         0xC8
+
+#define USB_DWC_CTRL1_OTGD     0x04 /* set to DISable OTG */
+#define USB_DWC_CTRL1_HSTRS    0x02 /* set to ENable EHCI */
+#define USB_DWC_CTRL1_DCRS     0x01 /* set to ENable UDC */
+
+#define USB_DWC_CTRL2_PHY1RS   0x04 /* set to enable PHY1 */
+#define USB_DWC_CTRL2_PHY0RS   0x02 /* set to enable PHY0 */
+#define USB_DWC_CTRL2_PHYRS    0x01 /* set to enable PHY */
+
+#define USB_DWC_CTRL3_OHCI1_CKEN       (1 << 19)
+#define USB_DWC_CTRL3_OHCI0_CKEN       (1 << 18)
+#define USB_DWC_CTRL3_EHCI0_CKEN       (1 << 17)
+#define USB_DWC_CTRL3_OTG0_CKEN                (1 << 16)
+
+#define USB_SBUS_CTRL_SBCA             0x04 /* coherent access */
+
+#define USB_INTEN_FORCE                        0x20
+#define USB_INTEN_PHY                  0x10
+#define USB_INTEN_UDC                  0x08
+#define USB_INTEN_EHCI                 0x04
+#define USB_INTEN_OHCI1                        0x02
+#define USB_INTEN_OHCI0                        0x01
 
 static DEFINE_SPINLOCK(alchemy_usb_lock);
 
+static inline void __au1300_usb_phyctl(void __iomem *base, int enable)
+{
+       unsigned long r, s;
+
+       r = __raw_readl(base + USB_DWC_CTRL2);
+       s = __raw_readl(base + USB_DWC_CTRL3);
+
+       s &= USB_DWC_CTRL3_OHCI1_CKEN | USB_DWC_CTRL3_OHCI0_CKEN |
+               USB_DWC_CTRL3_EHCI0_CKEN | USB_DWC_CTRL3_OTG0_CKEN;
+
+       if (enable) {
+               /* simply enable all PHYs */
+               r |= USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS |
+                    USB_DWC_CTRL2_PHYRS;
+               __raw_writel(r, base + USB_DWC_CTRL2);
+               wmb();
+       } else if (!s) {
+               /* no USB block active, do disable all PHYs */
+               r &= ~(USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS |
+                      USB_DWC_CTRL2_PHYRS);
+               __raw_writel(r, base + USB_DWC_CTRL2);
+               wmb();
+       }
+}
+
+static inline void __au1300_ohci_control(void __iomem *base, int enable, int id)
+{
+       unsigned long r;
+
+       if (enable) {
+               __raw_writel(1, base + USB_DWC_CTRL7);  /* start OHCI clock */
+               wmb();
+
+               r = __raw_readl(base + USB_DWC_CTRL3);  /* enable OHCI block */
+               r |= (id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN
+                              : USB_DWC_CTRL3_OHCI1_CKEN;
+               __raw_writel(r, base + USB_DWC_CTRL3);
+               wmb();
+
+               __au1300_usb_phyctl(base, enable);      /* power up the PHYs */
+
+               r = __raw_readl(base + USB_INT_ENABLE);
+               r |= (id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1;
+               __raw_writel(r, base + USB_INT_ENABLE);
+               wmb();
+
+               /* reset the OHCI start clock bit */
+               __raw_writel(0, base + USB_DWC_CTRL7);
+               wmb();
+       } else {
+               r = __raw_readl(base + USB_INT_ENABLE);
+               r &= ~((id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1);
+               __raw_writel(r, base + USB_INT_ENABLE);
+               wmb();
+
+               r = __raw_readl(base + USB_DWC_CTRL3);
+               r &= ~((id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN
+                                : USB_DWC_CTRL3_OHCI1_CKEN);
+               __raw_writel(r, base + USB_DWC_CTRL3);
+               wmb();
+
+               __au1300_usb_phyctl(base, enable);
+       }
+}
+
+static inline void __au1300_ehci_control(void __iomem *base, int enable)
+{
+       unsigned long r;
+
+       if (enable) {
+               r = __raw_readl(base + USB_DWC_CTRL3);
+               r |= USB_DWC_CTRL3_EHCI0_CKEN;
+               __raw_writel(r, base + USB_DWC_CTRL3);
+               wmb();
+
+               r = __raw_readl(base + USB_DWC_CTRL1);
+               r |= USB_DWC_CTRL1_HSTRS;
+               __raw_writel(r, base + USB_DWC_CTRL1);
+               wmb();
+
+               __au1300_usb_phyctl(base, enable);
+
+               r = __raw_readl(base + USB_INT_ENABLE);
+               r |= USB_INTEN_EHCI;
+               __raw_writel(r, base + USB_INT_ENABLE);
+               wmb();
+       } else {
+               r = __raw_readl(base + USB_INT_ENABLE);
+               r &= ~USB_INTEN_EHCI;
+               __raw_writel(r, base + USB_INT_ENABLE);
+               wmb();
+
+               r = __raw_readl(base + USB_DWC_CTRL1);
+               r &= ~USB_DWC_CTRL1_HSTRS;
+               __raw_writel(r, base + USB_DWC_CTRL1);
+               wmb();
+
+               r = __raw_readl(base + USB_DWC_CTRL3);
+               r &= ~USB_DWC_CTRL3_EHCI0_CKEN;
+               __raw_writel(r, base + USB_DWC_CTRL3);
+               wmb();
+
+               __au1300_usb_phyctl(base, enable);
+       }
+}
+
+static inline void __au1300_udc_control(void __iomem *base, int enable)
+{
+       unsigned long r;
+
+       if (enable) {
+               r = __raw_readl(base + USB_DWC_CTRL1);
+               r |= USB_DWC_CTRL1_DCRS;
+               __raw_writel(r, base + USB_DWC_CTRL1);
+               wmb();
+
+               __au1300_usb_phyctl(base, enable);
+
+               r = __raw_readl(base + USB_INT_ENABLE);
+               r |= USB_INTEN_UDC;
+               __raw_writel(r, base + USB_INT_ENABLE);
+               wmb();
+       } else {
+               r = __raw_readl(base + USB_INT_ENABLE);
+               r &= ~USB_INTEN_UDC;
+               __raw_writel(r, base + USB_INT_ENABLE);
+               wmb();
+
+               r = __raw_readl(base + USB_DWC_CTRL1);
+               r &= ~USB_DWC_CTRL1_DCRS;
+               __raw_writel(r, base + USB_DWC_CTRL1);
+               wmb();
+
+               __au1300_usb_phyctl(base, enable);
+       }
+}
+
+static inline void __au1300_otg_control(void __iomem *base, int enable)
+{
+       unsigned long r;
+       if (enable) {
+               r = __raw_readl(base + USB_DWC_CTRL3);
+               r |= USB_DWC_CTRL3_OTG0_CKEN;
+               __raw_writel(r, base + USB_DWC_CTRL3);
+               wmb();
+
+               r = __raw_readl(base + USB_DWC_CTRL1);
+               r &= ~USB_DWC_CTRL1_OTGD;
+               __raw_writel(r, base + USB_DWC_CTRL1);
+               wmb();
+
+               __au1300_usb_phyctl(base, enable);
+       } else {
+               r = __raw_readl(base + USB_DWC_CTRL1);
+               r |= USB_DWC_CTRL1_OTGD;
+               __raw_writel(r, base + USB_DWC_CTRL1);
+               wmb();
+
+               r = __raw_readl(base + USB_DWC_CTRL3);
+               r &= ~USB_DWC_CTRL3_OTG0_CKEN;
+               __raw_writel(r, base + USB_DWC_CTRL3);
+               wmb();
+
+               __au1300_usb_phyctl(base, enable);
+       }
+}
+
+static inline int au1300_usb_control(int block, int enable)
+{
+       void __iomem *base =
+               (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR);
+       int ret = 0;
+
+       switch (block) {
+       case ALCHEMY_USB_OHCI0:
+               __au1300_ohci_control(base, enable, 0);
+               break;
+       case ALCHEMY_USB_OHCI1:
+               __au1300_ohci_control(base, enable, 1);
+               break;
+       case ALCHEMY_USB_EHCI0:
+               __au1300_ehci_control(base, enable);
+               break;
+       case ALCHEMY_USB_UDC0:
+               __au1300_udc_control(base, enable);
+               break;
+       case ALCHEMY_USB_OTG0:
+               __au1300_otg_control(base, enable);
+               break;
+       default:
+               ret = -ENODEV;
+       }
+       return ret;
+}
+
+static inline void au1300_usb_init(void)
+{
+       void __iomem *base =
+               (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR);
+
+       /* set some sane defaults.  Note: we don't fiddle with DWC_CTRL4
+        * here at all: Port 2 routing (EHCI or UDC) must be set either
+        * by boot firmware or platform init code; I can't autodetect
+        * a sane setting.
+        */
+       __raw_writel(0, base + USB_INT_ENABLE); /* disable all USB irqs */
+       wmb();
+       __raw_writel(0, base + USB_DWC_CTRL3); /* disable all clocks */
+       wmb();
+       __raw_writel(~0, base + USB_MSR_ERR); /* clear all errors */
+       wmb();
+       __raw_writel(~0, base + USB_INT_STATUS); /* clear int status */
+       wmb();
+       /* set coherent access bit */
+       __raw_writel(USB_SBUS_CTRL_SBCA, base + USB_SBUS_CTRL);
+       wmb();
+}
 
 static inline void __au1200_ohci_control(void __iomem *base, int enable)
 {
@@ -233,6 +487,9 @@ int alchemy_usb_control(int block, int enable)
        case ALCHEMY_CPU_AU1200:
                ret = au1200_usb_control(block, enable);
                break;
+       case ALCHEMY_CPU_AU1300:
+               ret = au1300_usb_control(block, enable);
+               break;
        default:
                ret = -ENODEV;
        }
@@ -281,6 +538,20 @@ static void au1200_usb_pm(int susp)
        }
 }
 
+static void au1300_usb_pm(int susp)
+{
+       void __iomem *base =
+                       (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR);
+       /* remember Port2 routing */
+       if (susp) {
+               alchemy_usb_pmdata[0] = __raw_readl(base + USB_DWC_CTRL4);
+       } else {
+               au1300_usb_init();
+               __raw_writel(alchemy_usb_pmdata[0], base + USB_DWC_CTRL4);
+               wmb();
+       }
+}
+
 static void alchemy_usb_pm(int susp)
 {
        switch (alchemy_get_cputype()) {
@@ -295,6 +566,9 @@ static void alchemy_usb_pm(int susp)
        case ALCHEMY_CPU_AU1200:
                au1200_usb_pm(susp);
                break;
+       case ALCHEMY_CPU_AU1300:
+               au1300_usb_pm(susp);
+               break;
        }
 }
 
@@ -328,6 +602,9 @@ static int __init alchemy_usb_init(void)
        case ALCHEMY_CPU_AU1200:
                au1200_usb_init();
                break;
+       case ALCHEMY_CPU_AU1300:
+               au1300_usb_init();
+               break;
        }
 
        register_syscore_ops(&alchemy_usb_pm_ops);
index afb6743cf09401876bea18affd21f07b2c3f394c..f1424f9bc363d4edaac0fdce5b60a9f81ec447cb 100644 (file)
@@ -32,6 +32,10 @@ static const struct platform_device_id ehci_ath79_id_table[] = {
                .name           = "ar913x-ehci",
                .driver_data    = EHCI_ATH79_IP_V2,
        },
+       {
+               .name           = "ar933x-ehci",
+               .driver_data    = EHCI_ATH79_IP_V2,
+       },
        {
                /* terminating entry */
        },
index e311a511529babe7f4da7f67c8bd5dc988deee6c..a007a9fe0f874a3bbb8ba2c63e37e7d2e0de1ac5 100644 (file)
@@ -112,7 +112,7 @@ module_param (park, uint, S_IRUGO);
 MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets");
 
 /* for flakey hardware, ignore overcurrent indicators */
-static int ignore_oc = 0;
+static bool ignore_oc = 0;
 module_param (ignore_oc, bool, S_IRUGO);
 MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
 
index 32793ce3d9e9dd4a32588204d5a59680046374e6..9c2cc4633894b152047ed587b2cf9494d5fdc684 100644 (file)
@@ -183,7 +183,7 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
        }
 
        irq = irq_of_parse_and_map(dn, 0);
-       if (irq == NO_IRQ) {
+       if (!irq) {
                printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
                rv = -EBUSY;
                goto err_irq;
index 40d886adff536374a3c81808532199f3be8eb524..4ea63b2cac422cf20d706d6899e85520145388d3 100644 (file)
@@ -89,7 +89,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
 
 static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 {
-       int ret;
+       int ret, unit;
        struct usb_hcd *hcd;
 
        if (usb_disabled())
@@ -120,7 +120,9 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
                goto err2;
        }
 
-       if (alchemy_usb_control(ALCHEMY_USB_OHCI0, 1)) {
+       unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ?
+                       ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0;
+       if (alchemy_usb_control(unit, 1)) {
                printk(KERN_INFO "%s: controller init failed!\n", pdev->name);
                ret = -ENODEV;
                goto err3;
@@ -135,7 +137,7 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
                return ret;
        }
 
-       alchemy_usb_control(ALCHEMY_USB_OHCI0, 0);
+       alchemy_usb_control(unit, 0);
 err3:
        iounmap(hcd->regs);
 err2:
@@ -148,9 +150,12 @@ err1:
 static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
+       int unit;
 
+       unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ?
+                       ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0;
        usb_remove_hcd(hcd);
-       alchemy_usb_control(ALCHEMY_USB_OHCI0, 0);
+       alchemy_usb_control(unit, 0);
        iounmap(hcd->regs);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
index 5f5a63241436ce70c90ca00434b666ce89731428..34b9edd866513fe93577444cc82e9327d33e0b06 100644 (file)
@@ -115,13 +115,13 @@ static inline void sb800_prefetch(struct ohci_hcd *ohci, int on)
 
 
 /* Some boards misreport power switching/overcurrent */
-static int distrust_firmware = 1;
+static bool distrust_firmware = 1;
 module_param (distrust_firmware, bool, 0);
 MODULE_PARM_DESC (distrust_firmware,
        "true to distrust firmware power/overcurrent setup");
 
 /* Some boards leave IR set wrongly, since they fail BIOS/SMM handshakes */
-static int no_handshake = 0;
+static bool no_handshake = 0;
 module_param (no_handshake, bool, 0);
 MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
 
index 6f62de5c6e352a9cd5dad5baaf7b4f20a894a926..015c7c62ed49eb4879257e1bb393dce079c59e81 100644 (file)
@@ -233,7 +233,7 @@ module_param(park, uint, S_IRUGO);
 MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets");
 
 /* For flakey hardware, ignore overcurrent indicators */
-static int ignore_oc;
+static bool ignore_oc;
 module_param(ignore_oc, bool, S_IRUGO);
 MODULE_PARM_DESC(ignore_oc, "ignore bogus hardware overcurrent indications");
 
index 533d12cca371db9c122033f18aeb346f242b4589..16dd6a6abf007ced8c0be9204350a865318c50e8 100644 (file)
@@ -74,7 +74,7 @@ MODULE_LICENSE("GPL");
 #define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
 INT_MODULE_PARM(testing, 0);
 /* Some boards misreport power switching/overcurrent*/
-static int distrust_firmware = 1;
+static bool distrust_firmware = 1;
 module_param(distrust_firmware, bool, 0);
 MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren"
        "t setup");
index c8ae199cfbb883178f74ccceffbd2cea468bd2fd..6b5eb1017e2ca601044e3d1856d87070b0d21328 100644 (file)
@@ -59,7 +59,7 @@
 #define DRIVER_DESC "USB Universal Host Controller Interface driver"
 
 /* for flakey hardware, ignore overcurrent indicators */
-static int ignore_oc;
+static bool ignore_oc;
 module_param(ignore_oc, bool, S_IRUGO);
 MODULE_PARM_DESC(ignore_oc, "ignore hardware overcurrent indications");
 
index 2dbe600fbc1137bda53ecfae1a4468061f4a30ba..a4a3c7cd4a11c751b0be3d71d9040ea5ae22ea0f 100644 (file)
@@ -53,7 +53,7 @@ MODULE_AUTHOR("Tony Olech");
 MODULE_DESCRIPTION("FTDI ELAN driver");
 MODULE_LICENSE("GPL");
 #define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
-static int distrust_firmware = 1;
+static bool distrust_firmware = 1;
 module_param(distrust_firmware, bool, 0);
 MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren"
         "t setup");
index 2453a39b4794be15441deaf0763fef08cbf4571f..4fd0dc835ae566e1a115e363c23e5e3ccba5ef0e 100644 (file)
@@ -62,7 +62,7 @@ MODULE_LICENSE("GPL");
 
 /* Module parameters */
 static DEFINE_MUTEX(iowarrior_mutex);
-static int debug = 0;
+static bool debug = 0;
 module_param(debug, bool, 0644);
 MODULE_PARM_DESC(debug, "debug=1 enables debugging messages");
 
index 53be7aef6308fcb991aa3f2a04c8b9c3a74731ad..66bc376005d250f09cee76ea804f9ad8e5a48751 100644 (file)
@@ -750,7 +750,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
  * So this module parameter lets the heuristic be disabled.  When using
  * gadgetfs, the heuristic will probably need to be disabled.
  */
-static int cppi_rx_rndis = 1;
+static bool cppi_rx_rndis = 1;
 
 module_param(cppi_rx_rndis, bool, 0);
 MODULE_PARM_DESC(cppi_rx_rndis, "enable/disable RX RNDIS heuristic");
index f6ff7923048b1072c5790cfab5ffb1fb39d8e444..56cf0243979e504df48742f447dd1e6c977ab924 100644 (file)
@@ -1586,7 +1586,7 @@ irqreturn_t musb_interrupt(struct musb *musb)
 EXPORT_SYMBOL_GPL(musb_interrupt);
 
 #ifndef CONFIG_MUSB_PIO_ONLY
-static int __initdata use_dma = 1;
+static bool __initdata use_dma = 1;
 
 /* "modprobe ... use_dma=0" etc */
 module_param(use_dma, bool, 0);
index a163632877afa5a0a68fdbeb297c721ef2308273..97cb45916c4351110e3a21fb2613c2954855ee9b 100644 (file)
@@ -84,7 +84,7 @@ static bool ux500_configure_channel(struct dma_channel *channel,
        struct musb_hw_ep *hw_ep = ux500_channel->hw_ep;
        struct dma_chan *dma_chan = ux500_channel->dma_chan;
        struct dma_async_tx_descriptor *dma_desc;
-       enum dma_data_direction direction;
+       enum dma_transfer_direction direction;
        struct scatterlist sg;
        struct dma_slave_config slave_conf;
        enum dma_slave_buswidth addr_width;
@@ -104,7 +104,7 @@ static bool ux500_configure_channel(struct dma_channel *channel,
        sg_dma_address(&sg) = dma_addr;
        sg_dma_len(&sg) = len;
 
-       direction = ux500_channel->is_tx ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+       direction = ux500_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
        addr_width = (len & 0x3) ? DMA_SLAVE_BUSWIDTH_1_BYTE :
                                        DMA_SLAVE_BUSWIDTH_4_BYTES;
 
index 07ccea9ada408e30734f797d9aa81df6b610ee79..74fe6e62e0f7c6a18552d3958c3f6ad6580b80c5 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 
 #define AB8500_MAIN_WD_CTRL_REG 0x01
 #define AB8500_USB_LINE_STAT_REG 0x80
index b51fcd80d244b57ca75a540276ff45b1c1c3c8c0..72339bd6fcab862565ee222aa4ead450f1d2945d 100644 (file)
@@ -772,10 +772,10 @@ static void usbhsf_dma_prepare_tasklet(unsigned long data)
        struct dma_async_tx_descriptor *desc;
        struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt);
        struct device *dev = usbhs_priv_to_dev(priv);
-       enum dma_data_direction dir;
+       enum dma_transfer_direction dir;
        dma_cookie_t cookie;
 
-       dir = usbhs_pipe_is_dir_in(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+       dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
 
        sg_init_table(&sg, 1);
        sg_set_page(&sg, virt_to_page(pkt->dma),
index b43d07df4c44ac3c38d0b31997389669a6943613..123bf9155339c88ff8c0e428c323b08238dbe10b 100644 (file)
@@ -52,7 +52,7 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-static int debug;
+static bool debug;
 
 /* Vendor and Product ID */
 #define AIRCABLE_VID           0x16CA
index 18e875b92e001d1c290f2b95e498eea77c6b72cb..69328dcfd91ada46bbe4c5bbc43cbd212c72cc11 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 
-static int debug;
+static bool debug;
 /*
  * Version information
  */
index f9f29b289f2f076b407f83579e7e7ec6220d0688..29ffeb6279c7cd80cba7cdd46de9671085055d1a 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/usb/serial.h>
 #include "belkin_sa.h"
 
-static int debug;
+static bool debug;
 
 /*
  * Version Information
index 0e77511060c0795680941dc784753f58888ec014..5e53cc59e652c406926fc6a5f37fe8e86c975a04 100644 (file)
@@ -70,7 +70,7 @@
 #define CH341_NBREAK_BITS_REG2 0x40
 
 
-static int debug;
+static bool debug;
 
 static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x4348, 0x5523) },
index adfe660ed008f00061e75d85b159f95ac766523c..fba1147ed9169c1711027a693fcb8df5788aa031 100644 (file)
@@ -49,7 +49,7 @@ static void cp210x_break_ctl(struct tty_struct *, int);
 static int cp210x_startup(struct usb_serial *);
 static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
 
-static int debug;
+static bool debug;
 
 static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */
index 98bf83349838acdb1a98bb5e2a1861aef495e13f..6bc3802a581af7f43239869864146e69bc20c3e4 100644 (file)
@@ -43,7 +43,7 @@
 
 #define CYBERJACK_LOCAL_BUF_SIZE 32
 
-static int debug;
+static bool debug;
 
 /*
  * Version Information
index 07680d6b792b59ebff8143f851837659e3ae51dc..3bdeafa29c24d43c11ac71375c5eb93b6916a18d 100644 (file)
 #include "cypress_m8.h"
 
 
-static int debug;
-static int stats;
+static bool debug;
+static bool stats;
 static int interval;
-static int unstable_bauds;
+static bool unstable_bauds;
 
 /*
  * Version Information
index 6d26a77d0f2aedf0302696b48e5c399f44203749..b23bebd721a1f8e511a386b7667827afc8ebaa3e 100644 (file)
@@ -251,7 +251,7 @@ static int digi_read_oob_callback(struct urb *urb);
 
 /* Statics */
 
-static int debug;
+static bool debug;
 
 static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) },
index 504b5585ea4500bbea780b520cff4df748fd089b..aced6817bf95dc42d0a6c9be7b50db2552a75be0 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-static int debug;
+static bool debug;
 
 /*
  * Version Information
index c290df97108e944858b97ee62ca445f42e38aaf9..01b6404df395bd3c2a042c2f8c92b15b0905f6bd 100644 (file)
@@ -55,7 +55,7 @@
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
-static int debug;
+static bool debug;
 static __u16 vendor = FTDI_VID;
 static __u16 product;
 
index e21ce9ddfc631d824e38e9e27dd1e053a2677a11..5d4b099dcf8b5da5998e6aebaf67ccbff077db50 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/usb/serial.h>
 #include <linux/uaccess.h>
 
-static int debug;
+static bool debug;
 
 static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x1404, 0xcddc) },
index bf12565f8e87319ff82e6861ef9ef821677ef7ea..21343378c322e1ab3fd044a8f5ccdbefab43bede 100644 (file)
@@ -42,7 +42,7 @@
 static int initial_mode = 1;
 
 /* debug flag */
-static int debug;
+static bool debug;
 
 #define GARMIN_VENDOR_ID             0x091E
 
index abd2ee2b2f9942c2cdf35f1e29f0a5e83ed08b26..0497575e4799fd73fe65903dfea799ffce034518 100644 (file)
@@ -191,7 +191,7 @@ static const struct divisor_table_entry divisor_table[] = {
 };
 
 /* local variables */
-static int debug;
+static bool debug;
 
 static atomic_t CmdUrbs;       /* Number of outstanding Command Write Urbs */
 
index e44d375edaad2a785eacd7eabcfbba5d03cc26e3..65bf06aa591a091616b084943388194209b913a6 100644 (file)
@@ -210,10 +210,10 @@ static unsigned char OperationalMajorVersion;
 static unsigned char OperationalMinorVersion;
 static unsigned short OperationalBuildNumber;
 
-static int debug;
+static bool debug;
 
 static int closing_wait = EDGE_CLOSING_WAIT;
-static int ignore_cpu_rev;
+static bool ignore_cpu_rev;
 static int default_uart_mode;          /* RS232 */
 
 static void edge_tty_recv(struct device *dev, struct tty_struct *tty,
index 36f5cbe90485593aa0641d3e669ceb52fbe3bcd6..06053a920dd8dc829e1c6dc9ac6d5693f5d32643 100644 (file)
@@ -34,7 +34,7 @@
 #define DRIVER_DESC "USB PocketPC PDA driver"
 
 static __u16 product, vendor;
-static int debug;
+static bool debug;
 static int connect_retries = KP_RETRIES;
 static int initial_wait;
 
index 5170799d6e94739cffb66f3266254d900fd322f8..6f9356f3f99eb0838a610a95ee013efcfce1e7c7 100644 (file)
@@ -147,7 +147,7 @@ static struct usb_driver usb_ipw_driver = {
        .no_dynamic_id =        1,
 };
 
-static int debug;
+static bool debug;
 
 static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
index 0c537da0d3cda83d5b2bd655857a53fe803aa8ce..84a396e83671bdeca4de7ece00ac007020f418f4 100644 (file)
@@ -45,7 +45,7 @@
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Johan Hovold <jhovold@gmail.com>"
 #define DRIVER_DESC "USB IR Dongle driver"
 
-static int debug;
+static bool debug;
 
 /* if overridden by the user, then use their value for the size of the read and
  * write urbs */
index 64d0ffd4440b948a8f4aeb6e31e5b450403249a6..3077a443697601ed6e2040964f1d2c093aee1b04 100644 (file)
@@ -34,9 +34,9 @@
 
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
-static int debug = 1;
+static bool debug = 1;
 #else
-static int debug;
+static bool debug;
 #endif
 
 /*
@@ -65,7 +65,7 @@ static int clockmode = 1;
 static int cdmode = 1;
 static int iuu_cardin;
 static int iuu_cardout;
-static int xmas;
+static bool xmas;
 static int vcc_default = 5;
 
 static void read_rxcmd_callback(struct urb *urb);
index bc8dc203e818342b270104717d0133e38ef6cf8e..4cc36c76180126f80a9d81e23759318971873599 100644 (file)
@@ -45,7 +45,7 @@
 #include <linux/usb/serial.h>
 #include "keyspan.h"
 
-static int debug;
+static bool debug;
 
 /*
  * Version Information
index a40615674a6815e20ed44a7bbba1953943c176ea..7c62a7048302c78fca45a19c5e2a67feb3109415 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-static int debug;
+static bool debug;
 
 /* make a simple define to handle if we are compiling keyspan_pda or xircom support */
 #if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_KEYSPAN_PDA_MODULE)
index 19373cb7c5bfbe800c0a19bc5aa6be38f60386ae..fc064e1442ca988ae3330388cb4d855f023f1595 100644 (file)
@@ -49,7 +49,7 @@
 #include <linux/usb/serial.h>
 #include "kl5kusb105.h"
 
-static int debug;
+static bool debug;
 
 /*
  * Version Information
index a975bb80303f9ddad9b6ef62394a1d2889fcbf5a..27fa9c8a77b0745b7ccae628778d1b44ba9f41a7 100644 (file)
@@ -45,7 +45,7 @@
 #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
 #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
 
-static int debug;
+static bool debug;
 
 /*
  * Function prototypes
index 19d112f51b97516b325d07c984a7e71f03e7d665..4554ee49e635d5d4c3d283caf983555630d1b84c 100644 (file)
@@ -71,7 +71,7 @@ struct moschip_port {
        struct urb              *write_urb_pool[NUM_URBS];
 };
 
-static int debug;
+static bool debug;
 
 static struct usb_serial_driver moschip7720_2port_driver;
 
index 55cfd6265b98b7d91afb6bc1d9c91ad7245256db..03b5e249e95e1620b452cd4a000cc6ab8a8de0a8 100644 (file)
@@ -263,7 +263,7 @@ struct moschip_port {
 };
 
 
-static int debug;
+static bool debug;
 
 /*
  * mos7840_set_reg_sync
index 1f00f243c26cf5e1825632e40fc9c2a60287f9e3..b28f1db0195f8aafaf6f981c95bcdf6d3639e998 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-static int debug;
+static bool debug;
 
 static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */
index 45a8c55881d348cb52747c9c241d6573c17f0fc3..8b8d58a2ac12ad54f3e517298a68e18f9cdb6a24 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-static int debug;
+static bool debug;
 
 /*
  * Version Information
index 691f57a9d712a4b45e44137d9539595fdff83471..262ded9e076b8d91f9d145a704b0160edf396643 100644 (file)
@@ -32,7 +32,7 @@
  * an examples of 1D barcode types are EAN, UPC, Code39, IATA etc.. */
 #define DRIVER_DESC    "Opticon USB barcode to serial driver (1D)"
 
-static int debug;
+static bool debug;
 
 static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x065a, 0x0009) },
index c96b6b6509fb16e8a697fc9b7e3efbac47c85eb6..420d9857394a090a6bf1aae5d9ef86541585dd4d 100644 (file)
@@ -1234,7 +1234,7 @@ static struct usb_serial_driver option_1port_device = {
 #endif
 };
 
-static int debug;
+static bool debug;
 
 /* per port private data */
 
index 2161d1c3c089fa7d841ad516d06c5a1dd03f97f9..e287fd32682c2794f2ce664d159bdd120db22a9d 100644 (file)
@@ -74,7 +74,7 @@ static struct usb_driver oti6858_driver = {
        .no_dynamic_id =        1,
 };
 
-static int debug;
+static bool debug;
 
 /* requests */
 #define        OTI6858_REQ_GET_STATUS          (USB_DIR_IN | USB_TYPE_VENDOR | 0x00)
index 329295615d0634a86e9a10affe06ae52020e4949..3d8cda57ce7ac51ea9a3cf9aec600b55f80c8562 100644 (file)
@@ -36,7 +36,7 @@
  */
 #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
 
-static int debug;
+static bool debug;
 
 #define PL2303_CLOSING_WAIT    (30*HZ)
 
index aa9367f5b42143b0db23035a879355448a605528..1d5deee3be52211d10c6cc02edb7f121efc57541 100644 (file)
@@ -22,7 +22,7 @@
 #define DRIVER_AUTHOR "Qualcomm Inc"
 #define DRIVER_DESC "Qualcomm USB Serial driver"
 
-static int debug;
+static bool debug;
 
 static const struct usb_device_id id_table[] = {
        {USB_DEVICE(0x05c6, 0x9211)},   /* Acer Gobi QDL device */
index a36e2313eed0ecadd8d54b056903be2a92409a0a..d074b3740dcb8323d7b4f506c91adad21d24e354 100644 (file)
@@ -81,9 +81,9 @@
 #define CONFIG_USB_SERIAL_SAFE_PADDED 0
 #endif
 
-static int debug;
-static int safe = 1;
-static int padded = CONFIG_USB_SERIAL_SAFE_PADDED;
+static bool debug;
+static bool safe = 1;
+static bool padded = CONFIG_USB_SERIAL_SAFE_PADDED;
 
 #define DRIVER_VERSION "v0.1"
 #define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com, Johan Hovold <jhovold@gmail.com>"
index f2485429172faada3be3932990669e5991628afd..fdae0a4407cb7b9ddbc0068e4ef2690ba4bbfcf8 100644 (file)
@@ -46,8 +46,8 @@
    allocations > PAGE_SIZE and the number of packets in a page
    is an integer 512 is the largest possible packet on EHCI */
 
-static int debug;
-static int nmea;
+static bool debug;
+static bool nmea;
 
 /* Used in interface blacklisting */
 struct sierra_iface_info {
index 180ea6c7911ce4348adc8f06b30d6fee9d4ae282..d7f5eee18f0010bc7685aef9a6ec9e848277b14e 100644 (file)
@@ -33,7 +33,7 @@
 #define DRIVER_VERSION "v0.10"
 #define DRIVER_DESC    "SPCP8x5 USB to serial adaptor driver"
 
-static int debug;
+static bool debug;
 
 #define SPCP8x5_007_VID                0x04FC
 #define SPCP8x5_007_PID                0x0201
index 87362e48796e2662b82533b34f894ec9c08e966b..7697858d8858abefb181e9f139a17c17b6240890 100644 (file)
@@ -46,7 +46,7 @@
 #define FULLPWRBIT          0x00000080
 #define NEXT_BOARD_POWER_BIT        0x00000004
 
-static int debug;
+static bool debug;
 
 /* Version Information */
 #define DRIVER_VERSION "v0.1"
index c70cc012d03f2e7b82724bcc6a58423e78fb12b2..50651cf4fc613bc8ab0e89de48755361d50e9936 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/usb/serial.h>
 #include <linux/uaccess.h>
 
-static int debug;
+static bool debug;
 
 static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x05e0, 0x0600) },
index 4af21f46096e564fcfe767c327aab0378a0c845d..8468eb769a2919d38316993e670cb2810dfacbd7 100644 (file)
@@ -150,7 +150,7 @@ static int ti_download_firmware(struct ti_device *tdev);
 /* Data */
 
 /* module parameters */
-static int debug;
+static bool debug;
 static int closing_wait = TI_DEFAULT_CLOSING_WAIT;
 static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT];
 static unsigned int vendor_3410_count;
index ce6c1a65a5442b8082722d2d783cafd8be46beb7..611b206591cb4f3c39abfc8ccb4520bcc7a25f36 100644 (file)
@@ -61,7 +61,7 @@ static struct usb_driver usb_serial_driver = {
    drivers depend on it.
 */
 
-static int debug;
+static bool debug;
 /* initially all NULL */
 static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
 static DEFINE_MUTEX(table_lock);
index d555ca9567b8507baa292f0087d1b20f9881783a..c88657dd31c88495a65a49f0aff2aca047f89481 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/serial.h>
 #include "usb-wwan.h"
 
-static int debug;
+static bool debug;
 
 void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)
 {
index 1c11959a7d588f8b25e03013b83a4c3008b452be..210e4b10dc1126ade0a1ba9e04ea7a0485362404 100644 (file)
@@ -52,7 +52,7 @@ static int palm_os_4_probe(struct usb_serial *serial,
                                        const struct usb_device_id *id);
 
 /* Parameters that may be passed into the module. */
-static int debug;
+static bool debug;
 static __u16 vendor;
 static __u16 product;
 
index 11af903cb09f3da5d0b7a8ebf3fbc0f273faa3fe..7e0acf5c8e38bde7345b3e459f11e352e91739ac 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/ihex.h>
 #include "whiteheat.h"                 /* WhiteHEAT specific commands */
 
-static int debug;
+static bool debug;
 
 #ifndef CMSPAR
 #define CMSPAR 0
index 882a51fe7b3c8cd000dddc5f6b2214536f7b7636..9dab1f51dd43b3bac6e275eac77f995fb245d48d 100644 (file)
@@ -856,9 +856,9 @@ static const struct file_operations vhost_net_fops = {
 };
 
 static struct miscdevice vhost_net_misc = {
-       MISC_DYNAMIC_MINOR,
-       "vhost-net",
-       &vhost_net_fops,
+       .minor = VHOST_NET_MINOR,
+       .name = "vhost-net",
+       .fops = &vhost_net_fops,
 };
 
 static int vhost_net_init(void)
@@ -879,3 +879,5 @@ MODULE_VERSION("0.0.1");
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Michael S. Tsirkin");
 MODULE_DESCRIPTION("Host kernel accelerator for virtio net");
+MODULE_ALIAS_MISCDEV(VHOST_NET_MINOR);
+MODULE_ALIAS("devname:vhost-net");
index d83e967e4e15b6380fa1dc94584aac871b6a4b1d..6ca0c407c1447151f1d9b64bfb6c9445acd61b72 100644 (file)
@@ -1763,16 +1763,16 @@ config FB_AU1100
          au1100fb:panel=<name>.
 
 config FB_AU1200
-       bool "Au1200 LCD Driver"
+       bool "Au1200/Au1300 LCD Driver"
        depends on (FB = y) && MIPS_ALCHEMY
        select FB_SYS_FILLRECT
        select FB_SYS_COPYAREA
        select FB_SYS_IMAGEBLIT
        select FB_SYS_FOPS
        help
-         This is the framebuffer driver for the AMD Au1200 SOC.  It can drive
-         various panels and CRTs by passing in kernel cmd line option
-         au1200fb:panel=<name>.
+         This is the framebuffer driver for the Au1200/Au1300 SOCs.
+         It can drive various panels and CRTs by passing in kernel cmd line
+         option au1200fb:panel=<name>.
 
 config FB_VT8500
        bool "VT8500 LCD Driver"
@@ -2413,7 +2413,6 @@ source "drivers/video/omap/Kconfig"
 source "drivers/video/omap2/Kconfig"
 
 source "drivers/video/backlight/Kconfig"
-source "drivers/video/display/Kconfig"
 
 if VT
        source "drivers/video/console/Kconfig"
index 9b9d8fff7732917d0b16e28f705d552850c738b2..142606814d982bf1ed44df0090e4dbc04b8ab021 100644 (file)
@@ -13,7 +13,7 @@ fb-objs                           := $(fb-y)
 
 obj-$(CONFIG_VT)                 += console/
 obj-$(CONFIG_LOGO)               += logo/
-obj-y                            += backlight/ display/
+obj-y                            += backlight/
 
 obj-$(CONFIG_FB_CFB_FILLRECT)  += cfbfillrect.o
 obj-$(CONFIG_FB_CFB_COPYAREA)  += cfbcopyarea.o
index 5ea6596dd824084971b49bdf2e9364df7832746c..f23cae094f1b75e2781987705ef1ad115b540bb9 100644 (file)
 
       - hsstrt:   Start of horizontal synchronization pulse
       - hsstop:   End of horizontal synchronization pulse
-      - htotal:   Last value on the line (i.e. line length = htotal+1)
+      - htotal:   Last value on the line (i.e. line length = htotal + 1)
       - vsstrt:   Start of vertical synchronization pulse
       - vsstop:   End of vertical synchronization pulse
-      - vtotal:   Last line value (i.e. number of lines = vtotal+1)
+      - vtotal:   Last line value (i.e. number of lines = vtotal + 1)
       - hcenter:  Start of vertical retrace for interlace
 
    You can specify the blanking timings independently. Currently I just set
    clock):
 
       - diwstrt_h:   Horizontal start of the visible window
-      - diwstop_h:   Horizontal stop+1(*) of the visible window
+      - diwstop_h:   Horizontal stop + 1(*) of the visible window
       - diwstrt_v:   Vertical start of the visible window
       - diwstop_v:   Vertical stop of the visible window
       - ddfstrt:     Horizontal start of display DMA
 
    Sprite positioning:
 
-      - sprstrt_h:   Horizontal start-4 of sprite
+      - sprstrt_h:   Horizontal start - 4 of sprite
       - sprstrt_v:   Vertical start of sprite
 
    (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1.
    display parameters. Here's what I found out:
 
       - ddfstrt and ddfstop are best aligned to 64 pixels.
-      - the chipset needs 64+4 horizontal pixels after the DMA start before the
-        first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to
-        display the first pixel on the line too. Increase diwstrt_h for virtual
-        screen panning.
+      - the chipset needs 64 + 4 horizontal pixels after the DMA start before
+       the first pixel is output, so diwstrt_h = ddfstrt + 64 + 4 if you want
+       to display the first pixel on the line too. Increase diwstrt_h for
+       virtual screen panning.
       - the display DMA always fetches 64 pixels at a time (fmode = 3).
-      - ddfstop is ddfstrt+#pixels-64.
-      - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1
-        more than htotal.
+      - ddfstop is ddfstrt+#pixels - 64.
+      - diwstop_h = diwstrt_h + xres + 1. Because of the additional 1 this can
+       be 1 more than htotal.
       - hscroll simply adds a delay to the display output. Smooth horizontal
-        panning needs an extra 64 pixels on the left to prefetch the pixels that
-        `fall off' on the left.
+       panning needs an extra 64 pixels on the left to prefetch the pixels that
+       `fall off' on the left.
       - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane
-        DMA, so it's best to make the DMA start as late as possible.
+       DMA, so it's best to make the DMA start as late as possible.
       - you really don't want to make ddfstrt < 128, since this will steal DMA
-        cycles from the other DMA channels (audio, floppy and Chip RAM refresh).
+       cycles from the other DMA channels (audio, floppy and Chip RAM refresh).
       - I make diwstop_h and diwstop_v as large as possible.
 
    General dependencies
 
       - all values are SHRES pixel (35ns)
 
-                  table 1:fetchstart  table 2:prefetch    table 3:fetchsize
-                  ------------------  ----------------    -----------------
+                 table 1:fetchstart  table 2:prefetch    table 3:fetchsize
+                 ------------------  ----------------    -----------------
    Pixclock     # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES
    -------------#------+-----+------#------+-----+------#------+-----+------
    Bus width 1x #   16 |  32 |  64  #   16 |  32 |  64  #   64 |  64 |  64
       - chipset needs 4 pixels before the first pixel is output
       - ddfstrt must be aligned to fetchstart (table 1)
       - chipset needs also prefetch (table 2) to get first pixel data, so
-        ddfstrt = ((diwstrt_h-4) & -fetchstart) - prefetch
+       ddfstrt = ((diwstrt_h - 4) & -fetchstart) - prefetch
       - for horizontal panning decrease diwstrt_h
       - the length of a fetchline must be aligned to fetchsize (table 3)
       - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit
-        moved to optimize use of dma (useful for OCS/ECS overscan displays)
-      - ddfstop is ddfstrt+ddfsize-fetchsize
+       moved to optimize use of dma (useful for OCS/ECS overscan displays)
+      - ddfstop is ddfstrt + ddfsize - fetchsize
       - If C= didn't change anything for AGA, then at following positions the
-        dma bus is already used:
-        ddfstrt <  48 -> memory refresh
-                <  96 -> disk dma
-                < 160 -> audio dma
-                < 192 -> sprite 0 dma
-                < 416 -> sprite dma (32 per sprite)
+       dma bus is already used:
+       ddfstrt <  48 -> memory refresh
+               <  96 -> disk dma
+               < 160 -> audio dma
+               < 192 -> sprite 0 dma
+               < 416 -> sprite dma (32 per sprite)
       - in accordance with the hardware reference manual a hardware stop is at
-        192, but AGA (ECS?) can go below this.
+       192, but AGA (ECS?) can go below this.
 
    DMA priorities
    --------------
    the hardware cursor:
 
       - if you want to start display DMA too early, you lose the ability to
-        do smooth horizontal panning (xpanstep 1 -> 64).
+       do smooth horizontal panning (xpanstep 1 -> 64).
       - if you want to go even further, you lose the hardware cursor too.
 
    IMHO a hardware cursor is more important for X than horizontal scrolling,
    Standard VGA timings
    --------------------
 
-               xres  yres    left  right  upper  lower    hsync    vsync
-               ----  ----    ----  -----  -----  -----    -----    -----
+              xres  yres    left  right  upper  lower    hsync    vsync
+              ----  ----    ----  -----  -----  -----    -----    -----
       80x25     720   400      27     45     35     12      108        2
       80x30     720   480      27     45     30      9      108        2
 
 
    As a comparison, graphics/monitor.h suggests the following:
 
-               xres  yres    left  right  upper  lower    hsync    vsync
-               ----  ----    ----  -----  -----  -----    -----    -----
+              xres  yres    left  right  upper  lower    hsync    vsync
+              ----  ----    ----  -----  -----  -----    -----    -----
 
       VGA       640   480      52    112     24     19    112 -      2 +
       VGA70     640   400      52    112     27     21    112 -      2 -
 
       VSYNC    HSYNC    Vertical size    Vertical total
       -----    -----    -------------    --------------
-        +        +           Reserved          Reserved
-        +        -                400               414
-        -        +                350               362
-        -        -                480               496
+       +        +           Reserved          Reserved
+       +        -                400               414
+       -        +                350               362
+       -        -                480               496
 
    Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992
 
    -----------
 
       - a scanline is 64 Âµs long, of which 52.48 Âµs are visible. This is about
-        736 visible 70 ns pixels per line.
+       736 visible 70 ns pixels per line.
       - we have 625 scanlines, of which 575 are visible (interlaced); after
-        rounding this becomes 576.
+       rounding this becomes 576.
 
    RETMA -> NTSC
    -------------
 
       - a scanline is 63.5 Âµs long, of which 53.5 Âµs are visible.  This is about
-        736 visible 70 ns pixels per line.
+       736 visible 70 ns pixels per line.
       - we have 525 scanlines, of which 485 are visible (interlaced); after
-        rounding this becomes 484.
+       rounding this becomes 484.
 
    Thus if you want a PAL compatible display, you have to do the following:
 
       - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast
-        timings are to be used.
-      - make sure upper_margin+yres+lower_margin+vsync_len = 625 for an
-        interlaced, 312 for a non-interlaced and 156 for a doublescanned
-        display.
-      - make sure left_margin+xres+right_margin+hsync_len = 1816 for a SHRES,
-        908 for a HIRES and 454 for a LORES display.
+       timings are to be used.
+      - make sure upper_margin + yres + lower_margin + vsync_len = 625 for an
+       interlaced, 312 for a non-interlaced and 156 for a doublescanned
+       display.
+      - make sure left_margin + xres + right_margin + hsync_len = 1816 for a
+       SHRES, 908 for a HIRES and 454 for a LORES display.
       - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90),
-        left_margin+2*hsync_len must be greater or equal.
+       left_margin + 2 * hsync_len must be greater or equal.
       - the upper visible part begins at 48 (interlaced; non-interlaced:24,
-        doublescanned:12), upper_margin+2*vsync_len must be greater or equal.
+       doublescanned:12), upper_margin + 2 * vsync_len must be greater or
+       equal.
       - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync
-        of 4 scanlines
+       of 4 scanlines
 
    The settings for a NTSC compatible display are straightforward.
 
    anything about horizontal/vertical synchronization nor refresh rates.
 
 
-                                                            -- Geert --
+                                                           -- Geert --
 
 *******************************************************************************/
 
@@ -540,45 +541,45 @@ static u_short maxfmode, chipset;
         * Various macros
         */
 
-#define up2(v)         (((v)+1) & -2)
+#define up2(v)         (((v) + 1) & -2)
 #define down2(v)       ((v) & -2)
 #define div2(v)                ((v)>>1)
 #define mod2(v)                ((v) & 1)
 
-#define up4(v)         (((v)+3) & -4)
+#define up4(v)         (((v) + 3) & -4)
 #define down4(v)       ((v) & -4)
-#define mul4(v)                ((v)<<2)
+#define mul4(v)                ((v) << 2)
 #define div4(v)                ((v)>>2)
 #define mod4(v)                ((v) & 3)
 
-#define up8(v)         (((v)+7) & -8)
+#define up8(v)         (((v) + 7) & -8)
 #define down8(v)       ((v) & -8)
 #define div8(v)                ((v)>>3)
 #define mod8(v)                ((v) & 7)
 
-#define up16(v)                (((v)+15) & -16)
+#define up16(v)                (((v) + 15) & -16)
 #define down16(v)      ((v) & -16)
 #define div16(v)       ((v)>>4)
 #define mod16(v)       ((v) & 15)
 
-#define up32(v)                (((v)+31) & -32)
+#define up32(v)                (((v) + 31) & -32)
 #define down32(v)      ((v) & -32)
 #define div32(v)       ((v)>>5)
 #define mod32(v)       ((v) & 31)
 
-#define up64(v)                (((v)+63) & -64)
+#define up64(v)                (((v) + 63) & -64)
 #define down64(v)      ((v) & -64)
 #define div64(v)       ((v)>>6)
 #define mod64(v)       ((v) & 63)
 
-#define upx(x,v)       (((v)+(x)-1) & -(x))
-#define downx(x,v)     ((v) & -(x))
-#define modx(x,v)      ((v) & ((x)-1))
+#define upx(x, v)      (((v) + (x) - 1) & -(x))
+#define downx(x, v)    ((v) & -(x))
+#define modx(x, v)     ((v) & ((x) - 1))
 
 /* if x1 is not a constant, this macro won't make real sense :-) */
 #ifdef __mc68000__
 #define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \
-       "d" (x2), "d" ((long)((x1)/0x100000000ULL)), "0" ((long)(x1))); res;})
+       "d" (x2), "d" ((long)((x1) / 0x100000000ULL)), "0" ((long)(x1))); res;})
 #else
 /* We know a bit about the numbers, so we can do it this way */
 #define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \
@@ -607,7 +608,7 @@ static u_short maxfmode, chipset;
 #define VIDEOMEMSIZE_ECS_1M    (393216)  /* ECS (1MB) : max 1024*768*16    */
 #define VIDEOMEMSIZE_OCS       (262144)  /* OCS       : max ca. 800*600*16 */
 
-#define SPRITEMEMSIZE          (64*64/4) /* max 64*64*4 */
+#define SPRITEMEMSIZE          (64 * 64 / 4) /* max 64*64*4 */
 #define DUMMYSPRITEMEMSIZE     (8)
 static u_long spritememory;
 
@@ -634,9 +635,9 @@ static u_long min_fstrt = 192;
         * Copper Instructions
         */
 
-#define CMOVE(val, reg)                (CUSTOM_OFS(reg)<<16 | (val))
-#define CMOVE2(val, reg)       ((CUSTOM_OFS(reg)+2)<<16 | (val))
-#define CWAIT(x, y)            (((y) & 0x1fe)<<23 | ((x) & 0x7f0)<<13 | 0x0001fffe)
+#define CMOVE(val, reg)                (CUSTOM_OFS(reg) << 16 | (val))
+#define CMOVE2(val, reg)       ((CUSTOM_OFS(reg) + 2) << 16 | (val))
+#define CWAIT(x, y)            (((y) & 0x1fe) << 23 | ((x) & 0x7f0) << 13 | 0x0001fffe)
 #define CEND                   (0xfffffffe)
 
 
@@ -709,7 +710,7 @@ static u_short *lofsprite, *shfsprite, *dummysprite;
         * Current Video Mode
         */
 
-static struct amifb_par {
+struct amifb_par {
 
        /* General Values */
 
@@ -772,15 +773,6 @@ static struct amifb_par {
        /* Additional AGA Hardware Registers */
 
        u_short fmode;          /* vmode */
-} currentpar;
-
-
-static struct fb_info fb_info = {
-    .fix = {
-       .id             = "Amiga ",
-       .visual         = FB_VISUAL_PSEUDOCOLOR,
-       .accel          = FB_ACCEL_AMIGABLITT
-    }
 };
 
 
@@ -820,116 +812,123 @@ static u_short is_lace = 0;             /* Screen is laced */
 
 static struct fb_videomode ami_modedb[] __initdata = {
 
-    /*
-     *  AmigaOS Video Modes
-     *
-     *  If you change these, make sure to update DEFMODE_* as well!
-     */
-
-    {
-       /* 640x200, 15 kHz, 60 Hz (NTSC) */
-       "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2,
-       FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
-       "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4,
-       FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x256, 15 kHz, 50 Hz (PAL) */
-       "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2,
-       FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
-       "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4,
-       FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x480, 29 kHz, 57 Hz */
-       "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8,
-       0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x960, 29 kHz, 57 Hz interlaced */
-       "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, 16,
-       0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x200, 15 kHz, 72 Hz */
-       "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5,
-       0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x400, 15 kHz, 72 Hz interlaced */
-       "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, 10,
-       0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x400, 29 kHz, 68 Hz */
-       "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8,
-       0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x800, 29 kHz, 68 Hz interlaced */
-       "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, 16,
-       0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 800x300, 23 kHz, 70 Hz */
-       "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7,
-       0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 800x600, 23 kHz, 70 Hz interlaced */
-       "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, 14,
-       0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x200, 27 kHz, 57 Hz doublescan */
-       "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4,
-       0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
-    }, {
-       /* 640x400, 27 kHz, 57 Hz */
-       "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7,
-       0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x800, 27 kHz, 57 Hz interlaced */
-       "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, 14,
-       0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x256, 27 kHz, 47 Hz doublescan */
-       "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4,
-       0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
-    }, {
-       /* 640x512, 27 kHz, 47 Hz */
-       "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7,
-       0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x1024, 27 kHz, 47 Hz interlaced */
-       "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, 14,
-       0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
-    },
-
-    /*
-     *  VGA Video Modes
-     */
-
-    {
-       /* 640x480, 31 kHz, 60 Hz (VGA) */
-       "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2,
-       0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 640x400, 31 kHz, 70 Hz (VGA) */
-       "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2,
-       FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-    },
+       /*
+        *  AmigaOS Video Modes
+        *
+        *  If you change these, make sure to update DEFMODE_* as well!
+        */
+
+       {
+               /* 640x200, 15 kHz, 60 Hz (NTSC) */
+               "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2,
+               FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
+               "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4,
+               FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x256, 15 kHz, 50 Hz (PAL) */
+               "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2,
+               FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
+               "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4,
+               FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x480, 29 kHz, 57 Hz */
+               "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8,
+               0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x960, 29 kHz, 57 Hz interlaced */
+               "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72,
+               16,
+               0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x200, 15 kHz, 72 Hz */
+               "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5,
+               0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x400, 15 kHz, 72 Hz interlaced */
+               "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52,
+               10,
+               0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x400, 29 kHz, 68 Hz */
+               "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8,
+               0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x800, 29 kHz, 68 Hz interlaced */
+               "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80,
+               16,
+               0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 800x300, 23 kHz, 70 Hz */
+               "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7,
+               0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 800x600, 23 kHz, 70 Hz interlaced */
+               "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80,
+               14,
+               0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x200, 27 kHz, 57 Hz doublescan */
+               "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4,
+               0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
+       }, {
+               /* 640x400, 27 kHz, 57 Hz */
+               "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7,
+               0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x800, 27 kHz, 57 Hz interlaced */
+               "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80,
+               14,
+               0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x256, 27 kHz, 47 Hz doublescan */
+               "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4,
+               0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
+       }, {
+               /* 640x512, 27 kHz, 47 Hz */
+               "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7,
+               0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x1024, 27 kHz, 47 Hz interlaced */
+               "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80,
+               14,
+               0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+       },
+
+       /*
+        *  VGA Video Modes
+        */
+
+       {
+               /* 640x480, 31 kHz, 60 Hz (VGA) */
+               "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2,
+               0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 640x400, 31 kHz, 70 Hz (VGA) */
+               "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2,
+               FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT,
+               FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+       },
 
 #if 0
 
-    /*
-     *  A2024 video modes
-     *  These modes don't work yet because there's no A2024 driver.
-     */
-
-    {
-       /* 1024x800, 10 Hz */
-       "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,
-       0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-    }, {
-       /* 1024x800, 15 Hz */
-       "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,
-       0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
-    }
+       /*
+        *  A2024 video modes
+        *  These modes don't work yet because there's no A2024 driver.
+        */
+
+       {
+               /* 1024x800, 10 Hz */
+               "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,
+               0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+       }, {
+               /* 1024x800, 15 Hz */
+               "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0,
+               0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+       }
 #endif
 };
 
@@ -953,6 +952,11 @@ static int round_down_bpp = 1;     /* for mode probing */
 static int amifb_ilbm = 0;     /* interleaved or normal bitplanes */
 static int amifb_inverse = 0;
 
+static u32 amifb_hfmin __initdata;     /* monitor hfreq lower limit (Hz) */
+static u32 amifb_hfmax __initdata;     /* monitor hfreq upper limit (Hz) */
+static u16 amifb_vfmin __initdata;     /* monitor vfreq lower limit (Hz) */
+static u16 amifb_vfmax __initdata;     /* monitor vfreq upper limit (Hz) */
+
 
        /*
         * Macros for the conversion from real world values to hardware register
@@ -992,19 +996,20 @@ static int amifb_inverse = 0;
 /* bplcon1 (smooth scrolling) */
 
 #define hscroll2hw(hscroll) \
-       (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \
-        ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))
+       (((hscroll) << 12 & 0x3000) | ((hscroll) << 8 & 0xc300) | \
+        ((hscroll) << 4 & 0x0c00) | ((hscroll) << 2 & 0x00f0) | \
+        ((hscroll)>>2 & 0x000f))
 
 /* diwstrt/diwstop/diwhigh (visible display window) */
 
 #define diwstrt2hw(diwstrt_h, diwstrt_v) \
-       (((diwstrt_v)<<7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
+       (((diwstrt_v) << 7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))
 #define diwstop2hw(diwstop_h, diwstop_v) \
-       (((diwstop_v)<<7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
+       (((diwstop_v) << 7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))
 #define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \
-       (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \
+       (((diwstop_h) << 3 & 0x2000) | ((diwstop_h) << 11 & 0x1800) | \
         ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \
-        ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007))
+        ((diwstrt_h) << 3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007))
 
 /* ddfstrt/ddfstop (display DMA) */
 
@@ -1015,38 +1020,39 @@ static int amifb_inverse = 0;
 
 #define hsstrt2hw(hsstrt)      (div8(hsstrt))
 #define hsstop2hw(hsstop)      (div8(hsstop))
-#define htotal2hw(htotal)      (div8(htotal)-1)
+#define htotal2hw(htotal)      (div8(htotal) - 1)
 #define vsstrt2hw(vsstrt)      (div2(vsstrt))
 #define vsstop2hw(vsstop)      (div2(vsstop))
-#define vtotal2hw(vtotal)      (div2(vtotal)-1)
+#define vtotal2hw(vtotal)      (div2(vtotal) - 1)
 #define hcenter2hw(htotal)     (div8(htotal))
 
 /* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */
 
-#define hbstrt2hw(hbstrt)      (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))
-#define hbstop2hw(hbstop)      (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff))
+#define hbstrt2hw(hbstrt)      (((hbstrt) << 8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))
+#define hbstop2hw(hbstop)      (((hbstop) << 8 & 0x0700) | ((hbstop)>>3 & 0x00ff))
 #define vbstrt2hw(vbstrt)      (div2(vbstrt))
 #define vbstop2hw(vbstop)      (div2(vbstop))
 
 /* colour */
 
 #define rgb2hw8_high(red, green, blue) \
-       (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4))
+       (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4))
 #define rgb2hw8_low(red, green, blue) \
-       (((red & 0x0f)<<8) | ((green & 0x0f)<<4) | (blue & 0x0f))
+       (((red & 0x0f) << 8) | ((green & 0x0f) << 4) | (blue & 0x0f))
 #define rgb2hw4(red, green, blue) \
-       (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4))
+       (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4))
 #define rgb2hw2(red, green, blue) \
-       (((red & 0xc0)<<4) | (green & 0xc0) | ((blue & 0xc0)>>4))
+       (((red & 0xc0) << 4) | (green & 0xc0) | ((blue & 0xc0)>>4))
 
 /* sprpos/sprctl (sprite positioning) */
 
 #define spr2hw_pos(start_v, start_h) \
-       (((start_v)<<7&0xff00) | ((start_h)>>3&0x00ff))
+       (((start_v) << 7 & 0xff00) | ((start_h)>>3 & 0x00ff))
 #define spr2hw_ctl(start_v, start_h, stop_v) \
-       (((stop_v)<<7&0xff00) | ((start_v)>>4&0x0040) | ((stop_v)>>5&0x0020) | \
-        ((start_h)<<3&0x0018) | ((start_v)>>7&0x0004) | ((stop_v)>>8&0x0002) | \
-        ((start_h)>>2&0x0001))
+       (((stop_v) << 7 & 0xff00) | ((start_v)>>4 & 0x0040) | \
+        ((stop_v)>>5 & 0x0020) | ((start_h) << 3 & 0x0018) | \
+        ((start_v)>>7 & 0x0004) | ((stop_v)>>8 & 0x0002) | \
+        ((start_h)>>2 & 0x0001))
 
 /* get current vertical position of beam */
 #define get_vbpos()    ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe))
@@ -1055,7 +1061,7 @@ static int amifb_inverse = 0;
         * Copper Initialisation List
         */
 
-#define COPINITSIZE (sizeof(copins)*40)
+#define COPINITSIZE (sizeof(copins) * 40)
 
 enum {
        cip_bplcon0
@@ -1066,7 +1072,7 @@ enum {
         * Don't change the order, build_copper()/rebuild_copper() rely on this
         */
 
-#define COPLISTSIZE (sizeof(copins)*64)
+#define COPLISTSIZE (sizeof(copins) * 64)
 
 enum {
        cop_wait, cop_bplcon0,
@@ -1108,2693 +1114,2671 @@ static u_short sprfetchmode[3] = {
 };
 
 
-       /*
-        * Interface used by the world
-        */
-
-int amifb_setup(char*);
-
-static int amifb_check_var(struct fb_var_screeninfo *var,
-                          struct fb_info *info);
-static int amifb_set_par(struct fb_info *info);
-static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                          unsigned blue, unsigned transp,
-                          struct fb_info *info);
-static int amifb_blank(int blank, struct fb_info *info);
-static int amifb_pan_display(struct fb_var_screeninfo *var,
-                            struct fb_info *info);
-static void amifb_fillrect(struct fb_info *info,
-                          const struct fb_fillrect *rect);
-static void amifb_copyarea(struct fb_info *info,
-                          const struct fb_copyarea *region);
-static void amifb_imageblit(struct fb_info *info,
-                           const struct fb_image *image);
-static int amifb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg);
-
+/* --------------------------- Hardware routines --------------------------- */
 
        /*
-        * Interface to the low level console driver
+        * Get the video params out of `var'. If a value doesn't fit, round
+        * it up, if it's too big, return -EINVAL.
         */
 
-static void amifb_deinit(struct platform_device *pdev);
+static int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par,
+                         const struct fb_info *info)
+{
+       u_short clk_shift, line_shift;
+       u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;
+       u_int htotal, vtotal;
 
        /*
-        * Internal routines
+        * Find a matching Pixel Clock
         */
 
-static int flash_cursor(void);
-static irqreturn_t amifb_interrupt(int irq, void *dev_id);
-static u_long chipalloc(u_long size);
-static void chipfree(void);
+       for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++)
+               if (var->pixclock <= pixclock[clk_shift])
+                       break;
+       if (clk_shift > TAG_LORES) {
+               DPRINTK("pixclock too high\n");
+               return -EINVAL;
+       }
+       par->clk_shift = clk_shift;
 
        /*
-        * Hardware routines
+        * Check the Geometry Values
         */
 
-static int ami_decode_var(struct fb_var_screeninfo *var,
-                          struct amifb_par *par);
-static int ami_encode_var(struct fb_var_screeninfo *var,
-                          struct amifb_par *par);
-static void ami_pan_var(struct fb_var_screeninfo *var);
-static int ami_update_par(void);
-static void ami_update_display(void);
-static void ami_init_display(void);
-static void ami_do_blank(void);
-static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix);
-static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data);
-static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data);
-static int ami_get_cursorstate(struct fb_cursorstate *state);
-static int ami_set_cursorstate(struct fb_cursorstate *state);
-static void ami_set_sprite(void);
-static void ami_init_copper(void);
-static void ami_reinit_copper(void);
-static void ami_build_copper(void);
-static void ami_rebuild_copper(void);
-
-
-static struct fb_ops amifb_ops = {
-       .owner          = THIS_MODULE,
-       .fb_check_var   = amifb_check_var,
-       .fb_set_par     = amifb_set_par,
-       .fb_setcolreg   = amifb_setcolreg,
-       .fb_blank       = amifb_blank,
-       .fb_pan_display = amifb_pan_display,
-       .fb_fillrect    = amifb_fillrect,
-       .fb_copyarea    = amifb_copyarea,
-       .fb_imageblit   = amifb_imageblit,
-       .fb_ioctl       = amifb_ioctl,
-};
+       if ((par->xres = var->xres) < 64)
+               par->xres = 64;
+       if ((par->yres = var->yres) < 64)
+               par->yres = 64;
+       if ((par->vxres = var->xres_virtual) < par->xres)
+               par->vxres = par->xres;
+       if ((par->vyres = var->yres_virtual) < par->yres)
+               par->vyres = par->yres;
 
-static void __init amifb_setup_mcap(char *spec)
-{
-       char *p;
-       int vmin, vmax, hmin, hmax;
+       par->bpp = var->bits_per_pixel;
+       if (!var->nonstd) {
+               if (par->bpp < 1)
+                       par->bpp = 1;
+               if (par->bpp > maxdepth[clk_shift]) {
+                       if (round_down_bpp && maxdepth[clk_shift])
+                               par->bpp = maxdepth[clk_shift];
+                       else {
+                               DPRINTK("invalid bpp\n");
+                               return -EINVAL;
+                       }
+               }
+       } else if (var->nonstd == FB_NONSTD_HAM) {
+               if (par->bpp < 6)
+                       par->bpp = 6;
+               if (par->bpp != 6) {
+                       if (par->bpp < 8)
+                               par->bpp = 8;
+                       if (par->bpp != 8 || !IS_AGA) {
+                               DPRINTK("invalid bpp for ham mode\n");
+                               return -EINVAL;
+                       }
+               }
+       } else {
+               DPRINTK("unknown nonstd mode\n");
+               return -EINVAL;
+       }
 
-       /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
-        * <V*> vertical freq. in Hz
-        * <H*> horizontal freq. in kHz
+       /*
+        * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
+        * checks failed and smooth scrolling is not possible
         */
 
-       if (!(p = strsep(&spec, ";")) || !*p)
-               return;
-       vmin = simple_strtoul(p, NULL, 10);
-       if (vmin <= 0)
-               return;
-       if (!(p = strsep(&spec, ";")) || !*p)
-               return;
-       vmax = simple_strtoul(p, NULL, 10);
-       if (vmax <= 0 || vmax <= vmin)
-               return;
-       if (!(p = strsep(&spec, ";")) || !*p)
-               return;
-       hmin = 1000 * simple_strtoul(p, NULL, 10);
-       if (hmin <= 0)
-               return;
-       if (!(p = strsep(&spec, "")) || !*p)
-               return;
-       hmax = 1000 * simple_strtoul(p, NULL, 10);
-       if (hmax <= 0 || hmax <= hmin)
-               return;
-
-       fb_info.monspecs.vfmin = vmin;
-       fb_info.monspecs.vfmax = vmax;
-       fb_info.monspecs.hfmin = hmin;
-       fb_info.monspecs.hfmax = hmax;
-}
-
-int __init amifb_setup(char *options)
-{
-       char *this_opt;
-
-       if (!options || !*options)
-               return 0;
-
-       while ((this_opt = strsep(&options, ",")) != NULL) {
-               if (!*this_opt)
-                       continue;
-               if (!strcmp(this_opt, "inverse")) {
-                       amifb_inverse = 1;
-                       fb_invert_cmaps();
-               } else if (!strcmp(this_opt, "ilbm"))
-                       amifb_ilbm = 1;
-               else if (!strncmp(this_opt, "monitorcap:", 11))
-                       amifb_setup_mcap(this_opt+11);
-               else if (!strncmp(this_opt, "fstart:", 7))
-                       min_fstrt = simple_strtoul(this_opt+7, NULL, 0);
-               else
-                       mode_option = this_opt;
+       par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN;
+       switch (par->vmode & FB_VMODE_MASK) {
+       case FB_VMODE_INTERLACED:
+               line_shift = 0;
+               break;
+       case FB_VMODE_NONINTERLACED:
+               line_shift = 1;
+               break;
+       case FB_VMODE_DOUBLE:
+               if (!IS_AGA) {
+                       DPRINTK("double mode only possible with aga\n");
+                       return -EINVAL;
+               }
+               line_shift = 2;
+               break;
+       default:
+               DPRINTK("unknown video mode\n");
+               return -EINVAL;
+               break;
        }
+       par->line_shift = line_shift;
 
-       if (min_fstrt < 48)
-               min_fstrt = 48;
-
-       return 0;
-}
-
-
-static int amifb_check_var(struct fb_var_screeninfo *var,
-                          struct fb_info *info)
-{
-       int err;
-       struct amifb_par par;
-
-       /* Validate wanted screen parameters */
-       if ((err = ami_decode_var(var, &par)))
-               return err;
-
-       /* Encode (possibly rounded) screen parameters */
-       ami_encode_var(var, &par);
-       return 0;
-}
-
-
-static int amifb_set_par(struct fb_info *info)
-{
-       struct amifb_par *par = (struct amifb_par *)info->par;
-
-       do_vmode_pan = 0;
-       do_vmode_full = 0;
-
-       /* Decode wanted screen parameters */
-       ami_decode_var(&info->var, par);
-
-       /* Set new videomode */
-       ami_build_copper();
-
-       /* Set VBlank trigger */
-       do_vmode_full = 1;
+       /*
+        * Vertical and Horizontal Timings
+        */
 
-       /* Update fix for new screen parameters */
-       if (par->bpp == 1) {
-               info->fix.type = FB_TYPE_PACKED_PIXELS;
-               info->fix.type_aux = 0;
-       } else if (amifb_ilbm) {
-               info->fix.type = FB_TYPE_INTERLEAVED_PLANES;
-               info->fix.type_aux = par->next_line;
-       } else {
-               info->fix.type = FB_TYPE_PLANES;
-               info->fix.type_aux = 0;
-       }
-       info->fix.line_length = div8(upx(16<<maxfmode, par->vxres));
+       xres_n = par->xres << clk_shift;
+       yres_n = par->yres << line_shift;
+       par->htotal = down8((var->left_margin + par->xres + var->right_margin +
+                            var->hsync_len) << clk_shift);
+       par->vtotal =
+               down2(((var->upper_margin + par->yres + var->lower_margin +
+                       var->vsync_len) << line_shift) + 1);
 
-       if (par->vmode & FB_VMODE_YWRAP) {
-               info->fix.ywrapstep = 1;
-               info->fix.xpanstep = 0;
-               info->fix.ypanstep = 0;
-               info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP |
-                   FBINFO_READS_FAST; /* override SCROLL_REDRAW */
-       } else {
-               info->fix.ywrapstep = 0;
-               if (par->vmode & FB_VMODE_SMOOTH_XPAN)
-                       info->fix.xpanstep = 1;
+       if (IS_AGA)
+               par->bplcon3 = sprpixmode[clk_shift];
+       else
+               par->bplcon3 = 0;
+       if (var->sync & FB_SYNC_BROADCAST) {
+               par->diwstop_h = par->htotal -
+                       ((var->right_margin - var->hsync_len) << clk_shift);
+               if (IS_AGA)
+                       par->diwstop_h += mod4(var->hsync_len);
                else
-                       info->fix.xpanstep = 16<<maxfmode;
-               info->fix.ypanstep = 1;
-               info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
-       }
-       return 0;
-}
-
-
-       /*
-        * Pan or Wrap the Display
-        *
-        * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-        */
+                       par->diwstop_h = down4(par->diwstop_h);
 
-static int amifb_pan_display(struct fb_var_screeninfo *var,
-                            struct fb_info *info)
-{
-       if (var->vmode & FB_VMODE_YWRAP) {
-               if (var->yoffset < 0 ||
-                   var->yoffset >= info->var.yres_virtual || var->xoffset)
+               par->diwstrt_h = par->diwstop_h - xres_n;
+               par->diwstop_v = par->vtotal -
+                       ((var->lower_margin - var->vsync_len) << line_shift);
+               par->diwstrt_v = par->diwstop_v - yres_n;
+               if (par->diwstop_h >= par->htotal + 8) {
+                       DPRINTK("invalid diwstop_h\n");
                        return -EINVAL;
-       } else {
-               /*
-                * TODO: There will be problems when xpan!=1, so some columns
-                * on the right side will never be seen
-                */
-               if (var->xoffset+info->var.xres > upx(16<<maxfmode, info->var.xres_virtual) ||
-                   var->yoffset+info->var.yres > info->var.yres_virtual)
+               }
+               if (par->diwstop_v > par->vtotal) {
+                       DPRINTK("invalid diwstop_v\n");
                        return -EINVAL;
-       }
-       ami_pan_var(var);
-       info->var.xoffset = var->xoffset;
-       info->var.yoffset = var->yoffset;
-       if (var->vmode & FB_VMODE_YWRAP)
-               info->var.vmode |= FB_VMODE_YWRAP;
-       else
-               info->var.vmode &= ~FB_VMODE_YWRAP;
-       return 0;
-}
-
+               }
 
-#if BITS_PER_LONG == 32
-#define BYTES_PER_LONG 4
-#define SHIFT_PER_LONG 5
-#elif BITS_PER_LONG == 64
-#define BYTES_PER_LONG 8
-#define SHIFT_PER_LONG 6
-#else
-#define Please update me
-#endif
+               if (!IS_OCS) {
+                       /* Initialize sync with some reasonable values for pwrsave */
+                       par->hsstrt = 160;
+                       par->hsstop = 320;
+                       par->vsstrt = 30;
+                       par->vsstop = 34;
+               } else {
+                       par->hsstrt = 0;
+                       par->hsstop = 0;
+                       par->vsstrt = 0;
+                       par->vsstop = 0;
+               }
+               if (par->vtotal > (PAL_VTOTAL + NTSC_VTOTAL) / 2) {
+                       /* PAL video mode */
+                       if (par->htotal != PAL_HTOTAL) {
+                               DPRINTK("htotal invalid for pal\n");
+                               return -EINVAL;
+                       }
+                       if (par->diwstrt_h < PAL_DIWSTRT_H) {
+                               DPRINTK("diwstrt_h too low for pal\n");
+                               return -EINVAL;
+                       }
+                       if (par->diwstrt_v < PAL_DIWSTRT_V) {
+                               DPRINTK("diwstrt_v too low for pal\n");
+                               return -EINVAL;
+                       }
+                       htotal = PAL_HTOTAL>>clk_shift;
+                       vtotal = PAL_VTOTAL>>1;
+                       if (!IS_OCS) {
+                               par->beamcon0 = BMC0_PAL;
+                               par->bplcon3 |= BPC3_BRDRBLNK;
+                       } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
+                                  AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
+                               par->beamcon0 = BMC0_PAL;
+                               par->hsstop = 1;
+                       } else if (amiga_vblank != 50) {
+                               DPRINTK("pal not supported by this chipset\n");
+                               return -EINVAL;
+                       }
+               } else {
+                       /* NTSC video mode
+                        * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK
+                        * and NTSC activated, so than better let diwstop_h <= 1812
+                        */
+                       if (par->htotal != NTSC_HTOTAL) {
+                               DPRINTK("htotal invalid for ntsc\n");
+                               return -EINVAL;
+                       }
+                       if (par->diwstrt_h < NTSC_DIWSTRT_H) {
+                               DPRINTK("diwstrt_h too low for ntsc\n");
+                               return -EINVAL;
+                       }
+                       if (par->diwstrt_v < NTSC_DIWSTRT_V) {
+                               DPRINTK("diwstrt_v too low for ntsc\n");
+                               return -EINVAL;
+                       }
+                       htotal = NTSC_HTOTAL>>clk_shift;
+                       vtotal = NTSC_VTOTAL>>1;
+                       if (!IS_OCS) {
+                               par->beamcon0 = 0;
+                               par->bplcon3 |= BPC3_BRDRBLNK;
+                       } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
+                                  AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
+                               par->beamcon0 = 0;
+                               par->hsstop = 1;
+                       } else if (amiga_vblank != 60) {
+                               DPRINTK("ntsc not supported by this chipset\n");
+                               return -EINVAL;
+                       }
+               }
+               if (IS_OCS) {
+                       if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 ||
+                           par->diwstrt_v >=  512 || par->diwstop_v <  256) {
+                               DPRINTK("invalid position for display on ocs\n");
+                               return -EINVAL;
+                       }
+               }
+       } else if (!IS_OCS) {
+               /* Programmable video mode */
+               par->hsstrt = var->right_margin << clk_shift;
+               par->hsstop = (var->right_margin + var->hsync_len) << clk_shift;
+               par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift);
+               if (!IS_AGA)
+                       par->diwstop_h = down4(par->diwstop_h) - 16;
+               par->diwstrt_h = par->diwstop_h - xres_n;
+               par->hbstop = par->diwstrt_h + 4;
+               par->hbstrt = par->diwstop_h + 4;
+               if (par->hbstrt >= par->htotal + 8)
+                       par->hbstrt -= par->htotal;
+               par->hcenter = par->hsstrt + (par->htotal >> 1);
+               par->vsstrt = var->lower_margin << line_shift;
+               par->vsstop = (var->lower_margin + var->vsync_len) << line_shift;
+               par->diwstop_v = par->vtotal;
+               if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
+                       par->diwstop_v -= 2;
+               par->diwstrt_v = par->diwstop_v - yres_n;
+               par->vbstop = par->diwstrt_v - 2;
+               par->vbstrt = par->diwstop_v - 2;
+               if (par->vtotal > 2048) {
+                       DPRINTK("vtotal too high\n");
+                       return -EINVAL;
+               }
+               if (par->htotal > 2048) {
+                       DPRINTK("htotal too high\n");
+                       return -EINVAL;
+               }
+               par->bplcon3 |= BPC3_EXTBLKEN;
+               par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
+                               BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
+                               BMC0_PAL | BMC0_VARCSYEN;
+               if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+                       par->beamcon0 |= BMC0_HSYTRUE;
+               if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+                       par->beamcon0 |= BMC0_VSYTRUE;
+               if (var->sync & FB_SYNC_COMP_HIGH_ACT)
+                       par->beamcon0 |= BMC0_CSYTRUE;
+               htotal = par->htotal>>clk_shift;
+               vtotal = par->vtotal>>1;
+       } else {
+               DPRINTK("only broadcast modes possible for ocs\n");
+               return -EINVAL;
+       }
 
+       /*
+        * Checking the DMA timing
+        */
 
-    /*
-     *  Compose two values, using a bitmask as decision value
-     *  This is equivalent to (a & mask) | (b & ~mask)
-     */
+       fconst = 16 << maxfmode << clk_shift;
 
-static inline unsigned long comp(unsigned long a, unsigned long b,
-                                unsigned long mask)
-{
-       return ((a ^ b) & mask) ^ b;
-}
+       /*
+        * smallest window start value without turn off other dma cycles
+        * than sprite1-7, unless you change min_fstrt
+        */
 
 
-static inline unsigned long xor(unsigned long a, unsigned long b,
-                               unsigned long mask)
-{
-       return (a & mask) ^ b;
-}
+       fsize = ((maxfmode + clk_shift <= 1) ? fconst : 64);
+       fstrt = downx(fconst, par->diwstrt_h - 4) - fsize;
+       if (fstrt < min_fstrt) {
+               DPRINTK("fetch start too low\n");
+               return -EINVAL;
+       }
 
+       /*
+        * smallest window start value where smooth scrolling is possible
+        */
 
-    /*
-     *  Unaligned forward bit copy using 32-bit or 64-bit memory accesses
-     */
+       fstrt = downx(fconst, par->diwstrt_h - fconst + (1 << clk_shift) - 4) -
+               fsize;
+       if (fstrt < min_fstrt)
+               par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
 
-static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
-                  int src_idx, u32 n)
-{
-       unsigned long first, last;
-       int shift = dst_idx-src_idx, left, right;
-       unsigned long d0, d1;
-       int m;
+       maxfetchstop = down16(par->htotal - 80);
 
-       if (!n)
-               return;
+       fstrt = downx(fconst, par->diwstrt_h - 4) - 64 - fconst;
+       fsize = upx(fconst, xres_n +
+                   modx(fconst, downx(1 << clk_shift, par->diwstrt_h - 4)));
+       if (fstrt + fsize > maxfetchstop)
+               par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
 
-       shift = dst_idx-src_idx;
-       first = ~0UL >> dst_idx;
-       last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+       fsize = upx(fconst, xres_n);
+       if (fstrt + fsize > maxfetchstop) {
+               DPRINTK("fetch stop too high\n");
+               return -EINVAL;
+       }
 
-       if (!shift) {
-               // Same alignment for source and dest
+       if (maxfmode + clk_shift <= 1) {
+               fsize = up64(xres_n + fconst - 1);
+               if (min_fstrt + fsize - 64 > maxfetchstop)
+                       par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
 
-               if (dst_idx+n <= BITS_PER_LONG) {
-                       // Single word
-                       if (last)
-                               first &= last;
-                       *dst = comp(*src, *dst, first);
-               } else {
-                       // Multiple destination words
-                       // Leading bits
-                       if (first) {
-                               *dst = comp(*src, *dst, first);
-                               dst++;
-                               src++;
-                               n -= BITS_PER_LONG-dst_idx;
-                       }
+               fsize = up64(xres_n);
+               if (min_fstrt + fsize - 64 > maxfetchstop) {
+                       DPRINTK("fetch size too high\n");
+                       return -EINVAL;
+               }
 
-                       // Main chunk
-                       n /= BITS_PER_LONG;
-                       while (n >= 8) {
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               *dst++ = *src++;
-                               n -= 8;
-                       }
-                       while (n--)
-                               *dst++ = *src++;
+               fsize -= 64;
+       } else
+               fsize -= fconst;
 
-                       // Trailing bits
-                       if (last)
-                               *dst = comp(*src, *dst, last);
+       /*
+        * Check if there is enough time to update the bitplane pointers for ywrap
+        */
+
+       if (par->htotal - fsize - 64 < par->bpp * 64)
+               par->vmode &= ~FB_VMODE_YWRAP;
+
+       /*
+        * Bitplane calculations and check the Memory Requirements
+        */
+
+       if (amifb_ilbm) {
+               par->next_plane = div8(upx(16 << maxfmode, par->vxres));
+               par->next_line = par->bpp * par->next_plane;
+               if (par->next_line * par->vyres > info->fix.smem_len) {
+                       DPRINTK("too few video mem\n");
+                       return -EINVAL;
                }
        } else {
-               // Different alignment for source and dest
+               par->next_line = div8(upx(16 << maxfmode, par->vxres));
+               par->next_plane = par->vyres * par->next_line;
+               if (par->next_plane * par->bpp > info->fix.smem_len) {
+                       DPRINTK("too few video mem\n");
+                       return -EINVAL;
+               }
+       }
 
-               right = shift & (BITS_PER_LONG-1);
-               left = -shift & (BITS_PER_LONG-1);
+       /*
+        * Hardware Register Values
+        */
 
-               if (dst_idx+n <= BITS_PER_LONG) {
-                       // Single destination word
-                       if (last)
-                               first &= last;
-                       if (shift > 0) {
-                               // Single source word
-                               *dst = comp(*src >> right, *dst, first);
-                       } else if (src_idx+n <= BITS_PER_LONG) {
-                               // Single source word
-                               *dst = comp(*src << left, *dst, first);
-                       } else {
-                               // 2 source words
-                               d0 = *src++;
-                               d1 = *src;
-                               *dst = comp(d0 << left | d1 >> right, *dst,
-                                           first);
-                       }
-               } else {
-                       // Multiple destination words
-                       d0 = *src++;
-                       // Leading bits
-                       if (shift > 0) {
-                               // Single source word
-                               *dst = comp(d0 >> right, *dst, first);
-                               dst++;
-                               n -= BITS_PER_LONG-dst_idx;
-                       } else {
-                               // 2 source words
-                               d1 = *src++;
-                               *dst = comp(d0 << left | d1 >> right, *dst,
-                                           first);
-                               d0 = d1;
-                               dst++;
-                               n -= BITS_PER_LONG-dst_idx;
-                       }
+       par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift];
+       if (!IS_OCS)
+               par->bplcon0 |= BPC0_ECSENA;
+       if (par->bpp == 8)
+               par->bplcon0 |= BPC0_BPU3;
+       else
+               par->bplcon0 |= par->bpp << 12;
+       if (var->nonstd == FB_NONSTD_HAM)
+               par->bplcon0 |= BPC0_HAM;
+       if (var->sync & FB_SYNC_EXT)
+               par->bplcon0 |= BPC0_ERSY;
 
-                       // Main chunk
-                       m = n % BITS_PER_LONG;
-                       n /= BITS_PER_LONG;
-                       while (n >= 4) {
-                               d1 = *src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                               d1 = *src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                               d1 = *src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                               d1 = *src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                               n -= 4;
-                       }
-                       while (n--) {
-                               d1 = *src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                       }
+       if (IS_AGA)
+               par->fmode = bplfetchmode[maxfmode];
 
-                       // Trailing bits
-                       if (last) {
-                               if (m <= right) {
-                                       // Single source word
-                                       *dst = comp(d0 << left, *dst, last);
-                               } else {
-                                       // 2 source words
-                                       d1 = *src;
-                                       *dst = comp(d0 << left | d1 >> right,
-                                                   *dst, last);
-                               }
-                       }
-               }
+       switch (par->vmode & FB_VMODE_MASK) {
+       case FB_VMODE_INTERLACED:
+               par->bplcon0 |= BPC0_LACE;
+               break;
+       case FB_VMODE_DOUBLE:
+               if (IS_AGA)
+                       par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
+               break;
        }
-}
 
+       if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {
+               par->xoffset = var->xoffset;
+               par->yoffset = var->yoffset;
+               if (par->vmode & FB_VMODE_YWRAP) {
+                       if (par->xoffset || par->yoffset < 0 ||
+                           par->yoffset >= par->vyres)
+                               par->xoffset = par->yoffset = 0;
+               } else {
+                       if (par->xoffset < 0 ||
+                           par->xoffset > upx(16 << maxfmode, par->vxres - par->xres) ||
+                           par->yoffset < 0 || par->yoffset > par->vyres - par->yres)
+                               par->xoffset = par->yoffset = 0;
+               }
+       } else
+               par->xoffset = par->yoffset = 0;
 
-    /*
-     *  Unaligned reverse bit copy using 32-bit or 64-bit memory accesses
-     */
+       par->crsr.crsr_x = par->crsr.crsr_y = 0;
+       par->crsr.spot_x = par->crsr.spot_y = 0;
+       par->crsr.height = par->crsr.width = 0;
 
-static void bitcpy_rev(unsigned long *dst, int dst_idx,
-                      const unsigned long *src, int src_idx, u32 n)
-{
-       unsigned long first, last;
-       int shift = dst_idx-src_idx, left, right;
-       unsigned long d0, d1;
-       int m;
+       return 0;
+}
 
-       if (!n)
-               return;
+       /*
+        * Fill the `var' structure based on the values in `par' and maybe
+        * other values read out of the hardware.
+        */
 
-       dst += (n-1)/BITS_PER_LONG;
-       src += (n-1)/BITS_PER_LONG;
-       if ((n-1) % BITS_PER_LONG) {
-               dst_idx += (n-1) % BITS_PER_LONG;
-               dst += dst_idx >> SHIFT_PER_LONG;
-               dst_idx &= BITS_PER_LONG-1;
-               src_idx += (n-1) % BITS_PER_LONG;
-               src += src_idx >> SHIFT_PER_LONG;
-               src_idx &= BITS_PER_LONG-1;
-       }
+static void ami_encode_var(struct fb_var_screeninfo *var,
+                          struct amifb_par *par)
+{
+       u_short clk_shift, line_shift;
 
-       shift = dst_idx-src_idx;
-       first = ~0UL << (BITS_PER_LONG-1-dst_idx);
-       last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
+       memset(var, 0, sizeof(struct fb_var_screeninfo));
 
-       if (!shift) {
-               // Same alignment for source and dest
+       clk_shift = par->clk_shift;
+       line_shift = par->line_shift;
 
-               if ((unsigned long)dst_idx+1 >= n) {
-                       // Single word
-                       if (last)
-                               first &= last;
-                       *dst = comp(*src, *dst, first);
-               } else {
-                       // Multiple destination words
-                       // Leading bits
-                       if (first) {
-                               *dst = comp(*src, *dst, first);
-                               dst--;
-                               src--;
-                               n -= dst_idx+1;
-                       }
+       var->xres = par->xres;
+       var->yres = par->yres;
+       var->xres_virtual = par->vxres;
+       var->yres_virtual = par->vyres;
+       var->xoffset = par->xoffset;
+       var->yoffset = par->yoffset;
 
-                       // Main chunk
-                       n /= BITS_PER_LONG;
-                       while (n >= 8) {
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               *dst-- = *src--;
-                               n -= 8;
-                       }
-                       while (n--)
-                               *dst-- = *src--;
+       var->bits_per_pixel = par->bpp;
+       var->grayscale = 0;
 
-                       // Trailing bits
-                       if (last)
-                               *dst = comp(*src, *dst, last);
-               }
-       } else {
-               // Different alignment for source and dest
+       var->red.offset = 0;
+       var->red.msb_right = 0;
+       var->red.length = par->bpp;
+       if (par->bplcon0 & BPC0_HAM)
+               var->red.length -= 2;
+       var->blue = var->green = var->red;
+       var->transp.offset = 0;
+       var->transp.length = 0;
+       var->transp.msb_right = 0;
 
-               right = shift & (BITS_PER_LONG-1);
-               left = -shift & (BITS_PER_LONG-1);
+       if (par->bplcon0 & BPC0_HAM)
+               var->nonstd = FB_NONSTD_HAM;
+       else
+               var->nonstd = 0;
+       var->activate = 0;
 
-               if ((unsigned long)dst_idx+1 >= n) {
-                       // Single destination word
-                       if (last)
-                               first &= last;
-                       if (shift < 0) {
-                               // Single source word
-                               *dst = comp(*src << left, *dst, first);
-                       } else if (1+(unsigned long)src_idx >= n) {
-                               // Single source word
-                               *dst = comp(*src >> right, *dst, first);
-                       } else {
-                               // 2 source words
-                               d0 = *src--;
-                               d1 = *src;
-                               *dst = comp(d0 >> right | d1 << left, *dst,
-                                           first);
-                       }
-               } else {
-                       // Multiple destination words
-                       d0 = *src--;
-                       // Leading bits
-                       if (shift < 0) {
-                               // Single source word
-                               *dst = comp(d0 << left, *dst, first);
-                               dst--;
-                               n -= dst_idx+1;
-                       } else {
-                               // 2 source words
-                               d1 = *src--;
-                               *dst = comp(d0 >> right | d1 << left, *dst,
-                                           first);
-                               d0 = d1;
-                               dst--;
-                               n -= dst_idx+1;
-                       }
+       var->height = -1;
+       var->width = -1;
 
-                       // Main chunk
-                       m = n % BITS_PER_LONG;
-                       n /= BITS_PER_LONG;
-                       while (n >= 4) {
-                               d1 = *src--;
-                               *dst-- = d0 >> right | d1 << left;
-                               d0 = d1;
-                               d1 = *src--;
-                               *dst-- = d0 >> right | d1 << left;
-                               d0 = d1;
-                               d1 = *src--;
-                               *dst-- = d0 >> right | d1 << left;
-                               d0 = d1;
-                               d1 = *src--;
-                               *dst-- = d0 >> right | d1 << left;
-                               d0 = d1;
-                               n -= 4;
-                       }
-                       while (n--) {
-                               d1 = *src--;
-                               *dst-- = d0 >> right | d1 << left;
-                               d0 = d1;
-                       }
+       var->pixclock = pixclock[clk_shift];
 
-                       // Trailing bits
-                       if (last) {
-                               if (m <= left) {
-                                       // Single source word
-                                       *dst = comp(d0 >> right, *dst, last);
-                               } else {
-                                       // 2 source words
-                                       d1 = *src;
-                                       *dst = comp(d0 >> right | d1 << left,
-                                                   *dst, last);
-                               }
-                       }
-               }
+       if (IS_AGA && par->fmode & FMODE_BSCAN2)
+               var->vmode = FB_VMODE_DOUBLE;
+       else if (par->bplcon0 & BPC0_LACE)
+               var->vmode = FB_VMODE_INTERLACED;
+       else
+               var->vmode = FB_VMODE_NONINTERLACED;
+
+       if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) {
+               var->hsync_len = (par->hsstop - par->hsstrt)>>clk_shift;
+               var->right_margin = par->hsstrt>>clk_shift;
+               var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
+               var->vsync_len = (par->vsstop - par->vsstrt)>>line_shift;
+               var->lower_margin = par->vsstrt>>line_shift;
+               var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len;
+               var->sync = 0;
+               if (par->beamcon0 & BMC0_HSYTRUE)
+                       var->sync |= FB_SYNC_HOR_HIGH_ACT;
+               if (par->beamcon0 & BMC0_VSYTRUE)
+                       var->sync |= FB_SYNC_VERT_HIGH_ACT;
+               if (par->beamcon0 & BMC0_CSYTRUE)
+                       var->sync |= FB_SYNC_COMP_HIGH_ACT;
+       } else {
+               var->sync = FB_SYNC_BROADCAST;
+               var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h);
+               var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len;
+               var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
+               var->vsync_len = 4>>line_shift;
+               var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len;
+               var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres -
+                                   var->lower_margin - var->vsync_len;
        }
+
+       if (par->bplcon0 & BPC0_ERSY)
+               var->sync |= FB_SYNC_EXT;
+       if (par->vmode & FB_VMODE_YWRAP)
+               var->vmode |= FB_VMODE_YWRAP;
 }
 
 
-    /*
-     *  Unaligned forward inverting bit copy using 32-bit or 64-bit memory
-     *  accesses
-     */
+       /*
+        * Update hardware
+        */
 
-static void bitcpy_not(unsigned long *dst, int dst_idx,
-                      const unsigned long *src, int src_idx, u32 n)
+static void ami_update_par(struct fb_info *info)
 {
-       unsigned long first, last;
-       int shift = dst_idx-src_idx, left, right;
-       unsigned long d0, d1;
-       int m;
+       struct amifb_par *par = info->par;
+       short clk_shift, vshift, fstrt, fsize, fstop, fconst,  shift, move, mod;
 
-       if (!n)
-               return;
+       clk_shift = par->clk_shift;
 
-       shift = dst_idx-src_idx;
-       first = ~0UL >> dst_idx;
-       last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+       if (!(par->vmode & FB_VMODE_SMOOTH_XPAN))
+               par->xoffset = upx(16 << maxfmode, par->xoffset);
 
-       if (!shift) {
-               // Same alignment for source and dest
+       fconst = 16 << maxfmode << clk_shift;
+       vshift = modx(16 << maxfmode, par->xoffset);
+       fstrt = par->diwstrt_h - (vshift << clk_shift) - 4;
+       fsize = (par->xres + vshift) << clk_shift;
+       shift = modx(fconst, fstrt);
+       move = downx(2 << maxfmode, div8(par->xoffset));
+       if (maxfmode + clk_shift > 1) {
+               fstrt = downx(fconst, fstrt) - 64;
+               fsize = upx(fconst, fsize);
+               fstop = fstrt + fsize - fconst;
+       } else {
+               mod = fstrt = downx(fconst, fstrt) - fconst;
+               fstop = fstrt + upx(fconst, fsize) - 64;
+               fsize = up64(fsize);
+               fstrt = fstop - fsize + 64;
+               if (fstrt < min_fstrt) {
+                       fstop += min_fstrt - fstrt;
+                       fstrt = min_fstrt;
+               }
+               move = move - div8((mod - fstrt)>>clk_shift);
+       }
+       mod = par->next_line - div8(fsize>>clk_shift);
+       par->ddfstrt = fstrt;
+       par->ddfstop = fstop;
+       par->bplcon1 = hscroll2hw(shift);
+       par->bpl2mod = mod;
+       if (par->bplcon0 & BPC0_LACE)
+               par->bpl2mod += par->next_line;
+       if (IS_AGA && (par->fmode & FMODE_BSCAN2))
+               par->bpl1mod = -div8(fsize>>clk_shift);
+       else
+               par->bpl1mod = par->bpl2mod;
 
-               if (dst_idx+n <= BITS_PER_LONG) {
-                       // Single word
-                       if (last)
-                               first &= last;
-                       *dst = comp(~*src, *dst, first);
-               } else {
-                       // Multiple destination words
-                       // Leading bits
-                       if (first) {
-                               *dst = comp(~*src, *dst, first);
-                               dst++;
-                               src++;
-                               n -= BITS_PER_LONG-dst_idx;
+       if (par->yoffset) {
+               par->bplpt0 = info->fix.smem_start +
+                             par->next_line * par->yoffset + move;
+               if (par->vmode & FB_VMODE_YWRAP) {
+                       if (par->yoffset > par->vyres - par->yres) {
+                               par->bplpt0wrap = info->fix.smem_start + move;
+                               if (par->bplcon0 & BPC0_LACE &&
+                                   mod2(par->diwstrt_v + par->vyres -
+                                        par->yoffset))
+                                       par->bplpt0wrap += par->next_line;
                        }
+               }
+       } else
+               par->bplpt0 = info->fix.smem_start + move;
 
-                       // Main chunk
-                       n /= BITS_PER_LONG;
-                       while (n >= 8) {
-                               *dst++ = ~*src++;
-                               *dst++ = ~*src++;
-                               *dst++ = ~*src++;
-                               *dst++ = ~*src++;
-                               *dst++ = ~*src++;
-                               *dst++ = ~*src++;
-                               *dst++ = ~*src++;
-                               *dst++ = ~*src++;
-                               n -= 8;
-                       }
-                       while (n--)
-                               *dst++ = ~*src++;
+       if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
+               par->bplpt0 += par->next_line;
+}
 
-                       // Trailing bits
-                       if (last)
-                               *dst = comp(~*src, *dst, last);
-               }
-       } else {
-               // Different alignment for source and dest
 
-               right = shift & (BITS_PER_LONG-1);
-               left = -shift & (BITS_PER_LONG-1);
+       /*
+        * Pan or Wrap the Display
+        *
+        * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+        * in `var'.
+        */
 
-               if (dst_idx+n <= BITS_PER_LONG) {
-                       // Single destination word
-                       if (last)
-                               first &= last;
-                       if (shift > 0) {
-                               // Single source word
-                               *dst = comp(~*src >> right, *dst, first);
-                       } else if (src_idx+n <= BITS_PER_LONG) {
-                               // Single source word
-                               *dst = comp(~*src << left, *dst, first);
-                       } else {
-                               // 2 source words
-                               d0 = ~*src++;
-                               d1 = ~*src;
-                               *dst = comp(d0 << left | d1 >> right, *dst,
-                                           first);
-                       }
-               } else {
-                       // Multiple destination words
-                       d0 = ~*src++;
-                       // Leading bits
-                       if (shift > 0) {
-                               // Single source word
-                               *dst = comp(d0 >> right, *dst, first);
-                               dst++;
-                               n -= BITS_PER_LONG-dst_idx;
-                       } else {
-                               // 2 source words
-                               d1 = ~*src++;
-                               *dst = comp(d0 << left | d1 >> right, *dst,
-                                           first);
-                               d0 = d1;
-                               dst++;
-                               n -= BITS_PER_LONG-dst_idx;
-                       }
+static void ami_pan_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct amifb_par *par = info->par;
 
-                       // Main chunk
-                       m = n % BITS_PER_LONG;
-                       n /= BITS_PER_LONG;
-                       while (n >= 4) {
-                               d1 = ~*src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                               d1 = ~*src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                               d1 = ~*src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                               d1 = ~*src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                               n -= 4;
-                       }
-                       while (n--) {
-                               d1 = ~*src++;
-                               *dst++ = d0 << left | d1 >> right;
-                               d0 = d1;
-                       }
+       par->xoffset = var->xoffset;
+       par->yoffset = var->yoffset;
+       if (var->vmode & FB_VMODE_YWRAP)
+               par->vmode |= FB_VMODE_YWRAP;
+       else
+               par->vmode &= ~FB_VMODE_YWRAP;
 
-                       // Trailing bits
-                       if (last) {
-                               if (m <= right) {
-                                       // Single source word
-                                       *dst = comp(d0 << left, *dst, last);
-                               } else {
-                                       // 2 source words
-                                       d1 = ~*src;
-                                       *dst = comp(d0 << left | d1 >> right,
-                                                   *dst, last);
-                               }
-                       }
-               }
-       }
+       do_vmode_pan = 0;
+       ami_update_par(info);
+       do_vmode_pan = 1;
 }
 
 
-    /*
-     *  Unaligned 32-bit pattern fill using 32/64-bit memory accesses
-     */
-
-static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
+static void ami_update_display(const struct amifb_par *par)
 {
-       unsigned long val = pat;
-       unsigned long first, last;
-
-       if (!n)
-               return;
+       custom.bplcon1 = par->bplcon1;
+       custom.bpl1mod = par->bpl1mod;
+       custom.bpl2mod = par->bpl2mod;
+       custom.ddfstrt = ddfstrt2hw(par->ddfstrt);
+       custom.ddfstop = ddfstop2hw(par->ddfstop);
+}
 
-#if BITS_PER_LONG == 64
-       val |= val << 32;
-#endif
+       /*
+        * Change the video mode (called by VBlank interrupt)
+        */
 
-       first = ~0UL >> dst_idx;
-       last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+static void ami_init_display(const struct amifb_par *par)
+{
+       int i;
 
-       if (dst_idx+n <= BITS_PER_LONG) {
-               // Single word
-               if (last)
-                       first &= last;
-               *dst = comp(val, *dst, first);
-       } else {
-               // Multiple destination words
-               // Leading bits
-               if (first) {
-                       *dst = comp(val, *dst, first);
-                       dst++;
-                       n -= BITS_PER_LONG-dst_idx;
+       custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
+       custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
+       if (!IS_OCS) {
+               custom.bplcon3 = par->bplcon3;
+               if (IS_AGA)
+                       custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
+               if (par->beamcon0 & BMC0_VARBEAMEN) {
+                       custom.htotal = htotal2hw(par->htotal);
+                       custom.hbstrt = hbstrt2hw(par->hbstrt);
+                       custom.hbstop = hbstop2hw(par->hbstop);
+                       custom.hsstrt = hsstrt2hw(par->hsstrt);
+                       custom.hsstop = hsstop2hw(par->hsstop);
+                       custom.hcenter = hcenter2hw(par->hcenter);
+                       custom.vtotal = vtotal2hw(par->vtotal);
+                       custom.vbstrt = vbstrt2hw(par->vbstrt);
+                       custom.vbstop = vbstop2hw(par->vbstop);
+                       custom.vsstrt = vsstrt2hw(par->vsstrt);
+                       custom.vsstop = vsstop2hw(par->vsstop);
                }
+       }
+       if (!IS_OCS || par->hsstop)
+               custom.beamcon0 = par->beamcon0;
+       if (IS_AGA)
+               custom.fmode = par->fmode;
 
-               // Main chunk
-               n /= BITS_PER_LONG;
-               while (n >= 8) {
-                       *dst++ = val;
-                       *dst++ = val;
-                       *dst++ = val;
-                       *dst++ = val;
-                       *dst++ = val;
-                       *dst++ = val;
-                       *dst++ = val;
-                       *dst++ = val;
-                       n -= 8;
-               }
-               while (n--)
-                       *dst++ = val;
+       /*
+        * The minimum period for audio depends on htotal
+        */
 
-               // Trailing bits
-               if (last)
-                       *dst = comp(val, *dst, last);
+       amiga_audio_min_period = div16(par->htotal);
+
+       is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
+#if 1
+       if (is_lace) {
+               i = custom.vposr >> 15;
+       } else {
+               custom.vposw = custom.vposr | 0x8000;
+               i = 1;
        }
+#else
+       i = 1;
+       custom.vposw = custom.vposr | 0x8000;
+#endif
+       custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]);
 }
 
+       /*
+        * (Un)Blank the screen (called by VBlank interrupt)
+        */
 
-    /*
-     *  Unaligned 32-bit pattern xor using 32/64-bit memory accesses
-     */
-
-static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
+static void ami_do_blank(const struct amifb_par *par)
 {
-       unsigned long val = pat;
-       unsigned long first, last;
-
-       if (!n)
-               return;
-
-#if BITS_PER_LONG == 64
-       val |= val << 32;
+#if defined(CONFIG_FB_AMIGA_AGA)
+       u_short bplcon3 = par->bplcon3;
 #endif
+       u_char red, green, blue;
 
-       first = ~0UL >> dst_idx;
-       last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
-
-       if (dst_idx+n <= BITS_PER_LONG) {
-               // Single word
-               if (last)
-                       first &= last;
-               *dst = xor(val, *dst, first);
-       } else {
-               // Multiple destination words
-               // Leading bits
-               if (first) {
-                       *dst = xor(val, *dst, first);
-                       dst++;
-                       n -= BITS_PER_LONG-dst_idx;
+       if (do_blank > 0) {
+               custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
+               red = green = blue = 0;
+               if (!IS_OCS && do_blank > 1) {
+                       switch (do_blank) {
+                       case FB_BLANK_VSYNC_SUSPEND:
+                               custom.hsstrt = hsstrt2hw(par->hsstrt);
+                               custom.hsstop = hsstop2hw(par->hsstop);
+                               custom.vsstrt = vsstrt2hw(par->vtotal + 4);
+                               custom.vsstop = vsstop2hw(par->vtotal + 4);
+                               break;
+                       case FB_BLANK_HSYNC_SUSPEND:
+                               custom.hsstrt = hsstrt2hw(par->htotal + 16);
+                               custom.hsstop = hsstop2hw(par->htotal + 16);
+                               custom.vsstrt = vsstrt2hw(par->vsstrt);
+                               custom.vsstop = vsstrt2hw(par->vsstop);
+                               break;
+                       case FB_BLANK_POWERDOWN:
+                               custom.hsstrt = hsstrt2hw(par->htotal + 16);
+                               custom.hsstop = hsstop2hw(par->htotal + 16);
+                               custom.vsstrt = vsstrt2hw(par->vtotal + 4);
+                               custom.vsstop = vsstop2hw(par->vtotal + 4);
+                               break;
+                       }
+                       if (!(par->beamcon0 & BMC0_VARBEAMEN)) {
+                               custom.htotal = htotal2hw(par->htotal);
+                               custom.vtotal = vtotal2hw(par->vtotal);
+                               custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN |
+                                                 BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN;
+                       }
                }
-
-               // Main chunk
-               n /= BITS_PER_LONG;
-               while (n >= 4) {
-                       *dst++ ^= val;
-                       *dst++ ^= val;
-                       *dst++ ^= val;
-                       *dst++ ^= val;
-                       n -= 4;
+       } else {
+               custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
+               red = red0;
+               green = green0;
+               blue = blue0;
+               if (!IS_OCS) {
+                       custom.hsstrt = hsstrt2hw(par->hsstrt);
+                       custom.hsstop = hsstop2hw(par->hsstop);
+                       custom.vsstrt = vsstrt2hw(par->vsstrt);
+                       custom.vsstop = vsstop2hw(par->vsstop);
+                       custom.beamcon0 = par->beamcon0;
                }
-               while (n--)
-                       *dst++ ^= val;
-
-               // Trailing bits
-               if (last)
-                       *dst = xor(val, *dst, last);
        }
-}
+#if defined(CONFIG_FB_AMIGA_AGA)
+       if (IS_AGA) {
+               custom.bplcon3 = bplcon3;
+               custom.color[0] = rgb2hw8_high(red, green, blue);
+               custom.bplcon3 = bplcon3 | BPC3_LOCT;
+               custom.color[0] = rgb2hw8_low(red, green, blue);
+               custom.bplcon3 = bplcon3;
+       } else
+#endif
+#if defined(CONFIG_FB_AMIGA_ECS)
+       if (par->bplcon0 & BPC0_SHRES) {
+               u_short color, mask;
+               int i;
 
-static inline void fill_one_line(int bpp, unsigned long next_plane,
-                                unsigned long *dst, int dst_idx, u32 n,
-                                u32 color)
-{
-       while (1) {
-               dst += dst_idx >> SHIFT_PER_LONG;
-               dst_idx &= (BITS_PER_LONG-1);
-               bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n);
-               if (!--bpp)
-                       break;
-               color >>= 1;
-               dst_idx += next_plane*8;
-       }
+               mask = 0x3333;
+               color = rgb2hw2(red, green, blue);
+               for (i = 12; i >= 0; i -= 4)
+                       custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
+               mask <<= 2; color >>= 2;
+               for (i = 3; i >= 0; i--)
+                       custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
+       } else
+#endif
+               custom.color[0] = rgb2hw4(red, green, blue);
+       is_blanked = do_blank > 0 ? do_blank : 0;
 }
 
-static inline void xor_one_line(int bpp, unsigned long next_plane,
-                               unsigned long *dst, int dst_idx, u32 n,
-                               u32 color)
+static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix,
+                                 const struct amifb_par *par)
 {
-       while (color) {
-               dst += dst_idx >> SHIFT_PER_LONG;
-               dst_idx &= (BITS_PER_LONG-1);
-               bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n);
-               if (!--bpp)
-                       break;
-               color >>= 1;
-               dst_idx += next_plane*8;
-       }
+       fix->crsr_width = fix->crsr_xsize = par->crsr.width;
+       fix->crsr_height = fix->crsr_ysize = par->crsr.height;
+       fix->crsr_color1 = 17;
+       fix->crsr_color2 = 18;
+       return 0;
 }
 
-
-static void amifb_fillrect(struct fb_info *info,
-                          const struct fb_fillrect *rect)
+static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var,
+                                 u_char __user *data,
+                                 const struct amifb_par *par)
 {
-       struct amifb_par *par = (struct amifb_par *)info->par;
-       int dst_idx, x2, y2;
-       unsigned long *dst;
-       u32 width, height;
-
-       if (!rect->width || !rect->height)
-               return;
-
-       /*
-        * We could use hardware clipping but on many cards you get around
-        * hardware clipping by writing to framebuffer directly.
-        * */
-       x2 = rect->dx + rect->width;
-       y2 = rect->dy + rect->height;
-       x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
-       y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
-       width = x2 - rect->dx;
-       height = y2 - rect->dy;
-
-       dst = (unsigned long *)
-               ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
-       dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
-       dst_idx += rect->dy*par->next_line*8+rect->dx;
-       while (height--) {
-               switch (rect->rop) {
-                   case ROP_COPY:
-                       fill_one_line(info->var.bits_per_pixel,
-                                     par->next_plane, dst, dst_idx, width,
-                                     rect->color);
-                       break;
+       register u_short *lspr, *sspr;
+#ifdef __mc68000__
+       register u_long datawords asm ("d2");
+#else
+       register u_long datawords;
+#endif
+       register short delta;
+       register u_char color;
+       short height, width, bits, words;
+       int size, alloc;
 
-                   case ROP_XOR:
-                       xor_one_line(info->var.bits_per_pixel, par->next_plane,
-                                    dst, dst_idx, width, rect->color);
-                       break;
+       size = par->crsr.height * par->crsr.width;
+       alloc = var->height * var->width;
+       var->height = par->crsr.height;
+       var->width = par->crsr.width;
+       var->xspot = par->crsr.spot_x;
+       var->yspot = par->crsr.spot_y;
+       if (size > var->height * var->width)
+               return -ENAMETOOLONG;
+       if (!access_ok(VERIFY_WRITE, data, size))
+               return -EFAULT;
+       delta = 1 << par->crsr.fmode;
+       lspr = lofsprite + (delta << 1);
+       if (par->bplcon0 & BPC0_LACE)
+               sspr = shfsprite + (delta << 1);
+       else
+               sspr = NULL;
+       for (height = (short)var->height - 1; height >= 0; height--) {
+               bits = 0; words = delta; datawords = 0;
+               for (width = (short)var->width - 1; width >= 0; width--) {
+                       if (bits == 0) {
+                               bits = 16; --words;
+#ifdef __mc68000__
+                               asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0"
+                                       : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta));
+#else
+                               datawords = (*(lspr + delta) << 16) | (*lspr++);
+#endif
+                       }
+                       --bits;
+#ifdef __mc68000__
+                       asm volatile (
+                               "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; "
+                               "swap %1 ; lslw #1,%1 ; roxlb #1,%0"
+                               : "=d" (color), "=d" (datawords) : "1" (datawords));
+#else
+                       color = (((datawords >> 30) & 2)
+                                | ((datawords >> 15) & 1));
+                       datawords <<= 1;
+#endif
+                       put_user(color, data++);
+               }
+               if (bits > 0) {
+                       --words; ++lspr;
+               }
+               while (--words >= 0)
+                       ++lspr;
+#ifdef __mc68000__
+               asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
+                       : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
+#else
+               lspr += delta;
+               if (sspr) {
+                       u_short *tmp = lspr;
+                       lspr = sspr;
+                       sspr = tmp;
                }
-               dst_idx += par->next_line*8;
+#endif
        }
+       return 0;
 }
 
-static inline void copy_one_line(int bpp, unsigned long next_plane,
-                                unsigned long *dst, int dst_idx,
-                                unsigned long *src, int src_idx, u32 n)
+static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var,
+                                 u_char __user *data, struct amifb_par *par)
 {
-       while (1) {
-               dst += dst_idx >> SHIFT_PER_LONG;
-               dst_idx &= (BITS_PER_LONG-1);
-               src += src_idx >> SHIFT_PER_LONG;
-               src_idx &= (BITS_PER_LONG-1);
-               bitcpy(dst, dst_idx, src, src_idx, n);
-               if (!--bpp)
-                       break;
-               dst_idx += next_plane*8;
-               src_idx += next_plane*8;
-       }
-}
+       register u_short *lspr, *sspr;
+#ifdef __mc68000__
+       register u_long datawords asm ("d2");
+#else
+       register u_long datawords;
+#endif
+       register short delta;
+       u_short fmode;
+       short height, width, bits, words;
 
-static inline void copy_one_line_rev(int bpp, unsigned long next_plane,
-                                    unsigned long *dst, int dst_idx,
-                                    unsigned long *src, int src_idx, u32 n)
-{
-       while (1) {
-               dst += dst_idx >> SHIFT_PER_LONG;
-               dst_idx &= (BITS_PER_LONG-1);
-               src += src_idx >> SHIFT_PER_LONG;
-               src_idx &= (BITS_PER_LONG-1);
-               bitcpy_rev(dst, dst_idx, src, src_idx, n);
-               if (!--bpp)
-                       break;
-               dst_idx += next_plane*8;
-               src_idx += next_plane*8;
+       if (!var->width)
+               return -EINVAL;
+       else if (var->width <= 16)
+               fmode = TAG_FMODE_1;
+       else if (var->width <= 32)
+               fmode = TAG_FMODE_2;
+       else if (var->width <= 64)
+               fmode = TAG_FMODE_4;
+       else
+               return -EINVAL;
+       if (fmode > maxfmode)
+               return -EINVAL;
+       if (!var->height)
+               return -EINVAL;
+       if (!access_ok(VERIFY_READ, data, var->width * var->height))
+               return -EFAULT;
+       delta = 1 << fmode;
+       lofsprite = shfsprite = (u_short *)spritememory;
+       lspr = lofsprite + (delta << 1);
+       if (par->bplcon0 & BPC0_LACE) {
+               if (((var->height + 4) << fmode << 2) > SPRITEMEMSIZE)
+                       return -EINVAL;
+               memset(lspr, 0, (var->height + 4) << fmode << 2);
+               shfsprite += ((var->height + 5)&-2) << fmode;
+               sspr = shfsprite + (delta << 1);
+       } else {
+               if (((var->height + 2) << fmode << 2) > SPRITEMEMSIZE)
+                       return -EINVAL;
+               memset(lspr, 0, (var->height + 2) << fmode << 2);
+               sspr = NULL;
        }
-}
-
-
-static void amifb_copyarea(struct fb_info *info,
-                          const struct fb_copyarea *area)
-{
-       struct amifb_par *par = (struct amifb_par *)info->par;
-       int x2, y2;
-       u32 dx, dy, sx, sy, width, height;
-       unsigned long *dst, *src;
-       int dst_idx, src_idx;
-       int rev_copy = 0;
-
-       /* clip the destination */
-       x2 = area->dx + area->width;
-       y2 = area->dy + area->height;
-       dx = area->dx > 0 ? area->dx : 0;
-       dy = area->dy > 0 ? area->dy : 0;
-       x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
-       y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
-       width = x2 - dx;
-       height = y2 - dy;
-
-       if (area->sx + dx < area->dx || area->sy + dy < area->dy)
-               return;
-
-       /* update sx,sy */
-       sx = area->sx + (dx - area->dx);
-       sy = area->sy + (dy - area->dy);
-
-       /* the source must be completely inside the virtual screen */
-       if (sx + width > info->var.xres_virtual ||
-                       sy + height > info->var.yres_virtual)
-               return;
-
-       if (dy > sy || (dy == sy && dx > sx)) {
-               dy += height;
-               sy += height;
-               rev_copy = 1;
-       }
-       dst = (unsigned long *)
-               ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
-       src = dst;
-       dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
-       src_idx = dst_idx;
-       dst_idx += dy*par->next_line*8+dx;
-       src_idx += sy*par->next_line*8+sx;
-       if (rev_copy) {
-               while (height--) {
-                       dst_idx -= par->next_line*8;
-                       src_idx -= par->next_line*8;
-                       copy_one_line_rev(info->var.bits_per_pixel,
-                                         par->next_plane, dst, dst_idx, src,
-                                         src_idx, width);
+       for (height = (short)var->height - 1; height >= 0; height--) {
+               bits = 16; words = delta; datawords = 0;
+               for (width = (short)var->width - 1; width >= 0; width--) {
+                       unsigned long tdata = 0;
+                       get_user(tdata, data);
+                       data++;
+#ifdef __mc68000__
+                       asm volatile (
+                               "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; "
+                               "lsrb #1,%2 ; roxlw #1,%0 ; swap %0"
+                               : "=d" (datawords)
+                               : "0" (datawords), "d" (tdata));
+#else
+                       datawords = ((datawords << 1) & 0xfffefffe);
+                       datawords |= tdata & 1;
+                       datawords |= (tdata & 2) << (16 - 1);
+#endif
+                       if (--bits == 0) {
+                               bits = 16; --words;
+#ifdef __mc68000__
+                               asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+"
+                                       : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta));
+#else
+                               *(lspr + delta) = (u_short) (datawords >> 16);
+                               *lspr++ = (u_short) (datawords & 0xffff);
+#endif
+                       }
                }
-       } else {
-               while (height--) {
-                       copy_one_line(info->var.bits_per_pixel,
-                                     par->next_plane, dst, dst_idx, src,
-                                     src_idx, width);
-                       dst_idx += par->next_line*8;
-                       src_idx += par->next_line*8;
+               if (bits < 16) {
+                       --words;
+#ifdef __mc68000__
+                       asm volatile (
+                               "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; "
+                               "swap %2 ; lslw %4,%2 ; movew %2,%0@+"
+                               : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits));
+#else
+                       *(lspr + delta) = (u_short) (datawords >> (16 + bits));
+                       *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits);
+#endif
+               }
+               while (--words >= 0) {
+#ifdef __mc68000__
+                       asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+"
+                               : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0");
+#else
+                       *(lspr + delta) = 0;
+                       *lspr++ = 0;
+#endif
+               }
+#ifdef __mc68000__
+               asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
+                       : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
+#else
+               lspr += delta;
+               if (sspr) {
+                       u_short *tmp = lspr;
+                       lspr = sspr;
+                       sspr = tmp;
                }
+#endif
+       }
+       par->crsr.height = var->height;
+       par->crsr.width = var->width;
+       par->crsr.spot_x = var->xspot;
+       par->crsr.spot_y = var->yspot;
+       par->crsr.fmode = fmode;
+       if (IS_AGA) {
+               par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32);
+               par->fmode |= sprfetchmode[fmode];
+               custom.fmode = par->fmode;
        }
+       return 0;
 }
 
-
-static inline void expand_one_line(int bpp, unsigned long next_plane,
-                                  unsigned long *dst, int dst_idx, u32 n,
-                                  const u8 *data, u32 bgcolor, u32 fgcolor)
+static int ami_get_cursorstate(struct fb_cursorstate *state,
+                              const struct amifb_par *par)
 {
-    const unsigned long *src;
-    int src_idx;
-
-    while (1) {
-       dst += dst_idx >> SHIFT_PER_LONG;
-       dst_idx &= (BITS_PER_LONG-1);
-       if ((bgcolor ^ fgcolor) & 1) {
-           src = (unsigned long *)((unsigned long)data & ~(BYTES_PER_LONG-1));
-           src_idx = ((unsigned long)data & (BYTES_PER_LONG-1))*8;
-           if (fgcolor & 1)
-               bitcpy(dst, dst_idx, src, src_idx, n);
-           else
-               bitcpy_not(dst, dst_idx, src, src_idx, n);
-           /* set or clear */
-       } else
-           bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n);
-       if (!--bpp)
-           break;
-       bgcolor >>= 1;
-       fgcolor >>= 1;
-       dst_idx += next_plane*8;
-    }
+       state->xoffset = par->crsr.crsr_x;
+       state->yoffset = par->crsr.crsr_y;
+       state->mode = cursormode;
+       return 0;
 }
 
-
-static void amifb_imageblit(struct fb_info *info, const struct fb_image *image)
+static int ami_set_cursorstate(struct fb_cursorstate *state,
+                              struct amifb_par *par)
 {
-       struct amifb_par *par = (struct amifb_par *)info->par;
-       int x2, y2;
-       unsigned long *dst;
-       int dst_idx;
-       const char *src;
-       u32 dx, dy, width, height, pitch;
+       par->crsr.crsr_x = state->xoffset;
+       par->crsr.crsr_y = state->yoffset;
+       if ((cursormode = state->mode) == FB_CURSOR_OFF)
+               cursorstate = -1;
+       do_cursor = 1;
+       return 0;
+}
 
-       /*
-        * We could use hardware clipping but on many cards you get around
-        * hardware clipping by writing to framebuffer directly like we are
-        * doing here.
-        */
-       x2 = image->dx + image->width;
-       y2 = image->dy + image->height;
-       dx = image->dx;
-       dy = image->dy;
-       x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
-       y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
-       width  = x2 - dx;
-       height = y2 - dy;
+static void ami_set_sprite(const struct amifb_par *par)
+{
+       copins *copl, *cops;
+       u_short hs, vs, ve;
+       u_long pl, ps, pt;
+       short mx, my;
 
-       if (image->depth == 1) {
-               dst = (unsigned long *)
-                       ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
-               dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
-               dst_idx += dy*par->next_line*8+dx;
-               src = image->data;
-               pitch = (image->width+7)/8;
-               while (height--) {
-                       expand_one_line(info->var.bits_per_pixel,
-                                       par->next_plane, dst, dst_idx, width,
-                                       src, image->bg_color,
-                                       image->fg_color);
-                       dst_idx += par->next_line*8;
-                       src += pitch;
+       cops = copdisplay.list[currentcop][0];
+       copl = copdisplay.list[currentcop][1];
+       ps = pl = ZTWO_PADDR(dummysprite);
+       mx = par->crsr.crsr_x - par->crsr.spot_x;
+       my = par->crsr.crsr_y - par->crsr.spot_y;
+       if (!(par->vmode & FB_VMODE_YWRAP)) {
+               mx -= par->xoffset;
+               my -= par->yoffset;
+       }
+       if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 &&
+           mx > -(short)par->crsr.width && mx < par->xres &&
+           my > -(short)par->crsr.height && my < par->yres) {
+               pl = ZTWO_PADDR(lofsprite);
+               hs = par->diwstrt_h + (mx << par->clk_shift) - 4;
+               vs = par->diwstrt_v + (my << par->line_shift);
+               ve = vs + (par->crsr.height << par->line_shift);
+               if (par->bplcon0 & BPC0_LACE) {
+                       ps = ZTWO_PADDR(shfsprite);
+                       lofsprite[0] = spr2hw_pos(vs, hs);
+                       shfsprite[0] = spr2hw_pos(vs + 1, hs);
+                       if (mod2(vs)) {
+                               lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
+                               shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve + 1);
+                               pt = pl; pl = ps; ps = pt;
+                       } else {
+                               lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve + 1);
+                               shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve);
+                       }
+               } else {
+                       lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0);
+                       lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
                }
-       } else {
-               c2p_planar(info->screen_base, image->data, dx, dy, width,
-                          height, par->next_line, par->next_plane,
-                          image->width, info->var.bits_per_pixel);
+       }
+       copl[cop_spr0ptrh].w[1] = highw(pl);
+       copl[cop_spr0ptrl].w[1] = loww(pl);
+       if (par->bplcon0 & BPC0_LACE) {
+               cops[cop_spr0ptrh].w[1] = highw(ps);
+               cops[cop_spr0ptrl].w[1] = loww(ps);
        }
 }
 
 
        /*
-        * Amiga Frame Buffer Specific ioctls
+        * Initialise the Copper Initialisation List
         */
 
-static int amifb_ioctl(struct fb_info *info,
-                      unsigned int cmd, unsigned long arg)
+static void __init ami_init_copper(void)
 {
-       union {
-               struct fb_fix_cursorinfo fix;
-               struct fb_var_cursorinfo var;
-               struct fb_cursorstate state;
-       } crsr;
-       void __user *argp = (void __user *)arg;
+       copins *cop = copdisplay.init;
+       u_long p;
        int i;
 
-       switch (cmd) {
-               case FBIOGET_FCURSORINFO:
-                       i = ami_get_fix_cursorinfo(&crsr.fix);
-                       if (i)
-                               return i;
-                       return copy_to_user(argp, &crsr.fix,
-                                           sizeof(crsr.fix)) ? -EFAULT : 0;
-
-               case FBIOGET_VCURSORINFO:
-                       i = ami_get_var_cursorinfo(&crsr.var,
-                               ((struct fb_var_cursorinfo __user *)arg)->data);
-                       if (i)
-                               return i;
-                       return copy_to_user(argp, &crsr.var,
-                                           sizeof(crsr.var)) ? -EFAULT : 0;
-
-               case FBIOPUT_VCURSORINFO:
-                       if (copy_from_user(&crsr.var, argp, sizeof(crsr.var)))
-                               return -EFAULT;
-                       return ami_set_var_cursorinfo(&crsr.var,
-                               ((struct fb_var_cursorinfo __user *)arg)->data);
-
-               case FBIOGET_CURSORSTATE:
-                       i = ami_get_cursorstate(&crsr.state);
-                       if (i)
-                               return i;
-                       return copy_to_user(argp, &crsr.state,
-                                           sizeof(crsr.state)) ? -EFAULT : 0;
-
-               case FBIOPUT_CURSORSTATE:
-                       if (copy_from_user(&crsr.state, argp,
-                                          sizeof(crsr.state)))
-                               return -EFAULT;
-                       return ami_set_cursorstate(&crsr.state);
+       if (!IS_OCS) {
+               (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
+               (cop++)->l = CMOVE(0x0181, diwstrt);
+               (cop++)->l = CMOVE(0x0281, diwstop);
+               (cop++)->l = CMOVE(0x0000, diwhigh);
+       } else
+               (cop++)->l = CMOVE(BPC0_COLOR, bplcon0);
+       p = ZTWO_PADDR(dummysprite);
+       for (i = 0; i < 8; i++) {
+               (cop++)->l = CMOVE(0, spr[i].pos);
+               (cop++)->l = CMOVE(highw(p), sprpt[i]);
+               (cop++)->l = CMOVE2(loww(p), sprpt[i]);
        }
-       return -EINVAL;
-}
-
 
-       /*
-        * Allocate, Clear and Align a Block of Chip Memory
-        */
-
-static void *aligned_chipptr;
+       (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);
+       copdisplay.wait = cop;
+       (cop++)->l = CEND;
+       (cop++)->l = CMOVE(0, copjmp2);
+       cop->l = CEND;
 
-static inline u_long __init chipalloc(u_long size)
-{
-       aligned_chipptr = amiga_chip_alloc(size, "amifb [RAM]");
-       if (!aligned_chipptr) {
-               pr_err("amifb: No Chip RAM for frame buffer");
-               return 0;
-       }
-       memset(aligned_chipptr, 0, size);
-       return (u_long)aligned_chipptr;
+       custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);
+       custom.copjmp1 = 0;
 }
 
-static inline void chipfree(void)
+static void ami_reinit_copper(const struct amifb_par *par)
 {
-       if (aligned_chipptr)
-               amiga_chip_free(aligned_chipptr);
+       copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0;
+       copdisplay.wait->l = CWAIT(32, par->diwstrt_v - 4);
 }
 
 
        /*
-        * Initialisation
+        * Rebuild the Copper List
+        *
+        * We only change the things that are not static
         */
 
-static int __init amifb_probe(struct platform_device *pdev)
+static void ami_rebuild_copper(const struct amifb_par *par)
 {
-       int tag, i, err = 0;
-       u_long chipptr;
-       u_int defmode;
-
-#ifndef MODULE
-       char *option = NULL;
+       copins *copl, *cops;
+       u_short line, h_end1, h_end2;
+       short i;
+       u_long p;
 
-       if (fb_get_options("amifb", &option)) {
-               amifb_video_off();
-               return -ENODEV;
-       }
-       amifb_setup(option);
-#endif
-       custom.dmacon = DMAF_ALL | DMAF_MASTER;
-
-       switch (amiga_chipset) {
-#ifdef CONFIG_FB_AMIGA_OCS
-               case CS_OCS:
-                       strcat(fb_info.fix.id, "OCS");
-default_chipset:
-                       chipset = TAG_OCS;
-                       maxdepth[TAG_SHRES] = 0;        /* OCS means no SHRES */
-                       maxdepth[TAG_HIRES] = 4;
-                       maxdepth[TAG_LORES] = 6;
-                       maxfmode = TAG_FMODE_1;
-                       defmode = amiga_vblank == 50 ? DEFMODE_PAL
-                                                    : DEFMODE_NTSC;
-                       fb_info.fix.smem_len = VIDEOMEMSIZE_OCS;
-                       break;
-#endif /* CONFIG_FB_AMIGA_OCS */
-
-#ifdef CONFIG_FB_AMIGA_ECS
-               case CS_ECS:
-                       strcat(fb_info.fix.id, "ECS");
-                       chipset = TAG_ECS;
-                       maxdepth[TAG_SHRES] = 2;
-                       maxdepth[TAG_HIRES] = 4;
-                       maxdepth[TAG_LORES] = 6;
-                       maxfmode = TAG_FMODE_1;
-                       if (AMIGAHW_PRESENT(AMBER_FF))
-                           defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL
-                                                        : DEFMODE_AMBER_NTSC;
-                       else
-                           defmode = amiga_vblank == 50 ? DEFMODE_PAL
-                                                        : DEFMODE_NTSC;
-                       if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
-                           VIDEOMEMSIZE_ECS_2M)
-                               fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M;
-                       else
-                               fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M;
-                       break;
-#endif /* CONFIG_FB_AMIGA_ECS */
+       if (IS_AGA && maxfmode + par->clk_shift == 0)
+               h_end1 = par->diwstrt_h - 64;
+       else
+               h_end1 = par->htotal - 32;
+       h_end2 = par->ddfstop + 64;
 
-#ifdef CONFIG_FB_AMIGA_AGA
-               case CS_AGA:
-                       strcat(fb_info.fix.id, "AGA");
-                       chipset = TAG_AGA;
-                       maxdepth[TAG_SHRES] = 8;
-                       maxdepth[TAG_HIRES] = 8;
-                       maxdepth[TAG_LORES] = 8;
-                       maxfmode = TAG_FMODE_4;
-                       defmode = DEFMODE_AGA;
-                       if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
-                           VIDEOMEMSIZE_AGA_2M)
-                               fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M;
-                       else
-                               fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M;
-                       break;
-#endif /* CONFIG_FB_AMIGA_AGA */
+       ami_set_sprite(par);
 
-               default:
-#ifdef CONFIG_FB_AMIGA_OCS
-                       printk("Unknown graphics chipset, defaulting to OCS\n");
-                       strcat(fb_info.fix.id, "Unknown");
-                       goto default_chipset;
-#else /* CONFIG_FB_AMIGA_OCS */
-                       err = -ENODEV;
-                       goto amifb_error;
-#endif /* CONFIG_FB_AMIGA_OCS */
-                       break;
+       copl = copdisplay.rebuild[1];
+       p = par->bplpt0;
+       if (par->vmode & FB_VMODE_YWRAP) {
+               if ((par->vyres - par->yoffset) != 1 || !mod2(par->diwstrt_v)) {
+                       if (par->yoffset > par->vyres - par->yres) {
+                               for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
+                                       (copl++)->l = CMOVE(highw(p), bplpt[i]);
+                                       (copl++)->l = CMOVE2(loww(p), bplpt[i]);
+                               }
+                               line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 1;
+                               while (line >= 512) {
+                                       (copl++)->l = CWAIT(h_end1, 510);
+                                       line -= 512;
+                               }
+                               if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0)
+                                       (copl++)->l = CWAIT(h_end1, line);
+                               else
+                                       (copl++)->l = CWAIT(h_end2, line);
+                               p = par->bplpt0wrap;
+                       }
+               } else
+                       p = par->bplpt0wrap;
        }
-
-       /*
-        * Calculate the Pixel Clock Values for this Machine
-        */
-
-       {
-       u_long tmp = DIVUL(200000000000ULL, amiga_eclock);
-
-       pixclock[TAG_SHRES] = (tmp + 4) / 8;    /* SHRES:  35 ns / 28 MHz */
-       pixclock[TAG_HIRES] = (tmp + 2) / 4;    /* HIRES:  70 ns / 14 MHz */
-       pixclock[TAG_LORES] = (tmp + 1) / 2;    /* LORES: 140 ns /  7 MHz */
+       for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
+               (copl++)->l = CMOVE(highw(p), bplpt[i]);
+               (copl++)->l = CMOVE2(loww(p), bplpt[i]);
        }
+       copl->l = CEND;
 
-       /*
-        * Replace the Tag Values with the Real Pixel Clock Values
-        */
-
-       for (i = 0; i < NUM_TOTAL_MODES; i++) {
-               struct fb_videomode *mode = &ami_modedb[i];
-               tag = mode->pixclock;
-               if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
-                       mode->pixclock = pixclock[tag];
+       if (par->bplcon0 & BPC0_LACE) {
+               cops = copdisplay.rebuild[0];
+               p = par->bplpt0;
+               if (mod2(par->diwstrt_v))
+                       p -= par->next_line;
+               else
+                       p += par->next_line;
+               if (par->vmode & FB_VMODE_YWRAP) {
+                       if ((par->vyres - par->yoffset) != 1 || mod2(par->diwstrt_v)) {
+                               if (par->yoffset > par->vyres - par->yres + 1) {
+                                       for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
+                                               (cops++)->l = CMOVE(highw(p), bplpt[i]);
+                                               (cops++)->l = CMOVE2(loww(p), bplpt[i]);
+                                       }
+                                       line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 2;
+                                       while (line >= 512) {
+                                               (cops++)->l = CWAIT(h_end1, 510);
+                                               line -= 512;
+                                       }
+                                       if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0)
+                                               (cops++)->l = CWAIT(h_end1, line);
+                                       else
+                                               (cops++)->l = CWAIT(h_end2, line);
+                                       p = par->bplpt0wrap;
+                                       if (mod2(par->diwstrt_v + par->vyres -
+                                           par->yoffset))
+                                               p -= par->next_line;
+                                       else
+                                               p += par->next_line;
+                               }
+                       } else
+                               p = par->bplpt0wrap - par->next_line;
+               }
+               for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
+                       (cops++)->l = CMOVE(highw(p), bplpt[i]);
+                       (cops++)->l = CMOVE2(loww(p), bplpt[i]);
                }
+               cops->l = CEND;
        }
+}
+
 
        /*
-        *  These monitor specs are for a typical Amiga monitor (e.g. A1960)
+        * Build the Copper List
         */
-       if (fb_info.monspecs.hfmin == 0) {
-           fb_info.monspecs.hfmin = 15000;
-           fb_info.monspecs.hfmax = 38000;
-           fb_info.monspecs.vfmin = 49;
-           fb_info.monspecs.vfmax = 90;
-       }
 
-       fb_info.fbops = &amifb_ops;
-       fb_info.par = &currentpar;
-       fb_info.flags = FBINFO_DEFAULT;
-       fb_info.device = &pdev->dev;
+static void ami_build_copper(struct fb_info *info)
+{
+       struct amifb_par *par = info->par;
+       copins *copl, *cops;
+       u_long p;
 
-       if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb,
-                         NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
-               err = -EINVAL;
-               goto amifb_error;
-       }
+       currentcop = 1 - currentcop;
 
-       fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES,
-                                &fb_info.modelist);
+       copl = copdisplay.list[currentcop][1];
 
-       round_down_bpp = 0;
-       chipptr = chipalloc(fb_info.fix.smem_len+
-                           SPRITEMEMSIZE+
-                           DUMMYSPRITEMEMSIZE+
-                           COPINITSIZE+
-                           4*COPLISTSIZE);
-       if (!chipptr) {
-               err = -ENOMEM;
-               goto amifb_error;
-       }
+       (copl++)->l = CWAIT(0, 10);
+       (copl++)->l = CMOVE(par->bplcon0, bplcon0);
+       (copl++)->l = CMOVE(0, sprpt[0]);
+       (copl++)->l = CMOVE2(0, sprpt[0]);
 
-       assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len);
-       assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
-       assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
-       assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
-       assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);
-       assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);
-       assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);
-       assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);
+       if (par->bplcon0 & BPC0_LACE) {
+               cops = copdisplay.list[currentcop][0];
 
-       /*
-        * access the videomem with writethrough cache
-        */
-       fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory);
-       videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start,
-                                                  fb_info.fix.smem_len);
-       if (!videomemory) {
-               printk("amifb: WARNING! unable to map videomem cached writethrough\n");
-               fb_info.screen_base = (char *)ZTWO_VADDR(fb_info.fix.smem_start);
-       } else
-               fb_info.screen_base = (char *)videomemory;
+               (cops++)->l = CWAIT(0, 10);
+               (cops++)->l = CMOVE(par->bplcon0, bplcon0);
+               (cops++)->l = CMOVE(0, sprpt[0]);
+               (cops++)->l = CMOVE2(0, sprpt[0]);
 
-       memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
+               (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v + 1), diwstrt);
+               (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v + 1), diwstop);
+               (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
+               (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
+               if (!IS_OCS) {
+                       (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v + 1,
+                                           par->diwstop_h, par->diwstop_v + 1), diwhigh);
+                       (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
+                                           par->diwstop_h, par->diwstop_v), diwhigh);
+#if 0
+                       if (par->beamcon0 & BMC0_VARBEAMEN) {
+                               (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
+                               (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt + 1), vbstrt);
+                               (copl++)->l = CMOVE(vbstop2hw(par->vbstop + 1), vbstop);
+                               (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
+                               (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
+                               (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
+                       }
+#endif
+               }
+               p = ZTWO_PADDR(copdisplay.list[currentcop][0]);
+               (copl++)->l = CMOVE(highw(p), cop2lc);
+               (copl++)->l = CMOVE2(loww(p), cop2lc);
+               p = ZTWO_PADDR(copdisplay.list[currentcop][1]);
+               (cops++)->l = CMOVE(highw(p), cop2lc);
+               (cops++)->l = CMOVE2(loww(p), cop2lc);
+               copdisplay.rebuild[0] = cops;
+       } else {
+               (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
+               (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
+               if (!IS_OCS) {
+                       (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
+                                           par->diwstop_h, par->diwstop_v), diwhigh);
+#if 0
+                       if (par->beamcon0 & BMC0_VARBEAMEN) {
+                               (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
+                               (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
+                               (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
+                       }
+#endif
+               }
+       }
+       copdisplay.rebuild[1] = copl;
 
-       /*
-        * Enable Display DMA
-        */
+       ami_update_par(info);
+       ami_rebuild_copper(info->par);
+}
 
-       custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
-                       DMAF_BLITTER | DMAF_SPRITE;
 
-       /*
-        * Make sure the Copper has something to do
+static void __init amifb_setup_mcap(char *spec)
+{
+       char *p;
+       int vmin, vmax, hmin, hmax;
+
+       /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
+        * <V*> vertical freq. in Hz
+        * <H*> horizontal freq. in kHz
         */
 
-       ami_init_copper();
+       if (!(p = strsep(&spec, ";")) || !*p)
+               return;
+       vmin = simple_strtoul(p, NULL, 10);
+       if (vmin <= 0)
+               return;
+       if (!(p = strsep(&spec, ";")) || !*p)
+               return;
+       vmax = simple_strtoul(p, NULL, 10);
+       if (vmax <= 0 || vmax <= vmin)
+               return;
+       if (!(p = strsep(&spec, ";")) || !*p)
+               return;
+       hmin = 1000 * simple_strtoul(p, NULL, 10);
+       if (hmin <= 0)
+               return;
+       if (!(p = strsep(&spec, "")) || !*p)
+               return;
+       hmax = 1000 * simple_strtoul(p, NULL, 10);
+       if (hmax <= 0 || hmax <= hmin)
+               return;
 
-       if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,
-                       "fb vertb handler", &currentpar)) {
-               err = -EBUSY;
-               goto amifb_error;
-       }
+       amifb_hfmin = hmin;
+       amifb_hfmax = hmax;
+       amifb_vfmin = vmin;
+       amifb_vfmax = vmax;
+}
 
-       err = fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0);
-       if (err)
-               goto amifb_error;
+static int __init amifb_setup(char *options)
+{
+       char *this_opt;
 
-       if (register_framebuffer(&fb_info) < 0) {
-               err = -EINVAL;
-               goto amifb_error;
+       if (!options || !*options)
+               return 0;
+
+       while ((this_opt = strsep(&options, ",")) != NULL) {
+               if (!*this_opt)
+                       continue;
+               if (!strcmp(this_opt, "inverse")) {
+                       amifb_inverse = 1;
+                       fb_invert_cmaps();
+               } else if (!strcmp(this_opt, "ilbm"))
+                       amifb_ilbm = 1;
+               else if (!strncmp(this_opt, "monitorcap:", 11))
+                       amifb_setup_mcap(this_opt + 11);
+               else if (!strncmp(this_opt, "fstart:", 7))
+                       min_fstrt = simple_strtoul(this_opt + 7, NULL, 0);
+               else
+                       mode_option = this_opt;
        }
 
-       printk("fb%d: %s frame buffer device, using %dK of video memory\n",
-              fb_info.node, fb_info.fix.id, fb_info.fix.smem_len>>10);
+       if (min_fstrt < 48)
+               min_fstrt = 48;
 
        return 0;
-
-amifb_error:
-       amifb_deinit(pdev);
-       return err;
 }
 
-static void amifb_deinit(struct platform_device *pdev)
+
+static int amifb_check_var(struct fb_var_screeninfo *var,
+                          struct fb_info *info)
 {
-       if (fb_info.cmap.len)
-               fb_dealloc_cmap(&fb_info.cmap);
-       fb_dealloc_cmap(&fb_info.cmap);
-       chipfree();
-       if (videomemory)
-               iounmap((void*)videomemory);
-       custom.dmacon = DMAF_ALL | DMAF_MASTER;
+       int err;
+       struct amifb_par par;
+
+       /* Validate wanted screen parameters */
+       err = ami_decode_var(var, &par, info);
+       if (err)
+               return err;
+
+       /* Encode (possibly rounded) screen parameters */
+       ami_encode_var(var, &par);
+       return 0;
 }
 
 
-       /*
-        * Blank the display.
-        */
-
-static int amifb_blank(int blank, struct fb_info *info)
-{
-       do_blank = blank ? blank : -1;
-
-       return 0;
-}
-
-       /*
-        * Flash the cursor (called by VBlank interrupt)
-        */
-
-static int flash_cursor(void)
+static int amifb_set_par(struct fb_info *info)
 {
-       static int cursorcount = 1;
+       struct amifb_par *par = info->par;
+       int error;
 
-       if (cursormode == FB_CURSOR_FLASH) {
-               if (!--cursorcount) {
-                       cursorstate = -cursorstate;
-                       cursorcount = cursorrate;
-                       if (!is_blanked)
-                               return 1;
-               }
-       }
-       return 0;
-}
+       do_vmode_pan = 0;
+       do_vmode_full = 0;
 
-       /*
-        * VBlank Display Interrupt
-        */
+       /* Decode wanted screen parameters */
+       error = ami_decode_var(&info->var, par, info);
+       if (error)
+               return error;
 
-static irqreturn_t amifb_interrupt(int irq, void *dev_id)
-{
-       if (do_vmode_pan || do_vmode_full)
-               ami_update_display();
+       /* Set new videomode */
+       ami_build_copper(info);
 
-       if (do_vmode_full)
-               ami_init_display();
+       /* Set VBlank trigger */
+       do_vmode_full = 1;
 
-       if (do_vmode_pan) {
-               flash_cursor();
-               ami_rebuild_copper();
-               do_cursor = do_vmode_pan = 0;
-       } else if (do_cursor) {
-               flash_cursor();
-               ami_set_sprite();
-               do_cursor = 0;
+       /* Update fix for new screen parameters */
+       if (par->bpp == 1) {
+               info->fix.type = FB_TYPE_PACKED_PIXELS;
+               info->fix.type_aux = 0;
+       } else if (amifb_ilbm) {
+               info->fix.type = FB_TYPE_INTERLEAVED_PLANES;
+               info->fix.type_aux = par->next_line;
        } else {
-               if (flash_cursor())
-                       ami_set_sprite();
-       }
-
-       if (do_blank) {
-               ami_do_blank();
-               do_blank = 0;
+               info->fix.type = FB_TYPE_PLANES;
+               info->fix.type_aux = 0;
        }
+       info->fix.line_length = div8(upx(16 << maxfmode, par->vxres));
 
-       if (do_vmode_full) {
-               ami_reinit_copper();
-               do_vmode_full = 0;
+       if (par->vmode & FB_VMODE_YWRAP) {
+               info->fix.ywrapstep = 1;
+               info->fix.xpanstep = 0;
+               info->fix.ypanstep = 0;
+               info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP |
+                       FBINFO_READS_FAST; /* override SCROLL_REDRAW */
+       } else {
+               info->fix.ywrapstep = 0;
+               if (par->vmode & FB_VMODE_SMOOTH_XPAN)
+                       info->fix.xpanstep = 1;
+               else
+                       info->fix.xpanstep = 16 << maxfmode;
+               info->fix.ypanstep = 1;
+               info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
        }
-       return IRQ_HANDLED;
+       return 0;
 }
 
-/* --------------------------- Hardware routines --------------------------- */
 
        /*
-        * Get the video params out of `var'. If a value doesn't fit, round
-        * it up, if it's too big, return -EINVAL.
+        * Set a single color register. The values supplied are already
+        * rounded down to the hardware's capabilities (according to the
+        * entries in the var structure). Return != 0 for invalid regno.
         */
 
-static int ami_decode_var(struct fb_var_screeninfo *var,
-                          struct amifb_par *par)
+static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                          u_int transp, struct fb_info *info)
 {
-       u_short clk_shift, line_shift;
-       u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n;
-       u_int htotal, vtotal;
-
-       /*
-        * Find a matching Pixel Clock
-        */
-
-       for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++)
-               if (var->pixclock <= pixclock[clk_shift])
-                       break;
-       if (clk_shift > TAG_LORES) {
-               DPRINTK("pixclock too high\n");
-               return -EINVAL;
-       }
-       par->clk_shift = clk_shift;
+       const struct amifb_par *par = info->par;
 
-       /*
-        * Check the Geometry Values
-        */
-
-       if ((par->xres = var->xres) < 64)
-               par->xres = 64;
-       if ((par->yres = var->yres) < 64)
-               par->yres = 64;
-       if ((par->vxres = var->xres_virtual) < par->xres)
-               par->vxres = par->xres;
-       if ((par->vyres = var->yres_virtual) < par->yres)
-               par->vyres = par->yres;
-
-       par->bpp = var->bits_per_pixel;
-       if (!var->nonstd) {
-               if (par->bpp < 1)
-                       par->bpp = 1;
-               if (par->bpp > maxdepth[clk_shift]) {
-                       if (round_down_bpp && maxdepth[clk_shift])
-                               par->bpp = maxdepth[clk_shift];
-                       else {
-                               DPRINTK("invalid bpp\n");
-                               return -EINVAL;
-                       }
-               }
-       } else if (var->nonstd == FB_NONSTD_HAM) {
-               if (par->bpp < 6)
-                       par->bpp = 6;
-               if (par->bpp != 6) {
-                       if (par->bpp < 8)
-                               par->bpp = 8;
-                       if (par->bpp != 8 || !IS_AGA) {
-                               DPRINTK("invalid bpp for ham mode\n");
-                               return -EINVAL;
-                       }
-               }
+       if (IS_AGA) {
+               if (regno > 255)
+                       return 1;
+       } else if (par->bplcon0 & BPC0_SHRES) {
+               if (regno > 3)
+                       return 1;
        } else {
-               DPRINTK("unknown nonstd mode\n");
-               return -EINVAL;
+               if (regno > 31)
+                       return 1;
        }
-
-       /*
-        * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
-        * checks failed and smooth scrolling is not possible
-        */
-
-       par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN;
-       switch (par->vmode & FB_VMODE_MASK) {
-               case FB_VMODE_INTERLACED:
-                       line_shift = 0;
-                       break;
-               case FB_VMODE_NONINTERLACED:
-                       line_shift = 1;
-                       break;
-               case FB_VMODE_DOUBLE:
-                       if (!IS_AGA) {
-                               DPRINTK("double mode only possible with aga\n");
-                               return -EINVAL;
-                       }
-                       line_shift = 2;
-                       break;
-               default:
-                       DPRINTK("unknown video mode\n");
-                       return -EINVAL;
-                       break;
+       red >>= 8;
+       green >>= 8;
+       blue >>= 8;
+       if (!regno) {
+               red0 = red;
+               green0 = green;
+               blue0 = blue;
        }
-       par->line_shift = line_shift;
 
        /*
-        * Vertical and Horizontal Timings
+        * Update the corresponding Hardware Color Register, unless it's Color
+        * Register 0 and the screen is blanked.
+        *
+        * VBlank is switched off to protect bplcon3 or ecs_palette[] from
+        * being changed by ami_do_blank() during the VBlank.
         */
 
-       xres_n = par->xres<<clk_shift;
-       yres_n = par->yres<<line_shift;
-       par->htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<<clk_shift);
-       par->vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<<line_shift)+1);
-
-       if (IS_AGA)
-               par->bplcon3 = sprpixmode[clk_shift];
-       else
-               par->bplcon3 = 0;
-       if (var->sync & FB_SYNC_BROADCAST) {
-               par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<<clk_shift);
-               if (IS_AGA)
-                       par->diwstop_h += mod4(var->hsync_len);
-               else
-                       par->diwstop_h = down4(par->diwstop_h);
-
-               par->diwstrt_h = par->diwstop_h - xres_n;
-               par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<<line_shift);
-               par->diwstrt_v = par->diwstop_v - yres_n;
-               if (par->diwstop_h >= par->htotal+8) {
-                       DPRINTK("invalid diwstop_h\n");
-                       return -EINVAL;
-               }
-               if (par->diwstop_v > par->vtotal) {
-                       DPRINTK("invalid diwstop_v\n");
-                       return -EINVAL;
-               }
+       if (regno || !is_blanked) {
+#if defined(CONFIG_FB_AMIGA_AGA)
+               if (IS_AGA) {
+                       u_short bplcon3 = par->bplcon3;
+                       VBlankOff();
+                       custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000);
+                       custom.color[regno & 31] = rgb2hw8_high(red, green,
+                                                               blue);
+                       custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000) |
+                                        BPC3_LOCT;
+                       custom.color[regno & 31] = rgb2hw8_low(red, green,
+                                                              blue);
+                       custom.bplcon3 = bplcon3;
+                       VBlankOn();
+               } else
+#endif
+#if defined(CONFIG_FB_AMIGA_ECS)
+               if (par->bplcon0 & BPC0_SHRES) {
+                       u_short color, mask;
+                       int i;
 
-               if (!IS_OCS) {
-                       /* Initialize sync with some reasonable values for pwrsave */
-                       par->hsstrt = 160;
-                       par->hsstop = 320;
-                       par->vsstrt = 30;
-                       par->vsstop = 34;
-               } else {
-                       par->hsstrt = 0;
-                       par->hsstop = 0;
-                       par->vsstrt = 0;
-                       par->vsstop = 0;
-               }
-               if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) {
-                       /* PAL video mode */
-                       if (par->htotal != PAL_HTOTAL) {
-                               DPRINTK("htotal invalid for pal\n");
-                               return -EINVAL;
-                       }
-                       if (par->diwstrt_h < PAL_DIWSTRT_H) {
-                               DPRINTK("diwstrt_h too low for pal\n");
-                               return -EINVAL;
-                       }
-                       if (par->diwstrt_v < PAL_DIWSTRT_V) {
-                               DPRINTK("diwstrt_v too low for pal\n");
-                               return -EINVAL;
-                       }
-                       htotal = PAL_HTOTAL>>clk_shift;
-                       vtotal = PAL_VTOTAL>>1;
-                       if (!IS_OCS) {
-                               par->beamcon0 = BMC0_PAL;
-                               par->bplcon3 |= BPC3_BRDRBLNK;
-                       } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
-                                  AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
-                               par->beamcon0 = BMC0_PAL;
-                               par->hsstop = 1;
-                       } else if (amiga_vblank != 50) {
-                               DPRINTK("pal not supported by this chipset\n");
-                               return -EINVAL;
-                       }
-               } else {
-                       /* NTSC video mode
-                        * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK
-                        * and NTSC activated, so than better let diwstop_h <= 1812
-                        */
-                       if (par->htotal != NTSC_HTOTAL) {
-                               DPRINTK("htotal invalid for ntsc\n");
-                               return -EINVAL;
-                       }
-                       if (par->diwstrt_h < NTSC_DIWSTRT_H) {
-                               DPRINTK("diwstrt_h too low for ntsc\n");
-                               return -EINVAL;
-                       }
-                       if (par->diwstrt_v < NTSC_DIWSTRT_V) {
-                               DPRINTK("diwstrt_v too low for ntsc\n");
-                               return -EINVAL;
-                       }
-                       htotal = NTSC_HTOTAL>>clk_shift;
-                       vtotal = NTSC_VTOTAL>>1;
-                       if (!IS_OCS) {
-                               par->beamcon0 = 0;
-                               par->bplcon3 |= BPC3_BRDRBLNK;
-                       } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
-                                  AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
-                               par->beamcon0 = 0;
-                               par->hsstop = 1;
-                       } else if (amiga_vblank != 60) {
-                               DPRINTK("ntsc not supported by this chipset\n");
-                               return -EINVAL;
-                       }
-               }
-               if (IS_OCS) {
-                       if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 ||
-                           par->diwstrt_v >=  512 || par->diwstop_v <  256) {
-                               DPRINTK("invalid position for display on ocs\n");
-                               return -EINVAL;
-                       }
-               }
-       } else if (!IS_OCS) {
-               /* Programmable video mode */
-               par->hsstrt = var->right_margin<<clk_shift;
-               par->hsstop = (var->right_margin+var->hsync_len)<<clk_shift;
-               par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift);
-               if (!IS_AGA)
-                       par->diwstop_h = down4(par->diwstop_h) - 16;
-               par->diwstrt_h = par->diwstop_h - xres_n;
-               par->hbstop = par->diwstrt_h + 4;
-               par->hbstrt = par->diwstop_h + 4;
-               if (par->hbstrt >= par->htotal + 8)
-                       par->hbstrt -= par->htotal;
-               par->hcenter = par->hsstrt + (par->htotal >> 1);
-               par->vsstrt = var->lower_margin<<line_shift;
-               par->vsstop = (var->lower_margin+var->vsync_len)<<line_shift;
-               par->diwstop_v = par->vtotal;
-               if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
-                       par->diwstop_v -= 2;
-               par->diwstrt_v = par->diwstop_v - yres_n;
-               par->vbstop = par->diwstrt_v - 2;
-               par->vbstrt = par->diwstop_v - 2;
-               if (par->vtotal > 2048) {
-                       DPRINTK("vtotal too high\n");
-                       return -EINVAL;
-               }
-               if (par->htotal > 2048) {
-                       DPRINTK("htotal too high\n");
-                       return -EINVAL;
-               }
-               par->bplcon3 |= BPC3_EXTBLKEN;
-               par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS |
-                               BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN |
-                               BMC0_PAL | BMC0_VARCSYEN;
-               if (var->sync & FB_SYNC_HOR_HIGH_ACT)
-                       par->beamcon0 |= BMC0_HSYTRUE;
-               if (var->sync & FB_SYNC_VERT_HIGH_ACT)
-                       par->beamcon0 |= BMC0_VSYTRUE;
-               if (var->sync & FB_SYNC_COMP_HIGH_ACT)
-                       par->beamcon0 |= BMC0_CSYTRUE;
-               htotal = par->htotal>>clk_shift;
-               vtotal = par->vtotal>>1;
-       } else {
-               DPRINTK("only broadcast modes possible for ocs\n");
-               return -EINVAL;
+                       mask = 0x3333;
+                       color = rgb2hw2(red, green, blue);
+                       VBlankOff();
+                       for (i = regno + 12; i >= (int)regno; i -= 4)
+                               custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
+                       mask <<= 2; color >>= 2;
+                       regno = down16(regno) + mul4(mod4(regno));
+                       for (i = regno + 3; i >= (int)regno; i--)
+                               custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
+                       VBlankOn();
+               } else
+#endif
+                       custom.color[regno] = rgb2hw4(red, green, blue);
        }
+       return 0;
+}
+
 
        /*
-        * Checking the DMA timing
+        * Blank the display.
         */
 
-       fconst = 16<<maxfmode<<clk_shift;
+static int amifb_blank(int blank, struct fb_info *info)
+{
+       do_blank = blank ? blank : -1;
+
+       return 0;
+}
+
 
        /*
-        * smallest window start value without turn off other dma cycles
-        * than sprite1-7, unless you change min_fstrt
+        * Pan or Wrap the Display
+        *
+        * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
         */
 
-
-       fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64);
-       fstrt = downx(fconst, par->diwstrt_h-4) - fsize;
-       if (fstrt < min_fstrt) {
-               DPRINTK("fetch start too low\n");
-               return -EINVAL;
+static int amifb_pan_display(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
+{
+       if (var->vmode & FB_VMODE_YWRAP) {
+               if (var->yoffset < 0 ||
+                       var->yoffset >= info->var.yres_virtual || var->xoffset)
+                               return -EINVAL;
+       } else {
+               /*
+                * TODO: There will be problems when xpan!=1, so some columns
+                * on the right side will never be seen
+                */
+               if (var->xoffset + info->var.xres >
+                   upx(16 << maxfmode, info->var.xres_virtual) ||
+                   var->yoffset + info->var.yres > info->var.yres_virtual)
+                       return -EINVAL;
        }
+       ami_pan_var(var, info);
+       info->var.xoffset = var->xoffset;
+       info->var.yoffset = var->yoffset;
+       if (var->vmode & FB_VMODE_YWRAP)
+               info->var.vmode |= FB_VMODE_YWRAP;
+       else
+               info->var.vmode &= ~FB_VMODE_YWRAP;
+       return 0;
+}
+
+
+#if BITS_PER_LONG == 32
+#define BYTES_PER_LONG 4
+#define SHIFT_PER_LONG 5
+#elif BITS_PER_LONG == 64
+#define BYTES_PER_LONG 8
+#define SHIFT_PER_LONG 6
+#else
+#define Please update me
+#endif
+
 
        /*
-        * smallest window start value where smooth scrolling is possible
+        *  Compose two values, using a bitmask as decision value
+        *  This is equivalent to (a & mask) | (b & ~mask)
         */
 
-       fstrt = downx(fconst, par->diwstrt_h-fconst+(1<<clk_shift)-4) - fsize;
-       if (fstrt < min_fstrt)
-               par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
+static inline unsigned long comp(unsigned long a, unsigned long b,
+                                unsigned long mask)
+{
+       return ((a ^ b) & mask) ^ b;
+}
 
-       maxfetchstop = down16(par->htotal - 80);
 
-       fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst;
-       fsize = upx(fconst, xres_n + modx(fconst, downx(1<<clk_shift, par->diwstrt_h-4)));
-       if (fstrt + fsize > maxfetchstop)
-               par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
+static inline unsigned long xor(unsigned long a, unsigned long b,
+                               unsigned long mask)
+{
+       return (a & mask) ^ b;
+}
 
-       fsize = upx(fconst, xres_n);
-       if (fstrt + fsize > maxfetchstop) {
-               DPRINTK("fetch stop too high\n");
-               return -EINVAL;
-       }
 
-       if (maxfmode + clk_shift <= 1) {
-               fsize = up64(xres_n + fconst - 1);
-               if (min_fstrt + fsize - 64 > maxfetchstop)
-                       par->vmode &= ~FB_VMODE_SMOOTH_XPAN;
+       /*
+        *  Unaligned forward bit copy using 32-bit or 64-bit memory accesses
+        */
 
-               fsize = up64(xres_n);
-               if (min_fstrt + fsize - 64 > maxfetchstop) {
-                       DPRINTK("fetch size too high\n");
-                       return -EINVAL;
+static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
+                  int src_idx, u32 n)
+{
+       unsigned long first, last;
+       int shift = dst_idx - src_idx, left, right;
+       unsigned long d0, d1;
+       int m;
+
+       if (!n)
+               return;
+
+       shift = dst_idx - src_idx;
+       first = ~0UL >> dst_idx;
+       last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG));
+
+       if (!shift) {
+               // Same alignment for source and dest
+
+               if (dst_idx + n <= BITS_PER_LONG) {
+                       // Single word
+                       if (last)
+                               first &= last;
+                       *dst = comp(*src, *dst, first);
+               } else {
+                       // Multiple destination words
+                       // Leading bits
+                       if (first) {
+                               *dst = comp(*src, *dst, first);
+                               dst++;
+                               src++;
+                               n -= BITS_PER_LONG - dst_idx;
+                       }
+
+                       // Main chunk
+                       n /= BITS_PER_LONG;
+                       while (n >= 8) {
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               *dst++ = *src++;
+                               n -= 8;
+                       }
+                       while (n--)
+                               *dst++ = *src++;
+
+                       // Trailing bits
+                       if (last)
+                               *dst = comp(*src, *dst, last);
                }
+       } else {
+               // Different alignment for source and dest
 
-               fsize -= 64;
-       } else
-               fsize -= fconst;
+               right = shift & (BITS_PER_LONG - 1);
+               left = -shift & (BITS_PER_LONG - 1);
 
-       /*
-        * Check if there is enough time to update the bitplane pointers for ywrap
-        */
+               if (dst_idx + n <= BITS_PER_LONG) {
+                       // Single destination word
+                       if (last)
+                               first &= last;
+                       if (shift > 0) {
+                               // Single source word
+                               *dst = comp(*src >> right, *dst, first);
+                       } else if (src_idx + n <= BITS_PER_LONG) {
+                               // Single source word
+                               *dst = comp(*src << left, *dst, first);
+                       } else {
+                               // 2 source words
+                               d0 = *src++;
+                               d1 = *src;
+                               *dst = comp(d0 << left | d1 >> right, *dst,
+                                           first);
+                       }
+               } else {
+                       // Multiple destination words
+                       d0 = *src++;
+                       // Leading bits
+                       if (shift > 0) {
+                               // Single source word
+                               *dst = comp(d0 >> right, *dst, first);
+                               dst++;
+                               n -= BITS_PER_LONG - dst_idx;
+                       } else {
+                               // 2 source words
+                               d1 = *src++;
+                               *dst = comp(d0 << left | d1 >> right, *dst,
+                                           first);
+                               d0 = d1;
+                               dst++;
+                               n -= BITS_PER_LONG - dst_idx;
+                       }
+
+                       // Main chunk
+                       m = n % BITS_PER_LONG;
+                       n /= BITS_PER_LONG;
+                       while (n >= 4) {
+                               d1 = *src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                               d1 = *src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                               d1 = *src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                               d1 = *src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                               n -= 4;
+                       }
+                       while (n--) {
+                               d1 = *src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                       }
+
+                       // Trailing bits
+                       if (last) {
+                               if (m <= right) {
+                                       // Single source word
+                                       *dst = comp(d0 << left, *dst, last);
+                               } else {
+                                       // 2 source words
+                                       d1 = *src;
+                                       *dst = comp(d0 << left | d1 >> right,
+                                                   *dst, last);
+                               }
+                       }
+               }
+       }
+}
 
-       if (par->htotal-fsize-64 < par->bpp*64)
-               par->vmode &= ~FB_VMODE_YWRAP;
 
        /*
-        * Bitplane calculations and check the Memory Requirements
+        *  Unaligned reverse bit copy using 32-bit or 64-bit memory accesses
         */
 
-       if (amifb_ilbm) {
-               par->next_plane = div8(upx(16<<maxfmode, par->vxres));
-               par->next_line = par->bpp*par->next_plane;
-               if (par->next_line * par->vyres > fb_info.fix.smem_len) {
-                       DPRINTK("too few video mem\n");
-                       return -EINVAL;
+static void bitcpy_rev(unsigned long *dst, int dst_idx,
+                      const unsigned long *src, int src_idx, u32 n)
+{
+       unsigned long first, last;
+       int shift = dst_idx - src_idx, left, right;
+       unsigned long d0, d1;
+       int m;
+
+       if (!n)
+               return;
+
+       dst += (n - 1) / BITS_PER_LONG;
+       src += (n - 1) / BITS_PER_LONG;
+       if ((n - 1) % BITS_PER_LONG) {
+               dst_idx += (n - 1) % BITS_PER_LONG;
+               dst += dst_idx >> SHIFT_PER_LONG;
+               dst_idx &= BITS_PER_LONG - 1;
+               src_idx += (n - 1) % BITS_PER_LONG;
+               src += src_idx >> SHIFT_PER_LONG;
+               src_idx &= BITS_PER_LONG - 1;
+       }
+
+       shift = dst_idx - src_idx;
+       first = ~0UL << (BITS_PER_LONG - 1 - dst_idx);
+       last = ~(~0UL << (BITS_PER_LONG - 1 - ((dst_idx - n) % BITS_PER_LONG)));
+
+       if (!shift) {
+               // Same alignment for source and dest
+
+               if ((unsigned long)dst_idx + 1 >= n) {
+                       // Single word
+                       if (last)
+                               first &= last;
+                       *dst = comp(*src, *dst, first);
+               } else {
+                       // Multiple destination words
+                       // Leading bits
+                       if (first) {
+                               *dst = comp(*src, *dst, first);
+                               dst--;
+                               src--;
+                               n -= dst_idx + 1;
+                       }
+
+                       // Main chunk
+                       n /= BITS_PER_LONG;
+                       while (n >= 8) {
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               *dst-- = *src--;
+                               n -= 8;
+                       }
+                       while (n--)
+                               *dst-- = *src--;
+
+                       // Trailing bits
+                       if (last)
+                               *dst = comp(*src, *dst, last);
                }
        } else {
-               par->next_line = div8(upx(16<<maxfmode, par->vxres));
-               par->next_plane = par->vyres*par->next_line;
-               if (par->next_plane * par->bpp > fb_info.fix.smem_len) {
-                       DPRINTK("too few video mem\n");
-                       return -EINVAL;
-               }
-       }
-
-       /*
-        * Hardware Register Values
-        */
-
-       par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift];
-       if (!IS_OCS)
-               par->bplcon0 |= BPC0_ECSENA;
-       if (par->bpp == 8)
-               par->bplcon0 |= BPC0_BPU3;
-       else
-               par->bplcon0 |= par->bpp<<12;
-       if (var->nonstd == FB_NONSTD_HAM)
-               par->bplcon0 |= BPC0_HAM;
-       if (var->sync & FB_SYNC_EXT)
-               par->bplcon0 |= BPC0_ERSY;
-
-       if (IS_AGA)
-               par->fmode = bplfetchmode[maxfmode];
+               // Different alignment for source and dest
 
-       switch (par->vmode & FB_VMODE_MASK) {
-               case FB_VMODE_INTERLACED:
-                       par->bplcon0 |= BPC0_LACE;
-                       break;
-               case FB_VMODE_DOUBLE:
-                       if (IS_AGA)
-                               par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2;
-                       break;
-       }
+               right = shift & (BITS_PER_LONG - 1);
+               left = -shift & (BITS_PER_LONG - 1);
 
-       if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {
-               par->xoffset = var->xoffset;
-               par->yoffset = var->yoffset;
-               if (par->vmode & FB_VMODE_YWRAP) {
-                       if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres)
-                               par->xoffset = par->yoffset = 0;
+               if ((unsigned long)dst_idx + 1 >= n) {
+                       // Single destination word
+                       if (last)
+                               first &= last;
+                       if (shift < 0) {
+                               // Single source word
+                               *dst = comp(*src << left, *dst, first);
+                       } else if (1 + (unsigned long)src_idx >= n) {
+                               // Single source word
+                               *dst = comp(*src >> right, *dst, first);
+                       } else {
+                               // 2 source words
+                               d0 = *src--;
+                               d1 = *src;
+                               *dst = comp(d0 >> right | d1 << left, *dst,
+                                           first);
+                       }
                } else {
-                       if (par->xoffset < 0 || par->xoffset > upx(16<<maxfmode, par->vxres-par->xres) ||
-                           par->yoffset < 0 || par->yoffset > par->vyres-par->yres)
-                               par->xoffset = par->yoffset = 0;
-               }
-       } else
-               par->xoffset = par->yoffset = 0;
+                       // Multiple destination words
+                       d0 = *src--;
+                       // Leading bits
+                       if (shift < 0) {
+                               // Single source word
+                               *dst = comp(d0 << left, *dst, first);
+                               dst--;
+                               n -= dst_idx + 1;
+                       } else {
+                               // 2 source words
+                               d1 = *src--;
+                               *dst = comp(d0 >> right | d1 << left, *dst,
+                                           first);
+                               d0 = d1;
+                               dst--;
+                               n -= dst_idx + 1;
+                       }
 
-       par->crsr.crsr_x = par->crsr.crsr_y = 0;
-       par->crsr.spot_x = par->crsr.spot_y = 0;
-       par->crsr.height = par->crsr.width = 0;
+                       // Main chunk
+                       m = n % BITS_PER_LONG;
+                       n /= BITS_PER_LONG;
+                       while (n >= 4) {
+                               d1 = *src--;
+                               *dst-- = d0 >> right | d1 << left;
+                               d0 = d1;
+                               d1 = *src--;
+                               *dst-- = d0 >> right | d1 << left;
+                               d0 = d1;
+                               d1 = *src--;
+                               *dst-- = d0 >> right | d1 << left;
+                               d0 = d1;
+                               d1 = *src--;
+                               *dst-- = d0 >> right | d1 << left;
+                               d0 = d1;
+                               n -= 4;
+                       }
+                       while (n--) {
+                               d1 = *src--;
+                               *dst-- = d0 >> right | d1 << left;
+                               d0 = d1;
+                       }
 
-       return 0;
+                       // Trailing bits
+                       if (last) {
+                               if (m <= left) {
+                                       // Single source word
+                                       *dst = comp(d0 >> right, *dst, last);
+                               } else {
+                                       // 2 source words
+                                       d1 = *src;
+                                       *dst = comp(d0 >> right | d1 << left,
+                                                   *dst, last);
+                               }
+                       }
+               }
+       }
 }
 
+
        /*
-        * Fill the `var' structure based on the values in `par' and maybe
-        * other values read out of the hardware.
+        *  Unaligned forward inverting bit copy using 32-bit or 64-bit memory
+        *  accesses
         */
 
-static int ami_encode_var(struct fb_var_screeninfo *var,
-                          struct amifb_par *par)
+static void bitcpy_not(unsigned long *dst, int dst_idx,
+                      const unsigned long *src, int src_idx, u32 n)
 {
-       u_short clk_shift, line_shift;
-
-       memset(var, 0, sizeof(struct fb_var_screeninfo));
-
-       clk_shift = par->clk_shift;
-       line_shift = par->line_shift;
+       unsigned long first, last;
+       int shift = dst_idx - src_idx, left, right;
+       unsigned long d0, d1;
+       int m;
 
-       var->xres = par->xres;
-       var->yres = par->yres;
-       var->xres_virtual = par->vxres;
-       var->yres_virtual = par->vyres;
-       var->xoffset = par->xoffset;
-       var->yoffset = par->yoffset;
+       if (!n)
+               return;
 
-       var->bits_per_pixel = par->bpp;
-       var->grayscale = 0;
+       shift = dst_idx - src_idx;
+       first = ~0UL >> dst_idx;
+       last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG));
 
-       var->red.offset = 0;
-       var->red.msb_right = 0;
-       var->red.length = par->bpp;
-       if (par->bplcon0 & BPC0_HAM)
-           var->red.length -= 2;
-       var->blue = var->green = var->red;
-       var->transp.offset = 0;
-       var->transp.length = 0;
-       var->transp.msb_right = 0;
+       if (!shift) {
+               // Same alignment for source and dest
 
-       if (par->bplcon0 & BPC0_HAM)
-               var->nonstd = FB_NONSTD_HAM;
-       else
-               var->nonstd = 0;
-       var->activate = 0;
+               if (dst_idx + n <= BITS_PER_LONG) {
+                       // Single word
+                       if (last)
+                               first &= last;
+                       *dst = comp(~*src, *dst, first);
+               } else {
+                       // Multiple destination words
+                       // Leading bits
+                       if (first) {
+                               *dst = comp(~*src, *dst, first);
+                               dst++;
+                               src++;
+                               n -= BITS_PER_LONG - dst_idx;
+                       }
 
-       var->height = -1;
-       var->width = -1;
+                       // Main chunk
+                       n /= BITS_PER_LONG;
+                       while (n >= 8) {
+                               *dst++ = ~*src++;
+                               *dst++ = ~*src++;
+                               *dst++ = ~*src++;
+                               *dst++ = ~*src++;
+                               *dst++ = ~*src++;
+                               *dst++ = ~*src++;
+                               *dst++ = ~*src++;
+                               *dst++ = ~*src++;
+                               n -= 8;
+                       }
+                       while (n--)
+                               *dst++ = ~*src++;
 
-       var->pixclock = pixclock[clk_shift];
+                       // Trailing bits
+                       if (last)
+                               *dst = comp(~*src, *dst, last);
+               }
+       } else {
+               // Different alignment for source and dest
 
-       if (IS_AGA && par->fmode & FMODE_BSCAN2)
-               var->vmode = FB_VMODE_DOUBLE;
-       else if (par->bplcon0 & BPC0_LACE)
-               var->vmode = FB_VMODE_INTERLACED;
-       else
-               var->vmode = FB_VMODE_NONINTERLACED;
+               right = shift & (BITS_PER_LONG - 1);
+               left = -shift & (BITS_PER_LONG - 1);
 
-       if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) {
-               var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift;
-               var->right_margin = par->hsstrt>>clk_shift;
-               var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
-               var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift;
-               var->lower_margin = par->vsstrt>>line_shift;
-               var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len;
-               var->sync = 0;
-               if (par->beamcon0 & BMC0_HSYTRUE)
-                       var->sync |= FB_SYNC_HOR_HIGH_ACT;
-               if (par->beamcon0 & BMC0_VSYTRUE)
-                       var->sync |= FB_SYNC_VERT_HIGH_ACT;
-               if (par->beamcon0 & BMC0_CSYTRUE)
-                       var->sync |= FB_SYNC_COMP_HIGH_ACT;
-       } else {
-               var->sync = FB_SYNC_BROADCAST;
-               var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h);
-               var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len;
-               var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len;
-               var->vsync_len = 4>>line_shift;
-               var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len;
-               var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres -
-                                   var->lower_margin - var->vsync_len;
-       }
+               if (dst_idx + n <= BITS_PER_LONG) {
+                       // Single destination word
+                       if (last)
+                               first &= last;
+                       if (shift > 0) {
+                               // Single source word
+                               *dst = comp(~*src >> right, *dst, first);
+                       } else if (src_idx + n <= BITS_PER_LONG) {
+                               // Single source word
+                               *dst = comp(~*src << left, *dst, first);
+                       } else {
+                               // 2 source words
+                               d0 = ~*src++;
+                               d1 = ~*src;
+                               *dst = comp(d0 << left | d1 >> right, *dst,
+                                           first);
+                       }
+               } else {
+                       // Multiple destination words
+                       d0 = ~*src++;
+                       // Leading bits
+                       if (shift > 0) {
+                               // Single source word
+                               *dst = comp(d0 >> right, *dst, first);
+                               dst++;
+                               n -= BITS_PER_LONG - dst_idx;
+                       } else {
+                               // 2 source words
+                               d1 = ~*src++;
+                               *dst = comp(d0 << left | d1 >> right, *dst,
+                                           first);
+                               d0 = d1;
+                               dst++;
+                               n -= BITS_PER_LONG - dst_idx;
+                       }
 
-       if (par->bplcon0 & BPC0_ERSY)
-               var->sync |= FB_SYNC_EXT;
-       if (par->vmode & FB_VMODE_YWRAP)
-               var->vmode |= FB_VMODE_YWRAP;
+                       // Main chunk
+                       m = n % BITS_PER_LONG;
+                       n /= BITS_PER_LONG;
+                       while (n >= 4) {
+                               d1 = ~*src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                               d1 = ~*src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                               d1 = ~*src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                               d1 = ~*src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                               n -= 4;
+                       }
+                       while (n--) {
+                               d1 = ~*src++;
+                               *dst++ = d0 << left | d1 >> right;
+                               d0 = d1;
+                       }
 
-       return 0;
+                       // Trailing bits
+                       if (last) {
+                               if (m <= right) {
+                                       // Single source word
+                                       *dst = comp(d0 << left, *dst, last);
+                               } else {
+                                       // 2 source words
+                                       d1 = ~*src;
+                                       *dst = comp(d0 << left | d1 >> right,
+                                                   *dst, last);
+                               }
+                       }
+               }
+       }
 }
 
 
        /*
-        * Pan or Wrap the Display
-        *
-        * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-        * in `var'.
+        *  Unaligned 32-bit pattern fill using 32/64-bit memory accesses
         */
 
-static void ami_pan_var(struct fb_var_screeninfo *var)
+static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
 {
-       struct amifb_par *par = &currentpar;
+       unsigned long val = pat;
+       unsigned long first, last;
 
-       par->xoffset = var->xoffset;
-       par->yoffset = var->yoffset;
-       if (var->vmode & FB_VMODE_YWRAP)
-               par->vmode |= FB_VMODE_YWRAP;
-       else
-               par->vmode &= ~FB_VMODE_YWRAP;
+       if (!n)
+               return;
 
-       do_vmode_pan = 0;
-       ami_update_par();
-       do_vmode_pan = 1;
+#if BITS_PER_LONG == 64
+       val |= val << 32;
+#endif
+
+       first = ~0UL >> dst_idx;
+       last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG));
+
+       if (dst_idx + n <= BITS_PER_LONG) {
+               // Single word
+               if (last)
+                       first &= last;
+               *dst = comp(val, *dst, first);
+       } else {
+               // Multiple destination words
+               // Leading bits
+               if (first) {
+                       *dst = comp(val, *dst, first);
+                       dst++;
+                       n -= BITS_PER_LONG - dst_idx;
+               }
+
+               // Main chunk
+               n /= BITS_PER_LONG;
+               while (n >= 8) {
+                       *dst++ = val;
+                       *dst++ = val;
+                       *dst++ = val;
+                       *dst++ = val;
+                       *dst++ = val;
+                       *dst++ = val;
+                       *dst++ = val;
+                       *dst++ = val;
+                       n -= 8;
+               }
+               while (n--)
+                       *dst++ = val;
+
+               // Trailing bits
+               if (last)
+                       *dst = comp(val, *dst, last);
+       }
 }
 
+
        /*
-        * Update hardware
+        *  Unaligned 32-bit pattern xor using 32/64-bit memory accesses
         */
 
-static int ami_update_par(void)
+static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
 {
-       struct amifb_par *par = &currentpar;
-       short clk_shift, vshift, fstrt, fsize, fstop, fconst,  shift, move, mod;
+       unsigned long val = pat;
+       unsigned long first, last;
 
-       clk_shift = par->clk_shift;
+       if (!n)
+               return;
 
-       if (!(par->vmode & FB_VMODE_SMOOTH_XPAN))
-               par->xoffset = upx(16<<maxfmode, par->xoffset);
+#if BITS_PER_LONG == 64
+       val |= val << 32;
+#endif
 
-       fconst = 16<<maxfmode<<clk_shift;
-       vshift = modx(16<<maxfmode, par->xoffset);
-       fstrt = par->diwstrt_h - (vshift<<clk_shift) - 4;
-       fsize = (par->xres+vshift)<<clk_shift;
-       shift = modx(fconst, fstrt);
-       move = downx(2<<maxfmode, div8(par->xoffset));
-       if (maxfmode + clk_shift > 1) {
-               fstrt = downx(fconst, fstrt) - 64;
-               fsize = upx(fconst, fsize);
-               fstop = fstrt + fsize - fconst;
+       first = ~0UL >> dst_idx;
+       last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG));
+
+       if (dst_idx + n <= BITS_PER_LONG) {
+               // Single word
+               if (last)
+                       first &= last;
+               *dst = xor(val, *dst, first);
        } else {
-               mod = fstrt = downx(fconst, fstrt) - fconst;
-               fstop = fstrt + upx(fconst, fsize) - 64;
-               fsize = up64(fsize);
-               fstrt = fstop - fsize + 64;
-               if (fstrt < min_fstrt) {
-                       fstop += min_fstrt - fstrt;
-                       fstrt = min_fstrt;
+               // Multiple destination words
+               // Leading bits
+               if (first) {
+                       *dst = xor(val, *dst, first);
+                       dst++;
+                       n -= BITS_PER_LONG - dst_idx;
                }
-               move = move - div8((mod-fstrt)>>clk_shift);
-       }
-       mod = par->next_line - div8(fsize>>clk_shift);
-       par->ddfstrt = fstrt;
-       par->ddfstop = fstop;
-       par->bplcon1 = hscroll2hw(shift);
-       par->bpl2mod = mod;
-       if (par->bplcon0 & BPC0_LACE)
-               par->bpl2mod += par->next_line;
-       if (IS_AGA && (par->fmode & FMODE_BSCAN2))
-               par->bpl1mod = -div8(fsize>>clk_shift);
-       else
-               par->bpl1mod = par->bpl2mod;
 
-       if (par->yoffset) {
-               par->bplpt0 = fb_info.fix.smem_start + par->next_line*par->yoffset + move;
-               if (par->vmode & FB_VMODE_YWRAP) {
-                       if (par->yoffset > par->vyres-par->yres) {
-                               par->bplpt0wrap = fb_info.fix.smem_start + move;
-                               if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset))
-                                       par->bplpt0wrap += par->next_line;
-                       }
+               // Main chunk
+               n /= BITS_PER_LONG;
+               while (n >= 4) {
+                       *dst++ ^= val;
+                       *dst++ ^= val;
+                       *dst++ ^= val;
+                       *dst++ ^= val;
+                       n -= 4;
                }
-       } else
-               par->bplpt0 = fb_info.fix.smem_start + move;
+               while (n--)
+                       *dst++ ^= val;
 
-       if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
-               par->bplpt0 += par->next_line;
+               // Trailing bits
+               if (last)
+                       *dst = xor(val, *dst, last);
+       }
+}
 
-       return 0;
+static inline void fill_one_line(int bpp, unsigned long next_plane,
+                                unsigned long *dst, int dst_idx, u32 n,
+                                u32 color)
+{
+       while (1) {
+               dst += dst_idx >> SHIFT_PER_LONG;
+               dst_idx &= (BITS_PER_LONG - 1);
+               bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n);
+               if (!--bpp)
+                       break;
+               color >>= 1;
+               dst_idx += next_plane * 8;
+       }
 }
 
+static inline void xor_one_line(int bpp, unsigned long next_plane,
+                               unsigned long *dst, int dst_idx, u32 n,
+                               u32 color)
+{
+       while (color) {
+               dst += dst_idx >> SHIFT_PER_LONG;
+               dst_idx &= (BITS_PER_LONG - 1);
+               bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n);
+               if (!--bpp)
+                       break;
+               color >>= 1;
+               dst_idx += next_plane * 8;
+       }
+}
 
-       /*
-        * Set a single color register. The values supplied are already
-        * rounded down to the hardware's capabilities (according to the
-        * entries in the var structure). Return != 0 for invalid regno.
-        */
 
-static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                           u_int transp, struct fb_info *info)
+static void amifb_fillrect(struct fb_info *info,
+                          const struct fb_fillrect *rect)
 {
-       if (IS_AGA) {
-               if (regno > 255)
-                       return 1;
-       } else if (currentpar.bplcon0 & BPC0_SHRES) {
-               if (regno > 3)
-                       return 1;
-       } else {
-               if (regno > 31)
-                       return 1;
-       }
-       red >>= 8;
-       green >>= 8;
-       blue >>= 8;
-       if (!regno) {
-               red0 = red;
-               green0 = green;
-               blue0 = blue;
-       }
+       struct amifb_par *par = info->par;
+       int dst_idx, x2, y2;
+       unsigned long *dst;
+       u32 width, height;
+
+       if (!rect->width || !rect->height)
+               return;
 
        /*
-        * Update the corresponding Hardware Color Register, unless it's Color
-        * Register 0 and the screen is blanked.
-        *
-        * VBlank is switched off to protect bplcon3 or ecs_palette[] from
-        * being changed by ami_do_blank() during the VBlank.
-        */
+        * We could use hardware clipping but on many cards you get around
+        * hardware clipping by writing to framebuffer directly.
+        * */
+       x2 = rect->dx + rect->width;
+       y2 = rect->dy + rect->height;
+       x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+       y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+       width = x2 - rect->dx;
+       height = y2 - rect->dy;
 
-       if (regno || !is_blanked) {
-#if defined(CONFIG_FB_AMIGA_AGA)
-               if (IS_AGA) {
-                       u_short bplcon3 = currentpar.bplcon3;
-                       VBlankOff();
-                       custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000);
-                       custom.color[regno&31] = rgb2hw8_high(red, green, blue);
-                       custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT;
-                       custom.color[regno&31] = rgb2hw8_low(red, green, blue);
-                       custom.bplcon3 = bplcon3;
-                       VBlankOn();
-               } else
-#endif
-#if defined(CONFIG_FB_AMIGA_ECS)
-               if (currentpar.bplcon0 & BPC0_SHRES) {
-                       u_short color, mask;
-                       int i;
+       dst = (unsigned long *)
+               ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));
+       dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;
+       dst_idx += rect->dy * par->next_line * 8 + rect->dx;
+       while (height--) {
+               switch (rect->rop) {
+               case ROP_COPY:
+                       fill_one_line(info->var.bits_per_pixel,
+                                     par->next_plane, dst, dst_idx, width,
+                                     rect->color);
+                       break;
 
-                       mask = 0x3333;
-                       color = rgb2hw2(red, green, blue);
-                       VBlankOff();
-                       for (i = regno+12; i >= (int)regno; i -= 4)
-                               custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
-                       mask <<=2; color >>= 2;
-                       regno = down16(regno)+mul4(mod4(regno));
-                       for (i = regno+3; i >= (int)regno; i--)
-                               custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
-                       VBlankOn();
-               } else
-#endif
-                       custom.color[regno] = rgb2hw4(red, green, blue);
+               case ROP_XOR:
+                       xor_one_line(info->var.bits_per_pixel, par->next_plane,
+                                    dst, dst_idx, width, rect->color);
+                       break;
+               }
+               dst_idx += par->next_line * 8;
        }
-       return 0;
 }
 
-static void ami_update_display(void)
+static inline void copy_one_line(int bpp, unsigned long next_plane,
+                                unsigned long *dst, int dst_idx,
+                                unsigned long *src, int src_idx, u32 n)
 {
-       struct amifb_par *par = &currentpar;
-
-       custom.bplcon1 = par->bplcon1;
-       custom.bpl1mod = par->bpl1mod;
-       custom.bpl2mod = par->bpl2mod;
-       custom.ddfstrt = ddfstrt2hw(par->ddfstrt);
-       custom.ddfstop = ddfstop2hw(par->ddfstop);
+       while (1) {
+               dst += dst_idx >> SHIFT_PER_LONG;
+               dst_idx &= (BITS_PER_LONG - 1);
+               src += src_idx >> SHIFT_PER_LONG;
+               src_idx &= (BITS_PER_LONG - 1);
+               bitcpy(dst, dst_idx, src, src_idx, n);
+               if (!--bpp)
+                       break;
+               dst_idx += next_plane * 8;
+               src_idx += next_plane * 8;
+       }
 }
 
-       /*
-        * Change the video mode (called by VBlank interrupt)
-        */
-
-static void ami_init_display(void)
+static inline void copy_one_line_rev(int bpp, unsigned long next_plane,
+                                    unsigned long *dst, int dst_idx,
+                                    unsigned long *src, int src_idx, u32 n)
 {
-       struct amifb_par *par = &currentpar;
-       int i;
-
-       custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
-       custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
-       if (!IS_OCS) {
-               custom.bplcon3 = par->bplcon3;
-               if (IS_AGA)
-                       custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4;
-               if (par->beamcon0 & BMC0_VARBEAMEN) {
-                       custom.htotal = htotal2hw(par->htotal);
-                       custom.hbstrt = hbstrt2hw(par->hbstrt);
-                       custom.hbstop = hbstop2hw(par->hbstop);
-                       custom.hsstrt = hsstrt2hw(par->hsstrt);
-                       custom.hsstop = hsstop2hw(par->hsstop);
-                       custom.hcenter = hcenter2hw(par->hcenter);
-                       custom.vtotal = vtotal2hw(par->vtotal);
-                       custom.vbstrt = vbstrt2hw(par->vbstrt);
-                       custom.vbstop = vbstop2hw(par->vbstop);
-                       custom.vsstrt = vsstrt2hw(par->vsstrt);
-                       custom.vsstop = vsstop2hw(par->vsstop);
-               }
+       while (1) {
+               dst += dst_idx >> SHIFT_PER_LONG;
+               dst_idx &= (BITS_PER_LONG - 1);
+               src += src_idx >> SHIFT_PER_LONG;
+               src_idx &= (BITS_PER_LONG - 1);
+               bitcpy_rev(dst, dst_idx, src, src_idx, n);
+               if (!--bpp)
+                       break;
+               dst_idx += next_plane * 8;
+               src_idx += next_plane * 8;
        }
-       if (!IS_OCS || par->hsstop)
-               custom.beamcon0 = par->beamcon0;
-       if (IS_AGA)
-               custom.fmode = par->fmode;
+}
 
-       /*
-        * The minimum period for audio depends on htotal
-        */
 
-       amiga_audio_min_period = div16(par->htotal);
+static void amifb_copyarea(struct fb_info *info,
+                          const struct fb_copyarea *area)
+{
+       struct amifb_par *par = info->par;
+       int x2, y2;
+       u32 dx, dy, sx, sy, width, height;
+       unsigned long *dst, *src;
+       int dst_idx, src_idx;
+       int rev_copy = 0;
 
-       is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
-#if 1
-       if (is_lace) {
-               i = custom.vposr >> 15;
-       } else {
-               custom.vposw = custom.vposr | 0x8000;
-               i = 1;
-       }
-#else
-       i = 1;
-       custom.vposw = custom.vposr | 0x8000;
-#endif
-       custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]);
-}
+       /* clip the destination */
+       x2 = area->dx + area->width;
+       y2 = area->dy + area->height;
+       dx = area->dx > 0 ? area->dx : 0;
+       dy = area->dy > 0 ? area->dy : 0;
+       x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+       y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+       width = x2 - dx;
+       height = y2 - dy;
 
-       /*
-        * (Un)Blank the screen (called by VBlank interrupt)
-        */
+       if (area->sx + dx < area->dx || area->sy + dy < area->dy)
+               return;
 
-static void ami_do_blank(void)
-{
-       struct amifb_par *par = &currentpar;
-#if defined(CONFIG_FB_AMIGA_AGA)
-       u_short bplcon3 = par->bplcon3;
-#endif
-       u_char red, green, blue;
+       /* update sx,sy */
+       sx = area->sx + (dx - area->dx);
+       sy = area->sy + (dy - area->dy);
 
-       if (do_blank > 0) {
-               custom.dmacon = DMAF_RASTER | DMAF_SPRITE;
-               red = green = blue = 0;
-               if (!IS_OCS && do_blank > 1) {
-                       switch (do_blank) {
-                               case FB_BLANK_VSYNC_SUSPEND:
-                                       custom.hsstrt = hsstrt2hw(par->hsstrt);
-                                       custom.hsstop = hsstop2hw(par->hsstop);
-                                       custom.vsstrt = vsstrt2hw(par->vtotal+4);
-                                       custom.vsstop = vsstop2hw(par->vtotal+4);
-                                       break;
-                               case FB_BLANK_HSYNC_SUSPEND:
-                                       custom.hsstrt = hsstrt2hw(par->htotal+16);
-                                       custom.hsstop = hsstop2hw(par->htotal+16);
-                                       custom.vsstrt = vsstrt2hw(par->vsstrt);
-                                       custom.vsstop = vsstrt2hw(par->vsstop);
-                                       break;
-                               case FB_BLANK_POWERDOWN:
-                                       custom.hsstrt = hsstrt2hw(par->htotal+16);
-                                       custom.hsstop = hsstop2hw(par->htotal+16);
-                                       custom.vsstrt = vsstrt2hw(par->vtotal+4);
-                                       custom.vsstop = vsstop2hw(par->vtotal+4);
-                                       break;
-                       }
-                       if (!(par->beamcon0 & BMC0_VARBEAMEN)) {
-                               custom.htotal = htotal2hw(par->htotal);
-                               custom.vtotal = vtotal2hw(par->vtotal);
-                               custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN |
-                                                 BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN;
-                       }
+       /* the source must be completely inside the virtual screen */
+       if (sx + width > info->var.xres_virtual ||
+                       sy + height > info->var.yres_virtual)
+               return;
+
+       if (dy > sy || (dy == sy && dx > sx)) {
+               dy += height;
+               sy += height;
+               rev_copy = 1;
+       }
+       dst = (unsigned long *)
+               ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));
+       src = dst;
+       dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;
+       src_idx = dst_idx;
+       dst_idx += dy * par->next_line * 8 + dx;
+       src_idx += sy * par->next_line * 8 + sx;
+       if (rev_copy) {
+               while (height--) {
+                       dst_idx -= par->next_line * 8;
+                       src_idx -= par->next_line * 8;
+                       copy_one_line_rev(info->var.bits_per_pixel,
+                                         par->next_plane, dst, dst_idx, src,
+                                         src_idx, width);
                }
        } else {
-               custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
-               red = red0;
-               green = green0;
-               blue = blue0;
-               if (!IS_OCS) {
-                       custom.hsstrt = hsstrt2hw(par->hsstrt);
-                       custom.hsstop = hsstop2hw(par->hsstop);
-                       custom.vsstrt = vsstrt2hw(par->vsstrt);
-                       custom.vsstop = vsstop2hw(par->vsstop);
-                       custom.beamcon0 = par->beamcon0;
+               while (height--) {
+                       copy_one_line(info->var.bits_per_pixel,
+                                     par->next_plane, dst, dst_idx, src,
+                                     src_idx, width);
+                       dst_idx += par->next_line * 8;
+                       src_idx += par->next_line * 8;
                }
        }
-#if defined(CONFIG_FB_AMIGA_AGA)
-       if (IS_AGA) {
-               custom.bplcon3 = bplcon3;
-               custom.color[0] = rgb2hw8_high(red, green, blue);
-               custom.bplcon3 = bplcon3 | BPC3_LOCT;
-               custom.color[0] = rgb2hw8_low(red, green, blue);
-               custom.bplcon3 = bplcon3;
-       } else
-#endif
-#if defined(CONFIG_FB_AMIGA_ECS)
-       if (par->bplcon0 & BPC0_SHRES) {
-               u_short color, mask;
-               int i;
-
-               mask = 0x3333;
-               color = rgb2hw2(red, green, blue);
-               for (i = 12; i >= 0; i -= 4)
-                       custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
-               mask <<=2; color >>= 2;
-               for (i = 3; i >= 0; i--)
-                       custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color;
-       } else
-#endif
-               custom.color[0] = rgb2hw4(red, green, blue);
-       is_blanked = do_blank > 0 ? do_blank : 0;
 }
 
-static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix)
-{
-       struct amifb_par *par = &currentpar;
-
-       fix->crsr_width = fix->crsr_xsize = par->crsr.width;
-       fix->crsr_height = fix->crsr_ysize = par->crsr.height;
-       fix->crsr_color1 = 17;
-       fix->crsr_color2 = 18;
-       return 0;
-}
 
-static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data)
+static inline void expand_one_line(int bpp, unsigned long next_plane,
+                                  unsigned long *dst, int dst_idx, u32 n,
+                                  const u8 *data, u32 bgcolor, u32 fgcolor)
 {
-       struct amifb_par *par = &currentpar;
-       register u_short *lspr, *sspr;
-#ifdef __mc68000__
-       register u_long datawords asm ("d2");
-#else
-       register u_long datawords;
-#endif
-       register short delta;
-       register u_char color;
-       short height, width, bits, words;
-       int size, alloc;
+       const unsigned long *src;
+       int src_idx;
 
-       size = par->crsr.height*par->crsr.width;
-       alloc = var->height*var->width;
-       var->height = par->crsr.height;
-       var->width = par->crsr.width;
-       var->xspot = par->crsr.spot_x;
-       var->yspot = par->crsr.spot_y;
-       if (size > var->height*var->width)
-               return -ENAMETOOLONG;
-       if (!access_ok(VERIFY_WRITE, data, size))
-               return -EFAULT;
-       delta = 1<<par->crsr.fmode;
-       lspr = lofsprite + (delta<<1);
-       if (par->bplcon0 & BPC0_LACE)
-               sspr = shfsprite + (delta<<1);
-       else
-               sspr = NULL;
-       for (height = (short)var->height-1; height >= 0; height--) {
-               bits = 0; words = delta; datawords = 0;
-               for (width = (short)var->width-1; width >= 0; width--) {
-                       if (bits == 0) {
-                               bits = 16; --words;
-#ifdef __mc68000__
-                               asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0"
-                                       : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta));
-#else
-                               datawords = (*(lspr+delta) << 16) | (*lspr++);
-#endif
-                       }
-                       --bits;
-#ifdef __mc68000__
-                       asm volatile (
-                               "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; "
-                               "swap %1 ; lslw #1,%1 ; roxlb #1,%0"
-                               : "=d" (color), "=d" (datawords) : "1" (datawords));
-#else
-                       color = (((datawords >> 30) & 2)
-                                | ((datawords >> 15) & 1));
-                       datawords <<= 1;
-#endif
-                       put_user(color, data++);
-               }
-               if (bits > 0) {
-                       --words; ++lspr;
-               }
-               while (--words >= 0)
-                       ++lspr;
-#ifdef __mc68000__
-               asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
-                       : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
-#else
-               lspr += delta;
-               if (sspr) {
-                       u_short *tmp = lspr;
-                       lspr = sspr;
-                       sspr = tmp;
-               }
-#endif
+       while (1) {
+               dst += dst_idx >> SHIFT_PER_LONG;
+               dst_idx &= (BITS_PER_LONG - 1);
+               if ((bgcolor ^ fgcolor) & 1) {
+                       src = (unsigned long *)
+                               ((unsigned long)data & ~(BYTES_PER_LONG - 1));
+                       src_idx = ((unsigned long)data & (BYTES_PER_LONG - 1)) * 8;
+                       if (fgcolor & 1)
+                               bitcpy(dst, dst_idx, src, src_idx, n);
+                       else
+                               bitcpy_not(dst, dst_idx, src, src_idx, n);
+                       /* set or clear */
+               } else
+                       bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n);
+               if (!--bpp)
+                       break;
+               bgcolor >>= 1;
+               fgcolor >>= 1;
+               dst_idx += next_plane * 8;
        }
-       return 0;
 }
 
-static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data)
+
+static void amifb_imageblit(struct fb_info *info, const struct fb_image *image)
 {
-       struct amifb_par *par = &currentpar;
-       register u_short *lspr, *sspr;
-#ifdef __mc68000__
-       register u_long datawords asm ("d2");
-#else
-       register u_long datawords;
-#endif
-       register short delta;
-       u_short fmode;
-       short height, width, bits, words;
+       struct amifb_par *par = info->par;
+       int x2, y2;
+       unsigned long *dst;
+       int dst_idx;
+       const char *src;
+       u32 dx, dy, width, height, pitch;
 
-       if (!var->width)
-               return -EINVAL;
-       else if (var->width <= 16)
-               fmode = TAG_FMODE_1;
-       else if (var->width <= 32)
-               fmode = TAG_FMODE_2;
-       else if (var->width <= 64)
-               fmode = TAG_FMODE_4;
-       else
-               return -EINVAL;
-       if (fmode > maxfmode)
-               return -EINVAL;
-       if (!var->height)
-               return -EINVAL;
-       if (!access_ok(VERIFY_READ, data, var->width*var->height))
-               return -EFAULT;
-       delta = 1<<fmode;
-       lofsprite = shfsprite = (u_short *)spritememory;
-       lspr = lofsprite + (delta<<1);
-       if (par->bplcon0 & BPC0_LACE) {
-               if (((var->height+4)<<fmode<<2) > SPRITEMEMSIZE)
-                       return -EINVAL;
-               memset(lspr, 0, (var->height+4)<<fmode<<2);
-               shfsprite += ((var->height+5)&-2)<<fmode;
-               sspr = shfsprite + (delta<<1);
-       } else {
-               if (((var->height+2)<<fmode<<2) > SPRITEMEMSIZE)
-                       return -EINVAL;
-               memset(lspr, 0, (var->height+2)<<fmode<<2);
-               sspr = NULL;
-       }
-       for (height = (short)var->height-1; height >= 0; height--) {
-               bits = 16; words = delta; datawords = 0;
-               for (width = (short)var->width-1; width >= 0; width--) {
-                       unsigned long tdata = 0;
-                       get_user(tdata, data);
-                       data++;
-#ifdef __mc68000__
-                       asm volatile (
-                               "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; "
-                               "lsrb #1,%2 ; roxlw #1,%0 ; swap %0"
-                               : "=d" (datawords)
-                               : "0" (datawords), "d" (tdata));
-#else
-                       datawords = ((datawords << 1) & 0xfffefffe);
-                       datawords |= tdata & 1;
-                       datawords |= (tdata & 2) << (16-1);
-#endif
-                       if (--bits == 0) {
-                               bits = 16; --words;
-#ifdef __mc68000__
-                               asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+"
-                                       : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta));
-#else
-                               *(lspr+delta) = (u_short) (datawords >> 16);
-                               *lspr++ = (u_short) (datawords & 0xffff);
-#endif
-                       }
-               }
-               if (bits < 16) {
-                       --words;
-#ifdef __mc68000__
-                       asm volatile (
-                               "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; "
-                               "swap %2 ; lslw %4,%2 ; movew %2,%0@+"
-                               : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits));
-#else
-                       *(lspr+delta) = (u_short) (datawords >> (16+bits));
-                       *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits);
-#endif
-               }
-               while (--words >= 0) {
-#ifdef __mc68000__
-                       asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+"
-                               : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0");
-#else
-                       *(lspr+delta) = 0;
-                       *lspr++ = 0;
-#endif
-               }
-#ifdef __mc68000__
-               asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:"
-                       : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta));
-#else
-               lspr += delta;
-               if (sspr) {
-                       u_short *tmp = lspr;
-                       lspr = sspr;
-                       sspr = tmp;
+       /*
+        * We could use hardware clipping but on many cards you get around
+        * hardware clipping by writing to framebuffer directly like we are
+        * doing here.
+        */
+       x2 = image->dx + image->width;
+       y2 = image->dy + image->height;
+       dx = image->dx;
+       dy = image->dy;
+       x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+       y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+       width  = x2 - dx;
+       height = y2 - dy;
+
+       if (image->depth == 1) {
+               dst = (unsigned long *)
+                       ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));
+               dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;
+               dst_idx += dy * par->next_line * 8 + dx;
+               src = image->data;
+               pitch = (image->width + 7) / 8;
+               while (height--) {
+                       expand_one_line(info->var.bits_per_pixel,
+                                       par->next_plane, dst, dst_idx, width,
+                                       src, image->bg_color,
+                                       image->fg_color);
+                       dst_idx += par->next_line * 8;
+                       src += pitch;
                }
-#endif
-       }
-       par->crsr.height = var->height;
-       par->crsr.width = var->width;
-       par->crsr.spot_x = var->xspot;
-       par->crsr.spot_y = var->yspot;
-       par->crsr.fmode = fmode;
-       if (IS_AGA) {
-               par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32);
-               par->fmode |= sprfetchmode[fmode];
-               custom.fmode = par->fmode;
+       } else {
+               c2p_planar(info->screen_base, image->data, dx, dy, width,
+                          height, par->next_line, par->next_plane,
+                          image->width, info->var.bits_per_pixel);
        }
-       return 0;
 }
 
-static int ami_get_cursorstate(struct fb_cursorstate *state)
+
+       /*
+        * Amiga Frame Buffer Specific ioctls
+        */
+
+static int amifb_ioctl(struct fb_info *info,
+                      unsigned int cmd, unsigned long arg)
 {
-       struct amifb_par *par = &currentpar;
+       union {
+               struct fb_fix_cursorinfo fix;
+               struct fb_var_cursorinfo var;
+               struct fb_cursorstate state;
+       } crsr;
+       void __user *argp = (void __user *)arg;
+       int i;
 
-       state->xoffset = par->crsr.crsr_x;
-       state->yoffset = par->crsr.crsr_y;
-       state->mode = cursormode;
-       return 0;
+       switch (cmd) {
+       case FBIOGET_FCURSORINFO:
+               i = ami_get_fix_cursorinfo(&crsr.fix, info->par);
+               if (i)
+                       return i;
+               return copy_to_user(argp, &crsr.fix,
+                                   sizeof(crsr.fix)) ? -EFAULT : 0;
+
+       case FBIOGET_VCURSORINFO:
+               i = ami_get_var_cursorinfo(&crsr.var,
+                       ((struct fb_var_cursorinfo __user *)arg)->data,
+                       info->par);
+               if (i)
+                       return i;
+               return copy_to_user(argp, &crsr.var,
+                                   sizeof(crsr.var)) ? -EFAULT : 0;
+
+       case FBIOPUT_VCURSORINFO:
+               if (copy_from_user(&crsr.var, argp, sizeof(crsr.var)))
+                       return -EFAULT;
+               return ami_set_var_cursorinfo(&crsr.var,
+                       ((struct fb_var_cursorinfo __user *)arg)->data,
+                       info->par);
+
+       case FBIOGET_CURSORSTATE:
+               i = ami_get_cursorstate(&crsr.state, info->par);
+               if (i)
+                       return i;
+               return copy_to_user(argp, &crsr.state,
+                                   sizeof(crsr.state)) ? -EFAULT : 0;
+
+       case FBIOPUT_CURSORSTATE:
+               if (copy_from_user(&crsr.state, argp, sizeof(crsr.state)))
+                       return -EFAULT;
+               return ami_set_cursorstate(&crsr.state, info->par);
+       }
+       return -EINVAL;
 }
 
-static int ami_set_cursorstate(struct fb_cursorstate *state)
+
+       /*
+        * Flash the cursor (called by VBlank interrupt)
+        */
+
+static int flash_cursor(void)
 {
-       struct amifb_par *par = &currentpar;
+       static int cursorcount = 1;
 
-       par->crsr.crsr_x = state->xoffset;
-       par->crsr.crsr_y = state->yoffset;
-       if ((cursormode = state->mode) == FB_CURSOR_OFF)
-               cursorstate = -1;
-       do_cursor = 1;
+       if (cursormode == FB_CURSOR_FLASH) {
+               if (!--cursorcount) {
+                       cursorstate = -cursorstate;
+                       cursorcount = cursorrate;
+                       if (!is_blanked)
+                               return 1;
+               }
+       }
        return 0;
 }
 
-static void ami_set_sprite(void)
+       /*
+        * VBlank Display Interrupt
+        */
+
+static irqreturn_t amifb_interrupt(int irq, void *dev_id)
 {
-       struct amifb_par *par = &currentpar;
-       copins *copl, *cops;
-       u_short hs, vs, ve;
-       u_long pl, ps, pt;
-       short mx, my;
+       struct amifb_par *par = dev_id;
 
-       cops = copdisplay.list[currentcop][0];
-       copl = copdisplay.list[currentcop][1];
-       ps = pl = ZTWO_PADDR(dummysprite);
-       mx = par->crsr.crsr_x-par->crsr.spot_x;
-       my = par->crsr.crsr_y-par->crsr.spot_y;
-       if (!(par->vmode & FB_VMODE_YWRAP)) {
-               mx -= par->xoffset;
-               my -= par->yoffset;
+       if (do_vmode_pan || do_vmode_full)
+               ami_update_display(par);
+
+       if (do_vmode_full)
+               ami_init_display(par);
+
+       if (do_vmode_pan) {
+               flash_cursor();
+               ami_rebuild_copper(par);
+               do_cursor = do_vmode_pan = 0;
+       } else if (do_cursor) {
+               flash_cursor();
+               ami_set_sprite(par);
+               do_cursor = 0;
+       } else {
+               if (flash_cursor())
+                       ami_set_sprite(par);
        }
-       if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 &&
-           mx > -(short)par->crsr.width && mx < par->xres &&
-           my > -(short)par->crsr.height && my < par->yres) {
-               pl = ZTWO_PADDR(lofsprite);
-               hs = par->diwstrt_h + (mx<<par->clk_shift) - 4;
-               vs = par->diwstrt_v + (my<<par->line_shift);
-               ve = vs + (par->crsr.height<<par->line_shift);
-               if (par->bplcon0 & BPC0_LACE) {
-                       ps = ZTWO_PADDR(shfsprite);
-                       lofsprite[0] = spr2hw_pos(vs, hs);
-                       shfsprite[0] = spr2hw_pos(vs+1, hs);
-                       if (mod2(vs)) {
-                               lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
-                               shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1);
-                               pt = pl; pl = ps; ps = pt;
-                       } else {
-                               lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve+1);
-                               shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve);
-                       }
-               } else {
-                       lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0);
-                       lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve);
-               }
+
+       if (do_blank) {
+               ami_do_blank(par);
+               do_blank = 0;
        }
-       copl[cop_spr0ptrh].w[1] = highw(pl);
-       copl[cop_spr0ptrl].w[1] = loww(pl);
-       if (par->bplcon0 & BPC0_LACE) {
-               cops[cop_spr0ptrh].w[1] = highw(ps);
-               cops[cop_spr0ptrl].w[1] = loww(ps);
+
+       if (do_vmode_full) {
+               ami_reinit_copper(par);
+               do_vmode_full = 0;
+       }
+       return IRQ_HANDLED;
+}
+
+
+static struct fb_ops amifb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = amifb_check_var,
+       .fb_set_par     = amifb_set_par,
+       .fb_setcolreg   = amifb_setcolreg,
+       .fb_blank       = amifb_blank,
+       .fb_pan_display = amifb_pan_display,
+       .fb_fillrect    = amifb_fillrect,
+       .fb_copyarea    = amifb_copyarea,
+       .fb_imageblit   = amifb_imageblit,
+       .fb_ioctl       = amifb_ioctl,
+};
+
+
+       /*
+        * Allocate, Clear and Align a Block of Chip Memory
+        */
+
+static void *aligned_chipptr;
+
+static inline u_long __init chipalloc(u_long size)
+{
+       aligned_chipptr = amiga_chip_alloc(size, "amifb [RAM]");
+       if (!aligned_chipptr) {
+               pr_err("amifb: No Chip RAM for frame buffer");
+               return 0;
        }
+       memset(aligned_chipptr, 0, size);
+       return (u_long)aligned_chipptr;
+}
+
+static inline void chipfree(void)
+{
+       if (aligned_chipptr)
+               amiga_chip_free(aligned_chipptr);
 }
 
 
        /*
-        * Initialise the Copper Initialisation List
+        * Initialisation
         */
 
-static void __init ami_init_copper(void)
+static int __init amifb_probe(struct platform_device *pdev)
 {
-       copins *cop = copdisplay.init;
-       u_long p;
-       int i;
+       struct fb_info *info;
+       int tag, i, err = 0;
+       u_long chipptr;
+       u_int defmode;
 
-       if (!IS_OCS) {
-               (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0);
-               (cop++)->l = CMOVE(0x0181, diwstrt);
-               (cop++)->l = CMOVE(0x0281, diwstop);
-               (cop++)->l = CMOVE(0x0000, diwhigh);
-       } else
-               (cop++)->l = CMOVE(BPC0_COLOR, bplcon0);
-       p = ZTWO_PADDR(dummysprite);
-       for (i = 0; i < 8; i++) {
-               (cop++)->l = CMOVE(0, spr[i].pos);
-               (cop++)->l = CMOVE(highw(p), sprpt[i]);
-               (cop++)->l = CMOVE2(loww(p), sprpt[i]);
+#ifndef MODULE
+       char *option = NULL;
+
+       if (fb_get_options("amifb", &option)) {
+               amifb_video_off();
+               return -ENODEV;
        }
+       amifb_setup(option);
+#endif
+       custom.dmacon = DMAF_ALL | DMAF_MASTER;
 
-       (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq);
-       copdisplay.wait = cop;
-       (cop++)->l = CEND;
-       (cop++)->l = CMOVE(0, copjmp2);
-       cop->l = CEND;
+       info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev);
+       if (!info) {
+               dev_err(&pdev->dev, "framebuffer_alloc failed\n");
+               return -ENOMEM;
+       }
 
-       custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init);
-       custom.copjmp1 = 0;
-}
+       strcpy(info->fix.id, "Amiga ");
+       info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+       info->fix.accel = FB_ACCEL_AMIGABLITT;
 
-static void ami_reinit_copper(void)
-{
-       struct amifb_par *par = &currentpar;
+       switch (amiga_chipset) {
+#ifdef CONFIG_FB_AMIGA_OCS
+       case CS_OCS:
+               strcat(info->fix.id, "OCS");
+default_chipset:
+               chipset = TAG_OCS;
+               maxdepth[TAG_SHRES] = 0;        /* OCS means no SHRES */
+               maxdepth[TAG_HIRES] = 4;
+               maxdepth[TAG_LORES] = 6;
+               maxfmode = TAG_FMODE_1;
+               defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC;
+               info->fix.smem_len = VIDEOMEMSIZE_OCS;
+               break;
+#endif /* CONFIG_FB_AMIGA_OCS */
 
-       copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0;
-       copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4);
-}
+#ifdef CONFIG_FB_AMIGA_ECS
+       case CS_ECS:
+               strcat(info->fix.id, "ECS");
+               chipset = TAG_ECS;
+               maxdepth[TAG_SHRES] = 2;
+               maxdepth[TAG_HIRES] = 4;
+               maxdepth[TAG_LORES] = 6;
+               maxfmode = TAG_FMODE_1;
+               if (AMIGAHW_PRESENT(AMBER_FF))
+                       defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL
+                                                    : DEFMODE_AMBER_NTSC;
+               else
+                       defmode = amiga_vblank == 50 ? DEFMODE_PAL
+                                                    : DEFMODE_NTSC;
+               if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT >
+                   VIDEOMEMSIZE_ECS_2M)
+                       info->fix.smem_len = VIDEOMEMSIZE_ECS_2M;
+               else
+                       info->fix.smem_len = VIDEOMEMSIZE_ECS_1M;
+               break;
+#endif /* CONFIG_FB_AMIGA_ECS */
+
+#ifdef CONFIG_FB_AMIGA_AGA
+       case CS_AGA:
+               strcat(info->fix.id, "AGA");
+               chipset = TAG_AGA;
+               maxdepth[TAG_SHRES] = 8;
+               maxdepth[TAG_HIRES] = 8;
+               maxdepth[TAG_LORES] = 8;
+               maxfmode = TAG_FMODE_4;
+               defmode = DEFMODE_AGA;
+               if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT >
+                   VIDEOMEMSIZE_AGA_2M)
+                       info->fix.smem_len = VIDEOMEMSIZE_AGA_2M;
+               else
+                       info->fix.smem_len = VIDEOMEMSIZE_AGA_1M;
+               break;
+#endif /* CONFIG_FB_AMIGA_AGA */
+
+       default:
+#ifdef CONFIG_FB_AMIGA_OCS
+               printk("Unknown graphics chipset, defaulting to OCS\n");
+               strcat(info->fix.id, "Unknown");
+               goto default_chipset;
+#else /* CONFIG_FB_AMIGA_OCS */
+               err = -ENODEV;
+               goto release;
+#endif /* CONFIG_FB_AMIGA_OCS */
+               break;
+       }
 
        /*
-        * Build the Copper List
+        * Calculate the Pixel Clock Values for this Machine
         */
 
-static void ami_build_copper(void)
-{
-       struct amifb_par *par = &currentpar;
-       copins *copl, *cops;
-       u_long p;
+       {
+       u_long tmp = DIVUL(200000000000ULL, amiga_eclock);
 
-       currentcop = 1 - currentcop;
+       pixclock[TAG_SHRES] = (tmp + 4) / 8;    /* SHRES:  35 ns / 28 MHz */
+       pixclock[TAG_HIRES] = (tmp + 2) / 4;    /* HIRES:  70 ns / 14 MHz */
+       pixclock[TAG_LORES] = (tmp + 1) / 2;    /* LORES: 140 ns /  7 MHz */
+       }
 
-       copl = copdisplay.list[currentcop][1];
+       /*
+        * Replace the Tag Values with the Real Pixel Clock Values
+        */
 
-       (copl++)->l = CWAIT(0, 10);
-       (copl++)->l = CMOVE(par->bplcon0, bplcon0);
-       (copl++)->l = CMOVE(0, sprpt[0]);
-       (copl++)->l = CMOVE2(0, sprpt[0]);
+       for (i = 0; i < NUM_TOTAL_MODES; i++) {
+               struct fb_videomode *mode = &ami_modedb[i];
+               tag = mode->pixclock;
+               if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
+                       mode->pixclock = pixclock[tag];
+               }
+       }
 
-       if (par->bplcon0 & BPC0_LACE) {
-               cops = copdisplay.list[currentcop][0];
+       if (amifb_hfmin) {
+               info->monspecs.hfmin = amifb_hfmin;
+               info->monspecs.hfmax = amifb_hfmax;
+               info->monspecs.vfmin = amifb_vfmin;
+               info->monspecs.vfmax = amifb_vfmax;
+       } else {
+               /*
+                *  These are for a typical Amiga monitor (e.g. A1960)
+                */
+               info->monspecs.hfmin = 15000;
+               info->monspecs.hfmax = 38000;
+               info->monspecs.vfmin = 49;
+               info->monspecs.vfmax = 90;
+       }
 
-               (cops++)->l = CWAIT(0, 10);
-               (cops++)->l = CMOVE(par->bplcon0, bplcon0);
-               (cops++)->l = CMOVE(0, sprpt[0]);
-               (cops++)->l = CMOVE2(0, sprpt[0]);
+       info->fbops = &amifb_ops;
+       info->flags = FBINFO_DEFAULT;
+       info->device = &pdev->dev;
 
-               (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt);
-               (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop);
-               (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
-               (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
-               if (!IS_OCS) {
-                       (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1,
-                                           par->diwstop_h, par->diwstop_v+1), diwhigh);
-                       (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
-                                           par->diwstop_h, par->diwstop_v), diwhigh);
-#if 0
-                       if (par->beamcon0 & BMC0_VARBEAMEN) {
-                               (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
-                               (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt);
-                               (copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop);
-                               (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
-                               (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
-                               (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
-                       }
-#endif
-               }
-               p = ZTWO_PADDR(copdisplay.list[currentcop][0]);
-               (copl++)->l = CMOVE(highw(p), cop2lc);
-               (copl++)->l = CMOVE2(loww(p), cop2lc);
-               p = ZTWO_PADDR(copdisplay.list[currentcop][1]);
-               (cops++)->l = CMOVE(highw(p), cop2lc);
-               (cops++)->l = CMOVE2(loww(p), cop2lc);
-               copdisplay.rebuild[0] = cops;
-       } else {
-               (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt);
-               (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop);
-               if (!IS_OCS) {
-                       (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v,
-                                           par->diwstop_h, par->diwstop_v), diwhigh);
-#if 0
-                       if (par->beamcon0 & BMC0_VARBEAMEN) {
-                               (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal);
-                               (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt);
-                               (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop);
-                       }
-#endif
-               }
+       if (!fb_find_mode(&info->var, info, mode_option, ami_modedb,
+                         NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
+               err = -EINVAL;
+               goto release;
        }
-       copdisplay.rebuild[1] = copl;
 
-       ami_update_par();
-       ami_rebuild_copper();
-}
+       fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES,
+                                &info->modelist);
+
+       round_down_bpp = 0;
+       chipptr = chipalloc(info->fix.smem_len + SPRITEMEMSIZE +
+                           DUMMYSPRITEMEMSIZE + COPINITSIZE +
+                           4 * COPLISTSIZE);
+       if (!chipptr) {
+               err = -ENOMEM;
+               goto release;
+       }
+
+       assignchunk(videomemory, u_long, chipptr, info->fix.smem_len);
+       assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
+       assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
+       assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
+       assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);
+       assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);
+       assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);
+       assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);
 
        /*
-        * Rebuild the Copper List
-        *
-        * We only change the things that are not static
+        * access the videomem with writethrough cache
         */
+       info->fix.smem_start = (u_long)ZTWO_PADDR(videomemory);
+       videomemory = (u_long)ioremap_writethrough(info->fix.smem_start,
+                                                  info->fix.smem_len);
+       if (!videomemory) {
+               dev_warn(&pdev->dev,
+                        "Unable to map videomem cached writethrough\n");
+               info->screen_base = (char *)ZTWO_VADDR(info->fix.smem_start);
+       } else
+               info->screen_base = (char *)videomemory;
 
-static void ami_rebuild_copper(void)
-{
-       struct amifb_par *par = &currentpar;
-       copins *copl, *cops;
-       u_short line, h_end1, h_end2;
-       short i;
-       u_long p;
+       memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
 
-       if (IS_AGA && maxfmode + par->clk_shift == 0)
-               h_end1 = par->diwstrt_h-64;
-       else
-               h_end1 = par->htotal-32;
-       h_end2 = par->ddfstop+64;
+       /*
+        * Make sure the Copper has something to do
+        */
+       ami_init_copper();
 
-       ami_set_sprite();
+       /*
+        * Enable Display DMA
+        */
+       custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
+                       DMAF_BLITTER | DMAF_SPRITE;
 
-       copl = copdisplay.rebuild[1];
-       p = par->bplpt0;
-       if (par->vmode & FB_VMODE_YWRAP) {
-               if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) {
-                       if (par->yoffset > par->vyres-par->yres) {
-                               for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
-                                       (copl++)->l = CMOVE(highw(p), bplpt[i]);
-                                       (copl++)->l = CMOVE2(loww(p), bplpt[i]);
-                               }
-                               line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 1;
-                               while (line >= 512) {
-                                       (copl++)->l = CWAIT(h_end1, 510);
-                                       line -= 512;
-                               }
-                               if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0)
-                                       (copl++)->l = CWAIT(h_end1, line);
-                               else
-                                       (copl++)->l = CWAIT(h_end2, line);
-                               p = par->bplpt0wrap;
-                       }
-               } else p = par->bplpt0wrap;
-       }
-       for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
-               (copl++)->l = CMOVE(highw(p), bplpt[i]);
-               (copl++)->l = CMOVE2(loww(p), bplpt[i]);
-       }
-       copl->l = CEND;
+       err = request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,
+                         "fb vertb handler", info->par);
+       if (err)
+               goto disable_dma;
 
-       if (par->bplcon0 & BPC0_LACE) {
-               cops = copdisplay.rebuild[0];
-               p = par->bplpt0;
-               if (mod2(par->diwstrt_v))
-                       p -= par->next_line;
-               else
-                       p += par->next_line;
-               if (par->vmode & FB_VMODE_YWRAP) {
-                       if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) {
-                               if (par->yoffset > par->vyres-par->yres+1) {
-                                       for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
-                                               (cops++)->l = CMOVE(highw(p), bplpt[i]);
-                                               (cops++)->l = CMOVE2(loww(p), bplpt[i]);
-                                       }
-                                       line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 2;
-                                       while (line >= 512) {
-                                               (cops++)->l = CWAIT(h_end1, 510);
-                                               line -= 512;
-                                       }
-                                       if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0)
-                                               (cops++)->l = CWAIT(h_end1, line);
-                                       else
-                                               (cops++)->l = CWAIT(h_end2, line);
-                                       p = par->bplpt0wrap;
-                                       if (mod2(par->diwstrt_v+par->vyres-par->yoffset))
-                                               p -= par->next_line;
-                                       else
-                                               p += par->next_line;
-                               }
-                       } else p = par->bplpt0wrap - par->next_line;
-               }
-               for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) {
-                       (cops++)->l = CMOVE(highw(p), bplpt[i]);
-                       (cops++)->l = CMOVE2(loww(p), bplpt[i]);
-               }
-               cops->l = CEND;
-       }
+       err = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0);
+       if (err)
+               goto free_irq;
+
+       dev_set_drvdata(&pdev->dev, info);
+
+       err = register_framebuffer(info);
+       if (err)
+               goto unset_drvdata;
+
+       printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+              info->node, info->fix.id, info->fix.smem_len>>10);
+
+       return 0;
+
+unset_drvdata:
+       dev_set_drvdata(&pdev->dev, NULL);
+       fb_dealloc_cmap(&info->cmap);
+free_irq:
+       free_irq(IRQ_AMIGA_COPPER, info->par);
+disable_dma:
+       custom.dmacon = DMAF_ALL | DMAF_MASTER;
+       if (videomemory)
+               iounmap((void *)videomemory);
+       chipfree();
+release:
+       framebuffer_release(info);
+       return err;
 }
 
+
 static int __exit amifb_remove(struct platform_device *pdev)
 {
-       unregister_framebuffer(&fb_info);
-       amifb_deinit(pdev);
+       struct fb_info *info = dev_get_drvdata(&pdev->dev);
+
+       unregister_framebuffer(info);
+       dev_set_drvdata(&pdev->dev, NULL);
+       fb_dealloc_cmap(&info->cmap);
+       free_irq(IRQ_AMIGA_COPPER, info->par);
+       custom.dmacon = DMAF_ALL | DMAF_MASTER;
+       if (videomemory)
+               iounmap((void *)videomemory);
+       chipfree();
+       framebuffer_release(info);
        amifb_video_off();
        return 0;
 }
index 63409c122ae804ec9fea9dd684cfac1b516a32ef..0d7b20d4285d3cb47fc1894c237321756512942a 100644 (file)
@@ -100,8 +100,11 @@ static int atmel_bl_update_status(struct backlight_device *bl)
                brightness = 0;
 
        lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
-       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+       if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE)
+               lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
                        brightness ? contrast_ctr : 0);
+       else
+               lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
 
        bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
 
@@ -682,14 +685,30 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
 
        case FB_VISUAL_PSEUDOCOLOR:
                if (regno < 256) {
-                       val  = ((red   >> 11) & 0x001f);
-                       val |= ((green >>  6) & 0x03e0);
-                       val |= ((blue  >>  1) & 0x7c00);
-
-                       /*
-                        * TODO: intensity bit. Maybe something like
-                        *   ~(red[10] ^ green[10] ^ blue[10]) & 1
-                        */
+                       if (cpu_is_at91sam9261() || cpu_is_at91sam9263()
+                           || cpu_is_at91sam9rl()) {
+                               /* old style I+BGR:555 */
+                               val  = ((red   >> 11) & 0x001f);
+                               val |= ((green >>  6) & 0x03e0);
+                               val |= ((blue  >>  1) & 0x7c00);
+
+                               /*
+                                * TODO: intensity bit. Maybe something like
+                                *   ~(red[10] ^ green[10] ^ blue[10]) & 1
+                                */
+                       } else {
+                               /* new style BGR:565 / RGB:565 */
+                               if (sinfo->lcd_wiring_mode ==
+                                   ATMEL_LCDC_WIRING_RGB) {
+                                       val  = ((blue >> 11) & 0x001f);
+                                       val |= ((red  >>  0) & 0xf800);
+                               } else {
+                                       val  = ((red  >> 11) & 0x001f);
+                                       val |= ((blue >>  0) & 0xf800);
+                               }
+
+                               val |= ((green >>  5) & 0x07e0);
+                       }
 
                        lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
                        ret = 0;
index 44bdce4242ad0a8d48e09ae6c1b94481fb602de5..622f12b62a470ffb84658085c8d57194a33a7c63 100644 (file)
@@ -301,9 +301,9 @@ static struct fb_ops atyfb_ops = {
        .fb_sync        = atyfb_sync,
 };
 
-static int noaccel;
+static bool noaccel;
 #ifdef CONFIG_MTRR
-static int nomtrr;
+static bool nomtrr;
 #endif
 static int vram;
 static int pll;
index 150684882ef74fce86d33ea2ed14bad9afa5df5b..ce1506b75adfb4c04a028498b111b497139a8dec 100644 (file)
@@ -263,19 +263,19 @@ static reg_val common_regs[] = {
         
 static char *mode_option;
 static char *monitor_layout;
-static int noaccel = 0;
+static bool noaccel = 0;
 static int default_dynclk = -2;
-static int nomodeset = 0;
-static int ignore_edid = 0;
-static int mirror = 0;
+static bool nomodeset = 0;
+static bool ignore_edid = 0;
+static bool mirror = 0;
 static int panel_yres = 0;
-static int force_dfp = 0;
-static int force_measure_pll = 0;
+static bool force_dfp = 0;
+static bool force_measure_pll = 0;
 #ifdef CONFIG_MTRR
-static int nomtrr = 0;
+static bool nomtrr = 0;
 #endif
-static int force_sleep;
-static int ignore_devlist;
+static bool force_sleep;
+static bool ignore_devlist;
 #ifdef CONFIG_PMAC_BACKLIGHT
 static int backlight = 1;
 #else
index 649cb35de4ed401d2ffce0e1c5abcaeb71f4037a..de9da6774fd9e51f237ba7adc0aa8319ae8b6eec 100644 (file)
 
 #include "au1100fb.h"
 
-/*
- * Sanity check. If this is a new Au1100 based board, search for
- * the PB1100 ifdefs to make sure you modify the code accordingly.
- */
-#if defined(CONFIG_MIPS_PB1100)
-  #include <asm/mach-pb1x00/pb1100.h>
-#elif defined(CONFIG_MIPS_DB1100)
-  #include <asm/mach-db1x00/db1x00.h>
-#else
-  #error "Unknown Au1100 board, Au1100 FB driver not supported"
-#endif
-
 #define DRIVER_NAME "au1100fb"
 #define DRIVER_DESC "LCD controller driver for AU1100 processors"
 
index 72005598040f0668762c0a8288865c8e809c01de..04e4479d5afd70291a86497ec7e48118b2cf75cb 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/slab.h>
 
 #include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1200fb.h>  /* platform_data */
 #include "au1200fb.h"
 
 #define DRIVER_NAME "au1200fb"
@@ -143,6 +144,7 @@ struct au1200_lcd_iodata_t {
 /* Private, per-framebuffer management information (independent of the panel itself) */
 struct au1200fb_device {
        struct fb_info *fb_info;                /* FB driver info record */
+       struct au1200fb_platdata *pd;
 
        int                                     plane;
        unsigned char*          fb_mem;         /* FrameBuffer memory map */
@@ -201,9 +203,6 @@ struct window_settings {
 #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
 #endif
 
-extern int board_au1200fb_panel_init (void);
-extern int board_au1200fb_panel_shutdown (void);
-
 /*
  * Default window configurations
  */
@@ -334,8 +333,6 @@ struct panel_settings
        uint32 mode_toyclksrc;
        uint32 mode_backlight;
        uint32 mode_auxpll;
-       int (*device_init)(void);
-       int (*device_shutdown)(void);
 #define Xres min_xres
 #define Yres min_yres
        u32     min_xres;               /* Minimum horizontal resolution */
@@ -385,8 +382,6 @@ static struct panel_settings known_lcd_panels[] =
                .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
                .mode_backlight = 0x00000000,
                .mode_auxpll            = 8, /* 96MHz AUXPLL */
-               .device_init            = NULL,
-               .device_shutdown        = NULL,
                320, 320,
                240, 240,
        },
@@ -415,8 +410,6 @@ static struct panel_settings known_lcd_panels[] =
                .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
                .mode_backlight = 0x00000000,
                .mode_auxpll            = 8, /* 96MHz AUXPLL */
-               .device_init            = NULL,
-               .device_shutdown        = NULL,
                640, 480,
                640, 480,
        },
@@ -445,8 +438,6 @@ static struct panel_settings known_lcd_panels[] =
                .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
                .mode_backlight = 0x00000000,
                .mode_auxpll            = 8, /* 96MHz AUXPLL */
-               .device_init            = NULL,
-               .device_shutdown        = NULL,
                800, 800,
                600, 600,
        },
@@ -475,8 +466,6 @@ static struct panel_settings known_lcd_panels[] =
                .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
                .mode_backlight = 0x00000000,
                .mode_auxpll            = 6, /* 72MHz AUXPLL */
-               .device_init            = NULL,
-               .device_shutdown        = NULL,
                1024, 1024,
                768, 768,
        },
@@ -505,8 +494,6 @@ static struct panel_settings known_lcd_panels[] =
                .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
                .mode_backlight = 0x00000000,
                .mode_auxpll            = 10, /* 120MHz AUXPLL */
-               .device_init            = NULL,
-               .device_shutdown        = NULL,
                1280, 1280,
                1024, 1024,
        },
@@ -535,8 +522,6 @@ static struct panel_settings known_lcd_panels[] =
                .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
                .mode_backlight = 0x00000000,
                .mode_auxpll            = 8, /* 96MHz AUXPLL */
-               .device_init            = board_au1200fb_panel_init,
-               .device_shutdown        = board_au1200fb_panel_shutdown,
                1024, 1024,
                768, 768,
        },
@@ -568,8 +553,6 @@ static struct panel_settings known_lcd_panels[] =
                .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
                .mode_backlight = 0x00000000,
                .mode_auxpll            = 8, /* 96MHz AUXPLL */
-               .device_init            = board_au1200fb_panel_init,
-               .device_shutdown        = board_au1200fb_panel_shutdown,
                640, 480,
                640, 480,
        },
@@ -601,8 +584,6 @@ static struct panel_settings known_lcd_panels[] =
                .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
                .mode_backlight = 0x00000000,
                .mode_auxpll            = 8, /* 96MHz AUXPLL */
-               .device_init            = board_au1200fb_panel_init,
-               .device_shutdown        = board_au1200fb_panel_shutdown,
                320, 320,
                240, 240,
        },
@@ -634,11 +615,43 @@ static struct panel_settings known_lcd_panels[] =
                .mode_toyclksrc = 0x00000004, /* AUXPLL directly */
                .mode_backlight = 0x00000000,
                .mode_auxpll            = 8, /* 96MHz AUXPLL */
-               .device_init            = board_au1200fb_panel_init,
-               .device_shutdown        = board_au1200fb_panel_shutdown,
                856, 856,
                480, 480,
        },
+       [9] = {
+               .name = "DB1300_800x480",
+               .monspecs = {
+                       .modedb = NULL,
+                       .modedb_len = 0,
+                       .hfmin = 30000,
+                       .hfmax = 70000,
+                       .vfmin = 60,
+                       .vfmax = 60,
+                       .dclkmin = 6000000,
+                       .dclkmax = 28000000,
+                       .input = FB_DISP_RGB,
+               },
+               .mode_screen            = LCD_SCREEN_SX_N(800) |
+                                         LCD_SCREEN_SY_N(480),
+               .mode_horztiming        = LCD_HORZTIMING_HPW_N(5) |
+                                         LCD_HORZTIMING_HND1_N(16) |
+                                         LCD_HORZTIMING_HND2_N(8),
+               .mode_verttiming        = LCD_VERTTIMING_VPW_N(4) |
+                                         LCD_VERTTIMING_VND1_N(8) |
+                                         LCD_VERTTIMING_VND2_N(5),
+               .mode_clkcontrol        = LCD_CLKCONTROL_PCD_N(1) |
+                                         LCD_CLKCONTROL_IV |
+                                         LCD_CLKCONTROL_IH,
+               .mode_pwmdiv            = 0x00000000,
+               .mode_pwmhi             = 0x00000000,
+               .mode_outmask           = 0x00FFFFFF,
+               .mode_fifoctrl          = 0x2f2f2f2f,
+               .mode_toyclksrc         = 0x00000004, /* AUXPLL directly */
+               .mode_backlight         = 0x00000000,
+               .mode_auxpll            = (48/12) * 2,
+               800, 800,
+               480, 480,
+       },
 };
 
 #define NUM_PANELS (ARRAY_SIZE(known_lcd_panels))
@@ -764,7 +777,8 @@ static int au1200_setlocation (struct au1200fb_device *fbdev, int plane,
        return 0;
 }
 
-static void au1200_setpanel (struct panel_settings *newpanel)
+static void au1200_setpanel(struct panel_settings *newpanel,
+                           struct au1200fb_platdata *pd)
 {
        /*
         * Perform global setup/init of LCD controller
@@ -798,8 +812,8 @@ static void au1200_setpanel (struct panel_settings *newpanel)
                    the controller, the clock cannot be turned off before first
                        shutting down the controller.
                 */
-               if (panel->device_shutdown != NULL)
-                       panel->device_shutdown();
+               if (pd->panel_shutdown)
+                       pd->panel_shutdown();
        }
 
        /* Newpanel == NULL indicates a shutdown operation only */
@@ -852,7 +866,8 @@ static void au1200_setpanel (struct panel_settings *newpanel)
        au_sync();
 
        /* Call init of panel */
-       if (panel->device_init != NULL) panel->device_init();
+       if (pd->panel_init)
+               pd->panel_init();
 
        /* FIX!!!! not appropriate on panel change!!! Global setup/init */
        lcd->intenable = 0;
@@ -1185,6 +1200,8 @@ static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
  */
 static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
 {
+       struct au1200fb_device *fbdev = fbi->par;
+
        /* Short-circuit screen blanking */
        if (noblanking)
                return 0;
@@ -1194,13 +1211,13 @@ static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi)
        case FB_BLANK_UNBLANK:
        case FB_BLANK_NORMAL:
                /* printk("turn on panel\n"); */
-               au1200_setpanel(panel);
+               au1200_setpanel(panel, fbdev->pd);
                break;
        case FB_BLANK_VSYNC_SUSPEND:
        case FB_BLANK_HSYNC_SUSPEND:
        case FB_BLANK_POWERDOWN:
                /* printk("turn off panel\n"); */
-               au1200_setpanel(NULL);
+               au1200_setpanel(NULL, fbdev->pd);
                break;
        default:
                break;
@@ -1428,6 +1445,7 @@ static void get_window(unsigned int plane,
 static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
                           unsigned long arg)
 {
+       struct au1200fb_device *fbdev = info->par;
        int plane;
        int val;
 
@@ -1472,7 +1490,7 @@ static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
                                struct panel_settings *newpanel;
                                panel_index = iodata.global.panel_choice;
                                newpanel = &known_lcd_panels[panel_index];
-                               au1200_setpanel(newpanel);
+                               au1200_setpanel(newpanel, fbdev->pd);
                        }
                        break;
 
@@ -1588,22 +1606,102 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
 
 /*-------------------------------------------------------------------------*/
 
-/* AU1200 LCD controller device driver */
 
+static int au1200fb_setup(struct au1200fb_platdata *pd)
+{
+       char *options = NULL;
+       char *this_opt, *endptr;
+       int num_panels = ARRAY_SIZE(known_lcd_panels);
+       int panel_idx = -1;
+
+       fb_get_options(DRIVER_NAME, &options);
+
+       if (!options)
+               goto out;
+
+       while ((this_opt = strsep(&options, ",")) != NULL) {
+               /* Panel option - can be panel name,
+                * "bs" for board-switch, or number/index */
+               if (!strncmp(this_opt, "panel:", 6)) {
+                       int i;
+                       long int li;
+                       char *endptr;
+                       this_opt += 6;
+                       /* First check for index, which allows
+                        * to short circuit this mess */
+                       li = simple_strtol(this_opt, &endptr, 0);
+                       if (*endptr == '\0')
+                               panel_idx = (int)li;
+                       else if (strcmp(this_opt, "bs") == 0)
+                               panel_idx = pd->panel_index();
+                       else {
+                               for (i = 0; i < num_panels; i++) {
+                                       if (!strcmp(this_opt,
+                                                   known_lcd_panels[i].name)) {
+                                               panel_idx = i;
+                                               break;
+                                       }
+                               }
+                       }
+                       if ((panel_idx < 0) || (panel_idx >= num_panels))
+                               print_warn("Panel %s not supported!", this_opt);
+                       else
+                               panel_index = panel_idx;
+
+               } else if (strncmp(this_opt, "nohwcursor", 10) == 0)
+                       nohwcursor = 1;
+               else if (strncmp(this_opt, "devices:", 8) == 0) {
+                       this_opt += 8;
+                       device_count = simple_strtol(this_opt, &endptr, 0);
+                       if ((device_count < 0) ||
+                           (device_count > MAX_DEVICE_COUNT))
+                               device_count = MAX_DEVICE_COUNT;
+               } else if (strncmp(this_opt, "wincfg:", 7) == 0) {
+                       this_opt += 7;
+                       window_index = simple_strtol(this_opt, &endptr, 0);
+                       if ((window_index < 0) ||
+                           (window_index >= ARRAY_SIZE(windows)))
+                               window_index = DEFAULT_WINDOW_INDEX;
+               } else if (strncmp(this_opt, "off", 3) == 0)
+                       return 1;
+               else
+                       print_warn("Unsupported option \"%s\"", this_opt);
+       }
+
+out:
+       return 0;
+}
+
+/* AU1200 LCD controller device driver */
 static int __devinit au1200fb_drv_probe(struct platform_device *dev)
 {
        struct au1200fb_device *fbdev;
+       struct au1200fb_platdata *pd;
        struct fb_info *fbi = NULL;
        unsigned long page;
        int bpp, plane, ret, irq;
 
+       print_info("" DRIVER_DESC "");
+
+       pd = dev->dev.platform_data;
+       if (!pd)
+               return -ENODEV;
+
+       /* Setup driver with options */
+       if (au1200fb_setup(pd))
+               return -ENODEV;
+
+       /* Point to the panel selected */
+       panel = &known_lcd_panels[panel_index];
+       win = &windows[window_index];
+
+       printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
+       printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
+
        /* shut gcc up */
        ret = 0;
        fbdev = NULL;
 
-       /* Kickstart the panel */
-       au1200_setpanel(panel);
-
        for (plane = 0; plane < device_count; ++plane) {
                bpp = winbpp(win->w[plane].mode_winctrl1);
                if (win->w[plane].xres == 0)
@@ -1619,6 +1717,7 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev)
                _au1200fb_infos[plane] = fbi;
                fbdev = fbi->par;
                fbdev->fb_info = fbi;
+               fbdev->pd = pd;
 
                fbdev->plane = plane;
 
@@ -1680,6 +1779,11 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev)
                goto failed;
        }
 
+       platform_set_drvdata(dev, pd);
+
+       /* Kickstart the panel */
+       au1200_setpanel(panel, pd);
+
        return 0;
 
 failed:
@@ -1699,12 +1803,13 @@ failed:
 
 static int __devexit au1200fb_drv_remove(struct platform_device *dev)
 {
+       struct au1200fb_platdata *pd = platform_get_drvdata(dev);
        struct au1200fb_device *fbdev;
        struct fb_info *fbi;
        int plane;
 
        /* Turn off the panel */
-       au1200_setpanel(NULL);
+       au1200_setpanel(NULL, pd);
 
        for (plane = 0; plane < device_count; ++plane)  {
                fbi = _au1200fb_infos[plane];
@@ -1732,7 +1837,8 @@ static int __devexit au1200fb_drv_remove(struct platform_device *dev)
 #ifdef CONFIG_PM
 static int au1200fb_drv_suspend(struct device *dev)
 {
-       au1200_setpanel(NULL);
+       struct au1200fb_platdata *pd = dev_get_drvdata(dev);
+       au1200_setpanel(NULL, pd);
 
        lcd->outmask = 0;
        au_sync();
@@ -1742,11 +1848,12 @@ static int au1200fb_drv_suspend(struct device *dev)
 
 static int au1200fb_drv_resume(struct device *dev)
 {
+       struct au1200fb_platdata *pd = dev_get_drvdata(dev);
        struct fb_info *fbi;
        int i;
 
        /* Kickstart the panel */
-       au1200_setpanel(panel);
+       au1200_setpanel(panel, pd);
 
        for (i = 0; i < device_count; i++) {
                fbi = _au1200fb_infos[i];
@@ -1781,100 +1888,8 @@ static struct platform_driver au1200fb_driver = {
 
 /*-------------------------------------------------------------------------*/
 
-/* Kernel driver */
-
-static int au1200fb_setup(void)
-{
-       char *options = NULL;
-       char *this_opt, *endptr;
-       int num_panels = ARRAY_SIZE(known_lcd_panels);
-       int panel_idx = -1;
-
-       fb_get_options(DRIVER_NAME, &options);
-
-       if (options) {
-               while ((this_opt = strsep(&options,",")) != NULL) {
-                       /* Panel option - can be panel name,
-                        * "bs" for board-switch, or number/index */
-                       if (!strncmp(this_opt, "panel:", 6)) {
-                               int i;
-                               long int li;
-                               char *endptr;
-                               this_opt += 6;
-                               /* First check for index, which allows
-                                * to short circuit this mess */
-                               li = simple_strtol(this_opt, &endptr, 0);
-                               if (*endptr == '\0') {
-                                       panel_idx = (int)li;
-                               }
-                               else if (strcmp(this_opt, "bs") == 0) {
-                                       extern int board_au1200fb_panel(void);
-                                       panel_idx = board_au1200fb_panel();
-                               }
-
-                               else
-                               for (i = 0; i < num_panels; i++) {
-                                       if (!strcmp(this_opt, known_lcd_panels[i].name)) {
-                                               panel_idx = i;
-                                               break;
-                                       }
-                               }
-
-                               if ((panel_idx < 0) || (panel_idx >= num_panels)) {
-                                               print_warn("Panel %s not supported!", this_opt);
-                               }
-                               else
-                                       panel_index = panel_idx;
-                       }
-
-                       else if (strncmp(this_opt, "nohwcursor", 10) == 0) {
-                               nohwcursor = 1;
-                       }
-
-                       else if (strncmp(this_opt, "devices:", 8) == 0) {
-                               this_opt += 8;
-                               device_count = simple_strtol(this_opt,
-                                                            &endptr, 0);
-                               if ((device_count < 0) ||
-                                   (device_count > MAX_DEVICE_COUNT))
-                                       device_count = MAX_DEVICE_COUNT;
-                       }
-
-                       else if (strncmp(this_opt, "wincfg:", 7) == 0) {
-                               this_opt += 7;
-                               window_index = simple_strtol(this_opt,
-                                                            &endptr, 0);
-                               if ((window_index < 0) ||
-                                   (window_index >= ARRAY_SIZE(windows)))
-                                       window_index = DEFAULT_WINDOW_INDEX;
-                       }
-
-                       else if (strncmp(this_opt, "off", 3) == 0)
-                               return 1;
-                       /* Unsupported option */
-                       else {
-                               print_warn("Unsupported option \"%s\"", this_opt);
-                       }
-               }
-       }
-       return 0;
-}
-
 static int __init au1200fb_init(void)
 {
-       print_info("" DRIVER_DESC "");
-
-       /* Setup driver with options */
-       if (au1200fb_setup())
-               return -ENODEV;
-
-       /* Point to the panel selected */
-       panel = &known_lcd_panels[panel_index];
-       win = &windows[window_index];
-
-       printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
-       printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
-
        return platform_driver_register(&au1200fb_driver);
 }
 
index 6df7c54db0a3470b1150d1eb8f5089967628eb73..738c8ce7d132d1aaa88c3c625f5a6bc51aa04d72 100644 (file)
@@ -280,52 +280,74 @@ MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_ZORRO
-static const struct zorro_device_id cirrusfb_zorro_table[] = {
+struct zorrocl {
+       enum cirrus_board type; /* Board type */
+       u32 regoffset;          /* Offset of registers in first Zorro device */
+       u32 ramsize;            /* Size of video RAM in first Zorro device */
+                               /* If zero, use autoprobe on RAM device */
+       u32 ramoffset;          /* Offset of video RAM in first Zorro device */
+       zorro_id ramid;         /* Zorro ID of RAM device */
+       zorro_id ramid2;        /* Zorro ID of optional second RAM device */
+};
+
+static const struct zorrocl zcl_sd64 __devinitconst = {
+       .type           = BT_SD64,
+       .ramid          = ZORRO_PROD_HELFRICH_SD64_RAM,
+};
+
+static const struct zorrocl zcl_piccolo __devinitconst = {
+       .type           = BT_PICCOLO,
+       .ramid          = ZORRO_PROD_HELFRICH_PICCOLO_RAM,
+};
+
+static const struct zorrocl zcl_picasso __devinitconst = {
+       .type           = BT_PICASSO,
+       .ramid          = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
+};
+
+static const struct zorrocl zcl_spectrum __devinitconst = {
+       .type           = BT_SPECTRUM,
+       .ramid          = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
+};
+
+static const struct zorrocl zcl_picasso4_z3 __devinitconst = {
+       .type           = BT_PICASSO4,
+       .regoffset      = 0x00600000,
+       .ramsize        = 4 * MB_,
+       .ramoffset      = 0x01000000,   /* 0x02000000 for 64 MiB boards */
+};
+
+static const struct zorrocl zcl_picasso4_z2 __devinitconst = {
+       .type           = BT_PICASSO4,
+       .regoffset      = 0x10000,
+       .ramid          = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1,
+       .ramid2         = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2,
+};
+
+
+static const struct zorro_device_id cirrusfb_zorro_table[] __devinitconst = {
        {
-               .id             = ZORRO_PROD_HELFRICH_SD64_RAM,
-               .driver_data    = BT_SD64,
+               .id             = ZORRO_PROD_HELFRICH_SD64_REG,
+               .driver_data    = (unsigned long)&zcl_sd64,
        }, {
-               .id             = ZORRO_PROD_HELFRICH_PICCOLO_RAM,
-               .driver_data    = BT_PICCOLO,
+               .id             = ZORRO_PROD_HELFRICH_PICCOLO_REG,
+               .driver_data    = (unsigned long)&zcl_piccolo,
        }, {
-               .id     = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
-               .driver_data    = BT_PICASSO,
+               .id     = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
+               .driver_data    = (unsigned long)&zcl_picasso,
        }, {
-               .id             = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
-               .driver_data    = BT_SPECTRUM,
+               .id             = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
+               .driver_data    = (unsigned long)&zcl_spectrum,
        }, {
                .id             = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
-               .driver_data    = BT_PICASSO4,
+               .driver_data    = (unsigned long)&zcl_picasso4_z3,
+       }, {
+               .id             = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG,
+               .driver_data    = (unsigned long)&zcl_picasso4_z2,
        },
        { 0 }
 };
 MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table);
-
-static const struct {
-       zorro_id id2;
-       unsigned long size;
-} cirrusfb_zorro_table2[] = {
-       [BT_SD64] = {
-               .id2    = ZORRO_PROD_HELFRICH_SD64_REG,
-               .size   = 0x400000
-       },
-       [BT_PICCOLO] = {
-               .id2    = ZORRO_PROD_HELFRICH_PICCOLO_REG,
-               .size   = 0x200000
-       },
-       [BT_PICASSO] = {
-               .id2    = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
-               .size   = 0x200000
-       },
-       [BT_SPECTRUM] = {
-               .id2    = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
-               .size   = 0x200000
-       },
-       [BT_PICASSO4] = {
-               .id2    = 0,
-               .size   = 0x400000
-       }
-};
 #endif /* CONFIG_ZORRO */
 
 #ifdef CIRRUSFB_DEBUG
@@ -350,7 +372,7 @@ struct cirrusfb_info {
        void (*unmap)(struct fb_info *info);
 };
 
-static int noaccel __devinitdata;
+static bool noaccel __devinitdata;
 static char *mode_option __devinitdata = "640x480@60";
 
 /****************************************************************************/
@@ -1956,16 +1978,12 @@ static void cirrusfb_zorro_unmap(struct fb_info *info)
        struct cirrusfb_info *cinfo = info->par;
        struct zorro_dev *zdev = to_zorro_dev(info->device);
 
-       zorro_release_device(zdev);
-
-       if (cinfo->btype == BT_PICASSO4) {
-               cinfo->regbase -= 0x600000;
-               iounmap((void *)cinfo->regbase);
+       if (info->fix.smem_start > 16 * MB_)
                iounmap(info->screen_base);
-       } else {
-               if (zorro_resource_start(zdev) > 0x01000000)
-                       iounmap(info->screen_base);
-       }
+       if (info->fix.mmio_start > 16 * MB_)
+               iounmap(cinfo->regbase);
+
+       zorro_release_device(zdev);
 }
 #endif /* CONFIG_ZORRO */
 
@@ -2222,115 +2240,116 @@ static struct pci_driver cirrusfb_pci_driver = {
 static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
                                             const struct zorro_device_id *ent)
 {
-       struct cirrusfb_info *cinfo;
        struct fb_info *info;
+       int error;
+       const struct zorrocl *zcl;
        enum cirrus_board btype;
-       struct zorro_dev *z2 = NULL;
-       unsigned long board_addr, board_size, size;
-       int ret;
-
-       btype = ent->driver_data;
-       if (cirrusfb_zorro_table2[btype].id2)
-               z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL);
-       size = cirrusfb_zorro_table2[btype].size;
+       unsigned long regbase, ramsize, rambase;
+       struct cirrusfb_info *cinfo;
 
        info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
        if (!info) {
                printk(KERN_ERR "cirrusfb: could not allocate memory\n");
-               ret = -ENOMEM;
-               goto err_out;
+               return -ENOMEM;
+       }
+
+       zcl = (const struct zorrocl *)ent->driver_data;
+       btype = zcl->type;
+       regbase = zorro_resource_start(z) + zcl->regoffset;
+       ramsize = zcl->ramsize;
+       if (ramsize) {
+               rambase = zorro_resource_start(z) + zcl->ramoffset;
+               if (zorro_resource_len(z) == 64 * MB_) {
+                       /* Quirk for 64 MiB Picasso IV */
+                       rambase += zcl->ramoffset;
+               }
+       } else {
+               struct zorro_dev *ram = zorro_find_device(zcl->ramid, NULL);
+               if (!ram || !zorro_resource_len(ram)) {
+                       dev_err(info->device, "No video RAM found\n");
+                       error = -ENODEV;
+                       goto err_release_fb;
+               }
+               rambase = zorro_resource_start(ram);
+               ramsize = zorro_resource_len(ram);
+               if (zcl->ramid2 &&
+                   (ram = zorro_find_device(zcl->ramid2, NULL))) {
+                       if (zorro_resource_start(ram) != rambase + ramsize) {
+                               dev_warn(info->device,
+                                        "Skipping non-contiguous RAM at %pR\n",
+                                        &ram->resource);
+                       } else {
+                               ramsize += zorro_resource_len(ram);
+                       }
+               }
        }
 
-       dev_info(info->device, "%s board detected\n",
-                cirrusfb_board_info[btype].name);
-
-       cinfo = info->par;
-       cinfo->btype = btype;
-
-       assert(z);
-       assert(btype != BT_NONE);
-
-       board_addr = zorro_resource_start(z);
-       board_size = zorro_resource_len(z);
-       info->screen_size = size;
+       dev_info(info->device,
+                "%s board detected, REG at 0x%lx, %lu MiB RAM at 0x%lx\n",
+                cirrusfb_board_info[btype].name, regbase, ramsize / MB_,
+                rambase);
 
        if (!zorro_request_device(z, "cirrusfb")) {
-               dev_err(info->device, "cannot reserve region 0x%lx, abort\n",
-                       board_addr);
-               ret = -EBUSY;
+               dev_err(info->device, "Cannot reserve %pR\n", &z->resource);
+               error = -EBUSY;
                goto err_release_fb;
        }
 
-       ret = -EIO;
-
-       if (btype == BT_PICASSO4) {
-               dev_info(info->device, " REG at $%lx\n", board_addr + 0x600000);
-
-               /* To be precise, for the P4 this is not the */
-               /* begin of the board, but the begin of RAM. */
-               /* for P4, map in its address space in 2 chunks (### TEST! ) */
-               /* (note the ugly hardcoded 16M number) */
-               cinfo->regbase = ioremap(board_addr, 16777216);
-               if (!cinfo->regbase)
-                       goto err_release_region;
-
-               dev_dbg(info->device, "Virtual address for board set to: $%p\n",
-                       cinfo->regbase);
-               cinfo->regbase += 0x600000;
-               info->fix.mmio_start = board_addr + 0x600000;
-
-               info->fix.smem_start = board_addr + 16777216;
-               info->screen_base = ioremap(info->fix.smem_start, 16777216);
-               if (!info->screen_base)
-                       goto err_unmap_regbase;
-       } else {
-               dev_info(info->device, " REG at $%lx\n",
-                        (unsigned long) z2->resource.start);
-
-               info->fix.smem_start = board_addr;
-               if (board_addr > 0x01000000)
-                       info->screen_base = ioremap(board_addr, board_size);
-               else
-                       info->screen_base = (caddr_t) ZTWO_VADDR(board_addr);
-               if (!info->screen_base)
-                       goto err_release_region;
+       cinfo = info->par;
+       cinfo->btype = btype;
 
-               /* set address for REG area of board */
-               cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start);
-               info->fix.mmio_start = z2->resource.start;
+       info->fix.mmio_start = regbase;
+       cinfo->regbase = regbase > 16 * MB_ ? ioremap(regbase, 64 * 1024)
+                                           : (caddr_t)ZTWO_VADDR(regbase);
+       if (!cinfo->regbase) {
+               dev_err(info->device, "Cannot map registers\n");
+               error = -EIO;
+               goto err_release_dev;
+       }
 
-               dev_dbg(info->device, "Virtual address for board set to: $%p\n",
-                       cinfo->regbase);
+       info->fix.smem_start = rambase;
+       info->screen_size = ramsize;
+       info->screen_base = rambase > 16 * MB_ ? ioremap(rambase, ramsize)
+                                              : (caddr_t)ZTWO_VADDR(rambase);
+       if (!info->screen_base) {
+               dev_err(info->device, "Cannot map video RAM\n");
+               error = -EIO;
+               goto err_unmap_reg;
        }
+
        cinfo->unmap = cirrusfb_zorro_unmap;
 
        dev_info(info->device,
-                "Cirrus Logic chipset on Zorro bus, RAM (%lu MB) at $%lx\n",
-                board_size / MB_, board_addr);
-
-       zorro_set_drvdata(z, info);
+                "Cirrus Logic chipset on Zorro bus, RAM (%lu MiB) at 0x%lx\n",
+                ramsize / MB_, rambase);
 
        /* MCLK select etc. */
        if (cirrusfb_board_info[btype].init_sr1f)
                vga_wseq(cinfo->regbase, CL_SEQR1F,
                         cirrusfb_board_info[btype].sr1f);
 
-       ret = cirrusfb_register(info);
-       if (!ret)
-               return 0;
+       error = cirrusfb_register(info);
+       if (error) {
+               dev_err(info->device, "Failed to register device, error %d\n",
+                       error);
+               goto err_unmap_ram;
+       }
 
-       if (btype == BT_PICASSO4 || board_addr > 0x01000000)
+       zorro_set_drvdata(z, info);
+       return 0;
+
+err_unmap_ram:
+       if (rambase > 16 * MB_)
                iounmap(info->screen_base);
 
-err_unmap_regbase:
-       if (btype == BT_PICASSO4)
-               iounmap(cinfo->regbase - 0x600000);
-err_release_region:
-       release_region(board_addr, board_size);
+err_unmap_reg:
+       if (regbase > 16 * MB_)
+               iounmap(cinfo->regbase);
+err_release_dev:
+       zorro_release_device(z);
 err_release_fb:
        framebuffer_release(info);
-err_out:
-       return ret;
+       return error;
 }
 
 void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
@@ -2338,6 +2357,7 @@ void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
        struct fb_info *info = zorro_get_drvdata(z);
 
        cirrusfb_cleanup(info);
+       zorro_set_drvdata(z, NULL);
 }
 
 static struct zorro_driver cirrusfb_zorro_driver = {
index 93317b5b8740aa9730f7db0dadae41a7863559eb..a122d9287d1659e60ad35f1b1cdf6bd8121366e6 100644 (file)
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/gio_device.h>
+
 #include <video/newport.h>
 
 #include <linux/linux_logo.h>
 #include <linux/font.h>
 
-
-extern unsigned long sgi_gfxaddr;
-
 #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
 
 /* borrowed from fbcon.c */
@@ -304,12 +303,6 @@ static const char *newport_startup(void)
 {
        int i;
 
-       if (!sgi_gfxaddr)
-               return NULL;
-
-       if (!npregs)
-               npregs = (struct newport_regs *)/* ioremap cannot fail */
-                       ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
        npregs->cset.config = NPORT_CFG_GD0;
 
        if (newport_wait(npregs))
@@ -743,26 +736,58 @@ const struct consw newport_con = {
        .con_save_screen  = DUMMY
 };
 
-#ifdef MODULE
-static int __init newport_console_init(void)
+static int newport_probe(struct gio_device *dev,
+                        const struct gio_device_id *id)
 {
-       if (!sgi_gfxaddr)
-               return 0;
+       unsigned long newport_addr;
 
-       if (!npregs)
-               npregs = (struct newport_regs *)/* ioremap cannot fail */
-                       ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
+       if (!dev->resource.start)
+               return -EINVAL;
+
+       if (npregs)
+               return -EBUSY; /* we only support one Newport as console */
+
+       newport_addr = dev->resource.start + 0xF0000;
+       if (!request_mem_region(newport_addr, 0x10000, "Newport"))
+               return -ENODEV;
+
+       npregs = (struct newport_regs *)/* ioremap cannot fail */
+               ioremap(newport_addr, sizeof(struct newport_regs));
 
        return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
 }
-module_init(newport_console_init);
 
-static void __exit newport_console_exit(void)
+static void newport_remove(struct gio_device *dev)
 {
        give_up_console(&newport_con);
        iounmap((void *)npregs);
 }
+
+static struct gio_device_id newport_ids[] = {
+       { .id = 0x7e },
+       { .id = 0xff }
+};
+
+MODULE_ALIAS("gio:7e");
+
+static struct gio_driver newport_driver = {
+       .name = "newport",
+       .id_table = newport_ids,
+       .probe = newport_probe,
+       .remove = newport_remove,
+};
+
+int __init newport_console_init(void)
+{
+       return gio_register_driver(&newport_driver);
+}
+
+void __exit newport_console_exit(void)
+{
+       gio_unregister_driver(&newport_driver);
+}
+
+module_init(newport_console_init);
 module_exit(newport_console_exit);
-#endif
 
 MODULE_LICENSE("GPL");
index 7b2c40abae15b21e5ba26f460d809c216fb8e30a..0c189b32a4c5429f632bb812a784b9a4f8868607 100644 (file)
@@ -420,7 +420,7 @@ static int __init init_control(struct fb_info_control *p)
 
        /* Try to pick a video mode out of NVRAM if we have one. */
 #ifdef CONFIG_NVRAM
-       if (default_cmode == CMODE_NVRAM){
+       if (default_cmode == CMODE_NVRAM) {
                cmode = nvram_read_byte(NV_CMODE);
                if(cmode < CMODE_8 || cmode > CMODE_32)
                        cmode = CMODE_8;
diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig
deleted file mode 100644 (file)
index f99af93..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# Display drivers configuration
-#
-
-menu "Display device support"
-
-config DISPLAY_SUPPORT
-       tristate "Display panel/monitor support"
-       ---help---
-         This framework adds support for low-level control of a display.
-         This includes support for power.
-
-         Enable this to be able to choose the drivers for controlling the
-         physical display panel/monitor on some platforms. This not only
-         covers LCD displays for PDAs but also other types of displays
-         such as CRT, TVout etc.
-
-         To have support for your specific display panel you will have to
-         select the proper drivers which depend on this option.
-
-comment "Display hardware drivers"
-       depends on DISPLAY_SUPPORT
-
-endmenu
diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile
deleted file mode 100644 (file)
index c0ea832..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# Display drivers
-
-display-objs                           := display-sysfs.o
-
-obj-$(CONFIG_DISPLAY_SUPPORT)          += display.o
-
diff --git a/drivers/video/display/display-sysfs.c b/drivers/video/display/display-sysfs.c
deleted file mode 100644 (file)
index 0c647d7..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- *  display-sysfs.c - Display output driver sysfs interface
- *
- *  Copyright (C) 2007 James Simmons <jsimmons@infradead.org>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or (at
- *  your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-#include <linux/module.h>
-#include <linux/display.h>
-#include <linux/ctype.h>
-#include <linux/idr.h>
-#include <linux/err.h>
-#include <linux/kdev_t.h>
-#include <linux/slab.h>
-
-static ssize_t display_show_name(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct display_device *dsp = dev_get_drvdata(dev);
-       return snprintf(buf, PAGE_SIZE, "%s\n", dsp->name);
-}
-
-static ssize_t display_show_type(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct display_device *dsp = dev_get_drvdata(dev);
-       return snprintf(buf, PAGE_SIZE, "%s\n", dsp->type);
-}
-
-static ssize_t display_show_contrast(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct display_device *dsp = dev_get_drvdata(dev);
-       ssize_t rc = -ENXIO;
-
-       mutex_lock(&dsp->lock);
-       if (likely(dsp->driver) && dsp->driver->get_contrast)
-               rc = sprintf(buf, "%d\n", dsp->driver->get_contrast(dsp));
-       mutex_unlock(&dsp->lock);
-       return rc;
-}
-
-static ssize_t display_store_contrast(struct device *dev,
-                                       struct device_attribute *attr,
-                                       const char *buf, size_t count)
-{
-       struct display_device *dsp = dev_get_drvdata(dev);
-       ssize_t ret = -EINVAL, size;
-       int contrast;
-       char *endp;
-
-       contrast = simple_strtoul(buf, &endp, 0);
-       size = endp - buf;
-
-       if (isspace(*endp))
-               size++;
-
-       if (size != count)
-               return ret;
-
-       mutex_lock(&dsp->lock);
-       if (likely(dsp->driver && dsp->driver->set_contrast)) {
-               pr_debug("display: set contrast to %d\n", contrast);
-               dsp->driver->set_contrast(dsp, contrast);
-               ret = count;
-       }
-       mutex_unlock(&dsp->lock);
-       return ret;
-}
-
-static ssize_t display_show_max_contrast(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct display_device *dsp = dev_get_drvdata(dev);
-       ssize_t rc = -ENXIO;
-
-       mutex_lock(&dsp->lock);
-       if (likely(dsp->driver))
-               rc = sprintf(buf, "%d\n", dsp->driver->max_contrast);
-       mutex_unlock(&dsp->lock);
-       return rc;
-}
-
-static struct device_attribute display_attrs[] = {
-       __ATTR(name, S_IRUGO, display_show_name, NULL),
-       __ATTR(type, S_IRUGO, display_show_type, NULL),
-       __ATTR(contrast, S_IRUGO | S_IWUSR, display_show_contrast, display_store_contrast),
-       __ATTR(max_contrast, S_IRUGO, display_show_max_contrast, NULL),
-};
-
-static int display_suspend(struct device *dev, pm_message_t state)
-{
-       struct display_device *dsp = dev_get_drvdata(dev);
-
-       mutex_lock(&dsp->lock);
-       if (likely(dsp->driver->suspend))
-               dsp->driver->suspend(dsp, state);
-       mutex_unlock(&dsp->lock);
-       return 0;
-};
-
-static int display_resume(struct device *dev)
-{
-       struct display_device *dsp = dev_get_drvdata(dev);
-
-       mutex_lock(&dsp->lock);
-       if (likely(dsp->driver->resume))
-               dsp->driver->resume(dsp);
-       mutex_unlock(&dsp->lock);
-       return 0;
-};
-
-static struct mutex allocated_dsp_lock;
-static DEFINE_IDR(allocated_dsp);
-static struct class *display_class;
-
-struct display_device *display_device_register(struct display_driver *driver,
-                                               struct device *parent, void *devdata)
-{
-       struct display_device *new_dev = NULL;
-       int ret = -EINVAL;
-
-       if (unlikely(!driver))
-               return ERR_PTR(ret);
-
-       mutex_lock(&allocated_dsp_lock);
-       ret = idr_pre_get(&allocated_dsp, GFP_KERNEL);
-       mutex_unlock(&allocated_dsp_lock);
-       if (!ret)
-               return ERR_PTR(ret);
-
-       new_dev = kzalloc(sizeof(struct display_device), GFP_KERNEL);
-       if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) {
-               // Reserve the index for this display
-               mutex_lock(&allocated_dsp_lock);
-               ret = idr_get_new(&allocated_dsp, new_dev, &new_dev->idx);
-               mutex_unlock(&allocated_dsp_lock);
-
-               if (!ret) {
-                       new_dev->dev = device_create(display_class, parent,
-                                                    MKDEV(0, 0), new_dev,
-                                                    "display%d", new_dev->idx);
-                       if (!IS_ERR(new_dev->dev)) {
-                               new_dev->parent = parent;
-                               new_dev->driver = driver;
-                               mutex_init(&new_dev->lock);
-                               return new_dev;
-                       }
-                       mutex_lock(&allocated_dsp_lock);
-                       idr_remove(&allocated_dsp, new_dev->idx);
-                       mutex_unlock(&allocated_dsp_lock);
-                       ret = -EINVAL;
-               }
-       }
-       kfree(new_dev);
-       return ERR_PTR(ret);
-}
-EXPORT_SYMBOL(display_device_register);
-
-void display_device_unregister(struct display_device *ddev)
-{
-       if (!ddev)
-               return;
-       // Free device
-       mutex_lock(&ddev->lock);
-       device_unregister(ddev->dev);
-       mutex_unlock(&ddev->lock);
-       // Mark device index as available
-       mutex_lock(&allocated_dsp_lock);
-       idr_remove(&allocated_dsp, ddev->idx);
-       mutex_unlock(&allocated_dsp_lock);
-       kfree(ddev);
-}
-EXPORT_SYMBOL(display_device_unregister);
-
-static int __init display_class_init(void)
-{
-       display_class = class_create(THIS_MODULE, "display");
-       if (IS_ERR(display_class)) {
-               printk(KERN_ERR "Failed to create display class\n");
-               display_class = NULL;
-               return -EINVAL;
-       }
-       display_class->dev_attrs = display_attrs;
-       display_class->suspend = display_suspend;
-       display_class->resume = display_resume;
-       mutex_init(&allocated_dsp_lock);
-       return 0;
-}
-
-static void __exit display_class_exit(void)
-{
-       class_destroy(display_class);
-}
-
-module_init(display_class_init);
-module_exit(display_class_exit);
-
-MODULE_DESCRIPTION("Display Hardware handling");
-MODULE_AUTHOR("James Simmons <jsimmons@infradead.org>");
-MODULE_LICENSE("GPL");
-
index ad936295d8f439cb61d69d88d9b6ca736c2ba930..ac9141b8535600413b7d1c3cf495f30a5330d600 100644 (file)
@@ -967,6 +967,20 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
            memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
                u32 activate = var->activate;
 
+               /* When using FOURCC mode, make sure the red, green, blue and
+                * transp fields are set to 0.
+                */
+               if ((info->fix.capabilities & FB_CAP_FOURCC) &&
+                   var->grayscale > 1) {
+                       if (var->red.offset     || var->green.offset    ||
+                           var->blue.offset    || var->transp.offset   ||
+                           var->red.length     || var->green.length    ||
+                           var->blue.length    || var->transp.length   ||
+                           var->red.msb_right  || var->green.msb_right ||
+                           var->blue.msb_right || var->transp.msb_right)
+                               return -EINVAL;
+               }
+
                if (!info->fbops->fb_check_var) {
                        *var = info->var;
                        goto done;
index a16beeb5f548637698803ac22171691454f482aa..acf292bfba021a93206de3b028e147138b5ced99 100644 (file)
@@ -36,8 +36,7 @@
 #include <linux/fsl-diu-fb.h>
 #include "edid.h"
 
-#define FSL_AOI_NUM    6       /* 5 AOIs and one dummy AOI */
-                               /* 1 for plane 0, 2 for plane 1&2 each */
+#define NUM_AOIS       5       /* 1 for plane 0, 2 for planes 1 & 2 each */
 
 /* HW cursor parameters */
 #define MAX_CURS               32
 #define INT_PARERR     0x08    /* Display parameters error interrupt */
 #define INT_LS_BF_VS   0x10    /* Lines before vsync. interrupt */
 
-struct diu_addr {
-       void *vaddr;            /* Virtual address */
-       dma_addr_t paddr;       /* Physical address */
-       __u32 offset;
-};
-
 /*
  * List of supported video modes
  *
@@ -330,23 +323,6 @@ static unsigned int d_cache_line_size;
 
 static DEFINE_SPINLOCK(diu_lock);
 
-struct fsl_diu_data {
-       struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1];
-                               /*FSL_AOI_NUM has one dummy AOI */
-       struct device_attribute dev_attr;
-       struct diu_ad *dummy_ad;
-       void *dummy_aoi_virt;
-       unsigned int irq;
-       int fb_enabled;
-       enum fsl_diu_monitor_port monitor_port;
-       struct diu __iomem *diu_reg;
-       spinlock_t reg_lock;
-       struct diu_addr ad;
-       struct diu_addr gamma;
-       struct diu_addr pallete;
-       struct diu_addr cursor;
-};
-
 enum mfb_index {
        PLANE0 = 0,     /* Plane 0, only one AOI that fills the screen */
        PLANE1_AOI0,    /* Plane 1, first AOI */
@@ -370,6 +346,42 @@ struct mfb_info {
        u8 *edid_data;
 };
 
+/**
+ * struct fsl_diu_data - per-DIU data structure
+ * @dma_addr: DMA address of this structure
+ * @fsl_diu_info: fb_info objects, one per AOI
+ * @dev_attr: sysfs structure
+ * @irq: IRQ
+ * @monitor_port: the monitor port this DIU is connected to
+ * @diu_reg: pointer to the DIU hardware registers
+ * @reg_lock: spinlock for register access
+ * @dummy_aoi: video buffer for the 4x4 32-bit dummy AOI
+ * dummy_ad: DIU Area Descriptor for the dummy AOI
+ * @ad[]: Area Descriptors for each real AOI
+ * @gamma: gamma color table
+ * @cursor: hardware cursor data
+ *
+ * This data structure must be allocated with 32-byte alignment, so that the
+ * internal fields can be aligned properly.
+ */
+struct fsl_diu_data {
+       dma_addr_t dma_addr;
+       struct fb_info fsl_diu_info[NUM_AOIS];
+       struct mfb_info mfb[NUM_AOIS];
+       struct device_attribute dev_attr;
+       unsigned int irq;
+       enum fsl_diu_monitor_port monitor_port;
+       struct diu __iomem *diu_reg;
+       spinlock_t reg_lock;
+       u8 dummy_aoi[4 * 4 * 4];
+       struct diu_ad dummy_ad __aligned(8);
+       struct diu_ad ad[NUM_AOIS] __aligned(8);
+       u8 gamma[256 * 3] __aligned(32);
+       u8 cursor[MAX_CURS * MAX_CURS * 2] __aligned(32);
+} __aligned(32);
+
+/* Determine the DMA address of a member of the fsl_diu_data structure */
+#define DMA_ADDR(p, f) ((p)->dma_addr + offsetof(struct fsl_diu_data, f))
 
 static struct mfb_info mfb_template[] = {
        {
@@ -449,37 +461,6 @@ static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s)
        return diu_ops.valid_monitor_port(port);
 }
 
-/**
- * fsl_diu_alloc - allocate memory for the DIU
- * @size: number of bytes to allocate
- * @param: returned physical address of memory
- *
- * This function allocates a physically-contiguous block of memory.
- */
-static void *fsl_diu_alloc(size_t size, phys_addr_t *phys)
-{
-       void *virt;
-
-       virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO);
-       if (virt)
-               *phys = virt_to_phys(virt);
-
-       return virt;
-}
-
-/**
- * fsl_diu_free - release DIU memory
- * @virt: pointer returned by fsl_diu_alloc()
- * @size: number of bytes allocated by fsl_diu_alloc()
- *
- * This function releases memory allocated by fsl_diu_alloc().
- */
-static void fsl_diu_free(void *virt, size_t size)
-{
-       if (virt && size)
-               free_pages_exact(virt, size);
-}
-
 /*
  * Workaround for failed writing desc register of planes.
  * Needed with MPC5121 DIU rev 2.0 silicon.
@@ -495,8 +476,8 @@ static void fsl_diu_enable_panel(struct fb_info *info)
 {
        struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
        struct diu_ad *ad = mfbi->ad;
-       struct fsl_diu_data *machine_data = mfbi->parent;
-       struct diu __iomem *hw = machine_data->diu_reg;
+       struct fsl_diu_data *data = mfbi->parent;
+       struct diu __iomem *hw = data->diu_reg;
 
        switch (mfbi->index) {
        case PLANE0:
@@ -504,7 +485,7 @@ static void fsl_diu_enable_panel(struct fb_info *info)
                        wr_reg_wa(&hw->desc[0], ad->paddr);
                break;
        case PLANE1_AOI0:
-               cmfbi = machine_data->fsl_diu_info[2]->par;
+               cmfbi = &data->mfb[2];
                if (hw->desc[1] != ad->paddr) { /* AOI0 closed */
                        if (cmfbi->count > 0)   /* AOI1 open */
                                ad->next_ad =
@@ -515,7 +496,7 @@ static void fsl_diu_enable_panel(struct fb_info *info)
                }
                break;
        case PLANE2_AOI0:
-               cmfbi = machine_data->fsl_diu_info[4]->par;
+               cmfbi = &data->mfb[4];
                if (hw->desc[2] != ad->paddr) { /* AOI0 closed */
                        if (cmfbi->count > 0)   /* AOI1 open */
                                ad->next_ad =
@@ -526,17 +507,17 @@ static void fsl_diu_enable_panel(struct fb_info *info)
                }
                break;
        case PLANE1_AOI1:
-               pmfbi = machine_data->fsl_diu_info[1]->par;
+               pmfbi = &data->mfb[1];
                ad->next_ad = 0;
-               if (hw->desc[1] == machine_data->dummy_ad->paddr)
+               if (hw->desc[1] == data->dummy_ad.paddr)
                        wr_reg_wa(&hw->desc[1], ad->paddr);
                else                                    /* AOI0 open */
                        pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
                break;
        case PLANE2_AOI1:
-               pmfbi = machine_data->fsl_diu_info[3]->par;
+               pmfbi = &data->mfb[3];
                ad->next_ad = 0;
-               if (hw->desc[2] == machine_data->dummy_ad->paddr)
+               if (hw->desc[2] == data->dummy_ad.paddr)
                        wr_reg_wa(&hw->desc[2], ad->paddr);
                else                            /* AOI0 was open */
                        pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
@@ -548,52 +529,52 @@ static void fsl_diu_disable_panel(struct fb_info *info)
 {
        struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
        struct diu_ad *ad = mfbi->ad;
-       struct fsl_diu_data *machine_data = mfbi->parent;
-       struct diu __iomem *hw = machine_data->diu_reg;
+       struct fsl_diu_data *data = mfbi->parent;
+       struct diu __iomem *hw = data->diu_reg;
 
        switch (mfbi->index) {
        case PLANE0:
-               if (hw->desc[0] != machine_data->dummy_ad->paddr)
-                       wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr);
+               if (hw->desc[0] != data->dummy_ad.paddr)
+                       wr_reg_wa(&hw->desc[0], data->dummy_ad.paddr);
                break;
        case PLANE1_AOI0:
-               cmfbi = machine_data->fsl_diu_info[2]->par;
+               cmfbi = &data->mfb[2];
                if (cmfbi->count > 0)   /* AOI1 is open */
                        wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr);
                                        /* move AOI1 to the first */
                else                    /* AOI1 was closed */
-                       wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
+                       wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr);
                                        /* close AOI 0 */
                break;
        case PLANE2_AOI0:
-               cmfbi = machine_data->fsl_diu_info[4]->par;
+               cmfbi = &data->mfb[4];
                if (cmfbi->count > 0)   /* AOI1 is open */
                        wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr);
                                        /* move AOI1 to the first */
                else                    /* AOI1 was closed */
-                       wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
+                       wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr);
                                        /* close AOI 0 */
                break;
        case PLANE1_AOI1:
-               pmfbi = machine_data->fsl_diu_info[1]->par;
+               pmfbi = &data->mfb[1];
                if (hw->desc[1] != ad->paddr) {
                                /* AOI1 is not the first in the chain */
                        if (pmfbi->count > 0)
                                        /* AOI0 is open, must be the first */
                                pmfbi->ad->next_ad = 0;
                } else                  /* AOI1 is the first in the chain */
-                       wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
+                       wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr);
                                        /* close AOI 1 */
                break;
        case PLANE2_AOI1:
-               pmfbi = machine_data->fsl_diu_info[3]->par;
+               pmfbi = &data->mfb[3];
                if (hw->desc[2] != ad->paddr) {
                                /* AOI1 is not the first in the chain */
                        if (pmfbi->count > 0)
                                /* AOI0 is open, must be the first */
                                pmfbi->ad->next_ad = 0;
                } else          /* AOI1 is the first in the chain */
-                       wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
+                       wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr);
                                /* close AOI 1 */
                break;
        }
@@ -602,39 +583,33 @@ static void fsl_diu_disable_panel(struct fb_info *info)
 static void enable_lcdc(struct fb_info *info)
 {
        struct mfb_info *mfbi = info->par;
-       struct fsl_diu_data *machine_data = mfbi->parent;
-       struct diu __iomem *hw = machine_data->diu_reg;
+       struct fsl_diu_data *data = mfbi->parent;
+       struct diu __iomem *hw = data->diu_reg;
 
-       if (!machine_data->fb_enabled) {
-               out_be32(&hw->diu_mode, MFB_MODE1);
-               machine_data->fb_enabled++;
-       }
+       out_be32(&hw->diu_mode, MFB_MODE1);
 }
 
 static void disable_lcdc(struct fb_info *info)
 {
        struct mfb_info *mfbi = info->par;
-       struct fsl_diu_data *machine_data = mfbi->parent;
-       struct diu __iomem *hw = machine_data->diu_reg;
+       struct fsl_diu_data *data = mfbi->parent;
+       struct diu __iomem *hw = data->diu_reg;
 
-       if (machine_data->fb_enabled) {
-               out_be32(&hw->diu_mode, 0);
-               machine_data->fb_enabled = 0;
-       }
+       out_be32(&hw->diu_mode, 0);
 }
 
 static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
                                struct fb_info *info)
 {
        struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par;
-       struct fsl_diu_data *machine_data = mfbi->parent;
+       struct fsl_diu_data *data = mfbi->parent;
        int available_height, upper_aoi_bottom;
        enum mfb_index index = mfbi->index;
        int lower_aoi_is_open, upper_aoi_is_open;
        __u32 base_plane_width, base_plane_height, upper_aoi_height;
 
-       base_plane_width = machine_data->fsl_diu_info[0]->var.xres;
-       base_plane_height = machine_data->fsl_diu_info[0]->var.yres;
+       base_plane_width = data->fsl_diu_info[0].var.xres;
+       base_plane_height = data->fsl_diu_info[0].var.yres;
 
        if (mfbi->x_aoi_d < 0)
                mfbi->x_aoi_d = 0;
@@ -649,7 +624,7 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
                break;
        case PLANE1_AOI0:
        case PLANE2_AOI0:
-               lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par;
+               lower_aoi_mfbi = data->fsl_diu_info[index+1].par;
                lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0;
                if (var->xres > base_plane_width)
                        var->xres = base_plane_width;
@@ -667,9 +642,8 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
                break;
        case PLANE1_AOI1:
        case PLANE2_AOI1:
-               upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par;
-               upper_aoi_height =
-                               machine_data->fsl_diu_info[index-1]->var.yres;
+               upper_aoi_mfbi = data->fsl_diu_info[index-1].par;
+               upper_aoi_height = data->fsl_diu_info[index-1].var.yres;
                upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height;
                upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0;
                if (var->xres > base_plane_width)
@@ -809,33 +783,33 @@ static void update_lcdc(struct fb_info *info)
 {
        struct fb_var_screeninfo *var = &info->var;
        struct mfb_info *mfbi = info->par;
-       struct fsl_diu_data *machine_data = mfbi->parent;
+       struct fsl_diu_data *data = mfbi->parent;
        struct diu __iomem *hw;
        int i, j;
-       char __iomem *cursor_base, *gamma_table_base;
+       u8 *gamma_table_base;
 
        u32 temp;
 
-       hw = machine_data->diu_reg;
+       hw = data->diu_reg;
+
+       diu_ops.set_monitor_port(data->monitor_port);
+       gamma_table_base = data->gamma;
 
-       diu_ops.set_monitor_port(machine_data->monitor_port);
-       gamma_table_base = machine_data->gamma.vaddr;
-       cursor_base = machine_data->cursor.vaddr;
        /* Prep for DIU init  - gamma table, cursor table */
 
        for (i = 0; i <= 2; i++)
                for (j = 0; j <= 255; j++)
                        *gamma_table_base++ = j;
 
-       diu_ops.set_gamma_table(machine_data->monitor_port,
-                               machine_data->gamma.vaddr);
+       if (diu_ops.set_gamma_table)
+               diu_ops.set_gamma_table(data->monitor_port, data->gamma);
 
        disable_lcdc(info);
 
        /* Program DIU registers */
 
-       out_be32(&hw->gamma, machine_data->gamma.paddr);
-       out_be32(&hw->cursor, machine_data->cursor.paddr);
+       out_be32(&hw->gamma, DMA_ADDR(data, gamma));
+       out_be32(&hw->cursor, DMA_ADDR(data, cursor));
 
        out_be32(&hw->bgnd, 0x007F7F7F);        /* BGND */
        out_be32(&hw->bgnd_wb, 0);              /* BGND_WB */
@@ -870,16 +844,17 @@ static void update_lcdc(struct fb_info *info)
 
 static int map_video_memory(struct fb_info *info)
 {
-       phys_addr_t phys;
        u32 smem_len = info->fix.line_length * info->var.yres_virtual;
+       void *p;
 
-       info->screen_base = fsl_diu_alloc(smem_len, &phys);
-       if (info->screen_base == NULL) {
+       p = alloc_pages_exact(smem_len, GFP_DMA | __GFP_ZERO);
+       if (!p) {
                dev_err(info->dev, "unable to allocate fb memory\n");
                return -ENOMEM;
        }
        mutex_lock(&info->mm_lock);
-       info->fix.smem_start = (unsigned long) phys;
+       info->screen_base = p;
+       info->fix.smem_start = virt_to_phys(info->screen_base);
        info->fix.smem_len = smem_len;
        mutex_unlock(&info->mm_lock);
        info->screen_size = info->fix.smem_len;
@@ -889,12 +864,17 @@ static int map_video_memory(struct fb_info *info)
 
 static void unmap_video_memory(struct fb_info *info)
 {
-       fsl_diu_free(info->screen_base, info->fix.smem_len);
+       void *p = info->screen_base;
+       size_t l = info->fix.smem_len;
+
        mutex_lock(&info->mm_lock);
        info->screen_base = NULL;
        info->fix.smem_start = 0;
        info->fix.smem_len = 0;
        mutex_unlock(&info->mm_lock);
+
+       if (p)
+               free_pages_exact(p, l);
 }
 
 /*
@@ -913,6 +893,59 @@ static int fsl_diu_set_aoi(struct fb_info *info)
        return 0;
 }
 
+/**
+ * fsl_diu_get_pixel_format: return the pixel format for a given color depth
+ *
+ * The pixel format is a 32-bit value that determine which bits in each
+ * pixel are to be used for each color.  This is the default function used
+ * if the platform does not define its own version.
+ */
+static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel)
+{
+#define PF_BYTE_F              0x10000000
+#define PF_ALPHA_C_MASK                0x0E000000
+#define PF_ALPHA_C_SHIFT       25
+#define PF_BLUE_C_MASK         0x01800000
+#define PF_BLUE_C_SHIFT                23
+#define PF_GREEN_C_MASK                0x00600000
+#define PF_GREEN_C_SHIFT       21
+#define PF_RED_C_MASK          0x00180000
+#define PF_RED_C_SHIFT         19
+#define PF_PALETTE             0x00040000
+#define PF_PIXEL_S_MASK                0x00030000
+#define PF_PIXEL_S_SHIFT       16
+#define PF_COMP_3_MASK         0x0000F000
+#define PF_COMP_3_SHIFT                12
+#define PF_COMP_2_MASK         0x00000F00
+#define PF_COMP_2_SHIFT                8
+#define PF_COMP_1_MASK         0x000000F0
+#define PF_COMP_1_SHIFT                4
+#define PF_COMP_0_MASK         0x0000000F
+#define PF_COMP_0_SHIFT                0
+
+#define MAKE_PF(alpha, red, blue, green, size, c0, c1, c2, c3) \
+       cpu_to_le32(PF_BYTE_F | (alpha << PF_ALPHA_C_SHIFT) | \
+       (blue << PF_BLUE_C_SHIFT) | (green << PF_GREEN_C_SHIFT) | \
+       (red << PF_RED_C_SHIFT) | (c3 << PF_COMP_3_SHIFT) | \
+       (c2 << PF_COMP_2_SHIFT) | (c1 << PF_COMP_1_SHIFT) | \
+       (c0 << PF_COMP_0_SHIFT) | (size << PF_PIXEL_S_SHIFT))
+
+       switch (bits_per_pixel) {
+       case 32:
+               /* 0x88883316 */
+               return MAKE_PF(3, 2, 0, 1, 3, 8, 8, 8, 8);
+       case 24:
+               /* 0x88082219 */
+               return MAKE_PF(4, 0, 1, 2, 2, 0, 8, 8, 8);
+       case 16:
+               /* 0x65053118 */
+               return MAKE_PF(4, 2, 1, 0, 1, 5, 6, 5, 0);
+       default:
+               pr_err("fsl-diu: unsupported color depth %u\n", bits_per_pixel);
+               return 0;
+       }
+}
+
 /*
  * Using the fb_var_screeninfo in fb_info we set the resolution of this
  * particular framebuffer. This function alters the fb_fix_screeninfo stored
@@ -926,11 +959,11 @@ static int fsl_diu_set_par(struct fb_info *info)
        unsigned long len;
        struct fb_var_screeninfo *var = &info->var;
        struct mfb_info *mfbi = info->par;
-       struct fsl_diu_data *machine_data = mfbi->parent;
+       struct fsl_diu_data *data = mfbi->parent;
        struct diu_ad *ad = mfbi->ad;
        struct diu __iomem *hw;
 
-       hw = machine_data->diu_reg;
+       hw = data->diu_reg;
 
        set_fix(info);
        mfbi->cursor_reset = 1;
@@ -948,8 +981,12 @@ static int fsl_diu_set_par(struct fb_info *info)
                }
        }
 
-       ad->pix_fmt = diu_ops.get_pixel_format(machine_data->monitor_port,
-                                              var->bits_per_pixel);
+       if (diu_ops.get_pixel_format)
+               ad->pix_fmt = diu_ops.get_pixel_format(data->monitor_port,
+                                                      var->bits_per_pixel);
+       else
+               ad->pix_fmt = fsl_diu_get_pixel_format(var->bits_per_pixel);
+
        ad->addr    = cpu_to_le32(info->fix.smem_start);
        ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) |
                                var->xres_virtual) | mfbi->g_alpha;
@@ -1208,21 +1245,6 @@ static struct fb_ops fsl_diu_ops = {
        .fb_release = fsl_diu_release,
 };
 
-static int init_fbinfo(struct fb_info *info)
-{
-       struct mfb_info *mfbi = info->par;
-
-       info->device = NULL;
-       info->var.activate = FB_ACTIVATE_NOW;
-       info->fbops = &fsl_diu_ops;
-       info->flags = FBINFO_FLAG_DEFAULT;
-       info->pseudo_palette = &mfbi->pseudo_palette;
-
-       /* Allocate colormap */
-       fb_alloc_cmap(&info->cmap, 16, 0);
-       return 0;
-}
-
 static int __devinit install_fb(struct fb_info *info)
 {
        int rc;
@@ -1232,8 +1254,15 @@ static int __devinit install_fb(struct fb_info *info)
        unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db);
        int has_default_mode = 1;
 
-       if (init_fbinfo(info))
-               return -EINVAL;
+       info->var.activate = FB_ACTIVATE_NOW;
+       info->fbops = &fsl_diu_ops;
+       info->flags = FBINFO_DEFAULT | FBINFO_VIRTFB | FBINFO_PARTIAL_PAN_OK |
+               FBINFO_READS_FAST;
+       info->pseudo_palette = mfbi->pseudo_palette;
+
+       rc = fb_alloc_cmap(&info->cmap, 16, 0);
+       if (rc)
+               return rc;
 
        if (mfbi->index == PLANE0) {
                if (mfbi->edid_data) {
@@ -1359,16 +1388,16 @@ static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
        return IRQ_NONE;
 }
 
-static int request_irq_local(struct fsl_diu_data *machine_data)
+static int request_irq_local(struct fsl_diu_data *data)
 {
-       struct diu __iomem *hw = machine_data->diu_reg;
+       struct diu __iomem *hw = data->diu_reg;
        u32 ints;
        int ret;
 
        /* Read to clear the status */
        in_be32(&hw->int_status);
 
-       ret = request_irq(machine_data->irq, fsl_diu_isr, 0, "fsl-diu-fb", hw);
+       ret = request_irq(data->irq, fsl_diu_isr, 0, "fsl-diu-fb", hw);
        if (!ret) {
                ints = INT_PARERR | INT_LS_BF_VS;
 #if !defined(CONFIG_NOT_COHERENT_CACHE)
@@ -1383,14 +1412,14 @@ static int request_irq_local(struct fsl_diu_data *machine_data)
        return ret;
 }
 
-static void free_irq_local(struct fsl_diu_data *machine_data)
+static void free_irq_local(struct fsl_diu_data *data)
 {
-       struct diu __iomem *hw = machine_data->diu_reg;
+       struct diu __iomem *hw = data->diu_reg;
 
        /* Disable all LCDC interrupt */
        out_be32(&hw->int_mask, 0x1f);
 
-       free_irq(machine_data->irq, NULL);
+       free_irq(data->irq, NULL);
 }
 
 #ifdef CONFIG_PM
@@ -1400,20 +1429,20 @@ static void free_irq_local(struct fsl_diu_data *machine_data)
  */
 static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
 {
-       struct fsl_diu_data *machine_data;
+       struct fsl_diu_data *data;
 
-       machine_data = dev_get_drvdata(&ofdev->dev);
-       disable_lcdc(machine_data->fsl_diu_info[0]);
+       data = dev_get_drvdata(&ofdev->dev);
+       disable_lcdc(data->fsl_diu_info[0]);
 
        return 0;
 }
 
 static int fsl_diu_resume(struct platform_device *ofdev)
 {
-       struct fsl_diu_data *machine_data;
+       struct fsl_diu_data *data;
 
-       machine_data = dev_get_drvdata(&ofdev->dev);
-       enable_lcdc(machine_data->fsl_diu_info[0]);
+       data = dev_get_drvdata(&ofdev->dev);
+       enable_lcdc(data->fsl_diu_info[0]);
 
        return 0;
 }
@@ -1423,56 +1452,24 @@ static int fsl_diu_resume(struct platform_device *ofdev)
 #define fsl_diu_resume NULL
 #endif                         /* CONFIG_PM */
 
-/* Align to 64-bit(8-byte), 32-byte, etc. */
-static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size,
-                       u32 bytes_align)
-{
-       u32 offset;
-       dma_addr_t mask;
-
-       buf->vaddr =
-               dma_alloc_coherent(dev, size + bytes_align, &buf->paddr,
-                                  GFP_DMA | __GFP_ZERO);
-       if (!buf->vaddr)
-               return -ENOMEM;
-
-       mask = bytes_align - 1;
-       offset = buf->paddr & mask;
-       if (offset) {
-               buf->offset = bytes_align - offset;
-               buf->paddr = buf->paddr + offset;
-       } else
-               buf->offset = 0;
-
-       return 0;
-}
-
-static void free_buf(struct device *dev, struct diu_addr *buf, u32 size,
-                    u32 bytes_align)
-{
-       dma_free_coherent(dev, size + bytes_align, buf->vaddr,
-                         buf->paddr - buf->offset);
-}
-
 static ssize_t store_monitor(struct device *device,
        struct device_attribute *attr, const char *buf, size_t count)
 {
        enum fsl_diu_monitor_port old_monitor_port;
-       struct fsl_diu_data *machine_data =
+       struct fsl_diu_data *data =
                container_of(attr, struct fsl_diu_data, dev_attr);
 
-       old_monitor_port = machine_data->monitor_port;
-       machine_data->monitor_port = fsl_diu_name_to_port(buf);
+       old_monitor_port = data->monitor_port;
+       data->monitor_port = fsl_diu_name_to_port(buf);
 
-       if (old_monitor_port != machine_data->monitor_port) {
+       if (old_monitor_port != data->monitor_port) {
                /* All AOIs need adjust pixel format
                 * fsl_diu_set_par only change the pixsel format here
                 * unlikely to fail. */
-               fsl_diu_set_par(machine_data->fsl_diu_info[0]);
-               fsl_diu_set_par(machine_data->fsl_diu_info[1]);
-               fsl_diu_set_par(machine_data->fsl_diu_info[2]);
-               fsl_diu_set_par(machine_data->fsl_diu_info[3]);
-               fsl_diu_set_par(machine_data->fsl_diu_info[4]);
+               unsigned int i;
+
+               for (i=0; i < NUM_AOIS; i++)
+                       fsl_diu_set_par(&data->fsl_diu_info[i]);
        }
        return count;
 }
@@ -1480,10 +1477,10 @@ static ssize_t store_monitor(struct device *device,
 static ssize_t show_monitor(struct device *device,
        struct device_attribute *attr, char *buf)
 {
-       struct fsl_diu_data *machine_data =
+       struct fsl_diu_data *data =
                container_of(attr, struct fsl_diu_data, dev_attr);
 
-       switch (machine_data->monitor_port) {
+       switch (data->monitor_port) {
        case FSL_DIU_PORT_DVI:
                return sprintf(buf, "DVI\n");
        case FSL_DIU_PORT_LVDS:
@@ -1499,28 +1496,52 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct mfb_info *mfbi;
-       phys_addr_t dummy_ad_addr = 0;
-       int ret, i, error = 0;
-       struct fsl_diu_data *machine_data;
+       struct fsl_diu_data *data;
        int diu_mode;
+       dma_addr_t dma_addr; /* DMA addr of fsl_diu_data struct */
+       unsigned int i;
+       int ret;
 
-       machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
-       if (!machine_data)
+       data = dma_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
+                                 &dma_addr, GFP_DMA | __GFP_ZERO);
+       if (!data)
                return -ENOMEM;
+       data->dma_addr = dma_addr;
+
+       /*
+        * dma_alloc_coherent() uses a page allocator, so the address is
+        * always page-aligned.  We need the memory to be 32-byte aligned,
+        * so that's good.  However, if one day the allocator changes, we
+        * need to catch that.  It's not worth the effort to handle unaligned
+        * alloctions now because it's highly unlikely to ever be a problem.
+        */
+       if ((unsigned long)data & 31) {
+               dev_err(&pdev->dev, "misaligned allocation");
+               ret = -ENOMEM;
+               goto error;
+       }
 
-       spin_lock_init(&machine_data->reg_lock);
+       spin_lock_init(&data->reg_lock);
 
-       for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
-               machine_data->fsl_diu_info[i] =
-                       framebuffer_alloc(sizeof(struct mfb_info), &pdev->dev);
-               if (!machine_data->fsl_diu_info[i]) {
-                       dev_err(&pdev->dev, "cannot allocate memory\n");
-                       ret = -ENOMEM;
-                       goto error2;
-               }
-               mfbi = machine_data->fsl_diu_info[i]->par;
+       for (i = 0; i < NUM_AOIS; i++) {
+               struct fb_info *info = &data->fsl_diu_info[i];
+
+               info->device = &pdev->dev;
+               info->par = &data->mfb[i];
+
+               /*
+                * We store the physical address of the AD in the reserved
+                * 'paddr' field of the AD itself.
+                */
+               data->ad[i].paddr = DMA_ADDR(data, ad[i]);
+
+               info->fix.smem_start = 0;
+
+               /* Initialize the AOI data structure */
+               mfbi = info->par;
                memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
-               mfbi->parent = machine_data;
+               mfbi->parent = data;
+               mfbi->ad = &data->ad[i];
 
                if (mfbi->index == PLANE0) {
                        const u8 *prop;
@@ -1534,158 +1555,102 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
                }
        }
 
-       machine_data->diu_reg = of_iomap(np, 0);
-       if (!machine_data->diu_reg) {
+       data->diu_reg = of_iomap(np, 0);
+       if (!data->diu_reg) {
                dev_err(&pdev->dev, "cannot map DIU registers\n");
                ret = -EFAULT;
-               goto error2;
+               goto error;
        }
 
-       diu_mode = in_be32(&machine_data->diu_reg->diu_mode);
+       diu_mode = in_be32(&data->diu_reg->diu_mode);
        if (diu_mode == MFB_MODE0)
-               out_be32(&machine_data->diu_reg->diu_mode, 0); /* disable DIU */
+               out_be32(&data->diu_reg->diu_mode, 0); /* disable DIU */
 
        /* Get the IRQ of the DIU */
-       machine_data->irq = irq_of_parse_and_map(np, 0);
+       data->irq = irq_of_parse_and_map(np, 0);
 
-       if (!machine_data->irq) {
+       if (!data->irq) {
                dev_err(&pdev->dev, "could not get DIU IRQ\n");
                ret = -EINVAL;
                goto error;
        }
-       machine_data->monitor_port = monitor_port;
-
-       /* Area descriptor memory pool aligns to 64-bit boundary */
-       if (allocate_buf(&pdev->dev, &machine_data->ad,
-                        sizeof(struct diu_ad) * FSL_AOI_NUM, 8))
-               return -ENOMEM;
-
-       /* Get memory for Gamma Table  - 32-byte aligned memory */
-       if (allocate_buf(&pdev->dev, &machine_data->gamma, 768, 32)) {
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       /* For performance, cursor bitmap buffer aligns to 32-byte boundary */
-       if (allocate_buf(&pdev->dev, &machine_data->cursor,
-                        MAX_CURS * MAX_CURS * 2, 32)) {
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       i = ARRAY_SIZE(machine_data->fsl_diu_info);
-       machine_data->dummy_ad = (struct diu_ad *)((u32)machine_data->ad.vaddr +
-                       machine_data->ad.offset) + i;
-       machine_data->dummy_ad->paddr = machine_data->ad.paddr +
-                       i * sizeof(struct diu_ad);
-       machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr);
-       if (!machine_data->dummy_aoi_virt) {
-               ret = -ENOMEM;
-               goto error;
-       }
-       machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr);
-       machine_data->dummy_ad->pix_fmt = 0x88882317;
-       machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
-       machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) |  2);
-       machine_data->dummy_ad->offset_xyi = 0;
-       machine_data->dummy_ad->offset_xyd = 0;
-       machine_data->dummy_ad->next_ad = 0;
+       data->monitor_port = monitor_port;
+
+       /* Initialize the dummy Area Descriptor */
+       data->dummy_ad.addr = cpu_to_le32(DMA_ADDR(data, dummy_aoi));
+       data->dummy_ad.pix_fmt = 0x88882317;
+       data->dummy_ad.src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
+       data->dummy_ad.aoi_size = cpu_to_le32((4 << 16) |  2);
+       data->dummy_ad.offset_xyi = 0;
+       data->dummy_ad.offset_xyd = 0;
+       data->dummy_ad.next_ad = 0;
+       data->dummy_ad.paddr = DMA_ADDR(data, dummy_ad);
 
        /*
         * Let DIU display splash screen if it was pre-initialized
         * by the bootloader, set dummy area descriptor otherwise.
         */
        if (diu_mode == MFB_MODE0)
-               out_be32(&machine_data->diu_reg->desc[0],
-                        machine_data->dummy_ad->paddr);
-
-       out_be32(&machine_data->diu_reg->desc[1], machine_data->dummy_ad->paddr);
-       out_be32(&machine_data->diu_reg->desc[2], machine_data->dummy_ad->paddr);
-
-       for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
-               machine_data->fsl_diu_info[i]->fix.smem_start = 0;
-               mfbi = machine_data->fsl_diu_info[i]->par;
-               mfbi->ad = (struct diu_ad *)((u32)machine_data->ad.vaddr
-                                       + machine_data->ad.offset) + i;
-               mfbi->ad->paddr =
-                       machine_data->ad.paddr + i * sizeof(struct diu_ad);
-               ret = install_fb(machine_data->fsl_diu_info[i]);
+               out_be32(&data->diu_reg->desc[0], data->dummy_ad.paddr);
+
+       out_be32(&data->diu_reg->desc[1], data->dummy_ad.paddr);
+       out_be32(&data->diu_reg->desc[2], data->dummy_ad.paddr);
+
+       for (i = 0; i < NUM_AOIS; i++) {
+               ret = install_fb(&data->fsl_diu_info[i]);
                if (ret) {
                        dev_err(&pdev->dev, "could not register fb %d\n", i);
                        goto error;
                }
        }
 
-       if (request_irq_local(machine_data)) {
+       if (request_irq_local(data)) {
                dev_err(&pdev->dev, "could not claim irq\n");
                goto error;
        }
 
-       sysfs_attr_init(&machine_data->dev_attr.attr);
-       machine_data->dev_attr.attr.name = "monitor";
-       machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
-       machine_data->dev_attr.show = show_monitor;
-       machine_data->dev_attr.store = store_monitor;
-       error = device_create_file(machine_data->fsl_diu_info[0]->dev,
-                                 &machine_data->dev_attr);
-       if (error) {
+       sysfs_attr_init(&data->dev_attr.attr);
+       data->dev_attr.attr.name = "monitor";
+       data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
+       data->dev_attr.show = show_monitor;
+       data->dev_attr.store = store_monitor;
+       ret = device_create_file(&pdev->dev, &data->dev_attr);
+       if (ret) {
                dev_err(&pdev->dev, "could not create sysfs file %s\n",
-                       machine_data->dev_attr.attr.name);
+                       data->dev_attr.attr.name);
        }
 
-       dev_set_drvdata(&pdev->dev, machine_data);
+       dev_set_drvdata(&pdev->dev, data);
        return 0;
 
 error:
-       for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
-               uninstall_fb(machine_data->fsl_diu_info[i]);
-
-       if (machine_data->ad.vaddr)
-               free_buf(&pdev->dev, &machine_data->ad,
-                        sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
-       if (machine_data->gamma.vaddr)
-               free_buf(&pdev->dev, &machine_data->gamma, 768, 32);
-       if (machine_data->cursor.vaddr)
-               free_buf(&pdev->dev, &machine_data->cursor,
-                        MAX_CURS * MAX_CURS * 2, 32);
-       if (machine_data->dummy_aoi_virt)
-               fsl_diu_free(machine_data->dummy_aoi_virt, 64);
-       iounmap(machine_data->diu_reg);
-
-error2:
-       for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
-               if (machine_data->fsl_diu_info[i])
-                       framebuffer_release(machine_data->fsl_diu_info[i]);
-       kfree(machine_data);
+       for (i = 0; i < NUM_AOIS; i++)
+               uninstall_fb(&data->fsl_diu_info[i]);
+
+       iounmap(data->diu_reg);
+
+       dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data,
+                         data->dma_addr);
 
        return ret;
 }
 
 static int fsl_diu_remove(struct platform_device *pdev)
 {
-       struct fsl_diu_data *machine_data;
+       struct fsl_diu_data *data;
        int i;
 
-       machine_data = dev_get_drvdata(&pdev->dev);
-       disable_lcdc(machine_data->fsl_diu_info[0]);
-       free_irq_local(machine_data);
-       for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
-               uninstall_fb(machine_data->fsl_diu_info[i]);
-       if (machine_data->ad.vaddr)
-               free_buf(&pdev->dev, &machine_data->ad,
-                        sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
-       if (machine_data->gamma.vaddr)
-               free_buf(&pdev->dev, &machine_data->gamma, 768, 32);
-       if (machine_data->cursor.vaddr)
-               free_buf(&pdev->dev, &machine_data->cursor,
-                        MAX_CURS * MAX_CURS * 2, 32);
-       if (machine_data->dummy_aoi_virt)
-               fsl_diu_free(machine_data->dummy_aoi_virt, 64);
-       iounmap(machine_data->diu_reg);
-       for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
-               if (machine_data->fsl_diu_info[i])
-                       framebuffer_release(machine_data->fsl_diu_info[i]);
-       kfree(machine_data);
+       data = dev_get_drvdata(&pdev->dev);
+       disable_lcdc(&data->fsl_diu_info[0]);
+       free_irq_local(data);
+
+       for (i = 0; i < NUM_AOIS; i++)
+               uninstall_fb(&data->fsl_diu_info[i]);
+
+       iounmap(data->diu_reg);
+
+       dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data,
+                         data->dma_addr);
 
        return 0;
 }
index f37e02538203e20f2d735858e392ad0ebd2114d8..da066c210923479ea530b90de708f17eacfcd9bc 100644 (file)
@@ -70,7 +70,7 @@ static const struct fb_videomode grvga_modedb[] = {
     }
  };
 
-static struct fb_fix_screeninfo grvga_fix __initdata = {
+static struct fb_fix_screeninfo grvga_fix __devinitdata = {
        .id =           "AG SVGACTRL",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_PSEUDOCOLOR,
@@ -267,7 +267,7 @@ static struct fb_ops grvga_ops = {
        .fb_imageblit   = cfb_imageblit
 };
 
-static int __init grvga_parse_custom(char *options,
+static int __devinit grvga_parse_custom(char *options,
                                     struct fb_var_screeninfo *screendata)
 {
        char *this_opt;
index 4394389caf68d8e8ffa40c5d19e2eec3970d76eb..c645f928265001dc5bb5485a25a1a2012aafc2d4 100644 (file)
@@ -133,7 +133,7 @@ static struct fb_fix_screeninfo hga_fix __devinitdata = {
 /* Don't assume that tty1 will be the initial current console. */
 static int release_io_port = 0;
 static int release_io_ports = 0;
-static int nologo = 0;
+static bool nologo = 0;
 
 /* -------------------------------------------------------------------------
  *
index 318f6fb895b289d2c2b5b884dd7deebc8e1616cf..b83f36190cae41ff73609cc94695d42b34688d56 100644 (file)
@@ -135,8 +135,8 @@ static struct pci_driver i810fb_driver = {
 static char *mode_option __devinitdata = NULL;
 static int vram       __devinitdata = 4;
 static int bpp        __devinitdata = 8;
-static int mtrr       __devinitdata;
-static int accel      __devinitdata;
+static bool mtrr      __devinitdata;
+static bool accel     __devinitdata;
 static int hsync1     __devinitdata;
 static int hsync2     __devinitdata;
 static int vsync1     __devinitdata;
@@ -144,10 +144,10 @@ static int vsync2     __devinitdata;
 static int xres       __devinitdata;
 static int yres;
 static int vyres      __devinitdata;
-static int sync       __devinitdata;
-static int extvga     __devinitdata;
-static int dcolor     __devinitdata;
-static int ddc3       __devinitdata = 2;
+static bool sync      __devinitdata;
+static bool extvga    __devinitdata;
+static bool dcolor    __devinitdata;
+static bool ddc3      __devinitdata;
 
 /*------------------------------------------------------------*/
 
@@ -1776,7 +1776,7 @@ static void __devinit i810_init_defaults(struct i810fb_par *par,
        if (sync) 
                par->dev_flags |= ALWAYS_SYNC;
 
-       par->ddc_num = ddc3;
+       par->ddc_num = (ddc3 ? 3 : 2);
 
        if (bpp < 8)
                bpp = 8;
@@ -1999,7 +1999,7 @@ static int __devinit i810fb_setup(char *options)
                else if (!strncmp(this_opt, "dcolor", 6))
                        dcolor = 1;
                else if (!strncmp(this_opt, "ddc3", 4))
-                       ddc3 = 3;
+                       ddc3 = true;
                else
                        mode_option = this_opt;
        }
index 5ba3999910509f09fc1e0775518d5c23c520ec18..c6afa33a45322b4f70c57e2672535ab8cabef715 100644 (file)
@@ -230,15 +230,15 @@ MODULE_DESCRIPTION("Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DEVICE_TABLE(pci, intelfb_pci_table);
 
-static int accel        = 1;
+static bool accel       = 1;
 static int vram         = 4;
-static int hwcursor     = 0;
-static int mtrr         = 1;
-static int fixed        = 0;
-static int noinit       = 0;
-static int noregister   = 0;
-static int probeonly    = 0;
-static int idonly       = 0;
+static bool hwcursor    = 0;
+static bool mtrr        = 1;
+static bool fixed       = 0;
+static bool noinit      = 0;
+static bool noregister  = 0;
+static bool probeonly   = 0;
+static bool idonly      = 0;
 static int bailearly    = 0;
 static int voffset     = 48;
 static char *mode       = NULL;
@@ -263,7 +263,7 @@ module_param(probeonly, bool, 0);
 MODULE_PARM_DESC(probeonly, "Do a minimal probe (debug)");
 module_param(idonly, bool, 0);
 MODULE_PARM_DESC(idonly, "Just identify without doing anything else (debug)");
-module_param(bailearly, bool, 0);
+module_param(bailearly, int, 0);
 MODULE_PARM_DESC(bailearly, "Bail out early, depending on value (debug)");
 module_param(mode, charp, S_IRUGO);
 MODULE_PARM_DESC(mode,
index ea7a8ccc830c8659f23b13dc98db761b89a6c0da..080c35b34bbb9d68cd6e6d2eb5456dbf85a1ca88 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/bootinfo.h>
 #endif
 
-static int nologo;
+static bool nologo;
 module_param(nologo, bool, 0);
 MODULE_PARM_DESC(nologo, "Disables startup logo");
 
index 44bf8d4a216b41afb4d15244b1370c8848285700..401a56e250bd40e3ba484c403ff1975357e202e9 100644 (file)
@@ -147,7 +147,6 @@ static struct fb_var_screeninfo vesafb_defined = {
        39721L,48L,16L,33L,10L,
        96L,2L,~0,      /* No sync info */
        FB_VMODE_NONINTERLACED,
-       0, {0,0,0,0,0}
 };
 
 
index d7112c39614b0006736c8b9ea76f91e07a748683..02796a4317a94c95e3d2ae10649f69e36490c7fd 100644 (file)
@@ -593,7 +593,6 @@ static struct fb_var_screeninfo matroxfb_dh_defined = {
                39721L,48L,16L,33L,10L,
                96L,2,0,        /* no sync info */
                FB_VMODE_NONINTERLACED,
-               0, {0,0,0,0,0}
 };
 
 static int matroxfb_dh_regit(const struct matrox_fb_info *minfo,
index 6ce34160da7866484a9fb78f6e846ac2e3ea6d66..55bf6196b7a0e1185c6237df1f3b4baae5f7cb97 100644 (file)
@@ -1053,18 +1053,7 @@ static struct platform_driver mbxfb_driver = {
        },
 };
 
-int __devinit mbxfb_init(void)
-{
-       return platform_driver_register(&mbxfb_driver);
-}
-
-static void __devexit mbxfb_exit(void)
-{
-       platform_driver_unregister(&mbxfb_driver);
-}
-
-module_init(mbxfb_init);
-module_exit(mbxfb_exit);
+module_platform_driver(mbxfb_driver);
 
 MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device");
 MODULE_AUTHOR("Mike Rapoport, Compulab");
index e3406ab313059fcde53187f7bd9ea3f6352aff11..727a5149d81806be71c7b902be7d4a20b3309a2e 100644 (file)
@@ -245,6 +245,7 @@ struct mx3fb_data {
 
        uint32_t                h_start_width;
        uint32_t                v_start_width;
+       enum disp_data_mapping  disp_data_fmt;
 };
 
 struct dma_chan_request {
@@ -287,11 +288,14 @@ static void mx3fb_write_reg(struct mx3fb_data *mx3fb, u32 value, unsigned long r
        __raw_writel(value, mx3fb->reg_base + reg);
 }
 
-static const uint32_t di_mappings[] = {
-       0x1600AAAA, 0x00E05555, 0x00070000, 3,  /* RGB888 */
-       0x0005000F, 0x000B000F, 0x0011000F, 1,  /* RGB666 */
-       0x0011000F, 0x000B000F, 0x0005000F, 1,  /* BGR666 */
-       0x0004003F, 0x000A000F, 0x000F003F, 1   /* RGB565 */
+struct di_mapping {
+       uint32_t b0, b1, b2;
+};
+
+static const struct di_mapping di_mappings[] = {
+       [IPU_DISP_DATA_MAPPING_RGB666] = { 0x0005000f, 0x000b000f, 0x0011000f },
+       [IPU_DISP_DATA_MAPPING_RGB565] = { 0x0004003f, 0x000a000f, 0x000f003f },
+       [IPU_DISP_DATA_MAPPING_RGB888] = { 0x00070000, 0x000f0000, 0x00170000 },
 };
 
 static void sdc_fb_init(struct mx3fb_info *fbi)
@@ -334,7 +338,7 @@ static void sdc_enable_channel(struct mx3fb_info *mx3_fbi)
        /* This enables the channel */
        if (mx3_fbi->cookie < 0) {
                mx3_fbi->txd = dma_chan->device->device_prep_slave_sg(dma_chan,
-                     &mx3_fbi->sg[0], 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT);
+                     &mx3_fbi->sg[0], 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
                if (!mx3_fbi->txd) {
                        dev_err(mx3fb->dev, "Cannot allocate descriptor on %d\n",
                                dma_chan->chan_id);
@@ -425,7 +429,6 @@ static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel
  * @pixel_clk:         desired pixel clock frequency in Hz.
  * @width:             width of panel in pixels.
  * @height:            height of panel in pixels.
- * @pixel_fmt:         pixel format of buffer as FOURCC ASCII code.
  * @h_start_width:     number of pixel clocks between the HSYNC signal pulse
  *                     and the start of valid data.
  * @h_sync_width:      width of the HSYNC signal in units of pixel clocks.
@@ -442,7 +445,6 @@ static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel
 static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
                          uint32_t pixel_clk,
                          uint16_t width, uint16_t height,
-                         enum pixel_fmt pixel_fmt,
                          uint16_t h_start_width, uint16_t h_sync_width,
                          uint16_t h_end_width, uint16_t v_start_width,
                          uint16_t v_sync_width, uint16_t v_end_width,
@@ -453,6 +455,7 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
        uint32_t old_conf;
        uint32_t div;
        struct clk *ipu_clk;
+       const struct di_mapping *map;
 
        dev_dbg(mx3fb->dev, "panel size = %d x %d", width, height);
 
@@ -540,36 +543,10 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
                sig.Vsync_pol << DI_D3_VSYNC_POL_SHIFT;
        mx3fb_write_reg(mx3fb, old_conf, DI_DISP_SIG_POL);
 
-       switch (pixel_fmt) {
-       case IPU_PIX_FMT_RGB24:
-               mx3fb_write_reg(mx3fb, di_mappings[0], DI_DISP3_B0_MAP);
-               mx3fb_write_reg(mx3fb, di_mappings[1], DI_DISP3_B1_MAP);
-               mx3fb_write_reg(mx3fb, di_mappings[2], DI_DISP3_B2_MAP);
-               mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
-                            ((di_mappings[3] - 1) << 12), DI_DISP_ACC_CC);
-               break;
-       case IPU_PIX_FMT_RGB666:
-               mx3fb_write_reg(mx3fb, di_mappings[4], DI_DISP3_B0_MAP);
-               mx3fb_write_reg(mx3fb, di_mappings[5], DI_DISP3_B1_MAP);
-               mx3fb_write_reg(mx3fb, di_mappings[6], DI_DISP3_B2_MAP);
-               mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
-                            ((di_mappings[7] - 1) << 12), DI_DISP_ACC_CC);
-               break;
-       case IPU_PIX_FMT_BGR666:
-               mx3fb_write_reg(mx3fb, di_mappings[8], DI_DISP3_B0_MAP);
-               mx3fb_write_reg(mx3fb, di_mappings[9], DI_DISP3_B1_MAP);
-               mx3fb_write_reg(mx3fb, di_mappings[10], DI_DISP3_B2_MAP);
-               mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
-                            ((di_mappings[11] - 1) << 12), DI_DISP_ACC_CC);
-               break;
-       default:
-               mx3fb_write_reg(mx3fb, di_mappings[12], DI_DISP3_B0_MAP);
-               mx3fb_write_reg(mx3fb, di_mappings[13], DI_DISP3_B1_MAP);
-               mx3fb_write_reg(mx3fb, di_mappings[14], DI_DISP3_B2_MAP);
-               mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
-                            ((di_mappings[15] - 1) << 12), DI_DISP_ACC_CC);
-               break;
-       }
+       map = &di_mappings[mx3fb->disp_data_fmt];
+       mx3fb_write_reg(mx3fb, map->b0, DI_DISP3_B0_MAP);
+       mx3fb_write_reg(mx3fb, map->b1, DI_DISP3_B1_MAP);
+       mx3fb_write_reg(mx3fb, map->b2, DI_DISP3_B2_MAP);
 
        spin_unlock_irqrestore(&mx3fb->lock, lock_flags);
 
@@ -780,8 +757,6 @@ static int __set_par(struct fb_info *fbi, bool lock)
                if (sdc_init_panel(mx3fb, mode,
                                   (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
                                   fbi->var.xres, fbi->var.yres,
-                                  (fbi->var.sync & FB_SYNC_SWAP_RGB) ?
-                                  IPU_PIX_FMT_BGR666 : IPU_PIX_FMT_RGB666,
                                   fbi->var.left_margin,
                                   fbi->var.hsync_len,
                                   fbi->var.right_margin +
@@ -1117,7 +1092,7 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var,
                async_tx_ack(mx3_fbi->txd);
 
        txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg +
-               mx3_fbi->cur_ipu_buf, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT);
+               mx3_fbi->cur_ipu_buf, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
        if (!txd) {
                dev_err(fbi->device,
                        "Error preparing a DMA transaction descriptor.\n");
@@ -1349,6 +1324,12 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
        const struct fb_videomode *mode;
        int ret, num_modes;
 
+       if (mx3fb_pdata->disp_data_fmt >= ARRAY_SIZE(di_mappings)) {
+               dev_err(dev, "Illegal display data format %d\n",
+                               mx3fb_pdata->disp_data_fmt);
+               return -EINVAL;
+       }
+
        ichan->client = mx3fb;
        irq = ichan->eof_irq;
 
@@ -1402,6 +1383,8 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
        mx3fbi->mx3fb           = mx3fb;
        mx3fbi->blank           = FB_BLANK_NORMAL;
 
+       mx3fb->disp_data_fmt    = mx3fb_pdata->disp_data_fmt;
+
        init_completion(&mx3fbi->flip_cmpl);
        disable_irq(ichan->eof_irq);
        dev_dbg(mx3fb->dev, "disabling irq %d\n", ichan->eof_irq);
index eb3c5eea1a0fcc2ed868248b81d2ad9871d52018..4a89f889852d46c121444e63df424bccf12cb2a5 100644 (file)
@@ -902,18 +902,7 @@ static struct platform_driver mxsfb_driver = {
        },
 };
 
-static int __init mxsfb_init(void)
-{
-       return platform_driver_register(&mxsfb_driver);
-}
-
-static void __exit mxsfb_exit(void)
-{
-       platform_driver_unregister(&mxsfb_driver);
-}
-
-module_init(mxsfb_init);
-module_exit(mxsfb_exit);
+module_platform_driver(mxsfb_driver);
 
 MODULE_DESCRIPTION("Freescale mxs framebuffer driver");
 MODULE_AUTHOR("Sascha Hauer, Pengutronix");
index feea7b1dc3860a3f28965995d9aa24968cb7312d..fb3f6739110532ddeda7008eecfefd5e277dd207 100644 (file)
 
 /* --------------------------------------------------------------------- */
 
-static int internal;
-static int external;
-static int libretto;
-static int nostretch;
-static int nopciburst;
+static bool internal;
+static bool external;
+static bool libretto;
+static bool nostretch;
+static bool nopciburst;
 static char *mode_option __devinitdata = NULL;
 
 #ifdef MODULE
index d1fbbd888cf436b6ed8ce9d05e442ff3f605514b..e10f551ade2121eba471f4ddca476cc4e0b49d20 100644 (file)
@@ -762,18 +762,7 @@ static struct platform_driver nuc900fb_driver = {
        },
 };
 
-int __devinit nuc900fb_init(void)
-{
-       return platform_driver_register(&nuc900fb_driver);
-}
-
-static void __exit nuc900fb_cleanup(void)
-{
-       platform_driver_unregister(&nuc900fb_driver);
-}
-
-module_init(nuc900fb_init);
-module_exit(nuc900fb_cleanup);
+module_platform_driver(nuc900fb_driver);
 
 MODULE_DESCRIPTION("Framebuffer driver for the NUC900");
 MODULE_LICENSE("GPL");
index 081dc47452742a769235d74c18cf49545efe72fd..fe13ac567d545b9408bc6e00bb108cf7b0c0d69f 100644 (file)
@@ -81,7 +81,7 @@ static int vram __devinitdata = 0;
 static int bpp __devinitdata = 8;
 static int reverse_i2c __devinitdata;
 #ifdef CONFIG_MTRR
-static int nomtrr __devinitdata = 0;
+static bool nomtrr __devinitdata = false;
 #endif
 #ifdef CONFIG_PMAC_BACKLIGHT
 static int backlight __devinitdata = 1;
@@ -1509,7 +1509,7 @@ static int __devinit nvidiafb_setup(char *options)
                        backlight = simple_strtoul(this_opt+10, NULL, 0);
 #ifdef CONFIG_MTRR
                } else if (!strncmp(this_opt, "nomtrr", 6)) {
-                       nomtrr = 1;
+                       nomtrr = true;
 #endif
                } else if (!strncmp(this_opt, "fpdither:", 9)) {
                        fpdither = simple_strtol(this_opt+9, NULL, 0);
@@ -1599,7 +1599,7 @@ MODULE_PARM_DESC(bpp, "pixel width in bits"
 module_param(reverse_i2c, int, 0);
 MODULE_PARM_DESC(reverse_i2c, "reverse port assignment of the i2c bus");
 #ifdef CONFIG_MTRR
-module_param(nomtrr, bool, 0);
+module_param(nomtrr, bool, false);
 MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) "
                 "(default=0)");
 #endif
index 6978ae4ef83aedf90a560f1d166a890a413ad25e..0fdd6f6873bfcc1f153cb50462e588ebc49d33c0 100644 (file)
@@ -198,7 +198,7 @@ static int ams_delta_panel_resume(struct platform_device *pdev)
        return 0;
 }
 
-struct platform_driver ams_delta_panel_driver = {
+static struct platform_driver ams_delta_panel_driver = {
        .probe          = ams_delta_panel_probe,
        .remove         = ams_delta_panel_remove,
        .suspend        = ams_delta_panel_suspend,
@@ -209,15 +209,4 @@ struct platform_driver ams_delta_panel_driver = {
        },
 };
 
-static int __init ams_delta_panel_drv_init(void)
-{
-       return platform_driver_register(&ams_delta_panel_driver);
-}
-
-static void __exit ams_delta_panel_drv_cleanup(void)
-{
-       platform_driver_unregister(&ams_delta_panel_driver);
-}
-
-module_init(ams_delta_panel_drv_init);
-module_exit(ams_delta_panel_drv_cleanup);
+module_platform_driver(ams_delta_panel_driver);
index 622ad839fd9d46701af954235af4b30536f5c9da..49bdeca81e507829c5698306d0db156f84dd0eee 100644 (file)
@@ -113,7 +113,7 @@ static int h3_panel_resume(struct platform_device *pdev)
        return 0;
 }
 
-struct platform_driver h3_panel_driver = {
+static struct platform_driver h3_panel_driver = {
        .probe          = h3_panel_probe,
        .remove         = h3_panel_remove,
        .suspend        = h3_panel_suspend,
@@ -124,16 +124,4 @@ struct platform_driver h3_panel_driver = {
        },
 };
 
-static int __init h3_panel_drv_init(void)
-{
-       return platform_driver_register(&h3_panel_driver);
-}
-
-static void __exit h3_panel_drv_cleanup(void)
-{
-       platform_driver_unregister(&h3_panel_driver);
-}
-
-module_init(h3_panel_drv_init);
-module_exit(h3_panel_drv_cleanup);
-
+module_platform_driver(h3_panel_driver);
index 4802419da83b486477140d8e7388499bfd558a73..20f477851d5495a4b548426abcc39b805f071ea3 100644 (file)
@@ -104,7 +104,7 @@ static int htcherald_panel_resume(struct platform_device *pdev)
        return 0;
 }
 
-struct platform_driver htcherald_panel_driver = {
+static struct platform_driver htcherald_panel_driver = {
        .probe          = htcherald_panel_probe,
        .remove         = htcherald_panel_remove,
        .suspend        = htcherald_panel_suspend,
@@ -115,16 +115,4 @@ struct platform_driver htcherald_panel_driver = {
        },
 };
 
-static int __init htcherald_panel_drv_init(void)
-{
-       return platform_driver_register(&htcherald_panel_driver);
-}
-
-static void __exit htcherald_panel_drv_cleanup(void)
-{
-       platform_driver_unregister(&htcherald_panel_driver);
-}
-
-module_init(htcherald_panel_drv_init);
-module_exit(htcherald_panel_drv_cleanup);
-
+module_platform_driver(htcherald_panel_driver);
index 3271f1643b26fd40a8a3b5b6ad97c75d6e61ecf3..b38b1dd15ce35f059c446a36313424d2ab11274c 100644 (file)
@@ -98,7 +98,7 @@ static int innovator1510_panel_resume(struct platform_device *pdev)
        return 0;
 }
 
-struct platform_driver innovator1510_panel_driver = {
+static struct platform_driver innovator1510_panel_driver = {
        .probe          = innovator1510_panel_probe,
        .remove         = innovator1510_panel_remove,
        .suspend        = innovator1510_panel_suspend,
@@ -109,16 +109,4 @@ struct platform_driver innovator1510_panel_driver = {
        },
 };
 
-static int __init innovator1510_panel_drv_init(void)
-{
-       return platform_driver_register(&innovator1510_panel_driver);
-}
-
-static void __exit innovator1510_panel_drv_cleanup(void)
-{
-       platform_driver_unregister(&innovator1510_panel_driver);
-}
-
-module_init(innovator1510_panel_drv_init);
-module_exit(innovator1510_panel_drv_cleanup);
-
+module_platform_driver(innovator1510_panel_driver);
index 12cc52a70f9642ad2c7c568b00ecca24cbb084f5..7e8bd8e08a98c37313a377357aec0ff3e64192e7 100644 (file)
@@ -122,7 +122,7 @@ static int innovator1610_panel_resume(struct platform_device *pdev)
        return 0;
 }
 
-struct platform_driver innovator1610_panel_driver = {
+static struct platform_driver innovator1610_panel_driver = {
        .probe          = innovator1610_panel_probe,
        .remove         = innovator1610_panel_remove,
        .suspend        = innovator1610_panel_suspend,
@@ -133,16 +133,4 @@ struct platform_driver innovator1610_panel_driver = {
        },
 };
 
-static int __init innovator1610_panel_drv_init(void)
-{
-       return platform_driver_register(&innovator1610_panel_driver);
-}
-
-static void __exit innovator1610_panel_drv_cleanup(void)
-{
-       platform_driver_unregister(&innovator1610_panel_driver);
-}
-
-module_init(innovator1610_panel_drv_init);
-module_exit(innovator1610_panel_drv_cleanup);
-
+module_platform_driver(innovator1610_panel_driver);
index eb381db7fe519dcd449f919515cc2a9513d8c969..8d546dd55e814d9c622629fd4398ca5ac90a2084 100644 (file)
@@ -603,7 +603,6 @@ static int mipid_spi_remove(struct spi_device *spi)
 static struct spi_driver mipid_spi_driver = {
        .driver = {
                .name   = MIPID_MODULE_NAME,
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
        },
        .probe  = mipid_spi_probe,
index 6f8d13c41202a8addf821111d674a9e7fab8f8b9..5914220dfa9cbf46e0dfe81dc9ed34f8817a7af2 100644 (file)
@@ -116,7 +116,7 @@ static int osk_panel_resume(struct platform_device *pdev)
        return 0;
 }
 
-struct platform_driver osk_panel_driver = {
+static struct platform_driver osk_panel_driver = {
        .probe          = osk_panel_probe,
        .remove         = osk_panel_remove,
        .suspend        = osk_panel_suspend,
@@ -127,16 +127,4 @@ struct platform_driver osk_panel_driver = {
        },
 };
 
-static int __init osk_panel_drv_init(void)
-{
-       return platform_driver_register(&osk_panel_driver);
-}
-
-static void __exit osk_panel_drv_cleanup(void)
-{
-       platform_driver_unregister(&osk_panel_driver);
-}
-
-module_init(osk_panel_drv_init);
-module_exit(osk_panel_drv_cleanup);
-
+module_platform_driver(osk_panel_driver);
index 4cb301750d0269cca38b7129607a2fb51fa1c2e8..88c31eb0cd6c7768ad84d72f504fc1fb0f63a855 100644 (file)
@@ -97,7 +97,7 @@ static int palmte_panel_resume(struct platform_device *pdev)
        return 0;
 }
 
-struct platform_driver palmte_panel_driver = {
+static struct platform_driver palmte_panel_driver = {
        .probe          = palmte_panel_probe,
        .remove         = palmte_panel_remove,
        .suspend        = palmte_panel_suspend,
@@ -108,16 +108,4 @@ struct platform_driver palmte_panel_driver = {
        },
 };
 
-static int __init palmte_panel_drv_init(void)
-{
-       return platform_driver_register(&palmte_panel_driver);
-}
-
-static void __exit palmte_panel_drv_cleanup(void)
-{
-       platform_driver_unregister(&palmte_panel_driver);
-}
-
-module_init(palmte_panel_drv_init);
-module_exit(palmte_panel_drv_cleanup);
-
+module_platform_driver(palmte_panel_driver);
index b51b332e5a2bd16d05833996191034143808af52..aaf3c8ba12438d5323ef6d3e6c7002af3dd6b863 100644 (file)
@@ -102,7 +102,7 @@ static int palmtt_panel_resume(struct platform_device *pdev)
        return 0;
 }
 
-struct platform_driver palmtt_panel_driver = {
+static struct platform_driver palmtt_panel_driver = {
        .probe          = palmtt_panel_probe,
        .remove         = palmtt_panel_remove,
        .suspend        = palmtt_panel_suspend,
@@ -113,15 +113,4 @@ struct platform_driver palmtt_panel_driver = {
        },
 };
 
-static int __init palmtt_panel_drv_init(void)
-{
-       return platform_driver_register(&palmtt_panel_driver);
-}
-
-static void __exit palmtt_panel_drv_cleanup(void)
-{
-       platform_driver_unregister(&palmtt_panel_driver);
-}
-
-module_init(palmtt_panel_drv_init);
-module_exit(palmtt_panel_drv_cleanup);
+module_platform_driver(palmtt_panel_driver);
index 2334e56536bc94bf6310d20591ea79406110a40e..3b7d8aa1cf34606e15ef0e59b9374c7ea6267559 100644 (file)
@@ -98,7 +98,7 @@ static int palmz71_panel_resume(struct platform_device *pdev)
        return 0;
 }
 
-struct platform_driver palmz71_panel_driver = {
+static struct platform_driver palmz71_panel_driver = {
        .probe          = palmz71_panel_probe,
        .remove         = palmz71_panel_remove,
        .suspend        = palmz71_panel_suspend,
@@ -109,15 +109,4 @@ struct platform_driver palmz71_panel_driver = {
        },
 };
 
-static int __init palmz71_panel_drv_init(void)
-{
-       return platform_driver_register(&palmz71_panel_driver);
-}
-
-static void __exit palmz71_panel_drv_cleanup(void)
-{
-       platform_driver_unregister(&palmz71_panel_driver);
-}
-
-module_init(palmz71_panel_drv_init);
-module_exit(palmz71_panel_drv_cleanup);
+module_platform_driver(palmz71_panel_driver);
index 25d8e51031937c98ae5c05597f660d0cad363d98..b291bfaac80e79bc931c8131afec2a4f6a627353 100644 (file)
@@ -47,9 +47,9 @@ static unsigned int   def_rotate;
 static unsigned int    def_mirror;
 
 #ifdef CONFIG_FB_OMAP_MANUAL_UPDATE
-static int             manual_update = 1;
+static bool            manual_update = 1;
 #else
-static int             manual_update;
+static bool            manual_update;
 #endif
 
 static struct platform_device  *fbdev_pdev;
index 8d8e1fe1901c16248f0d75743d9625580e9af3c3..74d29b552901e3ee5a6ee1d5b65f86da6eb124ad 100644 (file)
@@ -41,7 +41,7 @@ config PANEL_NEC_NL8048HL11_01B
 
 config PANEL_PICODLP
        tristate "TI PICO DLP mini-projector"
-       depends on OMAP2_DSS && I2C
+       depends on OMAP2_DSS_DPI && I2C
        help
                A mini-projector used in TI's SDP4430 and EVM boards
                For more info please visit http://www.dlp.com/projector/
index dbd59b8e5b36520e76c472c5621b35bb7c262415..51a87e149e242b8262fd8c79fba84a07cb4a94de 100644 (file)
@@ -803,7 +803,6 @@ static int acx565akm_spi_remove(struct spi_device *spi)
 static struct spi_driver acx565akm_spi_driver = {
        .driver = {
                .name   = "acx565akm",
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
        },
        .probe  = acx565akm_spi_probe,
index 519c47d2057f8980f6370b9ef12deb0f7b6d2955..28b9a6d61b0f96c05e52dd67923ea20d79583d24 100644 (file)
@@ -297,6 +297,72 @@ static struct panel_config generic_dpi_panels[] = {
 
                .name                   = "apollon",
        },
+       /* FocalTech ETM070003DH6 */
+       {
+               {
+                       .x_res          = 800,
+                       .y_res          = 480,
+
+                       .pixel_clock    = 28000,
+
+                       .hsw            = 48,
+                       .hfp            = 40,
+                       .hbp            = 40,
+
+                       .vsw            = 3,
+                       .vfp            = 13,
+                       .vbp            = 29,
+               },
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                         OMAP_DSS_LCD_IHS,
+               .name                   = "focaltech_etm070003dh6",
+       },
+
+       /* Microtips Technologies - UMSH-8173MD */
+       {
+               {
+                       .x_res          = 800,
+                       .y_res          = 480,
+
+                       .pixel_clock    = 34560,
+
+                       .hsw            = 13,
+                       .hfp            = 101,
+                       .hbp            = 101,
+
+                       .vsw            = 23,
+                       .vfp            = 1,
+                       .vbp            = 1,
+               },
+               .acbi                   = 0x0,
+               .acb                    = 0x0,
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                         OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC,
+               .power_on_delay         = 0,
+               .power_off_delay        = 0,
+               .name                   = "microtips_umsh_8173md",
+       },
+
+       /* OrtusTech COM43H4M10XTC */
+       {
+               {
+                       .x_res          = 480,
+                       .y_res          = 272,
+
+                       .pixel_clock    = 8000,
+
+                       .hsw            = 41,
+                       .hfp            = 8,
+                       .hbp            = 4,
+
+                       .vsw            = 10,
+                       .vfp            = 4,
+                       .vbp            = 2,
+               },
+               .config                 = OMAP_DSS_LCD_TFT,
+
+               .name                   = "ortustech_com43h4m10xtc",
+       },
 };
 
 struct panel_drv_data {
index 150e8bae35a15d6148241e5f261b34464566c871..dc9408dc93d1ed36f702187aebab9e5d7605b84b 100644 (file)
@@ -708,7 +708,6 @@ static int mipid_spi_remove(struct spi_device *spi)
 static struct spi_driver mipid_spi_driver = {
        .driver = {
                .name   = "lcd_mipid",
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
        },
        .probe  = mipid_spi_probe,
index 2ba9d0ca187c866f97ec1c56b725865adecde137..0eb31caddca86cddea33b8a90d4e6c2b13fef711 100644 (file)
@@ -163,50 +163,93 @@ static void nec_8048_panel_remove(struct omap_dss_device *dssdev)
        kfree(necd);
 }
 
-static int nec_8048_panel_enable(struct omap_dss_device *dssdev)
+static int nec_8048_panel_power_on(struct omap_dss_device *dssdev)
 {
-       int r = 0;
+       int r;
        struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
        struct backlight_device *bl = necd->bl;
 
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               return 0;
+
+       r = omapdss_dpi_display_enable(dssdev);
+       if (r)
+               goto err0;
+
        if (dssdev->platform_enable) {
                r = dssdev->platform_enable(dssdev);
                if (r)
-                       return r;
+                       goto err1;
        }
 
        r = nec_8048_bl_update_status(bl);
        if (r < 0)
                dev_err(&dssdev->dev, "failed to set lcd brightness\n");
 
-       r = omapdss_dpi_display_enable(dssdev);
-
+       return 0;
+err1:
+       omapdss_dpi_display_disable(dssdev);
+err0:
        return r;
 }
 
-static void nec_8048_panel_disable(struct omap_dss_device *dssdev)
+static void nec_8048_panel_power_off(struct omap_dss_device *dssdev)
 {
        struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
        struct backlight_device *bl = necd->bl;
 
-       omapdss_dpi_display_disable(dssdev);
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               return;
 
        bl->props.brightness = 0;
        nec_8048_bl_update_status(bl);
 
        if (dssdev->platform_disable)
                dssdev->platform_disable(dssdev);
+
+       omapdss_dpi_display_disable(dssdev);
+}
+
+static int nec_8048_panel_enable(struct omap_dss_device *dssdev)
+{
+       int r;
+
+       r = nec_8048_panel_power_on(dssdev);
+       if (r)
+               return r;
+
+       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+       return 0;
+}
+
+static void nec_8048_panel_disable(struct omap_dss_device *dssdev)
+{
+       nec_8048_panel_power_off(dssdev);
+
+       dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 }
 
 static int nec_8048_panel_suspend(struct omap_dss_device *dssdev)
 {
-       nec_8048_panel_disable(dssdev);
+       nec_8048_panel_power_off(dssdev);
+
+       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
        return 0;
 }
 
 static int nec_8048_panel_resume(struct omap_dss_device *dssdev)
 {
-       return nec_8048_panel_enable(dssdev);
+       int r;
+
+       r = nec_8048_panel_power_on(dssdev);
+       if (r)
+               return r;
+
+       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+       return 0;
 }
 
 static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev)
@@ -303,7 +346,6 @@ static struct spi_driver nec_8048_spi_driver = {
        .resume         = nec_8048_spi_resume,
        .driver         = {
                .name   = "nec_8048_spi",
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
        },
 };
index 80c3f6ab1a94d73df39d18233c8ddc4dbd91304a..00c5c615585f91d3216df25a28fb64fbc42611b4 100644 (file)
@@ -198,12 +198,6 @@ struct taal_data {
        bool te_enabled;
 
        atomic_t do_update;
-       struct {
-               u16 x;
-               u16 y;
-               u16 w;
-               u16 h;
-       } update_region;
        int channel;
 
        struct delayed_work te_timeout_work;
@@ -1188,6 +1182,10 @@ static int taal_power_on(struct omap_dss_device *dssdev)
        if (r)
                goto err;
 
+       r = dsi_enable_video_output(dssdev, td->channel);
+       if (r)
+               goto err;
+
        td->enabled = 1;
 
        if (!td->intro_printed) {
@@ -1217,6 +1215,8 @@ static void taal_power_off(struct omap_dss_device *dssdev)
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
        int r;
 
+       dsi_disable_video_output(dssdev, td->channel);
+
        r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_OFF);
        if (!r)
                r = taal_sleep_in(td);
@@ -1394,12 +1394,8 @@ static irqreturn_t taal_te_isr(int irq, void *data)
        if (old) {
                cancel_delayed_work(&td->te_timeout_work);
 
-               r = omap_dsi_update(dssdev, td->channel,
-                               td->update_region.x,
-                               td->update_region.y,
-                               td->update_region.w,
-                               td->update_region.h,
-                               taal_framedone_cb, dssdev);
+               r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb,
+                               dssdev);
                if (r)
                        goto err;
        }
@@ -1444,26 +1440,20 @@ static int taal_update(struct omap_dss_device *dssdev,
                goto err;
        }
 
-       r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h, true);
-       if (r)
-               goto err;
-
-       r = taal_set_update_window(td, x, y, w, h);
+       /* XXX no need to send this every frame, but dsi break if not done */
+       r = taal_set_update_window(td, 0, 0,
+                       td->panel_config->timings.x_res,
+                       td->panel_config->timings.y_res);
        if (r)
                goto err;
 
        if (td->te_enabled && panel_data->use_ext_te) {
-               td->update_region.x = x;
-               td->update_region.y = y;
-               td->update_region.w = w;
-               td->update_region.h = h;
-               barrier();
                schedule_delayed_work(&td->te_timeout_work,
                                msecs_to_jiffies(250));
                atomic_set(&td->do_update, 1);
        } else {
-               r = omap_dsi_update(dssdev, td->channel, x, y, w, h,
-                               taal_framedone_cb, dssdev);
+               r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb,
+                               dssdev);
                if (r)
                        goto err;
        }
index 2462b9ec66623f2fa33d6f0b4852a8938e5ac85a..e6649aa8959135be0181744ea5e528ac4189e2c5 100644 (file)
@@ -512,7 +512,6 @@ static int __devexit tpo_td043_spi_remove(struct spi_device *spi)
 static struct spi_driver tpo_td043_spi_driver = {
        .driver = {
                .name   = "tpo_td043mtea1_panel_spi",
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
        },
        .probe  = tpo_td043_spi_probe,
index bd34ac5b20264b21c94b58864b5239c5c3838fb3..5c450b0f94d0bb03a5bfef064ac613424e527247 100644 (file)
@@ -1,5 +1,6 @@
 obj-$(CONFIG_OMAP2_DSS) += omapdss.o
-omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o
+omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
+       manager.o overlay.o apply.o
 omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
 omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
 omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
new file mode 100644 (file)
index 0000000..052dc87
--- /dev/null
@@ -0,0 +1,1324 @@
+/*
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "APPLY"
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/jiffies.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+/*
+ * We have 4 levels of cache for the dispc settings. First two are in SW and
+ * the latter two in HW.
+ *
+ *       set_info()
+ *          v
+ * +--------------------+
+ * |     user_info      |
+ * +--------------------+
+ *          v
+ *        apply()
+ *          v
+ * +--------------------+
+ * |       info         |
+ * +--------------------+
+ *          v
+ *      write_regs()
+ *          v
+ * +--------------------+
+ * |  shadow registers  |
+ * +--------------------+
+ *          v
+ * VFP or lcd/digit_enable
+ *          v
+ * +--------------------+
+ * |      registers     |
+ * +--------------------+
+ */
+
+struct ovl_priv_data {
+
+       bool user_info_dirty;
+       struct omap_overlay_info user_info;
+
+       bool info_dirty;
+       struct omap_overlay_info info;
+
+       bool shadow_info_dirty;
+
+       bool extra_info_dirty;
+       bool shadow_extra_info_dirty;
+
+       bool enabled;
+       enum omap_channel channel;
+       u32 fifo_low, fifo_high;
+
+       /*
+        * True if overlay is to be enabled. Used to check and calculate configs
+        * for the overlay before it is enabled in the HW.
+        */
+       bool enabling;
+};
+
+struct mgr_priv_data {
+
+       bool user_info_dirty;
+       struct omap_overlay_manager_info user_info;
+
+       bool info_dirty;
+       struct omap_overlay_manager_info info;
+
+       bool shadow_info_dirty;
+
+       /* If true, GO bit is up and shadow registers cannot be written.
+        * Never true for manual update displays */
+       bool busy;
+
+       /* If true, dispc output is enabled */
+       bool updating;
+
+       /* If true, a display is enabled using this manager */
+       bool enabled;
+};
+
+static struct {
+       struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
+       struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
+
+       bool irq_enabled;
+} dss_data;
+
+/* protects dss_data */
+static spinlock_t data_lock;
+/* lock for blocking functions */
+static DEFINE_MUTEX(apply_lock);
+static DECLARE_COMPLETION(extra_updated_completion);
+
+static void dss_register_vsync_isr(void);
+
+static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
+{
+       return &dss_data.ovl_priv_data_array[ovl->id];
+}
+
+static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
+{
+       return &dss_data.mgr_priv_data_array[mgr->id];
+}
+
+void dss_apply_init(void)
+{
+       const int num_ovls = dss_feat_get_num_ovls();
+       int i;
+
+       spin_lock_init(&data_lock);
+
+       for (i = 0; i < num_ovls; ++i) {
+               struct ovl_priv_data *op;
+
+               op = &dss_data.ovl_priv_data_array[i];
+
+               op->info.global_alpha = 255;
+
+               switch (i) {
+               case 0:
+                       op->info.zorder = 0;
+                       break;
+               case 1:
+                       op->info.zorder =
+                               dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
+                       break;
+               case 2:
+                       op->info.zorder =
+                               dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
+                       break;
+               case 3:
+                       op->info.zorder =
+                               dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
+                       break;
+               }
+
+               op->user_info = op->info;
+       }
+}
+
+static bool ovl_manual_update(struct omap_overlay *ovl)
+{
+       return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
+}
+
+static bool mgr_manual_update(struct omap_overlay_manager *mgr)
+{
+       return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
+}
+
+static int dss_check_settings_low(struct omap_overlay_manager *mgr,
+               struct omap_dss_device *dssdev, bool applying)
+{
+       struct omap_overlay_info *oi;
+       struct omap_overlay_manager_info *mi;
+       struct omap_overlay *ovl;
+       struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];
+       struct ovl_priv_data *op;
+       struct mgr_priv_data *mp;
+
+       mp = get_mgr_priv(mgr);
+
+       if (applying && mp->user_info_dirty)
+               mi = &mp->user_info;
+       else
+               mi = &mp->info;
+
+       /* collect the infos to be tested into the array */
+       list_for_each_entry(ovl, &mgr->overlays, list) {
+               op = get_ovl_priv(ovl);
+
+               if (!op->enabled && !op->enabling)
+                       oi = NULL;
+               else if (applying && op->user_info_dirty)
+                       oi = &op->user_info;
+               else
+                       oi = &op->info;
+
+               ois[ovl->id] = oi;
+       }
+
+       return dss_mgr_check(mgr, dssdev, mi, ois);
+}
+
+/*
+ * check manager and overlay settings using overlay_info from data->info
+ */
+static int dss_check_settings(struct omap_overlay_manager *mgr,
+               struct omap_dss_device *dssdev)
+{
+       return dss_check_settings_low(mgr, dssdev, false);
+}
+
+/*
+ * check manager and overlay settings using overlay_info from ovl->info if
+ * dirty and from data->info otherwise
+ */
+static int dss_check_settings_apply(struct omap_overlay_manager *mgr,
+               struct omap_dss_device *dssdev)
+{
+       return dss_check_settings_low(mgr, dssdev, true);
+}
+
+static bool need_isr(void)
+{
+       const int num_mgrs = dss_feat_get_num_mgrs();
+       int i;
+
+       for (i = 0; i < num_mgrs; ++i) {
+               struct omap_overlay_manager *mgr;
+               struct mgr_priv_data *mp;
+               struct omap_overlay *ovl;
+
+               mgr = omap_dss_get_overlay_manager(i);
+               mp = get_mgr_priv(mgr);
+
+               if (!mp->enabled)
+                       continue;
+
+               if (mgr_manual_update(mgr)) {
+                       /* to catch FRAMEDONE */
+                       if (mp->updating)
+                               return true;
+               } else {
+                       /* to catch GO bit going down */
+                       if (mp->busy)
+                               return true;
+
+                       /* to write new values to registers */
+                       if (mp->info_dirty)
+                               return true;
+
+                       /* to set GO bit */
+                       if (mp->shadow_info_dirty)
+                               return true;
+
+                       list_for_each_entry(ovl, &mgr->overlays, list) {
+                               struct ovl_priv_data *op;
+
+                               op = get_ovl_priv(ovl);
+
+                               /*
+                                * NOTE: we check extra_info flags even for
+                                * disabled overlays, as extra_infos need to be
+                                * always written.
+                                */
+
+                               /* to write new values to registers */
+                               if (op->extra_info_dirty)
+                                       return true;
+
+                               /* to set GO bit */
+                               if (op->shadow_extra_info_dirty)
+                                       return true;
+
+                               if (!op->enabled)
+                                       continue;
+
+                               /* to write new values to registers */
+                               if (op->info_dirty)
+                                       return true;
+
+                               /* to set GO bit */
+                               if (op->shadow_info_dirty)
+                                       return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+static bool need_go(struct omap_overlay_manager *mgr)
+{
+       struct omap_overlay *ovl;
+       struct mgr_priv_data *mp;
+       struct ovl_priv_data *op;
+
+       mp = get_mgr_priv(mgr);
+
+       if (mp->shadow_info_dirty)
+               return true;
+
+       list_for_each_entry(ovl, &mgr->overlays, list) {
+               op = get_ovl_priv(ovl);
+               if (op->shadow_info_dirty || op->shadow_extra_info_dirty)
+                       return true;
+       }
+
+       return false;
+}
+
+/* returns true if an extra_info field is currently being updated */
+static bool extra_info_update_ongoing(void)
+{
+       const int num_ovls = omap_dss_get_num_overlays();
+       struct ovl_priv_data *op;
+       struct omap_overlay *ovl;
+       struct mgr_priv_data *mp;
+       int i;
+
+       for (i = 0; i < num_ovls; ++i) {
+               ovl = omap_dss_get_overlay(i);
+               op = get_ovl_priv(ovl);
+
+               if (!ovl->manager)
+                       continue;
+
+               mp = get_mgr_priv(ovl->manager);
+
+               if (!mp->enabled)
+                       continue;
+
+               if (!mp->updating)
+                       continue;
+
+               if (op->extra_info_dirty || op->shadow_extra_info_dirty)
+                       return true;
+       }
+
+       return false;
+}
+
+/* wait until no extra_info updates are pending */
+static void wait_pending_extra_info_updates(void)
+{
+       bool updating;
+       unsigned long flags;
+       unsigned long t;
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       updating = extra_info_update_ongoing();
+
+       if (!updating) {
+               spin_unlock_irqrestore(&data_lock, flags);
+               return;
+       }
+
+       init_completion(&extra_updated_completion);
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       t = msecs_to_jiffies(500);
+       wait_for_completion_timeout(&extra_updated_completion, t);
+
+       updating = extra_info_update_ongoing();
+
+       WARN_ON(updating);
+}
+
+int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
+{
+       unsigned long timeout = msecs_to_jiffies(500);
+       struct mgr_priv_data *mp;
+       u32 irq;
+       int r;
+       int i;
+       struct omap_dss_device *dssdev = mgr->device;
+
+       if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               return 0;
+
+       if (mgr_manual_update(mgr))
+               return 0;
+
+       irq = dispc_mgr_get_vsync_irq(mgr->id);
+
+       mp = get_mgr_priv(mgr);
+       i = 0;
+       while (1) {
+               unsigned long flags;
+               bool shadow_dirty, dirty;
+
+               spin_lock_irqsave(&data_lock, flags);
+               dirty = mp->info_dirty;
+               shadow_dirty = mp->shadow_info_dirty;
+               spin_unlock_irqrestore(&data_lock, flags);
+
+               if (!dirty && !shadow_dirty) {
+                       r = 0;
+                       break;
+               }
+
+               /* 4 iterations is the worst case:
+                * 1 - initial iteration, dirty = true (between VFP and VSYNC)
+                * 2 - first VSYNC, dirty = true
+                * 3 - dirty = false, shadow_dirty = true
+                * 4 - shadow_dirty = false */
+               if (i++ == 3) {
+                       DSSERR("mgr(%d)->wait_for_go() not finishing\n",
+                                       mgr->id);
+                       r = 0;
+                       break;
+               }
+
+               r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
+               if (r == -ERESTARTSYS)
+                       break;
+
+               if (r) {
+                       DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
+                       break;
+               }
+       }
+
+       return r;
+}
+
+int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
+{
+       unsigned long timeout = msecs_to_jiffies(500);
+       struct ovl_priv_data *op;
+       struct omap_dss_device *dssdev;
+       u32 irq;
+       int r;
+       int i;
+
+       if (!ovl->manager)
+               return 0;
+
+       dssdev = ovl->manager->device;
+
+       if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               return 0;
+
+       if (ovl_manual_update(ovl))
+               return 0;
+
+       irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
+
+       op = get_ovl_priv(ovl);
+       i = 0;
+       while (1) {
+               unsigned long flags;
+               bool shadow_dirty, dirty;
+
+               spin_lock_irqsave(&data_lock, flags);
+               dirty = op->info_dirty;
+               shadow_dirty = op->shadow_info_dirty;
+               spin_unlock_irqrestore(&data_lock, flags);
+
+               if (!dirty && !shadow_dirty) {
+                       r = 0;
+                       break;
+               }
+
+               /* 4 iterations is the worst case:
+                * 1 - initial iteration, dirty = true (between VFP and VSYNC)
+                * 2 - first VSYNC, dirty = true
+                * 3 - dirty = false, shadow_dirty = true
+                * 4 - shadow_dirty = false */
+               if (i++ == 3) {
+                       DSSERR("ovl(%d)->wait_for_go() not finishing\n",
+                                       ovl->id);
+                       r = 0;
+                       break;
+               }
+
+               r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
+               if (r == -ERESTARTSYS)
+                       break;
+
+               if (r) {
+                       DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
+                       break;
+               }
+       }
+
+       return r;
+}
+
+static void dss_ovl_write_regs(struct omap_overlay *ovl)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       struct omap_overlay_info *oi;
+       bool ilace, replication;
+       struct mgr_priv_data *mp;
+       int r;
+
+       DSSDBGF("%d", ovl->id);
+
+       if (!op->enabled || !op->info_dirty)
+               return;
+
+       oi = &op->info;
+
+       replication = dss_use_replication(ovl->manager->device, oi->color_mode);
+
+       ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
+
+       r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
+       if (r) {
+               /*
+                * We can't do much here, as this function can be called from
+                * vsync interrupt.
+                */
+               DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
+
+               /* This will leave fifo configurations in a nonoptimal state */
+               op->enabled = false;
+               dispc_ovl_enable(ovl->id, false);
+               return;
+       }
+
+       mp = get_mgr_priv(ovl->manager);
+
+       op->info_dirty = false;
+       if (mp->updating)
+               op->shadow_info_dirty = true;
+}
+
+static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       struct mgr_priv_data *mp;
+
+       DSSDBGF("%d", ovl->id);
+
+       if (!op->extra_info_dirty)
+               return;
+
+       /* note: write also when op->enabled == false, so that the ovl gets
+        * disabled */
+
+       dispc_ovl_enable(ovl->id, op->enabled);
+       dispc_ovl_set_channel_out(ovl->id, op->channel);
+       dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
+
+       mp = get_mgr_priv(ovl->manager);
+
+       op->extra_info_dirty = false;
+       if (mp->updating)
+               op->shadow_extra_info_dirty = true;
+}
+
+static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
+{
+       struct mgr_priv_data *mp = get_mgr_priv(mgr);
+       struct omap_overlay *ovl;
+
+       DSSDBGF("%d", mgr->id);
+
+       if (!mp->enabled)
+               return;
+
+       WARN_ON(mp->busy);
+
+       /* Commit overlay settings */
+       list_for_each_entry(ovl, &mgr->overlays, list) {
+               dss_ovl_write_regs(ovl);
+               dss_ovl_write_regs_extra(ovl);
+       }
+
+       if (mp->info_dirty) {
+               dispc_mgr_setup(mgr->id, &mp->info);
+
+               mp->info_dirty = false;
+               if (mp->updating)
+                       mp->shadow_info_dirty = true;
+       }
+}
+
+static void dss_write_regs(void)
+{
+       const int num_mgrs = omap_dss_get_num_overlay_managers();
+       int i;
+
+       for (i = 0; i < num_mgrs; ++i) {
+               struct omap_overlay_manager *mgr;
+               struct mgr_priv_data *mp;
+               int r;
+
+               mgr = omap_dss_get_overlay_manager(i);
+               mp = get_mgr_priv(mgr);
+
+               if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
+                       continue;
+
+               r = dss_check_settings(mgr, mgr->device);
+               if (r) {
+                       DSSERR("cannot write registers for manager %s: "
+                                       "illegal configuration\n", mgr->name);
+                       continue;
+               }
+
+               dss_mgr_write_regs(mgr);
+       }
+}
+
+static void dss_set_go_bits(void)
+{
+       const int num_mgrs = omap_dss_get_num_overlay_managers();
+       int i;
+
+       for (i = 0; i < num_mgrs; ++i) {
+               struct omap_overlay_manager *mgr;
+               struct mgr_priv_data *mp;
+
+               mgr = omap_dss_get_overlay_manager(i);
+               mp = get_mgr_priv(mgr);
+
+               if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
+                       continue;
+
+               if (!need_go(mgr))
+                       continue;
+
+               mp->busy = true;
+
+               if (!dss_data.irq_enabled && need_isr())
+                       dss_register_vsync_isr();
+
+               dispc_mgr_go(mgr->id);
+       }
+
+}
+
+void dss_mgr_start_update(struct omap_overlay_manager *mgr)
+{
+       struct mgr_priv_data *mp = get_mgr_priv(mgr);
+       unsigned long flags;
+       int r;
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       WARN_ON(mp->updating);
+
+       r = dss_check_settings(mgr, mgr->device);
+       if (r) {
+               DSSERR("cannot start manual update: illegal configuration\n");
+               spin_unlock_irqrestore(&data_lock, flags);
+               return;
+       }
+
+       dss_mgr_write_regs(mgr);
+
+       mp->updating = true;
+
+       if (!dss_data.irq_enabled && need_isr())
+               dss_register_vsync_isr();
+
+       dispc_mgr_enable(mgr->id, true);
+
+       spin_unlock_irqrestore(&data_lock, flags);
+}
+
+static void dss_apply_irq_handler(void *data, u32 mask);
+
+static void dss_register_vsync_isr(void)
+{
+       const int num_mgrs = dss_feat_get_num_mgrs();
+       u32 mask;
+       int r, i;
+
+       mask = 0;
+       for (i = 0; i < num_mgrs; ++i)
+               mask |= dispc_mgr_get_vsync_irq(i);
+
+       for (i = 0; i < num_mgrs; ++i)
+               mask |= dispc_mgr_get_framedone_irq(i);
+
+       r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
+       WARN_ON(r);
+
+       dss_data.irq_enabled = true;
+}
+
+static void dss_unregister_vsync_isr(void)
+{
+       const int num_mgrs = dss_feat_get_num_mgrs();
+       u32 mask;
+       int r, i;
+
+       mask = 0;
+       for (i = 0; i < num_mgrs; ++i)
+               mask |= dispc_mgr_get_vsync_irq(i);
+
+       for (i = 0; i < num_mgrs; ++i)
+               mask |= dispc_mgr_get_framedone_irq(i);
+
+       r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
+       WARN_ON(r);
+
+       dss_data.irq_enabled = false;
+}
+
+static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
+{
+       struct omap_overlay *ovl;
+       struct mgr_priv_data *mp;
+       struct ovl_priv_data *op;
+
+       mp = get_mgr_priv(mgr);
+       mp->shadow_info_dirty = false;
+
+       list_for_each_entry(ovl, &mgr->overlays, list) {
+               op = get_ovl_priv(ovl);
+               op->shadow_info_dirty = false;
+               op->shadow_extra_info_dirty = false;
+       }
+}
+
+static void dss_apply_irq_handler(void *data, u32 mask)
+{
+       const int num_mgrs = dss_feat_get_num_mgrs();
+       int i;
+       bool extra_updating;
+
+       spin_lock(&data_lock);
+
+       /* clear busy, updating flags, shadow_dirty flags */
+       for (i = 0; i < num_mgrs; i++) {
+               struct omap_overlay_manager *mgr;
+               struct mgr_priv_data *mp;
+               bool was_updating;
+
+               mgr = omap_dss_get_overlay_manager(i);
+               mp = get_mgr_priv(mgr);
+
+               if (!mp->enabled)
+                       continue;
+
+               was_updating = mp->updating;
+               mp->updating = dispc_mgr_is_enabled(i);
+
+               if (!mgr_manual_update(mgr)) {
+                       bool was_busy = mp->busy;
+                       mp->busy = dispc_mgr_go_busy(i);
+
+                       if (was_busy && !mp->busy)
+                               mgr_clear_shadow_dirty(mgr);
+               } else {
+                       if (was_updating && !mp->updating)
+                               mgr_clear_shadow_dirty(mgr);
+               }
+       }
+
+       dss_write_regs();
+       dss_set_go_bits();
+
+       extra_updating = extra_info_update_ongoing();
+       if (!extra_updating)
+               complete_all(&extra_updated_completion);
+
+       if (!need_isr())
+               dss_unregister_vsync_isr();
+
+       spin_unlock(&data_lock);
+}
+
+static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
+{
+       struct ovl_priv_data *op;
+
+       op = get_ovl_priv(ovl);
+
+       if (!op->user_info_dirty)
+               return;
+
+       op->user_info_dirty = false;
+       op->info_dirty = true;
+       op->info = op->user_info;
+}
+
+static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
+{
+       struct mgr_priv_data *mp;
+
+       mp = get_mgr_priv(mgr);
+
+       if (!mp->user_info_dirty)
+               return;
+
+       mp->user_info_dirty = false;
+       mp->info_dirty = true;
+       mp->info = mp->user_info;
+}
+
+int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
+{
+       unsigned long flags;
+       struct omap_overlay *ovl;
+       int r;
+
+       DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       r = dss_check_settings_apply(mgr, mgr->device);
+       if (r) {
+               spin_unlock_irqrestore(&data_lock, flags);
+               DSSERR("failed to apply settings: illegal configuration.\n");
+               return r;
+       }
+
+       /* Configure overlays */
+       list_for_each_entry(ovl, &mgr->overlays, list)
+               omap_dss_mgr_apply_ovl(ovl);
+
+       /* Configure manager */
+       omap_dss_mgr_apply_mgr(mgr);
+
+       dss_write_regs();
+       dss_set_go_bits();
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       return 0;
+}
+
+static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
+{
+       struct ovl_priv_data *op;
+
+       op = get_ovl_priv(ovl);
+
+       if (op->enabled == enable)
+               return;
+
+       op->enabled = enable;
+       op->extra_info_dirty = true;
+}
+
+static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
+               u32 fifo_low, u32 fifo_high)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+
+       if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)
+               return;
+
+       op->fifo_low = fifo_low;
+       op->fifo_high = fifo_high;
+       op->extra_info_dirty = true;
+}
+
+static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       struct omap_dss_device *dssdev;
+       u32 size, burst_size;
+       u32 fifo_low, fifo_high;
+
+       if (!op->enabled && !op->enabling)
+               return;
+
+       dssdev = ovl->manager->device;
+
+       size = dispc_ovl_get_fifo_size(ovl->id);
+
+       burst_size = dispc_ovl_get_burst_size(ovl->id);
+
+       switch (dssdev->type) {
+       case OMAP_DISPLAY_TYPE_DPI:
+       case OMAP_DISPLAY_TYPE_DBI:
+       case OMAP_DISPLAY_TYPE_SDI:
+       case OMAP_DISPLAY_TYPE_VENC:
+       case OMAP_DISPLAY_TYPE_HDMI:
+               default_get_overlay_fifo_thresholds(ovl->id, size,
+                               burst_size, &fifo_low, &fifo_high);
+               break;
+#ifdef CONFIG_OMAP2_DSS_DSI
+       case OMAP_DISPLAY_TYPE_DSI:
+               dsi_get_overlay_fifo_thresholds(ovl->id, size,
+                               burst_size, &fifo_low, &fifo_high);
+               break;
+#endif
+       default:
+               BUG();
+       }
+
+       dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
+}
+
+static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
+{
+       struct omap_overlay *ovl;
+       struct mgr_priv_data *mp;
+
+       mp = get_mgr_priv(mgr);
+
+       if (!mp->enabled)
+               return;
+
+       list_for_each_entry(ovl, &mgr->overlays, list)
+               dss_ovl_setup_fifo(ovl);
+}
+
+static void dss_setup_fifos(void)
+{
+       const int num_mgrs = omap_dss_get_num_overlay_managers();
+       struct omap_overlay_manager *mgr;
+       int i;
+
+       for (i = 0; i < num_mgrs; ++i) {
+               mgr = omap_dss_get_overlay_manager(i);
+               dss_mgr_setup_fifos(mgr);
+       }
+}
+
+int dss_mgr_enable(struct omap_overlay_manager *mgr)
+{
+       struct mgr_priv_data *mp = get_mgr_priv(mgr);
+       unsigned long flags;
+       int r;
+
+       mutex_lock(&apply_lock);
+
+       if (mp->enabled)
+               goto out;
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       mp->enabled = true;
+
+       r = dss_check_settings(mgr, mgr->device);
+       if (r) {
+               DSSERR("failed to enable manager %d: check_settings failed\n",
+                               mgr->id);
+               goto err;
+       }
+
+       dss_setup_fifos();
+
+       dss_write_regs();
+       dss_set_go_bits();
+
+       if (!mgr_manual_update(mgr))
+               mp->updating = true;
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       if (!mgr_manual_update(mgr))
+               dispc_mgr_enable(mgr->id, true);
+
+out:
+       mutex_unlock(&apply_lock);
+
+       return 0;
+
+err:
+       mp->enabled = false;
+       spin_unlock_irqrestore(&data_lock, flags);
+       mutex_unlock(&apply_lock);
+       return r;
+}
+
+void dss_mgr_disable(struct omap_overlay_manager *mgr)
+{
+       struct mgr_priv_data *mp = get_mgr_priv(mgr);
+       unsigned long flags;
+
+       mutex_lock(&apply_lock);
+
+       if (!mp->enabled)
+               goto out;
+
+       if (!mgr_manual_update(mgr))
+               dispc_mgr_enable(mgr->id, false);
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       mp->updating = false;
+       mp->enabled = false;
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+out:
+       mutex_unlock(&apply_lock);
+}
+
+int dss_mgr_set_info(struct omap_overlay_manager *mgr,
+               struct omap_overlay_manager_info *info)
+{
+       struct mgr_priv_data *mp = get_mgr_priv(mgr);
+       unsigned long flags;
+       int r;
+
+       r = dss_mgr_simple_check(mgr, info);
+       if (r)
+               return r;
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       mp->user_info = *info;
+       mp->user_info_dirty = true;
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       return 0;
+}
+
+void dss_mgr_get_info(struct omap_overlay_manager *mgr,
+               struct omap_overlay_manager_info *info)
+{
+       struct mgr_priv_data *mp = get_mgr_priv(mgr);
+       unsigned long flags;
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       *info = mp->user_info;
+
+       spin_unlock_irqrestore(&data_lock, flags);
+}
+
+int dss_mgr_set_device(struct omap_overlay_manager *mgr,
+               struct omap_dss_device *dssdev)
+{
+       int r;
+
+       mutex_lock(&apply_lock);
+
+       if (dssdev->manager) {
+               DSSERR("display '%s' already has a manager '%s'\n",
+                              dssdev->name, dssdev->manager->name);
+               r = -EINVAL;
+               goto err;
+       }
+
+       if ((mgr->supported_displays & dssdev->type) == 0) {
+               DSSERR("display '%s' does not support manager '%s'\n",
+                              dssdev->name, mgr->name);
+               r = -EINVAL;
+               goto err;
+       }
+
+       dssdev->manager = mgr;
+       mgr->device = dssdev;
+
+       mutex_unlock(&apply_lock);
+
+       return 0;
+err:
+       mutex_unlock(&apply_lock);
+       return r;
+}
+
+int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
+{
+       int r;
+
+       mutex_lock(&apply_lock);
+
+       if (!mgr->device) {
+               DSSERR("failed to unset display, display not set.\n");
+               r = -EINVAL;
+               goto err;
+       }
+
+       /*
+        * Don't allow currently enabled displays to have the overlay manager
+        * pulled out from underneath them
+        */
+       if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
+               r = -EINVAL;
+               goto err;
+       }
+
+       mgr->device->manager = NULL;
+       mgr->device = NULL;
+
+       mutex_unlock(&apply_lock);
+
+       return 0;
+err:
+       mutex_unlock(&apply_lock);
+       return r;
+}
+
+
+int dss_ovl_set_info(struct omap_overlay *ovl,
+               struct omap_overlay_info *info)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       unsigned long flags;
+       int r;
+
+       r = dss_ovl_simple_check(ovl, info);
+       if (r)
+               return r;
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       op->user_info = *info;
+       op->user_info_dirty = true;
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       return 0;
+}
+
+void dss_ovl_get_info(struct omap_overlay *ovl,
+               struct omap_overlay_info *info)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       unsigned long flags;
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       *info = op->user_info;
+
+       spin_unlock_irqrestore(&data_lock, flags);
+}
+
+int dss_ovl_set_manager(struct omap_overlay *ovl,
+               struct omap_overlay_manager *mgr)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       unsigned long flags;
+       int r;
+
+       if (!mgr)
+               return -EINVAL;
+
+       mutex_lock(&apply_lock);
+
+       if (ovl->manager) {
+               DSSERR("overlay '%s' already has a manager '%s'\n",
+                               ovl->name, ovl->manager->name);
+               r = -EINVAL;
+               goto err;
+       }
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       if (op->enabled) {
+               spin_unlock_irqrestore(&data_lock, flags);
+               DSSERR("overlay has to be disabled to change the manager\n");
+               r = -EINVAL;
+               goto err;
+       }
+
+       op->channel = mgr->id;
+       op->extra_info_dirty = true;
+
+       ovl->manager = mgr;
+       list_add_tail(&ovl->list, &mgr->overlays);
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       /* XXX: When there is an overlay on a DSI manual update display, and
+        * the overlay is first disabled, then moved to tv, and enabled, we
+        * seem to get SYNC_LOST_DIGIT error.
+        *
+        * Waiting doesn't seem to help, but updating the manual update display
+        * after disabling the overlay seems to fix this. This hints that the
+        * overlay is perhaps somehow tied to the LCD output until the output
+        * is updated.
+        *
+        * Userspace workaround for this is to update the LCD after disabling
+        * the overlay, but before moving the overlay to TV.
+        */
+
+       mutex_unlock(&apply_lock);
+
+       return 0;
+err:
+       mutex_unlock(&apply_lock);
+       return r;
+}
+
+int dss_ovl_unset_manager(struct omap_overlay *ovl)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       unsigned long flags;
+       int r;
+
+       mutex_lock(&apply_lock);
+
+       if (!ovl->manager) {
+               DSSERR("failed to detach overlay: manager not set\n");
+               r = -EINVAL;
+               goto err;
+       }
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       if (op->enabled) {
+               spin_unlock_irqrestore(&data_lock, flags);
+               DSSERR("overlay has to be disabled to unset the manager\n");
+               r = -EINVAL;
+               goto err;
+       }
+
+       op->channel = -1;
+
+       ovl->manager = NULL;
+       list_del(&ovl->list);
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       mutex_unlock(&apply_lock);
+
+       return 0;
+err:
+       mutex_unlock(&apply_lock);
+       return r;
+}
+
+bool dss_ovl_is_enabled(struct omap_overlay *ovl)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       unsigned long flags;
+       bool e;
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       e = op->enabled;
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       return e;
+}
+
+int dss_ovl_enable(struct omap_overlay *ovl)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       unsigned long flags;
+       int r;
+
+       mutex_lock(&apply_lock);
+
+       if (op->enabled) {
+               r = 0;
+               goto err1;
+       }
+
+       if (ovl->manager == NULL || ovl->manager->device == NULL) {
+               r = -EINVAL;
+               goto err1;
+       }
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       op->enabling = true;
+
+       r = dss_check_settings(ovl->manager, ovl->manager->device);
+       if (r) {
+               DSSERR("failed to enable overlay %d: check_settings failed\n",
+                               ovl->id);
+               goto err2;
+       }
+
+       dss_setup_fifos();
+
+       op->enabling = false;
+       dss_apply_ovl_enable(ovl, true);
+
+       dss_write_regs();
+       dss_set_go_bits();
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       mutex_unlock(&apply_lock);
+
+       return 0;
+err2:
+       op->enabling = false;
+       spin_unlock_irqrestore(&data_lock, flags);
+err1:
+       mutex_unlock(&apply_lock);
+       return r;
+}
+
+int dss_ovl_disable(struct omap_overlay *ovl)
+{
+       struct ovl_priv_data *op = get_ovl_priv(ovl);
+       unsigned long flags;
+       int r;
+
+       mutex_lock(&apply_lock);
+
+       if (!op->enabled) {
+               r = 0;
+               goto err;
+       }
+
+       if (ovl->manager == NULL || ovl->manager->device == NULL) {
+               r = -EINVAL;
+               goto err;
+       }
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       dss_apply_ovl_enable(ovl, false);
+       dss_write_regs();
+       dss_set_go_bits();
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       mutex_unlock(&apply_lock);
+
+       return 0;
+
+err:
+       mutex_unlock(&apply_lock);
+       return r;
+}
+
index 86ec12e16c7c4f8580a15c0e393daa3fb3420352..8613f86fb56d32b4f45cf1f5900e5edea69abe9c 100644 (file)
@@ -50,7 +50,7 @@ module_param_named(def_disp, def_disp_name, charp, 0);
 MODULE_PARM_DESC(def_disp, "default display name");
 
 #ifdef DEBUG
-unsigned int dss_debug;
+bool dss_debug;
 module_param_named(debug, dss_debug, bool, 0644);
 #endif
 
@@ -178,6 +178,8 @@ static int omap_dss_probe(struct platform_device *pdev)
 
        dss_features_init();
 
+       dss_apply_init();
+
        dss_init_overlay_managers(pdev);
        dss_init_overlays(pdev);
 
index 5c81533eacaa6224c3aed27d0c1e72a60616c3d7..a5ec7f37c1857f99fdd411e38e0384f05c3e1936 100644 (file)
@@ -64,22 +64,6 @@ struct omap_dispc_isr_data {
        u32                     mask;
 };
 
-struct dispc_h_coef {
-       s8 hc4;
-       s8 hc3;
-       u8 hc2;
-       s8 hc1;
-       s8 hc0;
-};
-
-struct dispc_v_coef {
-       s8 vc22;
-       s8 vc2;
-       u8 vc1;
-       s8 vc0;
-       s8 vc00;
-};
-
 enum omap_burst_size {
        BURST_SIZE_X2 = 0,
        BURST_SIZE_X4 = 1,
@@ -438,6 +422,34 @@ static struct omap_dss_device *dispc_mgr_get_device(enum omap_channel channel)
        return mgr ? mgr->device : NULL;
 }
 
+u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return DISPC_IRQ_VSYNC;
+       case OMAP_DSS_CHANNEL_LCD2:
+               return DISPC_IRQ_VSYNC2;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               return DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
+       default:
+               BUG();
+       }
+}
+
+u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return DISPC_IRQ_FRAMEDONE;
+       case OMAP_DSS_CHANNEL_LCD2:
+               return DISPC_IRQ_FRAMEDONE2;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               return 0;
+       default:
+               BUG();
+       }
+}
+
 bool dispc_mgr_go_busy(enum omap_channel channel)
 {
        int bit;
@@ -533,105 +545,27 @@ static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
        dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
 }
 
-static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup,
-                                 int vscaleup, int five_taps,
-                                 enum omap_color_component color_comp)
-{
-       /* Coefficients for horizontal up-sampling */
-       static const struct dispc_h_coef coef_hup[8] = {
-               {  0,   0, 128,   0,  0 },
-               { -1,  13, 124,  -8,  0 },
-               { -2,  30, 112, -11, -1 },
-               { -5,  51,  95, -11, -2 },
-               {  0,  -9,  73,  73, -9 },
-               { -2, -11,  95,  51, -5 },
-               { -1, -11, 112,  30, -2 },
-               {  0,  -8, 124,  13, -1 },
-       };
-
-       /* Coefficients for vertical up-sampling */
-       static const struct dispc_v_coef coef_vup_3tap[8] = {
-               { 0,  0, 128,  0, 0 },
-               { 0,  3, 123,  2, 0 },
-               { 0, 12, 111,  5, 0 },
-               { 0, 32,  89,  7, 0 },
-               { 0,  0,  64, 64, 0 },
-               { 0,  7,  89, 32, 0 },
-               { 0,  5, 111, 12, 0 },
-               { 0,  2, 123,  3, 0 },
-       };
-
-       static const struct dispc_v_coef coef_vup_5tap[8] = {
-               {  0,   0, 128,   0,  0 },
-               { -1,  13, 124,  -8,  0 },
-               { -2,  30, 112, -11, -1 },
-               { -5,  51,  95, -11, -2 },
-               {  0,  -9,  73,  73, -9 },
-               { -2, -11,  95,  51, -5 },
-               { -1, -11, 112,  30, -2 },
-               {  0,  -8, 124,  13, -1 },
-       };
-
-       /* Coefficients for horizontal down-sampling */
-       static const struct dispc_h_coef coef_hdown[8] = {
-               {   0, 36, 56, 36,  0 },
-               {   4, 40, 55, 31, -2 },
-               {   8, 44, 54, 27, -5 },
-               {  12, 48, 53, 22, -7 },
-               {  -9, 17, 52, 51, 17 },
-               {  -7, 22, 53, 48, 12 },
-               {  -5, 27, 54, 44,  8 },
-               {  -2, 31, 55, 40,  4 },
-       };
-
-       /* Coefficients for vertical down-sampling */
-       static const struct dispc_v_coef coef_vdown_3tap[8] = {
-               { 0, 36, 56, 36, 0 },
-               { 0, 40, 57, 31, 0 },
-               { 0, 45, 56, 27, 0 },
-               { 0, 50, 55, 23, 0 },
-               { 0, 18, 55, 55, 0 },
-               { 0, 23, 55, 50, 0 },
-               { 0, 27, 56, 45, 0 },
-               { 0, 31, 57, 40, 0 },
-       };
-
-       static const struct dispc_v_coef coef_vdown_5tap[8] = {
-               {   0, 36, 56, 36,  0 },
-               {   4, 40, 55, 31, -2 },
-               {   8, 44, 54, 27, -5 },
-               {  12, 48, 53, 22, -7 },
-               {  -9, 17, 52, 51, 17 },
-               {  -7, 22, 53, 48, 12 },
-               {  -5, 27, 54, 44,  8 },
-               {  -2, 31, 55, 40,  4 },
-       };
-
-       const struct dispc_h_coef *h_coef;
-       const struct dispc_v_coef *v_coef;
+static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc,
+                               int fir_vinc, int five_taps,
+                               enum omap_color_component color_comp)
+{
+       const struct dispc_coef *h_coef, *v_coef;
        int i;
 
-       if (hscaleup)
-               h_coef = coef_hup;
-       else
-               h_coef = coef_hdown;
-
-       if (vscaleup)
-               v_coef = five_taps ? coef_vup_5tap : coef_vup_3tap;
-       else
-               v_coef = five_taps ? coef_vdown_5tap : coef_vdown_3tap;
+       h_coef = dispc_ovl_get_scale_coef(fir_hinc, true);
+       v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps);
 
        for (i = 0; i < 8; i++) {
                u32 h, hv;
 
-               h = FLD_VAL(h_coef[i].hc0, 7, 0)
-                       | FLD_VAL(h_coef[i].hc1, 15, 8)
-                       | FLD_VAL(h_coef[i].hc2, 23, 16)
-                       | FLD_VAL(h_coef[i].hc3, 31, 24);
-               hv = FLD_VAL(h_coef[i].hc4, 7, 0)
-                       | FLD_VAL(v_coef[i].vc0, 15, 8)
-                       | FLD_VAL(v_coef[i].vc1, 23, 16)
-                       | FLD_VAL(v_coef[i].vc2, 31, 24);
+               h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0)
+                       | FLD_VAL(h_coef[i].hc1_vc0, 15, 8)
+                       | FLD_VAL(h_coef[i].hc2_vc1, 23, 16)
+                       | FLD_VAL(h_coef[i].hc3_vc2, 31, 24);
+               hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0)
+                       | FLD_VAL(v_coef[i].hc1_vc0, 15, 8)
+                       | FLD_VAL(v_coef[i].hc2_vc1, 23, 16)
+                       | FLD_VAL(v_coef[i].hc3_vc2, 31, 24);
 
                if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
                        dispc_ovl_write_firh_reg(plane, i, h);
@@ -646,8 +580,8 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup,
        if (five_taps) {
                for (i = 0; i < 8; i++) {
                        u32 v;
-                       v = FLD_VAL(v_coef[i].vc00, 7, 0)
-                               | FLD_VAL(v_coef[i].vc22, 15, 8);
+                       v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0)
+                               | FLD_VAL(v_coef[i].hc4_vc22, 15, 8);
                        if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
                                dispc_ovl_write_firv_reg(plane, i, v);
                        else
@@ -875,8 +809,7 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane,
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
 }
 
-static void dispc_ovl_set_channel_out(enum omap_plane plane,
-               enum omap_channel channel)
+void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel)
 {
        int shift;
        u32 val;
@@ -923,6 +856,39 @@ static void dispc_ovl_set_channel_out(enum omap_plane plane,
        dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
 }
 
+static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
+{
+       int shift;
+       u32 val;
+       enum omap_channel channel;
+
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               shift = 8;
+               break;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+       case OMAP_DSS_VIDEO3:
+               shift = 16;
+               break;
+       default:
+               BUG();
+       }
+
+       val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
+
+       if (dss_has_feature(FEAT_MGR_LCD2)) {
+               if (FLD_GET(val, 31, 30) == 0)
+                       channel = FLD_GET(val, shift, shift);
+               else
+                       channel = OMAP_DSS_CHANNEL_LCD2;
+       } else {
+               channel = FLD_GET(val, shift, shift);
+       }
+
+       return channel;
+}
+
 static void dispc_ovl_set_burst_size(enum omap_plane plane,
                enum omap_burst_size burst_size)
 {
@@ -964,7 +930,7 @@ void dispc_enable_gamma_table(bool enable)
        REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
 }
 
-void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
+static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
 {
        u16 reg;
 
@@ -978,7 +944,7 @@ void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
        REG_FLD_MOD(reg, enable, 15, 15);
 }
 
-void dispc_mgr_set_cpr_coef(enum omap_channel channel,
+static void dispc_mgr_set_cpr_coef(enum omap_channel channel,
                struct omap_dss_cpr_coefs *coefs)
 {
        u32 coef_r, coef_g, coef_b;
@@ -1057,8 +1023,7 @@ u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
        return dispc.fifo_size[plane];
 }
 
-static void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low,
-               u32 high)
+void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
 {
        u8 hi_start, hi_end, lo_start, lo_end;
        u32 unit;
@@ -1169,17 +1134,12 @@ static void dispc_ovl_set_scale_param(enum omap_plane plane,
                enum omap_color_component color_comp)
 {
        int fir_hinc, fir_vinc;
-       int hscaleup, vscaleup;
-
-       hscaleup = orig_width <= out_width;
-       vscaleup = orig_height <= out_height;
-
-       dispc_ovl_set_scale_coef(plane, hscaleup, vscaleup, five_taps,
-                       color_comp);
 
        fir_hinc = 1024 * orig_width / out_width;
        fir_vinc = 1024 * orig_height / out_height;
 
+       dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps,
+                               color_comp);
        dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp);
 }
 
@@ -1654,6 +1614,9 @@ static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width,
        u32 fclk = 0;
        u64 tmp, pclk = dispc_mgr_pclk_rate(channel);
 
+       if (height <= out_height && width <= out_width)
+               return (unsigned long) pclk;
+
        if (height > out_height) {
                struct omap_dss_device *dssdev = dispc_mgr_get_device(channel);
                unsigned int ppl = dssdev->panel.timings.x_res;
@@ -1708,7 +1671,16 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width,
        else
                vf = 1;
 
-       return dispc_mgr_pclk_rate(channel) * vf * hf;
+       if (cpu_is_omap24xx()) {
+               if (vf > 1 && hf > 1)
+                       return dispc_mgr_pclk_rate(channel) * 4;
+               else
+                       return dispc_mgr_pclk_rate(channel) * 2;
+       } else if (cpu_is_omap34xx()) {
+               return dispc_mgr_pclk_rate(channel) * vf * hf;
+       } else {
+               return dispc_mgr_pclk_rate(channel) * hf;
+       }
 }
 
 static int dispc_ovl_calc_scaling(enum omap_plane plane,
@@ -1718,6 +1690,8 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
 {
        struct omap_overlay *ovl = omap_dss_get_overlay(plane);
        const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
+       const int maxsinglelinewidth =
+                               dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
        unsigned long fclk = 0;
 
        if (width == out_width && height == out_height)
@@ -1734,28 +1708,40 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
                        out_height > height * 8)
                return -EINVAL;
 
-       /* Must use 5-tap filter? */
-       *five_taps = height > out_height * 2;
-
-       if (!*five_taps) {
+       if (cpu_is_omap24xx()) {
+               if (width > maxsinglelinewidth)
+                       DSSERR("Cannot scale max input width exceeded");
+               *five_taps = false;
+               fclk = calc_fclk(channel, width, height, out_width,
+                                                               out_height);
+       } else if (cpu_is_omap34xx()) {
+               if (width > (maxsinglelinewidth * 2)) {
+                       DSSERR("Cannot setup scaling");
+                       DSSERR("width exceeds maximum width possible");
+                       return -EINVAL;
+               }
+               fclk = calc_fclk_five_taps(channel, width, height, out_width,
+                                               out_height, color_mode);
+               if (width > maxsinglelinewidth) {
+                       if (height > out_height && height < out_height * 2)
+                               *five_taps = false;
+                       else {
+                               DSSERR("cannot setup scaling with five taps");
+                               return -EINVAL;
+                       }
+               }
+               if (!*five_taps)
+                       fclk = calc_fclk(channel, width, height, out_width,
+                                       out_height);
+       } else {
+               if (width > maxsinglelinewidth) {
+                       DSSERR("Cannot scale width exceeds max line width");
+                       return -EINVAL;
+               }
                fclk = calc_fclk(channel, width, height, out_width,
                                out_height);
-
-               /* Try 5-tap filter if 3-tap fclk is too high */
-               if (cpu_is_omap34xx() && height > out_height &&
-                               fclk > dispc_fclk_rate())
-                       *five_taps = true;
-       }
-
-       if (width > (2048 >> *five_taps)) {
-               DSSERR("failed to set up scaling, fclk too low\n");
-               return -EINVAL;
        }
 
-       if (*five_taps)
-               fclk = calc_fclk_five_taps(channel, width, height,
-                               out_width, out_height, color_mode);
-
        DSSDBG("required fclk rate = %lu Hz\n", fclk);
        DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
 
@@ -1771,11 +1757,10 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
 }
 
 int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
-               bool ilace, enum omap_channel channel, bool replication,
-               u32 fifo_low, u32 fifo_high)
+               bool ilace, bool replication)
 {
        struct omap_overlay *ovl = omap_dss_get_overlay(plane);
-       bool five_taps = false;
+       bool five_taps = true;
        bool fieldmode = 0;
        int r, cconv = 0;
        unsigned offset0, offset1;
@@ -1783,36 +1768,43 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
        s32 pix_inc;
        u16 frame_height = oi->height;
        unsigned int field_offset = 0;
+       u16 outw, outh;
+       enum omap_channel channel;
+
+       channel = dispc_ovl_get_channel_out(plane);
 
        DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
-               "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d "
-               "fifo_low %d fifo high %d\n", plane, oi->paddr, oi->p_uv_addr,
+               "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n",
+               plane, oi->paddr, oi->p_uv_addr,
                oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
                oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
-               oi->mirror, ilace, channel, replication, fifo_low, fifo_high);
+               oi->mirror, ilace, channel, replication);
 
        if (oi->paddr == 0)
                return -EINVAL;
 
-       if (ilace && oi->height == oi->out_height)
+       outw = oi->out_width == 0 ? oi->width : oi->out_width;
+       outh = oi->out_height == 0 ? oi->height : oi->out_height;
+
+       if (ilace && oi->height == outh)
                fieldmode = 1;
 
        if (ilace) {
                if (fieldmode)
                        oi->height /= 2;
                oi->pos_y /= 2;
-               oi->out_height /= 2;
+               outh /= 2;
 
                DSSDBG("adjusting for ilace: height %d, pos_y %d, "
                                "out_height %d\n",
-                               oi->height, oi->pos_y, oi->out_height);
+                               oi->height, oi->pos_y, outh);
        }
 
        if (!dss_feat_color_mode_supported(plane, oi->color_mode))
                return -EINVAL;
 
        r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height,
-                       oi->out_width, oi->out_height, oi->color_mode,
+                       outw, outh, oi->color_mode,
                        &five_taps);
        if (r)
                return r;
@@ -1830,10 +1822,10 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
                 * so the integer part must be added to the base address of the
                 * bottom field.
                 */
-               if (!oi->height || oi->height == oi->out_height)
+               if (!oi->height || oi->height == outh)
                        field_offset = 0;
                else
-                       field_offset = oi->height / oi->out_height / 2;
+                       field_offset = oi->height / outh / 2;
        }
 
        /* Fields are independent but interleaved in memory. */
@@ -1869,7 +1861,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
        dispc_ovl_set_pix_inc(plane, pix_inc);
 
        DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width,
-                       oi->height, oi->out_width, oi->out_height);
+                       oi->height, outw, outh);
 
        dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y);
 
@@ -1877,10 +1869,10 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
 
        if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) {
                dispc_ovl_set_scaling(plane, oi->width, oi->height,
-                                  oi->out_width, oi->out_height,
+                                  outw, outh,
                                   ilace, five_taps, fieldmode,
                                   oi->color_mode, oi->rotation);
-               dispc_ovl_set_vid_size(plane, oi->out_width, oi->out_height);
+               dispc_ovl_set_vid_size(plane, outw, outh);
                dispc_ovl_set_vid_color_conv(plane, cconv);
        }
 
@@ -1891,10 +1883,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
        dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha);
        dispc_ovl_setup_global_alpha(plane, oi->global_alpha);
 
-       dispc_ovl_set_channel_out(plane, channel);
-
        dispc_ovl_enable_replication(plane, replication);
-       dispc_ovl_set_fifo_threshold(plane, fifo_low, fifo_high);
 
        return 0;
 }
@@ -1916,10 +1905,14 @@ static void dispc_disable_isr(void *data, u32 mask)
 
 static void _enable_lcd_out(enum omap_channel channel, bool enable)
 {
-       if (channel == OMAP_DSS_CHANNEL_LCD2)
+       if (channel == OMAP_DSS_CHANNEL_LCD2) {
                REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0);
-       else
+               /* flush posted write */
+               dispc_read_reg(DISPC_CONTROL2);
+       } else {
                REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
+               dispc_read_reg(DISPC_CONTROL);
+       }
 }
 
 static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable)
@@ -1967,6 +1960,8 @@ static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable)
 static void _enable_digit_out(bool enable)
 {
        REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
+       /* flush posted write */
+       dispc_read_reg(DISPC_CONTROL);
 }
 
 static void dispc_mgr_enable_digit_out(bool enable)
@@ -2124,25 +2119,12 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode)
 }
 
 
-void dispc_mgr_set_default_color(enum omap_channel channel, u32 color)
+static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color)
 {
        dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
 }
 
-u32 dispc_mgr_get_default_color(enum omap_channel channel)
-{
-       u32 l;
-
-       BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
-               channel != OMAP_DSS_CHANNEL_LCD &&
-               channel != OMAP_DSS_CHANNEL_LCD2);
-
-       l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel));
-
-       return l;
-}
-
-void dispc_mgr_set_trans_key(enum omap_channel ch,
+static void dispc_mgr_set_trans_key(enum omap_channel ch,
                enum omap_dss_trans_key_type type,
                u32 trans_key)
 {
@@ -2156,26 +2138,7 @@ void dispc_mgr_set_trans_key(enum omap_channel ch,
        dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
 }
 
-void dispc_mgr_get_trans_key(enum omap_channel ch,
-               enum omap_dss_trans_key_type *type,
-               u32 *trans_key)
-{
-       if (type) {
-               if (ch == OMAP_DSS_CHANNEL_LCD)
-                       *type = REG_GET(DISPC_CONFIG, 11, 11);
-               else if (ch == OMAP_DSS_CHANNEL_DIGIT)
-                       *type = REG_GET(DISPC_CONFIG, 13, 13);
-               else if (ch == OMAP_DSS_CHANNEL_LCD2)
-                       *type = REG_GET(DISPC_CONFIG2, 11, 11);
-               else
-                       BUG();
-       }
-
-       if (trans_key)
-               *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch));
-}
-
-void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
+static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
 {
        if (ch == OMAP_DSS_CHANNEL_LCD)
                REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
@@ -2185,7 +2148,8 @@ void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
                REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10);
 }
 
-void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable)
+static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch,
+               bool enable)
 {
        if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
                return;
@@ -2196,40 +2160,20 @@ void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable)
                REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
 }
 
-bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch)
-{
-       bool enabled;
-
-       if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
-               return false;
-
-       if (ch == OMAP_DSS_CHANNEL_LCD)
-               enabled = REG_GET(DISPC_CONFIG, 18, 18);
-       else if (ch == OMAP_DSS_CHANNEL_DIGIT)
-               enabled = REG_GET(DISPC_CONFIG, 19, 19);
-       else
-               BUG();
-
-       return enabled;
-}
-
-bool dispc_mgr_trans_key_enabled(enum omap_channel ch)
+void dispc_mgr_setup(enum omap_channel channel,
+               struct omap_overlay_manager_info *info)
 {
-       bool enabled;
-
-       if (ch == OMAP_DSS_CHANNEL_LCD)
-               enabled = REG_GET(DISPC_CONFIG, 10, 10);
-       else if (ch == OMAP_DSS_CHANNEL_DIGIT)
-               enabled = REG_GET(DISPC_CONFIG, 12, 12);
-       else if (ch == OMAP_DSS_CHANNEL_LCD2)
-               enabled = REG_GET(DISPC_CONFIG2, 10, 10);
-       else
-               BUG();
-
-       return enabled;
+       dispc_mgr_set_default_color(channel, info->default_color);
+       dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key);
+       dispc_mgr_enable_trans_key(channel, info->trans_enabled);
+       dispc_mgr_enable_alpha_fixed_zorder(channel,
+                       info->partial_alpha_enabled);
+       if (dss_has_feature(FEAT_CPR)) {
+               dispc_mgr_enable_cpr(channel, info->cpr_enable);
+               dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs);
+       }
 }
 
-
 void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
 {
        int code;
@@ -3184,7 +3128,8 @@ static void dispc_error_worker(struct work_struct *work)
                for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
                        struct omap_overlay_manager *mgr;
                        mgr = omap_dss_get_overlay_manager(i);
-                       mgr->device->driver->disable(mgr->device);
+                       if (mgr->device && mgr->device->driver)
+                               mgr->device->driver->disable(mgr->device);
                }
        }
 
index c06efc38983e6ee74d8562fcfb9debaef545c843..5836bd1650f9a93c53430734361065c47fef4c26 100644 (file)
 #define DISPC_OVL_PRELOAD(n)           (DISPC_OVL_BASE(n) + \
                                        DISPC_PRELOAD_OFFSET(n))
 
+/* DISPC up/downsampling FIR filter coefficient structure */
+struct dispc_coef {
+       s8 hc4_vc22;
+       s8 hc3_vc2;
+       u8 hc2_vc1;
+       s8 hc1_vc0;
+       s8 hc0_vc00;
+};
+
+const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps);
+
 /* DISPC manager/channel specific registers */
 static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel)
 {
diff --git a/drivers/video/omap2/dss/dispc_coefs.c b/drivers/video/omap2/dss/dispc_coefs.c
new file mode 100644 (file)
index 0000000..069bccb
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * linux/drivers/video/omap2/dss/dispc_coefs.c
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Chandrabhanu Mahapatra <cmahapatra@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <video/omapdss.h>
+#include "dispc.h"
+
+#define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
+
+static const struct dispc_coef coef3_M8[8] = {
+       { 0,  0, 128,  0, 0 },
+       { 0, -4, 123,  9, 0 },
+       { 0, -4, 108, 87, 0 },
+       { 0, -2,  87, 43, 0 },
+       { 0, 64,  64,  0, 0 },
+       { 0, 43,  87, -2, 0 },
+       { 0, 24, 108, -4, 0 },
+       { 0,  9, 123, -4, 0 },
+};
+
+static const struct dispc_coef coef3_M9[8] = {
+       { 0,  6, 116,  6, 0 },
+       { 0,  0, 112, 16, 0 },
+       { 0, -2, 100, 30, 0 },
+       { 0, -2,  83, 47, 0 },
+       { 0, 64,  64,  0, 0 },
+       { 0, 47,  83, -2, 0 },
+       { 0, 30, 100, -2, 0 },
+       { 0, 16, 112,  0, 0 },
+};
+
+static const struct dispc_coef coef3_M10[8] = {
+       { 0, 10, 108, 10, 0 },
+       { 0,  3, 104, 21, 0 },
+       { 0,  0,  94, 34, 0 },
+       { 0, -1,  80, 49, 0 },
+       { 0, 64,  64,  0, 0 },
+       { 0, 49,  80, -1, 0 },
+       { 0, 34,  94,  0, 0 },
+       { 0, 21, 104,  3, 0 },
+};
+
+static const struct dispc_coef coef3_M11[8] = {
+       { 0, 14, 100, 14, 0 },
+       { 0,  6,  98, 24, 0 },
+       { 0,  2,  90, 36, 0 },
+       { 0,  0,  78, 50, 0 },
+       { 0, 64,  64,  0, 0 },
+       { 0, 50,  78,  0, 0 },
+       { 0, 36,  90,  2, 0 },
+       { 0, 24,  98,  6, 0 },
+};
+
+static const struct dispc_coef coef3_M12[8] = {
+       { 0, 16,  96, 16, 0 },
+       { 0,  9,  93, 26, 0 },
+       { 0,  4,  86, 38, 0 },
+       { 0,  1,  76, 51, 0 },
+       { 0, 64,  64,  0, 0 },
+       { 0, 51,  76,  1, 0 },
+       { 0, 38,  86,  4, 0 },
+       { 0, 26,  93,  9, 0 },
+};
+
+static const struct dispc_coef coef3_M13[8] = {
+       { 0, 18,  92, 18, 0 },
+       { 0, 10,  90, 28, 0 },
+       { 0,  5,  83, 40, 0 },
+       { 0,  1,  75, 52, 0 },
+       { 0, 64,  64,  0, 0 },
+       { 0, 52,  75,  1, 0 },
+       { 0, 40,  83,  5, 0 },
+       { 0, 28,  90, 10, 0 },
+};
+
+static const struct dispc_coef coef3_M14[8] = {
+       { 0, 20, 88, 20, 0 },
+       { 0, 12, 86, 30, 0 },
+       { 0,  6, 81, 41, 0 },
+       { 0,  2, 74, 52, 0 },
+       { 0, 64, 64,  0, 0 },
+       { 0, 52, 74,  2, 0 },
+       { 0, 41, 81,  6, 0 },
+       { 0, 30, 86, 12, 0 },
+};
+
+static const struct dispc_coef coef3_M16[8] = {
+       { 0, 22, 84, 22, 0 },
+       { 0, 14, 82, 32, 0 },
+       { 0,  8, 78, 42, 0 },
+       { 0,  3, 72, 53, 0 },
+       { 0, 64, 64,  0, 0 },
+       { 0, 53, 72,  3, 0 },
+       { 0, 42, 78,  8, 0 },
+       { 0, 32, 82, 14, 0 },
+};
+
+static const struct dispc_coef coef3_M19[8] = {
+       { 0, 24, 80, 24, 0 },
+       { 0, 16, 79, 33, 0 },
+       { 0,  9, 76, 43, 0 },
+       { 0,  4, 70, 54, 0 },
+       { 0, 64, 64,  0, 0 },
+       { 0, 54, 70,  4, 0 },
+       { 0, 43, 76,  9, 0 },
+       { 0, 33, 79, 16, 0 },
+};
+
+static const struct dispc_coef coef3_M22[8] = {
+       { 0, 25, 78, 25, 0 },
+       { 0, 17, 77, 34, 0 },
+       { 0, 10, 74, 44, 0 },
+       { 0,  5, 69, 54, 0 },
+       { 0, 64, 64,  0, 0 },
+       { 0, 54, 69,  5, 0 },
+       { 0, 44, 74, 10, 0 },
+       { 0, 34, 77, 17, 0 },
+};
+
+static const struct dispc_coef coef3_M26[8] = {
+       { 0, 26, 76, 26, 0 },
+       { 0, 19, 74, 35, 0 },
+       { 0, 11, 72, 45, 0 },
+       { 0,  5, 69, 54, 0 },
+       { 0, 64, 64,  0, 0 },
+       { 0, 54, 69,  5, 0 },
+       { 0, 45, 72, 11, 0 },
+       { 0, 35, 74, 19, 0 },
+};
+
+static const struct dispc_coef coef3_M32[8] = {
+       { 0, 27, 74, 27, 0 },
+       { 0, 19, 73, 36, 0 },
+       { 0, 12, 71, 45, 0 },
+       { 0,  6, 68, 54, 0 },
+       { 0, 64, 64,  0, 0 },
+       { 0, 54, 68,  6, 0 },
+       { 0, 45, 71, 12, 0 },
+       { 0, 36, 73, 19, 0 },
+};
+
+static const struct dispc_coef coef5_M8[8] = {
+       {   0,   0, 128,   0,   0 },
+       {  -2,  14, 125, -10,   1 },
+       {  -6,  33, 114, -15,   2 },
+       { -10,  55,  98, -16,   1 },
+       {   0, -14,  78,  78, -14 },
+       {   1, -16,  98,  55, -10 },
+       {   2, -15, 114,  33,  -6 },
+       {   1, -10, 125,  14,  -2 },
+};
+
+static const struct dispc_coef coef5_M9[8] = {
+       {  -3,  10, 114,  10,  -3 },
+       {  -6,  24, 110,   0,  -1 },
+       {  -8,  40, 103,  -7,   0 },
+       { -11,  58,  91, -11,   1 },
+       {   0, -12,  76,  76, -12 },
+       {   1, -11,  91,  58, -11 },
+       {   0,  -7, 103,  40,  -8 },
+       {  -1,   0, 111,  24,  -6 },
+};
+
+static const struct dispc_coef coef5_M10[8] = {
+       {  -4,  18, 100,  18,  -4 },
+       {  -6,  30,  99,   8,  -3 },
+       {  -8,  44,  93,   0,  -1 },
+       {  -9,  58,  84,  -5,   0 },
+       {   0,  -8,  72,  72,  -8 },
+       {   0,  -5,  84,  58,  -9 },
+       {  -1,   0,  93,  44,  -8 },
+       {  -3,   8,  99,  30,  -6 },
+};
+
+static const struct dispc_coef coef5_M11[8] = {
+       {  -5,  23,  92,  23,  -5 },
+       {  -6,  34,  90,  13,  -3 },
+       {  -6,  45,  85,   6,  -2 },
+       {  -6,  57,  78,   0,  -1 },
+       {   0,  -4,  68,  68,  -4 },
+       {  -1,   0,  78,  57,  -6 },
+       {  -2,   6,  85,  45,  -6 },
+       {  -3,  13,  90,  34,  -6 },
+};
+
+static const struct dispc_coef coef5_M12[8] = {
+       {  -4,  26,  84,  26,  -4 },
+       {  -5,  36,  82,  18,  -3 },
+       {  -4,  46,  78,  10,  -2 },
+       {  -3,  55,  72,   5,  -1 },
+       {   0,   0,  64,  64,   0 },
+       {  -1,   5,  72,  55,  -3 },
+       {  -2,  10,  78,  46,  -4 },
+       {  -3,  18,  82,  36,  -5 },
+};
+
+static const struct dispc_coef coef5_M13[8] = {
+       {  -3,  28,  78,  28,  -3 },
+       {  -3,  37,  76,  21,  -3 },
+       {  -2,  45,  73,  14,  -2 },
+       {   0,  53,  68,   8,  -1 },
+       {   0,   3,  61,  61,   3 },
+       {  -1,   8,  68,  53,   0 },
+       {  -2,  14,  73,  45,  -2 },
+       {  -3,  21,  76,  37,  -3 },
+};
+
+static const struct dispc_coef coef5_M14[8] = {
+       {  -2,  30,  72,  30,  -2 },
+       {  -1,  37,  71,  23,  -2 },
+       {   0,  45,  69,  16,  -2 },
+       {   3,  52,  64,  10,  -1 },
+       {   0,   6,  58,  58,   6 },
+       {  -1,  10,  64,  52,   3 },
+       {  -2,  16,  69,  45,   0 },
+       {  -2,  23,  71,  37,  -1 },
+};
+
+static const struct dispc_coef coef5_M16[8] = {
+       {   0,  31,  66,  31,   0 },
+       {   1,  38,  65,  25,  -1 },
+       {   3,  44,  62,  20,  -1 },
+       {   6,  49,  59,  14,   0 },
+       {   0,  10,  54,  54,  10 },
+       {   0,  14,  59,  49,   6 },
+       {  -1,  20,  62,  44,   3 },
+       {  -1,  25,  65,  38,   1 },
+};
+
+static const struct dispc_coef coef5_M19[8] = {
+       {   3,  32,  58,  32,   3 },
+       {   4,  38,  58,  27,   1 },
+       {   7,  42,  55,  23,   1 },
+       {  10,  46,  54,  18,   0 },
+       {   0,  14,  50,  50,  14 },
+       {   0,  18,  54,  46,  10 },
+       {   1,  23,  55,  42,   7 },
+       {   1,  27,  58,  38,   4 },
+};
+
+static const struct dispc_coef coef5_M22[8] = {
+       {   4,  33,  54,  33,   4 },
+       {   6,  37,  54,  28,   3 },
+       {   9,  41,  53,  24,   1 },
+       {  12,  45,  51,  20,   0 },
+       {   0,  16,  48,  48,  16 },
+       {   0,  20,  51,  45,  12 },
+       {   1,  24,  53,  41,   9 },
+       {   3,  28,  54,  37,   6 },
+};
+
+static const struct dispc_coef coef5_M26[8] = {
+       {   6,  33,  50,  33,   6 },
+       {   8,  36,  51,  29,   4 },
+       {  11,  40,  50,  25,   2 },
+       {  14,  43,  48,  22,   1 },
+       {   0,  18,  46,  46,  18 },
+       {   1,  22,  48,  43,  14 },
+       {   2,  25,  50,  40,  11 },
+       {   4,  29,  51,  36,   8 },
+};
+
+static const struct dispc_coef coef5_M32[8] = {
+       {   7,  33,  48,  33,   7 },
+       {  10,  36,  48,  29,   5 },
+       {  13,  39,  47,  26,   3 },
+       {  16,  42,  46,  23,   1 },
+       {   0,  19,  45,  45,  19 },
+       {   1,  23,  46,  42,  16 },
+       {   3,  26,  47,  39,  13 },
+       {   5,  29,  48,  36,  10 },
+};
+
+const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps)
+{
+       int i;
+       static const struct {
+               int Mmin;
+               int Mmax;
+               const struct dispc_coef *coef_3;
+               const struct dispc_coef *coef_5;
+       } coefs[] = {
+               { 27, 32, coef3_M32, coef5_M32 },
+               { 23, 26, coef3_M26, coef5_M26 },
+               { 20, 22, coef3_M22, coef5_M22 },
+               { 17, 19, coef3_M19, coef5_M19 },
+               { 15, 16, coef3_M16, coef5_M16 },
+               { 14, 14, coef3_M14, coef5_M14 },
+               { 13, 13, coef3_M13, coef5_M13 },
+               { 12, 12, coef3_M12, coef5_M12 },
+               { 11, 11, coef3_M11, coef5_M11 },
+               { 10, 10, coef3_M10, coef5_M10 },
+               {  9,  9,  coef3_M9,  coef5_M9 },
+               {  4,  8,  coef3_M8,  coef5_M8 },
+               /*
+                * When upscaling more than two times, blockiness and outlines
+                * around the image are observed when M8 tables are used. M11,
+                * M16 and M19 tables are used to prevent this.
+                */
+               {  3,  3, coef3_M11, coef5_M11 },
+               {  2,  2, coef3_M16, coef5_M16 },
+               {  0,  1, coef3_M19, coef5_M19 },
+       };
+
+       inc /= 128;
+       for (i = 0; i < ARRAY_LEN(coefs); ++i)
+               if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax)
+                       return five_taps ? coefs[i].coef_5 : coefs[i].coef_3;
+       return NULL;
+}
index 976ac23dcd0cc3e25f3b400d62e20899911b966d..395d658a94fcab1e7e54131e96485b379fee07a7 100644 (file)
@@ -223,10 +223,13 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
 
        mdelay(2);
 
-       dssdev->manager->enable(dssdev->manager);
+       r = dss_mgr_enable(dssdev->manager);
+       if (r)
+               goto err_mgr_enable;
 
        return 0;
 
+err_mgr_enable:
 err_set_mode:
        if (dpi_use_dsi_pll(dssdev))
                dsi_pll_uninit(dpi.dsidev, true);
@@ -249,7 +252,7 @@ EXPORT_SYMBOL(omapdss_dpi_display_enable);
 
 void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
 {
-       dssdev->manager->disable(dssdev->manager);
+       dss_mgr_disable(dssdev->manager);
 
        if (dpi_use_dsi_pll(dssdev)) {
                dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
index 5abf8e7e74565fb1f70794dd21b7be9d65c97dc4..d4d676c82c12fbe9789edc354c85b5a14bd19cbb 100644 (file)
@@ -203,6 +203,21 @@ struct dsi_reg { u16 idx; };
 typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
 
 #define DSI_MAX_NR_ISRS                2
+#define DSI_MAX_NR_LANES       5
+
+enum dsi_lane_function {
+       DSI_LANE_UNUSED = 0,
+       DSI_LANE_CLK,
+       DSI_LANE_DATA1,
+       DSI_LANE_DATA2,
+       DSI_LANE_DATA3,
+       DSI_LANE_DATA4,
+};
+
+struct dsi_lane_config {
+       enum dsi_lane_function function;
+       u8 polarity;
+};
 
 struct dsi_isr_data {
        omap_dsi_isr_t  isr;
@@ -223,24 +238,6 @@ enum dsi_vc_source {
        DSI_VC_SOURCE_VP,
 };
 
-enum dsi_lane {
-       DSI_CLK_P       = 1 << 0,
-       DSI_CLK_N       = 1 << 1,
-       DSI_DATA1_P     = 1 << 2,
-       DSI_DATA1_N     = 1 << 3,
-       DSI_DATA2_P     = 1 << 4,
-       DSI_DATA2_N     = 1 << 5,
-       DSI_DATA3_P     = 1 << 6,
-       DSI_DATA3_N     = 1 << 7,
-       DSI_DATA4_P     = 1 << 8,
-       DSI_DATA4_N     = 1 << 9,
-};
-
-struct dsi_update_region {
-       u16 x, y, w, h;
-       struct omap_dss_device *device;
-};
-
 struct dsi_irq_stats {
        unsigned long last_reset;
        unsigned irq_count;
@@ -290,7 +287,9 @@ struct dsi_data {
        struct dsi_isr_tables isr_tables_copy;
 
        int update_channel;
-       struct dsi_update_region update_region;
+#ifdef DEBUG
+       unsigned update_bytes;
+#endif
 
        bool te_enabled;
        bool ulps_enabled;
@@ -327,7 +326,10 @@ struct dsi_data {
        unsigned long  fint_min, fint_max;
        unsigned long lpdiv_max;
 
-       int num_data_lanes;
+       unsigned num_lanes_supported;
+
+       struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
+       unsigned num_lanes_used;
 
        unsigned scp_clk_refcount;
 };
@@ -340,8 +342,8 @@ struct dsi_packet_sent_handler_data {
 static struct platform_device *dsi_pdev_map[MAX_NUM_DSI];
 
 #ifdef DEBUG
-static unsigned int dsi_perf;
-module_param_named(dsi_perf, dsi_perf, bool, 0644);
+static bool dsi_perf;
+module_param(dsi_perf, bool, 0644);
 #endif
 
 static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev)
@@ -413,14 +415,29 @@ static void dsi_completion_handler(void *data, u32 mask)
 static inline int wait_for_bit_change(struct platform_device *dsidev,
                const struct dsi_reg idx, int bitnum, int value)
 {
-       int t = 100000;
+       unsigned long timeout;
+       ktime_t wait;
+       int t;
 
-       while (REG_GET(dsidev, idx, bitnum, bitnum) != value) {
-               if (--t == 0)
-                       return !value;
+       /* first busyloop to see if the bit changes right away */
+       t = 100;
+       while (t-- > 0) {
+               if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
+                       return value;
        }
 
-       return value;
+       /* then loop for 500ms, sleeping for 1ms in between */
+       timeout = jiffies + msecs_to_jiffies(500);
+       while (time_before(jiffies, timeout)) {
+               if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
+                       return value;
+
+               wait = ns_to_ktime(1000 * 1000);
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
+       }
+
+       return !value;
 }
 
 u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
@@ -454,7 +471,6 @@ static void dsi_perf_mark_start(struct platform_device *dsidev)
 static void dsi_perf_show(struct platform_device *dsidev, const char *name)
 {
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       struct omap_dss_device *dssdev = dsi->update_region.device;
        ktime_t t, setup_time, trans_time;
        u32 total_bytes;
        u32 setup_us, trans_us, total_us;
@@ -476,9 +492,7 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name)
 
        total_us = setup_us + trans_us;
 
-       total_bytes = dsi->update_region.w *
-               dsi->update_region.h *
-               dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
+       total_bytes = dsi->update_bytes;
 
        printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
                        "%u bytes, %u kbytes/sec\n",
@@ -1720,17 +1734,19 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
        seq_printf(s,   "CLKIN4DDR\t%-16luregm %u\n",
                        cinfo->clkin4ddr, cinfo->regm);
 
-       seq_printf(s,   "%s (%s)\t%-16luregm_dispc %u\t(%s)\n",
-                       dss_get_generic_clk_source_name(dispc_clk_src),
-                       dss_feat_get_clk_source_name(dispc_clk_src),
+       seq_printf(s,   "DSI_PLL_HSDIV_DISPC (%s)\t%-16luregm_dispc %u\t(%s)\n",
+                       dss_feat_get_clk_source_name(dsi_module == 0 ?
+                               OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
+                               OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC),
                        cinfo->dsi_pll_hsdiv_dispc_clk,
                        cinfo->regm_dispc,
                        dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ?
                        "off" : "on");
 
-       seq_printf(s,   "%s (%s)\t%-16luregm_dsi %u\t(%s)\n",
-                       dss_get_generic_clk_source_name(dsi_clk_src),
-                       dss_feat_get_clk_source_name(dsi_clk_src),
+       seq_printf(s,   "DSI_PLL_HSDIV_DSI (%s)\t%-16luregm_dsi %u\t(%s)\n",
+                       dss_feat_get_clk_source_name(dsi_module == 0 ?
+                               OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
+                               OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI),
                        cinfo->dsi_pll_hsdiv_dsi_clk,
                        cinfo->regm_dsi,
                        dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ?
@@ -2029,34 +2045,6 @@ static int dsi_cio_power(struct platform_device *dsidev,
        return 0;
 }
 
-/* Number of data lanes present on DSI interface */
-static inline int dsi_get_num_data_lanes(struct platform_device *dsidev)
-{
-       /* DSI on OMAP3 doesn't have register DSI_GNQ, set number
-        * of data lanes as 2 by default */
-       if (dss_has_feature(FEAT_DSI_GNQ))
-               return REG_GET(dsidev, DSI_GNQ, 11, 9); /* NB_DATA_LANES */
-       else
-               return 2;
-}
-
-/* Number of data lanes used by the dss device */
-static inline int dsi_get_num_data_lanes_dssdev(struct omap_dss_device *dssdev)
-{
-       int num_data_lanes = 0;
-
-       if (dssdev->phy.dsi.data1_lane != 0)
-               num_data_lanes++;
-       if (dssdev->phy.dsi.data2_lane != 0)
-               num_data_lanes++;
-       if (dssdev->phy.dsi.data3_lane != 0)
-               num_data_lanes++;
-       if (dssdev->phy.dsi.data4_lane != 0)
-               num_data_lanes++;
-
-       return num_data_lanes;
-}
-
 static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
 {
        int val;
@@ -2088,59 +2076,112 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
        }
 }
 
-static void dsi_set_lane_config(struct omap_dss_device *dssdev)
+static int dsi_parse_lane_config(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-       u32 r;
-       int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       u8 lanes[DSI_MAX_NR_LANES];
+       u8 polarities[DSI_MAX_NR_LANES];
+       int num_lanes, i;
+
+       static const enum dsi_lane_function functions[] = {
+               DSI_LANE_CLK,
+               DSI_LANE_DATA1,
+               DSI_LANE_DATA2,
+               DSI_LANE_DATA3,
+               DSI_LANE_DATA4,
+       };
+
+       lanes[0] = dssdev->phy.dsi.clk_lane;
+       lanes[1] = dssdev->phy.dsi.data1_lane;
+       lanes[2] = dssdev->phy.dsi.data2_lane;
+       lanes[3] = dssdev->phy.dsi.data3_lane;
+       lanes[4] = dssdev->phy.dsi.data4_lane;
+       polarities[0] = dssdev->phy.dsi.clk_pol;
+       polarities[1] = dssdev->phy.dsi.data1_pol;
+       polarities[2] = dssdev->phy.dsi.data2_pol;
+       polarities[3] = dssdev->phy.dsi.data3_pol;
+       polarities[4] = dssdev->phy.dsi.data4_pol;
 
-       int clk_lane   = dssdev->phy.dsi.clk_lane;
-       int data1_lane = dssdev->phy.dsi.data1_lane;
-       int data2_lane = dssdev->phy.dsi.data2_lane;
-       int clk_pol    = dssdev->phy.dsi.clk_pol;
-       int data1_pol  = dssdev->phy.dsi.data1_pol;
-       int data2_pol  = dssdev->phy.dsi.data2_pol;
+       num_lanes = 0;
+
+       for (i = 0; i < dsi->num_lanes_supported; ++i)
+               dsi->lanes[i].function = DSI_LANE_UNUSED;
+
+       for (i = 0; i < dsi->num_lanes_supported; ++i) {
+               int num;
+
+               if (lanes[i] == DSI_LANE_UNUSED)
+                       break;
+
+               num = lanes[i] - 1;
+
+               if (num >= dsi->num_lanes_supported)
+                       return -EINVAL;
+
+               if (dsi->lanes[num].function != DSI_LANE_UNUSED)
+                       return -EINVAL;
+
+               dsi->lanes[num].function = functions[i];
+               dsi->lanes[num].polarity = polarities[i];
+               num_lanes++;
+       }
+
+       if (num_lanes < 2 || num_lanes > dsi->num_lanes_supported)
+               return -EINVAL;
+
+       dsi->num_lanes_used = num_lanes;
+
+       return 0;
+}
+
+static int dsi_set_lane_config(struct omap_dss_device *dssdev)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       static const u8 offsets[] = { 0, 4, 8, 12, 16 };
+       static const enum dsi_lane_function functions[] = {
+               DSI_LANE_CLK,
+               DSI_LANE_DATA1,
+               DSI_LANE_DATA2,
+               DSI_LANE_DATA3,
+               DSI_LANE_DATA4,
+       };
+       u32 r;
+       int i;
 
        r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
-       r = FLD_MOD(r, clk_lane, 2, 0);
-       r = FLD_MOD(r, clk_pol, 3, 3);
-       r = FLD_MOD(r, data1_lane, 6, 4);
-       r = FLD_MOD(r, data1_pol, 7, 7);
-       r = FLD_MOD(r, data2_lane, 10, 8);
-       r = FLD_MOD(r, data2_pol, 11, 11);
-       if (num_data_lanes_dssdev > 2) {
-               int data3_lane  = dssdev->phy.dsi.data3_lane;
-               int data3_pol  = dssdev->phy.dsi.data3_pol;
-
-               r = FLD_MOD(r, data3_lane, 14, 12);
-               r = FLD_MOD(r, data3_pol, 15, 15);
+
+       for (i = 0; i < dsi->num_lanes_used; ++i) {
+               unsigned offset = offsets[i];
+               unsigned polarity, lane_number;
+               unsigned t;
+
+               for (t = 0; t < dsi->num_lanes_supported; ++t)
+                       if (dsi->lanes[t].function == functions[i])
+                               break;
+
+               if (t == dsi->num_lanes_supported)
+                       return -EINVAL;
+
+               lane_number = t;
+               polarity = dsi->lanes[t].polarity;
+
+               r = FLD_MOD(r, lane_number + 1, offset + 2, offset);
+               r = FLD_MOD(r, polarity, offset + 3, offset + 3);
        }
-       if (num_data_lanes_dssdev > 3) {
-               int data4_lane  = dssdev->phy.dsi.data4_lane;
-               int data4_pol  = dssdev->phy.dsi.data4_pol;
 
-               r = FLD_MOD(r, data4_lane, 18, 16);
-               r = FLD_MOD(r, data4_pol, 19, 19);
+       /* clear the unused lanes */
+       for (; i < dsi->num_lanes_supported; ++i) {
+               unsigned offset = offsets[i];
+
+               r = FLD_MOD(r, 0, offset + 2, offset);
+               r = FLD_MOD(r, 0, offset + 3, offset + 3);
        }
-       dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);
 
-       /* The configuration of the DSI complex I/O (number of data lanes,
-          position, differential order) should not be changed while
-          DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for
-          the hardware to take into account a new configuration of the complex
-          I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to
-          follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1,
-          then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set
-          DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the
-          DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the
-          DSI complex I/O configuration is unknown. */
+       dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);
 
-       /*
-       REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0);
-       REG_FLD_MOD(dsidev, DSI_CTRL, 0, 0, 0);
-       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20);
-       REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0);
-       */
+       return 0;
 }
 
 static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns)
@@ -2230,49 +2271,28 @@ static void dsi_cio_timings(struct platform_device *dsidev)
        dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r);
 }
 
+/* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */
 static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev,
-               enum dsi_lane lanes)
+               unsigned mask_p, unsigned mask_n)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       int clk_lane   = dssdev->phy.dsi.clk_lane;
-       int data1_lane = dssdev->phy.dsi.data1_lane;
-       int data2_lane = dssdev->phy.dsi.data2_lane;
-       int data3_lane = dssdev->phy.dsi.data3_lane;
-       int data4_lane = dssdev->phy.dsi.data4_lane;
-       int clk_pol    = dssdev->phy.dsi.clk_pol;
-       int data1_pol  = dssdev->phy.dsi.data1_pol;
-       int data2_pol  = dssdev->phy.dsi.data2_pol;
-       int data3_pol  = dssdev->phy.dsi.data3_pol;
-       int data4_pol  = dssdev->phy.dsi.data4_pol;
-
-       u32 l = 0;
-       u8 lptxscp_start = dsi->num_data_lanes == 2 ? 22 : 26;
-
-       if (lanes & DSI_CLK_P)
-               l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 0 : 1));
-       if (lanes & DSI_CLK_N)
-               l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 1 : 0));
-
-       if (lanes & DSI_DATA1_P)
-               l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 0 : 1));
-       if (lanes & DSI_DATA1_N)
-               l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 1 : 0));
-
-       if (lanes & DSI_DATA2_P)
-               l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 0 : 1));
-       if (lanes & DSI_DATA2_N)
-               l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 1 : 0));
-
-       if (lanes & DSI_DATA3_P)
-               l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 0 : 1));
-       if (lanes & DSI_DATA3_N)
-               l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 1 : 0));
-
-       if (lanes & DSI_DATA4_P)
-               l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 0 : 1));
-       if (lanes & DSI_DATA4_N)
-               l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 1 : 0));
+       int i;
+       u32 l;
+       u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26;
+
+       l = 0;
+
+       for (i = 0; i < dsi->num_lanes_supported; ++i) {
+               unsigned p = dsi->lanes[i].polarity;
+
+               if (mask_p & (1 << i))
+                       l |= 1 << (i * 2 + (p ? 0 : 1));
+
+               if (mask_n & (1 << i))
+                       l |= 1 << (i * 2 + (p ? 1 : 0));
+       }
+
        /*
         * Bits in REGLPTXSCPDAT4TO0DXDY:
         * 17: DY0 18: DX0
@@ -2305,51 +2325,40 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
 static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-       int t;
-       int bits[3];
-       bool in_use[3];
-
-       if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
-               bits[0] = 28;
-               bits[1] = 27;
-               bits[2] = 26;
-       } else {
-               bits[0] = 24;
-               bits[1] = 25;
-               bits[2] = 26;
-       }
-
-       in_use[0] = false;
-       in_use[1] = false;
-       in_use[2] = false;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int t, i;
+       bool in_use[DSI_MAX_NR_LANES];
+       static const u8 offsets_old[] = { 28, 27, 26 };
+       static const u8 offsets_new[] = { 24, 25, 26, 27, 28 };
+       const u8 *offsets;
+
+       if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC))
+               offsets = offsets_old;
+       else
+               offsets = offsets_new;
 
-       if (dssdev->phy.dsi.clk_lane != 0)
-               in_use[dssdev->phy.dsi.clk_lane - 1] = true;
-       if (dssdev->phy.dsi.data1_lane != 0)
-               in_use[dssdev->phy.dsi.data1_lane - 1] = true;
-       if (dssdev->phy.dsi.data2_lane != 0)
-               in_use[dssdev->phy.dsi.data2_lane - 1] = true;
+       for (i = 0; i < dsi->num_lanes_supported; ++i)
+               in_use[i] = dsi->lanes[i].function != DSI_LANE_UNUSED;
 
        t = 100000;
        while (true) {
                u32 l;
-               int i;
                int ok;
 
                l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
 
                ok = 0;
-               for (i = 0; i < 3; ++i) {
-                       if (!in_use[i] || (l & (1 << bits[i])))
+               for (i = 0; i < dsi->num_lanes_supported; ++i) {
+                       if (!in_use[i] || (l & (1 << offsets[i])))
                                ok++;
                }
 
-               if (ok == 3)
+               if (ok == dsi->num_lanes_supported)
                        break;
 
                if (--t == 0) {
-                       for (i = 0; i < 3; ++i) {
-                               if (!in_use[i] || (l & (1 << bits[i])))
+                       for (i = 0; i < dsi->num_lanes_supported; ++i) {
+                               if (!in_use[i] || (l & (1 << offsets[i])))
                                        continue;
 
                                DSSERR("CIO TXCLKESC%d domain not coming " \
@@ -2362,22 +2371,20 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
        return 0;
 }
 
+/* return bitmask of enabled lanes, lane0 being the lsb */
 static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev)
 {
-       unsigned lanes = 0;
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       unsigned mask = 0;
+       int i;
 
-       if (dssdev->phy.dsi.clk_lane != 0)
-               lanes |= 1 << (dssdev->phy.dsi.clk_lane - 1);
-       if (dssdev->phy.dsi.data1_lane != 0)
-               lanes |= 1 << (dssdev->phy.dsi.data1_lane - 1);
-       if (dssdev->phy.dsi.data2_lane != 0)
-               lanes |= 1 << (dssdev->phy.dsi.data2_lane - 1);
-       if (dssdev->phy.dsi.data3_lane != 0)
-               lanes |= 1 << (dssdev->phy.dsi.data3_lane - 1);
-       if (dssdev->phy.dsi.data4_lane != 0)
-               lanes |= 1 << (dssdev->phy.dsi.data4_lane - 1);
+       for (i = 0; i < dsi->num_lanes_supported; ++i) {
+               if (dsi->lanes[i].function != DSI_LANE_UNUSED)
+                       mask |= 1 << i;
+       }
 
-       return lanes;
+       return mask;
 }
 
 static int dsi_cio_init(struct omap_dss_device *dssdev)
@@ -2385,7 +2392,6 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int r;
-       int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev);
        u32 l;
 
        DSSDBGF();
@@ -2407,7 +2413,9 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
                goto err_scp_clk_dom;
        }
 
-       dsi_set_lane_config(dssdev);
+       r = dsi_set_lane_config(dssdev);
+       if (r)
+               goto err_scp_clk_dom;
 
        /* set TX STOP MODE timer to maximum for this operation */
        l = dsi_read_reg(dsidev, DSI_TIMING1);
@@ -2418,7 +2426,8 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
        dsi_write_reg(dsidev, DSI_TIMING1, l);
 
        if (dsi->ulps_enabled) {
-               u32 lane_mask = DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P;
+               unsigned mask_p;
+               int i;
 
                DSSDBG("manual ulps exit\n");
 
@@ -2427,16 +2436,19 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
                 * ULPS exit sequence, as after reset the DSS HW thinks
                 * that we are not in ULPS mode, and refuses to send the
                 * sequence. So we need to send the ULPS exit sequence
-                * manually.
+                * manually by setting positive lines high and negative lines
+                * low for 1ms.
                 */
 
-               if (num_data_lanes_dssdev > 2)
-                       lane_mask |= DSI_DATA3_P;
+               mask_p = 0;
 
-               if (num_data_lanes_dssdev > 3)
-                       lane_mask |= DSI_DATA4_P;
+               for (i = 0; i < dsi->num_lanes_supported; ++i) {
+                       if (dsi->lanes[i].function == DSI_LANE_UNUSED)
+                               continue;
+                       mask_p |= 1 << i;
+               }
 
-               dsi_cio_enable_lane_override(dssdev, lane_mask);
+               dsi_cio_enable_lane_override(dssdev, mask_p, 0);
        }
 
        r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
@@ -2913,6 +2925,9 @@ static int dsi_vc_send_bta(struct platform_device *dsidev, int channel)
 
        REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
 
+       /* flush posted write */
+       dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
+
        return 0;
 }
 
@@ -3513,7 +3528,8 @@ static int dsi_enter_ulps(struct platform_device *dsidev)
 {
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        DECLARE_COMPLETION_ONSTACK(completion);
-       int r;
+       int r, i;
+       unsigned mask;
 
        DSSDBGF();
 
@@ -3524,9 +3540,11 @@ static int dsi_enter_ulps(struct platform_device *dsidev)
        if (dsi->ulps_enabled)
                return 0;
 
+       /* DDR_CLK_ALWAYS_ON */
        if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) {
-               DSSERR("DDR_CLK_ALWAYS_ON enabled when entering ULPS\n");
-               return -EIO;
+               dsi_if_enable(dsidev, 0);
+               REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13);
+               dsi_if_enable(dsidev, 1);
        }
 
        dsi_sync_vc(dsidev, 0);
@@ -3556,10 +3574,19 @@ static int dsi_enter_ulps(struct platform_device *dsidev)
        if (r)
                return r;
 
+       mask = 0;
+
+       for (i = 0; i < dsi->num_lanes_supported; ++i) {
+               if (dsi->lanes[i].function == DSI_LANE_UNUSED)
+                       continue;
+               mask |= 1 << i;
+       }
        /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */
        /* LANEx_ULPS_SIG2 */
-       REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (1 << 0) | (1 << 1) | (1 << 2),
-               7, 5);
+       REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, mask, 9, 5);
+
+       /* flush posted write and wait for SCP interface to finish the write */
+       dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2);
 
        if (wait_for_completion_timeout(&completion,
                                msecs_to_jiffies(1000)) == 0) {
@@ -3572,8 +3599,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev)
                        DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
 
        /* Reset LANEx_ULPS_SIG2 */
-       REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (0 << 0) | (0 << 1) | (0 << 2),
-               7, 5);
+       REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, 0, 9, 5);
+
+       /* flush posted write and wait for SCP interface to finish the write */
+       dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2);
 
        dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
 
@@ -3836,6 +3865,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
 static void dsi_proto_timings(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
        unsigned tclk_pre, tclk_post;
        unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
@@ -3843,7 +3873,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
        unsigned ddr_clk_pre, ddr_clk_post;
        unsigned enter_hs_mode_lat, exit_hs_mode_lat;
        unsigned ths_eot;
-       int ndl = dsi_get_num_data_lanes_dssdev(dssdev);
+       int ndl = dsi->num_lanes_used - 1;
        u32 r;
 
        r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
@@ -3945,68 +3975,82 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
        }
 }
 
-int dsi_video_mode_enable(struct omap_dss_device *dssdev, int channel)
+int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
        u8 data_type;
        u16 word_count;
+       int r;
 
-       switch (dssdev->panel.dsi_pix_fmt) {
-       case OMAP_DSS_DSI_FMT_RGB888:
-               data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
-               break;
-       case OMAP_DSS_DSI_FMT_RGB666:
-               data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
-               break;
-       case OMAP_DSS_DSI_FMT_RGB666_PACKED:
-               data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18;
-               break;
-       case OMAP_DSS_DSI_FMT_RGB565:
-               data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
-               break;
-       default:
-               BUG();
-       };
+       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+               switch (dssdev->panel.dsi_pix_fmt) {
+               case OMAP_DSS_DSI_FMT_RGB888:
+                       data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
+                       break;
+               case OMAP_DSS_DSI_FMT_RGB666:
+                       data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
+                       break;
+               case OMAP_DSS_DSI_FMT_RGB666_PACKED:
+                       data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18;
+                       break;
+               case OMAP_DSS_DSI_FMT_RGB565:
+                       data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
+                       break;
+               default:
+                       BUG();
+               };
 
-       dsi_if_enable(dsidev, false);
-       dsi_vc_enable(dsidev, channel, false);
+               dsi_if_enable(dsidev, false);
+               dsi_vc_enable(dsidev, channel, false);
 
-       /* MODE, 1 = video mode */
-       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4);
+               /* MODE, 1 = video mode */
+               REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4);
 
-       word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8);
+               word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8);
 
-       dsi_vc_write_long_header(dsidev, channel, data_type, word_count, 0);
+               dsi_vc_write_long_header(dsidev, channel, data_type,
+                               word_count, 0);
 
-       dsi_vc_enable(dsidev, channel, true);
-       dsi_if_enable(dsidev, true);
+               dsi_vc_enable(dsidev, channel, true);
+               dsi_if_enable(dsidev, true);
+       }
 
-       dssdev->manager->enable(dssdev->manager);
+       r = dss_mgr_enable(dssdev->manager);
+       if (r) {
+               if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+                       dsi_if_enable(dsidev, false);
+                       dsi_vc_enable(dsidev, channel, false);
+               }
+
+               return r;
+       }
 
        return 0;
 }
-EXPORT_SYMBOL(dsi_video_mode_enable);
+EXPORT_SYMBOL(dsi_enable_video_output);
 
-void dsi_video_mode_disable(struct omap_dss_device *dssdev, int channel)
+void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
 
-       dsi_if_enable(dsidev, false);
-       dsi_vc_enable(dsidev, channel, false);
+       if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+               dsi_if_enable(dsidev, false);
+               dsi_vc_enable(dsidev, channel, false);
 
-       /* MODE, 0 = command mode */
-       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4);
+               /* MODE, 0 = command mode */
+               REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4);
 
-       dsi_vc_enable(dsidev, channel, true);
-       dsi_if_enable(dsidev, true);
+               dsi_vc_enable(dsidev, channel, true);
+               dsi_if_enable(dsidev, true);
+       }
 
-       dssdev->manager->disable(dssdev->manager);
+       dss_mgr_disable(dssdev->manager);
 }
-EXPORT_SYMBOL(dsi_video_mode_disable);
+EXPORT_SYMBOL(dsi_disable_video_output);
 
 static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
-               u16 x, u16 y, u16 w, u16 h)
+               u16 w, u16 h)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
@@ -4021,8 +4065,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
        const unsigned channel = dsi->update_channel;
        const unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
 
-       DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
-                       x, y, w, h);
+       DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h);
 
        dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP);
 
@@ -4070,7 +4113,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
                msecs_to_jiffies(250));
        BUG_ON(r == 0);
 
-       dss_start_update(dssdev);
+       dss_mgr_start_update(dssdev->manager);
 
        if (dsi->te_enabled) {
                /* disable LP_RX_TO, so that we can receive TE.  Time to wait
@@ -4146,66 +4189,27 @@ static void dsi_framedone_irq_callback(void *data, u32 mask)
 #endif
 }
 
-int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
-                                   u16 *x, u16 *y, u16 *w, u16 *h,
-                                   bool enlarge_update_area)
+int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
+               void (*callback)(int, void *), void *data)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u16 dw, dh;
 
-       dssdev->driver->get_resolution(dssdev, &dw, &dh);
-
-       if  (*x > dw || *y > dh)
-               return -EINVAL;
-
-       if (*x + *w > dw)
-               return -EINVAL;
-
-       if (*y + *h > dh)
-               return -EINVAL;
-
-       if (*w == 1)
-               return -EINVAL;
-
-       if (*w == 0 || *h == 0)
-               return -EINVAL;
-
        dsi_perf_mark_setup(dsidev);
 
-       dss_setup_partial_planes(dssdev, x, y, w, h,
-                       enlarge_update_area);
-       dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h);
-
-       return 0;
-}
-EXPORT_SYMBOL(omap_dsi_prepare_update);
-
-int omap_dsi_update(struct omap_dss_device *dssdev,
-               int channel,
-               u16 x, u16 y, u16 w, u16 h,
-               void (*callback)(int, void *), void *data)
-{
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-
        dsi->update_channel = channel;
 
-       /* OMAP DSS cannot send updates of odd widths.
-        * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON
-        * here to make sure we catch erroneous updates. Otherwise we'll only
-        * see rather obscure HW error happening, as DSS halts. */
-       BUG_ON(x % 2 == 1);
-
        dsi->framedone_callback = callback;
        dsi->framedone_data = data;
 
-       dsi->update_region.x = x;
-       dsi->update_region.y = y;
-       dsi->update_region.w = w;
-       dsi->update_region.h = h;
-       dsi->update_region.device = dssdev;
+       dssdev->driver->get_resolution(dssdev, &dw, &dh);
 
-       dsi_update_screen_dispc(dssdev, x, y, w, h);
+#ifdef DEBUG
+       dsi->update_bytes = dw * dh *
+               dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
+#endif
+       dsi_update_screen_dispc(dssdev, dw, dh);
 
        return 0;
 }
@@ -4218,6 +4222,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
        int r;
 
        if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
+               u16 dw, dh;
                u32 irq;
                struct omap_video_timings timings = {
                        .hsw            = 1,
@@ -4228,6 +4233,10 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
                        .vbp            = 0,
                };
 
+               dssdev->driver->get_resolution(dssdev, &dw, &dh);
+               timings.x_res = dw;
+               timings.y_res = dh;
+
                irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ?
                        DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2;
 
@@ -4330,6 +4339,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
        int dsi_module = dsi_get_dsidev_id(dsidev);
        int r;
 
+       r = dsi_parse_lane_config(dssdev);
+       if (r) {
+               DSSERR("illegal lane config");
+               goto err0;
+       }
+
        r = dsi_pll_init(dsidev, true, true);
        if (r)
                goto err0;
@@ -4521,7 +4536,6 @@ int dsi_init_display(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       int dsi_module = dsi_get_dsidev_id(dsidev);
 
        DSSDBG("DSI init\n");
 
@@ -4543,12 +4557,6 @@ int dsi_init_display(struct omap_dss_device *dssdev)
                dsi->vdds_dsi_reg = vdds_dsi;
        }
 
-       if (dsi_get_num_data_lanes_dssdev(dssdev) > dsi->num_data_lanes) {
-               DSSERR("DSI%d can't support more than %d data lanes\n",
-                       dsi_module + 1, dsi->num_data_lanes);
-               return -EINVAL;
-       }
-
        return 0;
 }
 
@@ -4771,7 +4779,13 @@ static int omap_dsihw_probe(struct platform_device *dsidev)
        dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
               FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
 
-       dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev);
+       /* DSI on OMAP3 doesn't have register DSI_GNQ, set number
+        * of data to 3 by default */
+       if (dss_has_feature(FEAT_DSI_GNQ))
+               /* NB_DATA_LANES */
+               dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9);
+       else
+               dsi->num_lanes_supported = 3;
 
        dsi_runtime_put(dsidev);
 
index 6308fc59fc9e97c317bc93cc33904d6e5383f3d7..32ff69fb3333fbf352f03fcad01479020dc10efa 100644 (file)
@@ -28,7 +28,7 @@
 #endif
 
 #ifdef DEBUG
-extern unsigned int dss_debug;
+extern bool dss_debug;
 #ifdef DSS_SUBSYS_NAME
 #define DSSDBG(format, ...) \
        if (dss_debug) \
@@ -163,6 +163,34 @@ struct bus_type *dss_get_bus(void);
 struct regulator *dss_get_vdds_dsi(void);
 struct regulator *dss_get_vdds_sdi(void);
 
+/* apply */
+void dss_apply_init(void);
+int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr);
+int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
+void dss_mgr_start_update(struct omap_overlay_manager *mgr);
+int omap_dss_mgr_apply(struct omap_overlay_manager *mgr);
+
+int dss_mgr_enable(struct omap_overlay_manager *mgr);
+void dss_mgr_disable(struct omap_overlay_manager *mgr);
+int dss_mgr_set_info(struct omap_overlay_manager *mgr,
+               struct omap_overlay_manager_info *info);
+void dss_mgr_get_info(struct omap_overlay_manager *mgr,
+               struct omap_overlay_manager_info *info);
+int dss_mgr_set_device(struct omap_overlay_manager *mgr,
+               struct omap_dss_device *dssdev);
+int dss_mgr_unset_device(struct omap_overlay_manager *mgr);
+
+bool dss_ovl_is_enabled(struct omap_overlay *ovl);
+int dss_ovl_enable(struct omap_overlay *ovl);
+int dss_ovl_disable(struct omap_overlay *ovl);
+int dss_ovl_set_info(struct omap_overlay *ovl,
+               struct omap_overlay_info *info);
+void dss_ovl_get_info(struct omap_overlay *ovl,
+               struct omap_overlay_info *info);
+int dss_ovl_set_manager(struct omap_overlay *ovl,
+               struct omap_overlay_manager *mgr);
+int dss_ovl_unset_manager(struct omap_overlay *ovl);
+
 /* display */
 int dss_suspend_all_devices(void);
 int dss_resume_all_devices(void);
@@ -181,21 +209,22 @@ void default_get_overlay_fifo_thresholds(enum omap_plane plane,
 /* manager */
 int dss_init_overlay_managers(struct platform_device *pdev);
 void dss_uninit_overlay_managers(struct platform_device *pdev);
-int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
-void dss_setup_partial_planes(struct omap_dss_device *dssdev,
-                               u16 *x, u16 *y, u16 *w, u16 *h,
-                               bool enlarge_update_area);
-void dss_start_update(struct omap_dss_device *dssdev);
+int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
+               const struct omap_overlay_manager_info *info);
+int dss_mgr_check(struct omap_overlay_manager *mgr,
+               struct omap_dss_device *dssdev,
+               struct omap_overlay_manager_info *info,
+               struct omap_overlay_info **overlay_infos);
 
 /* overlay */
 void dss_init_overlays(struct platform_device *pdev);
 void dss_uninit_overlays(struct platform_device *pdev);
-int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev);
 void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
-#ifdef L4_EXAMPLE
-void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr);
-#endif
 void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
+int dss_ovl_simple_check(struct omap_overlay *ovl,
+               const struct omap_overlay_info *info);
+int dss_ovl_check(struct omap_overlay *ovl,
+               struct omap_overlay_info *info, struct omap_dss_device *dssdev);
 
 /* DSS */
 int dss_init_platform_driver(void);
@@ -399,21 +428,22 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
                struct dispc_clock_info *cinfo);
 
 
+void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
 u32 dispc_ovl_get_fifo_size(enum omap_plane plane);
 u32 dispc_ovl_get_burst_size(enum omap_plane plane);
 int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
-               bool ilace, enum omap_channel channel, bool replication,
-               u32 fifo_low, u32 fifo_high);
+               bool ilace, bool replication);
 int dispc_ovl_enable(enum omap_plane plane, bool enable);
-
+void dispc_ovl_set_channel_out(enum omap_plane plane,
+               enum omap_channel channel);
 
 void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable);
 void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height);
-void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable);
-void dispc_mgr_set_cpr_coef(enum omap_channel channel,
-               struct omap_dss_cpr_coefs *coefs);
+u32 dispc_mgr_get_vsync_irq(enum omap_channel channel);
+u32 dispc_mgr_get_framedone_irq(enum omap_channel channel);
 bool dispc_mgr_go_busy(enum omap_channel channel);
 void dispc_mgr_go(enum omap_channel channel);
+bool dispc_mgr_is_enabled(enum omap_channel channel);
 void dispc_mgr_enable(enum omap_channel channel, bool enable);
 bool dispc_mgr_is_channel_enabled(enum omap_channel channel);
 void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode);
@@ -421,18 +451,6 @@ void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable);
 void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines);
 void dispc_mgr_set_lcd_display_type(enum omap_channel channel,
                enum omap_lcd_display_type type);
-void dispc_mgr_set_default_color(enum omap_channel channel, u32 color);
-u32 dispc_mgr_get_default_color(enum omap_channel channel);
-void dispc_mgr_set_trans_key(enum omap_channel ch,
-               enum omap_dss_trans_key_type type,
-               u32 trans_key);
-void dispc_mgr_get_trans_key(enum omap_channel ch,
-               enum omap_dss_trans_key_type *type,
-               u32 *trans_key);
-void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable);
-void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable);
-bool dispc_mgr_trans_key_enabled(enum omap_channel ch);
-bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch);
 void dispc_mgr_set_lcd_timings(enum omap_channel channel,
                struct omap_video_timings *timings);
 void dispc_mgr_set_pol_freq(enum omap_channel channel,
@@ -443,6 +461,8 @@ int dispc_mgr_set_clock_div(enum omap_channel channel,
                struct dispc_clock_info *cinfo);
 int dispc_mgr_get_clock_div(enum omap_channel channel,
                struct dispc_clock_info *cinfo);
+void dispc_mgr_setup(enum omap_channel channel,
+               struct omap_overlay_manager_info *info);
 
 /* VENC */
 #ifdef CONFIG_OMAP2_DSS_VENC
index b402699168a52fe0b4f3ea8e07786eeb0afcf8a0..afcb59301c3727d20149d1b112fa8596cbf3127f 100644 (file)
@@ -304,6 +304,11 @@ static const struct dss_param_range omap2_dss_param_range[] = {
        [FEAT_PARAM_DSIPLL_FINT]                = { 0, 0 },
        [FEAT_PARAM_DSIPLL_LPDIV]               = { 0, 0 },
        [FEAT_PARAM_DOWNSCALE]                  = { 1, 2 },
+       /*
+        * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC
+        * scaler cannot scale a image with width more than 768.
+        */
+       [FEAT_PARAM_LINEWIDTH]                  = { 1, 768 },
 };
 
 static const struct dss_param_range omap3_dss_param_range[] = {
@@ -316,6 +321,7 @@ static const struct dss_param_range omap3_dss_param_range[] = {
        [FEAT_PARAM_DSIPLL_FINT]                = { 750000, 2100000 },
        [FEAT_PARAM_DSIPLL_LPDIV]               = { 1, (1 << 13) - 1},
        [FEAT_PARAM_DOWNSCALE]                  = { 1, 4 },
+       [FEAT_PARAM_LINEWIDTH]                  = { 1, 1024 },
 };
 
 static const struct dss_param_range omap4_dss_param_range[] = {
@@ -328,6 +334,7 @@ static const struct dss_param_range omap4_dss_param_range[] = {
        [FEAT_PARAM_DSIPLL_FINT]                = { 500000, 2500000 },
        [FEAT_PARAM_DSIPLL_LPDIV]               = { 0, (1 << 13) - 1 },
        [FEAT_PARAM_DOWNSCALE]                  = { 1, 4 },
+       [FEAT_PARAM_LINEWIDTH]                  = { 1, 2048 },
 };
 
 /* OMAP2 DSS Features */
@@ -465,6 +472,10 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = {
        .dump_core              =       ti_hdmi_4xxx_core_dump,
        .dump_pll               =       ti_hdmi_4xxx_pll_dump,
        .dump_phy               =       ti_hdmi_4xxx_phy_dump,
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+       .audio_enable           =       ti_hdmi_4xxx_wp_audio_enable,
+#endif
 
 };
 
index 6a6c05dd45ce56b45c1de6d1f2ac597932c74845..cd833bbaac3d60bf2e1b46395220a3a16d2bc907 100644 (file)
@@ -86,6 +86,7 @@ enum dss_range_param {
        FEAT_PARAM_DSIPLL_FINT,
        FEAT_PARAM_DSIPLL_LPDIV,
        FEAT_PARAM_DOWNSCALE,
+       FEAT_PARAM_LINEWIDTH,
 };
 
 /* DSS Feature Functions */
index c56378c555b0907255048e32384c1b5b191bc14f..b4c270edb915bde5ce721d8373950ee8fa2df667 100644 (file)
@@ -333,7 +333,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
        if (r)
                return r;
 
-       dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0);
+       dss_mgr_disable(dssdev->manager);
 
        p = &dssdev->panel.timings;
 
@@ -387,9 +387,16 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 
        hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1);
 
-       dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 1);
+       r = dss_mgr_enable(dssdev->manager);
+       if (r)
+               goto err_mgr_enable;
 
        return 0;
+
+err_mgr_enable:
+       hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0);
+       hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
+       hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
 err:
        hdmi_runtime_put();
        return -EIO;
@@ -397,7 +404,7 @@ err:
 
 static void hdmi_power_off(struct omap_dss_device *dssdev)
 {
-       dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0);
+       dss_mgr_disable(dssdev->manager);
 
        hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0);
        hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
@@ -554,11 +561,44 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
 #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
        defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
 
-static int hdmi_audio_hw_params(struct hdmi_ip_data *ip_data,
-                                       struct snd_pcm_substream *substream,
+static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct platform_device *pdev = to_platform_device(codec->dev);
+       struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec);
+       int err = 0;
+
+       if (!(ip_data->ops) && !(ip_data->ops->audio_enable)) {
+               dev_err(&pdev->dev, "Cannot enable/disable audio\n");
+               return -ENODEV;
+       }
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               ip_data->ops->audio_enable(ip_data, true);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               ip_data->ops->audio_enable(ip_data, false);
+               break;
+       default:
+               err = -EINVAL;
+       }
+       return err;
+}
+
+static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_pcm_hw_params *params,
                                    struct snd_soc_dai *dai)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec);
        struct hdmi_audio_format audio_format;
        struct hdmi_audio_dma audio_dma;
        struct hdmi_core_audio_config core_cfg;
@@ -698,7 +738,16 @@ static int hdmi_audio_startup(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int hdmi_audio_codec_probe(struct snd_soc_codec *codec)
+{
+       struct hdmi_ip_data *priv = &hdmi.ip_data;
+
+       snd_soc_codec_set_drvdata(codec, priv);
+       return 0;
+}
+
 static struct snd_soc_codec_driver hdmi_audio_codec_drv = {
+       .probe = hdmi_audio_codec_probe,
 };
 
 static struct snd_soc_dai_ops hdmi_audio_codec_ops = {
index 6e63845cc7d7705ad5dd0217e5b2247564218483..d1858e71c64e8bc448eb31e5e88680c12f4e9368 100644 (file)
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/spinlock.h>
 #include <linux/jiffies.h>
 
 #include <video/omapdss.h>
-#include <plat/cpu.h>
 
 #include "dss.h"
 #include "dss_features.h"
 
 static int num_managers;
-static struct list_head manager_list;
+static struct omap_overlay_manager *managers;
 
 static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
 {
@@ -106,7 +104,11 @@ put_device:
 static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
                                          char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.default_color);
+       struct omap_overlay_manager_info info;
+
+       mgr->get_manager_info(mgr, &info);
+
+       return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
 }
 
 static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
@@ -144,8 +146,11 @@ static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
                                           char *buf)
 {
        enum omap_dss_trans_key_type key_type;
+       struct omap_overlay_manager_info info;
+
+       mgr->get_manager_info(mgr, &info);
 
-       key_type = mgr->info.trans_key_type;
+       key_type = info.trans_key_type;
        BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
 
        return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
@@ -185,7 +190,11 @@ static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
 static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
                                            char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.trans_key);
+       struct omap_overlay_manager_info info;
+
+       mgr->get_manager_info(mgr, &info);
+
+       return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
 }
 
 static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
@@ -217,7 +226,11 @@ static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
 static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
                                              char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled);
+       struct omap_overlay_manager_info info;
+
+       mgr->get_manager_info(mgr, &info);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
 }
 
 static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
@@ -249,10 +262,14 @@ static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
 static ssize_t manager_alpha_blending_enabled_show(
                struct omap_overlay_manager *mgr, char *buf)
 {
+       struct omap_overlay_manager_info info;
+
+       mgr->get_manager_info(mgr, &info);
+
        WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
 
        return snprintf(buf, PAGE_SIZE, "%d\n",
-               mgr->info.partial_alpha_enabled);
+               info.partial_alpha_enabled);
 }
 
 static ssize_t manager_alpha_blending_enabled_store(
@@ -287,7 +304,11 @@ static ssize_t manager_alpha_blending_enabled_store(
 static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
                char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.cpr_enable);
+       struct omap_overlay_manager_info info;
+
+       mgr->get_manager_info(mgr, &info);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
 }
 
 static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
@@ -469,143 +490,6 @@ static struct kobj_type manager_ktype = {
        .default_attrs = manager_sysfs_attrs,
 };
 
-/*
- * We have 4 levels of cache for the dispc settings. First two are in SW and
- * the latter two in HW.
- *
- * +--------------------+
- * |overlay/manager_info|
- * +--------------------+
- *          v
- *        apply()
- *          v
- * +--------------------+
- * |     dss_cache      |
- * +--------------------+
- *          v
- *      configure()
- *          v
- * +--------------------+
- * |  shadow registers  |
- * +--------------------+
- *          v
- * VFP or lcd/digit_enable
- *          v
- * +--------------------+
- * |      registers     |
- * +--------------------+
- */
-
-struct overlay_cache_data {
-       /* If true, cache changed, but not written to shadow registers. Set
-        * in apply(), cleared when registers written. */
-       bool dirty;
-       /* If true, shadow registers contain changed values not yet in real
-        * registers. Set when writing to shadow registers, cleared at
-        * VSYNC/EVSYNC */
-       bool shadow_dirty;
-
-       bool enabled;
-
-       struct omap_overlay_info info;
-
-       enum omap_channel channel;
-       bool replication;
-       bool ilace;
-
-       u32 fifo_low;
-       u32 fifo_high;
-};
-
-struct manager_cache_data {
-       /* If true, cache changed, but not written to shadow registers. Set
-        * in apply(), cleared when registers written. */
-       bool dirty;
-       /* If true, shadow registers contain changed values not yet in real
-        * registers. Set when writing to shadow registers, cleared at
-        * VSYNC/EVSYNC */
-       bool shadow_dirty;
-
-       struct omap_overlay_manager_info info;
-
-       bool manual_update;
-       bool do_manual_update;
-
-       /* manual update region */
-       u16 x, y, w, h;
-
-       /* enlarge the update area if the update area contains scaled
-        * overlays */
-       bool enlarge_update_area;
-};
-
-static struct {
-       spinlock_t lock;
-       struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS];
-       struct manager_cache_data manager_cache[MAX_DSS_MANAGERS];
-
-       bool irq_enabled;
-} dss_cache;
-
-
-
-static int omap_dss_set_device(struct omap_overlay_manager *mgr,
-               struct omap_dss_device *dssdev)
-{
-       int i;
-       int r;
-
-       if (dssdev->manager) {
-               DSSERR("display '%s' already has a manager '%s'\n",
-                              dssdev->name, dssdev->manager->name);
-               return -EINVAL;
-       }
-
-       if ((mgr->supported_displays & dssdev->type) == 0) {
-               DSSERR("display '%s' does not support manager '%s'\n",
-                              dssdev->name, mgr->name);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < mgr->num_overlays; i++) {
-               struct omap_overlay *ovl = mgr->overlays[i];
-
-               if (ovl->manager != mgr || !ovl->info.enabled)
-                       continue;
-
-               r = dss_check_overlay(ovl, dssdev);
-               if (r)
-                       return r;
-       }
-
-       dssdev->manager = mgr;
-       mgr->device = dssdev;
-       mgr->device_changed = true;
-
-       return 0;
-}
-
-static int omap_dss_unset_device(struct omap_overlay_manager *mgr)
-{
-       if (!mgr->device) {
-               DSSERR("failed to unset display, display not set.\n");
-               return -EINVAL;
-       }
-
-       /*
-        * Don't allow currently enabled displays to have the overlay manager
-        * pulled out from underneath them
-        */
-       if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED)
-               return -EINVAL;
-
-       mgr->device->manager = NULL;
-       mgr->device = NULL;
-       mgr->device_changed = true;
-
-       return 0;
-}
-
 static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
 {
        unsigned long timeout = msecs_to_jiffies(500);
@@ -624,1022 +508,169 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
        return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
 }
 
-static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
-{
-       unsigned long timeout = msecs_to_jiffies(500);
-       struct manager_cache_data *mc;
-       u32 irq;
-       int r;
-       int i;
-       struct omap_dss_device *dssdev = mgr->device;
-
-       if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
-               return 0;
-
-       if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
-               return 0;
-
-       if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
-                       || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
-               irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
-       } else {
-               irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
-                       DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
-       }
-
-       mc = &dss_cache.manager_cache[mgr->id];
-       i = 0;
-       while (1) {
-               unsigned long flags;
-               bool shadow_dirty, dirty;
-
-               spin_lock_irqsave(&dss_cache.lock, flags);
-               dirty = mc->dirty;
-               shadow_dirty = mc->shadow_dirty;
-               spin_unlock_irqrestore(&dss_cache.lock, flags);
-
-               if (!dirty && !shadow_dirty) {
-                       r = 0;
-                       break;
-               }
-
-               /* 4 iterations is the worst case:
-                * 1 - initial iteration, dirty = true (between VFP and VSYNC)
-                * 2 - first VSYNC, dirty = true
-                * 3 - dirty = false, shadow_dirty = true
-                * 4 - shadow_dirty = false */
-               if (i++ == 3) {
-                       DSSERR("mgr(%d)->wait_for_go() not finishing\n",
-                                       mgr->id);
-                       r = 0;
-                       break;
-               }
-
-               r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
-               if (r == -ERESTARTSYS)
-                       break;
-
-               if (r) {
-                       DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
-                       break;
-               }
-       }
-
-       return r;
-}
-
-int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
-{
-       unsigned long timeout = msecs_to_jiffies(500);
-       struct overlay_cache_data *oc;
-       struct omap_dss_device *dssdev;
-       u32 irq;
-       int r;
-       int i;
-
-       if (!ovl->manager)
-               return 0;
-
-       dssdev = ovl->manager->device;
-
-       if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
-               return 0;
-
-       if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
-               return 0;
-
-       if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
-                       || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
-               irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
-       } else {
-               irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
-                       DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
-       }
-
-       oc = &dss_cache.overlay_cache[ovl->id];
-       i = 0;
-       while (1) {
-               unsigned long flags;
-               bool shadow_dirty, dirty;
-
-               spin_lock_irqsave(&dss_cache.lock, flags);
-               dirty = oc->dirty;
-               shadow_dirty = oc->shadow_dirty;
-               spin_unlock_irqrestore(&dss_cache.lock, flags);
-
-               if (!dirty && !shadow_dirty) {
-                       r = 0;
-                       break;
-               }
-
-               /* 4 iterations is the worst case:
-                * 1 - initial iteration, dirty = true (between VFP and VSYNC)
-                * 2 - first VSYNC, dirty = true
-                * 3 - dirty = false, shadow_dirty = true
-                * 4 - shadow_dirty = false */
-               if (i++ == 3) {
-                       DSSERR("ovl(%d)->wait_for_go() not finishing\n",
-                                       ovl->id);
-                       r = 0;
-                       break;
-               }
-
-               r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
-               if (r == -ERESTARTSYS)
-                       break;
-
-               if (r) {
-                       DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
-                       break;
-               }
-       }
-
-       return r;
-}
-
-static int overlay_enabled(struct omap_overlay *ovl)
-{
-       return ovl->info.enabled && ovl->manager && ovl->manager->device;
-}
-
-/* Is rect1 a subset of rect2? */
-static bool rectangle_subset(int x1, int y1, int w1, int h1,
-               int x2, int y2, int w2, int h2)
-{
-       if (x1 < x2 || y1 < y2)
-               return false;
-
-       if (x1 + w1 > x2 + w2)
-               return false;
-
-       if (y1 + h1 > y2 + h2)
-               return false;
-
-       return true;
-}
-
-/* Do rect1 and rect2 overlap? */
-static bool rectangle_intersects(int x1, int y1, int w1, int h1,
-               int x2, int y2, int w2, int h2)
-{
-       if (x1 >= x2 + w2)
-               return false;
-
-       if (x2 >= x1 + w1)
-               return false;
-
-       if (y1 >= y2 + h2)
-               return false;
-
-       if (y2 >= y1 + h1)
-               return false;
-
-       return true;
-}
-
-static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
-{
-       struct omap_overlay_info *oi = &oc->info;
-
-       if (oi->out_width != 0 && oi->width != oi->out_width)
-               return true;
-
-       if (oi->out_height != 0 && oi->height != oi->out_height)
-               return true;
-
-       return false;
-}
-
-static int configure_overlay(enum omap_plane plane)
+int dss_init_overlay_managers(struct platform_device *pdev)
 {
-       struct overlay_cache_data *c;
-       struct manager_cache_data *mc;
-       struct omap_overlay_info *oi, new_oi;
-       struct omap_overlay_manager_info *mi;
-       u16 outw, outh;
-       u16 x, y, w, h;
-       u32 paddr;
-       int r;
-       u16 orig_w, orig_h, orig_outw, orig_outh;
+       int i, r;
 
-       DSSDBGF("%d", plane);
+       num_managers = dss_feat_get_num_mgrs();
 
-       c = &dss_cache.overlay_cache[plane];
-       oi = &c->info;
+       managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers,
+                       GFP_KERNEL);
 
-       if (!c->enabled) {
-               dispc_ovl_enable(plane, 0);
-               return 0;
-       }
+       BUG_ON(managers == NULL);
 
-       mc = &dss_cache.manager_cache[c->channel];
-       mi = &mc->info;
-
-       x = oi->pos_x;
-       y = oi->pos_y;
-       w = oi->width;
-       h = oi->height;
-       outw = oi->out_width == 0 ? oi->width : oi->out_width;
-       outh = oi->out_height == 0 ? oi->height : oi->out_height;
-       paddr = oi->paddr;
-
-       orig_w = w;
-       orig_h = h;
-       orig_outw = outw;
-       orig_outh = outh;
-
-       if (mc->manual_update && mc->do_manual_update) {
-               unsigned bpp;
-               unsigned scale_x_m = w, scale_x_d = outw;
-               unsigned scale_y_m = h, scale_y_d = outh;
-
-               /* If the overlay is outside the update region, disable it */
-               if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
-                                       x, y, outw, outh)) {
-                       dispc_ovl_enable(plane, 0);
-                       return 0;
-               }
+       for (i = 0; i < num_managers; ++i) {
+               struct omap_overlay_manager *mgr = &managers[i];
 
-               switch (oi->color_mode) {
-               case OMAP_DSS_COLOR_NV12:
-                       bpp = 8;
-                       break;
-               case OMAP_DSS_COLOR_RGB16:
-               case OMAP_DSS_COLOR_ARGB16:
-               case OMAP_DSS_COLOR_YUV2:
-               case OMAP_DSS_COLOR_UYVY:
-               case OMAP_DSS_COLOR_RGBA16:
-               case OMAP_DSS_COLOR_RGBX16:
-               case OMAP_DSS_COLOR_ARGB16_1555:
-               case OMAP_DSS_COLOR_XRGB16_1555:
-                       bpp = 16;
+               switch (i) {
+               case 0:
+                       mgr->name = "lcd";
+                       mgr->id = OMAP_DSS_CHANNEL_LCD;
                        break;
-
-               case OMAP_DSS_COLOR_RGB24P:
-                       bpp = 24;
+               case 1:
+                       mgr->name = "tv";
+                       mgr->id = OMAP_DSS_CHANNEL_DIGIT;
                        break;
-
-               case OMAP_DSS_COLOR_RGB24U:
-               case OMAP_DSS_COLOR_ARGB32:
-               case OMAP_DSS_COLOR_RGBA32:
-               case OMAP_DSS_COLOR_RGBX32:
-                       bpp = 32;
+               case 2:
+                       mgr->name = "lcd2";
+                       mgr->id = OMAP_DSS_CHANNEL_LCD2;
                        break;
-
-               default:
-                       BUG();
                }
 
-               if (mc->x > oi->pos_x) {
-                       x = 0;
-                       outw -= (mc->x - oi->pos_x);
-                       paddr += (mc->x - oi->pos_x) *
-                               scale_x_m / scale_x_d * bpp / 8;
-               } else {
-                       x = oi->pos_x - mc->x;
-               }
-
-               if (mc->y > oi->pos_y) {
-                       y = 0;
-                       outh -= (mc->y - oi->pos_y);
-                       paddr += (mc->y - oi->pos_y) *
-                               scale_y_m / scale_y_d *
-                               oi->screen_width * bpp / 8;
-               } else {
-                       y = oi->pos_y - mc->y;
-               }
-
-               if (mc->w < (x + outw))
-                       outw -= (x + outw) - (mc->w);
-
-               if (mc->h < (y + outh))
-                       outh -= (y + outh) - (mc->h);
-
-               w = w * outw / orig_outw;
-               h = h * outh / orig_outh;
-
-               /* YUV mode overlay's input width has to be even and the
-                * algorithm above may adjust the width to be odd.
-                *
-                * Here we adjust the width if needed, preferring to increase
-                * the width if the original width was bigger.
-                */
-               if ((w & 1) &&
-                               (oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
-                                oi->color_mode == OMAP_DSS_COLOR_UYVY)) {
-                       if (orig_w > w)
-                               w += 1;
-                       else
-                               w -= 1;
-               }
-       }
-
-       new_oi = *oi;
-
-       /* update new_oi members which could have been possibly updated */
-       new_oi.pos_x = x;
-       new_oi.pos_y = y;
-       new_oi.width = w;
-       new_oi.height = h;
-       new_oi.out_width = outw;
-       new_oi.out_height = outh;
-       new_oi.paddr = paddr;
-
-       r = dispc_ovl_setup(plane, &new_oi, c->ilace, c->channel,
-               c->replication, c->fifo_low, c->fifo_high);
-       if (r) {
-               /* this shouldn't happen */
-               DSSERR("dispc_ovl_setup failed for ovl %d\n", plane);
-               dispc_ovl_enable(plane, 0);
-               return r;
-       }
-
-       dispc_ovl_enable(plane, 1);
-
-       return 0;
-}
-
-static void configure_manager(enum omap_channel channel)
-{
-       struct omap_overlay_manager_info *mi;
-
-       DSSDBGF("%d", channel);
-
-       /* picking info from the cache */
-       mi = &dss_cache.manager_cache[channel].info;
-
-       dispc_mgr_set_default_color(channel, mi->default_color);
-       dispc_mgr_set_trans_key(channel, mi->trans_key_type, mi->trans_key);
-       dispc_mgr_enable_trans_key(channel, mi->trans_enabled);
-       dispc_mgr_enable_alpha_fixed_zorder(channel, mi->partial_alpha_enabled);
-       if (dss_has_feature(FEAT_CPR)) {
-               dispc_mgr_enable_cpr(channel, mi->cpr_enable);
-               dispc_mgr_set_cpr_coef(channel, &mi->cpr_coefs);
-       }
-}
-
-/* configure_dispc() tries to write values from cache to shadow registers.
- * It writes only to those managers/overlays that are not busy.
- * returns 0 if everything could be written to shadow registers.
- * returns 1 if not everything could be written to shadow registers. */
-static int configure_dispc(void)
-{
-       struct overlay_cache_data *oc;
-       struct manager_cache_data *mc;
-       const int num_ovls = dss_feat_get_num_ovls();
-       const int num_mgrs = dss_feat_get_num_mgrs();
-       int i;
-       int r;
-       bool mgr_busy[MAX_DSS_MANAGERS];
-       bool mgr_go[MAX_DSS_MANAGERS];
-       bool busy;
-
-       r = 0;
-       busy = false;
-
-       for (i = 0; i < num_mgrs; i++) {
-               mgr_busy[i] = dispc_mgr_go_busy(i);
-               mgr_go[i] = false;
-       }
-
-       /* Commit overlay settings */
-       for (i = 0; i < num_ovls; ++i) {
-               oc = &dss_cache.overlay_cache[i];
-               mc = &dss_cache.manager_cache[oc->channel];
+               mgr->set_device = &dss_mgr_set_device;
+               mgr->unset_device = &dss_mgr_unset_device;
+               mgr->apply = &omap_dss_mgr_apply;
+               mgr->set_manager_info = &dss_mgr_set_info;
+               mgr->get_manager_info = &dss_mgr_get_info;
+               mgr->wait_for_go = &dss_mgr_wait_for_go;
+               mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
 
-               if (!oc->dirty)
-                       continue;
+               mgr->caps = 0;
+               mgr->supported_displays =
+                       dss_feat_get_supported_displays(mgr->id);
 
-               if (mc->manual_update && !mc->do_manual_update)
-                       continue;
+               INIT_LIST_HEAD(&mgr->overlays);
 
-               if (mgr_busy[oc->channel]) {
-                       busy = true;
-                       continue;
-               }
+               r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
+                               &pdev->dev.kobj, "manager%d", i);
 
-               r = configure_overlay(i);
                if (r)
-                       DSSERR("configure_overlay %d failed\n", i);
-
-               oc->dirty = false;
-               oc->shadow_dirty = true;
-               mgr_go[oc->channel] = true;
-       }
-
-       /* Commit manager settings */
-       for (i = 0; i < num_mgrs; ++i) {
-               mc = &dss_cache.manager_cache[i];
-
-               if (!mc->dirty)
-                       continue;
-
-               if (mc->manual_update && !mc->do_manual_update)
-                       continue;
-
-               if (mgr_busy[i]) {
-                       busy = true;
-                       continue;
-               }
-
-               configure_manager(i);
-               mc->dirty = false;
-               mc->shadow_dirty = true;
-               mgr_go[i] = true;
-       }
-
-       /* set GO */
-       for (i = 0; i < num_mgrs; ++i) {
-               mc = &dss_cache.manager_cache[i];
-
-               if (!mgr_go[i])
-                       continue;
-
-               /* We don't need GO with manual update display. LCD iface will
-                * always be turned off after frame, and new settings will be
-                * taken in to use at next update */
-               if (!mc->manual_update)
-                       dispc_mgr_go(i);
-       }
-
-       if (busy)
-               r = 1;
-       else
-               r = 0;
-
-       return r;
-}
-
-/* Make the coordinates even. There are some strange problems with OMAP and
- * partial DSI update when the update widths are odd. */
-static void make_even(u16 *x, u16 *w)
-{
-       u16 x1, x2;
-
-       x1 = *x;
-       x2 = *x + *w;
-
-       x1 &= ~1;
-       x2 = ALIGN(x2, 2);
-
-       *x = x1;
-       *w = x2 - x1;
-}
-
-/* Configure dispc for partial update. Return possibly modified update
- * area */
-void dss_setup_partial_planes(struct omap_dss_device *dssdev,
-               u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area)
-{
-       struct overlay_cache_data *oc;
-       struct manager_cache_data *mc;
-       struct omap_overlay_info *oi;
-       const int num_ovls = dss_feat_get_num_ovls();
-       struct omap_overlay_manager *mgr;
-       int i;
-       u16 x, y, w, h;
-       unsigned long flags;
-       bool area_changed;
-
-       x = *xi;
-       y = *yi;
-       w = *wi;
-       h = *hi;
-
-       DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n",
-               *xi, *yi, *wi, *hi);
-
-       mgr = dssdev->manager;
-
-       if (!mgr) {
-               DSSDBG("no manager\n");
-               return;
+                       DSSERR("failed to create sysfs file\n");
        }
 
-       make_even(&x, &w);
-
-       spin_lock_irqsave(&dss_cache.lock, flags);
-
-       /*
-        * Execute the outer loop until the inner loop has completed
-        * once without increasing the update area. This will ensure that
-        * all scaled overlays end up completely within the update area.
-        */
-       do {
-               area_changed = false;
-
-               /* We need to show the whole overlay if it is scaled. So look
-                * for those, and make the update area larger if found.
-                * Also mark the overlay cache dirty */
-               for (i = 0; i < num_ovls; ++i) {
-                       unsigned x1, y1, x2, y2;
-                       unsigned outw, outh;
-
-                       oc = &dss_cache.overlay_cache[i];
-                       oi = &oc->info;
-
-                       if (oc->channel != mgr->id)
-                               continue;
-
-                       oc->dirty = true;
-
-                       if (!enlarge_update_area)
-                               continue;
-
-                       if (!oc->enabled)
-                               continue;
-
-                       if (!dispc_is_overlay_scaled(oc))
-                               continue;
-
-                       outw = oi->out_width == 0 ?
-                               oi->width : oi->out_width;
-                       outh = oi->out_height == 0 ?
-                               oi->height : oi->out_height;
-
-                       /* is the overlay outside the update region? */
-                       if (!rectangle_intersects(x, y, w, h,
-                                               oi->pos_x, oi->pos_y,
-                                               outw, outh))
-                               continue;
-
-                       /* if the overlay totally inside the update region? */
-                       if (rectangle_subset(oi->pos_x, oi->pos_y, outw, outh,
-                                               x, y, w, h))
-                               continue;
-
-                       if (x > oi->pos_x)
-                               x1 = oi->pos_x;
-                       else
-                               x1 = x;
-
-                       if (y > oi->pos_y)
-                               y1 = oi->pos_y;
-                       else
-                               y1 = y;
-
-                       if ((x + w) < (oi->pos_x + outw))
-                               x2 = oi->pos_x + outw;
-                       else
-                               x2 = x + w;
-
-                       if ((y + h) < (oi->pos_y + outh))
-                               y2 = oi->pos_y + outh;
-                       else
-                               y2 = y + h;
-
-                       x = x1;
-                       y = y1;
-                       w = x2 - x1;
-                       h = y2 - y1;
-
-                       make_even(&x, &w);
-
-                       DSSDBG("changing upd area due to ovl(%d) "
-                              "scaling %d,%d %dx%d\n",
-                               i, x, y, w, h);
-
-                       area_changed = true;
-               }
-       } while (area_changed);
-
-       mc = &dss_cache.manager_cache[mgr->id];
-       mc->do_manual_update = true;
-       mc->enlarge_update_area = enlarge_update_area;
-       mc->x = x;
-       mc->y = y;
-       mc->w = w;
-       mc->h = h;
-
-       configure_dispc();
-
-       mc->do_manual_update = false;
-
-       spin_unlock_irqrestore(&dss_cache.lock, flags);
-
-       *xi = x;
-       *yi = y;
-       *wi = w;
-       *hi = h;
+       return 0;
 }
 
-void dss_start_update(struct omap_dss_device *dssdev)
+void dss_uninit_overlay_managers(struct platform_device *pdev)
 {
-       struct manager_cache_data *mc;
-       struct overlay_cache_data *oc;
-       const int num_ovls = dss_feat_get_num_ovls();
-       const int num_mgrs = dss_feat_get_num_mgrs();
-       struct omap_overlay_manager *mgr;
        int i;
 
-       mgr = dssdev->manager;
+       for (i = 0; i < num_managers; ++i) {
+               struct omap_overlay_manager *mgr = &managers[i];
 
-       for (i = 0; i < num_ovls; ++i) {
-               oc = &dss_cache.overlay_cache[i];
-               if (oc->channel != mgr->id)
-                       continue;
-
-               oc->shadow_dirty = false;
-       }
-
-       for (i = 0; i < num_mgrs; ++i) {
-               mc = &dss_cache.manager_cache[i];
-               if (mgr->id != i)
-                       continue;
-
-               mc->shadow_dirty = false;
+               kobject_del(&mgr->kobj);
+               kobject_put(&mgr->kobj);
        }
 
-       dssdev->manager->enable(dssdev->manager);
+       kfree(managers);
+       managers = NULL;
+       num_managers = 0;
 }
 
-static void dss_apply_irq_handler(void *data, u32 mask)
+int omap_dss_get_num_overlay_managers(void)
 {
-       struct manager_cache_data *mc;
-       struct overlay_cache_data *oc;
-       const int num_ovls = dss_feat_get_num_ovls();
-       const int num_mgrs = dss_feat_get_num_mgrs();
-       int i, r;
-       bool mgr_busy[MAX_DSS_MANAGERS];
-       u32 irq_mask;
-
-       for (i = 0; i < num_mgrs; i++)
-               mgr_busy[i] = dispc_mgr_go_busy(i);
-
-       spin_lock(&dss_cache.lock);
-
-       for (i = 0; i < num_ovls; ++i) {
-               oc = &dss_cache.overlay_cache[i];
-               if (!mgr_busy[oc->channel])
-                       oc->shadow_dirty = false;
-       }
-
-       for (i = 0; i < num_mgrs; ++i) {
-               mc = &dss_cache.manager_cache[i];
-               if (!mgr_busy[i])
-                       mc->shadow_dirty = false;
-       }
-
-       r = configure_dispc();
-       if (r == 1)
-               goto end;
-
-       /* re-read busy flags */
-       for (i = 0; i < num_mgrs; i++)
-               mgr_busy[i] = dispc_mgr_go_busy(i);
-
-       /* keep running as long as there are busy managers, so that
-        * we can collect overlay-applied information */
-       for (i = 0; i < num_mgrs; ++i) {
-               if (mgr_busy[i])
-                       goto end;
-       }
-
-       irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
-                       DISPC_IRQ_EVSYNC_EVEN;
-       if (dss_has_feature(FEAT_MGR_LCD2))
-               irq_mask |= DISPC_IRQ_VSYNC2;
-
-       omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask);
-       dss_cache.irq_enabled = false;
-
-end:
-       spin_unlock(&dss_cache.lock);
+       return num_managers;
 }
+EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
 
-static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
+struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
 {
-       struct overlay_cache_data *oc;
-       struct manager_cache_data *mc;
-       int i;
-       struct omap_overlay *ovl;
-       int num_planes_enabled = 0;
-       bool use_fifomerge;
-       unsigned long flags;
-       int r;
-
-       DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
-
-       r = dispc_runtime_get();
-       if (r)
-               return r;
-
-       spin_lock_irqsave(&dss_cache.lock, flags);
-
-       /* Configure overlays */
-       for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
-               struct omap_dss_device *dssdev;
-
-               ovl = omap_dss_get_overlay(i);
-
-               oc = &dss_cache.overlay_cache[ovl->id];
-
-               if (ovl->manager_changed) {
-                       ovl->manager_changed = false;
-                       ovl->info_dirty  = true;
-               }
-
-               if (!overlay_enabled(ovl)) {
-                       if (oc->enabled) {
-                               oc->enabled = false;
-                               oc->dirty = true;
-                       }
-                       continue;
-               }
-
-               if (!ovl->info_dirty) {
-                       if (oc->enabled)
-                               ++num_planes_enabled;
-                       continue;
-               }
-
-               dssdev = ovl->manager->device;
-
-               if (dss_check_overlay(ovl, dssdev)) {
-                       if (oc->enabled) {
-                               oc->enabled = false;
-                               oc->dirty = true;
-                       }
-                       continue;
-               }
-
-               ovl->info_dirty = false;
-               oc->dirty = true;
-               oc->info = ovl->info;
-
-               oc->replication =
-                       dss_use_replication(dssdev, ovl->info.color_mode);
-
-               oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
-
-               oc->channel = ovl->manager->id;
-
-               oc->enabled = true;
-
-               ++num_planes_enabled;
-       }
-
-       /* Configure managers */
-       list_for_each_entry(mgr, &manager_list, list) {
-               struct omap_dss_device *dssdev;
+       if (num >= num_managers)
+               return NULL;
 
-               mc = &dss_cache.manager_cache[mgr->id];
-
-               if (mgr->device_changed) {
-                       mgr->device_changed = false;
-                       mgr->info_dirty  = true;
-               }
-
-               if (!mgr->info_dirty)
-                       continue;
-
-               if (!mgr->device)
-                       continue;
-
-               dssdev = mgr->device;
-
-               mgr->info_dirty = false;
-               mc->dirty = true;
-               mc->info = mgr->info;
-
-               mc->manual_update =
-                       dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
-       }
-
-       /* XXX TODO: Try to get fifomerge working. The problem is that it
-        * affects both managers, not individually but at the same time. This
-        * means the change has to be well synchronized. I guess the proper way
-        * is to have a two step process for fifo merge:
-        *        fifomerge enable:
-        *             1. disable other planes, leaving one plane enabled
-        *             2. wait until the planes are disabled on HW
-        *             3. config merged fifo thresholds, enable fifomerge
-        *        fifomerge disable:
-        *             1. config unmerged fifo thresholds, disable fifomerge
-        *             2. wait until fifo changes are in HW
-        *             3. enable planes
-        */
-       use_fifomerge = false;
-
-       /* Configure overlay fifos */
-       for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
-               struct omap_dss_device *dssdev;
-               u32 size, burst_size;
-
-               ovl = omap_dss_get_overlay(i);
-
-               oc = &dss_cache.overlay_cache[ovl->id];
-
-               if (!oc->enabled)
-                       continue;
-
-               dssdev = ovl->manager->device;
-
-               size = dispc_ovl_get_fifo_size(ovl->id);
-               if (use_fifomerge)
-                       size *= 3;
-
-               burst_size = dispc_ovl_get_burst_size(ovl->id);
-
-               switch (dssdev->type) {
-               case OMAP_DISPLAY_TYPE_DPI:
-               case OMAP_DISPLAY_TYPE_DBI:
-               case OMAP_DISPLAY_TYPE_SDI:
-               case OMAP_DISPLAY_TYPE_VENC:
-               case OMAP_DISPLAY_TYPE_HDMI:
-                       default_get_overlay_fifo_thresholds(ovl->id, size,
-                                       burst_size, &oc->fifo_low,
-                                       &oc->fifo_high);
-                       break;
-#ifdef CONFIG_OMAP2_DSS_DSI
-               case OMAP_DISPLAY_TYPE_DSI:
-                       dsi_get_overlay_fifo_thresholds(ovl->id, size,
-                                       burst_size, &oc->fifo_low,
-                                       &oc->fifo_high);
-                       break;
-#endif
-               default:
-                       BUG();
-               }
-       }
-
-       r = 0;
-       if (!dss_cache.irq_enabled) {
-               u32 mask;
-
-               mask = DISPC_IRQ_VSYNC  | DISPC_IRQ_EVSYNC_ODD |
-                       DISPC_IRQ_EVSYNC_EVEN;
-               if (dss_has_feature(FEAT_MGR_LCD2))
-                       mask |= DISPC_IRQ_VSYNC2;
-
-               r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
-               dss_cache.irq_enabled = true;
-       }
-       configure_dispc();
-
-       spin_unlock_irqrestore(&dss_cache.lock, flags);
-
-       dispc_runtime_put();
-
-       return r;
+       return &managers[num];
 }
+EXPORT_SYMBOL(omap_dss_get_overlay_manager);
 
-static int dss_check_manager(struct omap_overlay_manager *mgr)
+int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
+               const struct omap_overlay_manager_info *info)
 {
        if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
                /*
                 * OMAP3 supports only graphics source transparency color key
                 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
-                * Alpha Mode
+                * Alpha Mode.
                 */
-               if (mgr->info.partial_alpha_enabled && mgr->info.trans_enabled
-                       && mgr->info.trans_key_type !=
-                               OMAP_DSS_COLOR_KEY_GFX_DST)
+               if (info->partial_alpha_enabled && info->trans_enabled
+                       && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
+                       DSSERR("check_manager: illegal transparency key\n");
                        return -EINVAL;
+               }
        }
 
        return 0;
 }
 
-static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
-               struct omap_overlay_manager_info *info)
-{
-       int r;
-       struct omap_overlay_manager_info old_info;
-
-       old_info = mgr->info;
-       mgr->info = *info;
-
-       r = dss_check_manager(mgr);
-       if (r) {
-               mgr->info = old_info;
-               return r;
-       }
-
-       mgr->info_dirty = true;
-
-       return 0;
-}
-
-static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
-               struct omap_overlay_manager_info *info)
+static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
+               struct omap_overlay_info **overlay_infos)
 {
-       *info = mgr->info;
-}
+       struct omap_overlay *ovl1, *ovl2;
+       struct omap_overlay_info *info1, *info2;
 
-static int dss_mgr_enable(struct omap_overlay_manager *mgr)
-{
-       dispc_mgr_enable(mgr->id, 1);
-       return 0;
-}
+       list_for_each_entry(ovl1, &mgr->overlays, list) {
+               info1 = overlay_infos[ovl1->id];
 
-static int dss_mgr_disable(struct omap_overlay_manager *mgr)
-{
-       dispc_mgr_enable(mgr->id, 0);
-       return 0;
-}
-
-static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
-{
-       ++num_managers;
-       list_add_tail(&manager->list, &manager_list);
-}
-
-int dss_init_overlay_managers(struct platform_device *pdev)
-{
-       int i, r;
-
-       spin_lock_init(&dss_cache.lock);
-
-       INIT_LIST_HEAD(&manager_list);
-
-       num_managers = 0;
-
-       for (i = 0; i < dss_feat_get_num_mgrs(); ++i) {
-               struct omap_overlay_manager *mgr;
-               mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
-
-               BUG_ON(mgr == NULL);
-
-               switch (i) {
-               case 0:
-                       mgr->name = "lcd";
-                       mgr->id = OMAP_DSS_CHANNEL_LCD;
-                       break;
-               case 1:
-                       mgr->name = "tv";
-                       mgr->id = OMAP_DSS_CHANNEL_DIGIT;
-                       break;
-               case 2:
-                       mgr->name = "lcd2";
-                       mgr->id = OMAP_DSS_CHANNEL_LCD2;
-                       break;
-               }
-
-               mgr->set_device = &omap_dss_set_device;
-               mgr->unset_device = &omap_dss_unset_device;
-               mgr->apply = &omap_dss_mgr_apply;
-               mgr->set_manager_info = &omap_dss_mgr_set_info;
-               mgr->get_manager_info = &omap_dss_mgr_get_info;
-               mgr->wait_for_go = &dss_mgr_wait_for_go;
-               mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
-
-               mgr->enable = &dss_mgr_enable;
-               mgr->disable = &dss_mgr_disable;
-
-               mgr->caps = 0;
-               mgr->supported_displays =
-                       dss_feat_get_supported_displays(mgr->id);
+               if (info1 == NULL)
+                       continue;
 
-               dss_overlay_setup_dispc_manager(mgr);
+               list_for_each_entry(ovl2, &mgr->overlays, list) {
+                       if (ovl1 == ovl2)
+                               continue;
 
-               omap_dss_add_overlay_manager(mgr);
+                       info2 = overlay_infos[ovl2->id];
 
-               r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
-                               &pdev->dev.kobj, "manager%d", i);
+                       if (info2 == NULL)
+                               continue;
 
-               if (r) {
-                       DSSERR("failed to create sysfs file\n");
-                       continue;
+                       if (info1->zorder == info2->zorder) {
+                               DSSERR("overlays %d and %d have the same "
+                                               "zorder %d\n",
+                                       ovl1->id, ovl2->id, info1->zorder);
+                               return -EINVAL;
+                       }
                }
        }
 
        return 0;
 }
 
-void dss_uninit_overlay_managers(struct platform_device *pdev)
+int dss_mgr_check(struct omap_overlay_manager *mgr,
+               struct omap_dss_device *dssdev,
+               struct omap_overlay_manager_info *info,
+               struct omap_overlay_info **overlay_infos)
 {
-       struct omap_overlay_manager *mgr;
+       struct omap_overlay *ovl;
+       int r;
 
-       while (!list_empty(&manager_list)) {
-               mgr = list_first_entry(&manager_list,
-                               struct omap_overlay_manager, list);
-               list_del(&mgr->list);
-               kobject_del(&mgr->kobj);
-               kobject_put(&mgr->kobj);
-               kfree(mgr);
+       if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
+               r = dss_mgr_check_zorder(mgr, overlay_infos);
+               if (r)
+                       return r;
        }
 
-       num_managers = 0;
-}
+       list_for_each_entry(ovl, &mgr->overlays, list) {
+               struct omap_overlay_info *oi;
+               int r;
 
-int omap_dss_get_num_overlay_managers(void)
-{
-       return num_managers;
-}
-EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
+               oi = overlay_infos[ovl->id];
 
-struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
-{
-       int i = 0;
-       struct omap_overlay_manager *mgr;
+               if (oi == NULL)
+                       continue;
 
-       list_for_each_entry(mgr, &manager_list, list) {
-               if (i++ == num)
-                       return mgr;
+               r = dss_ovl_check(ovl, oi, dssdev);
+               if (r)
+                       return r;
        }
 
-       return NULL;
+       return 0;
 }
-EXPORT_SYMBOL(omap_dss_get_overlay_manager);
-
index ab8e40e48759969671bc6025a4ef610ef3f61272..6e821810deec092324a0f1013fbb3cb32bba72dd 100644 (file)
@@ -38,7 +38,7 @@
 #include "dss_features.h"
 
 static int num_overlays;
-static struct list_head overlay_list;
+static struct omap_overlay *overlays;
 
 static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
 {
@@ -124,19 +124,31 @@ err:
 
 static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
 {
+       struct omap_overlay_info info;
+
+       ovl->get_overlay_info(ovl, &info);
+
        return snprintf(buf, PAGE_SIZE, "%d,%d\n",
-                       ovl->info.width, ovl->info.height);
+                       info.width, info.height);
 }
 
 static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width);
+       struct omap_overlay_info info;
+
+       ovl->get_overlay_info(ovl, &info);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);
 }
 
 static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
 {
+       struct omap_overlay_info info;
+
+       ovl->get_overlay_info(ovl, &info);
+
        return snprintf(buf, PAGE_SIZE, "%d,%d\n",
-                       ovl->info.pos_x, ovl->info.pos_y);
+                       info.pos_x, info.pos_y);
 }
 
 static ssize_t overlay_position_store(struct omap_overlay *ovl,
@@ -170,8 +182,12 @@ static ssize_t overlay_position_store(struct omap_overlay *ovl,
 
 static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
 {
+       struct omap_overlay_info info;
+
+       ovl->get_overlay_info(ovl, &info);
+
        return snprintf(buf, PAGE_SIZE, "%d,%d\n",
-                       ovl->info.out_width, ovl->info.out_height);
+                       info.out_width, info.out_height);
 }
 
 static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
@@ -205,7 +221,7 @@ static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
 
 static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled);
+       return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
 }
 
 static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
@@ -213,33 +229,30 @@ static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
 {
        int r;
        bool enable;
-       struct omap_overlay_info info;
-
-       ovl->get_overlay_info(ovl, &info);
 
        r = strtobool(buf, &enable);
        if (r)
                return r;
 
-       info.enabled = enable;
+       if (enable)
+               r = ovl->enable(ovl);
+       else
+               r = ovl->disable(ovl);
 
-       r = ovl->set_overlay_info(ovl, &info);
        if (r)
                return r;
 
-       if (ovl->manager) {
-               r = ovl->manager->apply(ovl->manager);
-               if (r)
-                       return r;
-       }
-
        return size;
 }
 
 static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
 {
+       struct omap_overlay_info info;
+
+       ovl->get_overlay_info(ovl, &info);
+
        return snprintf(buf, PAGE_SIZE, "%d\n",
-                       ovl->info.global_alpha);
+                       info.global_alpha);
 }
 
 static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
@@ -276,8 +289,12 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
 static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
                char *buf)
 {
+       struct omap_overlay_info info;
+
+       ovl->get_overlay_info(ovl, &info);
+
        return snprintf(buf, PAGE_SIZE, "%d\n",
-                       ovl->info.pre_mult_alpha);
+                       info.pre_mult_alpha);
 }
 
 static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
@@ -313,7 +330,11 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
 
 static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.zorder);
+       struct omap_overlay_info info;
+
+       ovl->get_overlay_info(ovl, &info);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder);
 }
 
 static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
@@ -430,183 +451,6 @@ static struct kobj_type overlay_ktype = {
        .default_attrs = overlay_sysfs_attrs,
 };
 
-/* Check if overlay parameters are compatible with display */
-int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
-{
-       struct omap_overlay_info *info;
-       u16 outw, outh;
-       u16 dw, dh;
-       int i;
-
-       if (!dssdev)
-               return 0;
-
-       if (!ovl->info.enabled)
-               return 0;
-
-       info = &ovl->info;
-
-       if (info->paddr == 0) {
-               DSSDBG("check_overlay failed: paddr 0\n");
-               return -EINVAL;
-       }
-
-       dssdev->driver->get_resolution(dssdev, &dw, &dh);
-
-       DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n",
-                       ovl->id,
-                       info->pos_x, info->pos_y,
-                       info->width, info->height,
-                       info->out_width, info->out_height,
-                       dw, dh);
-
-       if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
-               outw = info->width;
-               outh = info->height;
-       } else {
-               if (info->out_width == 0)
-                       outw = info->width;
-               else
-                       outw = info->out_width;
-
-               if (info->out_height == 0)
-                       outh = info->height;
-               else
-                       outh = info->out_height;
-       }
-
-       if (dw < info->pos_x + outw) {
-               DSSDBG("check_overlay failed 1: %d < %d + %d\n",
-                               dw, info->pos_x, outw);
-               return -EINVAL;
-       }
-
-       if (dh < info->pos_y + outh) {
-               DSSDBG("check_overlay failed 2: %d < %d + %d\n",
-                               dh, info->pos_y, outh);
-               return -EINVAL;
-       }
-
-       if ((ovl->supported_modes & info->color_mode) == 0) {
-               DSSERR("overlay doesn't support mode %d\n", info->color_mode);
-               return -EINVAL;
-       }
-
-       if (ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) {
-               if (info->zorder < 0 || info->zorder > 3) {
-                       DSSERR("zorder out of range: %d\n",
-                               info->zorder);
-                       return -EINVAL;
-               }
-               /*
-                * Check that zorder doesn't match with zorder of any other
-                * overlay which is enabled and is also connected to the same
-                * manager
-                */
-               for (i = 0; i < omap_dss_get_num_overlays(); i++) {
-                       struct omap_overlay *tmp_ovl = omap_dss_get_overlay(i);
-
-                       if (tmp_ovl->id != ovl->id &&
-                                       tmp_ovl->manager == ovl->manager &&
-                                       tmp_ovl->info.enabled == true &&
-                                       tmp_ovl->info.zorder == info->zorder) {
-                               DSSERR("%s and %s have same zorder: %d\n",
-                                       ovl->name, tmp_ovl->name, info->zorder);
-                               return -EINVAL;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static int dss_ovl_set_overlay_info(struct omap_overlay *ovl,
-               struct omap_overlay_info *info)
-{
-       int r;
-       struct omap_overlay_info old_info;
-
-       old_info = ovl->info;
-       ovl->info = *info;
-
-       if (ovl->manager) {
-               r = dss_check_overlay(ovl, ovl->manager->device);
-               if (r) {
-                       ovl->info = old_info;
-                       return r;
-               }
-       }
-
-       ovl->info_dirty = true;
-
-       return 0;
-}
-
-static void dss_ovl_get_overlay_info(struct omap_overlay *ovl,
-               struct omap_overlay_info *info)
-{
-       *info = ovl->info;
-}
-
-static int dss_ovl_wait_for_go(struct omap_overlay *ovl)
-{
-       return dss_mgr_wait_for_go_ovl(ovl);
-}
-
-static int omap_dss_set_manager(struct omap_overlay *ovl,
-               struct omap_overlay_manager *mgr)
-{
-       if (!mgr)
-               return -EINVAL;
-
-       if (ovl->manager) {
-               DSSERR("overlay '%s' already has a manager '%s'\n",
-                               ovl->name, ovl->manager->name);
-               return -EINVAL;
-       }
-
-       if (ovl->info.enabled) {
-               DSSERR("overlay has to be disabled to change the manager\n");
-               return -EINVAL;
-       }
-
-       ovl->manager = mgr;
-       ovl->manager_changed = true;
-
-       /* XXX: When there is an overlay on a DSI manual update display, and
-        * the overlay is first disabled, then moved to tv, and enabled, we
-        * seem to get SYNC_LOST_DIGIT error.
-        *
-        * Waiting doesn't seem to help, but updating the manual update display
-        * after disabling the overlay seems to fix this. This hints that the
-        * overlay is perhaps somehow tied to the LCD output until the output
-        * is updated.
-        *
-        * Userspace workaround for this is to update the LCD after disabling
-        * the overlay, but before moving the overlay to TV.
-        */
-
-       return 0;
-}
-
-static int omap_dss_unset_manager(struct omap_overlay *ovl)
-{
-       if (!ovl->manager) {
-               DSSERR("failed to detach overlay: manager not set\n");
-               return -EINVAL;
-       }
-
-       if (ovl->info.enabled) {
-               DSSERR("overlay has to be disabled to unset the manager\n");
-               return -EINVAL;
-       }
-
-       ovl->manager = NULL;
-       ovl->manager_changed = true;
-
-       return 0;
-}
-
 int omap_dss_get_num_overlays(void)
 {
        return num_overlays;
@@ -615,134 +459,65 @@ EXPORT_SYMBOL(omap_dss_get_num_overlays);
 
 struct omap_overlay *omap_dss_get_overlay(int num)
 {
-       int i = 0;
-       struct omap_overlay *ovl;
+       if (num >= num_overlays)
+               return NULL;
 
-       list_for_each_entry(ovl, &overlay_list, list) {
-               if (i++ == num)
-                       return ovl;
-       }
-
-       return NULL;
+       return &overlays[num];
 }
 EXPORT_SYMBOL(omap_dss_get_overlay);
 
-static void omap_dss_add_overlay(struct omap_overlay *overlay)
-{
-       ++num_overlays;
-       list_add_tail(&overlay->list, &overlay_list);
-}
-
-static struct omap_overlay *dispc_overlays[MAX_DSS_OVERLAYS];
-
-void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr)
-{
-       mgr->num_overlays = dss_feat_get_num_ovls();
-       mgr->overlays = dispc_overlays;
-}
-
-#ifdef L4_EXAMPLE
-static struct omap_overlay *l4_overlays[1];
-void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr)
-{
-       mgr->num_overlays = 1;
-       mgr->overlays = l4_overlays;
-}
-#endif
-
 void dss_init_overlays(struct platform_device *pdev)
 {
        int i, r;
 
-       INIT_LIST_HEAD(&overlay_list);
+       num_overlays = dss_feat_get_num_ovls();
 
-       num_overlays = 0;
+       overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays,
+                       GFP_KERNEL);
 
-       for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
-               struct omap_overlay *ovl;
-               ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
+       BUG_ON(overlays == NULL);
 
-               BUG_ON(ovl == NULL);
+       for (i = 0; i < num_overlays; ++i) {
+               struct omap_overlay *ovl = &overlays[i];
 
                switch (i) {
                case 0:
                        ovl->name = "gfx";
                        ovl->id = OMAP_DSS_GFX;
-                       ovl->info.global_alpha = 255;
-                       ovl->info.zorder = 0;
                        break;
                case 1:
                        ovl->name = "vid1";
                        ovl->id = OMAP_DSS_VIDEO1;
-                       ovl->info.global_alpha = 255;
-                       ovl->info.zorder =
-                               dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
                        break;
                case 2:
                        ovl->name = "vid2";
                        ovl->id = OMAP_DSS_VIDEO2;
-                       ovl->info.global_alpha = 255;
-                       ovl->info.zorder =
-                               dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
                        break;
                case 3:
                        ovl->name = "vid3";
                        ovl->id = OMAP_DSS_VIDEO3;
-                       ovl->info.global_alpha = 255;
-                       ovl->info.zorder =
-                               dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
                        break;
                }
 
-               ovl->set_manager = &omap_dss_set_manager;
-               ovl->unset_manager = &omap_dss_unset_manager;
-               ovl->set_overlay_info = &dss_ovl_set_overlay_info;
-               ovl->get_overlay_info = &dss_ovl_get_overlay_info;
-               ovl->wait_for_go = &dss_ovl_wait_for_go;
+               ovl->is_enabled = &dss_ovl_is_enabled;
+               ovl->enable = &dss_ovl_enable;
+               ovl->disable = &dss_ovl_disable;
+               ovl->set_manager = &dss_ovl_set_manager;
+               ovl->unset_manager = &dss_ovl_unset_manager;
+               ovl->set_overlay_info = &dss_ovl_set_info;
+               ovl->get_overlay_info = &dss_ovl_get_info;
+               ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;
 
                ovl->caps = dss_feat_get_overlay_caps(ovl->id);
                ovl->supported_modes =
                        dss_feat_get_supported_color_modes(ovl->id);
 
-               omap_dss_add_overlay(ovl);
-
                r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
                                &pdev->dev.kobj, "overlay%d", i);
 
-               if (r) {
-                       DSSERR("failed to create sysfs file\n");
-                       continue;
-               }
-
-               dispc_overlays[i] = ovl;
-       }
-
-#ifdef L4_EXAMPLE
-       {
-               struct omap_overlay *ovl;
-               ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
-
-               BUG_ON(ovl == NULL);
-
-               ovl->name = "l4";
-               ovl->supported_modes = OMAP_DSS_COLOR_RGB24U;
-
-               ovl->set_manager = &omap_dss_set_manager;
-               ovl->unset_manager = &omap_dss_unset_manager;
-               ovl->set_overlay_info = &dss_ovl_set_overlay_info;
-               ovl->get_overlay_info = &dss_ovl_get_overlay_info;
-
-               omap_dss_add_overlay(ovl);
-
-               r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
-                               &pdev->dev.kobj, "overlayl4");
-
                if (r)
                        DSSERR("failed to create sysfs file\n");
-
-               l4_overlays[0] = ovl;
        }
-#endif
 }
 
 /* connect overlays to the new device, if not already connected. if force
@@ -795,8 +570,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
                        ovl = omap_dss_get_overlay(i);
                        if (!ovl->manager || force) {
                                if (ovl->manager)
-                                       omap_dss_unset_manager(ovl);
-                               omap_dss_set_manager(ovl, mgr);
+                                       ovl->unset_manager(ovl);
+                               ovl->set_manager(ovl, mgr);
                        }
                }
 
@@ -806,17 +581,95 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
 
 void dss_uninit_overlays(struct platform_device *pdev)
 {
-       struct omap_overlay *ovl;
+       int i;
+
+       for (i = 0; i < num_overlays; ++i) {
+               struct omap_overlay *ovl = &overlays[i];
 
-       while (!list_empty(&overlay_list)) {
-               ovl = list_first_entry(&overlay_list,
-                               struct omap_overlay, list);
-               list_del(&ovl->list);
                kobject_del(&ovl->kobj);
                kobject_put(&ovl->kobj);
-               kfree(ovl);
        }
 
+       kfree(overlays);
+       overlays = NULL;
        num_overlays = 0;
 }
 
+int dss_ovl_simple_check(struct omap_overlay *ovl,
+               const struct omap_overlay_info *info)
+{
+       if (info->paddr == 0) {
+               DSSERR("check_overlay: paddr cannot be 0\n");
+               return -EINVAL;
+       }
+
+       if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
+               if (info->out_width != 0 && info->width != info->out_width) {
+                       DSSERR("check_overlay: overlay %d doesn't support "
+                                       "scaling\n", ovl->id);
+                       return -EINVAL;
+               }
+
+               if (info->out_height != 0 && info->height != info->out_height) {
+                       DSSERR("check_overlay: overlay %d doesn't support "
+                                       "scaling\n", ovl->id);
+                       return -EINVAL;
+               }
+       }
+
+       if ((ovl->supported_modes & info->color_mode) == 0) {
+               DSSERR("check_overlay: overlay %d doesn't support mode %d\n",
+                               ovl->id, info->color_mode);
+               return -EINVAL;
+       }
+
+       if (info->zorder >= omap_dss_get_num_overlays()) {
+               DSSERR("check_overlay: zorder %d too high\n", info->zorder);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int dss_ovl_check(struct omap_overlay *ovl,
+               struct omap_overlay_info *info, struct omap_dss_device *dssdev)
+{
+       u16 outw, outh;
+       u16 dw, dh;
+
+       if (dssdev == NULL)
+               return 0;
+
+       dssdev->driver->get_resolution(dssdev, &dw, &dh);
+
+       if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
+               outw = info->width;
+               outh = info->height;
+       } else {
+               if (info->out_width == 0)
+                       outw = info->width;
+               else
+                       outw = info->out_width;
+
+               if (info->out_height == 0)
+                       outh = info->height;
+               else
+                       outh = info->out_height;
+       }
+
+       if (dw < info->pos_x + outw) {
+               DSSERR("overlay %d horizontally not inside the display area "
+                               "(%d + %d >= %d)\n",
+                               ovl->id, info->pos_x, outw, dw);
+               return -EINVAL;
+       }
+
+       if (dh < info->pos_y + outh) {
+               DSSERR("overlay %d vertically not inside the display area "
+                               "(%d + %d >= %d)\n",
+                               ovl->id, info->pos_y, outh, dh);
+               return -EINVAL;
+       }
+
+       return 0;
+}
index 1130c608a5619637b33a8b85e140031f3ae4a2e8..814bb9500dca77a9b47c6216aedadd361ba5cdaf 100644 (file)
@@ -784,7 +784,6 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
        if (*w == 0 || *h == 0)
                return -EINVAL;
 
-       dss_setup_partial_planes(dssdev, x, y, w, h, true);
        dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h);
 
        return 0;
index 40305ad7841e26971ca8e88035af7385a85ce260..8266ca0d666bc2de7547a12c38eca9dc98aba11a 100644 (file)
@@ -123,10 +123,14 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
                goto err_sdi_enable;
        mdelay(2);
 
-       dssdev->manager->enable(dssdev->manager);
+       r = dss_mgr_enable(dssdev->manager);
+       if (r)
+               goto err_mgr_enable;
 
        return 0;
 
+err_mgr_enable:
+       dss_sdi_disable();
 err_sdi_enable:
 err_set_dispc_clock_div:
 err_set_dss_clock_div:
@@ -145,7 +149,7 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable);
 
 void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
 {
-       dssdev->manager->disable(dssdev->manager);
+       dss_mgr_disable(dssdev->manager);
 
        dss_sdi_disable();
 
index 2c3443dabb14c3505087fec3dd045d109cceabd9..7503f7f619a7fe43b7be266f04e9bf4cd7c8579a 100644 (file)
@@ -110,6 +110,11 @@ struct ti_hdmi_ip_ops {
 
        void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s);
 
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+       void (*audio_enable)(struct hdmi_ip_data *ip_data, bool start);
+#endif
+
 };
 
 struct hdmi_ip_data {
@@ -134,5 +139,8 @@ void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
 void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
 void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
 void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
-
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable);
+#endif
 #endif
index e1a6ce518af6c4c250f6d542e9a135e2927683ba..9af81f18f1633ffaaeae842d922f8800cd9d285c 100644 (file)
@@ -1204,36 +1204,13 @@ int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data,
        return 0;
 }
 
-int hdmi_audio_trigger(struct hdmi_ip_data *ip_data,
-                               struct snd_pcm_substream *substream, int cmd,
-                               struct snd_soc_dai *dai)
+void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable)
 {
-       int err = 0;
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               REG_FLD_MOD(hdmi_av_base(ip_data),
-                                       HDMI_CORE_AV_AUD_MODE, 1, 0, 0);
-               REG_FLD_MOD(hdmi_wp_base(ip_data),
-                                       HDMI_WP_AUDIO_CTRL, 1, 31, 31);
-               REG_FLD_MOD(hdmi_wp_base(ip_data),
-                                       HDMI_WP_AUDIO_CTRL, 1, 30, 30);
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               REG_FLD_MOD(hdmi_av_base(ip_data),
-                                       HDMI_CORE_AV_AUD_MODE, 0, 0, 0);
-               REG_FLD_MOD(hdmi_wp_base(ip_data),
-                                       HDMI_WP_AUDIO_CTRL, 0, 30, 30);
-               REG_FLD_MOD(hdmi_wp_base(ip_data),
-                                       HDMI_WP_AUDIO_CTRL, 0, 31, 31);
-               break;
-       default:
-               err = -EINVAL;
-       }
-       return err;
+       REG_FLD_MOD(hdmi_av_base(ip_data),
+                               HDMI_CORE_AV_AUD_MODE, enable, 0, 0);
+       REG_FLD_MOD(hdmi_wp_base(ip_data),
+                               HDMI_WP_AUDIO_CTRL, enable, 31, 31);
+       REG_FLD_MOD(hdmi_wp_base(ip_data),
+                               HDMI_WP_AUDIO_CTRL, enable, 30, 30);
 }
 #endif
index 204095632d27bd09b0f104994ed7d568f4d47e6a..a442998980f12231070592e9ade2d45cc5764716 100644 (file)
@@ -576,9 +576,6 @@ struct hdmi_core_audio_config {
 
 #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
        defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
-int hdmi_audio_trigger(struct hdmi_ip_data *ip_data,
-                               struct snd_pcm_substream *substream, int cmd,
-                               struct snd_soc_dai *dai);
 int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data,
                                u32 sample_freq, u32 *n, u32 *cts);
 void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data,
index 7533458ba4d24effd08aced87cff7c2ff47eb418..b3e9f90915815f4e82950743c72b6d36acad8913 100644 (file)
@@ -417,9 +417,10 @@ static const struct venc_config *venc_timings_to_config(
        BUG();
 }
 
-static void venc_power_on(struct omap_dss_device *dssdev)
+static int venc_power_on(struct omap_dss_device *dssdev)
 {
        u32 l;
+       int r;
 
        venc_reset();
        venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
@@ -447,7 +448,22 @@ static void venc_power_on(struct omap_dss_device *dssdev)
        if (dssdev->platform_enable)
                dssdev->platform_enable(dssdev);
 
-       dssdev->manager->enable(dssdev->manager);
+       r = dss_mgr_enable(dssdev->manager);
+       if (r)
+               goto err;
+
+       return 0;
+
+err:
+       venc_write_reg(VENC_OUTPUT_CONTROL, 0);
+       dss_set_dac_pwrdn_bgz(0);
+
+       if (dssdev->platform_disable)
+               dssdev->platform_disable(dssdev);
+
+       regulator_disable(venc.vdda_dac_reg);
+
+       return r;
 }
 
 static void venc_power_off(struct omap_dss_device *dssdev)
@@ -455,7 +471,7 @@ static void venc_power_off(struct omap_dss_device *dssdev)
        venc_write_reg(VENC_OUTPUT_CONTROL, 0);
        dss_set_dac_pwrdn_bgz(0);
 
-       dssdev->manager->disable(dssdev->manager);
+       dss_mgr_disable(dssdev->manager);
 
        if (dssdev->platform_disable)
                dssdev->platform_disable(dssdev);
@@ -504,7 +520,9 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
        if (r)
                goto err1;
 
-       venc_power_on(dssdev);
+       r = venc_power_on(dssdev);
+       if (r)
+               goto err2;
 
        venc.wss_data = 0;
 
@@ -512,6 +530,8 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
 
        mutex_unlock(&venc.venc_lock);
        return 0;
+err2:
+       venc_runtime_put();
 err1:
        omap_dss_stop_device(dssdev);
 err0:
index df7bcce5b107d82dcbc46803cffcade9178cea67..16ba6196f330bc03dd4abbc7fdb7de738dae84f4 100644 (file)
@@ -111,28 +111,22 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
                set_fb_fix(fbi);
        }
 
-       if (pi->enabled) {
-               struct omap_overlay_info info;
+       if (!pi->enabled) {
+               r = ovl->disable(ovl);
+               if (r)
+                       goto undo;
+       }
 
+       if (pi->enabled) {
                r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y,
                        pi->out_width, pi->out_height);
                if (r)
                        goto undo;
-
-               ovl->get_overlay_info(ovl, &info);
-
-               if (!info.enabled) {
-                       info.enabled = pi->enabled;
-                       r = ovl->set_overlay_info(ovl, &info);
-                       if (r)
-                               goto undo;
-               }
        } else {
                struct omap_overlay_info info;
 
                ovl->get_overlay_info(ovl, &info);
 
-               info.enabled = pi->enabled;
                info.pos_x = pi->pos_x;
                info.pos_y = pi->pos_y;
                info.out_width = pi->out_width;
@@ -146,6 +140,12 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
        if (ovl->manager)
                ovl->manager->apply(ovl->manager);
 
+       if (pi->enabled) {
+               r = ovl->enable(ovl);
+               if (r)
+                       goto undo;
+       }
+
        /* Release the locks in a specific order to keep lockdep happy */
        if (old_rg->id > new_rg->id) {
                omapfb_put_mem_region(old_rg);
@@ -189,19 +189,19 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
                memset(pi, 0, sizeof(*pi));
        } else {
                struct omap_overlay *ovl;
-               struct omap_overlay_info *ovli;
+               struct omap_overlay_info ovli;
 
                ovl = ofbi->overlays[0];
-               ovli = &ovl->info;
+               ovl->get_overlay_info(ovl, &ovli);
 
-               pi->pos_x = ovli->pos_x;
-               pi->pos_y = ovli->pos_y;
-               pi->enabled = ovli->enabled;
+               pi->pos_x = ovli.pos_x;
+               pi->pos_y = ovli.pos_y;
+               pi->enabled = ovl->is_enabled(ovl);
                pi->channel_out = 0; /* xxx */
                pi->mirror = 0;
                pi->mem_idx = get_mem_idx(ofbi);
-               pi->out_width = ovli->out_width;
-               pi->out_height = ovli->out_height;
+               pi->out_width = ovli.out_width;
+               pi->out_height = ovli.out_height;
        }
 
        return 0;
@@ -238,7 +238,9 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
                        continue;
 
                for (j = 0; j < ofbi2->num_overlays; j++) {
-                       if (ofbi2->overlays[j]->info.enabled) {
+                       struct omap_overlay *ovl;
+                       ovl = ofbi2->overlays[j];
+                       if (ovl->is_enabled(ovl)) {
                                r = -EBUSY;
                                goto out;
                        }
index 70aa47de7146fdc881dff6e9060976c005b1cf77..ce158311ff59930c3cce586741f758f6102c8750 100644 (file)
 
 static char *def_mode;
 static char *def_vram;
-static int def_vrfb;
+static bool def_vrfb;
 static int def_rotate;
-static int def_mirror;
+static bool def_mirror;
 static bool auto_update;
 static unsigned int auto_update_freq;
 module_param(auto_update, bool, 0);
 module_param(auto_update_freq, uint, 0644);
 
 #ifdef DEBUG
-unsigned int omapfb_debug;
+bool omapfb_debug;
 module_param_named(debug, omapfb_debug, bool, 0644);
-static unsigned int omapfb_test_pattern;
+static bool omapfb_test_pattern;
 module_param_named(test, omapfb_test_pattern, bool, 0644);
 #endif
 
@@ -970,16 +970,20 @@ int omapfb_apply_changes(struct fb_info *fbi, int init)
                                outh = var->yres;
                        }
                } else {
-                       outw = ovl->info.out_width;
-                       outh = ovl->info.out_height;
+                       struct omap_overlay_info info;
+                       ovl->get_overlay_info(ovl, &info);
+                       outw = info.out_width;
+                       outh = info.out_height;
                }
 
                if (init) {
                        posx = 0;
                        posy = 0;
                } else {
-                       posx = ovl->info.pos_x;
-                       posy = ovl->info.pos_y;
+                       struct omap_overlay_info info;
+                       ovl->get_overlay_info(ovl, &info);
+                       posx = info.pos_x;
+                       posy = info.pos_y;
                }
 
                r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
@@ -2067,6 +2071,8 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
                if (ofbi->num_overlays > 0) {
                        struct omap_overlay *ovl = ofbi->overlays[0];
 
+                       ovl->manager->apply(ovl->manager);
+
                        r = omapfb_overlay_enable(ovl, 1);
 
                        if (r) {
index 1694d5148f323fad66a03fe45f4054f4f7a4a09e..e8d8cc76a4351ce58e306d5a67b4b947cec2e9c1 100644 (file)
@@ -473,7 +473,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
                        continue;
 
                for (j = 0; j < ofbi2->num_overlays; j++) {
-                       if (ofbi2->overlays[j]->info.enabled) {
+                       struct omap_overlay *ovl;
+                       ovl = ofbi2->overlays[j];
+                       if (ovl->is_enabled(ovl)) {
                                r = -EBUSY;
                                goto out;
                        }
index fdf0edeccf4e9f5972aa0679952efd22a297bb92..c0bdc9b54ecf77d1f22355ca956b6367d2ceac70 100644 (file)
@@ -32,7 +32,7 @@
 #include <video/omapdss.h>
 
 #ifdef DEBUG
-extern unsigned int omapfb_debug;
+extern bool omapfb_debug;
 #define DBG(format, ...) \
        do { \
                if (omapfb_debug) \
@@ -181,13 +181,10 @@ static inline void omapfb_unlock(struct omapfb2_device *fbdev)
 static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
                int enable)
 {
-       struct omap_overlay_info info;
-
-       ovl->get_overlay_info(ovl, &info);
-       if (info.enabled == enable)
-               return 0;
-       info.enabled = enable;
-       return ovl->set_overlay_info(ovl, &info);
+       if (enable)
+               return ovl->enable(ovl);
+       else
+               return ovl->disable(ovl);
 }
 
 static inline struct omapfb2_mem_region *
index dc7bfa91e57ab1c87bc6b2b0e4d405b050895c9a..df31a24a5026e9af75a56c0e3b66ad8718a27703 100644 (file)
@@ -78,12 +78,12 @@ static char *mode_option __devinitdata;
  * these flags allow the user to specify that requests for +ve sync
  * should be silently turned in -ve sync.
  */
-static int lowhsync;
-static int lowvsync;
-static int noaccel __devinitdata;
+static bool lowhsync;
+static bool lowvsync;
+static bool noaccel __devinitdata;
 /* mtrr option */
 #ifdef CONFIG_MTRR
-static int nomtrr __devinitdata;
+static bool nomtrr __devinitdata;
 #endif
 
 /*
index 6632ee5ecb7e1243d2e6afc177a4a71eb6a5b6ec..055e527a8e4510383f6ebb7f0d4bd4838f3bcfce 100644 (file)
  */
 static int hwcursor = 1;
 static char *mode_option __devinitdata;
-static int noaccel __devinitdata;
+static bool noaccel __devinitdata;
 
 /* mtrr option */
 #ifdef CONFIG_MTRR
-static int nomtrr __devinitdata;
+static bool nomtrr __devinitdata;
 #endif
 
 /*
index b2252fea2858c732533af9063c889931ab27c895..6d30428e9cf9803d16ec06f68ff8342ab7d62958 100644 (file)
@@ -193,17 +193,6 @@ static struct platform_driver rgbfb_driver = {
        .remove = rgbfb_remove,
 };
 
-static int __init rgbfb_init(void)
-{
-       return platform_driver_register(&rgbfb_driver);
-}
-
-static void __exit rgbfb_exit(void)
-{
-       platform_driver_unregister(&rgbfb_driver);
-}
-
-module_init(rgbfb_init);
-module_exit(rgbfb_exit);
+module_platform_driver(rgbfb_driver);
 
 MODULE_LICENSE("GPL");
index 50e00395240f67b43eb93f9c7697c5ff12d60a1a..c5c741452cac16c766ac4c465f61228b2693395a 100644 (file)
@@ -856,17 +856,6 @@ static struct platform_driver sdum_driver = {
        .resume = sdum_resume,
 };
 
-int __init sdum_init(void)
-{
-       return platform_driver_register(&sdum_driver);
-}
-
-static void __exit sdum_exit(void)
-{
-       platform_driver_unregister(&sdum_driver);
-};
-
-module_init(sdum_init);
-module_exit(sdum_exit);
+module_platform_driver(sdum_driver);
 
 MODULE_LICENSE("GPL");
index 18ead6f0184d136dcfc884e21db207748e18a0ef..8384b941f6ba1dd922bdeffec17fede7f180fdca 100644 (file)
@@ -832,17 +832,7 @@ static struct platform_driver pxa168fb_driver = {
        .remove         = __devexit_p(pxa168fb_remove),
 };
 
-static int __init pxa168fb_init(void)
-{
-       return platform_driver_register(&pxa168fb_driver);
-}
-module_init(pxa168fb_init);
-
-static void __exit pxa168fb_exit(void)
-{
-       platform_driver_unregister(&pxa168fb_driver);
-}
-module_exit(pxa168fb_exit);
+module_platform_driver(pxa168fb_driver);
 
 MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> "
              "Green Wan <gwan@marvell.com>");
index 1ed8b366618df6234b83183f46d3ac18e6641b98..1d71c08a818f7d1fc646496f9ae9c32d77943c88 100644 (file)
@@ -747,20 +747,7 @@ static struct platform_driver pxa3xx_gcu_driver = {
        },
 };
 
-static int __init
-pxa3xx_gcu_init(void)
-{
-       return platform_driver_register(&pxa3xx_gcu_driver);
-}
-
-static void __exit
-pxa3xx_gcu_exit(void)
-{
-       platform_driver_unregister(&pxa3xx_gcu_driver);
-}
-
-module_init(pxa3xx_gcu_init);
-module_exit(pxa3xx_gcu_exit);
+module_platform_driver(pxa3xx_gcu_driver);
 
 MODULE_DESCRIPTION("PXA3xx graphics controller unit driver");
 MODULE_LICENSE("GPL");
index d8ab7be4fd6b5953ba1f2d57928b541038554c60..2f58cf9c813b95eed40e777658753150a2850fd1 100644 (file)
@@ -207,9 +207,9 @@ MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl);
 /* command line data, set in rivafb_setup() */
 static int flatpanel __devinitdata = -1; /* Autodetect later */
 static int forceCRTC __devinitdata = -1;
-static int noaccel   __devinitdata = 0;
+static bool noaccel  __devinitdata = 0;
 #ifdef CONFIG_MTRR
-static int nomtrr __devinitdata = 0;
+static bool nomtrr __devinitdata = 0;
 #endif
 #ifdef CONFIG_PMAC_BACKLIGHT
 static int backlight __devinitdata = 1;
@@ -218,7 +218,7 @@ static int backlight __devinitdata = 0;
 #endif
 
 static char *mode_option __devinitdata = NULL;
-static int  strictmode       = 0;
+static bool strictmode       = 0;
 
 static struct fb_fix_screeninfo __devinitdata rivafb_fix = {
        .type           = FB_TYPE_PACKED_PIXELS,
index 0753b1cfcb8bc9eb6df5fa234ac2441b9c48470b..0c63b69b6340b5eb271753dda31f02ecd59766a2 100644 (file)
@@ -192,6 +192,7 @@ struct s3c_fb_vsync {
  * @regs: The mapped hardware registers.
  * @variant: Variant information for this hardware.
  * @enabled: A bitmask of enabled hardware windows.
+ * @output_on: Flag if the physical output is enabled.
  * @pdata: The platform configuration data passed with the device.
  * @windows: The hardware windows that have been claimed.
  * @irq_no: IRQ line number
@@ -208,6 +209,7 @@ struct s3c_fb {
        struct s3c_fb_variant    variant;
 
        unsigned char            enabled;
+       bool                     output_on;
 
        struct s3c_fb_platdata  *pdata;
        struct s3c_fb_win       *windows[S3C_FB_MAX_WIN];
@@ -440,6 +442,39 @@ static void shadow_protect_win(struct s3c_fb_win *win, bool protect)
        }
 }
 
+/**
+ * s3c_fb_enable() - Set the state of the main LCD output
+ * @sfb: The main framebuffer state.
+ * @enable: The state to set.
+ */
+static void s3c_fb_enable(struct s3c_fb *sfb, int enable)
+{
+       u32 vidcon0 = readl(sfb->regs + VIDCON0);
+
+       if (enable && !sfb->output_on)
+               pm_runtime_get_sync(sfb->dev);
+
+       if (enable) {
+               vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
+       } else {
+               /* see the note in the framebuffer datasheet about
+                * why you cannot take both of these bits down at the
+                * same time. */
+
+               if (vidcon0 & VIDCON0_ENVID) {
+                       vidcon0 |= VIDCON0_ENVID;
+                       vidcon0 &= ~VIDCON0_ENVID_F;
+               }
+       }
+
+       writel(vidcon0, sfb->regs + VIDCON0);
+
+       if (!enable && sfb->output_on)
+               pm_runtime_put_sync(sfb->dev);
+
+       sfb->output_on = enable;
+}
+
 /**
  * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
  * @info: The framebuffer to change.
@@ -461,6 +496,8 @@ static int s3c_fb_set_par(struct fb_info *info)
 
        dev_dbg(sfb->dev, "setting framebuffer parameters\n");
 
+       pm_runtime_get_sync(sfb->dev);
+
        shadow_protect_win(win, 1);
 
        switch (var->bits_per_pixel) {
@@ -510,9 +547,10 @@ static int s3c_fb_set_par(struct fb_info *info)
                if (sfb->variant.is_2443)
                        data |= (1 << 5);
 
-               data |= VIDCON0_ENVID | VIDCON0_ENVID_F;
                writel(data, regs + VIDCON0);
 
+               s3c_fb_enable(sfb, 1);
+
                data = VIDTCON0_VBPD(var->upper_margin - 1) |
                       VIDTCON0_VFPD(var->lower_margin - 1) |
                       VIDTCON0_VSPW(var->vsync_len - 1);
@@ -574,6 +612,7 @@ static int s3c_fb_set_par(struct fb_info *info)
        }
 
        data = WINCONx_ENWIN;
+       sfb->enabled |= (1 << win->index);
 
        /* note, since we have to round up the bits-per-pixel, we end up
         * relying on the bitfield information for r/g/b/a to work out
@@ -621,7 +660,8 @@ static int s3c_fb_set_par(struct fb_info *info)
                } else if (var->transp.length == 1)
                        data |= WINCON1_BPPMODE_25BPP_A1888
                                | WINCON1_BLD_PIX;
-               else if (var->transp.length == 4)
+               else if ((var->transp.length == 4) ||
+                       (var->transp.length == 8))
                        data |= WINCON1_BPPMODE_28BPP_A4888
                                | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
                else
@@ -654,6 +694,8 @@ static int s3c_fb_set_par(struct fb_info *info)
 
        shadow_protect_win(win, 0);
 
+       pm_runtime_put_sync(sfb->dev);
+
        return 0;
 }
 
@@ -725,6 +767,8 @@ static int s3c_fb_setcolreg(unsigned regno,
        dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n",
                __func__, win->index, regno, red, green, blue);
 
+       pm_runtime_get_sync(sfb->dev);
+
        switch (info->fix.visual) {
        case FB_VISUAL_TRUECOLOR:
                /* true-colour, use pseudo-palette */
@@ -752,38 +796,14 @@ static int s3c_fb_setcolreg(unsigned regno,
                break;
 
        default:
+               pm_runtime_put_sync(sfb->dev);
                return 1;       /* unknown type */
        }
 
+       pm_runtime_put_sync(sfb->dev);
        return 0;
 }
 
-/**
- * s3c_fb_enable() - Set the state of the main LCD output
- * @sfb: The main framebuffer state.
- * @enable: The state to set.
- */
-static void s3c_fb_enable(struct s3c_fb *sfb, int enable)
-{
-       u32 vidcon0 = readl(sfb->regs + VIDCON0);
-
-       if (enable)
-               vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
-       else {
-               /* see the note in the framebuffer datasheet about
-                * why you cannot take both of these bits down at the
-                * same time. */
-
-               if (!(vidcon0 & VIDCON0_ENVID))
-                       return;
-
-               vidcon0 |= VIDCON0_ENVID;
-               vidcon0 &= ~VIDCON0_ENVID_F;
-       }
-
-       writel(vidcon0, sfb->regs + VIDCON0);
-}
-
 /**
  * s3c_fb_blank() - blank or unblank the given window
  * @blank_mode: The blank state from FB_BLANK_*
@@ -800,6 +820,8 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
 
        dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
 
+       pm_runtime_get_sync(sfb->dev);
+
        wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4));
 
        switch (blank_mode) {
@@ -810,12 +832,16 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
 
        case FB_BLANK_NORMAL:
                /* disable the DMA and display 0x0 (black) */
+               shadow_protect_win(win, 1);
                writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
                       sfb->regs + sfb->variant.winmap + (index * 4));
+               shadow_protect_win(win, 0);
                break;
 
        case FB_BLANK_UNBLANK:
+               shadow_protect_win(win, 1);
                writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4));
+               shadow_protect_win(win, 0);
                wincon |= WINCONx_ENWIN;
                sfb->enabled |= (1 << index);
                break;
@@ -823,10 +849,13 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
        case FB_BLANK_VSYNC_SUSPEND:
        case FB_BLANK_HSYNC_SUSPEND:
        default:
+               pm_runtime_put_sync(sfb->dev);
                return 1;
        }
 
+       shadow_protect_win(win, 1);
        writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
+       shadow_protect_win(win, 0);
 
        /* Check the enabled state to see if we need to be running the
         * main LCD interface, as if there are no active windows then
@@ -845,8 +874,13 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
        /* we're stuck with this until we can do something about overriding
         * the power control using the blanking event for a single fb.
         */
-       if (index == sfb->pdata->default_win)
+       if (index == sfb->pdata->default_win) {
+               shadow_protect_win(win, 1);
                s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
+               shadow_protect_win(win, 0);
+       }
+
+       pm_runtime_put_sync(sfb->dev);
 
        return 0;
 }
@@ -870,6 +904,8 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
        void __iomem *buf       = sfb->regs + win->index * 8;
        unsigned int start_boff, end_boff;
 
+       pm_runtime_get_sync(sfb->dev);
+
        /* Offset in bytes to the start of the displayed area */
        start_boff = var->yoffset * info->fix.line_length;
        /* X offset depends on the current bpp */
@@ -888,6 +924,7 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
                        break;
                default:
                        dev_err(sfb->dev, "invalid bpp\n");
+                       pm_runtime_put_sync(sfb->dev);
                        return -EINVAL;
                }
        }
@@ -903,6 +940,7 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
 
        shadow_protect_win(win, 0);
 
+       pm_runtime_put_sync(sfb->dev);
        return 0;
 }
 
@@ -992,11 +1030,16 @@ static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc)
        if (crtc != 0)
                return -ENODEV;
 
+       pm_runtime_get_sync(sfb->dev);
+
        count = sfb->vsync_info.count;
        s3c_fb_enable_irq(sfb);
        ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
                                       count != sfb->vsync_info.count,
                                       msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
+
+       pm_runtime_put_sync(sfb->dev);
+
        if (ret == 0)
                return -ETIMEDOUT;
 
@@ -1027,30 +1070,8 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
        return ret;
 }
 
-static int s3c_fb_open(struct fb_info *info, int user)
-{
-       struct s3c_fb_win *win = info->par;
-       struct s3c_fb *sfb = win->parent;
-
-       pm_runtime_get_sync(sfb->dev);
-
-       return 0;
-}
-
-static int s3c_fb_release(struct fb_info *info, int user)
-{
-       struct s3c_fb_win *win = info->par;
-       struct s3c_fb *sfb = win->parent;
-
-       pm_runtime_put_sync(sfb->dev);
-
-       return 0;
-}
-
 static struct fb_ops s3c_fb_ops = {
        .owner          = THIS_MODULE,
-       .fb_open        = s3c_fb_open,
-       .fb_release     = s3c_fb_release,
        .fb_check_var   = s3c_fb_check_var,
        .fb_set_par     = s3c_fb_set_par,
        .fb_blank       = s3c_fb_blank,
@@ -1452,7 +1473,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
                        dev_err(dev, "failed to create window %d\n", win);
                        for (; win >= 0; win--)
                                s3c_fb_release_win(sfb, sfb->windows[win]);
-                       goto err_irq;
+                       goto err_pm_runtime;
                }
        }
 
@@ -1461,7 +1482,8 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
 
        return 0;
 
-err_irq:
+err_pm_runtime:
+       pm_runtime_put_sync(sfb->dev);
        free_irq(sfb->irq_no, sfb);
 
 err_ioremap:
@@ -1471,6 +1493,8 @@ err_req_region:
        release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
 
 err_lcd_clk:
+       pm_runtime_disable(sfb->dev);
+
        if (!sfb->variant.has_clksel) {
                clk_disable(sfb->lcd_clk);
                clk_put(sfb->lcd_clk);
@@ -1524,7 +1548,7 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int s3c_fb_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -1571,10 +1595,15 @@ static int s3c_fb_resume(struct device *dev)
 
        for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
                void __iomem *regs = sfb->regs + sfb->variant.keycon;
+               win = sfb->windows[win_no];
+               if (!win)
+                       continue;
 
+               shadow_protect_win(win, 1);
                regs += (win_no * 8);
                writel(0xffffff, regs + WKEYCON0);
                writel(0xffffff, regs + WKEYCON1);
+               shadow_protect_win(win, 0);
        }
 
        /* restore framebuffers */
@@ -1589,27 +1618,19 @@ static int s3c_fb_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
+#ifdef CONFIG_PM_RUNTIME
 static int s3c_fb_runtime_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct s3c_fb *sfb = platform_get_drvdata(pdev);
-       struct s3c_fb_win *win;
-       int win_no;
-
-       for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
-               win = sfb->windows[win_no];
-               if (!win)
-                       continue;
-
-               /* use the blank function to push into power-down */
-               s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
-       }
 
        if (!sfb->variant.has_clksel)
                clk_disable(sfb->lcd_clk);
 
        clk_disable(sfb->bus_clk);
+
        return 0;
 }
 
@@ -1618,8 +1639,6 @@ static int s3c_fb_runtime_resume(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct s3c_fb *sfb = platform_get_drvdata(pdev);
        struct s3c_fb_platdata *pd = sfb->pdata;
-       struct s3c_fb_win *win;
-       int win_no;
 
        clk_enable(sfb->bus_clk);
 
@@ -1630,39 +1649,10 @@ static int s3c_fb_runtime_resume(struct device *dev)
        pd->setup_gpio();
        writel(pd->vidcon1, sfb->regs + VIDCON1);
 
-       /* zero all windows before we do anything */
-       for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
-               s3c_fb_clear_win(sfb, win_no);
-
-       for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
-               void __iomem *regs = sfb->regs + sfb->variant.keycon;
-
-               regs += (win_no * 8);
-               writel(0xffffff, regs + WKEYCON0);
-               writel(0xffffff, regs + WKEYCON1);
-       }
-
-       /* restore framebuffers */
-       for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
-               win = sfb->windows[win_no];
-               if (!win)
-                       continue;
-
-               dev_dbg(&pdev->dev, "resuming window %d\n", win_no);
-               s3c_fb_set_par(win->fbinfo);
-       }
-
        return 0;
 }
-
-#else
-#define s3c_fb_suspend NULL
-#define s3c_fb_resume  NULL
-#define s3c_fb_runtime_suspend NULL
-#define s3c_fb_runtime_resume NULL
 #endif
 
-
 #define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4))
 #define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8))
 
@@ -1985,10 +1975,9 @@ static struct platform_device_id s3c_fb_driver_ids[] = {
 MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
 
 static const struct dev_pm_ops s3cfb_pm_ops = {
-       .suspend        = s3c_fb_suspend,
-       .resume         = s3c_fb_resume,
-       .runtime_suspend        = s3c_fb_runtime_suspend,
-       .runtime_resume         = s3c_fb_runtime_resume,
+       SET_SYSTEM_SLEEP_PM_OPS(s3c_fb_suspend, s3c_fb_resume)
+       SET_RUNTIME_PM_OPS(s3c_fb_runtime_suspend, s3c_fb_runtime_resume,
+                          NULL)
 };
 
 static struct platform_driver s3c_fb_driver = {
@@ -2002,18 +1991,7 @@ static struct platform_driver s3c_fb_driver = {
        },
 };
 
-static int __init s3c_fb_init(void)
-{
-       return platform_driver_register(&s3c_fb_driver);
-}
-
-static void __exit s3c_fb_cleanup(void)
-{
-       platform_driver_unregister(&s3c_fb_driver);
-}
-
-module_init(s3c_fb_init);
-module_exit(s3c_fb_cleanup);
+module_platform_driver(s3c_fb_driver);
 
 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
index ee4c0df217f78bd07403873e28fda2abc3cc9abc..77f34c614c86bc73cd21cd189b542c5f07c1bab3 100644 (file)
@@ -26,8 +26,8 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/div64.h>
 
 #include <asm/mach/map.h>
 #ifdef CONFIG_FB_S3C2410_DEBUG
 static int debug       = 1;
 #else
-static int debug       = 0;
+static int debug;
 #endif
 
-#define dprintk(msg...)        if (debug) { printk(KERN_DEBUG "s3c2410fb: " msg); }
+#define dprintk(msg...)        if (debug) printk(KERN_DEBUG "s3c2410fb: " msg);
 
 /* useful functions */
 
@@ -567,11 +567,10 @@ static int s3c2410fb_blank(int blank_mode, struct fb_info *info)
 
        tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL;
 
-       if (blank_mode == FB_BLANK_POWERDOWN) {
+       if (blank_mode == FB_BLANK_POWERDOWN)
                s3c2410fb_lcd_enable(fbi, 0);
-       } else {
+       else
                s3c2410fb_lcd_enable(fbi, 1);
-       }
 
        if (blank_mode == FB_BLANK_UNBLANK)
                writel(0x0, tpal_reg);
@@ -812,7 +811,7 @@ static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
 #endif
 
 
-static char driver_name[] = "s3c2410fb";
+static const char driver_name[] = "s3c2410fb";
 
 static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
                                  enum s3c_drv_type drv_type)
@@ -881,7 +880,10 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
                goto release_mem;
        }
 
-       info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);
+       if (drv_type == DRV_S3C2412)
+               info->irq_base = info->io + S3C2412_LCDINTBASE;
+       else
+               info->irq_base = info->io + S3C2410_LCDINTBASE;
 
        dprintk("devinit\n");
 
@@ -927,7 +929,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
        clk_enable(info->clk);
        dprintk("got and enabled clock\n");
 
-       msleep(1);
+       usleep_range(1000, 1000);
 
        info->clk_rate = clk_get_rate(info->clk);
 
@@ -975,9 +977,8 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
 
        /* create device files */
        ret = device_create_file(&pdev->dev, &dev_attr_debug);
-       if (ret) {
+       if (ret)
                printk(KERN_ERR "failed to add debug attribute\n");
-       }
 
        printk(KERN_INFO "fb%d: %s frame buffer device\n",
                fbinfo->node, fbinfo->fix.id);
@@ -1027,7 +1028,7 @@ static int __devexit s3c2410fb_remove(struct platform_device *pdev)
        s3c2410fb_cpufreq_deregister(info);
 
        s3c2410fb_lcd_enable(info, 0);
-       msleep(1);
+       usleep_range(1000, 1000);
 
        s3c2410fb_unmap_video_memory(fbinfo);
 
@@ -1064,7 +1065,7 @@ static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state)
         * the LCD DMA engine is not going to get back on the bus
         * before the clock goes off again (bjd) */
 
-       msleep(1);
+       usleep_range(1000, 1000);
        clk_disable(info->clk);
 
        return 0;
@@ -1076,7 +1077,7 @@ static int s3c2410fb_resume(struct platform_device *dev)
        struct s3c2410fb_info *info = fbinfo->par;
 
        clk_enable(info->clk);
-       msleep(1);
+       usleep_range(1000, 1000);
 
        s3c2410fb_init_registers(fbinfo);
 
index 946a949f4c7d44cba635432f92c7591a54b773ab..2c80246b18b88eee0b22a90c8fbc5581c02aad96 100644 (file)
@@ -727,7 +727,7 @@ static int s3fb_set_par(struct fb_info *info)
        if (par->chip == CHIP_988_VIRGE_VX) {
                vga_wcrt(par->state.vgabase, 0x50, 0x00);
                vga_wcrt(par->state.vgabase, 0x67, 0x50);
-
+               msleep(10); /* screen remains blank sometimes without this */
                vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09);
                vga_wcrt(par->state.vgabase, 0x66, 0x90);
        }
@@ -901,7 +901,8 @@ static int s3fb_set_par(struct fb_info *info)
 
        /* Set Data Transfer Position */
        hsstart = ((info->var.xres + info->var.right_margin) * hmul) / 8;
-       value = clamp((htotal + hsstart + 1) / 2, hsstart + 4, htotal + 1);
+       /* + 2 is needed for Virge/VX, does no harm on other cards */
+       value = clamp((htotal + hsstart + 1) / 2 + 2, hsstart + 4, htotal + 1);
        svga_wcrt_multi(par->state.vgabase, s3_dtpc_regs, value);
 
        memset_io(info->screen_base, 0x00, screen_size);
@@ -1216,6 +1217,31 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
                        info->screen_size = 2 << 20;
                        break;
                }
+       } else if (par->chip == CHIP_988_VIRGE_VX) {
+               switch ((regval & 0x60) >> 5) {
+               case 0: /* 2MB */
+                       info->screen_size = 2 << 20;
+                       break;
+               case 1: /* 4MB */
+                       info->screen_size = 4 << 20;
+                       break;
+               case 2: /* 6MB */
+                       info->screen_size = 6 << 20;
+                       break;
+               case 3: /* 8MB */
+                       info->screen_size = 8 << 20;
+                       break;
+               }
+               /* off-screen memory */
+               regval = vga_rcrt(par->state.vgabase, 0x37);
+               switch ((regval & 0x60) >> 5) {
+               case 1: /* 4MB */
+                       info->screen_size -= 4 << 20;
+                       break;
+               case 2: /* 2MB */
+                       info->screen_size -= 2 << 20;
+                       break;
+               }
        } else
                info->screen_size = s3_memsizes[regval >> 5] << 10;
        info->fix.smem_len = info->screen_size;
index 37d764ad56b052a8249dc8d9062c7af07a09d167..3c1de981a18cf77a49fbe2b9239112e29ecfe547 100644 (file)
@@ -76,7 +76,7 @@ int sbusfb_mmap_helper(struct sbus_mmap_map *map,
                                map_offset = (physbase + map[i].poff) & POFF_MASK;
                                break;
                        }
-               if (!map_size){
+               if (!map_size) {
                        page += PAGE_SIZE;
                        continue;
                }
index 45e47d8471634d2bd9f57c2ef5e3da88cdc8494b..83b16e237a0e2f4fcf4d2438ea2f3439851129c8 100644 (file)
@@ -585,18 +585,7 @@ static struct platform_driver sh7760_lcdc_driver = {
        .remove = __devexit_p(sh7760fb_remove),
 };
 
-static int __init sh7760fb_init(void)
-{
-       return platform_driver_register(&sh7760_lcdc_driver);
-}
-
-static void __exit sh7760fb_exit(void)
-{
-       platform_driver_unregister(&sh7760_lcdc_driver);
-}
-
-module_init(sh7760fb_init);
-module_exit(sh7760fb_exit);
+module_platform_driver(sh7760_lcdc_driver);
 
 MODULE_AUTHOR("Nobuhiro Iwamatsu, Manuel Lauss");
 MODULE_DESCRIPTION("FBdev for SH7760/63 integrated LCD Controller");
index 72ee96bc6b3e4ca20f68bef852b0c498c2408cc9..05151b82f40f9867bd36ea5579610a5e6ae82af4 100644 (file)
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/bitmap.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/init.h>
@@ -41,6 +42,7 @@
 #define VMCTR1         0x0020
 #define VMCTR2         0x0024
 #define VMLEN1         0x0028
+#define VMLEN2         0x002c
 #define CMTSRTREQ      0x0070
 #define CMTSRTCTR      0x00d0
 
@@ -51,8 +53,7 @@ struct sh_mipi {
        void __iomem    *base;
        void __iomem    *linkbase;
        struct clk      *dsit_clk;
-       struct clk      *dsip_clk;
-       struct device   *dev;
+       struct platform_device *pdev;
 
        void    *next_board_data;
        void    (*next_display_on)(void *board_data, struct fb_info *info);
@@ -124,35 +125,15 @@ static void sh_mipi_shutdown(struct platform_device *pdev)
        sh_mipi_dsi_enable(mipi, false);
 }
 
-static void mipi_display_on(void *arg, struct fb_info *info)
-{
-       struct sh_mipi *mipi = arg;
-
-       pm_runtime_get_sync(mipi->dev);
-       sh_mipi_dsi_enable(mipi, true);
-
-       if (mipi->next_display_on)
-               mipi->next_display_on(mipi->next_board_data, info);
-}
-
-static void mipi_display_off(void *arg)
-{
-       struct sh_mipi *mipi = arg;
-
-       if (mipi->next_display_off)
-               mipi->next_display_off(mipi->next_board_data);
-
-       sh_mipi_dsi_enable(mipi, false);
-       pm_runtime_put(mipi->dev);
-}
-
 static int __init sh_mipi_setup(struct sh_mipi *mipi,
                                struct sh_mipi_dsi_info *pdata)
 {
        void __iomem *base = mipi->base;
        struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan;
-       u32 pctype, datatype, pixfmt, linelength, vmctr2 = 0x00e00000;
+       u32 pctype, datatype, pixfmt, linelength, vmctr2;
+       u32 tmp, top, bottom, delay, div;
        bool yuv;
+       int bpp;
 
        /*
         * Select data format. MIPI DSI is not hot-pluggable, so, we just use
@@ -253,6 +234,9 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
            (!yuv && ch->interface_type != RGB24))
                return -EINVAL;
 
+       if (!pdata->lane)
+               return -EINVAL;
+
        /* reset DSI link */
        iowrite32(0x00000001, base + SYSCTRL);
        /* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */
@@ -261,15 +245,6 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
 
        /* setup DSI link */
 
-       /*
-        * Default = ULPS enable |
-        *      Contention detection enabled |
-        *      EoT packet transmission enable |
-        *      CRC check enable |
-        *      ECC check enable
-        * additionally enable first two lanes
-        */
-       iowrite32(0x00003703, base + SYSCONF);
        /*
         * T_wakeup = 0x7000
         * T_hs-trail = 3
@@ -290,15 +265,24 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
        iowrite32(0x0fffffff, base + TATOVSET);
        /* Peripheral reset timeout, default 0xffffffff */
        iowrite32(0x0fffffff, base + PRTOVSET);
-       /* Enable timeout counters */
-       iowrite32(0x00000f00, base + DSICTRL);
        /* Interrupts not used, disable all */
        iowrite32(0, base + DSIINTE);
        /* DSI-Tx bias on */
        iowrite32(0x00000001, base + PHYCTRL);
        udelay(200);
-       /* Deassert resets, power on, set multiplier */
-       iowrite32(0x03070b01, base + PHYCTRL);
+       /* Deassert resets, power on */
+       iowrite32(0x03070001, base + PHYCTRL);
+
+       /*
+        * Default = ULPS enable |
+        *      Contention detection enabled |
+        *      EoT packet transmission enable |
+        *      CRC check enable |
+        *      ECC check enable
+        */
+       bitmap_fill((unsigned long *)&tmp, pdata->lane);
+       tmp |= 0x00003700;
+       iowrite32(tmp, base + SYSCONF);
 
        /* setup l-bridge */
 
@@ -316,18 +300,68 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
         * Non-burst mode with sync pulses: VSE and HSE are output,
         * HSA period allowed, no commands in LP
         */
+       vmctr2 = 0;
+       if (pdata->flags & SH_MIPI_DSI_VSEE)
+               vmctr2 |= 1 << 23;
+       if (pdata->flags & SH_MIPI_DSI_HSEE)
+               vmctr2 |= 1 << 22;
+       if (pdata->flags & SH_MIPI_DSI_HSAE)
+               vmctr2 |= 1 << 21;
+       if (pdata->flags & SH_MIPI_DSI_BL2E)
+               vmctr2 |= 1 << 17;
        if (pdata->flags & SH_MIPI_DSI_HSABM)
-               vmctr2 |= 0x20;
-       if (pdata->flags & SH_MIPI_DSI_HSPBM)
-               vmctr2 |= 0x10;
+               vmctr2 |= 1 << 5;
+       if (pdata->flags & SH_MIPI_DSI_HBPBM)
+               vmctr2 |= 1 << 4;
+       if (pdata->flags & SH_MIPI_DSI_HFPBM)
+               vmctr2 |= 1 << 3;
        iowrite32(vmctr2, mipi->linkbase + VMCTR2);
 
        /*
-        * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see
-        * sh_mobile_lcdc_info.ch[0].lcd_cfg[0].xres), HSALEN = 1 - default
-        * (unused if VMCTR2[HSABM] = 0)
+        * VMLEN1 = RGBLEN | HSALEN
+        *
+        * see
+        *  Video mode - Blanking Packet setting
+        */
+       top = linelength << 16; /* RGBLEN */
+       bottom = 0x00000001;
+       if (pdata->flags & SH_MIPI_DSI_HSABM) /* HSALEN */
+               bottom = (pdata->lane * ch->lcd_cfg[0].hsync_len) - 10;
+       iowrite32(top | bottom , mipi->linkbase + VMLEN1);
+
+       /*
+        * VMLEN2 = HBPLEN | HFPLEN
+        *
+        * see
+        *  Video mode - Blanking Packet setting
         */
-       iowrite32(1 | (linelength << 16), mipi->linkbase + VMLEN1);
+       top     = 0x00010000;
+       bottom  = 0x00000001;
+       delay   = 0;
+
+       div = 1;        /* HSbyteCLK is calculation base
+                        * HS4divCLK = HSbyteCLK/2
+                        * HS6divCLK is not supported for now */
+       if (pdata->flags & SH_MIPI_DSI_HS4divCLK)
+               div = 2;
+
+       if (pdata->flags & SH_MIPI_DSI_HFPBM) { /* HBPLEN */
+               top = ch->lcd_cfg[0].hsync_len + ch->lcd_cfg[0].left_margin;
+               top = ((pdata->lane * top / div) - 10) << 16;
+       }
+       if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */
+               bottom = ch->lcd_cfg[0].right_margin;
+               bottom = (pdata->lane * bottom / div) - 12;
+       }
+
+       bpp = linelength / ch->lcd_cfg[0].xres; /* byte / pixel */
+       if ((pdata->lane / div) > bpp) {
+               tmp = ch->lcd_cfg[0].xres / bpp; /* output cycle */
+               tmp = ch->lcd_cfg[0].xres - tmp; /* (input - output) cycle */
+               delay = (pdata->lane * tmp);
+       }
+
+       iowrite32(top | (bottom + delay) , mipi->linkbase + VMLEN2);
 
        msleep(5);
 
@@ -352,9 +386,56 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi,
                          pixfmt << 4);
        sh_mipi_dcs(ch->chan, MIPI_DCS_SET_DISPLAY_ON);
 
+       /* Enable timeout counters */
+       iowrite32(0x00000f00, base + DSICTRL);
+
        return 0;
 }
 
+static void mipi_display_on(void *arg, struct fb_info *info)
+{
+       struct sh_mipi *mipi = arg;
+       struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data;
+       int ret;
+
+       pm_runtime_get_sync(&mipi->pdev->dev);
+
+       ret = pdata->set_dot_clock(mipi->pdev, mipi->base, 1);
+       if (ret < 0)
+               goto mipi_display_on_fail1;
+
+       ret = sh_mipi_setup(mipi, pdata);
+       if (ret < 0)
+               goto mipi_display_on_fail2;
+
+       sh_mipi_dsi_enable(mipi, true);
+
+       if (mipi->next_display_on)
+               mipi->next_display_on(mipi->next_board_data, info);
+
+       return;
+
+mipi_display_on_fail1:
+       pm_runtime_put_sync(&mipi->pdev->dev);
+mipi_display_on_fail2:
+       pdata->set_dot_clock(mipi->pdev, mipi->base, 0);
+}
+
+static void mipi_display_off(void *arg)
+{
+       struct sh_mipi *mipi = arg;
+       struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data;
+
+       if (mipi->next_display_off)
+               mipi->next_display_off(mipi->next_board_data);
+
+       sh_mipi_dsi_enable(mipi, false);
+
+       pdata->set_dot_clock(mipi->pdev, mipi->base, 0);
+
+       pm_runtime_put_sync(&mipi->pdev->dev);
+}
+
 static int __init sh_mipi_probe(struct platform_device *pdev)
 {
        struct sh_mipi *mipi;
@@ -363,11 +444,13 @@ static int __init sh_mipi_probe(struct platform_device *pdev)
        struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        unsigned long rate, f_current;
        int idx = pdev->id, ret;
-       char dsip_clk[] = "dsi.p_clk";
 
        if (!res || !res2 || idx >= ARRAY_SIZE(mipi_dsi) || !pdata)
                return -ENODEV;
 
+       if (!pdata->set_dot_clock)
+               return -EINVAL;
+
        mutex_lock(&array_lock);
        if (idx < 0)
                for (idx = 0; idx < ARRAY_SIZE(mipi_dsi) && mipi_dsi[idx]; idx++)
@@ -408,7 +491,7 @@ static int __init sh_mipi_probe(struct platform_device *pdev)
                goto emap2;
        }
 
-       mipi->dev = &pdev->dev;
+       mipi->pdev = pdev;
 
        mipi->dsit_clk = clk_get(&pdev->dev, "dsit_clk");
        if (IS_ERR(mipi->dsit_clk)) {
@@ -428,44 +511,15 @@ static int __init sh_mipi_probe(struct platform_device *pdev)
 
        dev_dbg(&pdev->dev, "DSI-T clk %lu -> %lu\n", f_current, rate);
 
-       sprintf(dsip_clk, "dsi%1.1dp_clk", idx);
-       mipi->dsip_clk = clk_get(&pdev->dev, dsip_clk);
-       if (IS_ERR(mipi->dsip_clk)) {
-               ret = PTR_ERR(mipi->dsip_clk);
-               goto eclkpget;
-       }
-
-       f_current = clk_get_rate(mipi->dsip_clk);
-       /* Between 10 and 50MHz */
-       rate = clk_round_rate(mipi->dsip_clk, 24000000);
-       if (rate > 0 && rate != f_current)
-               ret = clk_set_rate(mipi->dsip_clk, rate);
-       else
-               ret = rate;
-       if (ret < 0)
-               goto esetprate;
-
-       dev_dbg(&pdev->dev, "DSI-P clk %lu -> %lu\n", f_current, rate);
-
-       msleep(10);
-
        ret = clk_enable(mipi->dsit_clk);
        if (ret < 0)
                goto eclkton;
 
-       ret = clk_enable(mipi->dsip_clk);
-       if (ret < 0)
-               goto eclkpon;
-
        mipi_dsi[idx] = mipi;
 
        pm_runtime_enable(&pdev->dev);
        pm_runtime_resume(&pdev->dev);
 
-       ret = sh_mipi_setup(mipi, pdata);
-       if (ret < 0)
-               goto emipisetup;
-
        mutex_unlock(&array_lock);
        platform_set_drvdata(pdev, mipi);
 
@@ -482,16 +536,7 @@ static int __init sh_mipi_probe(struct platform_device *pdev)
 
        return 0;
 
-emipisetup:
-       mipi_dsi[idx] = NULL;
-       pm_runtime_disable(&pdev->dev);
-       clk_disable(mipi->dsip_clk);
-eclkpon:
-       clk_disable(mipi->dsit_clk);
 eclkton:
-esetprate:
-       clk_put(mipi->dsip_clk);
-eclkpget:
 esettrate:
        clk_put(mipi->dsit_clk);
 eclktget:
@@ -542,10 +587,9 @@ static int __exit sh_mipi_remove(struct platform_device *pdev)
        pdata->lcd_chan->board_cfg.board_data = NULL;
 
        pm_runtime_disable(&pdev->dev);
-       clk_disable(mipi->dsip_clk);
        clk_disable(mipi->dsit_clk);
        clk_put(mipi->dsit_clk);
-       clk_put(mipi->dsip_clk);
+
        iounmap(mipi->linkbase);
        if (res2)
                release_mem_region(res2->start, resource_size(res2));
index facffc2549766e3ebefd5b8a13e78721523946eb..aac5b369d73cb3acf8b33e9ab1acedebf14c45ac 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
+#include <linux/videodev2.h>
 #include <linux/vmalloc.h>
 #include <linux/ioctl.h>
 #include <linux/slab.h>
@@ -102,7 +103,7 @@ struct sh_mobile_lcdc_priv {
        struct sh_mobile_lcdc_chan ch[2];
        struct notifier_block notifier;
        int started;
-       int forced_bpp; /* 2 channel LCDC must share bpp setting */
+       int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
        struct sh_mobile_meram_info *meram_dev;
 };
 
@@ -215,6 +216,47 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
        lcdc_sys_read_data,
 };
 
+static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
+{
+       if (var->grayscale > 1)
+               return var->grayscale;
+
+       switch (var->bits_per_pixel) {
+       case 16:
+               return V4L2_PIX_FMT_RGB565;
+       case 24:
+               return V4L2_PIX_FMT_BGR24;
+       case 32:
+               return V4L2_PIX_FMT_BGR32;
+       default:
+               return 0;
+       }
+}
+
+static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
+{
+       return var->grayscale > 1;
+}
+
+static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var)
+{
+       if (var->grayscale <= 1)
+               return false;
+
+       switch (var->grayscale) {
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV61:
+       case V4L2_PIX_FMT_NV24:
+       case V4L2_PIX_FMT_NV42:
+               return true;
+
+       default:
+               return false;
+       }
+}
+
 static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
 {
        if (atomic_inc_and_test(&priv->hw_usecnt)) {
@@ -420,7 +462,7 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
        tmp = ((display_var->xres & 7) << 24) |
                ((display_h_total & 7) << 16) |
                ((display_var->hsync_len & 7) << 8) |
-               hsync_pos;
+               (hsync_pos & 7);
        lcdc_write_chan(ch, LDHAJR, tmp);
 }
 
@@ -435,7 +477,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 {
        struct sh_mobile_lcdc_chan *ch;
        unsigned long tmp;
-       int bpp = 0;
        int k, m;
 
        /* Enable LCDC channels. Read data from external memory, avoid using the
@@ -454,9 +495,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
                if (!ch->enabled)
                        continue;
 
-               if (!bpp)
-                       bpp = ch->info->var.bits_per_pixel;
-
                /* Power supply */
                lcdc_write_chan(ch, LDPMR, 0);
 
@@ -487,31 +525,37 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 
                sh_mobile_lcdc_geometry(ch);
 
-               if (ch->info->var.nonstd) {
-                       tmp = (ch->info->var.nonstd << 16);
-                       switch (ch->info->var.bits_per_pixel) {
-                       case 12:
-                               tmp |= LDDFR_YF_420;
-                               break;
-                       case 16:
-                               tmp |= LDDFR_YF_422;
-                               break;
-                       case 24:
-                       default:
-                               tmp |= LDDFR_YF_444;
-                               break;
-                       }
-               } else {
-                       switch (ch->info->var.bits_per_pixel) {
-                       case 16:
-                               tmp = LDDFR_PKF_RGB16;
-                               break;
-                       case 24:
-                               tmp = LDDFR_PKF_RGB24;
+               switch (sh_mobile_format_fourcc(&ch->info->var)) {
+               case V4L2_PIX_FMT_RGB565:
+                       tmp = LDDFR_PKF_RGB16;
+                       break;
+               case V4L2_PIX_FMT_BGR24:
+                       tmp = LDDFR_PKF_RGB24;
+                       break;
+               case V4L2_PIX_FMT_BGR32:
+                       tmp = LDDFR_PKF_ARGB32;
+                       break;
+               case V4L2_PIX_FMT_NV12:
+               case V4L2_PIX_FMT_NV21:
+                       tmp = LDDFR_CC | LDDFR_YF_420;
+                       break;
+               case V4L2_PIX_FMT_NV16:
+               case V4L2_PIX_FMT_NV61:
+                       tmp = LDDFR_CC | LDDFR_YF_422;
+                       break;
+               case V4L2_PIX_FMT_NV24:
+               case V4L2_PIX_FMT_NV42:
+                       tmp = LDDFR_CC | LDDFR_YF_444;
+                       break;
+               }
+
+               if (sh_mobile_format_is_yuv(&ch->info->var)) {
+                       switch (ch->info->var.colorspace) {
+                       case V4L2_COLORSPACE_REC709:
+                               tmp |= LDDFR_CF1;
                                break;
-                       case 32:
-                       default:
-                               tmp = LDDFR_PKF_ARGB32;
+                       case V4L2_COLORSPACE_JPEG:
+                               tmp |= LDDFR_CF0;
                                break;
                        }
                }
@@ -519,7 +563,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
                lcdc_write_chan(ch, LDDFR, tmp);
                lcdc_write_chan(ch, LDMLSR, ch->pitch);
                lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
-               if (ch->info->var.nonstd)
+               if (sh_mobile_format_is_yuv(&ch->info->var))
                        lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
 
                /* When using deferred I/O mode, configure the LCDC for one-shot
@@ -536,21 +580,23 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
        }
 
        /* Word and long word swap. */
-       if  (priv->ch[0].info->var.nonstd)
+       switch (sh_mobile_format_fourcc(&priv->ch[0].info->var)) {
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_NV61:
+       case V4L2_PIX_FMT_NV42:
+               tmp = LDDDSR_LS | LDDDSR_WS;
+               break;
+       case V4L2_PIX_FMT_BGR24:
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV24:
                tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
-       else {
-               switch (bpp) {
-               case 16:
-                       tmp = LDDDSR_LS | LDDDSR_WS;
-                       break;
-               case 24:
-                       tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
-                       break;
-               case 32:
-               default:
-                       tmp = LDDDSR_LS;
-                       break;
-               }
+               break;
+       case V4L2_PIX_FMT_BGR32:
+       default:
+               tmp = LDDDSR_LS;
+               break;
        }
        lcdc_write(priv, _LDDDSR, tmp);
 
@@ -622,12 +668,24 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
                        ch->meram_enabled = 0;
                }
 
-               if (!ch->info->var.nonstd)
-                       pixelformat = SH_MOBILE_MERAM_PF_RGB;
-               else if (ch->info->var.bits_per_pixel == 24)
-                       pixelformat = SH_MOBILE_MERAM_PF_NV24;
-               else
+               switch (sh_mobile_format_fourcc(&ch->info->var)) {
+               case V4L2_PIX_FMT_NV12:
+               case V4L2_PIX_FMT_NV21:
+               case V4L2_PIX_FMT_NV16:
+               case V4L2_PIX_FMT_NV61:
                        pixelformat = SH_MOBILE_MERAM_PF_NV;
+                       break;
+               case V4L2_PIX_FMT_NV24:
+               case V4L2_PIX_FMT_NV42:
+                       pixelformat = SH_MOBILE_MERAM_PF_NV24;
+                       break;
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_BGR24:
+               case V4L2_PIX_FMT_BGR32:
+               default:
+                       pixelformat = SH_MOBILE_MERAM_PF_RGB;
+                       break;
+               }
 
                ret = mdev->ops->meram_register(mdev, cfg, ch->pitch,
                                        ch->info->var.yres, pixelformat,
@@ -845,6 +903,7 @@ static struct fb_fix_screeninfo sh_mobile_lcdc_fix  = {
        .xpanstep =     0,
        .ypanstep =     1,
        .ywrapstep =    0,
+       .capabilities = FB_CAP_FOURCC,
 };
 
 static void sh_mobile_lcdc_fillrect(struct fb_info *info,
@@ -877,8 +936,9 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
        unsigned long new_pan_offset;
        unsigned long base_addr_y, base_addr_c;
        unsigned long c_offset;
+       bool yuv = sh_mobile_format_is_yuv(&info->var);
 
-       if (!info->var.nonstd)
+       if (!yuv)
                new_pan_offset = var->yoffset * info->fix.line_length
                               + var->xoffset * (info->var.bits_per_pixel / 8);
        else
@@ -892,7 +952,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
 
        /* Set the source address for the next refresh */
        base_addr_y = ch->dma_handle + new_pan_offset;
-       if (info->var.nonstd) {
+       if (yuv) {
                /* Set y offset */
                c_offset = var->yoffset * info->fix.line_length
                         * (info->var.bits_per_pixel - 8) / 8;
@@ -900,7 +960,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
                            + info->var.xres * info->var.yres_virtual
                            + c_offset;
                /* Set x offset */
-               if (info->var.bits_per_pixel == 24)
+               if (sh_mobile_format_fourcc(&info->var) == V4L2_PIX_FMT_NV24)
                        base_addr_c += 2 * var->xoffset;
                else
                        base_addr_c += var->xoffset;
@@ -924,7 +984,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
        ch->base_addr_c = base_addr_c;
 
        lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
-       if (info->var.nonstd)
+       if (yuv)
                lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
 
        if (lcdc_chan_is_sublcd(ch))
@@ -1100,51 +1160,84 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
        if (var->yres_virtual < var->yres)
                var->yres_virtual = var->yres;
 
-       if (var->bits_per_pixel <= 16) {                /* RGB 565 */
-               var->bits_per_pixel = 16;
-               var->red.offset = 11;
-               var->red.length = 5;
-               var->green.offset = 5;
-               var->green.length = 6;
-               var->blue.offset = 0;
-               var->blue.length = 5;
-               var->transp.offset = 0;
-               var->transp.length = 0;
-       } else if (var->bits_per_pixel <= 24) {         /* RGB 888 */
-               var->bits_per_pixel = 24;
-               var->red.offset = 16;
-               var->red.length = 8;
-               var->green.offset = 8;
-               var->green.length = 8;
-               var->blue.offset = 0;
-               var->blue.length = 8;
-               var->transp.offset = 0;
-               var->transp.length = 0;
-       } else if (var->bits_per_pixel <= 32) {         /* RGBA 888 */
-               var->bits_per_pixel = 32;
-               var->red.offset = 16;
-               var->red.length = 8;
-               var->green.offset = 8;
-               var->green.length = 8;
-               var->blue.offset = 0;
-               var->blue.length = 8;
-               var->transp.offset = 24;
-               var->transp.length = 8;
-       } else
-               return -EINVAL;
+       if (sh_mobile_format_is_fourcc(var)) {
+               switch (var->grayscale) {
+               case V4L2_PIX_FMT_NV12:
+               case V4L2_PIX_FMT_NV21:
+                       var->bits_per_pixel = 12;
+                       break;
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_NV16:
+               case V4L2_PIX_FMT_NV61:
+                       var->bits_per_pixel = 16;
+                       break;
+               case V4L2_PIX_FMT_BGR24:
+               case V4L2_PIX_FMT_NV24:
+               case V4L2_PIX_FMT_NV42:
+                       var->bits_per_pixel = 24;
+                       break;
+               case V4L2_PIX_FMT_BGR32:
+                       var->bits_per_pixel = 32;
+                       break;
+               default:
+                       return -EINVAL;
+               }
 
-       var->red.msb_right = 0;
-       var->green.msb_right = 0;
-       var->blue.msb_right = 0;
-       var->transp.msb_right = 0;
+               /* Default to RGB and JPEG color-spaces for RGB and YUV formats
+                * respectively.
+                */
+               if (!sh_mobile_format_is_yuv(var))
+                       var->colorspace = V4L2_COLORSPACE_SRGB;
+               else if (var->colorspace != V4L2_COLORSPACE_REC709)
+                       var->colorspace = V4L2_COLORSPACE_JPEG;
+       } else {
+               if (var->bits_per_pixel <= 16) {                /* RGB 565 */
+                       var->bits_per_pixel = 16;
+                       var->red.offset = 11;
+                       var->red.length = 5;
+                       var->green.offset = 5;
+                       var->green.length = 6;
+                       var->blue.offset = 0;
+                       var->blue.length = 5;
+                       var->transp.offset = 0;
+                       var->transp.length = 0;
+               } else if (var->bits_per_pixel <= 24) {         /* RGB 888 */
+                       var->bits_per_pixel = 24;
+                       var->red.offset = 16;
+                       var->red.length = 8;
+                       var->green.offset = 8;
+                       var->green.length = 8;
+                       var->blue.offset = 0;
+                       var->blue.length = 8;
+                       var->transp.offset = 0;
+                       var->transp.length = 0;
+               } else if (var->bits_per_pixel <= 32) {         /* RGBA 888 */
+                       var->bits_per_pixel = 32;
+                       var->red.offset = 16;
+                       var->red.length = 8;
+                       var->green.offset = 8;
+                       var->green.length = 8;
+                       var->blue.offset = 0;
+                       var->blue.length = 8;
+                       var->transp.offset = 24;
+                       var->transp.length = 8;
+               } else
+                       return -EINVAL;
+
+               var->red.msb_right = 0;
+               var->green.msb_right = 0;
+               var->blue.msb_right = 0;
+               var->transp.msb_right = 0;
+       }
 
        /* Make sure we don't exceed our allocated memory. */
        if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
            info->fix.smem_len)
                return -EINVAL;
 
-       /* only accept the forced_bpp for dual channel configurations */
-       if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel)
+       /* only accept the forced_fourcc for dual channel configurations */
+       if (p->forced_fourcc &&
+           p->forced_fourcc != sh_mobile_format_fourcc(var))
                return -EINVAL;
 
        return 0;
@@ -1158,7 +1251,7 @@ static int sh_mobile_set_par(struct fb_info *info)
 
        sh_mobile_lcdc_stop(ch->lcdc);
 
-       if (info->var.nonstd)
+       if (sh_mobile_format_is_yuv(&info->var))
                info->fix.line_length = info->var.xres;
        else
                info->fix.line_length = info->var.xres
@@ -1170,6 +1263,14 @@ static int sh_mobile_set_par(struct fb_info *info)
                info->fix.line_length = line_length;
        }
 
+       if (sh_mobile_format_is_fourcc(&info->var)) {
+               info->fix.type = FB_TYPE_FOURCC;
+               info->fix.visual = FB_VISUAL_FOURCC;
+       } else {
+               info->fix.type = FB_TYPE_PACKED_PIXELS;
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+       }
+
        return ret;
 }
 
@@ -1464,9 +1565,9 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
        for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) {
                unsigned int size = mode->yres * mode->xres;
 
-               /* NV12 buffers must have even number of lines */
-               if ((cfg->nonstd) && cfg->bpp == 12 &&
-                               (mode->yres & 0x1)) {
+               /* NV12/NV21 buffers must have even number of lines */
+               if ((cfg->fourcc == V4L2_PIX_FMT_NV12 ||
+                    cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) {
                        dev_err(dev, "yres must be multiple of 2 for YCbCr420 "
                                "mode.\n");
                        return -EINVAL;
@@ -1484,14 +1585,6 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
                dev_dbg(dev, "Found largest videomode %ux%u\n",
                        max_mode->xres, max_mode->yres);
 
-       /* Initialize fixed screen information. Restrict pan to 2 lines steps
-        * for NV12.
-        */
-       info->fix = sh_mobile_lcdc_fix;
-       info->fix.smem_len = max_size * 2 * cfg->bpp / 8;
-       if (cfg->nonstd && cfg->bpp == 12)
-               info->fix.ypanstep = 2;
-
        /* Create the mode list. */
        if (cfg->lcd_cfg == NULL) {
                mode = &default_720p;
@@ -1509,19 +1602,38 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
         */
        var = &info->var;
        fb_videomode_to_var(var, mode);
-       var->bits_per_pixel = cfg->bpp;
        var->width = cfg->lcd_size_cfg.width;
        var->height = cfg->lcd_size_cfg.height;
        var->yres_virtual = var->yres * 2;
        var->activate = FB_ACTIVATE_NOW;
 
+       switch (cfg->fourcc) {
+       case V4L2_PIX_FMT_RGB565:
+               var->bits_per_pixel = 16;
+               break;
+       case V4L2_PIX_FMT_BGR24:
+               var->bits_per_pixel = 24;
+               break;
+       case V4L2_PIX_FMT_BGR32:
+               var->bits_per_pixel = 32;
+               break;
+       default:
+               var->grayscale = cfg->fourcc;
+               break;
+       }
+
+       /* Make sure the memory size check won't fail. smem_len is initialized
+        * later based on var.
+        */
+       info->fix.smem_len = UINT_MAX;
        ret = sh_mobile_check_var(var, info);
        if (ret)
                return ret;
 
+       max_size = max_size * var->bits_per_pixel / 8 * 2;
+
        /* Allocate frame buffer memory and color map. */
-       buf = dma_alloc_coherent(dev, info->fix.smem_len, &ch->dma_handle,
-                                GFP_KERNEL);
+       buf = dma_alloc_coherent(dev, max_size, &ch->dma_handle, GFP_KERNEL);
        if (!buf) {
                dev_err(dev, "unable to allocate buffer\n");
                return -ENOMEM;
@@ -1530,16 +1642,27 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
        ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
        if (ret < 0) {
                dev_err(dev, "unable to allocate cmap\n");
-               dma_free_coherent(dev, info->fix.smem_len,
-                                 buf, ch->dma_handle);
+               dma_free_coherent(dev, max_size, buf, ch->dma_handle);
                return ret;
        }
 
+       /* Initialize fixed screen information. Restrict pan to 2 lines steps
+        * for NV12 and NV21.
+        */
+       info->fix = sh_mobile_lcdc_fix;
        info->fix.smem_start = ch->dma_handle;
-       if (var->nonstd)
+       info->fix.smem_len = max_size;
+       if (cfg->fourcc == V4L2_PIX_FMT_NV12 ||
+           cfg->fourcc == V4L2_PIX_FMT_NV21)
+               info->fix.ypanstep = 2;
+
+       if (sh_mobile_format_is_yuv(var)) {
                info->fix.line_length = var->xres;
-       else
-               info->fix.line_length = var->xres * (cfg->bpp / 8);
+               info->fix.visual = FB_VISUAL_FOURCC;
+       } else {
+               info->fix.line_length = var->xres * var->bits_per_pixel / 8;
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+       }
 
        info->screen_base = buf;
        info->device = dev;
@@ -1626,9 +1749,9 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
                goto err1;
        }
 
-       /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */
+       /* for dual channel LCDC (MAIN + SUB) force shared format setting */
        if (num_channels == 2)
-               priv->forced_bpp = pdata->ch[0].bpp;
+               priv->forced_fourcc = pdata->ch[0].fourcc;
 
        priv->base = ioremap_nocache(res->start, resource_size(res));
        if (!priv->base)
@@ -1675,13 +1798,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
                if (error < 0)
                        goto err1;
 
-               dev_info(info->dev,
-                        "registered %s/%s as %dx%d %dbpp.\n",
-                        pdev->name,
-                        (ch->cfg.chan == LCDC_CHAN_MAINLCD) ?
-                        "mainlcd" : "sublcd",
-                        info->var.xres, info->var.yres,
-                        ch->cfg.bpp);
+               dev_info(info->dev, "registered %s/%s as %dx%d %dbpp.\n",
+                        pdev->name, (ch->cfg.chan == LCDC_CHAN_MAINLCD) ?
+                        "mainlcd" : "sublcd", info->var.xres, info->var.yres,
+                        info->var.bits_per_pixel);
 
                /* deferred io mode: disable clock to save power */
                if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
@@ -1709,18 +1829,7 @@ static struct platform_driver sh_mobile_lcdc_driver = {
        .remove         = sh_mobile_lcdc_remove,
 };
 
-static int __init sh_mobile_lcdc_init(void)
-{
-       return platform_driver_register(&sh_mobile_lcdc_driver);
-}
-
-static void __exit sh_mobile_lcdc_exit(void)
-{
-       platform_driver_unregister(&sh_mobile_lcdc_driver);
-}
-
-module_init(sh_mobile_lcdc_init);
-module_exit(sh_mobile_lcdc_exit);
+module_platform_driver(sh_mobile_lcdc_driver);
 
 MODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver");
 MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
index 4d63490209cdf1431430aa343a513d29e11ba846..f45d83ecfd21ee6a6ee106128f3e8818458d100c 100644 (file)
@@ -679,18 +679,7 @@ static struct platform_driver sh_mobile_meram_driver = {
        .remove         = sh_mobile_meram_remove,
 };
 
-static int __init sh_mobile_meram_init(void)
-{
-       return platform_driver_register(&sh_mobile_meram_driver);
-}
-
-static void __exit sh_mobile_meram_exit(void)
-{
-       platform_driver_unregister(&sh_mobile_meram_driver);
-}
-
-module_init(sh_mobile_meram_init);
-module_exit(sh_mobile_meram_exit);
+module_platform_driver(sh_mobile_meram_driver);
 
 MODULE_DESCRIPTION("SuperH Mobile MERAM driver");
 MODULE_AUTHOR("Damian Hobson-Garcia / Takanari Hayama");
index a78254cf8e83eb971db5bd7f6cb499745a6741f6..3690effbedccc2bf552c66e997ca5257b1b4c20a 100644 (file)
@@ -2230,18 +2230,7 @@ static struct platform_driver sm501fb_driver = {
        },
 };
 
-static int __devinit sm501fb_init(void)
-{
-       return platform_driver_register(&sm501fb_driver);
-}
-
-static void __exit sm501fb_cleanup(void)
-{
-       platform_driver_unregister(&sm501fb_driver);
-}
-
-module_init(sm501fb_init);
-module_exit(sm501fb_cleanup);
+module_platform_driver(sm501fb_driver);
 
 module_param_named(mode, fb_mode, charp, 0);
 MODULE_PARM_DESC(mode,
index 3c22994ea31aac07256e1383503ac77ad97e650a..ccbfef5e828f3d19815dc7f91c27164c737f4250 100644 (file)
@@ -130,8 +130,8 @@ static struct usb_device_id id_table[] = {
 MODULE_DEVICE_TABLE(usb, id_table);
 
 /* module options */
-static int console;   /* Optionally allow fbcon to consume first framebuffer */
-static int fb_defio = true;  /* Optionally enable fb_defio mmap support */
+static bool console;   /* Optionally allow fbcon to consume first framebuffer */
+static bool fb_defio = true;  /* Optionally enable fb_defio mmap support */
 
 /* ufx keeps a list of urbs for efficient bulk transfers */
 static void ufx_urb_completion(struct urb *urb);
index 2301c275d63a60c033446637a3ebe5b169998a43..111fb32e87695c4343db204cc5b8dd703d725e30 100644 (file)
 
 /* initialized by setup */
 
-static int vgapass;            /* enable VGA passthrough cable */
+static bool vgapass;           /* enable VGA passthrough cable */
 static int mem;                        /* mem size in MB, 0 = autodetect */
-static int clipping = 1;       /* use clipping (slower, safer) */
+static bool clipping = 1;      /* use clipping (slower, safer) */
 static int gfxclk;             /* force FBI freq in Mhz . Dangerous */
-static int slowpci;            /* slow PCI settings */
+static bool slowpci;           /* slow PCI settings */
 
 /*
   Possible default video modes: 800x600@60, 640x480@75, 1024x768@76, 640x480@60
index a99b994c9b6b121441937acf5ce6d6143cfc5d0e..e026724a3a56528a3782e87f9615109bdcd1811f 100644 (file)
@@ -169,7 +169,7 @@ static int nowrap = 1;      /* not implemented (yet) */
 static int hwcursor = 1;
 static char *mode_option __devinitdata;
 /* mtrr option */
-static int nomtrr __devinitdata;
+static bool nomtrr __devinitdata;
 
 /* -------------------------------------------------------------------------
  *                     Hardware-specific funcions
index 1f868d0187a20672cfb407a31ab1540460e8994c..a19773149bd7edaa7844ff2777ebf771e9fe9013 100644 (file)
@@ -69,9 +69,9 @@ static struct usb_device_id id_table[] = {
 MODULE_DEVICE_TABLE(usb, id_table);
 
 /* module options */
-static int console = 1; /* Allow fbcon to open framebuffer */
-static int fb_defio = 1;  /* Detect mmap writes using page faults */
-static int shadow = 1; /* Optionally disable shadow framebuffer */
+static bool console = 1; /* Allow fbcon to open framebuffer */
+static bool fb_defio = 1;  /* Detect mmap writes using page faults */
+static bool shadow = 1; /* Optionally disable shadow framebuffer */
 
 /* dlfb keeps a list of urbs for efficient bulk transfers */
 static void dlfb_urb_completion(struct urb *urb);
index 7f8472cc993b2908e2ebc695cac102242dccc921..e7f69ef572dc9948f66989d1b7771cfc04d354f5 100644 (file)
@@ -44,11 +44,11 @@ static struct fb_fix_screeninfo uvesafb_fix __devinitdata = {
 };
 
 static int mtrr                __devinitdata = 3; /* enable mtrr by default */
-static int blank       = 1;               /* enable blanking by default */
+static bool blank      = 1;               /* enable blanking by default */
 static int ypan                = 1;             /* 0: scroll, 1: ypan, 2: ywrap */
 static bool pmi_setpal __devinitdata = true; /* use PMI for palette changes */
-static int nocrtc      __devinitdata; /* ignore CRTC settings */
-static int noedid      __devinitdata; /* don't try DDC transfers */
+static bool nocrtc     __devinitdata; /* ignore CRTC settings */
+static bool noedid     __devinitdata; /* don't try DDC transfers */
 static int vram_remap  __devinitdata; /* set amt. of memory to be used */
 static int vram_total  __devinitdata; /* set total amount of memory */
 static u16 maxclk      __devinitdata; /* maximum pixel clock */
index bf2f78065cf97d8d0bcdf492087244946783e99c..501a922aa9dc425c0d45258c8fb19ac897d51da9 100644 (file)
@@ -110,7 +110,7 @@ static struct fb_fix_screeninfo vfb_fix __devinitdata = {
        .accel =        FB_ACCEL_NONE,
 };
 
-static int vfb_enable __initdata = 0;  /* disabled by default */
+static bool vfb_enable __initdata = 0; /* disabled by default */
 module_param(vfb_enable, bool, 0);
 
 static int vfb_check_var(struct fb_var_screeninfo *var,
index 777c21dd7a6ba8b126d4a63feec5765b48a24db7..2a5fe6ede845a96dcfdf40c6e48c5295c11ba756 100644 (file)
@@ -457,18 +457,7 @@ static struct platform_driver vt8500lcd_driver = {
        },
 };
 
-static int __init vt8500lcd_init(void)
-{
-       return platform_driver_register(&vt8500lcd_driver);
-}
-
-static void __exit vt8500lcd_exit(void)
-{
-       platform_driver_unregister(&vt8500lcd_driver);
-}
-
-module_init(vt8500lcd_init);
-module_exit(vt8500lcd_exit);
+module_platform_driver(vt8500lcd_driver);
 
 MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
 MODULE_DESCRIPTION("LCD controller driver for VIA VT8500");
index 2375e5bbf572e8c55d0e65d1a94ddca813634ce9..90a2e30272ad7ae90e4b106426dd37c486c73cd6 100644 (file)
@@ -1620,18 +1620,7 @@ static struct platform_driver w100fb_driver = {
        },
 };
 
-int __init w100fb_init(void)
-{
-       return platform_driver_register(&w100fb_driver);
-}
-
-void __exit w100fb_cleanup(void)
-{
-       platform_driver_unregister(&w100fb_driver);
-}
-
-module_init(w100fb_init);
-module_exit(w100fb_cleanup);
+module_platform_driver(w100fb_driver);
 
 MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver");
 MODULE_LICENSE("GPL");
index 96e34a569169db21d47f2b1ac3e687cb68bcb071..c8703bd61b74f6c2a9a77c8e7ebdb1aadcfa63d0 100644 (file)
@@ -404,18 +404,7 @@ static struct platform_driver wm8505fb_driver = {
        },
 };
 
-static int __init wm8505fb_init(void)
-{
-       return platform_driver_register(&wm8505fb_driver);
-}
-
-static void __exit wm8505fb_exit(void)
-{
-       platform_driver_unregister(&wm8505fb_driver);
-}
-
-module_init(wm8505fb_init);
-module_exit(wm8505fb_exit);
+module_platform_driver(wm8505fb_driver);
 
 MODULE_AUTHOR("Ed Spiridonov <edo.rus@gmail.com>");
 MODULE_DESCRIPTION("Framebuffer driver for WMT WM8505");
index 45832b7ef7d2c39107d719a1c58a378709c5dc57..55be3865015bd103aabd9a1bdb1d7837c6c0530d 100644 (file)
@@ -167,18 +167,7 @@ static struct platform_driver wmt_ge_rops_driver = {
        },
 };
 
-static int __init wmt_ge_rops_init(void)
-{
-       return platform_driver_register(&wmt_ge_rops_driver);
-}
-
-static void __exit wmt_ge_rops_exit(void)
-{
-       platform_driver_unregister(&wmt_ge_rops_driver);
-}
-
-module_init(wmt_ge_rops_init);
-module_exit(wmt_ge_rops_exit);
+module_platform_driver(wmt_ge_rops_driver);
 
 MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com");
 MODULE_DESCRIPTION("Accelerators for raster operations using "
index fcb6cd90f64d8ade134626076a622ac4a2a16118..18084525402ace0afd1c08ada58e2c2a50f5cfad 100644 (file)
@@ -511,25 +511,7 @@ static struct platform_driver xilinxfb_of_driver = {
        },
 };
 
-
-/* ---------------------------------------------------------------------
- * Module setup and teardown
- */
-
-static int __init
-xilinxfb_init(void)
-{
-       return platform_driver_register(&xilinxfb_of_driver);
-}
-
-static void __exit
-xilinxfb_cleanup(void)
-{
-       platform_driver_unregister(&xilinxfb_of_driver);
-}
-
-module_init(xilinxfb_init);
-module_exit(xilinxfb_cleanup);
+module_platform_driver(xilinxfb_of_driver);
 
 MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
 MODULE_DESCRIPTION("Xilinx TFT frame buffer driver");
index 94fd738a7741d046c76f53477d2487e94cde97ff..95aeedf198f8c9b6ee08fa59b8767d66f3ec0cc6 100644 (file)
@@ -1,4 +1,5 @@
-/* Virtio balloon implementation, inspired by Dor Loar and Marcelo
+/*
+ * Virtio balloon implementation, inspired by Dor Laor and Marcelo
  * Tosatti's implementations.
  *
  *  Copyright 2008 Rusty Russell IBM Corporation
@@ -17,7 +18,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
-//#define DEBUG
+
 #include <linux/virtio.h>
 #include <linux/virtio_balloon.h>
 #include <linux/swap.h>
@@ -87,7 +88,7 @@ static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)
        init_completion(&vb->acked);
 
        /* We should always be able to add one buffer to an empty queue. */
-       if (virtqueue_add_buf(vq, &sg, 1, 0, vb) < 0)
+       if (virtqueue_add_buf(vq, &sg, 1, 0, vb, GFP_KERNEL) < 0)
                BUG();
        virtqueue_kick(vq);
 
@@ -149,7 +150,6 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
                vb->num_pages--;
        }
 
-
        /*
         * Note that if
         * virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
@@ -220,7 +220,7 @@ static void stats_handle_request(struct virtio_balloon *vb)
 
        vq = vb->stats_vq;
        sg_init_one(&sg, vb->stats, sizeof(vb->stats));
-       if (virtqueue_add_buf(vq, &sg, 1, 0, vb) < 0)
+       if (virtqueue_add_buf(vq, &sg, 1, 0, vb, GFP_KERNEL) < 0)
                BUG();
        virtqueue_kick(vq);
 }
@@ -275,32 +275,21 @@ static int balloon(void *_vballoon)
        return 0;
 }
 
-static int virtballoon_probe(struct virtio_device *vdev)
+static int init_vqs(struct virtio_balloon *vb)
 {
-       struct virtio_balloon *vb;
        struct virtqueue *vqs[3];
        vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request };
        const char *names[] = { "inflate", "deflate", "stats" };
        int err, nvqs;
 
-       vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
-       if (!vb) {
-               err = -ENOMEM;
-               goto out;
-       }
-
-       INIT_LIST_HEAD(&vb->pages);
-       vb->num_pages = 0;
-       init_waitqueue_head(&vb->config_change);
-       vb->vdev = vdev;
-       vb->need_stats_update = 0;
-
-       /* We expect two virtqueues: inflate and deflate,
-        * and optionally stat. */
+       /*
+        * We expect two virtqueues: inflate and deflate, and
+        * optionally stat.
+        */
        nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2;
-       err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
+       err = vb->vdev->config->find_vqs(vb->vdev, nvqs, vqs, callbacks, names);
        if (err)
-               goto out_free_vb;
+               return err;
 
        vb->inflate_vq = vqs[0];
        vb->deflate_vq = vqs[1];
@@ -313,10 +302,34 @@ static int virtballoon_probe(struct virtio_device *vdev)
                 * use it to signal us later.
                 */
                sg_init_one(&sg, vb->stats, sizeof vb->stats);
-               if (virtqueue_add_buf(vb->stats_vq, &sg, 1, 0, vb) < 0)
+               if (virtqueue_add_buf(vb->stats_vq, &sg, 1, 0, vb, GFP_KERNEL)
+                   < 0)
                        BUG();
                virtqueue_kick(vb->stats_vq);
        }
+       return 0;
+}
+
+static int virtballoon_probe(struct virtio_device *vdev)
+{
+       struct virtio_balloon *vb;
+       int err;
+
+       vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
+       if (!vb) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       INIT_LIST_HEAD(&vb->pages);
+       vb->num_pages = 0;
+       init_waitqueue_head(&vb->config_change);
+       vb->vdev = vdev;
+       vb->need_stats_update = 0;
+
+       err = init_vqs(vb);
+       if (err)
+               goto out_free_vb;
 
        vb->thread = kthread_run(balloon, vb, "vballoon");
        if (IS_ERR(vb->thread)) {
@@ -351,6 +364,48 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev)
        kfree(vb);
 }
 
+#ifdef CONFIG_PM
+static int virtballoon_freeze(struct virtio_device *vdev)
+{
+       /*
+        * The kthread is already frozen by the PM core before this
+        * function is called.
+        */
+
+       /* Ensure we don't get any more requests from the host */
+       vdev->config->reset(vdev);
+       vdev->config->del_vqs(vdev);
+       return 0;
+}
+
+static int virtballoon_thaw(struct virtio_device *vdev)
+{
+       return init_vqs(vdev->priv);
+}
+
+static int virtballoon_restore(struct virtio_device *vdev)
+{
+       struct virtio_balloon *vb = vdev->priv;
+       struct page *page, *page2;
+
+       /* We're starting from a clean slate */
+       vb->num_pages = 0;
+
+       /*
+        * If a request wasn't complete at the time of freezing, this
+        * could have been set.
+        */
+       vb->need_stats_update = 0;
+
+       /* We don't have these pages in the balloon anymore! */
+       list_for_each_entry_safe(page, page2, &vb->pages, lru) {
+               list_del(&page->lru);
+               totalram_pages++;
+       }
+       return init_vqs(vdev->priv);
+}
+#endif
+
 static unsigned int features[] = {
        VIRTIO_BALLOON_F_MUST_TELL_HOST,
        VIRTIO_BALLOON_F_STATS_VQ,
@@ -365,6 +420,11 @@ static struct virtio_driver virtio_balloon_driver = {
        .probe =        virtballoon_probe,
        .remove =       __devexit_p(virtballoon_remove),
        .config_changed = virtballoon_changed,
+#ifdef CONFIG_PM
+       .freeze =       virtballoon_freeze,
+       .restore =      virtballoon_restore,
+       .thaw =         virtballoon_thaw,
+#endif
 };
 
 static int __init init(void)
index 0269717436af03f5d502be98629927e7591e5cc4..01d6dc250d5c50a8c01ea22d34818721d8c845d5 100644 (file)
@@ -310,8 +310,8 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index,
                        vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
 
        /* Create the vring */
-       vq = vring_new_virtqueue(info->num, VIRTIO_MMIO_VRING_ALIGN,
-                                vdev, info->queue, vm_notify, callback, name);
+       vq = vring_new_virtqueue(info->num, VIRTIO_MMIO_VRING_ALIGN, vdev,
+                                true, info->queue, vm_notify, callback, name);
        if (!vq) {
                err = -ENOMEM;
                goto error_new_virtqueue;
index baabb7937ec2c338fc813fb91cfaac21b0c94484..635e1efb3792689b6e283766a64af11be6dc8dc6 100644 (file)
@@ -55,6 +55,10 @@ struct virtio_pci_device
        unsigned msix_vectors;
        /* Vectors allocated, excluding per-vq vectors if any */
        unsigned msix_used_vectors;
+
+       /* Status saved during hibernate/restore */
+       u8 saved_status;
+
        /* Whether we have vector per vq */
        bool per_vq_vectors;
 };
@@ -414,8 +418,8 @@ static struct virtqueue *setup_vq(struct virtio_device *vdev, unsigned index,
                  vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
 
        /* create the vring */
-       vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN,
-                                vdev, info->queue, vp_notify, callback, name);
+       vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN, vdev,
+                                true, info->queue, vp_notify, callback, name);
        if (!vq) {
                err = -ENOMEM;
                goto out_activate_queue;
@@ -716,19 +720,114 @@ static void __devexit virtio_pci_remove(struct pci_dev *pci_dev)
 }
 
 #ifdef CONFIG_PM
-static int virtio_pci_suspend(struct pci_dev *pci_dev, pm_message_t state)
+static int virtio_pci_suspend(struct device *dev)
 {
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+
        pci_save_state(pci_dev);
        pci_set_power_state(pci_dev, PCI_D3hot);
        return 0;
 }
 
-static int virtio_pci_resume(struct pci_dev *pci_dev)
+static int virtio_pci_resume(struct device *dev)
 {
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+
        pci_restore_state(pci_dev);
        pci_set_power_state(pci_dev, PCI_D0);
        return 0;
 }
+
+static int virtio_pci_freeze(struct device *dev)
+{
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+       struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+       struct virtio_driver *drv;
+       int ret;
+
+       drv = container_of(vp_dev->vdev.dev.driver,
+                          struct virtio_driver, driver);
+
+       ret = 0;
+       vp_dev->saved_status = vp_get_status(&vp_dev->vdev);
+       if (drv && drv->freeze)
+               ret = drv->freeze(&vp_dev->vdev);
+
+       if (!ret)
+               pci_disable_device(pci_dev);
+       return ret;
+}
+
+static int restore_common(struct device *dev)
+{
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+       struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+       int ret;
+
+       ret = pci_enable_device(pci_dev);
+       if (ret)
+               return ret;
+       pci_set_master(pci_dev);
+       vp_finalize_features(&vp_dev->vdev);
+
+       return ret;
+}
+
+static int virtio_pci_thaw(struct device *dev)
+{
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+       struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+       struct virtio_driver *drv;
+       int ret;
+
+       ret = restore_common(dev);
+       if (ret)
+               return ret;
+
+       drv = container_of(vp_dev->vdev.dev.driver,
+                          struct virtio_driver, driver);
+
+       if (drv && drv->thaw)
+               ret = drv->thaw(&vp_dev->vdev);
+       else if (drv && drv->restore)
+               ret = drv->restore(&vp_dev->vdev);
+
+       /* Finally, tell the device we're all set */
+       if (!ret)
+               vp_set_status(&vp_dev->vdev, vp_dev->saved_status);
+
+       return ret;
+}
+
+static int virtio_pci_restore(struct device *dev)
+{
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+       struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+       struct virtio_driver *drv;
+       int ret;
+
+       drv = container_of(vp_dev->vdev.dev.driver,
+                          struct virtio_driver, driver);
+
+       ret = restore_common(dev);
+       if (!ret && drv && drv->restore)
+               ret = drv->restore(&vp_dev->vdev);
+
+       /* Finally, tell the device we're all set */
+       if (!ret)
+               vp_set_status(&vp_dev->vdev, vp_dev->saved_status);
+
+       return ret;
+}
+
+static const struct dev_pm_ops virtio_pci_pm_ops = {
+       .suspend        = virtio_pci_suspend,
+       .resume         = virtio_pci_resume,
+       .freeze         = virtio_pci_freeze,
+       .thaw           = virtio_pci_thaw,
+       .restore        = virtio_pci_restore,
+       .poweroff       = virtio_pci_suspend,
+};
 #endif
 
 static struct pci_driver virtio_pci_driver = {
@@ -737,8 +836,7 @@ static struct pci_driver virtio_pci_driver = {
        .probe          = virtio_pci_probe,
        .remove         = __devexit_p(virtio_pci_remove),
 #ifdef CONFIG_PM
-       .suspend        = virtio_pci_suspend,
-       .resume         = virtio_pci_resume,
+       .driver.pm      = &virtio_pci_pm_ops,
 #endif
 };
 
index c7a2c208f6eaded137c1f0d9ea73ea0a14100e65..79e1b292c0309b8175a84d7e4353ff94b8e13eb0 100644 (file)
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/hrtimer.h>
 
 /* virtio guest is communicating with a virtual "device" that actually runs on
  * a host processor.  Memory barriers are used to control SMP effects. */
 #ifdef CONFIG_SMP
 /* Where possible, use SMP barriers which are more lightweight than mandatory
  * barriers, because mandatory barriers control MMIO effects on accesses
- * through relaxed memory I/O windows (which virtio does not use). */
-#define virtio_mb() smp_mb()
-#define virtio_rmb() smp_rmb()
-#define virtio_wmb() smp_wmb()
+ * through relaxed memory I/O windows (which virtio-pci does not use). */
+#define virtio_mb(vq) \
+       do { if ((vq)->weak_barriers) smp_mb(); else mb(); } while(0)
+#define virtio_rmb(vq) \
+       do { if ((vq)->weak_barriers) smp_rmb(); else rmb(); } while(0)
+#define virtio_wmb(vq) \
+       do { if ((vq)->weak_barriers) smp_rmb(); else rmb(); } while(0)
 #else
 /* We must force memory ordering even if guest is UP since host could be
  * running on another CPU, but SMP barriers are defined to barrier() in that
  * configuration. So fall back to mandatory barriers instead. */
-#define virtio_mb() mb()
-#define virtio_rmb() rmb()
-#define virtio_wmb() wmb()
+#define virtio_mb(vq) mb()
+#define virtio_rmb(vq) rmb()
+#define virtio_wmb(vq) wmb()
 #endif
 
 #ifdef DEBUG
@@ -77,6 +81,9 @@ struct vring_virtqueue
        /* Actual memory layout for this queue */
        struct vring vring;
 
+       /* Can we use weak barriers? */
+       bool weak_barriers;
+
        /* Other side has made a mess, don't try any more. */
        bool broken;
 
@@ -102,6 +109,10 @@ struct vring_virtqueue
 #ifdef DEBUG
        /* They're supposed to lock for us. */
        unsigned int in_use;
+
+       /* Figure out if their kicks are too delayed. */
+       bool last_add_time_valid;
+       ktime_t last_add_time;
 #endif
 
        /* Tokens for callbacks. */
@@ -160,12 +171,29 @@ static int vring_add_indirect(struct vring_virtqueue *vq,
        return head;
 }
 
-int virtqueue_add_buf_gfp(struct virtqueue *_vq,
-                         struct scatterlist sg[],
-                         unsigned int out,
-                         unsigned int in,
-                         void *data,
-                         gfp_t gfp)
+/**
+ * virtqueue_add_buf - expose buffer to other end
+ * @vq: the struct virtqueue we're talking about.
+ * @sg: the description of the buffer(s).
+ * @out_num: the number of sg readable by other side
+ * @in_num: the number of sg which are writable (after readable ones)
+ * @data: the token identifying the buffer.
+ * @gfp: how to do memory allocations (if necessary).
+ *
+ * Caller must ensure we don't call this with other virtqueue operations
+ * at the same time (except where noted).
+ *
+ * Returns remaining capacity of queue or a negative error
+ * (ie. ENOSPC).  Note that it only really makes sense to treat all
+ * positive return values as "available": indirect buffers mean that
+ * we can put an entire sg[] array inside a single queue entry.
+ */
+int virtqueue_add_buf(struct virtqueue *_vq,
+                     struct scatterlist sg[],
+                     unsigned int out,
+                     unsigned int in,
+                     void *data,
+                     gfp_t gfp)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
        unsigned int i, avail, uninitialized_var(prev);
@@ -175,6 +203,19 @@ int virtqueue_add_buf_gfp(struct virtqueue *_vq,
 
        BUG_ON(data == NULL);
 
+#ifdef DEBUG
+       {
+               ktime_t now = ktime_get();
+
+               /* No kick or get, with .1 second between?  Warn. */
+               if (vq->last_add_time_valid)
+                       WARN_ON(ktime_to_ms(ktime_sub(now, vq->last_add_time))
+                                           > 100);
+               vq->last_add_time = now;
+               vq->last_add_time_valid = true;
+       }
+#endif
+
        /* If the host supports indirect descriptor tables, and we have multiple
         * buffers, then go indirect. FIXME: tune this threshold */
        if (vq->indirect && (out + in) > 1 && vq->num_free) {
@@ -227,40 +268,102 @@ add_head:
        vq->data[head] = data;
 
        /* Put entry in available array (but don't update avail->idx until they
-        * do sync).  FIXME: avoid modulus here? */
-       avail = (vq->vring.avail->idx + vq->num_added++) % vq->vring.num;
+        * do sync). */
+       avail = (vq->vring.avail->idx & (vq->vring.num-1));
        vq->vring.avail->ring[avail] = head;
 
+       /* Descriptors and available array need to be set before we expose the
+        * new available array entries. */
+       virtio_wmb(vq);
+       vq->vring.avail->idx++;
+       vq->num_added++;
+
+       /* This is very unlikely, but theoretically possible.  Kick
+        * just in case. */
+       if (unlikely(vq->num_added == (1 << 16) - 1))
+               virtqueue_kick(_vq);
+
        pr_debug("Added buffer head %i to %p\n", head, vq);
        END_USE(vq);
 
        return vq->num_free;
 }
-EXPORT_SYMBOL_GPL(virtqueue_add_buf_gfp);
+EXPORT_SYMBOL_GPL(virtqueue_add_buf);
 
-void virtqueue_kick(struct virtqueue *_vq)
+/**
+ * virtqueue_kick_prepare - first half of split virtqueue_kick call.
+ * @vq: the struct virtqueue
+ *
+ * Instead of virtqueue_kick(), you can do:
+ *     if (virtqueue_kick_prepare(vq))
+ *             virtqueue_notify(vq);
+ *
+ * This is sometimes useful because the virtqueue_kick_prepare() needs
+ * to be serialized, but the actual virtqueue_notify() call does not.
+ */
+bool virtqueue_kick_prepare(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
        u16 new, old;
+       bool needs_kick;
+
        START_USE(vq);
        /* Descriptors and available array need to be set before we expose the
         * new available array entries. */
-       virtio_wmb();
+       virtio_wmb(vq);
 
-       old = vq->vring.avail->idx;
-       new = vq->vring.avail->idx = old + vq->num_added;
+       old = vq->vring.avail->idx - vq->num_added;
+       new = vq->vring.avail->idx;
        vq->num_added = 0;
 
-       /* Need to update avail index before checking if we should notify */
-       virtio_mb();
-
-       if (vq->event ?
-           vring_need_event(vring_avail_event(&vq->vring), new, old) :
-           !(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
-               /* Prod other side to tell it about changes. */
-               vq->notify(&vq->vq);
+#ifdef DEBUG
+       if (vq->last_add_time_valid) {
+               WARN_ON(ktime_to_ms(ktime_sub(ktime_get(),
+                                             vq->last_add_time)) > 100);
+       }
+       vq->last_add_time_valid = false;
+#endif
 
+       if (vq->event) {
+               needs_kick = vring_need_event(vring_avail_event(&vq->vring),
+                                             new, old);
+       } else {
+               needs_kick = !(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY);
+       }
        END_USE(vq);
+       return needs_kick;
+}
+EXPORT_SYMBOL_GPL(virtqueue_kick_prepare);
+
+/**
+ * virtqueue_notify - second half of split virtqueue_kick call.
+ * @vq: the struct virtqueue
+ *
+ * This does not need to be serialized.
+ */
+void virtqueue_notify(struct virtqueue *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+
+       /* Prod other side to tell it about changes. */
+       vq->notify(_vq);
+}
+EXPORT_SYMBOL_GPL(virtqueue_notify);
+
+/**
+ * virtqueue_kick - update after add_buf
+ * @vq: the struct virtqueue
+ *
+ * After one or more virtqueue_add_buf calls, invoke this to kick
+ * the other side.
+ *
+ * Caller must ensure we don't call this with other virtqueue
+ * operations at the same time (except where noted).
+ */
+void virtqueue_kick(struct virtqueue *vq)
+{
+       if (virtqueue_kick_prepare(vq))
+               virtqueue_notify(vq);
 }
 EXPORT_SYMBOL_GPL(virtqueue_kick);
 
@@ -294,11 +397,28 @@ static inline bool more_used(const struct vring_virtqueue *vq)
        return vq->last_used_idx != vq->vring.used->idx;
 }
 
+/**
+ * virtqueue_get_buf - get the next used buffer
+ * @vq: the struct virtqueue we're talking about.
+ * @len: the length written into the buffer
+ *
+ * If the driver wrote data into the buffer, @len will be set to the
+ * amount written.  This means you don't need to clear the buffer
+ * beforehand to ensure there's no data leakage in the case of short
+ * writes.
+ *
+ * Caller must ensure we don't call this with other virtqueue
+ * operations at the same time (except where noted).
+ *
+ * Returns NULL if there are no used buffers, or the "data" token
+ * handed to virtqueue_add_buf().
+ */
 void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
        void *ret;
        unsigned int i;
+       u16 last_used;
 
        START_USE(vq);
 
@@ -314,10 +434,11 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
        }
 
        /* Only get used array entries after they have been exposed by host. */
-       virtio_rmb();
+       virtio_rmb(vq);
 
-       i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id;
-       *len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len;
+       last_used = (vq->last_used_idx & (vq->vring.num - 1));
+       i = vq->vring.used->ring[last_used].id;
+       *len = vq->vring.used->ring[last_used].len;
 
        if (unlikely(i >= vq->vring.num)) {
                BAD_RING(vq, "id %u out of range\n", i);
@@ -337,14 +458,27 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
         * the read in the next get_buf call. */
        if (!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) {
                vring_used_event(&vq->vring) = vq->last_used_idx;
-               virtio_mb();
+               virtio_mb(vq);
        }
 
+#ifdef DEBUG
+       vq->last_add_time_valid = false;
+#endif
+
        END_USE(vq);
        return ret;
 }
 EXPORT_SYMBOL_GPL(virtqueue_get_buf);
 
+/**
+ * virtqueue_disable_cb - disable callbacks
+ * @vq: the struct virtqueue we're talking about.
+ *
+ * Note that this is not necessarily synchronous, hence unreliable and only
+ * useful as an optimization.
+ *
+ * Unlike other operations, this need not be serialized.
+ */
 void virtqueue_disable_cb(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
@@ -353,6 +487,17 @@ void virtqueue_disable_cb(struct virtqueue *_vq)
 }
 EXPORT_SYMBOL_GPL(virtqueue_disable_cb);
 
+/**
+ * virtqueue_enable_cb - restart callbacks after disable_cb.
+ * @vq: the struct virtqueue we're talking about.
+ *
+ * This re-enables callbacks; it returns "false" if there are pending
+ * buffers in the queue, to detect a possible race between the driver
+ * checking for more work, and enabling callbacks.
+ *
+ * Caller must ensure we don't call this with other virtqueue
+ * operations at the same time (except where noted).
+ */
 bool virtqueue_enable_cb(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
@@ -366,7 +511,7 @@ bool virtqueue_enable_cb(struct virtqueue *_vq)
         * entry. Always do both to keep code simple. */
        vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
        vring_used_event(&vq->vring) = vq->last_used_idx;
-       virtio_mb();
+       virtio_mb(vq);
        if (unlikely(more_used(vq))) {
                END_USE(vq);
                return false;
@@ -377,6 +522,19 @@ bool virtqueue_enable_cb(struct virtqueue *_vq)
 }
 EXPORT_SYMBOL_GPL(virtqueue_enable_cb);
 
+/**
+ * virtqueue_enable_cb_delayed - restart callbacks after disable_cb.
+ * @vq: the struct virtqueue we're talking about.
+ *
+ * This re-enables callbacks but hints to the other side to delay
+ * interrupts until most of the available buffers have been processed;
+ * it returns "false" if there are many pending buffers in the queue,
+ * to detect a possible race between the driver checking for more work,
+ * and enabling callbacks.
+ *
+ * Caller must ensure we don't call this with other virtqueue
+ * operations at the same time (except where noted).
+ */
 bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
@@ -393,7 +551,7 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
        /* TODO: tune this threshold */
        bufs = (u16)(vq->vring.avail->idx - vq->last_used_idx) * 3 / 4;
        vring_used_event(&vq->vring) = vq->last_used_idx + bufs;
-       virtio_mb();
+       virtio_mb(vq);
        if (unlikely((u16)(vq->vring.used->idx - vq->last_used_idx) > bufs)) {
                END_USE(vq);
                return false;
@@ -404,6 +562,14 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
 }
 EXPORT_SYMBOL_GPL(virtqueue_enable_cb_delayed);
 
+/**
+ * virtqueue_detach_unused_buf - detach first unused buffer
+ * @vq: the struct virtqueue we're talking about.
+ *
+ * Returns NULL or the "data" token handed to virtqueue_add_buf().
+ * This is not valid on an active queue; it is useful only for device
+ * shutdown.
+ */
 void *virtqueue_detach_unused_buf(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
@@ -453,6 +619,7 @@ EXPORT_SYMBOL_GPL(vring_interrupt);
 struct virtqueue *vring_new_virtqueue(unsigned int num,
                                      unsigned int vring_align,
                                      struct virtio_device *vdev,
+                                     bool weak_barriers,
                                      void *pages,
                                      void (*notify)(struct virtqueue *),
                                      void (*callback)(struct virtqueue *),
@@ -476,12 +643,14 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
        vq->vq.vdev = vdev;
        vq->vq.name = name;
        vq->notify = notify;
+       vq->weak_barriers = weak_barriers;
        vq->broken = false;
        vq->last_used_idx = 0;
        vq->num_added = 0;
        list_add_tail(&vq->vq.list, &vdev->vqs);
 #ifdef DEBUG
        vq->in_use = false;
+       vq->last_add_time_valid = false;
 #endif
 
        vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC);
@@ -530,7 +699,13 @@ void vring_transport_features(struct virtio_device *vdev)
 }
 EXPORT_SYMBOL_GPL(vring_transport_features);
 
-/* return the size of the vring within the virtqueue */
+/**
+ * virtqueue_get_vring_size - return the size of the virtqueue's vring
+ * @vq: the struct virtqueue containing the vring of interest.
+ *
+ * Returns the size of the vring.  This is mainly used for boasting to
+ * userspace.  Unlike other operations, this need not be serialized.
+ */
 unsigned int virtqueue_get_vring_size(struct virtqueue *_vq)
 {
 
index d4d8d1fdccc42987c4919a12157f89ebd47b291f..e45ca2b4bfbeea2722fb91097fc8f1cfea63d60c 100644 (file)
@@ -100,7 +100,7 @@ MODULE_PARM_DESC(f71862fg_pin,
        "Watchdog f71862fg reset output pin configuration. Choose pin 56 or 63"
                        " (default=" __MODULE_STRING(WATCHDOG_F71862FG_PIN)")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 0444);
 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 
index eed5436ffb512dd75b54f3c10a97040f71a0c71d..20feb4d3d791037049bbd95b9b0d8c93874f8af6 100644 (file)
@@ -55,7 +55,7 @@ module_param(timeout, ushort, 0);
 MODULE_PARM_DESC(timeout,
        "Watchdog timeout in ticks. (0<timeout<65536, default=65535)");
 
-static int reset = 1;
+static bool reset = 1;
 module_param(reset, bool, 0);
 MODULE_PARM_DESC(reset,
        "Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset");
index ba6eda4b51433e20e87f4ae977cdd565f7d3c300..0edb91c0de6bf2b69d6de3ec41d43d38b5d823b5 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/bio.h>
 #include <linux/io.h>
+#include <linux/export.h>
 #include <xen/page.h>
 
 bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
@@ -11,3 +12,4 @@ bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
        return __BIOVEC_PHYS_MERGEABLE(vec1, vec2) &&
                ((mfn1 == mfn2) || ((mfn1+1) == mfn2));
 }
+EXPORT_SYMBOL(xen_biovec_phys_mergeable);
index 3832e303c33aca5ceabf0bb1540e02a28b7765bc..596e6a7b17d68bc3ebf424cc11344da1cc32f1e5 100644 (file)
@@ -221,7 +221,7 @@ static int register_balloon(struct device *dev)
 {
        int i, error;
 
-       error = bus_register(&balloon_subsys);
+       error = subsys_system_register(&balloon_subsys, NULL);
        if (error)
                return error;
 
index 52fed16d870161c781c23275e8aeaedb9cef9b7c..30d7be026c189de2b4235eb7818a6d5e971aa0fb 100644 (file)
@@ -16,7 +16,7 @@
 #include "conf_space.h"
 #include "conf_space_quirks.h"
 
-static int permissive;
+static bool permissive;
 module_param(permissive, bool, 0644);
 
 /* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word,
index 8e1c44d8ab469d2e28d47a838cb003fafb79949c..d5dcf8d5d3d91efbaba633f4c2f60259b9c455d0 100644 (file)
@@ -16,7 +16,7 @@
 #define INVALID_EVTCHN_IRQ  (-1)
 struct workqueue_struct *xen_pcibk_wq;
 
-static int __read_mostly passthrough;
+static bool __read_mostly passthrough;
 module_param(passthrough, bool, S_IRUGO);
 MODULE_PARM_DESC(passthrough,
        "Option to specify how to export PCI topology to guest:\n"\
index 5f43bfba3c7a76906244b47fce383ab310c08c5b..0d15a3d113a2c77bb119913f6fa2229a7c0605fa 100644 (file)
@@ -82,7 +82,6 @@ fw-shipped-$(CONFIG_SERIAL_8250_CS) += cis/MT5634ZLX.cis cis/RS-COM-2P.cis \
 fw-shipped-$(CONFIG_PCMCIA_SMC91C92) += ositech/Xilinx7OD.bin
 fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \
                                      advansys/3550.bin advansys/38C0800.bin
-fw-shipped-$(CONFIG_SCSI_ISCI) += isci/isci_firmware.bin
 fw-shipped-$(CONFIG_SCSI_QLOGIC_1280) += qlogic/1040.bin qlogic/1280.bin \
                                         qlogic/12160.bin
 fw-shipped-$(CONFIG_SCSI_QLOGICPTI) += qlogic/isp1000.bin
diff --git a/firmware/isci/isci_firmware.bin.ihex b/firmware/isci/isci_firmware.bin.ihex
deleted file mode 100644 (file)
index 2e66195..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-:10000000495343554F454D42E80018100002000087
-:1000100000000000000000000101000000000000DE
-:10002000FFFFCF5F0100000008DD0B0000FC0F00A8
-:10003000097C0B006EFC0A00FFFFCF5F010000008F
-:1000400008DD0B0000FC0F00097C0B006EFC0A00B1
-:10005000FFFFCF5F0100000008DD0B0000FC0F0078
-:10006000097C0B006EFC0A00FFFFCF5F010000005F
-:1000700008DD0B0000FC0F00097C0B006EFC0A0081
-:100080000101000000000000FFFFCF5F0200000040
-:1000900008DD0B0000FC0F00097C0B006EFC0A0061
-:1000A000FFFFCF5F0200000008DD0B0000FC0F0027
-:1000B000097C0B006EFC0A00FFFFCF5F020000000E
-:1000C00008DD0B0000FC0F00097C0B006EFC0A0031
-:1000D000FFFFCF5F0200000008DD0B0000FC0F00F7
-:0800E000097C0B006EFC0A0014
-:00000001FF
index 78c514cfd212d66b8e6311d4a25435be6493c26d..969beb0e22311a4f7e7f4155524709d5dd8269bf 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -476,14 +476,21 @@ static void kiocb_batch_init(struct kiocb_batch *batch, long total)
        batch->count = total;
 }
 
-static void kiocb_batch_free(struct kiocb_batch *batch)
+static void kiocb_batch_free(struct kioctx *ctx, struct kiocb_batch *batch)
 {
        struct kiocb *req, *n;
 
+       if (list_empty(&batch->head))
+               return;
+
+       spin_lock_irq(&ctx->ctx_lock);
        list_for_each_entry_safe(req, n, &batch->head, ki_batch) {
                list_del(&req->ki_batch);
+               list_del(&req->ki_list);
                kmem_cache_free(kiocb_cachep, req);
+               ctx->reqs_active--;
        }
+       spin_unlock_irq(&ctx->ctx_lock);
 }
 
 /*
@@ -1742,7 +1749,7 @@ long do_io_submit(aio_context_t ctx_id, long nr,
        }
        blk_finish_plug(&plug);
 
-       kiocb_batch_free(&batch);
+       kiocb_batch_free(ctx, &batch);
        put_ioctx(ctx);
        return i ? i : ret;
 }
index 9ef5b2914407c40327db81a5688850a808210991..da8876d38a7b7e3a50101f02817cbbbc460cec20 100644 (file)
@@ -76,7 +76,7 @@ static int autofs4_write(struct autofs_sb_info *sbi,
                data += wr;
                bytes -= wr;
        }
-       mutex_lock(&sbi->pipe_mutex);
+       mutex_unlock(&sbi->pipe_mutex);
 
        set_fs(fs);
 
index afe74dda632b92ae529aff9a92d319e5ff7052c5..0e575d1304b461e67bfbbba6ef234c53838b8998 100644 (file)
@@ -1139,6 +1139,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
        mutex_lock_nested(&bdev->bd_mutex, for_part);
        if (!bdev->bd_openers) {
                bdev->bd_disk = disk;
+               bdev->bd_queue = disk->queue;
                bdev->bd_contains = bdev;
                if (!partno) {
                        struct backing_dev_info *bdi;
@@ -1159,6 +1160,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                                        disk_put_part(bdev->bd_part);
                                        bdev->bd_part = NULL;
                                        bdev->bd_disk = NULL;
+                                       bdev->bd_queue = NULL;
                                        mutex_unlock(&bdev->bd_mutex);
                                        disk_unblock_events(disk);
                                        put_disk(disk);
@@ -1232,6 +1234,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
        disk_put_part(bdev->bd_part);
        bdev->bd_disk = NULL;
        bdev->bd_part = NULL;
+       bdev->bd_queue = NULL;
        bdev_inode_switch_bdi(bdev->bd_inode, &default_backing_dev_info);
        if (bdev != bdev->bd_contains)
                __blkdev_put(bdev->bd_contains, mode, 1);
index ecb9fd3be1433838911f4c947627436d816cb136..d33f01c08b60b329247fe4d8729a387af7c263e4 100644 (file)
@@ -31,3 +31,22 @@ config BTRFS_FS_POSIX_ACL
          Linux website <http://acl.bestbits.at/>.
 
          If you don't know what Access Control Lists are, say N
+
+config BTRFS_FS_CHECK_INTEGRITY
+       bool "Btrfs with integrity check tool compiled in (DANGEROUS)"
+       depends on BTRFS_FS
+       help
+         Adds code that examines all block write requests (including
+         writes of the super block). The goal is to verify that the
+         state of the filesystem on disk is always consistent, i.e.,
+         after a power-loss or kernel panic event the filesystem is
+         in a consistent state.
+
+         If the integrity check tool is included and activated in
+         the mount options, plenty of kernel memory is used, and
+         plenty of additional CPU cycles are spent. Enabling this
+         functionality is not intended for normal use.
+
+         In most cases, unless you are a btrfs developer who needs
+         to verify the integrity of (super)-block write requests
+         during the run of a regression test, say N
index c0ddfd29c5e5a348464d5c3d15a77a7708fd8d79..0c4fa2befae793f1a6845322d7ba71aaa5da4374 100644 (file)
@@ -8,6 +8,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
           extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
           export.o tree-log.o free-space-cache.o zlib.o lzo.o \
           compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
-          reada.o backref.o
+          reada.o backref.o ulist.o
 
 btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
+btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
index 22c64fff1bd524b213ce8b13a233f861680d8424..b9a843226de859c34c8e17f9172aeab0ff0f3be1 100644 (file)
 #include "ctree.h"
 #include "disk-io.h"
 #include "backref.h"
+#include "ulist.h"
+#include "transaction.h"
+#include "delayed-ref.h"
 
-struct __data_ref {
+/*
+ * this structure records all encountered refs on the way up to the root
+ */
+struct __prelim_ref {
        struct list_head list;
-       u64 inum;
-       u64 root;
-       u64 extent_data_item_offset;
+       u64 root_id;
+       struct btrfs_key key;
+       int level;
+       int count;
+       u64 parent;
+       u64 wanted_disk_byte;
 };
 
-struct __shared_ref {
-       struct list_head list;
+static int __add_prelim_ref(struct list_head *head, u64 root_id,
+                           struct btrfs_key *key, int level, u64 parent,
+                           u64 wanted_disk_byte, int count)
+{
+       struct __prelim_ref *ref;
+
+       /* in case we're adding delayed refs, we're holding the refs spinlock */
+       ref = kmalloc(sizeof(*ref), GFP_ATOMIC);
+       if (!ref)
+               return -ENOMEM;
+
+       ref->root_id = root_id;
+       if (key)
+               ref->key = *key;
+       else
+               memset(&ref->key, 0, sizeof(ref->key));
+
+       ref->level = level;
+       ref->count = count;
+       ref->parent = parent;
+       ref->wanted_disk_byte = wanted_disk_byte;
+       list_add_tail(&ref->list, head);
+
+       return 0;
+}
+
+static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
+                               struct ulist *parents,
+                               struct extent_buffer *eb, int level,
+                               u64 wanted_objectid, u64 wanted_disk_byte)
+{
+       int ret;
+       int slot;
+       struct btrfs_file_extent_item *fi;
+       struct btrfs_key key;
        u64 disk_byte;
-};
+
+add_parent:
+       ret = ulist_add(parents, eb->start, 0, GFP_NOFS);
+       if (ret < 0)
+               return ret;
+
+       if (level != 0)
+               return 0;
+
+       /*
+        * if the current leaf is full with EXTENT_DATA items, we must
+        * check the next one if that holds a reference as well.
+        * ref->count cannot be used to skip this check.
+        * repeat this until we don't find any additional EXTENT_DATA items.
+        */
+       while (1) {
+               ret = btrfs_next_leaf(root, path);
+               if (ret < 0)
+                       return ret;
+               if (ret)
+                       return 0;
+
+               eb = path->nodes[0];
+               for (slot = 0; slot < btrfs_header_nritems(eb); ++slot) {
+                       btrfs_item_key_to_cpu(eb, &key, slot);
+                       if (key.objectid != wanted_objectid ||
+                           key.type != BTRFS_EXTENT_DATA_KEY)
+                               return 0;
+                       fi = btrfs_item_ptr(eb, slot,
+                                               struct btrfs_file_extent_item);
+                       disk_byte = btrfs_file_extent_disk_bytenr(eb, fi);
+                       if (disk_byte == wanted_disk_byte)
+                               goto add_parent;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * resolve an indirect backref in the form (root_id, key, level)
+ * to a logical address
+ */
+static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
+                                       struct __prelim_ref *ref,
+                                       struct ulist *parents)
+{
+       struct btrfs_path *path;
+       struct btrfs_root *root;
+       struct btrfs_key root_key;
+       struct btrfs_key key = {0};
+       struct extent_buffer *eb;
+       int ret = 0;
+       int root_level;
+       int level = ref->level;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       root_key.objectid = ref->root_id;
+       root_key.type = BTRFS_ROOT_ITEM_KEY;
+       root_key.offset = (u64)-1;
+       root = btrfs_read_fs_root_no_name(fs_info, &root_key);
+       if (IS_ERR(root)) {
+               ret = PTR_ERR(root);
+               goto out;
+       }
+
+       rcu_read_lock();
+       root_level = btrfs_header_level(root->node);
+       rcu_read_unlock();
+
+       if (root_level + 1 == level)
+               goto out;
+
+       path->lowest_level = level;
+       ret = btrfs_search_slot(NULL, root, &ref->key, path, 0, 0);
+       pr_debug("search slot in root %llu (level %d, ref count %d) returned "
+                "%d for key (%llu %u %llu)\n",
+                (unsigned long long)ref->root_id, level, ref->count, ret,
+                (unsigned long long)ref->key.objectid, ref->key.type,
+                (unsigned long long)ref->key.offset);
+       if (ret < 0)
+               goto out;
+
+       eb = path->nodes[level];
+       if (!eb) {
+               WARN_ON(1);
+               ret = 1;
+               goto out;
+       }
+
+       if (level == 0) {
+               if (ret == 1 && path->slots[0] >= btrfs_header_nritems(eb)) {
+                       ret = btrfs_next_leaf(root, path);
+                       if (ret)
+                               goto out;
+                       eb = path->nodes[0];
+               }
+
+               btrfs_item_key_to_cpu(eb, &key, path->slots[0]);
+       }
+
+       /* the last two parameters will only be used for level == 0 */
+       ret = add_all_parents(root, path, parents, eb, level, key.objectid,
+                               ref->wanted_disk_byte);
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+/*
+ * resolve all indirect backrefs from the list
+ */
+static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
+                                  struct list_head *head)
+{
+       int err;
+       int ret = 0;
+       struct __prelim_ref *ref;
+       struct __prelim_ref *ref_safe;
+       struct __prelim_ref *new_ref;
+       struct ulist *parents;
+       struct ulist_node *node;
+
+       parents = ulist_alloc(GFP_NOFS);
+       if (!parents)
+               return -ENOMEM;
+
+       /*
+        * _safe allows us to insert directly after the current item without
+        * iterating over the newly inserted items.
+        * we're also allowed to re-assign ref during iteration.
+        */
+       list_for_each_entry_safe(ref, ref_safe, head, list) {
+               if (ref->parent)        /* already direct */
+                       continue;
+               if (ref->count == 0)
+                       continue;
+               err = __resolve_indirect_ref(fs_info, ref, parents);
+               if (err) {
+                       if (ret == 0)
+                               ret = err;
+                       continue;
+               }
+
+               /* we put the first parent into the ref at hand */
+               node = ulist_next(parents, NULL);
+               ref->parent = node ? node->val : 0;
+
+               /* additional parents require new refs being added here */
+               while ((node = ulist_next(parents, node))) {
+                       new_ref = kmalloc(sizeof(*new_ref), GFP_NOFS);
+                       if (!new_ref) {
+                               ret = -ENOMEM;
+                               break;
+                       }
+                       memcpy(new_ref, ref, sizeof(*ref));
+                       new_ref->parent = node->val;
+                       list_add(&new_ref->list, &ref->list);
+               }
+               ulist_reinit(parents);
+       }
+
+       ulist_free(parents);
+       return ret;
+}
+
+/*
+ * merge two lists of backrefs and adjust counts accordingly
+ *
+ * mode = 1: merge identical keys, if key is set
+ * mode = 2: merge identical parents
+ */
+static int __merge_refs(struct list_head *head, int mode)
+{
+       struct list_head *pos1;
+
+       list_for_each(pos1, head) {
+               struct list_head *n2;
+               struct list_head *pos2;
+               struct __prelim_ref *ref1;
+
+               ref1 = list_entry(pos1, struct __prelim_ref, list);
+
+               if (mode == 1 && ref1->key.type == 0)
+                       continue;
+               for (pos2 = pos1->next, n2 = pos2->next; pos2 != head;
+                    pos2 = n2, n2 = pos2->next) {
+                       struct __prelim_ref *ref2;
+
+                       ref2 = list_entry(pos2, struct __prelim_ref, list);
+
+                       if (mode == 1) {
+                               if (memcmp(&ref1->key, &ref2->key,
+                                          sizeof(ref1->key)) ||
+                                   ref1->level != ref2->level ||
+                                   ref1->root_id != ref2->root_id)
+                                       continue;
+                               ref1->count += ref2->count;
+                       } else {
+                               if (ref1->parent != ref2->parent)
+                                       continue;
+                               ref1->count += ref2->count;
+                       }
+                       list_del(&ref2->list);
+                       kfree(ref2);
+               }
+
+       }
+       return 0;
+}
+
+/*
+ * add all currently queued delayed refs from this head whose seq nr is
+ * smaller or equal that seq to the list
+ */
+static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
+                             struct btrfs_key *info_key,
+                             struct list_head *prefs)
+{
+       struct btrfs_delayed_extent_op *extent_op = head->extent_op;
+       struct rb_node *n = &head->node.rb_node;
+       int sgn;
+       int ret;
+
+       if (extent_op && extent_op->update_key)
+               btrfs_disk_key_to_cpu(info_key, &extent_op->key);
+
+       while ((n = rb_prev(n))) {
+               struct btrfs_delayed_ref_node *node;
+               node = rb_entry(n, struct btrfs_delayed_ref_node,
+                               rb_node);
+               if (node->bytenr != head->node.bytenr)
+                       break;
+               WARN_ON(node->is_head);
+
+               if (node->seq > seq)
+                       continue;
+
+               switch (node->action) {
+               case BTRFS_ADD_DELAYED_EXTENT:
+               case BTRFS_UPDATE_DELAYED_HEAD:
+                       WARN_ON(1);
+                       continue;
+               case BTRFS_ADD_DELAYED_REF:
+                       sgn = 1;
+                       break;
+               case BTRFS_DROP_DELAYED_REF:
+                       sgn = -1;
+                       break;
+               default:
+                       BUG_ON(1);
+               }
+               switch (node->type) {
+               case BTRFS_TREE_BLOCK_REF_KEY: {
+                       struct btrfs_delayed_tree_ref *ref;
+
+                       ref = btrfs_delayed_node_to_tree_ref(node);
+                       ret = __add_prelim_ref(prefs, ref->root, info_key,
+                                              ref->level + 1, 0, node->bytenr,
+                                              node->ref_mod * sgn);
+                       break;
+               }
+               case BTRFS_SHARED_BLOCK_REF_KEY: {
+                       struct btrfs_delayed_tree_ref *ref;
+
+                       ref = btrfs_delayed_node_to_tree_ref(node);
+                       ret = __add_prelim_ref(prefs, ref->root, info_key,
+                                              ref->level + 1, ref->parent,
+                                              node->bytenr,
+                                              node->ref_mod * sgn);
+                       break;
+               }
+               case BTRFS_EXTENT_DATA_REF_KEY: {
+                       struct btrfs_delayed_data_ref *ref;
+                       struct btrfs_key key;
+
+                       ref = btrfs_delayed_node_to_data_ref(node);
+
+                       key.objectid = ref->objectid;
+                       key.type = BTRFS_EXTENT_DATA_KEY;
+                       key.offset = ref->offset;
+                       ret = __add_prelim_ref(prefs, ref->root, &key, 0, 0,
+                                              node->bytenr,
+                                              node->ref_mod * sgn);
+                       break;
+               }
+               case BTRFS_SHARED_DATA_REF_KEY: {
+                       struct btrfs_delayed_data_ref *ref;
+                       struct btrfs_key key;
+
+                       ref = btrfs_delayed_node_to_data_ref(node);
+
+                       key.objectid = ref->objectid;
+                       key.type = BTRFS_EXTENT_DATA_KEY;
+                       key.offset = ref->offset;
+                       ret = __add_prelim_ref(prefs, ref->root, &key, 0,
+                                              ref->parent, node->bytenr,
+                                              node->ref_mod * sgn);
+                       break;
+               }
+               default:
+                       WARN_ON(1);
+               }
+               BUG_ON(ret);
+       }
+
+       return 0;
+}
+
+/*
+ * add all inline backrefs for bytenr to the list
+ */
+static int __add_inline_refs(struct btrfs_fs_info *fs_info,
+                            struct btrfs_path *path, u64 bytenr,
+                            struct btrfs_key *info_key, int *info_level,
+                            struct list_head *prefs)
+{
+       int ret;
+       int slot;
+       struct extent_buffer *leaf;
+       struct btrfs_key key;
+       unsigned long ptr;
+       unsigned long end;
+       struct btrfs_extent_item *ei;
+       u64 flags;
+       u64 item_size;
+
+       /*
+        * enumerate all inline refs
+        */
+       leaf = path->nodes[0];
+       slot = path->slots[0] - 1;
+
+       item_size = btrfs_item_size_nr(leaf, slot);
+       BUG_ON(item_size < sizeof(*ei));
+
+       ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
+       flags = btrfs_extent_flags(leaf, ei);
+
+       ptr = (unsigned long)(ei + 1);
+       end = (unsigned long)ei + item_size;
+
+       if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
+               struct btrfs_tree_block_info *info;
+               struct btrfs_disk_key disk_key;
+
+               info = (struct btrfs_tree_block_info *)ptr;
+               *info_level = btrfs_tree_block_level(leaf, info);
+               btrfs_tree_block_key(leaf, info, &disk_key);
+               btrfs_disk_key_to_cpu(info_key, &disk_key);
+               ptr += sizeof(struct btrfs_tree_block_info);
+               BUG_ON(ptr > end);
+       } else {
+               BUG_ON(!(flags & BTRFS_EXTENT_FLAG_DATA));
+       }
+
+       while (ptr < end) {
+               struct btrfs_extent_inline_ref *iref;
+               u64 offset;
+               int type;
+
+               iref = (struct btrfs_extent_inline_ref *)ptr;
+               type = btrfs_extent_inline_ref_type(leaf, iref);
+               offset = btrfs_extent_inline_ref_offset(leaf, iref);
+
+               switch (type) {
+               case BTRFS_SHARED_BLOCK_REF_KEY:
+                       ret = __add_prelim_ref(prefs, 0, info_key,
+                                               *info_level + 1, offset,
+                                               bytenr, 1);
+                       break;
+               case BTRFS_SHARED_DATA_REF_KEY: {
+                       struct btrfs_shared_data_ref *sdref;
+                       int count;
+
+                       sdref = (struct btrfs_shared_data_ref *)(iref + 1);
+                       count = btrfs_shared_data_ref_count(leaf, sdref);
+                       ret = __add_prelim_ref(prefs, 0, NULL, 0, offset,
+                                              bytenr, count);
+                       break;
+               }
+               case BTRFS_TREE_BLOCK_REF_KEY:
+                       ret = __add_prelim_ref(prefs, offset, info_key,
+                                              *info_level + 1, 0, bytenr, 1);
+                       break;
+               case BTRFS_EXTENT_DATA_REF_KEY: {
+                       struct btrfs_extent_data_ref *dref;
+                       int count;
+                       u64 root;
+
+                       dref = (struct btrfs_extent_data_ref *)(&iref->offset);
+                       count = btrfs_extent_data_ref_count(leaf, dref);
+                       key.objectid = btrfs_extent_data_ref_objectid(leaf,
+                                                                     dref);
+                       key.type = BTRFS_EXTENT_DATA_KEY;
+                       key.offset = btrfs_extent_data_ref_offset(leaf, dref);
+                       root = btrfs_extent_data_ref_root(leaf, dref);
+                       ret = __add_prelim_ref(prefs, root, &key, 0, 0, bytenr,
+                                               count);
+                       break;
+               }
+               default:
+                       WARN_ON(1);
+               }
+               BUG_ON(ret);
+               ptr += btrfs_extent_inline_ref_size(type);
+       }
+
+       return 0;
+}
+
+/*
+ * add all non-inline backrefs for bytenr to the list
+ */
+static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
+                           struct btrfs_path *path, u64 bytenr,
+                           struct btrfs_key *info_key, int info_level,
+                           struct list_head *prefs)
+{
+       struct btrfs_root *extent_root = fs_info->extent_root;
+       int ret;
+       int slot;
+       struct extent_buffer *leaf;
+       struct btrfs_key key;
+
+       while (1) {
+               ret = btrfs_next_item(extent_root, path);
+               if (ret < 0)
+                       break;
+               if (ret) {
+                       ret = 0;
+                       break;
+               }
+
+               slot = path->slots[0];
+               leaf = path->nodes[0];
+               btrfs_item_key_to_cpu(leaf, &key, slot);
+
+               if (key.objectid != bytenr)
+                       break;
+               if (key.type < BTRFS_TREE_BLOCK_REF_KEY)
+                       continue;
+               if (key.type > BTRFS_SHARED_DATA_REF_KEY)
+                       break;
+
+               switch (key.type) {
+               case BTRFS_SHARED_BLOCK_REF_KEY:
+                       ret = __add_prelim_ref(prefs, 0, info_key,
+                                               info_level + 1, key.offset,
+                                               bytenr, 1);
+                       break;
+               case BTRFS_SHARED_DATA_REF_KEY: {
+                       struct btrfs_shared_data_ref *sdref;
+                       int count;
+
+                       sdref = btrfs_item_ptr(leaf, slot,
+                                             struct btrfs_shared_data_ref);
+                       count = btrfs_shared_data_ref_count(leaf, sdref);
+                       ret = __add_prelim_ref(prefs, 0, NULL, 0, key.offset,
+                                               bytenr, count);
+                       break;
+               }
+               case BTRFS_TREE_BLOCK_REF_KEY:
+                       ret = __add_prelim_ref(prefs, key.offset, info_key,
+                                               info_level + 1, 0, bytenr, 1);
+                       break;
+               case BTRFS_EXTENT_DATA_REF_KEY: {
+                       struct btrfs_extent_data_ref *dref;
+                       int count;
+                       u64 root;
+
+                       dref = btrfs_item_ptr(leaf, slot,
+                                             struct btrfs_extent_data_ref);
+                       count = btrfs_extent_data_ref_count(leaf, dref);
+                       key.objectid = btrfs_extent_data_ref_objectid(leaf,
+                                                                     dref);
+                       key.type = BTRFS_EXTENT_DATA_KEY;
+                       key.offset = btrfs_extent_data_ref_offset(leaf, dref);
+                       root = btrfs_extent_data_ref_root(leaf, dref);
+                       ret = __add_prelim_ref(prefs, root, &key, 0, 0,
+                                               bytenr, count);
+                       break;
+               }
+               default:
+                       WARN_ON(1);
+               }
+               BUG_ON(ret);
+       }
+
+       return ret;
+}
+
+/*
+ * this adds all existing backrefs (inline backrefs, backrefs and delayed
+ * refs) for the given bytenr to the refs list, merges duplicates and resolves
+ * indirect refs to their parent bytenr.
+ * When roots are found, they're added to the roots list
+ *
+ * FIXME some caching might speed things up
+ */
+static int find_parent_nodes(struct btrfs_trans_handle *trans,
+                            struct btrfs_fs_info *fs_info, u64 bytenr,
+                            u64 seq, struct ulist *refs, struct ulist *roots)
+{
+       struct btrfs_key key;
+       struct btrfs_path *path;
+       struct btrfs_key info_key = { 0 };
+       struct btrfs_delayed_ref_root *delayed_refs = NULL;
+       struct btrfs_delayed_ref_head *head = NULL;
+       int info_level = 0;
+       int ret;
+       struct list_head prefs_delayed;
+       struct list_head prefs;
+       struct __prelim_ref *ref;
+
+       INIT_LIST_HEAD(&prefs);
+       INIT_LIST_HEAD(&prefs_delayed);
+
+       key.objectid = bytenr;
+       key.type = BTRFS_EXTENT_ITEM_KEY;
+       key.offset = (u64)-1;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       /*
+        * grab both a lock on the path and a lock on the delayed ref head.
+        * We need both to get a consistent picture of how the refs look
+        * at a specified point in time
+        */
+again:
+       ret = btrfs_search_slot(trans, fs_info->extent_root, &key, path, 0, 0);
+       if (ret < 0)
+               goto out;
+       BUG_ON(ret == 0);
+
+       /*
+        * look if there are updates for this ref queued and lock the head
+        */
+       delayed_refs = &trans->transaction->delayed_refs;
+       spin_lock(&delayed_refs->lock);
+       head = btrfs_find_delayed_ref_head(trans, bytenr);
+       if (head) {
+               if (!mutex_trylock(&head->mutex)) {
+                       atomic_inc(&head->node.refs);
+                       spin_unlock(&delayed_refs->lock);
+
+                       btrfs_release_path(path);
+
+                       /*
+                        * Mutex was contended, block until it's
+                        * released and try again
+                        */
+                       mutex_lock(&head->mutex);
+                       mutex_unlock(&head->mutex);
+                       btrfs_put_delayed_ref(&head->node);
+                       goto again;
+               }
+               ret = __add_delayed_refs(head, seq, &info_key, &prefs_delayed);
+               if (ret)
+                       goto out;
+       }
+       spin_unlock(&delayed_refs->lock);
+
+       if (path->slots[0]) {
+               struct extent_buffer *leaf;
+               int slot;
+
+               leaf = path->nodes[0];
+               slot = path->slots[0] - 1;
+               btrfs_item_key_to_cpu(leaf, &key, slot);
+               if (key.objectid == bytenr &&
+                   key.type == BTRFS_EXTENT_ITEM_KEY) {
+                       ret = __add_inline_refs(fs_info, path, bytenr,
+                                               &info_key, &info_level, &prefs);
+                       if (ret)
+                               goto out;
+                       ret = __add_keyed_refs(fs_info, path, bytenr, &info_key,
+                                              info_level, &prefs);
+                       if (ret)
+                               goto out;
+               }
+       }
+       btrfs_release_path(path);
+
+       /*
+        * when adding the delayed refs above, the info_key might not have
+        * been known yet. Go over the list and replace the missing keys
+        */
+       list_for_each_entry(ref, &prefs_delayed, list) {
+               if ((ref->key.offset | ref->key.type | ref->key.objectid) == 0)
+                       memcpy(&ref->key, &info_key, sizeof(ref->key));
+       }
+       list_splice_init(&prefs_delayed, &prefs);
+
+       ret = __merge_refs(&prefs, 1);
+       if (ret)
+               goto out;
+
+       ret = __resolve_indirect_refs(fs_info, &prefs);
+       if (ret)
+               goto out;
+
+       ret = __merge_refs(&prefs, 2);
+       if (ret)
+               goto out;
+
+       while (!list_empty(&prefs)) {
+               ref = list_first_entry(&prefs, struct __prelim_ref, list);
+               list_del(&ref->list);
+               if (ref->count < 0)
+                       WARN_ON(1);
+               if (ref->count && ref->root_id && ref->parent == 0) {
+                       /* no parent == root of tree */
+                       ret = ulist_add(roots, ref->root_id, 0, GFP_NOFS);
+                       BUG_ON(ret < 0);
+               }
+               if (ref->count && ref->parent) {
+                       ret = ulist_add(refs, ref->parent, 0, GFP_NOFS);
+                       BUG_ON(ret < 0);
+               }
+               kfree(ref);
+       }
+
+out:
+       if (head)
+               mutex_unlock(&head->mutex);
+       btrfs_free_path(path);
+       while (!list_empty(&prefs)) {
+               ref = list_first_entry(&prefs, struct __prelim_ref, list);
+               list_del(&ref->list);
+               kfree(ref);
+       }
+       while (!list_empty(&prefs_delayed)) {
+               ref = list_first_entry(&prefs_delayed, struct __prelim_ref,
+                                      list);
+               list_del(&ref->list);
+               kfree(ref);
+       }
+
+       return ret;
+}
+
+/*
+ * Finds all leafs with a reference to the specified combination of bytenr and
+ * offset. key_list_head will point to a list of corresponding keys (caller must
+ * free each list element). The leafs will be stored in the leafs ulist, which
+ * must be freed with ulist_free.
+ *
+ * returns 0 on success, <0 on error
+ */
+static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
+                               struct btrfs_fs_info *fs_info, u64 bytenr,
+                               u64 num_bytes, u64 seq, struct ulist **leafs)
+{
+       struct ulist *tmp;
+       int ret;
+
+       tmp = ulist_alloc(GFP_NOFS);
+       if (!tmp)
+               return -ENOMEM;
+       *leafs = ulist_alloc(GFP_NOFS);
+       if (!*leafs) {
+               ulist_free(tmp);
+               return -ENOMEM;
+       }
+
+       ret = find_parent_nodes(trans, fs_info, bytenr, seq, *leafs, tmp);
+       ulist_free(tmp);
+
+       if (ret < 0 && ret != -ENOENT) {
+               ulist_free(*leafs);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * walk all backrefs for a given extent to find all roots that reference this
+ * extent. Walking a backref means finding all extents that reference this
+ * extent and in turn walk the backrefs of those, too. Naturally this is a
+ * recursive process, but here it is implemented in an iterative fashion: We
+ * find all referencing extents for the extent in question and put them on a
+ * list. In turn, we find all referencing extents for those, further appending
+ * to the list. The way we iterate the list allows adding more elements after
+ * the current while iterating. The process stops when we reach the end of the
+ * list. Found roots are added to the roots list.
+ *
+ * returns 0 on success, < 0 on error.
+ */
+int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
+                               struct btrfs_fs_info *fs_info, u64 bytenr,
+                               u64 num_bytes, u64 seq, struct ulist **roots)
+{
+       struct ulist *tmp;
+       struct ulist_node *node = NULL;
+       int ret;
+
+       tmp = ulist_alloc(GFP_NOFS);
+       if (!tmp)
+               return -ENOMEM;
+       *roots = ulist_alloc(GFP_NOFS);
+       if (!*roots) {
+               ulist_free(tmp);
+               return -ENOMEM;
+       }
+
+       while (1) {
+               ret = find_parent_nodes(trans, fs_info, bytenr, seq,
+                                       tmp, *roots);
+               if (ret < 0 && ret != -ENOENT) {
+                       ulist_free(tmp);
+                       ulist_free(*roots);
+                       return ret;
+               }
+               node = ulist_next(tmp, node);
+               if (!node)
+                       break;
+               bytenr = node->val;
+       }
+
+       ulist_free(tmp);
+       return 0;
+}
+
 
 static int __inode_info(u64 inum, u64 ioff, u8 key_type,
                        struct btrfs_root *fs_root, struct btrfs_path *path,
@@ -181,8 +952,11 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
        btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]);
        if (found_key->type != BTRFS_EXTENT_ITEM_KEY ||
            found_key->objectid > logical ||
-           found_key->objectid + found_key->offset <= logical)
+           found_key->objectid + found_key->offset <= logical) {
+               pr_debug("logical %llu is not within any extent\n",
+                        (unsigned long long)logical);
                return -ENOENT;
+       }
 
        eb = path->nodes[0];
        item_size = btrfs_item_size_nr(eb, path->slots[0]);
@@ -191,6 +965,13 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
        ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
        flags = btrfs_extent_flags(eb, ei);
 
+       pr_debug("logical %llu is at position %llu within the extent (%llu "
+                "EXTENT_ITEM %llu) flags %#llx size %u\n",
+                (unsigned long long)logical,
+                (unsigned long long)(logical - found_key->objectid),
+                (unsigned long long)found_key->objectid,
+                (unsigned long long)found_key->offset,
+                (unsigned long long)flags, item_size);
        if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)
                return BTRFS_EXTENT_FLAG_TREE_BLOCK;
        if (flags & BTRFS_EXTENT_FLAG_DATA)
@@ -287,128 +1068,11 @@ int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
        return 0;
 }
 
-static int __data_list_add(struct list_head *head, u64 inum,
-                               u64 extent_data_item_offset, u64 root)
-{
-       struct __data_ref *ref;
-
-       ref = kmalloc(sizeof(*ref), GFP_NOFS);
-       if (!ref)
-               return -ENOMEM;
-
-       ref->inum = inum;
-       ref->extent_data_item_offset = extent_data_item_offset;
-       ref->root = root;
-       list_add_tail(&ref->list, head);
-
-       return 0;
-}
-
-static int __data_list_add_eb(struct list_head *head, struct extent_buffer *eb,
-                               struct btrfs_extent_data_ref *dref)
-{
-       return __data_list_add(head, btrfs_extent_data_ref_objectid(eb, dref),
-                               btrfs_extent_data_ref_offset(eb, dref),
-                               btrfs_extent_data_ref_root(eb, dref));
-}
-
-static int __shared_list_add(struct list_head *head, u64 disk_byte)
-{
-       struct __shared_ref *ref;
-
-       ref = kmalloc(sizeof(*ref), GFP_NOFS);
-       if (!ref)
-               return -ENOMEM;
-
-       ref->disk_byte = disk_byte;
-       list_add_tail(&ref->list, head);
-
-       return 0;
-}
-
-static int __iter_shared_inline_ref_inodes(struct btrfs_fs_info *fs_info,
-                                          u64 logical, u64 inum,
-                                          u64 extent_data_item_offset,
-                                          u64 extent_offset,
-                                          struct btrfs_path *path,
-                                          struct list_head *data_refs,
-                                          iterate_extent_inodes_t *iterate,
-                                          void *ctx)
-{
-       u64 ref_root;
-       u32 item_size;
-       struct btrfs_key key;
-       struct extent_buffer *eb;
-       struct btrfs_extent_item *ei;
-       struct btrfs_extent_inline_ref *eiref;
-       struct __data_ref *ref;
-       int ret;
-       int type;
-       int last;
-       unsigned long ptr = 0;
-
-       WARN_ON(!list_empty(data_refs));
-       ret = extent_from_logical(fs_info, logical, path, &key);
-       if (ret & BTRFS_EXTENT_FLAG_DATA)
-               ret = -EIO;
-       if (ret < 0)
-               goto out;
-
-       eb = path->nodes[0];
-       ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
-       item_size = btrfs_item_size_nr(eb, path->slots[0]);
-
-       ret = 0;
-       ref_root = 0;
-       /*
-        * as done in iterate_extent_inodes, we first build a list of refs to
-        * iterate, then free the path and then iterate them to avoid deadlocks.
-        */
-       do {
-               last = __get_extent_inline_ref(&ptr, eb, ei, item_size,
-                                               &eiref, &type);
-               if (last < 0) {
-                       ret = last;
-                       goto out;
-               }
-               if (type == BTRFS_TREE_BLOCK_REF_KEY ||
-                   type == BTRFS_SHARED_BLOCK_REF_KEY) {
-                       ref_root = btrfs_extent_inline_ref_offset(eb, eiref);
-                       ret = __data_list_add(data_refs, inum,
-                                               extent_data_item_offset,
-                                               ref_root);
-               }
-       } while (!ret && !last);
-
-       btrfs_release_path(path);
-
-       if (ref_root == 0) {
-               printk(KERN_ERR "btrfs: failed to find tree block ref "
-                       "for shared data backref %llu\n", logical);
-               WARN_ON(1);
-               ret = -EIO;
-       }
-
-out:
-       while (!list_empty(data_refs)) {
-               ref = list_first_entry(data_refs, struct __data_ref, list);
-               list_del(&ref->list);
-               if (!ret)
-                       ret = iterate(ref->inum, extent_offset +
-                                       ref->extent_data_item_offset,
-                                       ref->root, ctx);
-               kfree(ref);
-       }
-
-       return ret;
-}
-
-static int __iter_shared_inline_ref(struct btrfs_fs_info *fs_info,
-                                   u64 logical, u64 orig_extent_item_objectid,
-                                   u64 extent_offset, struct btrfs_path *path,
-                                   struct list_head *data_refs,
-                                   iterate_extent_inodes_t *iterate,
-                                   void *ctx)
+static int iterate_leaf_refs(struct btrfs_fs_info *fs_info,
+                               struct btrfs_path *path, u64 logical,
+                               u64 orig_extent_item_objectid,
+                               u64 extent_item_pos, u64 root,
+                               iterate_extent_inodes_t *iterate, void *ctx)
 {
        u64 disk_byte;
        struct btrfs_key key;
@@ -416,8 +1080,10 @@ static int __iter_shared_inline_ref(struct btrfs_fs_info *fs_info,
        struct extent_buffer *eb;
        int slot;
        int nritems;
-       int ret;
-       int found = 0;
+       int ret = 0;
+       int extent_type;
+       u64 data_offset;
+       u64 data_len;
 
        eb = read_tree_block(fs_info->tree_root, logical,
                                fs_info->tree_root->leafsize, 0);
@@ -435,149 +1101,99 @@ static int __iter_shared_inline_ref(struct btrfs_fs_info *fs_info,
                if (key.type != BTRFS_EXTENT_DATA_KEY)
                        continue;
                fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
-               if (!fi) {
-                       free_extent_buffer(eb);
-                       return -EIO;
-               }
+               extent_type = btrfs_file_extent_type(eb, fi);
+               if (extent_type == BTRFS_FILE_EXTENT_INLINE)
+                       continue;
+               /* don't skip BTRFS_FILE_EXTENT_PREALLOC, we can handle that */
                disk_byte = btrfs_file_extent_disk_bytenr(eb, fi);
-               if (disk_byte != orig_extent_item_objectid) {
-                       if (found)
-                               break;
-                       else
-                               continue;
-               }
-               ++found;
-               ret = __iter_shared_inline_ref_inodes(fs_info, logical,
-                                                       key.objectid,
-                                                       key.offset,
-                                                       extent_offset, path,
-                                                       data_refs,
-                                                       iterate, ctx);
-               if (ret)
-                       break;
-       }
+               if (disk_byte != orig_extent_item_objectid)
+                       continue;
 
-       if (!found) {
-               printk(KERN_ERR "btrfs: failed to follow shared data backref "
-                       "to parent %llu\n", logical);
-               WARN_ON(1);
-               ret = -EIO;
+               data_offset = btrfs_file_extent_offset(eb, fi);
+               data_len = btrfs_file_extent_num_bytes(eb, fi);
+
+               if (extent_item_pos < data_offset ||
+                   extent_item_pos >= data_offset + data_len)
+                       continue;
+
+               pr_debug("ref for %llu resolved, key (%llu EXTEND_DATA %llu), "
+                               "root %llu\n", orig_extent_item_objectid,
+                               key.objectid, key.offset, root);
+               ret = iterate(key.objectid,
+                               key.offset + (extent_item_pos - data_offset),
+                               root, ctx);
+               if (ret) {
+                       pr_debug("stopping iteration because ret=%d\n", ret);
+                       break;
+               }
        }
 
        free_extent_buffer(eb);
+
        return ret;
 }
 
 /*
  * calls iterate() for every inode that references the extent identified by
- * the given parameters. will use the path given as a parameter and return it
- * released.
+ * the given parameters.
  * when the iterator function returns a non-zero value, iteration stops.
+ * path is guaranteed to be in released state when iterate() is called.
  */
 int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
                                struct btrfs_path *path,
-                               u64 extent_item_objectid,
-                               u64 extent_offset,
+                               u64 extent_item_objectid, u64 extent_item_pos,
                                iterate_extent_inodes_t *iterate, void *ctx)
 {
-       unsigned long ptr = 0;
-       int last;
        int ret;
-       int type;
-       u64 logical;
-       u32 item_size;
-       struct btrfs_extent_inline_ref *eiref;
-       struct btrfs_extent_data_ref *dref;
-       struct extent_buffer *eb;
-       struct btrfs_extent_item *ei;
-       struct btrfs_key key;
        struct list_head data_refs = LIST_HEAD_INIT(data_refs);
        struct list_head shared_refs = LIST_HEAD_INIT(shared_refs);
-       struct __data_ref *ref_d;
-       struct __shared_ref *ref_s;
-
-       eb = path->nodes[0];
-       ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
-       item_size = btrfs_item_size_nr(eb, path->slots[0]);
-
-       /* first we iterate the inline refs, ... */
-       do {
-               last = __get_extent_inline_ref(&ptr, eb, ei, item_size,
-                                               &eiref, &type);
-               if (last == -ENOENT) {
-                       ret = 0;
-                       break;
-               }
-               if (last < 0) {
-                       ret = last;
-                       break;
-               }
+       struct btrfs_trans_handle *trans;
+       struct ulist *refs;
+       struct ulist *roots;
+       struct ulist_node *ref_node = NULL;
+       struct ulist_node *root_node = NULL;
+       struct seq_list seq_elem;
+       struct btrfs_delayed_ref_root *delayed_refs;
+
+       trans = btrfs_join_transaction(fs_info->extent_root);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
+
+       pr_debug("resolving all inodes for extent %llu\n",
+                       extent_item_objectid);
+
+       delayed_refs = &trans->transaction->delayed_refs;
+       spin_lock(&delayed_refs->lock);
+       btrfs_get_delayed_seq(delayed_refs, &seq_elem);
+       spin_unlock(&delayed_refs->lock);
+
+       ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid,
+                                  extent_item_pos, seq_elem.seq,
+                                  &refs);
 
-               if (type == BTRFS_EXTENT_DATA_REF_KEY) {
-                       dref = (struct btrfs_extent_data_ref *)(&eiref->offset);
-                       ret = __data_list_add_eb(&data_refs, eb, dref);
-               } else if (type == BTRFS_SHARED_DATA_REF_KEY) {
-                       logical = btrfs_extent_inline_ref_offset(eb, eiref);
-                       ret = __shared_list_add(&shared_refs, logical);
-               }
-       } while (!ret && !last);
+       if (ret)
+               goto out;
 
-       /* ... then we proceed to in-tree references and ... */
-       while (!ret) {
-               ++path->slots[0];
-               if (path->slots[0] > btrfs_header_nritems(eb)) {
-                       ret = btrfs_next_leaf(fs_info->extent_root, path);
-                       if (ret) {
-                               if (ret == 1)
-                                       ret = 0; /* we're done */
-                               break;
-                       }
-                       eb = path->nodes[0];
-               }
-               btrfs_item_key_to_cpu(eb, &key, path->slots[0]);
-               if (key.objectid != extent_item_objectid)
+       while (!ret && (ref_node = ulist_next(refs, ref_node))) {
+               ret = btrfs_find_all_roots(trans, fs_info, ref_node->val, -1,
+                                               seq_elem.seq, &roots);
+               if (ret)
                        break;
-               if (key.type == BTRFS_EXTENT_DATA_REF_KEY) {
-                       dref = btrfs_item_ptr(eb, path->slots[0],
-                                               struct btrfs_extent_data_ref);
-                       ret = __data_list_add_eb(&data_refs, eb, dref);
-               } else if (key.type == BTRFS_SHARED_DATA_REF_KEY) {
-                       ret = __shared_list_add(&shared_refs, key.offset);
+               while (!ret && (root_node = ulist_next(roots, root_node))) {
+                       pr_debug("root %llu references leaf %llu\n",
+                                       root_node->val, ref_node->val);
+                       ret = iterate_leaf_refs(fs_info, path, ref_node->val,
+                                               extent_item_objectid,
+                                               extent_item_pos, root_node->val,
+                                               iterate, ctx);
                }
        }
 
-       btrfs_release_path(path);
-
-       /*
-        * ... only at the very end we can process the refs we found. this is
-        * because the iterator function we call is allowed to make tree lookups
-        * and we have to avoid deadlocks. additionally, we need more tree
-        * lookups ourselves for shared data refs.
-        */
-       while (!list_empty(&data_refs)) {
-               ref_d = list_first_entry(&data_refs, struct __data_ref, list);
-               list_del(&ref_d->list);
-               if (!ret)
-                       ret = iterate(ref_d->inum, extent_offset +
-                                       ref_d->extent_data_item_offset,
-                                       ref_d->root, ctx);
-               kfree(ref_d);
-       }
-
-       while (!list_empty(&shared_refs)) {
-               ref_s = list_first_entry(&shared_refs, struct __shared_ref,
-                                       list);
-               list_del(&ref_s->list);
-               if (!ret)
-                       ret = __iter_shared_inline_ref(fs_info,
-                                                       ref_s->disk_byte,
-                                                       extent_item_objectid,
-                                                       extent_offset, path,
-                                                       &data_refs,
-                                                       iterate, ctx);
-               kfree(ref_s);
-       }
-
+       ulist_free(refs);
+       ulist_free(roots);
+out:
+       btrfs_put_delayed_seq(delayed_refs, &seq_elem);
+       btrfs_end_transaction(trans, fs_info->extent_root);
        return ret;
 }
 
@@ -586,19 +1202,20 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
                                iterate_extent_inodes_t *iterate, void *ctx)
 {
        int ret;
-       u64 offset;
+       u64 extent_item_pos;
        struct btrfs_key found_key;
 
        ret = extent_from_logical(fs_info, logical, path,
                                        &found_key);
+       btrfs_release_path(path);
        if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK)
                ret = -EINVAL;
        if (ret < 0)
                return ret;
 
-       offset = logical - found_key.objectid;
+       extent_item_pos = logical - found_key.objectid;
        ret = iterate_extent_inodes(fs_info, path, found_key.objectid,
-                                       offset, iterate, ctx);
+                                       extent_item_pos, iterate, ctx);
 
        return ret;
 }
@@ -643,6 +1260,10 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root,
                for (cur = 0; cur < btrfs_item_size(eb, item); cur += len) {
                        name_len = btrfs_inode_ref_name_len(eb, iref);
                        /* path must be released before calling iterate()! */
+                       pr_debug("following ref at offset %u for inode %llu in "
+                                "tree %llu\n", cur,
+                                (unsigned long long)found_key.objectid,
+                                (unsigned long long)fs_root->objectid);
                        ret = iterate(parent, iref, eb, ctx);
                        if (ret) {
                                free_extent_buffer(eb);
@@ -683,10 +1304,14 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref,
                return PTR_ERR(fspath);
 
        if (fspath > fspath_min) {
+               pr_debug("path resolved: %s\n", fspath);
                ipath->fspath->val[i] = (u64)(unsigned long)fspath;
                ++ipath->fspath->elem_cnt;
                ipath->fspath->bytes_left = fspath - fspath_min;
        } else {
+               pr_debug("missed path, not enough space. missing bytes: %lu, "
+                        "constructed so far: %s\n",
+                        (unsigned long)(fspath_min - fspath), fspath_min);
                ++ipath->fspath->elem_missed;
                ipath->fspath->bytes_missing += fspath_min - fspath;
                ipath->fspath->bytes_left = 0;
index 92618837cb8f94a3a799ea3d08093d9b33aab336..d00dfa9ca9342c96f5057af09fb06418cd943cb6 100644 (file)
@@ -20,6 +20,7 @@
 #define __BTRFS_BACKREF__
 
 #include "ioctl.h"
+#include "ulist.h"
 
 struct inode_fs_paths {
        struct btrfs_path               *btrfs_path;
@@ -54,6 +55,10 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
 
 int paths_from_inode(u64 inum, struct inode_fs_paths *ipath);
 
+int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
+                               struct btrfs_fs_info *fs_info, u64 bytenr,
+                               u64 num_bytes, u64 seq, struct ulist **roots);
+
 struct btrfs_data_container *init_data_container(u32 total_bytes);
 struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
                                        struct btrfs_path *path);
index 634608d2a6d03b5d8741e573de0b142ff8cb6310..9b9b15fd5204347c5ef2931fb186af679cb0d369 100644 (file)
@@ -51,6 +51,9 @@ struct btrfs_inode {
        /* held while logging the inode in tree-log.c */
        struct mutex log_mutex;
 
+       /* held while doing delalloc reservations */
+       struct mutex delalloc_mutex;
+
        /* used to order data wrt metadata */
        struct btrfs_ordered_inode_tree ordered_tree;
 
diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c
new file mode 100644 (file)
index 0000000..ad0b3ba
--- /dev/null
@@ -0,0 +1,3068 @@
+/*
+ * Copyright (C) STRATO AG 2011.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+/*
+ * This module can be used to catch cases when the btrfs kernel
+ * code executes write requests to the disk that bring the file
+ * system in an inconsistent state. In such a state, a power-loss
+ * or kernel panic event would cause that the data on disk is
+ * lost or at least damaged.
+ *
+ * Code is added that examines all block write requests during
+ * runtime (including writes of the super block). Three rules
+ * are verified and an error is printed on violation of the
+ * rules:
+ * 1. It is not allowed to write a disk block which is
+ *    currently referenced by the super block (either directly
+ *    or indirectly).
+ * 2. When a super block is written, it is verified that all
+ *    referenced (directly or indirectly) blocks fulfill the
+ *    following requirements:
+ *    2a. All referenced blocks have either been present when
+ *        the file system was mounted, (i.e., they have been
+ *        referenced by the super block) or they have been
+ *        written since then and the write completion callback
+ *        was called and a FLUSH request to the device where
+ *        these blocks are located was received and completed.
+ *    2b. All referenced blocks need to have a generation
+ *        number which is equal to the parent's number.
+ *
+ * One issue that was found using this module was that the log
+ * tree on disk became temporarily corrupted because disk blocks
+ * that had been in use for the log tree had been freed and
+ * reused too early, while being referenced by the written super
+ * block.
+ *
+ * The search term in the kernel log that can be used to filter
+ * on the existence of detected integrity issues is
+ * "btrfs: attempt".
+ *
+ * The integrity check is enabled via mount options. These
+ * mount options are only supported if the integrity check
+ * tool is compiled by defining BTRFS_FS_CHECK_INTEGRITY.
+ *
+ * Example #1, apply integrity checks to all metadata:
+ * mount /dev/sdb1 /mnt -o check_int
+ *
+ * Example #2, apply integrity checks to all metadata and
+ * to data extents:
+ * mount /dev/sdb1 /mnt -o check_int_data
+ *
+ * Example #3, apply integrity checks to all metadata and dump
+ * the tree that the super block references to kernel messages
+ * each time after a super block was written:
+ * mount /dev/sdb1 /mnt -o check_int,check_int_print_mask=263
+ *
+ * If the integrity check tool is included and activated in
+ * the mount options, plenty of kernel memory is used, and
+ * plenty of additional CPU cycles are spent. Enabling this
+ * functionality is not intended for normal use. In most
+ * cases, unless you are a btrfs developer who needs to verify
+ * the integrity of (super)-block write requests, do not
+ * enable the config option BTRFS_FS_CHECK_INTEGRITY to
+ * include and compile the integrity check tool.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/buffer_head.h>
+#include <linux/mutex.h>
+#include <linux/crc32c.h>
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include "ctree.h"
+#include "disk-io.h"
+#include "transaction.h"
+#include "extent_io.h"
+#include "disk-io.h"
+#include "volumes.h"
+#include "print-tree.h"
+#include "locking.h"
+#include "check-integrity.h"
+
+#define BTRFSIC_BLOCK_HASHTABLE_SIZE 0x10000
+#define BTRFSIC_BLOCK_LINK_HASHTABLE_SIZE 0x10000
+#define BTRFSIC_DEV2STATE_HASHTABLE_SIZE 0x100
+#define BTRFSIC_BLOCK_MAGIC_NUMBER 0x14491051
+#define BTRFSIC_BLOCK_LINK_MAGIC_NUMBER 0x11070807
+#define BTRFSIC_DEV2STATE_MAGIC_NUMBER 0x20111530
+#define BTRFSIC_BLOCK_STACK_FRAME_MAGIC_NUMBER 20111300
+#define BTRFSIC_TREE_DUMP_MAX_INDENT_LEVEL (200 - 6)   /* in characters,
+                                                        * excluding " [...]" */
+#define BTRFSIC_BLOCK_SIZE PAGE_SIZE
+
+#define BTRFSIC_GENERATION_UNKNOWN ((u64)-1)
+
+/*
+ * The definition of the bitmask fields for the print_mask.
+ * They are specified with the mount option check_integrity_print_mask.
+ */
+#define BTRFSIC_PRINT_MASK_SUPERBLOCK_WRITE                    0x00000001
+#define BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION                0x00000002
+#define BTRFSIC_PRINT_MASK_TREE_AFTER_SB_WRITE                 0x00000004
+#define BTRFSIC_PRINT_MASK_TREE_BEFORE_SB_WRITE                        0x00000008
+#define BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH                       0x00000010
+#define BTRFSIC_PRINT_MASK_END_IO_BIO_BH                       0x00000020
+#define BTRFSIC_PRINT_MASK_VERBOSE                             0x00000040
+#define BTRFSIC_PRINT_MASK_VERY_VERBOSE                                0x00000080
+#define BTRFSIC_PRINT_MASK_INITIAL_TREE                                0x00000100
+#define BTRFSIC_PRINT_MASK_INITIAL_ALL_TREES                   0x00000200
+#define BTRFSIC_PRINT_MASK_INITIAL_DATABASE                    0x00000400
+#define BTRFSIC_PRINT_MASK_NUM_COPIES                          0x00000800
+#define BTRFSIC_PRINT_MASK_TREE_WITH_ALL_MIRRORS               0x00001000
+
+struct btrfsic_dev_state;
+struct btrfsic_state;
+
+struct btrfsic_block {
+       u32 magic_num;          /* only used for debug purposes */
+       unsigned int is_metadata:1;     /* if it is meta-data, not data-data */
+       unsigned int is_superblock:1;   /* if it is one of the superblocks */
+       unsigned int is_iodone:1;       /* if is done by lower subsystem */
+       unsigned int iodone_w_error:1;  /* error was indicated to endio */
+       unsigned int never_written:1;   /* block was added because it was
+                                        * referenced, not because it was
+                                        * written */
+       unsigned int mirror_num:2;      /* large enough to hold
+                                        * BTRFS_SUPER_MIRROR_MAX */
+       struct btrfsic_dev_state *dev_state;
+       u64 dev_bytenr;         /* key, physical byte num on disk */
+       u64 logical_bytenr;     /* logical byte num on disk */
+       u64 generation;
+       struct btrfs_disk_key disk_key; /* extra info to print in case of
+                                        * issues, will not always be correct */
+       struct list_head collision_resolving_node;      /* list node */
+       struct list_head all_blocks_node;       /* list node */
+
+       /* the following two lists contain block_link items */
+       struct list_head ref_to_list;   /* list */
+       struct list_head ref_from_list; /* list */
+       struct btrfsic_block *next_in_same_bio;
+       void *orig_bio_bh_private;
+       union {
+               bio_end_io_t *bio;
+               bh_end_io_t *bh;
+       } orig_bio_bh_end_io;
+       int submit_bio_bh_rw;
+       u64 flush_gen; /* only valid if !never_written */
+};
+
+/*
+ * Elements of this type are allocated dynamically and required because
+ * each block object can refer to and can be ref from multiple blocks.
+ * The key to lookup them in the hashtable is the dev_bytenr of
+ * the block ref to plus the one from the block refered from.
+ * The fact that they are searchable via a hashtable and that a
+ * ref_cnt is maintained is not required for the btrfs integrity
+ * check algorithm itself, it is only used to make the output more
+ * beautiful in case that an error is detected (an error is defined
+ * as a write operation to a block while that block is still referenced).
+ */
+struct btrfsic_block_link {
+       u32 magic_num;          /* only used for debug purposes */
+       u32 ref_cnt;
+       struct list_head node_ref_to;   /* list node */
+       struct list_head node_ref_from; /* list node */
+       struct list_head collision_resolving_node;      /* list node */
+       struct btrfsic_block *block_ref_to;
+       struct btrfsic_block *block_ref_from;
+       u64 parent_generation;
+};
+
+struct btrfsic_dev_state {
+       u32 magic_num;          /* only used for debug purposes */
+       struct block_device *bdev;
+       struct btrfsic_state *state;
+       struct list_head collision_resolving_node;      /* list node */
+       struct btrfsic_block dummy_block_for_bio_bh_flush;
+       u64 last_flush_gen;
+       char name[BDEVNAME_SIZE];
+};
+
+struct btrfsic_block_hashtable {
+       struct list_head table[BTRFSIC_BLOCK_HASHTABLE_SIZE];
+};
+
+struct btrfsic_block_link_hashtable {
+       struct list_head table[BTRFSIC_BLOCK_LINK_HASHTABLE_SIZE];
+};
+
+struct btrfsic_dev_state_hashtable {
+       struct list_head table[BTRFSIC_DEV2STATE_HASHTABLE_SIZE];
+};
+
+struct btrfsic_block_data_ctx {
+       u64 start;              /* virtual bytenr */
+       u64 dev_bytenr;         /* physical bytenr on device */
+       u32 len;
+       struct btrfsic_dev_state *dev;
+       char *data;
+       struct buffer_head *bh; /* do not use if set to NULL */
+};
+
+/* This structure is used to implement recursion without occupying
+ * any stack space, refer to btrfsic_process_metablock() */
+struct btrfsic_stack_frame {
+       u32 magic;
+       u32 nr;
+       int error;
+       int i;
+       int limit_nesting;
+       int num_copies;
+       int mirror_num;
+       struct btrfsic_block *block;
+       struct btrfsic_block_data_ctx *block_ctx;
+       struct btrfsic_block *next_block;
+       struct btrfsic_block_data_ctx next_block_ctx;
+       struct btrfs_header *hdr;
+       struct btrfsic_stack_frame *prev;
+};
+
+/* Some state per mounted filesystem */
+struct btrfsic_state {
+       u32 print_mask;
+       int include_extent_data;
+       int csum_size;
+       struct list_head all_blocks_list;
+       struct btrfsic_block_hashtable block_hashtable;
+       struct btrfsic_block_link_hashtable block_link_hashtable;
+       struct btrfs_root *root;
+       u64 max_superblock_generation;
+       struct btrfsic_block *latest_superblock;
+};
+
+static void btrfsic_block_init(struct btrfsic_block *b);
+static struct btrfsic_block *btrfsic_block_alloc(void);
+static void btrfsic_block_free(struct btrfsic_block *b);
+static void btrfsic_block_link_init(struct btrfsic_block_link *n);
+static struct btrfsic_block_link *btrfsic_block_link_alloc(void);
+static void btrfsic_block_link_free(struct btrfsic_block_link *n);
+static void btrfsic_dev_state_init(struct btrfsic_dev_state *ds);
+static struct btrfsic_dev_state *btrfsic_dev_state_alloc(void);
+static void btrfsic_dev_state_free(struct btrfsic_dev_state *ds);
+static void btrfsic_block_hashtable_init(struct btrfsic_block_hashtable *h);
+static void btrfsic_block_hashtable_add(struct btrfsic_block *b,
+                                       struct btrfsic_block_hashtable *h);
+static void btrfsic_block_hashtable_remove(struct btrfsic_block *b);
+static struct btrfsic_block *btrfsic_block_hashtable_lookup(
+               struct block_device *bdev,
+               u64 dev_bytenr,
+               struct btrfsic_block_hashtable *h);
+static void btrfsic_block_link_hashtable_init(
+               struct btrfsic_block_link_hashtable *h);
+static void btrfsic_block_link_hashtable_add(
+               struct btrfsic_block_link *l,
+               struct btrfsic_block_link_hashtable *h);
+static void btrfsic_block_link_hashtable_remove(struct btrfsic_block_link *l);
+static struct btrfsic_block_link *btrfsic_block_link_hashtable_lookup(
+               struct block_device *bdev_ref_to,
+               u64 dev_bytenr_ref_to,
+               struct block_device *bdev_ref_from,
+               u64 dev_bytenr_ref_from,
+               struct btrfsic_block_link_hashtable *h);
+static void btrfsic_dev_state_hashtable_init(
+               struct btrfsic_dev_state_hashtable *h);
+static void btrfsic_dev_state_hashtable_add(
+               struct btrfsic_dev_state *ds,
+               struct btrfsic_dev_state_hashtable *h);
+static void btrfsic_dev_state_hashtable_remove(struct btrfsic_dev_state *ds);
+static struct btrfsic_dev_state *btrfsic_dev_state_hashtable_lookup(
+               struct block_device *bdev,
+               struct btrfsic_dev_state_hashtable *h);
+static struct btrfsic_stack_frame *btrfsic_stack_frame_alloc(void);
+static void btrfsic_stack_frame_free(struct btrfsic_stack_frame *sf);
+static int btrfsic_process_superblock(struct btrfsic_state *state,
+                                     struct btrfs_fs_devices *fs_devices);
+static int btrfsic_process_metablock(struct btrfsic_state *state,
+                                    struct btrfsic_block *block,
+                                    struct btrfsic_block_data_ctx *block_ctx,
+                                    struct btrfs_header *hdr,
+                                    int limit_nesting, int force_iodone_flag);
+static int btrfsic_create_link_to_next_block(
+               struct btrfsic_state *state,
+               struct btrfsic_block *block,
+               struct btrfsic_block_data_ctx
+               *block_ctx, u64 next_bytenr,
+               int limit_nesting,
+               struct btrfsic_block_data_ctx *next_block_ctx,
+               struct btrfsic_block **next_blockp,
+               int force_iodone_flag,
+               int *num_copiesp, int *mirror_nump,
+               struct btrfs_disk_key *disk_key,
+               u64 parent_generation);
+static int btrfsic_handle_extent_data(struct btrfsic_state *state,
+                                     struct btrfsic_block *block,
+                                     struct btrfsic_block_data_ctx *block_ctx,
+                                     u32 item_offset, int force_iodone_flag);
+static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len,
+                            struct btrfsic_block_data_ctx *block_ctx_out,
+                            int mirror_num);
+static int btrfsic_map_superblock(struct btrfsic_state *state, u64 bytenr,
+                                 u32 len, struct block_device *bdev,
+                                 struct btrfsic_block_data_ctx *block_ctx_out);
+static void btrfsic_release_block_ctx(struct btrfsic_block_data_ctx *block_ctx);
+static int btrfsic_read_block(struct btrfsic_state *state,
+                             struct btrfsic_block_data_ctx *block_ctx);
+static void btrfsic_dump_database(struct btrfsic_state *state);
+static int btrfsic_test_for_metadata(struct btrfsic_state *state,
+                                    const u8 *data, unsigned int size);
+static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
+                                         u64 dev_bytenr, u8 *mapped_data,
+                                         unsigned int len, struct bio *bio,
+                                         int *bio_is_patched,
+                                         struct buffer_head *bh,
+                                         int submit_bio_bh_rw);
+static int btrfsic_process_written_superblock(
+               struct btrfsic_state *state,
+               struct btrfsic_block *const block,
+               struct btrfs_super_block *const super_hdr);
+static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status);
+static void btrfsic_bh_end_io(struct buffer_head *bh, int uptodate);
+static int btrfsic_is_block_ref_by_superblock(const struct btrfsic_state *state,
+                                             const struct btrfsic_block *block,
+                                             int recursion_level);
+static int btrfsic_check_all_ref_blocks(struct btrfsic_state *state,
+                                       struct btrfsic_block *const block,
+                                       int recursion_level);
+static void btrfsic_print_add_link(const struct btrfsic_state *state,
+                                  const struct btrfsic_block_link *l);
+static void btrfsic_print_rem_link(const struct btrfsic_state *state,
+                                  const struct btrfsic_block_link *l);
+static char btrfsic_get_block_type(const struct btrfsic_state *state,
+                                  const struct btrfsic_block *block);
+static void btrfsic_dump_tree(const struct btrfsic_state *state);
+static void btrfsic_dump_tree_sub(const struct btrfsic_state *state,
+                                 const struct btrfsic_block *block,
+                                 int indent_level);
+static struct btrfsic_block_link *btrfsic_block_link_lookup_or_add(
+               struct btrfsic_state *state,
+               struct btrfsic_block_data_ctx *next_block_ctx,
+               struct btrfsic_block *next_block,
+               struct btrfsic_block *from_block,
+               u64 parent_generation);
+static struct btrfsic_block *btrfsic_block_lookup_or_add(
+               struct btrfsic_state *state,
+               struct btrfsic_block_data_ctx *block_ctx,
+               const char *additional_string,
+               int is_metadata,
+               int is_iodone,
+               int never_written,
+               int mirror_num,
+               int *was_created);
+static int btrfsic_process_superblock_dev_mirror(
+               struct btrfsic_state *state,
+               struct btrfsic_dev_state *dev_state,
+               struct btrfs_device *device,
+               int superblock_mirror_num,
+               struct btrfsic_dev_state **selected_dev_state,
+               struct btrfs_super_block *selected_super);
+static struct btrfsic_dev_state *btrfsic_dev_state_lookup(
+               struct block_device *bdev);
+static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
+                                          u64 bytenr,
+                                          struct btrfsic_dev_state *dev_state,
+                                          u64 dev_bytenr, char *data);
+
+static struct mutex btrfsic_mutex;
+static int btrfsic_is_initialized;
+static struct btrfsic_dev_state_hashtable btrfsic_dev_state_hashtable;
+
+
+static void btrfsic_block_init(struct btrfsic_block *b)
+{
+       b->magic_num = BTRFSIC_BLOCK_MAGIC_NUMBER;
+       b->dev_state = NULL;
+       b->dev_bytenr = 0;
+       b->logical_bytenr = 0;
+       b->generation = BTRFSIC_GENERATION_UNKNOWN;
+       b->disk_key.objectid = 0;
+       b->disk_key.type = 0;
+       b->disk_key.offset = 0;
+       b->is_metadata = 0;
+       b->is_superblock = 0;
+       b->is_iodone = 0;
+       b->iodone_w_error = 0;
+       b->never_written = 0;
+       b->mirror_num = 0;
+       b->next_in_same_bio = NULL;
+       b->orig_bio_bh_private = NULL;
+       b->orig_bio_bh_end_io.bio = NULL;
+       INIT_LIST_HEAD(&b->collision_resolving_node);
+       INIT_LIST_HEAD(&b->all_blocks_node);
+       INIT_LIST_HEAD(&b->ref_to_list);
+       INIT_LIST_HEAD(&b->ref_from_list);
+       b->submit_bio_bh_rw = 0;
+       b->flush_gen = 0;
+}
+
+static struct btrfsic_block *btrfsic_block_alloc(void)
+{
+       struct btrfsic_block *b;
+
+       b = kzalloc(sizeof(*b), GFP_NOFS);
+       if (NULL != b)
+               btrfsic_block_init(b);
+
+       return b;
+}
+
+static void btrfsic_block_free(struct btrfsic_block *b)
+{
+       BUG_ON(!(NULL == b || BTRFSIC_BLOCK_MAGIC_NUMBER == b->magic_num));
+       kfree(b);
+}
+
+static void btrfsic_block_link_init(struct btrfsic_block_link *l)
+{
+       l->magic_num = BTRFSIC_BLOCK_LINK_MAGIC_NUMBER;
+       l->ref_cnt = 1;
+       INIT_LIST_HEAD(&l->node_ref_to);
+       INIT_LIST_HEAD(&l->node_ref_from);
+       INIT_LIST_HEAD(&l->collision_resolving_node);
+       l->block_ref_to = NULL;
+       l->block_ref_from = NULL;
+}
+
+static struct btrfsic_block_link *btrfsic_block_link_alloc(void)
+{
+       struct btrfsic_block_link *l;
+
+       l = kzalloc(sizeof(*l), GFP_NOFS);
+       if (NULL != l)
+               btrfsic_block_link_init(l);
+
+       return l;
+}
+
+static void btrfsic_block_link_free(struct btrfsic_block_link *l)
+{
+       BUG_ON(!(NULL == l || BTRFSIC_BLOCK_LINK_MAGIC_NUMBER == l->magic_num));
+       kfree(l);
+}
+
+static void btrfsic_dev_state_init(struct btrfsic_dev_state *ds)
+{
+       ds->magic_num = BTRFSIC_DEV2STATE_MAGIC_NUMBER;
+       ds->bdev = NULL;
+       ds->state = NULL;
+       ds->name[0] = '\0';
+       INIT_LIST_HEAD(&ds->collision_resolving_node);
+       ds->last_flush_gen = 0;
+       btrfsic_block_init(&ds->dummy_block_for_bio_bh_flush);
+       ds->dummy_block_for_bio_bh_flush.is_iodone = 1;
+       ds->dummy_block_for_bio_bh_flush.dev_state = ds;
+}
+
+static struct btrfsic_dev_state *btrfsic_dev_state_alloc(void)
+{
+       struct btrfsic_dev_state *ds;
+
+       ds = kzalloc(sizeof(*ds), GFP_NOFS);
+       if (NULL != ds)
+               btrfsic_dev_state_init(ds);
+
+       return ds;
+}
+
+static void btrfsic_dev_state_free(struct btrfsic_dev_state *ds)
+{
+       BUG_ON(!(NULL == ds ||
+                BTRFSIC_DEV2STATE_MAGIC_NUMBER == ds->magic_num));
+       kfree(ds);
+}
+
+static void btrfsic_block_hashtable_init(struct btrfsic_block_hashtable *h)
+{
+       int i;
+
+       for (i = 0; i < BTRFSIC_BLOCK_HASHTABLE_SIZE; i++)
+               INIT_LIST_HEAD(h->table + i);
+}
+
+static void btrfsic_block_hashtable_add(struct btrfsic_block *b,
+                                       struct btrfsic_block_hashtable *h)
+{
+       const unsigned int hashval =
+           (((unsigned int)(b->dev_bytenr >> 16)) ^
+            ((unsigned int)((uintptr_t)b->dev_state->bdev))) &
+            (BTRFSIC_BLOCK_HASHTABLE_SIZE - 1);
+
+       list_add(&b->collision_resolving_node, h->table + hashval);
+}
+
+static void btrfsic_block_hashtable_remove(struct btrfsic_block *b)
+{
+       list_del(&b->collision_resolving_node);
+}
+
+static struct btrfsic_block *btrfsic_block_hashtable_lookup(
+               struct block_device *bdev,
+               u64 dev_bytenr,
+               struct btrfsic_block_hashtable *h)
+{
+       const unsigned int hashval =
+           (((unsigned int)(dev_bytenr >> 16)) ^
+            ((unsigned int)((uintptr_t)bdev))) &
+            (BTRFSIC_BLOCK_HASHTABLE_SIZE - 1);
+       struct list_head *elem;
+
+       list_for_each(elem, h->table + hashval) {
+               struct btrfsic_block *const b =
+                   list_entry(elem, struct btrfsic_block,
+                              collision_resolving_node);
+
+               if (b->dev_state->bdev == bdev && b->dev_bytenr == dev_bytenr)
+                       return b;
+       }
+
+       return NULL;
+}
+
+static void btrfsic_block_link_hashtable_init(
+               struct btrfsic_block_link_hashtable *h)
+{
+       int i;
+
+       for (i = 0; i < BTRFSIC_BLOCK_LINK_HASHTABLE_SIZE; i++)
+               INIT_LIST_HEAD(h->table + i);
+}
+
+static void btrfsic_block_link_hashtable_add(
+               struct btrfsic_block_link *l,
+               struct btrfsic_block_link_hashtable *h)
+{
+       const unsigned int hashval =
+           (((unsigned int)(l->block_ref_to->dev_bytenr >> 16)) ^
+            ((unsigned int)(l->block_ref_from->dev_bytenr >> 16)) ^
+            ((unsigned int)((uintptr_t)l->block_ref_to->dev_state->bdev)) ^
+            ((unsigned int)((uintptr_t)l->block_ref_from->dev_state->bdev)))
+            & (BTRFSIC_BLOCK_LINK_HASHTABLE_SIZE - 1);
+
+       BUG_ON(NULL == l->block_ref_to);
+       BUG_ON(NULL == l->block_ref_from);
+       list_add(&l->collision_resolving_node, h->table + hashval);
+}
+
+static void btrfsic_block_link_hashtable_remove(struct btrfsic_block_link *l)
+{
+       list_del(&l->collision_resolving_node);
+}
+
+static struct btrfsic_block_link *btrfsic_block_link_hashtable_lookup(
+               struct block_device *bdev_ref_to,
+               u64 dev_bytenr_ref_to,
+               struct block_device *bdev_ref_from,
+               u64 dev_bytenr_ref_from,
+               struct btrfsic_block_link_hashtable *h)
+{
+       const unsigned int hashval =
+           (((unsigned int)(dev_bytenr_ref_to >> 16)) ^
+            ((unsigned int)(dev_bytenr_ref_from >> 16)) ^
+            ((unsigned int)((uintptr_t)bdev_ref_to)) ^
+            ((unsigned int)((uintptr_t)bdev_ref_from))) &
+            (BTRFSIC_BLOCK_LINK_HASHTABLE_SIZE - 1);
+       struct list_head *elem;
+
+       list_for_each(elem, h->table + hashval) {
+               struct btrfsic_block_link *const l =
+                   list_entry(elem, struct btrfsic_block_link,
+                              collision_resolving_node);
+
+               BUG_ON(NULL == l->block_ref_to);
+               BUG_ON(NULL == l->block_ref_from);
+               if (l->block_ref_to->dev_state->bdev == bdev_ref_to &&
+                   l->block_ref_to->dev_bytenr == dev_bytenr_ref_to &&
+                   l->block_ref_from->dev_state->bdev == bdev_ref_from &&
+                   l->block_ref_from->dev_bytenr == dev_bytenr_ref_from)
+                       return l;
+       }
+
+       return NULL;
+}
+
+static void btrfsic_dev_state_hashtable_init(
+               struct btrfsic_dev_state_hashtable *h)
+{
+       int i;
+
+       for (i = 0; i < BTRFSIC_DEV2STATE_HASHTABLE_SIZE; i++)
+               INIT_LIST_HEAD(h->table + i);
+}
+
+static void btrfsic_dev_state_hashtable_add(
+               struct btrfsic_dev_state *ds,
+               struct btrfsic_dev_state_hashtable *h)
+{
+       const unsigned int hashval =
+           (((unsigned int)((uintptr_t)ds->bdev)) &
+            (BTRFSIC_DEV2STATE_HASHTABLE_SIZE - 1));
+
+       list_add(&ds->collision_resolving_node, h->table + hashval);
+}
+
+static void btrfsic_dev_state_hashtable_remove(struct btrfsic_dev_state *ds)
+{
+       list_del(&ds->collision_resolving_node);
+}
+
+static struct btrfsic_dev_state *btrfsic_dev_state_hashtable_lookup(
+               struct block_device *bdev,
+               struct btrfsic_dev_state_hashtable *h)
+{
+       const unsigned int hashval =
+           (((unsigned int)((uintptr_t)bdev)) &
+            (BTRFSIC_DEV2STATE_HASHTABLE_SIZE - 1));
+       struct list_head *elem;
+
+       list_for_each(elem, h->table + hashval) {
+               struct btrfsic_dev_state *const ds =
+                   list_entry(elem, struct btrfsic_dev_state,
+                              collision_resolving_node);
+
+               if (ds->bdev == bdev)
+                       return ds;
+       }
+
+       return NULL;
+}
+
+static int btrfsic_process_superblock(struct btrfsic_state *state,
+                                     struct btrfs_fs_devices *fs_devices)
+{
+       int ret;
+       struct btrfs_super_block *selected_super;
+       struct list_head *dev_head = &fs_devices->devices;
+       struct btrfs_device *device;
+       struct btrfsic_dev_state *selected_dev_state = NULL;
+       int pass;
+
+       BUG_ON(NULL == state);
+       selected_super = kmalloc(sizeof(*selected_super), GFP_NOFS);
+       if (NULL == selected_super) {
+               printk(KERN_INFO "btrfsic: error, kmalloc failed!\n");
+               return -1;
+       }
+
+       list_for_each_entry(device, dev_head, dev_list) {
+               int i;
+               struct btrfsic_dev_state *dev_state;
+
+               if (!device->bdev || !device->name)
+                       continue;
+
+               dev_state = btrfsic_dev_state_lookup(device->bdev);
+               BUG_ON(NULL == dev_state);
+               for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
+                       ret = btrfsic_process_superblock_dev_mirror(
+                                       state, dev_state, device, i,
+                                       &selected_dev_state, selected_super);
+                       if (0 != ret && 0 == i) {
+                               kfree(selected_super);
+                               return ret;
+                       }
+               }
+       }
+
+       if (NULL == state->latest_superblock) {
+               printk(KERN_INFO "btrfsic: no superblock found!\n");
+               kfree(selected_super);
+               return -1;
+       }
+
+       state->csum_size = btrfs_super_csum_size(selected_super);
+
+       for (pass = 0; pass < 3; pass++) {
+               int num_copies;
+               int mirror_num;
+               u64 next_bytenr;
+
+               switch (pass) {
+               case 0:
+                       next_bytenr = btrfs_super_root(selected_super);
+                       if (state->print_mask &
+                           BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION)
+                               printk(KERN_INFO "root@%llu\n",
+                                      (unsigned long long)next_bytenr);
+                       break;
+               case 1:
+                       next_bytenr = btrfs_super_chunk_root(selected_super);
+                       if (state->print_mask &
+                           BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION)
+                               printk(KERN_INFO "chunk@%llu\n",
+                                      (unsigned long long)next_bytenr);
+                       break;
+               case 2:
+                       next_bytenr = btrfs_super_log_root(selected_super);
+                       if (0 == next_bytenr)
+                               continue;
+                       if (state->print_mask &
+                           BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION)
+                               printk(KERN_INFO "log@%llu\n",
+                                      (unsigned long long)next_bytenr);
+                       break;
+               }
+
+               num_copies =
+                   btrfs_num_copies(&state->root->fs_info->mapping_tree,
+                                    next_bytenr, PAGE_SIZE);
+               if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
+                       printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
+                              (unsigned long long)next_bytenr, num_copies);
+
+               for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
+                       struct btrfsic_block *next_block;
+                       struct btrfsic_block_data_ctx tmp_next_block_ctx;
+                       struct btrfsic_block_link *l;
+                       struct btrfs_header *hdr;
+
+                       ret = btrfsic_map_block(state, next_bytenr, PAGE_SIZE,
+                                               &tmp_next_block_ctx,
+                                               mirror_num);
+                       if (ret) {
+                               printk(KERN_INFO "btrfsic:"
+                                      " btrfsic_map_block(root @%llu,"
+                                      " mirror %d) failed!\n",
+                                      (unsigned long long)next_bytenr,
+                                      mirror_num);
+                               kfree(selected_super);
+                               return -1;
+                       }
+
+                       next_block = btrfsic_block_hashtable_lookup(
+                                       tmp_next_block_ctx.dev->bdev,
+                                       tmp_next_block_ctx.dev_bytenr,
+                                       &state->block_hashtable);
+                       BUG_ON(NULL == next_block);
+
+                       l = btrfsic_block_link_hashtable_lookup(
+                                       tmp_next_block_ctx.dev->bdev,
+                                       tmp_next_block_ctx.dev_bytenr,
+                                       state->latest_superblock->dev_state->
+                                       bdev,
+                                       state->latest_superblock->dev_bytenr,
+                                       &state->block_link_hashtable);
+                       BUG_ON(NULL == l);
+
+                       ret = btrfsic_read_block(state, &tmp_next_block_ctx);
+                       if (ret < (int)BTRFSIC_BLOCK_SIZE) {
+                               printk(KERN_INFO
+                                      "btrfsic: read @logical %llu failed!\n",
+                                      (unsigned long long)
+                                      tmp_next_block_ctx.start);
+                               btrfsic_release_block_ctx(&tmp_next_block_ctx);
+                               kfree(selected_super);
+                               return -1;
+                       }
+
+                       hdr = (struct btrfs_header *)tmp_next_block_ctx.data;
+                       ret = btrfsic_process_metablock(state,
+                                                       next_block,
+                                                       &tmp_next_block_ctx,
+                                                       hdr,
+                                                       BTRFS_MAX_LEVEL + 3, 1);
+                       btrfsic_release_block_ctx(&tmp_next_block_ctx);
+               }
+       }
+
+       kfree(selected_super);
+       return ret;
+}
+
+static int btrfsic_process_superblock_dev_mirror(
+               struct btrfsic_state *state,
+               struct btrfsic_dev_state *dev_state,
+               struct btrfs_device *device,
+               int superblock_mirror_num,
+               struct btrfsic_dev_state **selected_dev_state,
+               struct btrfs_super_block *selected_super)
+{
+       struct btrfs_super_block *super_tmp;
+       u64 dev_bytenr;
+       struct buffer_head *bh;
+       struct btrfsic_block *superblock_tmp;
+       int pass;
+       struct block_device *const superblock_bdev = device->bdev;
+
+       /* super block bytenr is always the unmapped device bytenr */
+       dev_bytenr = btrfs_sb_offset(superblock_mirror_num);
+       bh = __bread(superblock_bdev, dev_bytenr / 4096, 4096);
+       if (NULL == bh)
+               return -1;
+       super_tmp = (struct btrfs_super_block *)
+           (bh->b_data + (dev_bytenr & 4095));
+
+       if (btrfs_super_bytenr(super_tmp) != dev_bytenr ||
+           strncmp((char *)(&(super_tmp->magic)), BTRFS_MAGIC,
+                   sizeof(super_tmp->magic)) ||
+           memcmp(device->uuid, super_tmp->dev_item.uuid, BTRFS_UUID_SIZE)) {
+               brelse(bh);
+               return 0;
+       }
+
+       superblock_tmp =
+           btrfsic_block_hashtable_lookup(superblock_bdev,
+                                          dev_bytenr,
+                                          &state->block_hashtable);
+       if (NULL == superblock_tmp) {
+               superblock_tmp = btrfsic_block_alloc();
+               if (NULL == superblock_tmp) {
+                       printk(KERN_INFO "btrfsic: error, kmalloc failed!\n");
+                       brelse(bh);
+                       return -1;
+               }
+               /* for superblock, only the dev_bytenr makes sense */
+               superblock_tmp->dev_bytenr = dev_bytenr;
+               superblock_tmp->dev_state = dev_state;
+               superblock_tmp->logical_bytenr = dev_bytenr;
+               superblock_tmp->generation = btrfs_super_generation(super_tmp);
+               superblock_tmp->is_metadata = 1;
+               superblock_tmp->is_superblock = 1;
+               superblock_tmp->is_iodone = 1;
+               superblock_tmp->never_written = 0;
+               superblock_tmp->mirror_num = 1 + superblock_mirror_num;
+               if (state->print_mask & BTRFSIC_PRINT_MASK_SUPERBLOCK_WRITE)
+                       printk(KERN_INFO "New initial S-block (bdev %p, %s)"
+                              " @%llu (%s/%llu/%d)\n",
+                              superblock_bdev, device->name,
+                              (unsigned long long)dev_bytenr,
+                              dev_state->name,
+                              (unsigned long long)dev_bytenr,
+                              superblock_mirror_num);
+               list_add(&superblock_tmp->all_blocks_node,
+                        &state->all_blocks_list);
+               btrfsic_block_hashtable_add(superblock_tmp,
+                                           &state->block_hashtable);
+       }
+
+       /* select the one with the highest generation field */
+       if (btrfs_super_generation(super_tmp) >
+           state->max_superblock_generation ||
+           0 == state->max_superblock_generation) {
+               memcpy(selected_super, super_tmp, sizeof(*selected_super));
+               *selected_dev_state = dev_state;
+               state->max_superblock_generation =
+                   btrfs_super_generation(super_tmp);
+               state->latest_superblock = superblock_tmp;
+       }
+
+       for (pass = 0; pass < 3; pass++) {
+               u64 next_bytenr;
+               int num_copies;
+               int mirror_num;
+               const char *additional_string = NULL;
+               struct btrfs_disk_key tmp_disk_key;
+
+               tmp_disk_key.type = BTRFS_ROOT_ITEM_KEY;
+               tmp_disk_key.offset = 0;
+               switch (pass) {
+               case 0:
+                       tmp_disk_key.objectid =
+                           cpu_to_le64(BTRFS_ROOT_TREE_OBJECTID);
+                       additional_string = "initial root ";
+                       next_bytenr = btrfs_super_root(super_tmp);
+                       break;
+               case 1:
+                       tmp_disk_key.objectid =
+                           cpu_to_le64(BTRFS_CHUNK_TREE_OBJECTID);
+                       additional_string = "initial chunk ";
+                       next_bytenr = btrfs_super_chunk_root(super_tmp);
+                       break;
+               case 2:
+                       tmp_disk_key.objectid =
+                           cpu_to_le64(BTRFS_TREE_LOG_OBJECTID);
+                       additional_string = "initial log ";
+                       next_bytenr = btrfs_super_log_root(super_tmp);
+                       if (0 == next_bytenr)
+                               continue;
+                       break;
+               }
+
+               num_copies =
+                   btrfs_num_copies(&state->root->fs_info->mapping_tree,
+                                    next_bytenr, PAGE_SIZE);
+               if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
+                       printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
+                              (unsigned long long)next_bytenr, num_copies);
+               for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
+                       struct btrfsic_block *next_block;
+                       struct btrfsic_block_data_ctx tmp_next_block_ctx;
+                       struct btrfsic_block_link *l;
+
+                       if (btrfsic_map_block(state, next_bytenr, PAGE_SIZE,
+                                             &tmp_next_block_ctx,
+                                             mirror_num)) {
+                               printk(KERN_INFO "btrfsic: btrfsic_map_block("
+                                      "bytenr @%llu, mirror %d) failed!\n",
+                                      (unsigned long long)next_bytenr,
+                                      mirror_num);
+                               brelse(bh);
+                               return -1;
+                       }
+
+                       next_block = btrfsic_block_lookup_or_add(
+                                       state, &tmp_next_block_ctx,
+                                       additional_string, 1, 1, 0,
+                                       mirror_num, NULL);
+                       if (NULL == next_block) {
+                               btrfsic_release_block_ctx(&tmp_next_block_ctx);
+                               brelse(bh);
+                               return -1;
+                       }
+
+                       next_block->disk_key = tmp_disk_key;
+                       next_block->generation = BTRFSIC_GENERATION_UNKNOWN;
+                       l = btrfsic_block_link_lookup_or_add(
+                                       state, &tmp_next_block_ctx,
+                                       next_block, superblock_tmp,
+                                       BTRFSIC_GENERATION_UNKNOWN);
+                       btrfsic_release_block_ctx(&tmp_next_block_ctx);
+                       if (NULL == l) {
+                               brelse(bh);
+                               return -1;
+                       }
+               }
+       }
+       if (state->print_mask & BTRFSIC_PRINT_MASK_INITIAL_ALL_TREES)
+               btrfsic_dump_tree_sub(state, superblock_tmp, 0);
+
+       brelse(bh);
+       return 0;
+}
+
+static struct btrfsic_stack_frame *btrfsic_stack_frame_alloc(void)
+{
+       struct btrfsic_stack_frame *sf;
+
+       sf = kzalloc(sizeof(*sf), GFP_NOFS);
+       if (NULL == sf)
+               printk(KERN_INFO "btrfsic: alloc memory failed!\n");
+       else
+               sf->magic = BTRFSIC_BLOCK_STACK_FRAME_MAGIC_NUMBER;
+       return sf;
+}
+
+static void btrfsic_stack_frame_free(struct btrfsic_stack_frame *sf)
+{
+       BUG_ON(!(NULL == sf ||
+                BTRFSIC_BLOCK_STACK_FRAME_MAGIC_NUMBER == sf->magic));
+       kfree(sf);
+}
+
+static int btrfsic_process_metablock(
+               struct btrfsic_state *state,
+               struct btrfsic_block *const first_block,
+               struct btrfsic_block_data_ctx *const first_block_ctx,
+               struct btrfs_header *const first_hdr,
+               int first_limit_nesting, int force_iodone_flag)
+{
+       struct btrfsic_stack_frame initial_stack_frame = { 0 };
+       struct btrfsic_stack_frame *sf;
+       struct btrfsic_stack_frame *next_stack;
+
+       sf = &initial_stack_frame;
+       sf->error = 0;
+       sf->i = -1;
+       sf->limit_nesting = first_limit_nesting;
+       sf->block = first_block;
+       sf->block_ctx = first_block_ctx;
+       sf->next_block = NULL;
+       sf->hdr = first_hdr;
+       sf->prev = NULL;
+
+continue_with_new_stack_frame:
+       sf->block->generation = le64_to_cpu(sf->hdr->generation);
+       if (0 == sf->hdr->level) {
+               struct btrfs_leaf *const leafhdr =
+                   (struct btrfs_leaf *)sf->hdr;
+
+               if (-1 == sf->i) {
+                       sf->nr = le32_to_cpu(leafhdr->header.nritems);
+
+                       if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                               printk(KERN_INFO
+                                      "leaf %llu items %d generation %llu"
+                                      " owner %llu\n",
+                                      (unsigned long long)
+                                      sf->block_ctx->start,
+                                      sf->nr,
+                                      (unsigned long long)
+                                      le64_to_cpu(leafhdr->header.generation),
+                                      (unsigned long long)
+                                      le64_to_cpu(leafhdr->header.owner));
+               }
+
+continue_with_current_leaf_stack_frame:
+               if (0 == sf->num_copies || sf->mirror_num > sf->num_copies) {
+                       sf->i++;
+                       sf->num_copies = 0;
+               }
+
+               if (sf->i < sf->nr) {
+                       struct btrfs_item *disk_item = leafhdr->items + sf->i;
+                       struct btrfs_disk_key *disk_key = &disk_item->key;
+                       u8 type;
+                       const u32 item_offset = le32_to_cpu(disk_item->offset);
+
+                       type = disk_key->type;
+
+                       if (BTRFS_ROOT_ITEM_KEY == type) {
+                               const struct btrfs_root_item *const root_item =
+                                   (struct btrfs_root_item *)
+                                   (sf->block_ctx->data +
+                                    offsetof(struct btrfs_leaf, items) +
+                                    item_offset);
+                               const u64 next_bytenr =
+                                   le64_to_cpu(root_item->bytenr);
+
+                               sf->error =
+                                   btrfsic_create_link_to_next_block(
+                                               state,
+                                               sf->block,
+                                               sf->block_ctx,
+                                               next_bytenr,
+                                               sf->limit_nesting,
+                                               &sf->next_block_ctx,
+                                               &sf->next_block,
+                                               force_iodone_flag,
+                                               &sf->num_copies,
+                                               &sf->mirror_num,
+                                               disk_key,
+                                               le64_to_cpu(root_item->
+                                               generation));
+                               if (sf->error)
+                                       goto one_stack_frame_backwards;
+
+                               if (NULL != sf->next_block) {
+                                       struct btrfs_header *const next_hdr =
+                                           (struct btrfs_header *)
+                                           sf->next_block_ctx.data;
+
+                                       next_stack =
+                                           btrfsic_stack_frame_alloc();
+                                       if (NULL == next_stack) {
+                                               btrfsic_release_block_ctx(
+                                                               &sf->
+                                                               next_block_ctx);
+                                               goto one_stack_frame_backwards;
+                                       }
+
+                                       next_stack->i = -1;
+                                       next_stack->block = sf->next_block;
+                                       next_stack->block_ctx =
+                                           &sf->next_block_ctx;
+                                       next_stack->next_block = NULL;
+                                       next_stack->hdr = next_hdr;
+                                       next_stack->limit_nesting =
+                                           sf->limit_nesting - 1;
+                                       next_stack->prev = sf;
+                                       sf = next_stack;
+                                       goto continue_with_new_stack_frame;
+                               }
+                       } else if (BTRFS_EXTENT_DATA_KEY == type &&
+                                  state->include_extent_data) {
+                               sf->error = btrfsic_handle_extent_data(
+                                               state,
+                                               sf->block,
+                                               sf->block_ctx,
+                                               item_offset,
+                                               force_iodone_flag);
+                               if (sf->error)
+                                       goto one_stack_frame_backwards;
+                       }
+
+                       goto continue_with_current_leaf_stack_frame;
+               }
+       } else {
+               struct btrfs_node *const nodehdr = (struct btrfs_node *)sf->hdr;
+
+               if (-1 == sf->i) {
+                       sf->nr = le32_to_cpu(nodehdr->header.nritems);
+
+                       if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                               printk(KERN_INFO "node %llu level %d items %d"
+                                      " generation %llu owner %llu\n",
+                                      (unsigned long long)
+                                      sf->block_ctx->start,
+                                      nodehdr->header.level, sf->nr,
+                                      (unsigned long long)
+                                      le64_to_cpu(nodehdr->header.generation),
+                                      (unsigned long long)
+                                      le64_to_cpu(nodehdr->header.owner));
+               }
+
+continue_with_current_node_stack_frame:
+               if (0 == sf->num_copies || sf->mirror_num > sf->num_copies) {
+                       sf->i++;
+                       sf->num_copies = 0;
+               }
+
+               if (sf->i < sf->nr) {
+                       struct btrfs_key_ptr *disk_key_ptr =
+                           nodehdr->ptrs + sf->i;
+                       const u64 next_bytenr =
+                           le64_to_cpu(disk_key_ptr->blockptr);
+
+                       sf->error = btrfsic_create_link_to_next_block(
+                                       state,
+                                       sf->block,
+                                       sf->block_ctx,
+                                       next_bytenr,
+                                       sf->limit_nesting,
+                                       &sf->next_block_ctx,
+                                       &sf->next_block,
+                                       force_iodone_flag,
+                                       &sf->num_copies,
+                                       &sf->mirror_num,
+                                       &disk_key_ptr->key,
+                                       le64_to_cpu(disk_key_ptr->generation));
+                       if (sf->error)
+                               goto one_stack_frame_backwards;
+
+                       if (NULL != sf->next_block) {
+                               struct btrfs_header *const next_hdr =
+                                   (struct btrfs_header *)
+                                   sf->next_block_ctx.data;
+
+                               next_stack = btrfsic_stack_frame_alloc();
+                               if (NULL == next_stack)
+                                       goto one_stack_frame_backwards;
+
+                               next_stack->i = -1;
+                               next_stack->block = sf->next_block;
+                               next_stack->block_ctx = &sf->next_block_ctx;
+                               next_stack->next_block = NULL;
+                               next_stack->hdr = next_hdr;
+                               next_stack->limit_nesting =
+                                   sf->limit_nesting - 1;
+                               next_stack->prev = sf;
+                               sf = next_stack;
+                               goto continue_with_new_stack_frame;
+                       }
+
+                       goto continue_with_current_node_stack_frame;
+               }
+       }
+
+one_stack_frame_backwards:
+       if (NULL != sf->prev) {
+               struct btrfsic_stack_frame *const prev = sf->prev;
+
+               /* the one for the initial block is freed in the caller */
+               btrfsic_release_block_ctx(sf->block_ctx);
+
+               if (sf->error) {
+                       prev->error = sf->error;
+                       btrfsic_stack_frame_free(sf);
+                       sf = prev;
+                       goto one_stack_frame_backwards;
+               }
+
+               btrfsic_stack_frame_free(sf);
+               sf = prev;
+               goto continue_with_new_stack_frame;
+       } else {
+               BUG_ON(&initial_stack_frame != sf);
+       }
+
+       return sf->error;
+}
+
+static int btrfsic_create_link_to_next_block(
+               struct btrfsic_state *state,
+               struct btrfsic_block *block,
+               struct btrfsic_block_data_ctx *block_ctx,
+               u64 next_bytenr,
+               int limit_nesting,
+               struct btrfsic_block_data_ctx *next_block_ctx,
+               struct btrfsic_block **next_blockp,
+               int force_iodone_flag,
+               int *num_copiesp, int *mirror_nump,
+               struct btrfs_disk_key *disk_key,
+               u64 parent_generation)
+{
+       struct btrfsic_block *next_block = NULL;
+       int ret;
+       struct btrfsic_block_link *l;
+       int did_alloc_block_link;
+       int block_was_created;
+
+       *next_blockp = NULL;
+       if (0 == *num_copiesp) {
+               *num_copiesp =
+                   btrfs_num_copies(&state->root->fs_info->mapping_tree,
+                                    next_bytenr, PAGE_SIZE);
+               if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
+                       printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
+                              (unsigned long long)next_bytenr, *num_copiesp);
+               *mirror_nump = 1;
+       }
+
+       if (*mirror_nump > *num_copiesp)
+               return 0;
+
+       if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+               printk(KERN_INFO
+                      "btrfsic_create_link_to_next_block(mirror_num=%d)\n",
+                      *mirror_nump);
+       ret = btrfsic_map_block(state, next_bytenr,
+                               BTRFSIC_BLOCK_SIZE,
+                               next_block_ctx, *mirror_nump);
+       if (ret) {
+               printk(KERN_INFO
+                      "btrfsic: btrfsic_map_block(@%llu, mirror=%d) failed!\n",
+                      (unsigned long long)next_bytenr, *mirror_nump);
+               btrfsic_release_block_ctx(next_block_ctx);
+               *next_blockp = NULL;
+               return -1;
+       }
+
+       next_block = btrfsic_block_lookup_or_add(state,
+                                                next_block_ctx, "referenced ",
+                                                1, force_iodone_flag,
+                                                !force_iodone_flag,
+                                                *mirror_nump,
+                                                &block_was_created);
+       if (NULL == next_block) {
+               btrfsic_release_block_ctx(next_block_ctx);
+               *next_blockp = NULL;
+               return -1;
+       }
+       if (block_was_created) {
+               l = NULL;
+               next_block->generation = BTRFSIC_GENERATION_UNKNOWN;
+       } else {
+               if (next_block->logical_bytenr != next_bytenr &&
+                   !(!next_block->is_metadata &&
+                     0 == next_block->logical_bytenr)) {
+                       printk(KERN_INFO
+                              "Referenced block @%llu (%s/%llu/%d)"
+                              " found in hash table, %c,"
+                              " bytenr mismatch (!= stored %llu).\n",
+                              (unsigned long long)next_bytenr,
+                              next_block_ctx->dev->name,
+                              (unsigned long long)next_block_ctx->dev_bytenr,
+                              *mirror_nump,
+                              btrfsic_get_block_type(state, next_block),
+                              (unsigned long long)next_block->logical_bytenr);
+               } else if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                       printk(KERN_INFO
+                              "Referenced block @%llu (%s/%llu/%d)"
+                              " found in hash table, %c.\n",
+                              (unsigned long long)next_bytenr,
+                              next_block_ctx->dev->name,
+                              (unsigned long long)next_block_ctx->dev_bytenr,
+                              *mirror_nump,
+                              btrfsic_get_block_type(state, next_block));
+               next_block->logical_bytenr = next_bytenr;
+
+               next_block->mirror_num = *mirror_nump;
+               l = btrfsic_block_link_hashtable_lookup(
+                               next_block_ctx->dev->bdev,
+                               next_block_ctx->dev_bytenr,
+                               block_ctx->dev->bdev,
+                               block_ctx->dev_bytenr,
+                               &state->block_link_hashtable);
+       }
+
+       next_block->disk_key = *disk_key;
+       if (NULL == l) {
+               l = btrfsic_block_link_alloc();
+               if (NULL == l) {
+                       printk(KERN_INFO "btrfsic: error, kmalloc failed!\n");
+                       btrfsic_release_block_ctx(next_block_ctx);
+                       *next_blockp = NULL;
+                       return -1;
+               }
+
+               did_alloc_block_link = 1;
+               l->block_ref_to = next_block;
+               l->block_ref_from = block;
+               l->ref_cnt = 1;
+               l->parent_generation = parent_generation;
+
+               if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                       btrfsic_print_add_link(state, l);
+
+               list_add(&l->node_ref_to, &block->ref_to_list);
+               list_add(&l->node_ref_from, &next_block->ref_from_list);
+
+               btrfsic_block_link_hashtable_add(l,
+                                                &state->block_link_hashtable);
+       } else {
+               did_alloc_block_link = 0;
+               if (0 == limit_nesting) {
+                       l->ref_cnt++;
+                       l->parent_generation = parent_generation;
+                       if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                               btrfsic_print_add_link(state, l);
+               }
+       }
+
+       if (limit_nesting > 0 && did_alloc_block_link) {
+               ret = btrfsic_read_block(state, next_block_ctx);
+               if (ret < (int)BTRFSIC_BLOCK_SIZE) {
+                       printk(KERN_INFO
+                              "btrfsic: read block @logical %llu failed!\n",
+                              (unsigned long long)next_bytenr);
+                       btrfsic_release_block_ctx(next_block_ctx);
+                       *next_blockp = NULL;
+                       return -1;
+               }
+
+               *next_blockp = next_block;
+       } else {
+               *next_blockp = NULL;
+       }
+       (*mirror_nump)++;
+
+       return 0;
+}
+
+static int btrfsic_handle_extent_data(
+               struct btrfsic_state *state,
+               struct btrfsic_block *block,
+               struct btrfsic_block_data_ctx *block_ctx,
+               u32 item_offset, int force_iodone_flag)
+{
+       int ret;
+       struct btrfs_file_extent_item *file_extent_item =
+           (struct btrfs_file_extent_item *)(block_ctx->data +
+                                             offsetof(struct btrfs_leaf,
+                                                      items) + item_offset);
+       u64 next_bytenr =
+           le64_to_cpu(file_extent_item->disk_bytenr) +
+           le64_to_cpu(file_extent_item->offset);
+       u64 num_bytes = le64_to_cpu(file_extent_item->num_bytes);
+       u64 generation = le64_to_cpu(file_extent_item->generation);
+       struct btrfsic_block_link *l;
+
+       if (state->print_mask & BTRFSIC_PRINT_MASK_VERY_VERBOSE)
+               printk(KERN_INFO "extent_data: type %u, disk_bytenr = %llu,"
+                      " offset = %llu, num_bytes = %llu\n",
+                      file_extent_item->type,
+                      (unsigned long long)
+                      le64_to_cpu(file_extent_item->disk_bytenr),
+                      (unsigned long long)
+                      le64_to_cpu(file_extent_item->offset),
+                      (unsigned long long)
+                      le64_to_cpu(file_extent_item->num_bytes));
+       if (BTRFS_FILE_EXTENT_REG != file_extent_item->type ||
+           ((u64)0) == le64_to_cpu(file_extent_item->disk_bytenr))
+               return 0;
+       while (num_bytes > 0) {
+               u32 chunk_len;
+               int num_copies;
+               int mirror_num;
+
+               if (num_bytes > BTRFSIC_BLOCK_SIZE)
+                       chunk_len = BTRFSIC_BLOCK_SIZE;
+               else
+                       chunk_len = num_bytes;
+
+               num_copies =
+                   btrfs_num_copies(&state->root->fs_info->mapping_tree,
+                                    next_bytenr, PAGE_SIZE);
+               if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
+                       printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
+                              (unsigned long long)next_bytenr, num_copies);
+               for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
+                       struct btrfsic_block_data_ctx next_block_ctx;
+                       struct btrfsic_block *next_block;
+                       int block_was_created;
+
+                       if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                               printk(KERN_INFO "btrfsic_handle_extent_data("
+                                      "mirror_num=%d)\n", mirror_num);
+                       if (state->print_mask & BTRFSIC_PRINT_MASK_VERY_VERBOSE)
+                               printk(KERN_INFO
+                                      "\tdisk_bytenr = %llu, num_bytes %u\n",
+                                      (unsigned long long)next_bytenr,
+                                      chunk_len);
+                       ret = btrfsic_map_block(state, next_bytenr,
+                                               chunk_len, &next_block_ctx,
+                                               mirror_num);
+                       if (ret) {
+                               printk(KERN_INFO
+                                      "btrfsic: btrfsic_map_block(@%llu,"
+                                      " mirror=%d) failed!\n",
+                                      (unsigned long long)next_bytenr,
+                                      mirror_num);
+                               return -1;
+                       }
+
+                       next_block = btrfsic_block_lookup_or_add(
+                                       state,
+                                       &next_block_ctx,
+                                       "referenced ",
+                                       0,
+                                       force_iodone_flag,
+                                       !force_iodone_flag,
+                                       mirror_num,
+                                       &block_was_created);
+                       if (NULL == next_block) {
+                               printk(KERN_INFO
+                                      "btrfsic: error, kmalloc failed!\n");
+                               btrfsic_release_block_ctx(&next_block_ctx);
+                               return -1;
+                       }
+                       if (!block_was_created) {
+                               if (next_block->logical_bytenr != next_bytenr &&
+                                   !(!next_block->is_metadata &&
+                                     0 == next_block->logical_bytenr)) {
+                                       printk(KERN_INFO
+                                              "Referenced block"
+                                              " @%llu (%s/%llu/%d)"
+                                              " found in hash table, D,"
+                                              " bytenr mismatch"
+                                              " (!= stored %llu).\n",
+                                              (unsigned long long)next_bytenr,
+                                              next_block_ctx.dev->name,
+                                              (unsigned long long)
+                                              next_block_ctx.dev_bytenr,
+                                              mirror_num,
+                                              (unsigned long long)
+                                              next_block->logical_bytenr);
+                               }
+                               next_block->logical_bytenr = next_bytenr;
+                               next_block->mirror_num = mirror_num;
+                       }
+
+                       l = btrfsic_block_link_lookup_or_add(state,
+                                                            &next_block_ctx,
+                                                            next_block, block,
+                                                            generation);
+                       btrfsic_release_block_ctx(&next_block_ctx);
+                       if (NULL == l)
+                               return -1;
+               }
+
+               next_bytenr += chunk_len;
+               num_bytes -= chunk_len;
+       }
+
+       return 0;
+}
+
+static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len,
+                            struct btrfsic_block_data_ctx *block_ctx_out,
+                            int mirror_num)
+{
+       int ret;
+       u64 length;
+       struct btrfs_bio *multi = NULL;
+       struct btrfs_device *device;
+
+       length = len;
+       ret = btrfs_map_block(&state->root->fs_info->mapping_tree, READ,
+                             bytenr, &length, &multi, mirror_num);
+
+       device = multi->stripes[0].dev;
+       block_ctx_out->dev = btrfsic_dev_state_lookup(device->bdev);
+       block_ctx_out->dev_bytenr = multi->stripes[0].physical;
+       block_ctx_out->start = bytenr;
+       block_ctx_out->len = len;
+       block_ctx_out->data = NULL;
+       block_ctx_out->bh = NULL;
+
+       if (0 == ret)
+               kfree(multi);
+       if (NULL == block_ctx_out->dev) {
+               ret = -ENXIO;
+               printk(KERN_INFO "btrfsic: error, cannot lookup dev (#1)!\n");
+       }
+
+       return ret;
+}
+
+static int btrfsic_map_superblock(struct btrfsic_state *state, u64 bytenr,
+                                 u32 len, struct block_device *bdev,
+                                 struct btrfsic_block_data_ctx *block_ctx_out)
+{
+       block_ctx_out->dev = btrfsic_dev_state_lookup(bdev);
+       block_ctx_out->dev_bytenr = bytenr;
+       block_ctx_out->start = bytenr;
+       block_ctx_out->len = len;
+       block_ctx_out->data = NULL;
+       block_ctx_out->bh = NULL;
+       if (NULL != block_ctx_out->dev) {
+               return 0;
+       } else {
+               printk(KERN_INFO "btrfsic: error, cannot lookup dev (#2)!\n");
+               return -ENXIO;
+       }
+}
+
+static void btrfsic_release_block_ctx(struct btrfsic_block_data_ctx *block_ctx)
+{
+       if (NULL != block_ctx->bh) {
+               brelse(block_ctx->bh);
+               block_ctx->bh = NULL;
+       }
+}
+
+static int btrfsic_read_block(struct btrfsic_state *state,
+                             struct btrfsic_block_data_ctx *block_ctx)
+{
+       block_ctx->bh = NULL;
+       if (block_ctx->dev_bytenr & 4095) {
+               printk(KERN_INFO
+                      "btrfsic: read_block() with unaligned bytenr %llu\n",
+                      (unsigned long long)block_ctx->dev_bytenr);
+               return -1;
+       }
+       if (block_ctx->len > 4096) {
+               printk(KERN_INFO
+                      "btrfsic: read_block() with too huge size %d\n",
+                      block_ctx->len);
+               return -1;
+       }
+
+       block_ctx->bh = __bread(block_ctx->dev->bdev,
+                               block_ctx->dev_bytenr >> 12, 4096);
+       if (NULL == block_ctx->bh)
+               return -1;
+       block_ctx->data = block_ctx->bh->b_data;
+
+       return block_ctx->len;
+}
+
+static void btrfsic_dump_database(struct btrfsic_state *state)
+{
+       struct list_head *elem_all;
+
+       BUG_ON(NULL == state);
+
+       printk(KERN_INFO "all_blocks_list:\n");
+       list_for_each(elem_all, &state->all_blocks_list) {
+               const struct btrfsic_block *const b_all =
+                   list_entry(elem_all, struct btrfsic_block,
+                              all_blocks_node);
+               struct list_head *elem_ref_to;
+               struct list_head *elem_ref_from;
+
+               printk(KERN_INFO "%c-block @%llu (%s/%llu/%d)\n",
+                      btrfsic_get_block_type(state, b_all),
+                      (unsigned long long)b_all->logical_bytenr,
+                      b_all->dev_state->name,
+                      (unsigned long long)b_all->dev_bytenr,
+                      b_all->mirror_num);
+
+               list_for_each(elem_ref_to, &b_all->ref_to_list) {
+                       const struct btrfsic_block_link *const l =
+                           list_entry(elem_ref_to,
+                                      struct btrfsic_block_link,
+                                      node_ref_to);
+
+                       printk(KERN_INFO " %c @%llu (%s/%llu/%d)"
+                              " refers %u* to"
+                              " %c @%llu (%s/%llu/%d)\n",
+                              btrfsic_get_block_type(state, b_all),
+                              (unsigned long long)b_all->logical_bytenr,
+                              b_all->dev_state->name,
+                              (unsigned long long)b_all->dev_bytenr,
+                              b_all->mirror_num,
+                              l->ref_cnt,
+                              btrfsic_get_block_type(state, l->block_ref_to),
+                              (unsigned long long)
+                              l->block_ref_to->logical_bytenr,
+                              l->block_ref_to->dev_state->name,
+                              (unsigned long long)l->block_ref_to->dev_bytenr,
+                              l->block_ref_to->mirror_num);
+               }
+
+               list_for_each(elem_ref_from, &b_all->ref_from_list) {
+                       const struct btrfsic_block_link *const l =
+                           list_entry(elem_ref_from,
+                                      struct btrfsic_block_link,
+                                      node_ref_from);
+
+                       printk(KERN_INFO " %c @%llu (%s/%llu/%d)"
+                              " is ref %u* from"
+                              " %c @%llu (%s/%llu/%d)\n",
+                              btrfsic_get_block_type(state, b_all),
+                              (unsigned long long)b_all->logical_bytenr,
+                              b_all->dev_state->name,
+                              (unsigned long long)b_all->dev_bytenr,
+                              b_all->mirror_num,
+                              l->ref_cnt,
+                              btrfsic_get_block_type(state, l->block_ref_from),
+                              (unsigned long long)
+                              l->block_ref_from->logical_bytenr,
+                              l->block_ref_from->dev_state->name,
+                              (unsigned long long)
+                              l->block_ref_from->dev_bytenr,
+                              l->block_ref_from->mirror_num);
+               }
+
+               printk(KERN_INFO "\n");
+       }
+}
+
+/*
+ * Test whether the disk block contains a tree block (leaf or node)
+ * (note that this test fails for the super block)
+ */
+static int btrfsic_test_for_metadata(struct btrfsic_state *state,
+                                    const u8 *data, unsigned int size)
+{
+       struct btrfs_header *h;
+       u8 csum[BTRFS_CSUM_SIZE];
+       u32 crc = ~(u32)0;
+       int fail = 0;
+       int crc_fail = 0;
+
+       h = (struct btrfs_header *)data;
+
+       if (memcmp(h->fsid, state->root->fs_info->fsid, BTRFS_UUID_SIZE))
+               fail++;
+
+       crc = crc32c(crc, data + BTRFS_CSUM_SIZE, PAGE_SIZE - BTRFS_CSUM_SIZE);
+       btrfs_csum_final(crc, csum);
+       if (memcmp(csum, h->csum, state->csum_size))
+               crc_fail++;
+
+       return fail || crc_fail;
+}
+
+static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
+                                         u64 dev_bytenr,
+                                         u8 *mapped_data, unsigned int len,
+                                         struct bio *bio,
+                                         int *bio_is_patched,
+                                         struct buffer_head *bh,
+                                         int submit_bio_bh_rw)
+{
+       int is_metadata;
+       struct btrfsic_block *block;
+       struct btrfsic_block_data_ctx block_ctx;
+       int ret;
+       struct btrfsic_state *state = dev_state->state;
+       struct block_device *bdev = dev_state->bdev;
+
+       WARN_ON(len > PAGE_SIZE);
+       is_metadata = (0 == btrfsic_test_for_metadata(state, mapped_data, len));
+       if (NULL != bio_is_patched)
+               *bio_is_patched = 0;
+
+       block = btrfsic_block_hashtable_lookup(bdev, dev_bytenr,
+                                              &state->block_hashtable);
+       if (NULL != block) {
+               u64 bytenr;
+               struct list_head *elem_ref_to;
+               struct list_head *tmp_ref_to;
+
+               if (block->is_superblock) {
+                       bytenr = le64_to_cpu(((struct btrfs_super_block *)
+                                             mapped_data)->bytenr);
+                       is_metadata = 1;
+                       if (state->print_mask &
+                           BTRFSIC_PRINT_MASK_TREE_BEFORE_SB_WRITE) {
+                               printk(KERN_INFO
+                                      "[before new superblock is written]:\n");
+                               btrfsic_dump_tree_sub(state, block, 0);
+                       }
+               }
+               if (is_metadata) {
+                       if (!block->is_superblock) {
+                               bytenr = le64_to_cpu(((struct btrfs_header *)
+                                                     mapped_data)->bytenr);
+                               btrfsic_cmp_log_and_dev_bytenr(state, bytenr,
+                                                              dev_state,
+                                                              dev_bytenr,
+                                                              mapped_data);
+                       }
+                       if (block->logical_bytenr != bytenr) {
+                               printk(KERN_INFO
+                                      "Written block @%llu (%s/%llu/%d)"
+                                      " found in hash table, %c,"
+                                      " bytenr mismatch"
+                                      " (!= stored %llu).\n",
+                                      (unsigned long long)bytenr,
+                                      dev_state->name,
+                                      (unsigned long long)dev_bytenr,
+                                      block->mirror_num,
+                                      btrfsic_get_block_type(state, block),
+                                      (unsigned long long)
+                                      block->logical_bytenr);
+                               block->logical_bytenr = bytenr;
+                       } else if (state->print_mask &
+                                  BTRFSIC_PRINT_MASK_VERBOSE)
+                               printk(KERN_INFO
+                                      "Written block @%llu (%s/%llu/%d)"
+                                      " found in hash table, %c.\n",
+                                      (unsigned long long)bytenr,
+                                      dev_state->name,
+                                      (unsigned long long)dev_bytenr,
+                                      block->mirror_num,
+                                      btrfsic_get_block_type(state, block));
+               } else {
+                       bytenr = block->logical_bytenr;
+                       if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                               printk(KERN_INFO
+                                      "Written block @%llu (%s/%llu/%d)"
+                                      " found in hash table, %c.\n",
+                                      (unsigned long long)bytenr,
+                                      dev_state->name,
+                                      (unsigned long long)dev_bytenr,
+                                      block->mirror_num,
+                                      btrfsic_get_block_type(state, block));
+               }
+
+               if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                       printk(KERN_INFO
+                              "ref_to_list: %cE, ref_from_list: %cE\n",
+                              list_empty(&block->ref_to_list) ? ' ' : '!',
+                              list_empty(&block->ref_from_list) ? ' ' : '!');
+               if (btrfsic_is_block_ref_by_superblock(state, block, 0)) {
+                       printk(KERN_INFO "btrfs: attempt to overwrite %c-block"
+                              " @%llu (%s/%llu/%d), old(gen=%llu,"
+                              " objectid=%llu, type=%d, offset=%llu),"
+                              " new(gen=%llu),"
+                              " which is referenced by most recent superblock"
+                              " (superblockgen=%llu)!\n",
+                              btrfsic_get_block_type(state, block),
+                              (unsigned long long)bytenr,
+                              dev_state->name,
+                              (unsigned long long)dev_bytenr,
+                              block->mirror_num,
+                              (unsigned long long)block->generation,
+                              (unsigned long long)
+                              le64_to_cpu(block->disk_key.objectid),
+                              block->disk_key.type,
+                              (unsigned long long)
+                              le64_to_cpu(block->disk_key.offset),
+                              (unsigned long long)
+                              le64_to_cpu(((struct btrfs_header *)
+                                           mapped_data)->generation),
+                              (unsigned long long)
+                              state->max_superblock_generation);
+                       btrfsic_dump_tree(state);
+               }
+
+               if (!block->is_iodone && !block->never_written) {
+                       printk(KERN_INFO "btrfs: attempt to overwrite %c-block"
+                              " @%llu (%s/%llu/%d), oldgen=%llu, newgen=%llu,"
+                              " which is not yet iodone!\n",
+                              btrfsic_get_block_type(state, block),
+                              (unsigned long long)bytenr,
+                              dev_state->name,
+                              (unsigned long long)dev_bytenr,
+                              block->mirror_num,
+                              (unsigned long long)block->generation,
+                              (unsigned long long)
+                              le64_to_cpu(((struct btrfs_header *)
+                                           mapped_data)->generation));
+                       /* it would not be safe to go on */
+                       btrfsic_dump_tree(state);
+                       return;
+               }
+
+               /*
+                * Clear all references of this block. Do not free
+                * the block itself even if is not referenced anymore
+                * because it still carries valueable information
+                * like whether it was ever written and IO completed.
+                */
+               list_for_each_safe(elem_ref_to, tmp_ref_to,
+                                  &block->ref_to_list) {
+                       struct btrfsic_block_link *const l =
+                           list_entry(elem_ref_to,
+                                      struct btrfsic_block_link,
+                                      node_ref_to);
+
+                       if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                               btrfsic_print_rem_link(state, l);
+                       l->ref_cnt--;
+                       if (0 == l->ref_cnt) {
+                               list_del(&l->node_ref_to);
+                               list_del(&l->node_ref_from);
+                               btrfsic_block_link_hashtable_remove(l);
+                               btrfsic_block_link_free(l);
+                       }
+               }
+
+               if (block->is_superblock)
+                       ret = btrfsic_map_superblock(state, bytenr, len,
+                                                    bdev, &block_ctx);
+               else
+                       ret = btrfsic_map_block(state, bytenr, len,
+                                               &block_ctx, 0);
+               if (ret) {
+                       printk(KERN_INFO
+                              "btrfsic: btrfsic_map_block(root @%llu)"
+                              " failed!\n", (unsigned long long)bytenr);
+                       return;
+               }
+               block_ctx.data = mapped_data;
+               /* the following is required in case of writes to mirrors,
+                * use the same that was used for the lookup */
+               block_ctx.dev = dev_state;
+               block_ctx.dev_bytenr = dev_bytenr;
+
+               if (is_metadata || state->include_extent_data) {
+                       block->never_written = 0;
+                       block->iodone_w_error = 0;
+                       if (NULL != bio) {
+                               block->is_iodone = 0;
+                               BUG_ON(NULL == bio_is_patched);
+                               if (!*bio_is_patched) {
+                                       block->orig_bio_bh_private =
+                                           bio->bi_private;
+                                       block->orig_bio_bh_end_io.bio =
+                                           bio->bi_end_io;
+                                       block->next_in_same_bio = NULL;
+                                       bio->bi_private = block;
+                                       bio->bi_end_io = btrfsic_bio_end_io;
+                                       *bio_is_patched = 1;
+                               } else {
+                                       struct btrfsic_block *chained_block =
+                                           (struct btrfsic_block *)
+                                           bio->bi_private;
+
+                                       BUG_ON(NULL == chained_block);
+                                       block->orig_bio_bh_private =
+                                           chained_block->orig_bio_bh_private;
+                                       block->orig_bio_bh_end_io.bio =
+                                           chained_block->orig_bio_bh_end_io.
+                                           bio;
+                                       block->next_in_same_bio = chained_block;
+                                       bio->bi_private = block;
+                               }
+                       } else if (NULL != bh) {
+                               block->is_iodone = 0;
+                               block->orig_bio_bh_private = bh->b_private;
+                               block->orig_bio_bh_end_io.bh = bh->b_end_io;
+                               block->next_in_same_bio = NULL;
+                               bh->b_private = block;
+                               bh->b_end_io = btrfsic_bh_end_io;
+                       } else {
+                               block->is_iodone = 1;
+                               block->orig_bio_bh_private = NULL;
+                               block->orig_bio_bh_end_io.bio = NULL;
+                               block->next_in_same_bio = NULL;
+                       }
+               }
+
+               block->flush_gen = dev_state->last_flush_gen + 1;
+               block->submit_bio_bh_rw = submit_bio_bh_rw;
+               if (is_metadata) {
+                       block->logical_bytenr = bytenr;
+                       block->is_metadata = 1;
+                       if (block->is_superblock) {
+                               ret = btrfsic_process_written_superblock(
+                                               state,
+                                               block,
+                                               (struct btrfs_super_block *)
+                                               mapped_data);
+                               if (state->print_mask &
+                                   BTRFSIC_PRINT_MASK_TREE_AFTER_SB_WRITE) {
+                                       printk(KERN_INFO
+                                       "[after new superblock is written]:\n");
+                                       btrfsic_dump_tree_sub(state, block, 0);
+                               }
+                       } else {
+                               block->mirror_num = 0;  /* unknown */
+                               ret = btrfsic_process_metablock(
+                                               state,
+                                               block,
+                                               &block_ctx,
+                                               (struct btrfs_header *)
+                                               block_ctx.data,
+                                               0, 0);
+                       }
+                       if (ret)
+                               printk(KERN_INFO
+                                      "btrfsic: btrfsic_process_metablock"
+                                      "(root @%llu) failed!\n",
+                                      (unsigned long long)dev_bytenr);
+               } else {
+                       block->is_metadata = 0;
+                       block->mirror_num = 0;  /* unknown */
+                       block->generation = BTRFSIC_GENERATION_UNKNOWN;
+                       if (!state->include_extent_data
+                           && list_empty(&block->ref_from_list)) {
+                               /*
+                                * disk block is overwritten with extent
+                                * data (not meta data) and we are configured
+                                * to not include extent data: take the
+                                * chance and free the block's memory
+                                */
+                               btrfsic_block_hashtable_remove(block);
+                               list_del(&block->all_blocks_node);
+                               btrfsic_block_free(block);
+                       }
+               }
+               btrfsic_release_block_ctx(&block_ctx);
+       } else {
+               /* block has not been found in hash table */
+               u64 bytenr;
+
+               if (!is_metadata) {
+                       if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                               printk(KERN_INFO "Written block (%s/%llu/?)"
+                                      " !found in hash table, D.\n",
+                                      dev_state->name,
+                                      (unsigned long long)dev_bytenr);
+                       if (!state->include_extent_data)
+                               return; /* ignore that written D block */
+
+                       /* this is getting ugly for the
+                        * include_extent_data case... */
+                       bytenr = 0;     /* unknown */
+                       block_ctx.start = bytenr;
+                       block_ctx.len = len;
+                       block_ctx.bh = NULL;
+               } else {
+                       bytenr = le64_to_cpu(((struct btrfs_header *)
+                                             mapped_data)->bytenr);
+                       btrfsic_cmp_log_and_dev_bytenr(state, bytenr, dev_state,
+                                                      dev_bytenr,
+                                                      mapped_data);
+                       if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                               printk(KERN_INFO
+                                      "Written block @%llu (%s/%llu/?)"
+                                      " !found in hash table, M.\n",
+                                      (unsigned long long)bytenr,
+                                      dev_state->name,
+                                      (unsigned long long)dev_bytenr);
+
+                       ret = btrfsic_map_block(state, bytenr, len, &block_ctx,
+                                               0);
+                       if (ret) {
+                               printk(KERN_INFO
+                                      "btrfsic: btrfsic_map_block(root @%llu)"
+                                      " failed!\n",
+                                      (unsigned long long)dev_bytenr);
+                               return;
+                       }
+               }
+               block_ctx.data = mapped_data;
+               /* the following is required in case of writes to mirrors,
+                * use the same that was used for the lookup */
+               block_ctx.dev = dev_state;
+               block_ctx.dev_bytenr = dev_bytenr;
+
+               block = btrfsic_block_alloc();
+               if (NULL == block) {
+                       printk(KERN_INFO "btrfsic: error, kmalloc failed!\n");
+                       btrfsic_release_block_ctx(&block_ctx);
+                       return;
+               }
+               block->dev_state = dev_state;
+               block->dev_bytenr = dev_bytenr;
+               block->logical_bytenr = bytenr;
+               block->is_metadata = is_metadata;
+               block->never_written = 0;
+               block->iodone_w_error = 0;
+               block->mirror_num = 0;  /* unknown */
+               block->flush_gen = dev_state->last_flush_gen + 1;
+               block->submit_bio_bh_rw = submit_bio_bh_rw;
+               if (NULL != bio) {
+                       block->is_iodone = 0;
+                       BUG_ON(NULL == bio_is_patched);
+                       if (!*bio_is_patched) {
+                               block->orig_bio_bh_private = bio->bi_private;
+                               block->orig_bio_bh_end_io.bio = bio->bi_end_io;
+                               block->next_in_same_bio = NULL;
+                               bio->bi_private = block;
+                               bio->bi_end_io = btrfsic_bio_end_io;
+                               *bio_is_patched = 1;
+                       } else {
+                               struct btrfsic_block *chained_block =
+                                   (struct btrfsic_block *)
+                                   bio->bi_private;
+
+                               BUG_ON(NULL == chained_block);
+                               block->orig_bio_bh_private =
+                                   chained_block->orig_bio_bh_private;
+                               block->orig_bio_bh_end_io.bio =
+                                   chained_block->orig_bio_bh_end_io.bio;
+                               block->next_in_same_bio = chained_block;
+                               bio->bi_private = block;
+                       }
+               } else if (NULL != bh) {
+                       block->is_iodone = 0;
+                       block->orig_bio_bh_private = bh->b_private;
+                       block->orig_bio_bh_end_io.bh = bh->b_end_io;
+                       block->next_in_same_bio = NULL;
+                       bh->b_private = block;
+                       bh->b_end_io = btrfsic_bh_end_io;
+               } else {
+                       block->is_iodone = 1;
+                       block->orig_bio_bh_private = NULL;
+                       block->orig_bio_bh_end_io.bio = NULL;
+                       block->next_in_same_bio = NULL;
+               }
+               if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                       printk(KERN_INFO
+                              "New written %c-block @%llu (%s/%llu/%d)\n",
+                              is_metadata ? 'M' : 'D',
+                              (unsigned long long)block->logical_bytenr,
+                              block->dev_state->name,
+                              (unsigned long long)block->dev_bytenr,
+                              block->mirror_num);
+               list_add(&block->all_blocks_node, &state->all_blocks_list);
+               btrfsic_block_hashtable_add(block, &state->block_hashtable);
+
+               if (is_metadata) {
+                       ret = btrfsic_process_metablock(state, block,
+                                                       &block_ctx,
+                                                       (struct btrfs_header *)
+                                                       block_ctx.data, 0, 0);
+                       if (ret)
+                               printk(KERN_INFO
+                                      "btrfsic: process_metablock(root @%llu)"
+                                      " failed!\n",
+                                      (unsigned long long)dev_bytenr);
+               }
+               btrfsic_release_block_ctx(&block_ctx);
+       }
+}
+
+static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status)
+{
+       struct btrfsic_block *block = (struct btrfsic_block *)bp->bi_private;
+       int iodone_w_error;
+
+       /* mutex is not held! This is not save if IO is not yet completed
+        * on umount */
+       iodone_w_error = 0;
+       if (bio_error_status)
+               iodone_w_error = 1;
+
+       BUG_ON(NULL == block);
+       bp->bi_private = block->orig_bio_bh_private;
+       bp->bi_end_io = block->orig_bio_bh_end_io.bio;
+
+       do {
+               struct btrfsic_block *next_block;
+               struct btrfsic_dev_state *const dev_state = block->dev_state;
+
+               if ((dev_state->state->print_mask &
+                    BTRFSIC_PRINT_MASK_END_IO_BIO_BH))
+                       printk(KERN_INFO
+                              "bio_end_io(err=%d) for %c @%llu (%s/%llu/%d)\n",
+                              bio_error_status,
+                              btrfsic_get_block_type(dev_state->state, block),
+                              (unsigned long long)block->logical_bytenr,
+                              dev_state->name,
+                              (unsigned long long)block->dev_bytenr,
+                              block->mirror_num);
+               next_block = block->next_in_same_bio;
+               block->iodone_w_error = iodone_w_error;
+               if (block->submit_bio_bh_rw & REQ_FLUSH) {
+                       dev_state->last_flush_gen++;
+                       if ((dev_state->state->print_mask &
+                            BTRFSIC_PRINT_MASK_END_IO_BIO_BH))
+                               printk(KERN_INFO
+                                      "bio_end_io() new %s flush_gen=%llu\n",
+                                      dev_state->name,
+                                      (unsigned long long)
+                                      dev_state->last_flush_gen);
+               }
+               if (block->submit_bio_bh_rw & REQ_FUA)
+                       block->flush_gen = 0; /* FUA completed means block is
+                                              * on disk */
+               block->is_iodone = 1; /* for FLUSH, this releases the block */
+               block = next_block;
+       } while (NULL != block);
+
+       bp->bi_end_io(bp, bio_error_status);
+}
+
+static void btrfsic_bh_end_io(struct buffer_head *bh, int uptodate)
+{
+       struct btrfsic_block *block = (struct btrfsic_block *)bh->b_private;
+       int iodone_w_error = !uptodate;
+       struct btrfsic_dev_state *dev_state;
+
+       BUG_ON(NULL == block);
+       dev_state = block->dev_state;
+       if ((dev_state->state->print_mask & BTRFSIC_PRINT_MASK_END_IO_BIO_BH))
+               printk(KERN_INFO
+                      "bh_end_io(error=%d) for %c @%llu (%s/%llu/%d)\n",
+                      iodone_w_error,
+                      btrfsic_get_block_type(dev_state->state, block),
+                      (unsigned long long)block->logical_bytenr,
+                      block->dev_state->name,
+                      (unsigned long long)block->dev_bytenr,
+                      block->mirror_num);
+
+       block->iodone_w_error = iodone_w_error;
+       if (block->submit_bio_bh_rw & REQ_FLUSH) {
+               dev_state->last_flush_gen++;
+               if ((dev_state->state->print_mask &
+                    BTRFSIC_PRINT_MASK_END_IO_BIO_BH))
+                       printk(KERN_INFO
+                              "bh_end_io() new %s flush_gen=%llu\n",
+                              dev_state->name,
+                              (unsigned long long)dev_state->last_flush_gen);
+       }
+       if (block->submit_bio_bh_rw & REQ_FUA)
+               block->flush_gen = 0; /* FUA completed means block is on disk */
+
+       bh->b_private = block->orig_bio_bh_private;
+       bh->b_end_io = block->orig_bio_bh_end_io.bh;
+       block->is_iodone = 1; /* for FLUSH, this releases the block */
+       bh->b_end_io(bh, uptodate);
+}
+
+static int btrfsic_process_written_superblock(
+               struct btrfsic_state *state,
+               struct btrfsic_block *const superblock,
+               struct btrfs_super_block *const super_hdr)
+{
+       int pass;
+
+       superblock->generation = btrfs_super_generation(super_hdr);
+       if (!(superblock->generation > state->max_superblock_generation ||
+             0 == state->max_superblock_generation)) {
+               if (state->print_mask & BTRFSIC_PRINT_MASK_SUPERBLOCK_WRITE)
+                       printk(KERN_INFO
+                              "btrfsic: superblock @%llu (%s/%llu/%d)"
+                              " with old gen %llu <= %llu\n",
+                              (unsigned long long)superblock->logical_bytenr,
+                              superblock->dev_state->name,
+                              (unsigned long long)superblock->dev_bytenr,
+                              superblock->mirror_num,
+                              (unsigned long long)
+                              btrfs_super_generation(super_hdr),
+                              (unsigned long long)
+                              state->max_superblock_generation);
+       } else {
+               if (state->print_mask & BTRFSIC_PRINT_MASK_SUPERBLOCK_WRITE)
+                       printk(KERN_INFO
+                              "btrfsic: got new superblock @%llu (%s/%llu/%d)"
+                              " with new gen %llu > %llu\n",
+                              (unsigned long long)superblock->logical_bytenr,
+                              superblock->dev_state->name,
+                              (unsigned long long)superblock->dev_bytenr,
+                              superblock->mirror_num,
+                              (unsigned long long)
+                              btrfs_super_generation(super_hdr),
+                              (unsigned long long)
+                              state->max_superblock_generation);
+
+               state->max_superblock_generation =
+                   btrfs_super_generation(super_hdr);
+               state->latest_superblock = superblock;
+       }
+
+       for (pass = 0; pass < 3; pass++) {
+               int ret;
+               u64 next_bytenr;
+               struct btrfsic_block *next_block;
+               struct btrfsic_block_data_ctx tmp_next_block_ctx;
+               struct btrfsic_block_link *l;
+               int num_copies;
+               int mirror_num;
+               const char *additional_string = NULL;
+               struct btrfs_disk_key tmp_disk_key;
+
+               tmp_disk_key.type = BTRFS_ROOT_ITEM_KEY;
+               tmp_disk_key.offset = 0;
+
+               switch (pass) {
+               case 0:
+                       tmp_disk_key.objectid =
+                           cpu_to_le64(BTRFS_ROOT_TREE_OBJECTID);
+                       additional_string = "root ";
+                       next_bytenr = btrfs_super_root(super_hdr);
+                       if (state->print_mask &
+                           BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION)
+                               printk(KERN_INFO "root@%llu\n",
+                                      (unsigned long long)next_bytenr);
+                       break;
+               case 1:
+                       tmp_disk_key.objectid =
+                           cpu_to_le64(BTRFS_CHUNK_TREE_OBJECTID);
+                       additional_string = "chunk ";
+                       next_bytenr = btrfs_super_chunk_root(super_hdr);
+                       if (state->print_mask &
+                           BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION)
+                               printk(KERN_INFO "chunk@%llu\n",
+                                      (unsigned long long)next_bytenr);
+                       break;
+               case 2:
+                       tmp_disk_key.objectid =
+                           cpu_to_le64(BTRFS_TREE_LOG_OBJECTID);
+                       additional_string = "log ";
+                       next_bytenr = btrfs_super_log_root(super_hdr);
+                       if (0 == next_bytenr)
+                               continue;
+                       if (state->print_mask &
+                           BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION)
+                               printk(KERN_INFO "log@%llu\n",
+                                      (unsigned long long)next_bytenr);
+                       break;
+               }
+
+               num_copies =
+                   btrfs_num_copies(&state->root->fs_info->mapping_tree,
+                                    next_bytenr, PAGE_SIZE);
+               if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
+                       printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
+                              (unsigned long long)next_bytenr, num_copies);
+               for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
+                       int was_created;
+
+                       if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                               printk(KERN_INFO
+                                      "btrfsic_process_written_superblock("
+                                      "mirror_num=%d)\n", mirror_num);
+                       ret = btrfsic_map_block(state, next_bytenr, PAGE_SIZE,
+                                               &tmp_next_block_ctx,
+                                               mirror_num);
+                       if (ret) {
+                               printk(KERN_INFO
+                                      "btrfsic: btrfsic_map_block(@%llu,"
+                                      " mirror=%d) failed!\n",
+                                      (unsigned long long)next_bytenr,
+                                      mirror_num);
+                               return -1;
+                       }
+
+                       next_block = btrfsic_block_lookup_or_add(
+                                       state,
+                                       &tmp_next_block_ctx,
+                                       additional_string,
+                                       1, 0, 1,
+                                       mirror_num,
+                                       &was_created);
+                       if (NULL == next_block) {
+                               printk(KERN_INFO
+                                      "btrfsic: error, kmalloc failed!\n");
+                               btrfsic_release_block_ctx(&tmp_next_block_ctx);
+                               return -1;
+                       }
+
+                       next_block->disk_key = tmp_disk_key;
+                       if (was_created)
+                               next_block->generation =
+                                   BTRFSIC_GENERATION_UNKNOWN;
+                       l = btrfsic_block_link_lookup_or_add(
+                                       state,
+                                       &tmp_next_block_ctx,
+                                       next_block,
+                                       superblock,
+                                       BTRFSIC_GENERATION_UNKNOWN);
+                       btrfsic_release_block_ctx(&tmp_next_block_ctx);
+                       if (NULL == l)
+                               return -1;
+               }
+       }
+
+       if (-1 == btrfsic_check_all_ref_blocks(state, superblock, 0)) {
+               WARN_ON(1);
+               btrfsic_dump_tree(state);
+       }
+
+       return 0;
+}
+
+static int btrfsic_check_all_ref_blocks(struct btrfsic_state *state,
+                                       struct btrfsic_block *const block,
+                                       int recursion_level)
+{
+       struct list_head *elem_ref_to;
+       int ret = 0;
+
+       if (recursion_level >= 3 + BTRFS_MAX_LEVEL) {
+               /*
+                * Note that this situation can happen and does not
+                * indicate an error in regular cases. It happens
+                * when disk blocks are freed and later reused.
+                * The check-integrity module is not aware of any
+                * block free operations, it just recognizes block
+                * write operations. Therefore it keeps the linkage
+                * information for a block until a block is
+                * rewritten. This can temporarily cause incorrect
+                * and even circular linkage informations. This
+                * causes no harm unless such blocks are referenced
+                * by the most recent super block.
+                */
+               if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                       printk(KERN_INFO
+                              "btrfsic: abort cyclic linkage (case 1).\n");
+
+               return ret;
+       }
+
+       /*
+        * This algorithm is recursive because the amount of used stack
+        * space is very small and the max recursion depth is limited.
+        */
+       list_for_each(elem_ref_to, &block->ref_to_list) {
+               const struct btrfsic_block_link *const l =
+                   list_entry(elem_ref_to, struct btrfsic_block_link,
+                              node_ref_to);
+
+               if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                       printk(KERN_INFO
+                              "rl=%d, %c @%llu (%s/%llu/%d)"
+                              " %u* refers to %c @%llu (%s/%llu/%d)\n",
+                              recursion_level,
+                              btrfsic_get_block_type(state, block),
+                              (unsigned long long)block->logical_bytenr,
+                              block->dev_state->name,
+                              (unsigned long long)block->dev_bytenr,
+                              block->mirror_num,
+                              l->ref_cnt,
+                              btrfsic_get_block_type(state, l->block_ref_to),
+                              (unsigned long long)
+                              l->block_ref_to->logical_bytenr,
+                              l->block_ref_to->dev_state->name,
+                              (unsigned long long)l->block_ref_to->dev_bytenr,
+                              l->block_ref_to->mirror_num);
+               if (l->block_ref_to->never_written) {
+                       printk(KERN_INFO "btrfs: attempt to write superblock"
+                              " which references block %c @%llu (%s/%llu/%d)"
+                              " which is never written!\n",
+                              btrfsic_get_block_type(state, l->block_ref_to),
+                              (unsigned long long)
+                              l->block_ref_to->logical_bytenr,
+                              l->block_ref_to->dev_state->name,
+                              (unsigned long long)l->block_ref_to->dev_bytenr,
+                              l->block_ref_to->mirror_num);
+                       ret = -1;
+               } else if (!l->block_ref_to->is_iodone) {
+                       printk(KERN_INFO "btrfs: attempt to write superblock"
+                              " which references block %c @%llu (%s/%llu/%d)"
+                              " which is not yet iodone!\n",
+                              btrfsic_get_block_type(state, l->block_ref_to),
+                              (unsigned long long)
+                              l->block_ref_to->logical_bytenr,
+                              l->block_ref_to->dev_state->name,
+                              (unsigned long long)l->block_ref_to->dev_bytenr,
+                              l->block_ref_to->mirror_num);
+                       ret = -1;
+               } else if (l->parent_generation !=
+                          l->block_ref_to->generation &&
+                          BTRFSIC_GENERATION_UNKNOWN !=
+                          l->parent_generation &&
+                          BTRFSIC_GENERATION_UNKNOWN !=
+                          l->block_ref_to->generation) {
+                       printk(KERN_INFO "btrfs: attempt to write superblock"
+                              " which references block %c @%llu (%s/%llu/%d)"
+                              " with generation %llu !="
+                              " parent generation %llu!\n",
+                              btrfsic_get_block_type(state, l->block_ref_to),
+                              (unsigned long long)
+                              l->block_ref_to->logical_bytenr,
+                              l->block_ref_to->dev_state->name,
+                              (unsigned long long)l->block_ref_to->dev_bytenr,
+                              l->block_ref_to->mirror_num,
+                              (unsigned long long)l->block_ref_to->generation,
+                              (unsigned long long)l->parent_generation);
+                       ret = -1;
+               } else if (l->block_ref_to->flush_gen >
+                          l->block_ref_to->dev_state->last_flush_gen) {
+                       printk(KERN_INFO "btrfs: attempt to write superblock"
+                              " which references block %c @%llu (%s/%llu/%d)"
+                              " which is not flushed out of disk's write cache"
+                              " (block flush_gen=%llu,"
+                              " dev->flush_gen=%llu)!\n",
+                              btrfsic_get_block_type(state, l->block_ref_to),
+                              (unsigned long long)
+                              l->block_ref_to->logical_bytenr,
+                              l->block_ref_to->dev_state->name,
+                              (unsigned long long)l->block_ref_to->dev_bytenr,
+                              l->block_ref_to->mirror_num,
+                              (unsigned long long)block->flush_gen,
+                              (unsigned long long)
+                              l->block_ref_to->dev_state->last_flush_gen);
+                       ret = -1;
+               } else if (-1 == btrfsic_check_all_ref_blocks(state,
+                                                             l->block_ref_to,
+                                                             recursion_level +
+                                                             1)) {
+                       ret = -1;
+               }
+       }
+
+       return ret;
+}
+
+static int btrfsic_is_block_ref_by_superblock(
+               const struct btrfsic_state *state,
+               const struct btrfsic_block *block,
+               int recursion_level)
+{
+       struct list_head *elem_ref_from;
+
+       if (recursion_level >= 3 + BTRFS_MAX_LEVEL) {
+               /* refer to comment at "abort cyclic linkage (case 1)" */
+               if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                       printk(KERN_INFO
+                              "btrfsic: abort cyclic linkage (case 2).\n");
+
+               return 0;
+       }
+
+       /*
+        * This algorithm is recursive because the amount of used stack space
+        * is very small and the max recursion depth is limited.
+        */
+       list_for_each(elem_ref_from, &block->ref_from_list) {
+               const struct btrfsic_block_link *const l =
+                   list_entry(elem_ref_from, struct btrfsic_block_link,
+                              node_ref_from);
+
+               if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                       printk(KERN_INFO
+                              "rl=%d, %c @%llu (%s/%llu/%d)"
+                              " is ref %u* from %c @%llu (%s/%llu/%d)\n",
+                              recursion_level,
+                              btrfsic_get_block_type(state, block),
+                              (unsigned long long)block->logical_bytenr,
+                              block->dev_state->name,
+                              (unsigned long long)block->dev_bytenr,
+                              block->mirror_num,
+                              l->ref_cnt,
+                              btrfsic_get_block_type(state, l->block_ref_from),
+                              (unsigned long long)
+                              l->block_ref_from->logical_bytenr,
+                              l->block_ref_from->dev_state->name,
+                              (unsigned long long)
+                              l->block_ref_from->dev_bytenr,
+                              l->block_ref_from->mirror_num);
+               if (l->block_ref_from->is_superblock &&
+                   state->latest_superblock->dev_bytenr ==
+                   l->block_ref_from->dev_bytenr &&
+                   state->latest_superblock->dev_state->bdev ==
+                   l->block_ref_from->dev_state->bdev)
+                       return 1;
+               else if (btrfsic_is_block_ref_by_superblock(state,
+                                                           l->block_ref_from,
+                                                           recursion_level +
+                                                           1))
+                       return 1;
+       }
+
+       return 0;
+}
+
+static void btrfsic_print_add_link(const struct btrfsic_state *state,
+                                  const struct btrfsic_block_link *l)
+{
+       printk(KERN_INFO
+              "Add %u* link from %c @%llu (%s/%llu/%d)"
+              " to %c @%llu (%s/%llu/%d).\n",
+              l->ref_cnt,
+              btrfsic_get_block_type(state, l->block_ref_from),
+              (unsigned long long)l->block_ref_from->logical_bytenr,
+              l->block_ref_from->dev_state->name,
+              (unsigned long long)l->block_ref_from->dev_bytenr,
+              l->block_ref_from->mirror_num,
+              btrfsic_get_block_type(state, l->block_ref_to),
+              (unsigned long long)l->block_ref_to->logical_bytenr,
+              l->block_ref_to->dev_state->name,
+              (unsigned long long)l->block_ref_to->dev_bytenr,
+              l->block_ref_to->mirror_num);
+}
+
+static void btrfsic_print_rem_link(const struct btrfsic_state *state,
+                                  const struct btrfsic_block_link *l)
+{
+       printk(KERN_INFO
+              "Rem %u* link from %c @%llu (%s/%llu/%d)"
+              " to %c @%llu (%s/%llu/%d).\n",
+              l->ref_cnt,
+              btrfsic_get_block_type(state, l->block_ref_from),
+              (unsigned long long)l->block_ref_from->logical_bytenr,
+              l->block_ref_from->dev_state->name,
+              (unsigned long long)l->block_ref_from->dev_bytenr,
+              l->block_ref_from->mirror_num,
+              btrfsic_get_block_type(state, l->block_ref_to),
+              (unsigned long long)l->block_ref_to->logical_bytenr,
+              l->block_ref_to->dev_state->name,
+              (unsigned long long)l->block_ref_to->dev_bytenr,
+              l->block_ref_to->mirror_num);
+}
+
+static char btrfsic_get_block_type(const struct btrfsic_state *state,
+                                  const struct btrfsic_block *block)
+{
+       if (block->is_superblock &&
+           state->latest_superblock->dev_bytenr == block->dev_bytenr &&
+           state->latest_superblock->dev_state->bdev == block->dev_state->bdev)
+               return 'S';
+       else if (block->is_superblock)
+               return 's';
+       else if (block->is_metadata)
+               return 'M';
+       else
+               return 'D';
+}
+
+static void btrfsic_dump_tree(const struct btrfsic_state *state)
+{
+       btrfsic_dump_tree_sub(state, state->latest_superblock, 0);
+}
+
+static void btrfsic_dump_tree_sub(const struct btrfsic_state *state,
+                                 const struct btrfsic_block *block,
+                                 int indent_level)
+{
+       struct list_head *elem_ref_to;
+       int indent_add;
+       static char buf[80];
+       int cursor_position;
+
+       /*
+        * Should better fill an on-stack buffer with a complete line and
+        * dump it at once when it is time to print a newline character.
+        */
+
+       /*
+        * This algorithm is recursive because the amount of used stack space
+        * is very small and the max recursion depth is limited.
+        */
+       indent_add = sprintf(buf, "%c-%llu(%s/%llu/%d)",
+                            btrfsic_get_block_type(state, block),
+                            (unsigned long long)block->logical_bytenr,
+                            block->dev_state->name,
+                            (unsigned long long)block->dev_bytenr,
+                            block->mirror_num);
+       if (indent_level + indent_add > BTRFSIC_TREE_DUMP_MAX_INDENT_LEVEL) {
+               printk("[...]\n");
+               return;
+       }
+       printk(buf);
+       indent_level += indent_add;
+       if (list_empty(&block->ref_to_list)) {
+               printk("\n");
+               return;
+       }
+       if (block->mirror_num > 1 &&
+           !(state->print_mask & BTRFSIC_PRINT_MASK_TREE_WITH_ALL_MIRRORS)) {
+               printk(" [...]\n");
+               return;
+       }
+
+       cursor_position = indent_level;
+       list_for_each(elem_ref_to, &block->ref_to_list) {
+               const struct btrfsic_block_link *const l =
+                   list_entry(elem_ref_to, struct btrfsic_block_link,
+                              node_ref_to);
+
+               while (cursor_position < indent_level) {
+                       printk(" ");
+                       cursor_position++;
+               }
+               if (l->ref_cnt > 1)
+                       indent_add = sprintf(buf, " %d*--> ", l->ref_cnt);
+               else
+                       indent_add = sprintf(buf, " --> ");
+               if (indent_level + indent_add >
+                   BTRFSIC_TREE_DUMP_MAX_INDENT_LEVEL) {
+                       printk("[...]\n");
+                       cursor_position = 0;
+                       continue;
+               }
+
+               printk(buf);
+
+               btrfsic_dump_tree_sub(state, l->block_ref_to,
+                                     indent_level + indent_add);
+               cursor_position = 0;
+       }
+}
+
+static struct btrfsic_block_link *btrfsic_block_link_lookup_or_add(
+               struct btrfsic_state *state,
+               struct btrfsic_block_data_ctx *next_block_ctx,
+               struct btrfsic_block *next_block,
+               struct btrfsic_block *from_block,
+               u64 parent_generation)
+{
+       struct btrfsic_block_link *l;
+
+       l = btrfsic_block_link_hashtable_lookup(next_block_ctx->dev->bdev,
+                                               next_block_ctx->dev_bytenr,
+                                               from_block->dev_state->bdev,
+                                               from_block->dev_bytenr,
+                                               &state->block_link_hashtable);
+       if (NULL == l) {
+               l = btrfsic_block_link_alloc();
+               if (NULL == l) {
+                       printk(KERN_INFO
+                              "btrfsic: error, kmalloc" " failed!\n");
+                       return NULL;
+               }
+
+               l->block_ref_to = next_block;
+               l->block_ref_from = from_block;
+               l->ref_cnt = 1;
+               l->parent_generation = parent_generation;
+
+               if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                       btrfsic_print_add_link(state, l);
+
+               list_add(&l->node_ref_to, &from_block->ref_to_list);
+               list_add(&l->node_ref_from, &next_block->ref_from_list);
+
+               btrfsic_block_link_hashtable_add(l,
+                                                &state->block_link_hashtable);
+       } else {
+               l->ref_cnt++;
+               l->parent_generation = parent_generation;
+               if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                       btrfsic_print_add_link(state, l);
+       }
+
+       return l;
+}
+
+static struct btrfsic_block *btrfsic_block_lookup_or_add(
+               struct btrfsic_state *state,
+               struct btrfsic_block_data_ctx *block_ctx,
+               const char *additional_string,
+               int is_metadata,
+               int is_iodone,
+               int never_written,
+               int mirror_num,
+               int *was_created)
+{
+       struct btrfsic_block *block;
+
+       block = btrfsic_block_hashtable_lookup(block_ctx->dev->bdev,
+                                              block_ctx->dev_bytenr,
+                                              &state->block_hashtable);
+       if (NULL == block) {
+               struct btrfsic_dev_state *dev_state;
+
+               block = btrfsic_block_alloc();
+               if (NULL == block) {
+                       printk(KERN_INFO "btrfsic: error, kmalloc failed!\n");
+                       return NULL;
+               }
+               dev_state = btrfsic_dev_state_lookup(block_ctx->dev->bdev);
+               if (NULL == dev_state) {
+                       printk(KERN_INFO
+                              "btrfsic: error, lookup dev_state failed!\n");
+                       btrfsic_block_free(block);
+                       return NULL;
+               }
+               block->dev_state = dev_state;
+               block->dev_bytenr = block_ctx->dev_bytenr;
+               block->logical_bytenr = block_ctx->start;
+               block->is_metadata = is_metadata;
+               block->is_iodone = is_iodone;
+               block->never_written = never_written;
+               block->mirror_num = mirror_num;
+               if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                       printk(KERN_INFO
+                              "New %s%c-block @%llu (%s/%llu/%d)\n",
+                              additional_string,
+                              btrfsic_get_block_type(state, block),
+                              (unsigned long long)block->logical_bytenr,
+                              dev_state->name,
+                              (unsigned long long)block->dev_bytenr,
+                              mirror_num);
+               list_add(&block->all_blocks_node, &state->all_blocks_list);
+               btrfsic_block_hashtable_add(block, &state->block_hashtable);
+               if (NULL != was_created)
+                       *was_created = 1;
+       } else {
+               if (NULL != was_created)
+                       *was_created = 0;
+       }
+
+       return block;
+}
+
+static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
+                                          u64 bytenr,
+                                          struct btrfsic_dev_state *dev_state,
+                                          u64 dev_bytenr, char *data)
+{
+       int num_copies;
+       int mirror_num;
+       int ret;
+       struct btrfsic_block_data_ctx block_ctx;
+       int match = 0;
+
+       num_copies = btrfs_num_copies(&state->root->fs_info->mapping_tree,
+                                     bytenr, PAGE_SIZE);
+
+       for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
+               ret = btrfsic_map_block(state, bytenr, PAGE_SIZE,
+                                       &block_ctx, mirror_num);
+               if (ret) {
+                       printk(KERN_INFO "btrfsic:"
+                              " btrfsic_map_block(logical @%llu,"
+                              " mirror %d) failed!\n",
+                              (unsigned long long)bytenr, mirror_num);
+                       continue;
+               }
+
+               if (dev_state->bdev == block_ctx.dev->bdev &&
+                   dev_bytenr == block_ctx.dev_bytenr) {
+                       match++;
+                       btrfsic_release_block_ctx(&block_ctx);
+                       break;
+               }
+               btrfsic_release_block_ctx(&block_ctx);
+       }
+
+       if (!match) {
+               printk(KERN_INFO "btrfs: attempt to write M-block which contains logical bytenr that doesn't map to dev+physical bytenr of submit_bio,"
+                      " buffer->log_bytenr=%llu, submit_bio(bdev=%s,"
+                      " phys_bytenr=%llu)!\n",
+                      (unsigned long long)bytenr, dev_state->name,
+                      (unsigned long long)dev_bytenr);
+               for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
+                       ret = btrfsic_map_block(state, bytenr, PAGE_SIZE,
+                                               &block_ctx, mirror_num);
+                       if (ret)
+                               continue;
+
+                       printk(KERN_INFO "Read logical bytenr @%llu maps to"
+                              " (%s/%llu/%d)\n",
+                              (unsigned long long)bytenr,
+                              block_ctx.dev->name,
+                              (unsigned long long)block_ctx.dev_bytenr,
+                              mirror_num);
+               }
+               WARN_ON(1);
+       }
+}
+
+static struct btrfsic_dev_state *btrfsic_dev_state_lookup(
+               struct block_device *bdev)
+{
+       struct btrfsic_dev_state *ds;
+
+       ds = btrfsic_dev_state_hashtable_lookup(bdev,
+                                               &btrfsic_dev_state_hashtable);
+       return ds;
+}
+
+int btrfsic_submit_bh(int rw, struct buffer_head *bh)
+{
+       struct btrfsic_dev_state *dev_state;
+
+       if (!btrfsic_is_initialized)
+               return submit_bh(rw, bh);
+
+       mutex_lock(&btrfsic_mutex);
+       /* since btrfsic_submit_bh() might also be called before
+        * btrfsic_mount(), this might return NULL */
+       dev_state = btrfsic_dev_state_lookup(bh->b_bdev);
+
+       /* Only called to write the superblock (incl. FLUSH/FUA) */
+       if (NULL != dev_state &&
+           (rw & WRITE) && bh->b_size > 0) {
+               u64 dev_bytenr;
+
+               dev_bytenr = 4096 * bh->b_blocknr;
+               if (dev_state->state->print_mask &
+                   BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH)
+                       printk(KERN_INFO
+                              "submit_bh(rw=0x%x, blocknr=%lu (bytenr %llu),"
+                              " size=%lu, data=%p, bdev=%p)\n",
+                              rw, bh->b_blocknr,
+                              (unsigned long long)dev_bytenr, bh->b_size,
+                              bh->b_data, bh->b_bdev);
+               btrfsic_process_written_block(dev_state, dev_bytenr,
+                                             bh->b_data, bh->b_size, NULL,
+                                             NULL, bh, rw);
+       } else if (NULL != dev_state && (rw & REQ_FLUSH)) {
+               if (dev_state->state->print_mask &
+                   BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH)
+                       printk(KERN_INFO
+                              "submit_bh(rw=0x%x) FLUSH, bdev=%p)\n",
+                              rw, bh->b_bdev);
+               if (!dev_state->dummy_block_for_bio_bh_flush.is_iodone) {
+                       if ((dev_state->state->print_mask &
+                            (BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH |
+                             BTRFSIC_PRINT_MASK_VERBOSE)))
+                               printk(KERN_INFO
+                                      "btrfsic_submit_bh(%s) with FLUSH"
+                                      " but dummy block already in use"
+                                      " (ignored)!\n",
+                                      dev_state->name);
+               } else {
+                       struct btrfsic_block *const block =
+                               &dev_state->dummy_block_for_bio_bh_flush;
+
+                       block->is_iodone = 0;
+                       block->never_written = 0;
+                       block->iodone_w_error = 0;
+                       block->flush_gen = dev_state->last_flush_gen + 1;
+                       block->submit_bio_bh_rw = rw;
+                       block->orig_bio_bh_private = bh->b_private;
+                       block->orig_bio_bh_end_io.bh = bh->b_end_io;
+                       block->next_in_same_bio = NULL;
+                       bh->b_private = block;
+                       bh->b_end_io = btrfsic_bh_end_io;
+               }
+       }
+       mutex_unlock(&btrfsic_mutex);
+       return submit_bh(rw, bh);
+}
+
+void btrfsic_submit_bio(int rw, struct bio *bio)
+{
+       struct btrfsic_dev_state *dev_state;
+
+       if (!btrfsic_is_initialized) {
+               submit_bio(rw, bio);
+               return;
+       }
+
+       mutex_lock(&btrfsic_mutex);
+       /* since btrfsic_submit_bio() is also called before
+        * btrfsic_mount(), this might return NULL */
+       dev_state = btrfsic_dev_state_lookup(bio->bi_bdev);
+       if (NULL != dev_state &&
+           (rw & WRITE) && NULL != bio->bi_io_vec) {
+               unsigned int i;
+               u64 dev_bytenr;
+               int bio_is_patched;
+
+               dev_bytenr = 512 * bio->bi_sector;
+               bio_is_patched = 0;
+               if (dev_state->state->print_mask &
+                   BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH)
+                       printk(KERN_INFO
+                              "submit_bio(rw=0x%x, bi_vcnt=%u,"
+                              " bi_sector=%lu (bytenr %llu), bi_bdev=%p)\n",
+                              rw, bio->bi_vcnt, bio->bi_sector,
+                              (unsigned long long)dev_bytenr,
+                              bio->bi_bdev);
+
+               for (i = 0; i < bio->bi_vcnt; i++) {
+                       u8 *mapped_data;
+
+                       mapped_data = kmap(bio->bi_io_vec[i].bv_page);
+                       if ((BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH |
+                            BTRFSIC_PRINT_MASK_VERBOSE) ==
+                           (dev_state->state->print_mask &
+                            (BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH |
+                             BTRFSIC_PRINT_MASK_VERBOSE)))
+                               printk(KERN_INFO
+                                      "#%u: page=%p, mapped=%p, len=%u,"
+                                      " offset=%u\n",
+                                      i, bio->bi_io_vec[i].bv_page,
+                                      mapped_data,
+                                      bio->bi_io_vec[i].bv_len,
+                                      bio->bi_io_vec[i].bv_offset);
+                       btrfsic_process_written_block(dev_state, dev_bytenr,
+                                                     mapped_data,
+                                                     bio->bi_io_vec[i].bv_len,
+                                                     bio, &bio_is_patched,
+                                                     NULL, rw);
+                       kunmap(bio->bi_io_vec[i].bv_page);
+                       dev_bytenr += bio->bi_io_vec[i].bv_len;
+               }
+       } else if (NULL != dev_state && (rw & REQ_FLUSH)) {
+               if (dev_state->state->print_mask &
+                   BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH)
+                       printk(KERN_INFO
+                              "submit_bio(rw=0x%x) FLUSH, bdev=%p)\n",
+                              rw, bio->bi_bdev);
+               if (!dev_state->dummy_block_for_bio_bh_flush.is_iodone) {
+                       if ((dev_state->state->print_mask &
+                            (BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH |
+                             BTRFSIC_PRINT_MASK_VERBOSE)))
+                               printk(KERN_INFO
+                                      "btrfsic_submit_bio(%s) with FLUSH"
+                                      " but dummy block already in use"
+                                      " (ignored)!\n",
+                                      dev_state->name);
+               } else {
+                       struct btrfsic_block *const block =
+                               &dev_state->dummy_block_for_bio_bh_flush;
+
+                       block->is_iodone = 0;
+                       block->never_written = 0;
+                       block->iodone_w_error = 0;
+                       block->flush_gen = dev_state->last_flush_gen + 1;
+                       block->submit_bio_bh_rw = rw;
+                       block->orig_bio_bh_private = bio->bi_private;
+                       block->orig_bio_bh_end_io.bio = bio->bi_end_io;
+                       block->next_in_same_bio = NULL;
+                       bio->bi_private = block;
+                       bio->bi_end_io = btrfsic_bio_end_io;
+               }
+       }
+       mutex_unlock(&btrfsic_mutex);
+
+       submit_bio(rw, bio);
+}
+
+int btrfsic_mount(struct btrfs_root *root,
+                 struct btrfs_fs_devices *fs_devices,
+                 int including_extent_data, u32 print_mask)
+{
+       int ret;
+       struct btrfsic_state *state;
+       struct list_head *dev_head = &fs_devices->devices;
+       struct btrfs_device *device;
+
+       state = kzalloc(sizeof(*state), GFP_NOFS);
+       if (NULL == state) {
+               printk(KERN_INFO "btrfs check-integrity: kmalloc() failed!\n");
+               return -1;
+       }
+
+       if (!btrfsic_is_initialized) {
+               mutex_init(&btrfsic_mutex);
+               btrfsic_dev_state_hashtable_init(&btrfsic_dev_state_hashtable);
+               btrfsic_is_initialized = 1;
+       }
+       mutex_lock(&btrfsic_mutex);
+       state->root = root;
+       state->print_mask = print_mask;
+       state->include_extent_data = including_extent_data;
+       state->csum_size = 0;
+       INIT_LIST_HEAD(&state->all_blocks_list);
+       btrfsic_block_hashtable_init(&state->block_hashtable);
+       btrfsic_block_link_hashtable_init(&state->block_link_hashtable);
+       state->max_superblock_generation = 0;
+       state->latest_superblock = NULL;
+
+       list_for_each_entry(device, dev_head, dev_list) {
+               struct btrfsic_dev_state *ds;
+               char *p;
+
+               if (!device->bdev || !device->name)
+                       continue;
+
+               ds = btrfsic_dev_state_alloc();
+               if (NULL == ds) {
+                       printk(KERN_INFO
+                              "btrfs check-integrity: kmalloc() failed!\n");
+                       mutex_unlock(&btrfsic_mutex);
+                       return -1;
+               }
+               ds->bdev = device->bdev;
+               ds->state = state;
+               bdevname(ds->bdev, ds->name);
+               ds->name[BDEVNAME_SIZE - 1] = '\0';
+               for (p = ds->name; *p != '\0'; p++);
+               while (p > ds->name && *p != '/')
+                       p--;
+               if (*p == '/')
+                       p++;
+               strlcpy(ds->name, p, sizeof(ds->name));
+               btrfsic_dev_state_hashtable_add(ds,
+                                               &btrfsic_dev_state_hashtable);
+       }
+
+       ret = btrfsic_process_superblock(state, fs_devices);
+       if (0 != ret) {
+               mutex_unlock(&btrfsic_mutex);
+               btrfsic_unmount(root, fs_devices);
+               return ret;
+       }
+
+       if (state->print_mask & BTRFSIC_PRINT_MASK_INITIAL_DATABASE)
+               btrfsic_dump_database(state);
+       if (state->print_mask & BTRFSIC_PRINT_MASK_INITIAL_TREE)
+               btrfsic_dump_tree(state);
+
+       mutex_unlock(&btrfsic_mutex);
+       return 0;
+}
+
+void btrfsic_unmount(struct btrfs_root *root,
+                    struct btrfs_fs_devices *fs_devices)
+{
+       struct list_head *elem_all;
+       struct list_head *tmp_all;
+       struct btrfsic_state *state;
+       struct list_head *dev_head = &fs_devices->devices;
+       struct btrfs_device *device;
+
+       if (!btrfsic_is_initialized)
+               return;
+
+       mutex_lock(&btrfsic_mutex);
+
+       state = NULL;
+       list_for_each_entry(device, dev_head, dev_list) {
+               struct btrfsic_dev_state *ds;
+
+               if (!device->bdev || !device->name)
+                       continue;
+
+               ds = btrfsic_dev_state_hashtable_lookup(
+                               device->bdev,
+                               &btrfsic_dev_state_hashtable);
+               if (NULL != ds) {
+                       state = ds->state;
+                       btrfsic_dev_state_hashtable_remove(ds);
+                       btrfsic_dev_state_free(ds);
+               }
+       }
+
+       if (NULL == state) {
+               printk(KERN_INFO
+                      "btrfsic: error, cannot find state information"
+                      " on umount!\n");
+               mutex_unlock(&btrfsic_mutex);
+               return;
+       }
+
+       /*
+        * Don't care about keeping the lists' state up to date,
+        * just free all memory that was allocated dynamically.
+        * Free the blocks and the block_links.
+        */
+       list_for_each_safe(elem_all, tmp_all, &state->all_blocks_list) {
+               struct btrfsic_block *const b_all =
+                   list_entry(elem_all, struct btrfsic_block,
+                              all_blocks_node);
+               struct list_head *elem_ref_to;
+               struct list_head *tmp_ref_to;
+
+               list_for_each_safe(elem_ref_to, tmp_ref_to,
+                                  &b_all->ref_to_list) {
+                       struct btrfsic_block_link *const l =
+                           list_entry(elem_ref_to,
+                                      struct btrfsic_block_link,
+                                      node_ref_to);
+
+                       if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+                               btrfsic_print_rem_link(state, l);
+
+                       l->ref_cnt--;
+                       if (0 == l->ref_cnt)
+                               btrfsic_block_link_free(l);
+               }
+
+               if (b_all->is_iodone)
+                       btrfsic_block_free(b_all);
+               else
+                       printk(KERN_INFO "btrfs: attempt to free %c-block"
+                              " @%llu (%s/%llu/%d) on umount which is"
+                              " not yet iodone!\n",
+                              btrfsic_get_block_type(state, b_all),
+                              (unsigned long long)b_all->logical_bytenr,
+                              b_all->dev_state->name,
+                              (unsigned long long)b_all->dev_bytenr,
+                              b_all->mirror_num);
+       }
+
+       mutex_unlock(&btrfsic_mutex);
+
+       kfree(state);
+}
diff --git a/fs/btrfs/check-integrity.h b/fs/btrfs/check-integrity.h
new file mode 100644 (file)
index 0000000..8b59175
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) STRATO AG 2011.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#if !defined(__BTRFS_CHECK_INTEGRITY__)
+#define __BTRFS_CHECK_INTEGRITY__
+
+#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+int btrfsic_submit_bh(int rw, struct buffer_head *bh);
+void btrfsic_submit_bio(int rw, struct bio *bio);
+#else
+#define btrfsic_submit_bh submit_bh
+#define btrfsic_submit_bio submit_bio
+#endif
+
+int btrfsic_mount(struct btrfs_root *root,
+                 struct btrfs_fs_devices *fs_devices,
+                 int including_extent_data, u32 print_mask);
+void btrfsic_unmount(struct btrfs_root *root,
+                    struct btrfs_fs_devices *fs_devices);
+
+#endif
index dede441bdeee2678225187bece170710abe1a9b4..0639a555e16ed1975702ed5509dc9bc1c4dbf490 100644 (file)
@@ -240,7 +240,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
 
        cow = btrfs_alloc_free_block(trans, root, buf->len, 0,
                                     new_root_objectid, &disk_key, level,
-                                    buf->start, 0);
+                                    buf->start, 0, 1);
        if (IS_ERR(cow))
                return PTR_ERR(cow);
 
@@ -261,9 +261,9 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
 
        WARN_ON(btrfs_header_generation(buf) > trans->transid);
        if (new_root_objectid == BTRFS_TREE_RELOC_OBJECTID)
-               ret = btrfs_inc_ref(trans, root, cow, 1);
+               ret = btrfs_inc_ref(trans, root, cow, 1, 1);
        else
-               ret = btrfs_inc_ref(trans, root, cow, 0);
+               ret = btrfs_inc_ref(trans, root, cow, 0, 1);
 
        if (ret)
                return ret;
@@ -350,14 +350,14 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
                if ((owner == root->root_key.objectid ||
                     root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) &&
                    !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) {
-                       ret = btrfs_inc_ref(trans, root, buf, 1);
+                       ret = btrfs_inc_ref(trans, root, buf, 1, 1);
                        BUG_ON(ret);
 
                        if (root->root_key.objectid ==
                            BTRFS_TREE_RELOC_OBJECTID) {
-                               ret = btrfs_dec_ref(trans, root, buf, 0);
+                               ret = btrfs_dec_ref(trans, root, buf, 0, 1);
                                BUG_ON(ret);
-                               ret = btrfs_inc_ref(trans, root, cow, 1);
+                               ret = btrfs_inc_ref(trans, root, cow, 1, 1);
                                BUG_ON(ret);
                        }
                        new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
@@ -365,9 +365,9 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
 
                        if (root->root_key.objectid ==
                            BTRFS_TREE_RELOC_OBJECTID)
-                               ret = btrfs_inc_ref(trans, root, cow, 1);
+                               ret = btrfs_inc_ref(trans, root, cow, 1, 1);
                        else
-                               ret = btrfs_inc_ref(trans, root, cow, 0);
+                               ret = btrfs_inc_ref(trans, root, cow, 0, 1);
                        BUG_ON(ret);
                }
                if (new_flags != 0) {
@@ -381,11 +381,11 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
                if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
                        if (root->root_key.objectid ==
                            BTRFS_TREE_RELOC_OBJECTID)
-                               ret = btrfs_inc_ref(trans, root, cow, 1);
+                               ret = btrfs_inc_ref(trans, root, cow, 1, 1);
                        else
-                               ret = btrfs_inc_ref(trans, root, cow, 0);
+                               ret = btrfs_inc_ref(trans, root, cow, 0, 1);
                        BUG_ON(ret);
-                       ret = btrfs_dec_ref(trans, root, buf, 1);
+                       ret = btrfs_dec_ref(trans, root, buf, 1, 1);
                        BUG_ON(ret);
                }
                clean_tree_block(trans, root, buf);
@@ -446,7 +446,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
 
        cow = btrfs_alloc_free_block(trans, root, buf->len, parent_start,
                                     root->root_key.objectid, &disk_key,
-                                    level, search_start, empty_size);
+                                    level, search_start, empty_size, 1);
        if (IS_ERR(cow))
                return PTR_ERR(cow);
 
@@ -484,7 +484,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                rcu_assign_pointer(root->node, cow);
 
                btrfs_free_tree_block(trans, root, buf, parent_start,
-                                     last_ref);
+                                     last_ref, 1);
                free_extent_buffer(buf);
                add_root_to_dirty_list(root);
        } else {
@@ -500,7 +500,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                                              trans->transid);
                btrfs_mark_buffer_dirty(parent);
                btrfs_free_tree_block(trans, root, buf, parent_start,
-                                     last_ref);
+                                     last_ref, 1);
        }
        if (unlock_orig)
                btrfs_tree_unlock(buf);
@@ -957,7 +957,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                free_extent_buffer(mid);
 
                root_sub_used(root, mid->len);
-               btrfs_free_tree_block(trans, root, mid, 0, 1);
+               btrfs_free_tree_block(trans, root, mid, 0, 1, 0);
                /* once for the root ptr */
                free_extent_buffer(mid);
                return 0;
@@ -1015,7 +1015,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                        if (wret)
                                ret = wret;
                        root_sub_used(root, right->len);
-                       btrfs_free_tree_block(trans, root, right, 0, 1);
+                       btrfs_free_tree_block(trans, root, right, 0, 1, 0);
                        free_extent_buffer(right);
                        right = NULL;
                } else {
@@ -1055,7 +1055,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                if (wret)
                        ret = wret;
                root_sub_used(root, mid->len);
-               btrfs_free_tree_block(trans, root, mid, 0, 1);
+               btrfs_free_tree_block(trans, root, mid, 0, 1, 0);
                free_extent_buffer(mid);
                mid = NULL;
        } else {
@@ -2089,7 +2089,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
 
        c = btrfs_alloc_free_block(trans, root, root->nodesize, 0,
                                   root->root_key.objectid, &lower_key,
-                                  level, root->node->start, 0);
+                                  level, root->node->start, 0, 0);
        if (IS_ERR(c))
                return PTR_ERR(c);
 
@@ -2216,7 +2216,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
 
        split = btrfs_alloc_free_block(trans, root, root->nodesize, 0,
                                        root->root_key.objectid,
-                                       &disk_key, level, c->start, 0);
+                                       &disk_key, level, c->start, 0, 0);
        if (IS_ERR(split))
                return PTR_ERR(split);
 
@@ -2970,7 +2970,7 @@ again:
 
        right = btrfs_alloc_free_block(trans, root, root->leafsize, 0,
                                        root->root_key.objectid,
-                                       &disk_key, 0, l->start, 0);
+                                       &disk_key, 0, l->start, 0, 0);
        if (IS_ERR(right))
                return PTR_ERR(right);
 
@@ -3781,7 +3781,7 @@ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,
 
        root_sub_used(root, leaf->len);
 
-       btrfs_free_tree_block(trans, root, leaf, 0, 1);
+       btrfs_free_tree_block(trans, root, leaf, 0, 1, 0);
        return 0;
 }
 /*
index 67385033323d6e49817398a1df9b1596df07e839..27ebe61d3cccd0233518d743216dce4b7b8c933f 100644 (file)
@@ -86,6 +86,9 @@ struct btrfs_ordered_sum;
 /* holds checksums of all the data extents */
 #define BTRFS_CSUM_TREE_OBJECTID 7ULL
 
+/* for storing balance parameters in the root tree */
+#define BTRFS_BALANCE_OBJECTID -4ULL
+
 /* orhpan objectid for tracking unlinked/truncated files */
 #define BTRFS_ORPHAN_OBJECTID -5ULL
 
@@ -692,6 +695,54 @@ struct btrfs_root_ref {
        __le16 name_len;
 } __attribute__ ((__packed__));
 
+struct btrfs_disk_balance_args {
+       /*
+        * profiles to operate on, single is denoted by
+        * BTRFS_AVAIL_ALLOC_BIT_SINGLE
+        */
+       __le64 profiles;
+
+       /* usage filter */
+       __le64 usage;
+
+       /* devid filter */
+       __le64 devid;
+
+       /* devid subset filter [pstart..pend) */
+       __le64 pstart;
+       __le64 pend;
+
+       /* btrfs virtual address space subset filter [vstart..vend) */
+       __le64 vstart;
+       __le64 vend;
+
+       /*
+        * profile to convert to, single is denoted by
+        * BTRFS_AVAIL_ALLOC_BIT_SINGLE
+        */
+       __le64 target;
+
+       /* BTRFS_BALANCE_ARGS_* */
+       __le64 flags;
+
+       __le64 unused[8];
+} __attribute__ ((__packed__));
+
+/*
+ * store balance parameters to disk so that balance can be properly
+ * resumed after crash or unmount
+ */
+struct btrfs_balance_item {
+       /* BTRFS_BALANCE_* */
+       __le64 flags;
+
+       struct btrfs_disk_balance_args data;
+       struct btrfs_disk_balance_args meta;
+       struct btrfs_disk_balance_args sys;
+
+       __le64 unused[4];
+} __attribute__ ((__packed__));
+
 #define BTRFS_FILE_EXTENT_INLINE 0
 #define BTRFS_FILE_EXTENT_REG 1
 #define BTRFS_FILE_EXTENT_PREALLOC 2
@@ -751,14 +802,32 @@ struct btrfs_csum_item {
 } __attribute__ ((__packed__));
 
 /* different types of block groups (and chunks) */
-#define BTRFS_BLOCK_GROUP_DATA     (1 << 0)
-#define BTRFS_BLOCK_GROUP_SYSTEM   (1 << 1)
-#define BTRFS_BLOCK_GROUP_METADATA (1 << 2)
-#define BTRFS_BLOCK_GROUP_RAID0    (1 << 3)
-#define BTRFS_BLOCK_GROUP_RAID1    (1 << 4)
-#define BTRFS_BLOCK_GROUP_DUP     (1 << 5)
-#define BTRFS_BLOCK_GROUP_RAID10   (1 << 6)
-#define BTRFS_NR_RAID_TYPES       5
+#define BTRFS_BLOCK_GROUP_DATA         (1ULL << 0)
+#define BTRFS_BLOCK_GROUP_SYSTEM       (1ULL << 1)
+#define BTRFS_BLOCK_GROUP_METADATA     (1ULL << 2)
+#define BTRFS_BLOCK_GROUP_RAID0                (1ULL << 3)
+#define BTRFS_BLOCK_GROUP_RAID1                (1ULL << 4)
+#define BTRFS_BLOCK_GROUP_DUP          (1ULL << 5)
+#define BTRFS_BLOCK_GROUP_RAID10       (1ULL << 6)
+#define BTRFS_BLOCK_GROUP_RESERVED     BTRFS_AVAIL_ALLOC_BIT_SINGLE
+#define BTRFS_NR_RAID_TYPES            5
+
+#define BTRFS_BLOCK_GROUP_TYPE_MASK    (BTRFS_BLOCK_GROUP_DATA |    \
+                                        BTRFS_BLOCK_GROUP_SYSTEM |  \
+                                        BTRFS_BLOCK_GROUP_METADATA)
+
+#define BTRFS_BLOCK_GROUP_PROFILE_MASK (BTRFS_BLOCK_GROUP_RAID0 |   \
+                                        BTRFS_BLOCK_GROUP_RAID1 |   \
+                                        BTRFS_BLOCK_GROUP_DUP |     \
+                                        BTRFS_BLOCK_GROUP_RAID10)
+/*
+ * We need a bit for restriper to be able to tell when chunks of type
+ * SINGLE are available.  This "extended" profile format is used in
+ * fs_info->avail_*_alloc_bits (in-memory) and balance item fields
+ * (on-disk).  The corresponding on-disk bit in chunk.type is reserved
+ * to avoid remappings between two formats in future.
+ */
+#define BTRFS_AVAIL_ALLOC_BIT_SINGLE   (1ULL << 48)
 
 struct btrfs_block_group_item {
        __le64 used;
@@ -916,6 +985,7 @@ struct btrfs_block_group_cache {
 struct reloc_control;
 struct btrfs_device;
 struct btrfs_fs_devices;
+struct btrfs_balance_control;
 struct btrfs_delayed_root;
 struct btrfs_fs_info {
        u8 fsid[BTRFS_FSID_SIZE];
@@ -971,7 +1041,7 @@ struct btrfs_fs_info {
         * is required instead of the faster short fsync log commits
         */
        u64 last_trans_log_full_commit;
-       unsigned long mount_opt:20;
+       unsigned long mount_opt:21;
        unsigned long compress_type:4;
        u64 max_inline;
        u64 alloc_start;
@@ -1132,12 +1202,23 @@ struct btrfs_fs_info {
        spinlock_t ref_cache_lock;
        u64 total_ref_cache_size;
 
+       /*
+        * these three are in extended format (availability of single
+        * chunks is denoted by BTRFS_AVAIL_ALLOC_BIT_SINGLE bit, other
+        * types are denoted by corresponding BTRFS_BLOCK_GROUP_* bits)
+        */
        u64 avail_data_alloc_bits;
        u64 avail_metadata_alloc_bits;
        u64 avail_system_alloc_bits;
-       u64 data_alloc_profile;
-       u64 metadata_alloc_profile;
-       u64 system_alloc_profile;
+
+       /* restriper state */
+       spinlock_t balance_lock;
+       struct mutex balance_mutex;
+       atomic_t balance_running;
+       atomic_t balance_pause_req;
+       atomic_t balance_cancel_req;
+       struct btrfs_balance_control *balance_ctl;
+       wait_queue_head_t balance_wait_q;
 
        unsigned data_chunk_allocations;
        unsigned metadata_ratio;
@@ -1155,6 +1236,10 @@ struct btrfs_fs_info {
        int scrub_workers_refcnt;
        struct btrfs_workers scrub_workers;
 
+#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+       u32 check_integrity_print_mask;
+#endif
+
        /* filesystem state */
        u64 fs_state;
 
@@ -1383,6 +1468,8 @@ struct btrfs_ioctl_defrag_range_args {
 #define BTRFS_DEV_ITEM_KEY     216
 #define BTRFS_CHUNK_ITEM_KEY   228
 
+#define BTRFS_BALANCE_ITEM_KEY 248
+
 /*
  * string items are for debugging.  They just store a short string of
  * data in the FS
@@ -1413,6 +1500,9 @@ struct btrfs_ioctl_defrag_range_args {
 #define BTRFS_MOUNT_AUTO_DEFRAG                (1 << 16)
 #define BTRFS_MOUNT_INODE_MAP_CACHE    (1 << 17)
 #define BTRFS_MOUNT_RECOVERY           (1 << 18)
+#define BTRFS_MOUNT_SKIP_BALANCE       (1 << 19)
+#define BTRFS_MOUNT_CHECK_INTEGRITY    (1 << 20)
+#define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21)
 
 #define btrfs_clear_opt(o, opt)                ((o) &= ~BTRFS_MOUNT_##opt)
 #define btrfs_set_opt(o, opt)          ((o) |= BTRFS_MOUNT_##opt)
@@ -2077,8 +2167,86 @@ BTRFS_SETGET_STACK_FUNCS(backup_bytes_used, struct btrfs_root_backup,
 BTRFS_SETGET_STACK_FUNCS(backup_num_devices, struct btrfs_root_backup,
                   num_devices, 64);
 
-/* struct btrfs_super_block */
+/* struct btrfs_balance_item */
+BTRFS_SETGET_FUNCS(balance_flags, struct btrfs_balance_item, flags, 64);
 
+static inline void btrfs_balance_data(struct extent_buffer *eb,
+                                     struct btrfs_balance_item *bi,
+                                     struct btrfs_disk_balance_args *ba)
+{
+       read_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
+}
+
+static inline void btrfs_set_balance_data(struct extent_buffer *eb,
+                                         struct btrfs_balance_item *bi,
+                                         struct btrfs_disk_balance_args *ba)
+{
+       write_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
+}
+
+static inline void btrfs_balance_meta(struct extent_buffer *eb,
+                                     struct btrfs_balance_item *bi,
+                                     struct btrfs_disk_balance_args *ba)
+{
+       read_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
+}
+
+static inline void btrfs_set_balance_meta(struct extent_buffer *eb,
+                                         struct btrfs_balance_item *bi,
+                                         struct btrfs_disk_balance_args *ba)
+{
+       write_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
+}
+
+static inline void btrfs_balance_sys(struct extent_buffer *eb,
+                                    struct btrfs_balance_item *bi,
+                                    struct btrfs_disk_balance_args *ba)
+{
+       read_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
+}
+
+static inline void btrfs_set_balance_sys(struct extent_buffer *eb,
+                                        struct btrfs_balance_item *bi,
+                                        struct btrfs_disk_balance_args *ba)
+{
+       write_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
+}
+
+static inline void
+btrfs_disk_balance_args_to_cpu(struct btrfs_balance_args *cpu,
+                              struct btrfs_disk_balance_args *disk)
+{
+       memset(cpu, 0, sizeof(*cpu));
+
+       cpu->profiles = le64_to_cpu(disk->profiles);
+       cpu->usage = le64_to_cpu(disk->usage);
+       cpu->devid = le64_to_cpu(disk->devid);
+       cpu->pstart = le64_to_cpu(disk->pstart);
+       cpu->pend = le64_to_cpu(disk->pend);
+       cpu->vstart = le64_to_cpu(disk->vstart);
+       cpu->vend = le64_to_cpu(disk->vend);
+       cpu->target = le64_to_cpu(disk->target);
+       cpu->flags = le64_to_cpu(disk->flags);
+}
+
+static inline void
+btrfs_cpu_balance_args_to_disk(struct btrfs_disk_balance_args *disk,
+                              struct btrfs_balance_args *cpu)
+{
+       memset(disk, 0, sizeof(*disk));
+
+       disk->profiles = cpu_to_le64(cpu->profiles);
+       disk->usage = cpu_to_le64(cpu->usage);
+       disk->devid = cpu_to_le64(cpu->devid);
+       disk->pstart = cpu_to_le64(cpu->pstart);
+       disk->pend = cpu_to_le64(cpu->pend);
+       disk->vstart = cpu_to_le64(cpu->vstart);
+       disk->vend = cpu_to_le64(cpu->vend);
+       disk->target = cpu_to_le64(cpu->target);
+       disk->flags = cpu_to_le64(cpu->flags);
+}
+
+/* struct btrfs_super_block */
 BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
 BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64);
 BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block,
@@ -2196,7 +2364,7 @@ static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb,
        return btrfs_item_size(eb, e) - offset;
 }
 
-static inline struct btrfs_root *btrfs_sb(struct super_block *sb)
+static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb)
 {
        return sb->s_fs_info;
 }
@@ -2277,11 +2445,11 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
                                        struct btrfs_root *root, u32 blocksize,
                                        u64 parent, u64 root_objectid,
                                        struct btrfs_disk_key *key, int level,
-                                       u64 hint, u64 empty_size);
+                                       u64 hint, u64 empty_size, int for_cow);
 void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           struct extent_buffer *buf,
-                          u64 parent, int last_ref);
+                          u64 parent, int last_ref, int for_cow);
 struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
                                            struct btrfs_root *root,
                                            u64 bytenr, u32 blocksize,
@@ -2301,17 +2469,17 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
                                  u64 search_end, struct btrfs_key *ins,
                                  u64 data);
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref);
+                 struct extent_buffer *buf, int full_backref, int for_cow);
 int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref);
+                 struct extent_buffer *buf, int full_backref, int for_cow);
 int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root,
                                u64 bytenr, u64 num_bytes, u64 flags,
                                int is_data);
 int btrfs_free_extent(struct btrfs_trans_handle *trans,
                      struct btrfs_root *root,
-                     u64 bytenr, u64 num_bytes, u64 parent,
-                     u64 root_objectid, u64 owner, u64 offset);
+                     u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid,
+                     u64 owner, u64 offset, int for_cow);
 
 int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len);
 int btrfs_free_and_pin_reserved_extent(struct btrfs_root *root,
@@ -2323,7 +2491,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
 int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                         struct btrfs_root *root,
                         u64 bytenr, u64 num_bytes, u64 parent,
-                        u64 root_objectid, u64 owner, u64 offset);
+                        u64 root_objectid, u64 owner, u64 offset, int for_cow);
 
 int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                                    struct btrfs_root *root);
@@ -2482,10 +2650,18 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
 }
 
 int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
+static inline int btrfs_next_item(struct btrfs_root *root, struct btrfs_path *p)
+{
+       ++p->slots[0];
+       if (p->slots[0] >= btrfs_header_nritems(p->nodes[0]))
+               return btrfs_next_leaf(root, p);
+       return 0;
+}
 int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
 void btrfs_drop_snapshot(struct btrfs_root *root,
-                        struct btrfs_block_rsv *block_rsv, int update_ref);
+                        struct btrfs_block_rsv *block_rsv, int update_ref,
+                        int for_reloc);
 int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        struct extent_buffer *node,
@@ -2500,6 +2676,7 @@ static inline int btrfs_fs_closing(struct btrfs_fs_info *fs_info)
 }
 static inline void free_fs_info(struct btrfs_fs_info *fs_info)
 {
+       kfree(fs_info->balance_ctl);
        kfree(fs_info->delayed_root);
        kfree(fs_info->extent_root);
        kfree(fs_info->tree_root);
@@ -2510,6 +2687,24 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info)
        kfree(fs_info->super_for_commit);
        kfree(fs_info);
 }
+/**
+ * profile_is_valid - tests whether a given profile is valid and reduced
+ * @flags: profile to validate
+ * @extended: if true @flags is treated as an extended profile
+ */
+static inline int profile_is_valid(u64 flags, int extended)
+{
+       u64 mask = ~BTRFS_BLOCK_GROUP_PROFILE_MASK;
+
+       flags &= ~BTRFS_BLOCK_GROUP_TYPE_MASK;
+       if (extended)
+               mask &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
+
+       if (flags & mask)
+               return 0;
+       /* true if zero or exactly one bit set */
+       return (flags & (~flags + 1)) == flags;
+}
 
 /* root-item.c */
 int btrfs_find_root_ref(struct btrfs_root *tree_root,
index 9c1eccc2c503e5eec8bd20d3dfc057a417eef89a..fe4cd0f1cef188b8cf584c67c8ab0f58ffb62cbb 100644 (file)
@@ -595,8 +595,12 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,
 
        num_bytes = btrfs_calc_trans_metadata_size(root, 1);
        ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
-       if (!ret)
+       if (!ret) {
+               trace_btrfs_space_reservation(root->fs_info, "delayed_item",
+                                             item->key.objectid,
+                                             num_bytes, 1);
                item->bytes_reserved = num_bytes;
+       }
 
        return ret;
 }
@@ -610,6 +614,9 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root,
                return;
 
        rsv = &root->fs_info->delayed_block_rsv;
+       trace_btrfs_space_reservation(root->fs_info, "delayed_item",
+                                     item->key.objectid, item->bytes_reserved,
+                                     0);
        btrfs_block_rsv_release(root, rsv,
                                item->bytes_reserved);
 }
@@ -624,7 +631,7 @@ static int btrfs_delayed_inode_reserve_metadata(
        struct btrfs_block_rsv *dst_rsv;
        u64 num_bytes;
        int ret;
-       int release = false;
+       bool release = false;
 
        src_rsv = trans->block_rsv;
        dst_rsv = &root->fs_info->delayed_block_rsv;
@@ -651,8 +658,13 @@ static int btrfs_delayed_inode_reserve_metadata(
                 */
                if (ret == -EAGAIN)
                        ret = -ENOSPC;
-               if (!ret)
+               if (!ret) {
                        node->bytes_reserved = num_bytes;
+                       trace_btrfs_space_reservation(root->fs_info,
+                                                     "delayed_inode",
+                                                     btrfs_ino(inode),
+                                                     num_bytes, 1);
+               }
                return ret;
        } else if (src_rsv == &root->fs_info->delalloc_block_rsv) {
                spin_lock(&BTRFS_I(inode)->lock);
@@ -707,11 +719,17 @@ out:
         * reservation here.  I think it may be time for a documentation page on
         * how block rsvs. work.
         */
-       if (!ret)
+       if (!ret) {
+               trace_btrfs_space_reservation(root->fs_info, "delayed_inode",
+                                             btrfs_ino(inode), num_bytes, 1);
                node->bytes_reserved = num_bytes;
+       }
 
-       if (release)
+       if (release) {
+               trace_btrfs_space_reservation(root->fs_info, "delalloc",
+                                             btrfs_ino(inode), num_bytes, 0);
                btrfs_block_rsv_release(root, src_rsv, num_bytes);
+       }
 
        return ret;
 }
@@ -725,6 +743,8 @@ static void btrfs_delayed_inode_release_metadata(struct btrfs_root *root,
                return;
 
        rsv = &root->fs_info->delayed_block_rsv;
+       trace_btrfs_space_reservation(root->fs_info, "delayed_inode",
+                                     node->inode_id, node->bytes_reserved, 0);
        btrfs_block_rsv_release(root, rsv,
                                node->bytes_reserved);
        node->bytes_reserved = 0;
@@ -1372,13 +1392,6 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
                goto release_node;
        }
 
-       ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item);
-       /*
-        * we have reserved enough space when we start a new transaction,
-        * so reserving metadata failure is impossible
-        */
-       BUG_ON(ret);
-
        delayed_item->key.objectid = btrfs_ino(dir);
        btrfs_set_key_type(&delayed_item->key, BTRFS_DIR_INDEX_KEY);
        delayed_item->key.offset = index;
@@ -1391,6 +1404,14 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
        dir_item->type = type;
        memcpy((char *)(dir_item + 1), name, name_len);
 
+       ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item);
+       /*
+        * we have reserved enough space when we start a new transaction,
+        * so reserving metadata failure is impossible
+        */
+       BUG_ON(ret);
+
+
        mutex_lock(&delayed_node->mutex);
        ret = __btrfs_add_delayed_insertion_item(delayed_node, delayed_item);
        if (unlikely(ret)) {
index 125cf76fcd086803d35bd257bdb54168486e0e0b..66e4f29505a33dbecd45b5d6a80e878c87818bc0 100644 (file)
@@ -101,6 +101,11 @@ static int comp_entry(struct btrfs_delayed_ref_node *ref2,
                return -1;
        if (ref1->type > ref2->type)
                return 1;
+       /* merging of sequenced refs is not allowed */
+       if (ref1->seq < ref2->seq)
+               return -1;
+       if (ref1->seq > ref2->seq)
+               return 1;
        if (ref1->type == BTRFS_TREE_BLOCK_REF_KEY ||
            ref1->type == BTRFS_SHARED_BLOCK_REF_KEY) {
                return comp_tree_refs(btrfs_delayed_node_to_tree_ref(ref2),
@@ -150,16 +155,22 @@ static struct btrfs_delayed_ref_node *tree_insert(struct rb_root *root,
 
 /*
  * find an head entry based on bytenr. This returns the delayed ref
- * head if it was able to find one, or NULL if nothing was in that spot
+ * head if it was able to find one, or NULL if nothing was in that spot.
+ * If return_bigger is given, the next bigger entry is returned if no exact
+ * match is found.
  */
 static struct btrfs_delayed_ref_node *find_ref_head(struct rb_root *root,
                                  u64 bytenr,
-                                 struct btrfs_delayed_ref_node **last)
+                                 struct btrfs_delayed_ref_node **last,
+                                 int return_bigger)
 {
-       struct rb_node *n = root->rb_node;
+       struct rb_node *n;
        struct btrfs_delayed_ref_node *entry;
-       int cmp;
+       int cmp = 0;
 
+again:
+       n = root->rb_node;
+       entry = NULL;
        while (n) {
                entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node);
                WARN_ON(!entry->in_tree);
@@ -182,6 +193,19 @@ static struct btrfs_delayed_ref_node *find_ref_head(struct rb_root *root,
                else
                        return entry;
        }
+       if (entry && return_bigger) {
+               if (cmp > 0) {
+                       n = rb_next(&entry->rb_node);
+                       if (!n)
+                               n = rb_first(root);
+                       entry = rb_entry(n, struct btrfs_delayed_ref_node,
+                                        rb_node);
+                       bytenr = entry->bytenr;
+                       return_bigger = 0;
+                       goto again;
+               }
+               return entry;
+       }
        return NULL;
 }
 
@@ -209,6 +233,24 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
        return 0;
 }
 
+int btrfs_check_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs,
+                           u64 seq)
+{
+       struct seq_list *elem;
+
+       assert_spin_locked(&delayed_refs->lock);
+       if (list_empty(&delayed_refs->seq_head))
+               return 0;
+
+       elem = list_first_entry(&delayed_refs->seq_head, struct seq_list, list);
+       if (seq >= elem->seq) {
+               pr_debug("holding back delayed_ref %llu, lowest is %llu (%p)\n",
+                        seq, elem->seq, delayed_refs);
+               return 1;
+       }
+       return 0;
+}
+
 int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
                           struct list_head *cluster, u64 start)
 {
@@ -223,20 +265,8 @@ int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
                node = rb_first(&delayed_refs->root);
        } else {
                ref = NULL;
-               find_ref_head(&delayed_refs->root, start, &ref);
+               find_ref_head(&delayed_refs->root, start + 1, &ref, 1);
                if (ref) {
-                       struct btrfs_delayed_ref_node *tmp;
-
-                       node = rb_prev(&ref->rb_node);
-                       while (node) {
-                               tmp = rb_entry(node,
-                                              struct btrfs_delayed_ref_node,
-                                              rb_node);
-                               if (tmp->bytenr < start)
-                                       break;
-                               ref = tmp;
-                               node = rb_prev(&ref->rb_node);
-                       }
                        node = &ref->rb_node;
                } else
                        node = rb_first(&delayed_refs->root);
@@ -390,7 +420,8 @@ update_existing_head_ref(struct btrfs_delayed_ref_node *existing,
  * this does all the dirty work in terms of maintaining the correct
  * overall modification count.
  */
-static noinline int add_delayed_ref_head(struct btrfs_trans_handle *trans,
+static noinline int add_delayed_ref_head(struct btrfs_fs_info *fs_info,
+                                       struct btrfs_trans_handle *trans,
                                        struct btrfs_delayed_ref_node *ref,
                                        u64 bytenr, u64 num_bytes,
                                        int action, int is_data)
@@ -437,6 +468,7 @@ static noinline int add_delayed_ref_head(struct btrfs_trans_handle *trans,
        ref->action  = 0;
        ref->is_head = 1;
        ref->in_tree = 1;
+       ref->seq = 0;
 
        head_ref = btrfs_delayed_node_to_head(ref);
        head_ref->must_insert_reserved = must_insert_reserved;
@@ -468,14 +500,17 @@ static noinline int add_delayed_ref_head(struct btrfs_trans_handle *trans,
 /*
  * helper to insert a delayed tree ref into the rbtree.
  */
-static noinline int add_delayed_tree_ref(struct btrfs_trans_handle *trans,
+static noinline int add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
+                                        struct btrfs_trans_handle *trans,
                                         struct btrfs_delayed_ref_node *ref,
                                         u64 bytenr, u64 num_bytes, u64 parent,
-                                        u64 ref_root, int level, int action)
+                                        u64 ref_root, int level, int action,
+                                        int for_cow)
 {
        struct btrfs_delayed_ref_node *existing;
        struct btrfs_delayed_tree_ref *full_ref;
        struct btrfs_delayed_ref_root *delayed_refs;
+       u64 seq = 0;
 
        if (action == BTRFS_ADD_DELAYED_EXTENT)
                action = BTRFS_ADD_DELAYED_REF;
@@ -491,14 +526,17 @@ static noinline int add_delayed_tree_ref(struct btrfs_trans_handle *trans,
        ref->is_head = 0;
        ref->in_tree = 1;
 
+       if (need_ref_seq(for_cow, ref_root))
+               seq = inc_delayed_seq(delayed_refs);
+       ref->seq = seq;
+
        full_ref = btrfs_delayed_node_to_tree_ref(ref);
-       if (parent) {
-               full_ref->parent = parent;
+       full_ref->parent = parent;
+       full_ref->root = ref_root;
+       if (parent)
                ref->type = BTRFS_SHARED_BLOCK_REF_KEY;
-       } else {
-               full_ref->root = ref_root;
+       else
                ref->type = BTRFS_TREE_BLOCK_REF_KEY;
-       }
        full_ref->level = level;
 
        trace_btrfs_delayed_tree_ref(ref, full_ref, action);
@@ -522,15 +560,17 @@ static noinline int add_delayed_tree_ref(struct btrfs_trans_handle *trans,
 /*
  * helper to insert a delayed data ref into the rbtree.
  */
-static noinline int add_delayed_data_ref(struct btrfs_trans_handle *trans,
+static noinline int add_delayed_data_ref(struct btrfs_fs_info *fs_info,
+                                        struct btrfs_trans_handle *trans,
                                         struct btrfs_delayed_ref_node *ref,
                                         u64 bytenr, u64 num_bytes, u64 parent,
                                         u64 ref_root, u64 owner, u64 offset,
-                                        int action)
+                                        int action, int for_cow)
 {
        struct btrfs_delayed_ref_node *existing;
        struct btrfs_delayed_data_ref *full_ref;
        struct btrfs_delayed_ref_root *delayed_refs;
+       u64 seq = 0;
 
        if (action == BTRFS_ADD_DELAYED_EXTENT)
                action = BTRFS_ADD_DELAYED_REF;
@@ -546,14 +586,18 @@ static noinline int add_delayed_data_ref(struct btrfs_trans_handle *trans,
        ref->is_head = 0;
        ref->in_tree = 1;
 
+       if (need_ref_seq(for_cow, ref_root))
+               seq = inc_delayed_seq(delayed_refs);
+       ref->seq = seq;
+
        full_ref = btrfs_delayed_node_to_data_ref(ref);
-       if (parent) {
-               full_ref->parent = parent;
+       full_ref->parent = parent;
+       full_ref->root = ref_root;
+       if (parent)
                ref->type = BTRFS_SHARED_DATA_REF_KEY;
-       } else {
-               full_ref->root = ref_root;
+       else
                ref->type = BTRFS_EXTENT_DATA_REF_KEY;
-       }
+
        full_ref->objectid = owner;
        full_ref->offset = offset;
 
@@ -580,10 +624,12 @@ static noinline int add_delayed_data_ref(struct btrfs_trans_handle *trans,
  * to make sure the delayed ref is eventually processed before this
  * transaction commits.
  */
-int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans,
+int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
+                              struct btrfs_trans_handle *trans,
                               u64 bytenr, u64 num_bytes, u64 parent,
                               u64 ref_root,  int level, int action,
-                              struct btrfs_delayed_extent_op *extent_op)
+                              struct btrfs_delayed_extent_op *extent_op,
+                              int for_cow)
 {
        struct btrfs_delayed_tree_ref *ref;
        struct btrfs_delayed_ref_head *head_ref;
@@ -610,13 +656,17 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans,
         * insert both the head node and the new ref without dropping
         * the spin lock
         */
-       ret = add_delayed_ref_head(trans, &head_ref->node, bytenr, num_bytes,
-                                  action, 0);
+       ret = add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
+                                  num_bytes, action, 0);
        BUG_ON(ret);
 
-       ret = add_delayed_tree_ref(trans, &ref->node, bytenr, num_bytes,
-                                  parent, ref_root, level, action);
+       ret = add_delayed_tree_ref(fs_info, trans, &ref->node, bytenr,
+                                  num_bytes, parent, ref_root, level, action,
+                                  for_cow);
        BUG_ON(ret);
+       if (!need_ref_seq(for_cow, ref_root) &&
+           waitqueue_active(&delayed_refs->seq_wait))
+               wake_up(&delayed_refs->seq_wait);
        spin_unlock(&delayed_refs->lock);
        return 0;
 }
@@ -624,11 +674,13 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans,
 /*
  * add a delayed data ref. it's similar to btrfs_add_delayed_tree_ref.
  */
-int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans,
+int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
+                              struct btrfs_trans_handle *trans,
                               u64 bytenr, u64 num_bytes,
                               u64 parent, u64 ref_root,
                               u64 owner, u64 offset, int action,
-                              struct btrfs_delayed_extent_op *extent_op)
+                              struct btrfs_delayed_extent_op *extent_op,
+                              int for_cow)
 {
        struct btrfs_delayed_data_ref *ref;
        struct btrfs_delayed_ref_head *head_ref;
@@ -655,18 +707,23 @@ int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans,
         * insert both the head node and the new ref without dropping
         * the spin lock
         */
-       ret = add_delayed_ref_head(trans, &head_ref->node, bytenr, num_bytes,
-                                  action, 1);
+       ret = add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
+                                  num_bytes, action, 1);
        BUG_ON(ret);
 
-       ret = add_delayed_data_ref(trans, &ref->node, bytenr, num_bytes,
-                                  parent, ref_root, owner, offset, action);
+       ret = add_delayed_data_ref(fs_info, trans, &ref->node, bytenr,
+                                  num_bytes, parent, ref_root, owner, offset,
+                                  action, for_cow);
        BUG_ON(ret);
+       if (!need_ref_seq(for_cow, ref_root) &&
+           waitqueue_active(&delayed_refs->seq_wait))
+               wake_up(&delayed_refs->seq_wait);
        spin_unlock(&delayed_refs->lock);
        return 0;
 }
 
-int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans,
+int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
+                               struct btrfs_trans_handle *trans,
                                u64 bytenr, u64 num_bytes,
                                struct btrfs_delayed_extent_op *extent_op)
 {
@@ -683,11 +740,13 @@ int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans,
        delayed_refs = &trans->transaction->delayed_refs;
        spin_lock(&delayed_refs->lock);
 
-       ret = add_delayed_ref_head(trans, &head_ref->node, bytenr,
+       ret = add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
                                   num_bytes, BTRFS_UPDATE_DELAYED_HEAD,
                                   extent_op->is_data);
        BUG_ON(ret);
 
+       if (waitqueue_active(&delayed_refs->seq_wait))
+               wake_up(&delayed_refs->seq_wait);
        spin_unlock(&delayed_refs->lock);
        return 0;
 }
@@ -704,7 +763,7 @@ btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr)
        struct btrfs_delayed_ref_root *delayed_refs;
 
        delayed_refs = &trans->transaction->delayed_refs;
-       ref = find_ref_head(&delayed_refs->root, bytenr, NULL);
+       ref = find_ref_head(&delayed_refs->root, bytenr, NULL, 0);
        if (ref)
                return btrfs_delayed_node_to_head(ref);
        return NULL;
index e287e3b0eab0d970d37f0f4c70fd688b22f276ac..d8f244d9492511e3b108b26bcf4da1bc9fbf6826 100644 (file)
@@ -33,6 +33,9 @@ struct btrfs_delayed_ref_node {
        /* the size of the extent */
        u64 num_bytes;
 
+       /* seq number to keep track of insertion order */
+       u64 seq;
+
        /* ref count on this data structure */
        atomic_t refs;
 
@@ -98,19 +101,15 @@ struct btrfs_delayed_ref_head {
 
 struct btrfs_delayed_tree_ref {
        struct btrfs_delayed_ref_node node;
-       union {
-               u64 root;
-               u64 parent;
-       };
+       u64 root;
+       u64 parent;
        int level;
 };
 
 struct btrfs_delayed_data_ref {
        struct btrfs_delayed_ref_node node;
-       union {
-               u64 root;
-               u64 parent;
-       };
+       u64 root;
+       u64 parent;
        u64 objectid;
        u64 offset;
 };
@@ -140,6 +139,26 @@ struct btrfs_delayed_ref_root {
        int flushing;
 
        u64 run_delayed_start;
+
+       /*
+        * seq number of delayed refs. We need to know if a backref was being
+        * added before the currently processed ref or afterwards.
+        */
+       u64 seq;
+
+       /*
+        * seq_list holds a list of all seq numbers that are currently being
+        * added to the list. While walking backrefs (btrfs_find_all_roots,
+        * qgroups), which might take some time, no newer ref must be processed,
+        * as it might influence the outcome of the walk.
+        */
+       struct list_head seq_head;
+
+       /*
+        * when the only refs we have in the list must not be processed, we want
+        * to wait for more refs to show up or for the end of backref walking.
+        */
+       wait_queue_head_t seq_wait;
 };
 
 static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref)
@@ -151,16 +170,21 @@ static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref)
        }
 }
 
-int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans,
+int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
+                              struct btrfs_trans_handle *trans,
                               u64 bytenr, u64 num_bytes, u64 parent,
                               u64 ref_root, int level, int action,
-                              struct btrfs_delayed_extent_op *extent_op);
-int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans,
+                              struct btrfs_delayed_extent_op *extent_op,
+                              int for_cow);
+int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
+                              struct btrfs_trans_handle *trans,
                               u64 bytenr, u64 num_bytes,
                               u64 parent, u64 ref_root,
                               u64 owner, u64 offset, int action,
-                              struct btrfs_delayed_extent_op *extent_op);
-int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans,
+                              struct btrfs_delayed_extent_op *extent_op,
+                              int for_cow);
+int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
+                               struct btrfs_trans_handle *trans,
                                u64 bytenr, u64 num_bytes,
                                struct btrfs_delayed_extent_op *extent_op);
 
@@ -170,6 +194,60 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
                           struct btrfs_delayed_ref_head *head);
 int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
                           struct list_head *cluster, u64 search_start);
+
+struct seq_list {
+       struct list_head list;
+       u64 seq;
+};
+
+static inline u64 inc_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs)
+{
+       assert_spin_locked(&delayed_refs->lock);
+       ++delayed_refs->seq;
+       return delayed_refs->seq;
+}
+
+static inline void
+btrfs_get_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs,
+                     struct seq_list *elem)
+{
+       assert_spin_locked(&delayed_refs->lock);
+       elem->seq = delayed_refs->seq;
+       list_add_tail(&elem->list, &delayed_refs->seq_head);
+}
+
+static inline void
+btrfs_put_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs,
+                     struct seq_list *elem)
+{
+       spin_lock(&delayed_refs->lock);
+       list_del(&elem->list);
+       wake_up(&delayed_refs->seq_wait);
+       spin_unlock(&delayed_refs->lock);
+}
+
+int btrfs_check_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs,
+                           u64 seq);
+
+/*
+ * delayed refs with a ref_seq > 0 must be held back during backref walking.
+ * this only applies to items in one of the fs-trees. for_cow items never need
+ * to be held back, so they won't get a ref_seq number.
+ */
+static inline int need_ref_seq(int for_cow, u64 rootid)
+{
+       if (for_cow)
+               return 0;
+
+       if (rootid == BTRFS_FS_TREE_OBJECTID)
+               return 1;
+
+       if ((s64)rootid >= (s64)BTRFS_FIRST_FREE_OBJECTID)
+               return 1;
+
+       return 0;
+}
+
 /*
  * a node might live in a head or a regular ref, this lets you
  * test for the proper type to use.
index f99a099a7747fd4ff2b0584a3f689d33a52136ab..7aa9cd36bf1b496efd2a02e7cc86c1a08a29c663 100644 (file)
@@ -43,6 +43,7 @@
 #include "tree-log.h"
 #include "free-space-cache.h"
 #include "inode-map.h"
+#include "check-integrity.h"
 
 static struct extent_io_ops btree_extent_io_ops;
 static void end_workqueue_fn(struct btrfs_work *work);
@@ -872,7 +873,8 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
 
 #ifdef CONFIG_MIGRATION
 static int btree_migratepage(struct address_space *mapping,
-                       struct page *newpage, struct page *page)
+                       struct page *newpage, struct page *page,
+                       enum migrate_mode mode)
 {
        /*
         * we can't safely write a btree page from here,
@@ -887,7 +889,7 @@ static int btree_migratepage(struct address_space *mapping,
        if (page_has_private(page) &&
            !try_to_release_page(page, GFP_KERNEL))
                return -EAGAIN;
-       return migrate_page(mapping, newpage, page);
+       return migrate_page(mapping, newpage, page, mode);
 }
 #endif
 
@@ -1142,7 +1144,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        root->orphan_item_inserted = 0;
        root->orphan_cleanup_state = 0;
 
-       root->fs_info = fs_info;
        root->objectid = objectid;
        root->last_trans = 0;
        root->highest_objectid = 0;
@@ -1216,6 +1217,14 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
        return 0;
 }
 
+static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_root *root = kzalloc(sizeof(*root), GFP_NOFS);
+       if (root)
+               root->fs_info = fs_info;
+       return root;
+}
+
 static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
                                         struct btrfs_fs_info *fs_info)
 {
@@ -1223,7 +1232,7 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
        struct btrfs_root *tree_root = fs_info->tree_root;
        struct extent_buffer *leaf;
 
-       root = kzalloc(sizeof(*root), GFP_NOFS);
+       root = btrfs_alloc_root(fs_info);
        if (!root)
                return ERR_PTR(-ENOMEM);
 
@@ -1243,7 +1252,8 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
        root->ref_cows = 0;
 
        leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0,
-                                     BTRFS_TREE_LOG_OBJECTID, NULL, 0, 0, 0);
+                                     BTRFS_TREE_LOG_OBJECTID, NULL,
+                                     0, 0, 0, 0);
        if (IS_ERR(leaf)) {
                kfree(root);
                return ERR_CAST(leaf);
@@ -1317,7 +1327,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
        u32 blocksize;
        int ret = 0;
 
-       root = kzalloc(sizeof(*root), GFP_NOFS);
+       root = btrfs_alloc_root(fs_info);
        if (!root)
                return ERR_PTR(-ENOMEM);
        if (location->offset == (u64)-1) {
@@ -1873,9 +1883,9 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
 }
 
 
-struct btrfs_root *open_ctree(struct super_block *sb,
-                             struct btrfs_fs_devices *fs_devices,
-                             char *options)
+int open_ctree(struct super_block *sb,
+              struct btrfs_fs_devices *fs_devices,
+              char *options)
 {
        u32 sectorsize;
        u32 nodesize;
@@ -1887,8 +1897,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        struct btrfs_key location;
        struct buffer_head *bh;
        struct btrfs_super_block *disk_super;
-       struct btrfs_root *tree_root = btrfs_sb(sb);
-       struct btrfs_fs_info *fs_info = tree_root->fs_info;
+       struct btrfs_fs_info *fs_info = btrfs_sb(sb);
+       struct btrfs_root *tree_root;
        struct btrfs_root *extent_root;
        struct btrfs_root *csum_root;
        struct btrfs_root *chunk_root;
@@ -1899,16 +1909,14 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        int num_backups_tried = 0;
        int backup_index = 0;
 
-       extent_root = fs_info->extent_root =
-               kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
-       csum_root = fs_info->csum_root =
-               kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
-       chunk_root = fs_info->chunk_root =
-               kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
-       dev_root = fs_info->dev_root =
-               kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
+       tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info);
+       extent_root = fs_info->extent_root = btrfs_alloc_root(fs_info);
+       csum_root = fs_info->csum_root = btrfs_alloc_root(fs_info);
+       chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info);
+       dev_root = fs_info->dev_root = btrfs_alloc_root(fs_info);
 
-       if (!extent_root || !csum_root || !chunk_root || !dev_root) {
+       if (!tree_root || !extent_root || !csum_root ||
+           !chunk_root || !dev_root) {
                err = -ENOMEM;
                goto fail;
        }
@@ -1997,6 +2005,17 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        init_waitqueue_head(&fs_info->scrub_pause_wait);
        init_rwsem(&fs_info->scrub_super_lock);
        fs_info->scrub_workers_refcnt = 0;
+#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+       fs_info->check_integrity_print_mask = 0;
+#endif
+
+       spin_lock_init(&fs_info->balance_lock);
+       mutex_init(&fs_info->balance_mutex);
+       atomic_set(&fs_info->balance_running, 0);
+       atomic_set(&fs_info->balance_pause_req, 0);
+       atomic_set(&fs_info->balance_cancel_req, 0);
+       fs_info->balance_ctl = NULL;
+       init_waitqueue_head(&fs_info->balance_wait_q);
 
        sb->s_blocksize = 4096;
        sb->s_blocksize_bits = blksize_bits(4096);
@@ -2266,9 +2285,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
           (unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node),
           BTRFS_UUID_SIZE);
 
-       mutex_lock(&fs_info->chunk_mutex);
        ret = btrfs_read_chunk_tree(chunk_root);
-       mutex_unlock(&fs_info->chunk_mutex);
        if (ret) {
                printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n",
                       sb->s_id);
@@ -2317,9 +2334,6 @@ retry_root_backup:
 
        fs_info->generation = generation;
        fs_info->last_trans_committed = generation;
-       fs_info->data_alloc_profile = (u64)-1;
-       fs_info->metadata_alloc_profile = (u64)-1;
-       fs_info->system_alloc_profile = fs_info->metadata_alloc_profile;
 
        ret = btrfs_init_space_info(fs_info);
        if (ret) {
@@ -2352,6 +2366,19 @@ retry_root_backup:
                btrfs_set_opt(fs_info->mount_opt, SSD);
        }
 
+#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+       if (btrfs_test_opt(tree_root, CHECK_INTEGRITY)) {
+               ret = btrfsic_mount(tree_root, fs_devices,
+                                   btrfs_test_opt(tree_root,
+                                       CHECK_INTEGRITY_INCLUDING_EXTENT_DATA) ?
+                                   1 : 0,
+                                   fs_info->check_integrity_print_mask);
+               if (ret)
+                       printk(KERN_WARNING "btrfs: failed to initialize"
+                              " integrity check module %s\n", sb->s_id);
+       }
+#endif
+
        /* do not make disk changes in broken FS */
        if (btrfs_super_log_root(disk_super) != 0 &&
            !(fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)) {
@@ -2367,7 +2394,7 @@ retry_root_backup:
                     btrfs_level_size(tree_root,
                                      btrfs_super_log_root_level(disk_super));
 
-               log_tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
+               log_tree_root = btrfs_alloc_root(fs_info);
                if (!log_tree_root) {
                        err = -ENOMEM;
                        goto fail_trans_kthread;
@@ -2422,13 +2449,17 @@ retry_root_backup:
                if (!err)
                        err = btrfs_orphan_cleanup(fs_info->tree_root);
                up_read(&fs_info->cleanup_work_sem);
+
+               if (!err)
+                       err = btrfs_recover_balance(fs_info->tree_root);
+
                if (err) {
                        close_ctree(tree_root);
-                       return ERR_PTR(err);
+                       return err;
                }
        }
 
-       return tree_root;
+       return 0;
 
 fail_trans_kthread:
        kthread_stop(fs_info->transaction_kthread);
@@ -2474,8 +2505,7 @@ fail_srcu:
        cleanup_srcu_struct(&fs_info->subvol_srcu);
 fail:
        btrfs_close_devices(fs_info->fs_devices);
-       free_fs_info(fs_info);
-       return ERR_PTR(err);
+       return err;
 
 recovery_tree_root:
        if (!btrfs_test_opt(tree_root, RECOVERY))
@@ -2630,7 +2660,7 @@ static int write_dev_supers(struct btrfs_device *device,
                 * we fua the first super.  The others we allow
                 * to go down lazy.
                 */
-               ret = submit_bh(WRITE_FUA, bh);
+               ret = btrfsic_submit_bh(WRITE_FUA, bh);
                if (ret)
                        errors++;
        }
@@ -2707,7 +2737,7 @@ static int write_dev_flush(struct btrfs_device *device, int wait)
        device->flush_bio = bio;
 
        bio_get(bio);
-       submit_bio(WRITE_FLUSH, bio);
+       btrfsic_submit_bio(WRITE_FLUSH, bio);
 
        return 0;
 }
@@ -2971,6 +3001,9 @@ int close_ctree(struct btrfs_root *root)
        fs_info->closing = 1;
        smp_mb();
 
+       /* pause restriper - we want to resume on mount */
+       btrfs_pause_balance(root->fs_info);
+
        btrfs_scrub_cancel(root);
 
        /* wait for any defraggers to finish */
@@ -2978,7 +3011,7 @@ int close_ctree(struct btrfs_root *root)
                   (atomic_read(&fs_info->defrag_running) == 0));
 
        /* clear out the rbtree of defraggable inodes */
-       btrfs_run_defrag_inodes(root->fs_info);
+       btrfs_run_defrag_inodes(fs_info);
 
        /*
         * Here come 2 situations when btrfs is broken to flip readonly:
@@ -3007,8 +3040,8 @@ int close_ctree(struct btrfs_root *root)
 
        btrfs_put_block_group_cache(fs_info);
 
-       kthread_stop(root->fs_info->transaction_kthread);
-       kthread_stop(root->fs_info->cleaner_kthread);
+       kthread_stop(fs_info->transaction_kthread);
+       kthread_stop(fs_info->cleaner_kthread);
 
        fs_info->closing = 2;
        smp_mb();
@@ -3026,14 +3059,14 @@ int close_ctree(struct btrfs_root *root)
        free_extent_buffer(fs_info->extent_root->commit_root);
        free_extent_buffer(fs_info->tree_root->node);
        free_extent_buffer(fs_info->tree_root->commit_root);
-       free_extent_buffer(root->fs_info->chunk_root->node);
-       free_extent_buffer(root->fs_info->chunk_root->commit_root);
-       free_extent_buffer(root->fs_info->dev_root->node);
-       free_extent_buffer(root->fs_info->dev_root->commit_root);
-       free_extent_buffer(root->fs_info->csum_root->node);
-       free_extent_buffer(root->fs_info->csum_root->commit_root);
+       free_extent_buffer(fs_info->chunk_root->node);
+       free_extent_buffer(fs_info->chunk_root->commit_root);
+       free_extent_buffer(fs_info->dev_root->node);
+       free_extent_buffer(fs_info->dev_root->commit_root);
+       free_extent_buffer(fs_info->csum_root->node);
+       free_extent_buffer(fs_info->csum_root->commit_root);
 
-       btrfs_free_block_groups(root->fs_info);
+       btrfs_free_block_groups(fs_info);
 
        del_fs_roots(fs_info);
 
@@ -3053,14 +3086,17 @@ int close_ctree(struct btrfs_root *root)
        btrfs_stop_workers(&fs_info->caching_workers);
        btrfs_stop_workers(&fs_info->readahead_workers);
 
+#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+       if (btrfs_test_opt(root, CHECK_INTEGRITY))
+               btrfsic_unmount(root, fs_info->fs_devices);
+#endif
+
        btrfs_close_devices(fs_info->fs_devices);
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
 
        bdi_destroy(&fs_info->bdi);
        cleanup_srcu_struct(&fs_info->subvol_srcu);
 
-       free_fs_info(fs_info);
-
        return 0;
 }
 
index c99d0a8f13fa2f38642f7826cb00c45070ac95ae..e4bc4741319bd3a1e094de03566feeb360d35e4d 100644 (file)
@@ -46,9 +46,9 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
                                                   u64 bytenr, u32 blocksize);
 int clean_tree_block(struct btrfs_trans_handle *trans,
                     struct btrfs_root *root, struct extent_buffer *buf);
-struct btrfs_root *open_ctree(struct super_block *sb,
-                             struct btrfs_fs_devices *fs_devices,
-                             char *options);
+int open_ctree(struct super_block *sb,
+              struct btrfs_fs_devices *fs_devices,
+              char *options);
 int close_ctree(struct btrfs_root *root);
 int write_ctree_super(struct btrfs_trans_handle *trans,
                      struct btrfs_root *root, int max_mirrors);
index 1b8dc33778f9c411206cc6ad9467546412431947..5f77166fd01c7eb3d33cb78666e31822fc0a1083 100644 (file)
@@ -67,7 +67,7 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
                                       u64 root_objectid, u32 generation,
                                       int check_generation)
 {
-       struct btrfs_fs_info *fs_info = btrfs_sb(sb)->fs_info;
+       struct btrfs_fs_info *fs_info = btrfs_sb(sb);
        struct btrfs_root *root;
        struct inode *inode;
        struct btrfs_key key;
index f5fbe576d2baf48519a01bd449344b49edffa070..700879ed64cfcc73f43f6e03819e579578db1e57 100644 (file)
@@ -618,8 +618,7 @@ static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info,
        struct list_head *head = &info->space_info;
        struct btrfs_space_info *found;
 
-       flags &= BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_SYSTEM |
-                BTRFS_BLOCK_GROUP_METADATA;
+       flags &= BTRFS_BLOCK_GROUP_TYPE_MASK;
 
        rcu_read_lock();
        list_for_each_entry_rcu(found, head, list) {
@@ -1872,20 +1871,24 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
 int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                         struct btrfs_root *root,
                         u64 bytenr, u64 num_bytes, u64 parent,
-                        u64 root_objectid, u64 owner, u64 offset)
+                        u64 root_objectid, u64 owner, u64 offset, int for_cow)
 {
        int ret;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+
        BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID &&
               root_objectid == BTRFS_TREE_LOG_OBJECTID);
 
        if (owner < BTRFS_FIRST_FREE_OBJECTID) {
-               ret = btrfs_add_delayed_tree_ref(trans, bytenr, num_bytes,
+               ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr,
+                                       num_bytes,
                                        parent, root_objectid, (int)owner,
-                                       BTRFS_ADD_DELAYED_REF, NULL);
+                                       BTRFS_ADD_DELAYED_REF, NULL, for_cow);
        } else {
-               ret = btrfs_add_delayed_data_ref(trans, bytenr, num_bytes,
+               ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
+                                       num_bytes,
                                        parent, root_objectid, owner, offset,
-                                       BTRFS_ADD_DELAYED_REF, NULL);
+                                       BTRFS_ADD_DELAYED_REF, NULL, for_cow);
        }
        return ret;
 }
@@ -2232,6 +2235,28 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                        }
                }
 
+               /*
+                * locked_ref is the head node, so we have to go one
+                * node back for any delayed ref updates
+                */
+               ref = select_delayed_ref(locked_ref);
+
+               if (ref && ref->seq &&
+                   btrfs_check_delayed_seq(delayed_refs, ref->seq)) {
+                       /*
+                        * there are still refs with lower seq numbers in the
+                        * process of being added. Don't run this ref yet.
+                        */
+                       list_del_init(&locked_ref->cluster);
+                       mutex_unlock(&locked_ref->mutex);
+                       locked_ref = NULL;
+                       delayed_refs->num_heads_ready++;
+                       spin_unlock(&delayed_refs->lock);
+                       cond_resched();
+                       spin_lock(&delayed_refs->lock);
+                       continue;
+               }
+
                /*
                 * record the must insert reserved flag before we
                 * drop the spin lock.
@@ -2242,11 +2267,6 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                extent_op = locked_ref->extent_op;
                locked_ref->extent_op = NULL;
 
-               /*
-                * locked_ref is the head node, so we have to go one
-                * node back for any delayed ref updates
-                */
-               ref = select_delayed_ref(locked_ref);
                if (!ref) {
                        /* All delayed refs have been processed, Go ahead
                         * and send the head node to run_one_delayed_ref,
@@ -2267,9 +2287,7 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                                BUG_ON(ret);
                                kfree(extent_op);
 
-                               cond_resched();
-                               spin_lock(&delayed_refs->lock);
-                               continue;
+                               goto next;
                        }
 
                        list_del_init(&locked_ref->cluster);
@@ -2279,7 +2297,12 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                ref->in_tree = 0;
                rb_erase(&ref->rb_node, &delayed_refs->root);
                delayed_refs->num_entries--;
-
+               /*
+                * we modified num_entries, but as we're currently running
+                * delayed refs, skip
+                *     wake_up(&delayed_refs->seq_wait);
+                * here.
+                */
                spin_unlock(&delayed_refs->lock);
 
                ret = run_one_delayed_ref(trans, root, ref, extent_op,
@@ -2289,13 +2312,34 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                btrfs_put_delayed_ref(ref);
                kfree(extent_op);
                count++;
-
+next:
+               do_chunk_alloc(trans, root->fs_info->extent_root,
+                              2 * 1024 * 1024,
+                              btrfs_get_alloc_profile(root, 0),
+                              CHUNK_ALLOC_NO_FORCE);
                cond_resched();
                spin_lock(&delayed_refs->lock);
        }
        return count;
 }
 
+
+static void wait_for_more_refs(struct btrfs_delayed_ref_root *delayed_refs,
+                       unsigned long num_refs)
+{
+       struct list_head *first_seq = delayed_refs->seq_head.next;
+
+       spin_unlock(&delayed_refs->lock);
+       pr_debug("waiting for more refs (num %ld, first %p)\n",
+                num_refs, first_seq);
+       wait_event(delayed_refs->seq_wait,
+                  num_refs != delayed_refs->num_entries ||
+                  delayed_refs->seq_head.next != first_seq);
+       pr_debug("done waiting for more refs (num %ld, first %p)\n",
+                delayed_refs->num_entries, delayed_refs->seq_head.next);
+       spin_lock(&delayed_refs->lock);
+}
+
 /*
  * this starts processing the delayed reference count updates and
  * extent insertions we have queued up so far.  count can be
@@ -2311,15 +2355,23 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
        struct btrfs_delayed_ref_node *ref;
        struct list_head cluster;
        int ret;
+       u64 delayed_start;
        int run_all = count == (unsigned long)-1;
        int run_most = 0;
+       unsigned long num_refs = 0;
+       int consider_waiting;
 
        if (root == root->fs_info->extent_root)
                root = root->fs_info->tree_root;
 
+       do_chunk_alloc(trans, root->fs_info->extent_root,
+                      2 * 1024 * 1024, btrfs_get_alloc_profile(root, 0),
+                      CHUNK_ALLOC_NO_FORCE);
+
        delayed_refs = &trans->transaction->delayed_refs;
        INIT_LIST_HEAD(&cluster);
 again:
+       consider_waiting = 0;
        spin_lock(&delayed_refs->lock);
        if (count == 0) {
                count = delayed_refs->num_entries * 2;
@@ -2336,11 +2388,35 @@ again:
                 * of refs to process starting at the first one we are able to
                 * lock
                 */
+               delayed_start = delayed_refs->run_delayed_start;
                ret = btrfs_find_ref_cluster(trans, &cluster,
                                             delayed_refs->run_delayed_start);
                if (ret)
                        break;
 
+               if (delayed_start >= delayed_refs->run_delayed_start) {
+                       if (consider_waiting == 0) {
+                               /*
+                                * btrfs_find_ref_cluster looped. let's do one
+                                * more cycle. if we don't run any delayed ref
+                                * during that cycle (because we can't because
+                                * all of them are blocked) and if the number of
+                                * refs doesn't change, we avoid busy waiting.
+                                */
+                               consider_waiting = 1;
+                               num_refs = delayed_refs->num_entries;
+                       } else {
+                               wait_for_more_refs(delayed_refs, num_refs);
+                               /*
+                                * after waiting, things have changed. we
+                                * dropped the lock and someone else might have
+                                * run some refs, built new clusters and so on.
+                                * therefore, we restart staleness detection.
+                                */
+                               consider_waiting = 0;
+                       }
+               }
+
                ret = run_clustered_refs(trans, root, &cluster);
                BUG_ON(ret < 0);
 
@@ -2348,6 +2424,11 @@ again:
 
                if (count == 0)
                        break;
+
+               if (ret || delayed_refs->run_delayed_start == 0) {
+                       /* refs were run, let's reset staleness detection */
+                       consider_waiting = 0;
+               }
        }
 
        if (run_all) {
@@ -2405,7 +2486,8 @@ int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans,
        extent_op->update_key = 0;
        extent_op->is_data = is_data ? 1 : 0;
 
-       ret = btrfs_add_delayed_extent_op(trans, bytenr, num_bytes, extent_op);
+       ret = btrfs_add_delayed_extent_op(root->fs_info, trans, bytenr,
+                                         num_bytes, extent_op);
        if (ret)
                kfree(extent_op);
        return ret;
@@ -2590,7 +2672,7 @@ out:
 static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           struct extent_buffer *buf,
-                          int full_backref, int inc)
+                          int full_backref, int inc, int for_cow)
 {
        u64 bytenr;
        u64 num_bytes;
@@ -2603,7 +2685,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
        int level;
        int ret = 0;
        int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *,
-                           u64, u64, u64, u64, u64, u64);
+                           u64, u64, u64, u64, u64, u64, int);
 
        ref_root = btrfs_header_owner(buf);
        nritems = btrfs_header_nritems(buf);
@@ -2640,14 +2722,15 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                        key.offset -= btrfs_file_extent_offset(buf, fi);
                        ret = process_func(trans, root, bytenr, num_bytes,
                                           parent, ref_root, key.objectid,
-                                          key.offset);
+                                          key.offset, for_cow);
                        if (ret)
                                goto fail;
                } else {
                        bytenr = btrfs_node_blockptr(buf, i);
                        num_bytes = btrfs_level_size(root, level - 1);
                        ret = process_func(trans, root, bytenr, num_bytes,
-                                          parent, ref_root, level - 1, 0);
+                                          parent, ref_root, level - 1, 0,
+                                          for_cow);
                        if (ret)
                                goto fail;
                }
@@ -2659,15 +2742,15 @@ fail:
 }
 
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref)
+                 struct extent_buffer *buf, int full_backref, int for_cow)
 {
-       return __btrfs_mod_ref(trans, root, buf, full_backref, 1);
+       return __btrfs_mod_ref(trans, root, buf, full_backref, 1, for_cow);
 }
 
 int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref)
+                 struct extent_buffer *buf, int full_backref, int for_cow)
 {
-       return __btrfs_mod_ref(trans, root, buf, full_backref, 0);
+       return __btrfs_mod_ref(trans, root, buf, full_backref, 0, for_cow);
 }
 
 static int write_one_cache_group(struct btrfs_trans_handle *trans,
@@ -2993,9 +3076,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
                INIT_LIST_HEAD(&found->block_groups[i]);
        init_rwsem(&found->groups_sem);
        spin_lock_init(&found->lock);
-       found->flags = flags & (BTRFS_BLOCK_GROUP_DATA |
-                               BTRFS_BLOCK_GROUP_SYSTEM |
-                               BTRFS_BLOCK_GROUP_METADATA);
+       found->flags = flags & BTRFS_BLOCK_GROUP_TYPE_MASK;
        found->total_bytes = total_bytes;
        found->disk_total = total_bytes * factor;
        found->bytes_used = bytes_used;
@@ -3016,20 +3097,27 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
 
 static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
 {
-       u64 extra_flags = flags & (BTRFS_BLOCK_GROUP_RAID0 |
-                                  BTRFS_BLOCK_GROUP_RAID1 |
-                                  BTRFS_BLOCK_GROUP_RAID10 |
-                                  BTRFS_BLOCK_GROUP_DUP);
-       if (extra_flags) {
-               if (flags & BTRFS_BLOCK_GROUP_DATA)
-                       fs_info->avail_data_alloc_bits |= extra_flags;
-               if (flags & BTRFS_BLOCK_GROUP_METADATA)
-                       fs_info->avail_metadata_alloc_bits |= extra_flags;
-               if (flags & BTRFS_BLOCK_GROUP_SYSTEM)
-                       fs_info->avail_system_alloc_bits |= extra_flags;
-       }
+       u64 extra_flags = flags & BTRFS_BLOCK_GROUP_PROFILE_MASK;
+
+       /* chunk -> extended profile */
+       if (extra_flags == 0)
+               extra_flags = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
+
+       if (flags & BTRFS_BLOCK_GROUP_DATA)
+               fs_info->avail_data_alloc_bits |= extra_flags;
+       if (flags & BTRFS_BLOCK_GROUP_METADATA)
+               fs_info->avail_metadata_alloc_bits |= extra_flags;
+       if (flags & BTRFS_BLOCK_GROUP_SYSTEM)
+               fs_info->avail_system_alloc_bits |= extra_flags;
 }
 
+/*
+ * @flags: available profiles in extended format (see ctree.h)
+ *
+ * Returns reduced profile in chunk format.  If profile changing is in
+ * progress (either running or paused) picks the target profile (if it's
+ * already available), otherwise falls back to plain reducing.
+ */
 u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
 {
        /*
@@ -3040,6 +3128,34 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
        u64 num_devices = root->fs_info->fs_devices->rw_devices +
                root->fs_info->fs_devices->missing_devices;
 
+       /* pick restriper's target profile if it's available */
+       spin_lock(&root->fs_info->balance_lock);
+       if (root->fs_info->balance_ctl) {
+               struct btrfs_balance_control *bctl = root->fs_info->balance_ctl;
+               u64 tgt = 0;
+
+               if ((flags & BTRFS_BLOCK_GROUP_DATA) &&
+                   (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
+                   (flags & bctl->data.target)) {
+                       tgt = BTRFS_BLOCK_GROUP_DATA | bctl->data.target;
+               } else if ((flags & BTRFS_BLOCK_GROUP_SYSTEM) &&
+                          (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
+                          (flags & bctl->sys.target)) {
+                       tgt = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target;
+               } else if ((flags & BTRFS_BLOCK_GROUP_METADATA) &&
+                          (bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
+                          (flags & bctl->meta.target)) {
+                       tgt = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target;
+               }
+
+               if (tgt) {
+                       spin_unlock(&root->fs_info->balance_lock);
+                       flags = tgt;
+                       goto out;
+               }
+       }
+       spin_unlock(&root->fs_info->balance_lock);
+
        if (num_devices == 1)
                flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0);
        if (num_devices < 4)
@@ -3059,22 +3175,25 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
        if ((flags & BTRFS_BLOCK_GROUP_RAID0) &&
            ((flags & BTRFS_BLOCK_GROUP_RAID1) |
             (flags & BTRFS_BLOCK_GROUP_RAID10) |
-            (flags & BTRFS_BLOCK_GROUP_DUP)))
+            (flags & BTRFS_BLOCK_GROUP_DUP))) {
                flags &= ~BTRFS_BLOCK_GROUP_RAID0;
+       }
+
+out:
+       /* extended -> chunk profile */
+       flags &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
        return flags;
 }
 
 static u64 get_alloc_profile(struct btrfs_root *root, u64 flags)
 {
        if (flags & BTRFS_BLOCK_GROUP_DATA)
-               flags |= root->fs_info->avail_data_alloc_bits &
-                        root->fs_info->data_alloc_profile;
+               flags |= root->fs_info->avail_data_alloc_bits;
        else if (flags & BTRFS_BLOCK_GROUP_SYSTEM)
-               flags |= root->fs_info->avail_system_alloc_bits &
-                        root->fs_info->system_alloc_profile;
+               flags |= root->fs_info->avail_system_alloc_bits;
        else if (flags & BTRFS_BLOCK_GROUP_METADATA)
-               flags |= root->fs_info->avail_metadata_alloc_bits &
-                        root->fs_info->metadata_alloc_profile;
+               flags |= root->fs_info->avail_metadata_alloc_bits;
+
        return btrfs_reduce_alloc_profile(root, flags);
 }
 
@@ -3191,6 +3310,8 @@ commit_trans:
                return -ENOSPC;
        }
        data_sinfo->bytes_may_use += bytes;
+       trace_btrfs_space_reservation(root->fs_info, "space_info",
+                                     (u64)data_sinfo, bytes, 1);
        spin_unlock(&data_sinfo->lock);
 
        return 0;
@@ -3210,6 +3331,8 @@ void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes)
        data_sinfo = BTRFS_I(inode)->space_info;
        spin_lock(&data_sinfo->lock);
        data_sinfo->bytes_may_use -= bytes;
+       trace_btrfs_space_reservation(root->fs_info, "space_info",
+                                     (u64)data_sinfo, bytes, 0);
        spin_unlock(&data_sinfo->lock);
 }
 
@@ -3257,27 +3380,15 @@ static int should_alloc_chunk(struct btrfs_root *root,
                if (num_bytes - num_allocated < thresh)
                        return 1;
        }
-
-       /*
-        * we have two similar checks here, one based on percentage
-        * and once based on a hard number of 256MB.  The idea
-        * is that if we have a good amount of free
-        * room, don't allocate a chunk.  A good mount is
-        * less than 80% utilized of the chunks we have allocated,
-        * or more than 256MB free
-        */
-       if (num_allocated + alloc_bytes + 256 * 1024 * 1024 < num_bytes)
-               return 0;
-
-       if (num_allocated + alloc_bytes < div_factor(num_bytes, 8))
-               return 0;
-
        thresh = btrfs_super_total_bytes(root->fs_info->super_copy);
 
-       /* 256MB or 5% of the FS */
-       thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 5));
+       /* 256MB or 2% of the FS */
+       thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 2));
+       /* system chunks need a much small threshold */
+       if (sinfo->flags & BTRFS_BLOCK_GROUP_SYSTEM)
+               thresh = 32 * 1024 * 1024;
 
-       if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 3))
+       if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 8))
                return 0;
        return 1;
 }
@@ -3291,7 +3402,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
        int wait_for_alloc = 0;
        int ret = 0;
 
-       flags = btrfs_reduce_alloc_profile(extent_root, flags);
+       BUG_ON(!profile_is_valid(flags, 0));
 
        space_info = __find_space_info(extent_root->fs_info, flags);
        if (!space_info) {
@@ -3582,6 +3693,10 @@ again:
        if (used <= space_info->total_bytes) {
                if (used + orig_bytes <= space_info->total_bytes) {
                        space_info->bytes_may_use += orig_bytes;
+                       trace_btrfs_space_reservation(root->fs_info,
+                                                     "space_info",
+                                                     (u64)space_info,
+                                                     orig_bytes, 1);
                        ret = 0;
                } else {
                        /*
@@ -3649,6 +3764,10 @@ again:
 
                if (used + num_bytes < space_info->total_bytes + avail) {
                        space_info->bytes_may_use += orig_bytes;
+                       trace_btrfs_space_reservation(root->fs_info,
+                                                     "space_info",
+                                                     (u64)space_info,
+                                                     orig_bytes, 1);
                        ret = 0;
                } else {
                        wait_ordered = true;
@@ -3755,7 +3874,8 @@ static void block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv,
        spin_unlock(&block_rsv->lock);
 }
 
-static void block_rsv_release_bytes(struct btrfs_block_rsv *block_rsv,
+static void block_rsv_release_bytes(struct btrfs_fs_info *fs_info,
+                                   struct btrfs_block_rsv *block_rsv,
                                    struct btrfs_block_rsv *dest, u64 num_bytes)
 {
        struct btrfs_space_info *space_info = block_rsv->space_info;
@@ -3791,6 +3911,9 @@ static void block_rsv_release_bytes(struct btrfs_block_rsv *block_rsv,
                if (num_bytes) {
                        spin_lock(&space_info->lock);
                        space_info->bytes_may_use -= num_bytes;
+                       trace_btrfs_space_reservation(fs_info, "space_info",
+                                                     (u64)space_info,
+                                                     num_bytes, 0);
                        space_info->reservation_progress++;
                        spin_unlock(&space_info->lock);
                }
@@ -3947,7 +4070,8 @@ void btrfs_block_rsv_release(struct btrfs_root *root,
        if (global_rsv->full || global_rsv == block_rsv ||
            block_rsv->space_info != global_rsv->space_info)
                global_rsv = NULL;
-       block_rsv_release_bytes(block_rsv, global_rsv, num_bytes);
+       block_rsv_release_bytes(root->fs_info, block_rsv, global_rsv,
+                               num_bytes);
 }
 
 /*
@@ -4006,11 +4130,15 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
                num_bytes = sinfo->total_bytes - num_bytes;
                block_rsv->reserved += num_bytes;
                sinfo->bytes_may_use += num_bytes;
+               trace_btrfs_space_reservation(fs_info, "space_info",
+                                             (u64)sinfo, num_bytes, 1);
        }
 
        if (block_rsv->reserved >= block_rsv->size) {
                num_bytes = block_rsv->reserved - block_rsv->size;
                sinfo->bytes_may_use -= num_bytes;
+               trace_btrfs_space_reservation(fs_info, "space_info",
+                                             (u64)sinfo, num_bytes, 0);
                sinfo->reservation_progress++;
                block_rsv->reserved = block_rsv->size;
                block_rsv->full = 1;
@@ -4045,7 +4173,8 @@ static void init_global_block_rsv(struct btrfs_fs_info *fs_info)
 
 static void release_global_block_rsv(struct btrfs_fs_info *fs_info)
 {
-       block_rsv_release_bytes(&fs_info->global_block_rsv, NULL, (u64)-1);
+       block_rsv_release_bytes(fs_info, &fs_info->global_block_rsv, NULL,
+                               (u64)-1);
        WARN_ON(fs_info->delalloc_block_rsv.size > 0);
        WARN_ON(fs_info->delalloc_block_rsv.reserved > 0);
        WARN_ON(fs_info->trans_block_rsv.size > 0);
@@ -4062,6 +4191,8 @@ void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
        if (!trans->bytes_reserved)
                return;
 
+       trace_btrfs_space_reservation(root->fs_info, "transaction", (u64)trans,
+                                     trans->bytes_reserved, 0);
        btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
        trans->bytes_reserved = 0;
 }
@@ -4079,6 +4210,8 @@ int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
         * when we are truly done with the orphan item.
         */
        u64 num_bytes = btrfs_calc_trans_metadata_size(root, 1);
+       trace_btrfs_space_reservation(root->fs_info, "orphan",
+                                     btrfs_ino(inode), num_bytes, 1);
        return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
 }
 
@@ -4086,6 +4219,8 @@ void btrfs_orphan_release_metadata(struct inode *inode)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        u64 num_bytes = btrfs_calc_trans_metadata_size(root, 1);
+       trace_btrfs_space_reservation(root->fs_info, "orphan",
+                                     btrfs_ino(inode), num_bytes, 0);
        btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes);
 }
 
@@ -4213,12 +4348,11 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
        /* Need to be holding the i_mutex here if we aren't free space cache */
        if (btrfs_is_free_space_inode(root, inode))
                flush = 0;
-       else
-               WARN_ON(!mutex_is_locked(&inode->i_mutex));
 
        if (flush && btrfs_transaction_in_commit(root->fs_info))
                schedule_timeout(1);
 
+       mutex_lock(&BTRFS_I(inode)->delalloc_mutex);
        num_bytes = ALIGN(num_bytes, root->sectorsize);
 
        spin_lock(&BTRFS_I(inode)->lock);
@@ -4266,8 +4400,14 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
                if (dropped)
                        to_free += btrfs_calc_trans_metadata_size(root, dropped);
 
-               if (to_free)
+               if (to_free) {
                        btrfs_block_rsv_release(root, block_rsv, to_free);
+                       trace_btrfs_space_reservation(root->fs_info,
+                                                     "delalloc",
+                                                     btrfs_ino(inode),
+                                                     to_free, 0);
+               }
+               mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
                return ret;
        }
 
@@ -4278,7 +4418,11 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
        }
        BTRFS_I(inode)->reserved_extents += nr_extents;
        spin_unlock(&BTRFS_I(inode)->lock);
+       mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
 
+       if (to_reserve)
+               trace_btrfs_space_reservation(root->fs_info,"delalloc",
+                                             btrfs_ino(inode), to_reserve, 1);
        block_rsv_add_bytes(block_rsv, to_reserve, 1);
 
        return 0;
@@ -4308,6 +4452,8 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
        if (dropped > 0)
                to_free += btrfs_calc_trans_metadata_size(root, dropped);
 
+       trace_btrfs_space_reservation(root->fs_info, "delalloc",
+                                     btrfs_ino(inode), to_free, 0);
        btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
                                to_free);
 }
@@ -4562,7 +4708,10 @@ static int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache,
                        cache->reserved += num_bytes;
                        space_info->bytes_reserved += num_bytes;
                        if (reserve == RESERVE_ALLOC) {
-                               BUG_ON(space_info->bytes_may_use < num_bytes);
+                               trace_btrfs_space_reservation(cache->fs_info,
+                                                             "space_info",
+                                                             (u64)space_info,
+                                                             num_bytes, 0);
                                space_info->bytes_may_use -= num_bytes;
                        }
                }
@@ -4928,6 +5077,8 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
        rb_erase(&head->node.rb_node, &delayed_refs->root);
 
        delayed_refs->num_entries--;
+       if (waitqueue_active(&delayed_refs->seq_wait))
+               wake_up(&delayed_refs->seq_wait);
 
        /*
         * we don't take a ref on the node because we're removing it from the
@@ -4955,16 +5106,17 @@ out:
 void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           struct extent_buffer *buf,
-                          u64 parent, int last_ref)
+                          u64 parent, int last_ref, int for_cow)
 {
        struct btrfs_block_group_cache *cache = NULL;
        int ret;
 
        if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
-               ret = btrfs_add_delayed_tree_ref(trans, buf->start, buf->len,
-                                               parent, root->root_key.objectid,
-                                               btrfs_header_level(buf),
-                                               BTRFS_DROP_DELAYED_REF, NULL);
+               ret = btrfs_add_delayed_tree_ref(root->fs_info, trans,
+                                       buf->start, buf->len,
+                                       parent, root->root_key.objectid,
+                                       btrfs_header_level(buf),
+                                       BTRFS_DROP_DELAYED_REF, NULL, for_cow);
                BUG_ON(ret);
        }
 
@@ -4999,12 +5151,12 @@ out:
        btrfs_put_block_group(cache);
 }
 
-int btrfs_free_extent(struct btrfs_trans_handle *trans,
-                     struct btrfs_root *root,
-                     u64 bytenr, u64 num_bytes, u64 parent,
-                     u64 root_objectid, u64 owner, u64 offset)
+int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+                     u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid,
+                     u64 owner, u64 offset, int for_cow)
 {
        int ret;
+       struct btrfs_fs_info *fs_info = root->fs_info;
 
        /*
         * tree log blocks never actually go into the extent allocation
@@ -5016,14 +5168,17 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
                btrfs_pin_extent(root, bytenr, num_bytes, 1);
                ret = 0;
        } else if (owner < BTRFS_FIRST_FREE_OBJECTID) {
-               ret = btrfs_add_delayed_tree_ref(trans, bytenr, num_bytes,
+               ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr,
+                                       num_bytes,
                                        parent, root_objectid, (int)owner,
-                                       BTRFS_DROP_DELAYED_REF, NULL);
+                                       BTRFS_DROP_DELAYED_REF, NULL, for_cow);
                BUG_ON(ret);
        } else {
-               ret = btrfs_add_delayed_data_ref(trans, bytenr, num_bytes,
-                                       parent, root_objectid, owner,
-                                       offset, BTRFS_DROP_DELAYED_REF, NULL);
+               ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
+                                               num_bytes,
+                                               parent, root_objectid, owner,
+                                               offset, BTRFS_DROP_DELAYED_REF,
+                                               NULL, for_cow);
                BUG_ON(ret);
        }
        return ret;
@@ -5146,6 +5301,8 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
        ins->objectid = 0;
        ins->offset = 0;
 
+       trace_find_free_extent(orig_root, num_bytes, empty_size, data);
+
        space_info = __find_space_info(root->fs_info, data);
        if (!space_info) {
                printk(KERN_ERR "No space info for %llu\n", data);
@@ -5295,15 +5452,6 @@ alloc:
                if (unlikely(block_group->ro))
                        goto loop;
 
-               spin_lock(&block_group->free_space_ctl->tree_lock);
-               if (cached &&
-                   block_group->free_space_ctl->free_space <
-                   num_bytes + empty_cluster + empty_size) {
-                       spin_unlock(&block_group->free_space_ctl->tree_lock);
-                       goto loop;
-               }
-               spin_unlock(&block_group->free_space_ctl->tree_lock);
-
                /*
                 * Ok we want to try and use the cluster allocator, so
                 * lets look there
@@ -5331,6 +5479,8 @@ alloc:
                        if (offset) {
                                /* we have a block, we're done */
                                spin_unlock(&last_ptr->refill_lock);
+                               trace_btrfs_reserve_extent_cluster(root,
+                                       block_group, search_start, num_bytes);
                                goto checks;
                        }
 
@@ -5349,8 +5499,15 @@ refill_cluster:
                         * plenty of times and not have found
                         * anything, so we are likely way too
                         * fragmented for the clustering stuff to find
-                        * anything.  */
-                       if (loop >= LOOP_NO_EMPTY_SIZE) {
+                        * anything.
+                        *
+                        * However, if the cluster is taken from the
+                        * current block group, release the cluster
+                        * first, so that we stand a better chance of
+                        * succeeding in the unclustered
+                        * allocation.  */
+                       if (loop >= LOOP_NO_EMPTY_SIZE &&
+                           last_ptr->block_group != block_group) {
                                spin_unlock(&last_ptr->refill_lock);
                                goto unclustered_alloc;
                        }
@@ -5361,6 +5518,11 @@ refill_cluster:
                         */
                        btrfs_return_cluster_to_free_space(NULL, last_ptr);
 
+                       if (loop >= LOOP_NO_EMPTY_SIZE) {
+                               spin_unlock(&last_ptr->refill_lock);
+                               goto unclustered_alloc;
+                       }
+
                        /* allocate a cluster in this block group */
                        ret = btrfs_find_space_cluster(trans, root,
                                               block_group, last_ptr,
@@ -5377,6 +5539,9 @@ refill_cluster:
                                if (offset) {
                                        /* we found one, proceed */
                                        spin_unlock(&last_ptr->refill_lock);
+                                       trace_btrfs_reserve_extent_cluster(root,
+                                               block_group, search_start,
+                                               num_bytes);
                                        goto checks;
                                }
                        } else if (!cached && loop > LOOP_CACHING_NOWAIT
@@ -5401,6 +5566,15 @@ refill_cluster:
                }
 
 unclustered_alloc:
+               spin_lock(&block_group->free_space_ctl->tree_lock);
+               if (cached &&
+                   block_group->free_space_ctl->free_space <
+                   num_bytes + empty_cluster + empty_size) {
+                       spin_unlock(&block_group->free_space_ctl->tree_lock);
+                       goto loop;
+               }
+               spin_unlock(&block_group->free_space_ctl->tree_lock);
+
                offset = btrfs_find_space_for_alloc(block_group, search_start,
                                                    num_bytes, empty_size);
                /*
@@ -5438,9 +5612,6 @@ checks:
                        goto loop;
                }
 
-               ins->objectid = search_start;
-               ins->offset = num_bytes;
-
                if (offset < search_start)
                        btrfs_add_free_space(used_block_group, offset,
                                             search_start - offset);
@@ -5457,6 +5628,8 @@ checks:
                ins->objectid = search_start;
                ins->offset = num_bytes;
 
+               trace_btrfs_reserve_extent(orig_root, block_group,
+                                          search_start, num_bytes);
                if (offset < search_start)
                        btrfs_add_free_space(used_block_group, offset,
                                             search_start - offset);
@@ -5842,9 +6015,10 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
 
        BUG_ON(root_objectid == BTRFS_TREE_LOG_OBJECTID);
 
-       ret = btrfs_add_delayed_data_ref(trans, ins->objectid, ins->offset,
-                                        0, root_objectid, owner, offset,
-                                        BTRFS_ADD_DELAYED_EXTENT, NULL);
+       ret = btrfs_add_delayed_data_ref(root->fs_info, trans, ins->objectid,
+                                        ins->offset, 0,
+                                        root_objectid, owner, offset,
+                                        BTRFS_ADD_DELAYED_EXTENT, NULL, 0);
        return ret;
 }
 
@@ -5997,10 +6171,11 @@ use_block_rsv(struct btrfs_trans_handle *trans,
        return ERR_PTR(-ENOSPC);
 }
 
-static void unuse_block_rsv(struct btrfs_block_rsv *block_rsv, u32 blocksize)
+static void unuse_block_rsv(struct btrfs_fs_info *fs_info,
+                           struct btrfs_block_rsv *block_rsv, u32 blocksize)
 {
        block_rsv_add_bytes(block_rsv, blocksize, 0);
-       block_rsv_release_bytes(block_rsv, NULL, 0);
+       block_rsv_release_bytes(fs_info, block_rsv, NULL, 0);
 }
 
 /*
@@ -6014,7 +6189,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
                                        struct btrfs_root *root, u32 blocksize,
                                        u64 parent, u64 root_objectid,
                                        struct btrfs_disk_key *key, int level,
-                                       u64 hint, u64 empty_size)
+                                       u64 hint, u64 empty_size, int for_cow)
 {
        struct btrfs_key ins;
        struct btrfs_block_rsv *block_rsv;
@@ -6030,7 +6205,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
        ret = btrfs_reserve_extent(trans, root, blocksize, blocksize,
                                   empty_size, hint, (u64)-1, &ins, 0);
        if (ret) {
-               unuse_block_rsv(block_rsv, blocksize);
+               unuse_block_rsv(root->fs_info, block_rsv, blocksize);
                return ERR_PTR(ret);
        }
 
@@ -6058,10 +6233,11 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
                extent_op->update_flags = 1;
                extent_op->is_data = 0;
 
-               ret = btrfs_add_delayed_tree_ref(trans, ins.objectid,
+               ret = btrfs_add_delayed_tree_ref(root->fs_info, trans,
+                                       ins.objectid,
                                        ins.offset, parent, root_objectid,
                                        level, BTRFS_ADD_DELAYED_EXTENT,
-                                       extent_op);
+                                       extent_op, for_cow);
                BUG_ON(ret);
        }
        return buf;
@@ -6078,6 +6254,7 @@ struct walk_control {
        int keep_locks;
        int reada_slot;
        int reada_count;
+       int for_reloc;
 };
 
 #define DROP_REFERENCE 1
@@ -6216,9 +6393,9 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
        /* wc->stage == UPDATE_BACKREF */
        if (!(wc->flags[level] & flag)) {
                BUG_ON(!path->locks[level]);
-               ret = btrfs_inc_ref(trans, root, eb, 1);
+               ret = btrfs_inc_ref(trans, root, eb, 1, wc->for_reloc);
                BUG_ON(ret);
-               ret = btrfs_dec_ref(trans, root, eb, 0);
+               ret = btrfs_dec_ref(trans, root, eb, 0, wc->for_reloc);
                BUG_ON(ret);
                ret = btrfs_set_disk_extent_flags(trans, root, eb->start,
                                                  eb->len, flag, 0);
@@ -6362,7 +6539,7 @@ skip:
                }
 
                ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
-                                       root->root_key.objectid, level - 1, 0);
+                               root->root_key.objectid, level - 1, 0, 0);
                BUG_ON(ret);
        }
        btrfs_tree_unlock(next);
@@ -6436,9 +6613,11 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
        if (wc->refs[level] == 1) {
                if (level == 0) {
                        if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF)
-                               ret = btrfs_dec_ref(trans, root, eb, 1);
+                               ret = btrfs_dec_ref(trans, root, eb, 1,
+                                                   wc->for_reloc);
                        else
-                               ret = btrfs_dec_ref(trans, root, eb, 0);
+                               ret = btrfs_dec_ref(trans, root, eb, 0,
+                                                   wc->for_reloc);
                        BUG_ON(ret);
                }
                /* make block locked assertion in clean_tree_block happy */
@@ -6465,7 +6644,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
                               btrfs_header_owner(path->nodes[level + 1]));
        }
 
-       btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1);
+       btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1, 0);
 out:
        wc->refs[level] = 0;
        wc->flags[level] = 0;
@@ -6549,7 +6728,8 @@ static noinline int walk_up_tree(struct btrfs_trans_handle *trans,
  * blocks are properly updated.
  */
 void btrfs_drop_snapshot(struct btrfs_root *root,
-                        struct btrfs_block_rsv *block_rsv, int update_ref)
+                        struct btrfs_block_rsv *block_rsv, int update_ref,
+                        int for_reloc)
 {
        struct btrfs_path *path;
        struct btrfs_trans_handle *trans;
@@ -6637,6 +6817,7 @@ void btrfs_drop_snapshot(struct btrfs_root *root,
        wc->stage = DROP_REFERENCE;
        wc->update_ref = update_ref;
        wc->keep_locks = 0;
+       wc->for_reloc = for_reloc;
        wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root);
 
        while (1) {
@@ -6721,6 +6902,7 @@ out:
  * drop subtree rooted at tree block 'node'.
  *
  * NOTE: this function will unlock and release tree block 'node'
+ * only used by relocation code
  */
 int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
@@ -6765,6 +6947,7 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
        wc->stage = DROP_REFERENCE;
        wc->update_ref = 0;
        wc->keep_locks = 1;
+       wc->for_reloc = 1;
        wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root);
 
        while (1) {
@@ -6792,6 +6975,29 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
        u64 stripped = BTRFS_BLOCK_GROUP_RAID0 |
                BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
 
+       if (root->fs_info->balance_ctl) {
+               struct btrfs_balance_control *bctl = root->fs_info->balance_ctl;
+               u64 tgt = 0;
+
+               /* pick restriper's target profile and return */
+               if (flags & BTRFS_BLOCK_GROUP_DATA &&
+                   bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) {
+                       tgt = BTRFS_BLOCK_GROUP_DATA | bctl->data.target;
+               } else if (flags & BTRFS_BLOCK_GROUP_SYSTEM &&
+                          bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) {
+                       tgt = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target;
+               } else if (flags & BTRFS_BLOCK_GROUP_METADATA &&
+                          bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) {
+                       tgt = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target;
+               }
+
+               if (tgt) {
+                       /* extended -> chunk profile */
+                       tgt &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
+                       return tgt;
+               }
+       }
+
        /*
         * we add in the count of missing devices because we want
         * to make sure that any RAID levels on a degraded FS
@@ -7085,7 +7291,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
                 * space to fit our block group in.
                 */
                if (device->total_bytes > device->bytes_used + min_free) {
-                       ret = find_free_dev_extent(NULL, device, min_free,
+                       ret = find_free_dev_extent(device, min_free,
                                                   &dev_offset, NULL);
                        if (!ret)
                                dev_nr++;
@@ -7447,6 +7653,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
        ret = update_space_info(root->fs_info, cache->flags, size, bytes_used,
                                &cache->space_info);
        BUG_ON(ret);
+       update_global_block_rsv(root->fs_info);
 
        spin_lock(&cache->space_info->lock);
        cache->space_info->bytes_readonly += cache->bytes_super;
@@ -7466,6 +7673,22 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
        return 0;
 }
 
+static void clear_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
+{
+       u64 extra_flags = flags & BTRFS_BLOCK_GROUP_PROFILE_MASK;
+
+       /* chunk -> extended profile */
+       if (extra_flags == 0)
+               extra_flags = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
+
+       if (flags & BTRFS_BLOCK_GROUP_DATA)
+               fs_info->avail_data_alloc_bits &= ~extra_flags;
+       if (flags & BTRFS_BLOCK_GROUP_METADATA)
+               fs_info->avail_metadata_alloc_bits &= ~extra_flags;
+       if (flags & BTRFS_BLOCK_GROUP_SYSTEM)
+               fs_info->avail_system_alloc_bits &= ~extra_flags;
+}
+
 int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root, u64 group_start)
 {
@@ -7476,6 +7699,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
        struct btrfs_key key;
        struct inode *inode;
        int ret;
+       int index;
        int factor;
 
        root = root->fs_info->extent_root;
@@ -7491,6 +7715,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
        free_excluded_extents(root, block_group);
 
        memcpy(&key, &block_group->key, sizeof(key));
+       index = get_block_group_index(block_group);
        if (block_group->flags & (BTRFS_BLOCK_GROUP_DUP |
                                  BTRFS_BLOCK_GROUP_RAID1 |
                                  BTRFS_BLOCK_GROUP_RAID10))
@@ -7565,6 +7790,8 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
         * are still on the list after taking the semaphore
         */
        list_del_init(&block_group->list);
+       if (list_empty(&block_group->space_info->block_groups[index]))
+               clear_avail_alloc_bits(root->fs_info, block_group->flags);
        up_write(&block_group->space_info->groups_sem);
 
        if (block_group->cached == BTRFS_CACHE_STARTED)
index 49f3c9dc09f4c81902299fd81c62da1ed8423250..9d09a4f81875817ebc45a7c5b80cbe6008061b22 100644 (file)
@@ -18,6 +18,7 @@
 #include "ctree.h"
 #include "btrfs_inode.h"
 #include "volumes.h"
+#include "check-integrity.h"
 
 static struct kmem_cache *extent_state_cache;
 static struct kmem_cache *extent_buffer_cache;
@@ -1895,7 +1896,7 @@ int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
        }
        bio->bi_bdev = dev->bdev;
        bio_add_page(bio, page, length, start-page_offset(page));
-       submit_bio(WRITE_SYNC, bio);
+       btrfsic_submit_bio(WRITE_SYNC, bio);
        wait_for_completion(&compl);
 
        if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
@@ -2393,7 +2394,7 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num,
                ret = tree->ops->submit_bio_hook(page->mapping->host, rw, bio,
                                           mirror_num, bio_flags, start);
        else
-               submit_bio(rw, bio);
+               btrfsic_submit_bio(rw, bio);
 
        if (bio_flagged(bio, BIO_EOPNOTSUPP))
                ret = -EOPNOTSUPP;
@@ -3579,6 +3580,7 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
        atomic_set(&eb->blocking_writers, 0);
        atomic_set(&eb->spinning_readers, 0);
        atomic_set(&eb->spinning_writers, 0);
+       eb->lock_nested = 0;
        init_waitqueue_head(&eb->write_lock_wq);
        init_waitqueue_head(&eb->read_lock_wq);
 
index 7604c30013227fd823b1523503f8faaeccf283c4..bc6a042cb6fc496e6910d21fb3cdaec000f43b8e 100644 (file)
@@ -129,6 +129,7 @@ struct extent_buffer {
        struct list_head leak_list;
        struct rcu_head rcu_head;
        atomic_t refs;
+       pid_t lock_owner;
 
        /* count of read lock holders on the extent buffer */
        atomic_t write_locks;
@@ -137,6 +138,7 @@ struct extent_buffer {
        atomic_t blocking_readers;
        atomic_t spinning_readers;
        atomic_t spinning_writers;
+       int lock_nested;
 
        /* protects write locks */
        rwlock_t lock;
index 034d985032296cd4dfbc80e4d6717ac8b4ea77c4..859ba2dd88903ba207c7b0e448e0f5ce7f99e46e 100644 (file)
@@ -678,7 +678,7 @@ next_slot:
                                                disk_bytenr, num_bytes, 0,
                                                root->root_key.objectid,
                                                new_key.objectid,
-                                               start - extent_offset);
+                                               start - extent_offset, 0);
                                BUG_ON(ret);
                                *hint_byte = disk_bytenr;
                        }
@@ -753,7 +753,7 @@ next_slot:
                                                disk_bytenr, num_bytes, 0,
                                                root->root_key.objectid,
                                                key.objectid, key.offset -
-                                               extent_offset);
+                                               extent_offset, 0);
                                BUG_ON(ret);
                                inode_sub_bytes(inode,
                                                extent_end - key.offset);
@@ -962,7 +962,7 @@ again:
 
                ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
                                           root->root_key.objectid,
-                                          ino, orig_offset);
+                                          ino, orig_offset, 0);
                BUG_ON(ret);
 
                if (split == start) {
@@ -989,7 +989,7 @@ again:
                del_nr++;
                ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
                                        0, root->root_key.objectid,
-                                       ino, orig_offset);
+                                       ino, orig_offset, 0);
                BUG_ON(ret);
        }
        other_start = 0;
@@ -1006,7 +1006,7 @@ again:
                del_nr++;
                ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
                                        0, root->root_key.objectid,
-                                       ino, orig_offset);
+                                       ino, orig_offset, 0);
                BUG_ON(ret);
        }
        if (del_nr == 0) {
@@ -1274,7 +1274,6 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                                                   dirty_pages);
                if (dirty_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1)
                        btrfs_btree_balance_dirty(root, 1);
-               btrfs_throttle(root);
 
                pos += copied;
                num_written += copied;
index 9a897bf795380808e728c8d074cb58c5bcd9cf89..d20ff87ca603bba8255b04a95f34d11bb385ab33 100644 (file)
@@ -319,9 +319,11 @@ static void io_ctl_drop_pages(struct io_ctl *io_ctl)
        io_ctl_unmap_page(io_ctl);
 
        for (i = 0; i < io_ctl->num_pages; i++) {
-               ClearPageChecked(io_ctl->pages[i]);
-               unlock_page(io_ctl->pages[i]);
-               page_cache_release(io_ctl->pages[i]);
+               if (io_ctl->pages[i]) {
+                       ClearPageChecked(io_ctl->pages[i]);
+                       unlock_page(io_ctl->pages[i]);
+                       page_cache_release(io_ctl->pages[i]);
+               }
        }
 }
 
@@ -635,7 +637,10 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
        if (!num_entries)
                return 0;
 
-       io_ctl_init(&io_ctl, inode, root);
+       ret = io_ctl_init(&io_ctl, inode, root);
+       if (ret)
+               return ret;
+
        ret = readahead_cache(inode);
        if (ret)
                goto out;
@@ -838,7 +843,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
        struct io_ctl io_ctl;
        struct list_head bitmap_list;
        struct btrfs_key key;
-       u64 start, end, len;
+       u64 start, extent_start, extent_end, len;
        int entries = 0;
        int bitmaps = 0;
        int ret;
@@ -849,7 +854,9 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
        if (!i_size_read(inode))
                return -1;
 
-       io_ctl_init(&io_ctl, inode, root);
+       ret = io_ctl_init(&io_ctl, inode, root);
+       if (ret)
+               return -1;
 
        /* Get the cluster for this block_group if it exists */
        if (block_group && !list_empty(&block_group->cluster_list))
@@ -857,25 +864,12 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
                                     struct btrfs_free_cluster,
                                     block_group_list);
 
-       /*
-        * We shouldn't have switched the pinned extents yet so this is the
-        * right one
-        */
-       unpin = root->fs_info->pinned_extents;
-
        /* Lock all pages first so we can lock the extent safely. */
        io_ctl_prepare_pages(&io_ctl, inode, 0);
 
        lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
                         0, &cached_state, GFP_NOFS);
 
-       /*
-        * When searching for pinned extents, we need to start at our start
-        * offset.
-        */
-       if (block_group)
-               start = block_group->key.objectid;
-
        node = rb_first(&ctl->free_space_offset);
        if (!node && cluster) {
                node = rb_first(&cluster->root);
@@ -918,9 +912,20 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
         * We want to add any pinned extents to our free space cache
         * so we don't leak the space
         */
+
+       /*
+        * We shouldn't have switched the pinned extents yet so this is the
+        * right one
+        */
+       unpin = root->fs_info->pinned_extents;
+
+       if (block_group)
+               start = block_group->key.objectid;
+
        while (block_group && (start < block_group->key.objectid +
                               block_group->key.offset)) {
-               ret = find_first_extent_bit(unpin, start, &start, &end,
+               ret = find_first_extent_bit(unpin, start,
+                                           &extent_start, &extent_end,
                                            EXTENT_DIRTY);
                if (ret) {
                        ret = 0;
@@ -928,20 +933,21 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
                }
 
                /* This pinned extent is out of our range */
-               if (start >= block_group->key.objectid +
+               if (extent_start >= block_group->key.objectid +
                    block_group->key.offset)
                        break;
 
-               len = block_group->key.objectid +
-                       block_group->key.offset - start;
-               len = min(len, end + 1 - start);
+               extent_start = max(extent_start, start);
+               extent_end = min(block_group->key.objectid +
+                                block_group->key.offset, extent_end + 1);
+               len = extent_end - extent_start;
 
                entries++;
-               ret = io_ctl_add_entry(&io_ctl, start, len, NULL);
+               ret = io_ctl_add_entry(&io_ctl, extent_start, len, NULL);
                if (ret)
                        goto out_nospc;
 
-               start = end + 1;
+               start = extent_end;
        }
 
        /* Write out the bitmaps */
@@ -2283,23 +2289,23 @@ out:
 static int btrfs_bitmap_cluster(struct btrfs_block_group_cache *block_group,
                                struct btrfs_free_space *entry,
                                struct btrfs_free_cluster *cluster,
-                               u64 offset, u64 bytes, u64 min_bytes)
+                               u64 offset, u64 bytes,
+                               u64 cont1_bytes, u64 min_bytes)
 {
        struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        unsigned long next_zero;
        unsigned long i;
-       unsigned long search_bits;
-       unsigned long total_bits;
+       unsigned long want_bits;
+       unsigned long min_bits;
        unsigned long found_bits;
        unsigned long start = 0;
        unsigned long total_found = 0;
        int ret;
-       bool found = false;
 
        i = offset_to_bit(entry->offset, block_group->sectorsize,
                          max_t(u64, offset, entry->offset));
-       search_bits = bytes_to_bits(bytes, block_group->sectorsize);
-       total_bits = bytes_to_bits(min_bytes, block_group->sectorsize);
+       want_bits = bytes_to_bits(bytes, block_group->sectorsize);
+       min_bits = bytes_to_bits(min_bytes, block_group->sectorsize);
 
 again:
        found_bits = 0;
@@ -2308,7 +2314,7 @@ again:
             i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, i + 1)) {
                next_zero = find_next_zero_bit(entry->bitmap,
                                               BITS_PER_BITMAP, i);
-               if (next_zero - i >= search_bits) {
+               if (next_zero - i >= min_bits) {
                        found_bits = next_zero - i;
                        break;
                }
@@ -2318,10 +2324,9 @@ again:
        if (!found_bits)
                return -ENOSPC;
 
-       if (!found) {
+       if (!total_found) {
                start = i;
                cluster->max_size = 0;
-               found = true;
        }
 
        total_found += found_bits;
@@ -2329,13 +2334,8 @@ again:
        if (cluster->max_size < found_bits * block_group->sectorsize)
                cluster->max_size = found_bits * block_group->sectorsize;
 
-       if (total_found < total_bits) {
-               i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, next_zero);
-               if (i - start > total_bits * 2) {
-                       total_found = 0;
-                       cluster->max_size = 0;
-                       found = false;
-               }
+       if (total_found < want_bits || cluster->max_size < cont1_bytes) {
+               i = next_zero + 1;
                goto again;
        }
 
@@ -2346,28 +2346,31 @@ again:
                                 &entry->offset_index, 1);
        BUG_ON(ret);
 
+       trace_btrfs_setup_cluster(block_group, cluster,
+                                 total_found * block_group->sectorsize, 1);
        return 0;
 }
 
 /*
  * This searches the block group for just extents to fill the cluster with.
+ * Try to find a cluster with at least bytes total bytes, at least one
+ * extent of cont1_bytes, and other clusters of at least min_bytes.
  */
 static noinline int
 setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
                        struct btrfs_free_cluster *cluster,
                        struct list_head *bitmaps, u64 offset, u64 bytes,
-                       u64 min_bytes)
+                       u64 cont1_bytes, u64 min_bytes)
 {
        struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *first = NULL;
        struct btrfs_free_space *entry = NULL;
-       struct btrfs_free_space *prev = NULL;
        struct btrfs_free_space *last;
        struct rb_node *node;
        u64 window_start;
        u64 window_free;
        u64 max_extent;
-       u64 max_gap = 128 * 1024;
+       u64 total_size = 0;
 
        entry = tree_search_offset(ctl, offset, 0, 1);
        if (!entry)
@@ -2377,8 +2380,8 @@ setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
         * We don't want bitmaps, so just move along until we find a normal
         * extent entry.
         */
-       while (entry->bitmap) {
-               if (list_empty(&entry->list))
+       while (entry->bitmap || entry->bytes < min_bytes) {
+               if (entry->bitmap && list_empty(&entry->list))
                        list_add_tail(&entry->list, bitmaps);
                node = rb_next(&entry->offset_index);
                if (!node)
@@ -2391,12 +2394,9 @@ setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
        max_extent = entry->bytes;
        first = entry;
        last = entry;
-       prev = entry;
 
-       while (window_free <= min_bytes) {
-               node = rb_next(&entry->offset_index);
-               if (!node)
-                       return -ENOSPC;
+       for (node = rb_next(&entry->offset_index); node;
+            node = rb_next(&entry->offset_index)) {
                entry = rb_entry(node, struct btrfs_free_space, offset_index);
 
                if (entry->bitmap) {
@@ -2405,26 +2405,18 @@ setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
                        continue;
                }
 
-               /*
-                * we haven't filled the empty size and the window is
-                * very large.  reset and try again
-                */
-               if (entry->offset - (prev->offset + prev->bytes) > max_gap ||
-                   entry->offset - window_start > (min_bytes * 2)) {
-                       first = entry;
-                       window_start = entry->offset;
-                       window_free = entry->bytes;
-                       last = entry;
+               if (entry->bytes < min_bytes)
+                       continue;
+
+               last = entry;
+               window_free += entry->bytes;
+               if (entry->bytes > max_extent)
                        max_extent = entry->bytes;
-               } else {
-                       last = entry;
-                       window_free += entry->bytes;
-                       if (entry->bytes > max_extent)
-                               max_extent = entry->bytes;
-               }
-               prev = entry;
        }
 
+       if (window_free < bytes || max_extent < cont1_bytes)
+               return -ENOSPC;
+
        cluster->window_start = first->offset;
 
        node = &first->offset_index;
@@ -2438,17 +2430,18 @@ setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
 
                entry = rb_entry(node, struct btrfs_free_space, offset_index);
                node = rb_next(&entry->offset_index);
-               if (entry->bitmap)
+               if (entry->bitmap || entry->bytes < min_bytes)
                        continue;
 
                rb_erase(&entry->offset_index, &ctl->free_space_offset);
                ret = tree_insert_offset(&cluster->root, entry->offset,
                                         &entry->offset_index, 0);
+               total_size += entry->bytes;
                BUG_ON(ret);
        } while (node && entry != last);
 
        cluster->max_size = max_extent;
-
+       trace_btrfs_setup_cluster(block_group, cluster, total_size, 0);
        return 0;
 }
 
@@ -2460,7 +2453,7 @@ static noinline int
 setup_cluster_bitmap(struct btrfs_block_group_cache *block_group,
                     struct btrfs_free_cluster *cluster,
                     struct list_head *bitmaps, u64 offset, u64 bytes,
-                    u64 min_bytes)
+                    u64 cont1_bytes, u64 min_bytes)
 {
        struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *entry;
@@ -2485,7 +2478,7 @@ setup_cluster_bitmap(struct btrfs_block_group_cache *block_group,
                if (entry->bytes < min_bytes)
                        continue;
                ret = btrfs_bitmap_cluster(block_group, entry, cluster, offset,
-                                          bytes, min_bytes);
+                                          bytes, cont1_bytes, min_bytes);
                if (!ret)
                        return 0;
        }
@@ -2499,7 +2492,7 @@ setup_cluster_bitmap(struct btrfs_block_group_cache *block_group,
 
 /*
  * here we try to find a cluster of blocks in a block group.  The goal
- * is to find at least bytes free and up to empty_size + bytes free.
+ * is to find at least bytes+empty_size.
  * We might not find them all in one contiguous area.
  *
  * returns zero and sets up cluster if things worked out, otherwise
@@ -2515,23 +2508,24 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
        struct btrfs_free_space *entry, *tmp;
        LIST_HEAD(bitmaps);
        u64 min_bytes;
+       u64 cont1_bytes;
        int ret;
 
-       /* for metadata, allow allocates with more holes */
+       /*
+        * Choose the minimum extent size we'll require for this
+        * cluster.  For SSD_SPREAD, don't allow any fragmentation.
+        * For metadata, allow allocates with smaller extents.  For
+        * data, keep it dense.
+        */
        if (btrfs_test_opt(root, SSD_SPREAD)) {
-               min_bytes = bytes + empty_size;
+               cont1_bytes = min_bytes = bytes + empty_size;
        } else if (block_group->flags & BTRFS_BLOCK_GROUP_METADATA) {
-               /*
-                * we want to do larger allocations when we are
-                * flushing out the delayed refs, it helps prevent
-                * making more work as we go along.
-                */
-               if (trans->transaction->delayed_refs.flushing)
-                       min_bytes = max(bytes, (bytes + empty_size) >> 1);
-               else
-                       min_bytes = max(bytes, (bytes + empty_size) >> 4);
-       } else
-               min_bytes = max(bytes, (bytes + empty_size) >> 2);
+               cont1_bytes = bytes;
+               min_bytes = block_group->sectorsize;
+       } else {
+               cont1_bytes = max(bytes, (bytes + empty_size) >> 2);
+               min_bytes = block_group->sectorsize;
+       }
 
        spin_lock(&ctl->tree_lock);
 
@@ -2539,7 +2533,7 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
         * If we know we don't have enough space to make a cluster don't even
         * bother doing all the work to try and find one.
         */
-       if (ctl->free_space < min_bytes) {
+       if (ctl->free_space < bytes) {
                spin_unlock(&ctl->tree_lock);
                return -ENOSPC;
        }
@@ -2552,11 +2546,17 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
                goto out;
        }
 
+       trace_btrfs_find_cluster(block_group, offset, bytes, empty_size,
+                                min_bytes);
+
+       INIT_LIST_HEAD(&bitmaps);
        ret = setup_cluster_no_bitmap(block_group, cluster, &bitmaps, offset,
-                                     bytes, min_bytes);
+                                     bytes + empty_size,
+                                     cont1_bytes, min_bytes);
        if (ret)
                ret = setup_cluster_bitmap(block_group, cluster, &bitmaps,
-                                          offset, bytes, min_bytes);
+                                          offset, bytes + empty_size,
+                                          cont1_bytes, min_bytes);
 
        /* Clear our temporary list */
        list_for_each_entry_safe(entry, tmp, &bitmaps, list)
@@ -2567,6 +2567,8 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
                list_add_tail(&cluster->block_group_list,
                              &block_group->cluster_list);
                cluster->block_group = block_group;
+       } else {
+               trace_btrfs_failed_cluster_setup(block_group);
        }
 out:
        spin_unlock(&cluster->lock);
@@ -2588,17 +2590,57 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster)
        cluster->block_group = NULL;
 }
 
-int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
-                          u64 *trimmed, u64 start, u64 end, u64 minlen)
+static int do_trimming(struct btrfs_block_group_cache *block_group,
+                      u64 *total_trimmed, u64 start, u64 bytes,
+                      u64 reserved_start, u64 reserved_bytes)
 {
-       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
-       struct btrfs_free_space *entry = NULL;
+       struct btrfs_space_info *space_info = block_group->space_info;
        struct btrfs_fs_info *fs_info = block_group->fs_info;
-       u64 bytes = 0;
-       u64 actually_trimmed;
-       int ret = 0;
+       int ret;
+       int update = 0;
+       u64 trimmed = 0;
 
-       *trimmed = 0;
+       spin_lock(&space_info->lock);
+       spin_lock(&block_group->lock);
+       if (!block_group->ro) {
+               block_group->reserved += reserved_bytes;
+               space_info->bytes_reserved += reserved_bytes;
+               update = 1;
+       }
+       spin_unlock(&block_group->lock);
+       spin_unlock(&space_info->lock);
+
+       ret = btrfs_error_discard_extent(fs_info->extent_root,
+                                        start, bytes, &trimmed);
+       if (!ret)
+               *total_trimmed += trimmed;
+
+       btrfs_add_free_space(block_group, reserved_start, reserved_bytes);
+
+       if (update) {
+               spin_lock(&space_info->lock);
+               spin_lock(&block_group->lock);
+               if (block_group->ro)
+                       space_info->bytes_readonly += reserved_bytes;
+               block_group->reserved -= reserved_bytes;
+               space_info->bytes_reserved -= reserved_bytes;
+               spin_unlock(&space_info->lock);
+               spin_unlock(&block_group->lock);
+       }
+
+       return ret;
+}
+
+static int trim_no_bitmap(struct btrfs_block_group_cache *block_group,
+                         u64 *total_trimmed, u64 start, u64 end, u64 minlen)
+{
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
+       struct btrfs_free_space *entry;
+       struct rb_node *node;
+       int ret = 0;
+       u64 extent_start;
+       u64 extent_bytes;
+       u64 bytes;
 
        while (start < end) {
                spin_lock(&ctl->tree_lock);
@@ -2609,81 +2651,118 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
                }
 
                entry = tree_search_offset(ctl, start, 0, 1);
-               if (!entry)
-                       entry = tree_search_offset(ctl,
-                                                  offset_to_bitmap(ctl, start),
-                                                  1, 1);
-
-               if (!entry || entry->offset >= end) {
+               if (!entry) {
                        spin_unlock(&ctl->tree_lock);
                        break;
                }
 
-               if (entry->bitmap) {
-                       ret = search_bitmap(ctl, entry, &start, &bytes);
-                       if (!ret) {
-                               if (start >= end) {
-                                       spin_unlock(&ctl->tree_lock);
-                                       break;
-                               }
-                               bytes = min(bytes, end - start);
-                               bitmap_clear_bits(ctl, entry, start, bytes);
-                               if (entry->bytes == 0)
-                                       free_bitmap(ctl, entry);
-                       } else {
-                               start = entry->offset + BITS_PER_BITMAP *
-                                       block_group->sectorsize;
+               /* skip bitmaps */
+               while (entry->bitmap) {
+                       node = rb_next(&entry->offset_index);
+                       if (!node) {
                                spin_unlock(&ctl->tree_lock);
-                               ret = 0;
-                               continue;
+                               goto out;
                        }
-               } else {
-                       start = entry->offset;
-                       bytes = min(entry->bytes, end - start);
-                       unlink_free_space(ctl, entry);
-                       kmem_cache_free(btrfs_free_space_cachep, entry);
+                       entry = rb_entry(node, struct btrfs_free_space,
+                                        offset_index);
                }
 
+               if (entry->offset >= end) {
+                       spin_unlock(&ctl->tree_lock);
+                       break;
+               }
+
+               extent_start = entry->offset;
+               extent_bytes = entry->bytes;
+               start = max(start, extent_start);
+               bytes = min(extent_start + extent_bytes, end) - start;
+               if (bytes < minlen) {
+                       spin_unlock(&ctl->tree_lock);
+                       goto next;
+               }
+
+               unlink_free_space(ctl, entry);
+               kmem_cache_free(btrfs_free_space_cachep, entry);
+
                spin_unlock(&ctl->tree_lock);
 
-               if (bytes >= minlen) {
-                       struct btrfs_space_info *space_info;
-                       int update = 0;
-
-                       space_info = block_group->space_info;
-                       spin_lock(&space_info->lock);
-                       spin_lock(&block_group->lock);
-                       if (!block_group->ro) {
-                               block_group->reserved += bytes;
-                               space_info->bytes_reserved += bytes;
-                               update = 1;
-                       }
-                       spin_unlock(&block_group->lock);
-                       spin_unlock(&space_info->lock);
-
-                       ret = btrfs_error_discard_extent(fs_info->extent_root,
-                                                        start,
-                                                        bytes,
-                                                        &actually_trimmed);
-
-                       btrfs_add_free_space(block_group, start, bytes);
-                       if (update) {
-                               spin_lock(&space_info->lock);
-                               spin_lock(&block_group->lock);
-                               if (block_group->ro)
-                                       space_info->bytes_readonly += bytes;
-                               block_group->reserved -= bytes;
-                               space_info->bytes_reserved -= bytes;
-                               spin_unlock(&space_info->lock);
-                               spin_unlock(&block_group->lock);
-                       }
+               ret = do_trimming(block_group, total_trimmed, start, bytes,
+                                 extent_start, extent_bytes);
+               if (ret)
+                       break;
+next:
+               start += bytes;
 
-                       if (ret)
-                               break;
-                       *trimmed += actually_trimmed;
+               if (fatal_signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+
+               cond_resched();
+       }
+out:
+       return ret;
+}
+
+static int trim_bitmaps(struct btrfs_block_group_cache *block_group,
+                       u64 *total_trimmed, u64 start, u64 end, u64 minlen)
+{
+       struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
+       struct btrfs_free_space *entry;
+       int ret = 0;
+       int ret2;
+       u64 bytes;
+       u64 offset = offset_to_bitmap(ctl, start);
+
+       while (offset < end) {
+               bool next_bitmap = false;
+
+               spin_lock(&ctl->tree_lock);
+
+               if (ctl->free_space < minlen) {
+                       spin_unlock(&ctl->tree_lock);
+                       break;
+               }
+
+               entry = tree_search_offset(ctl, offset, 1, 0);
+               if (!entry) {
+                       spin_unlock(&ctl->tree_lock);
+                       next_bitmap = true;
+                       goto next;
+               }
+
+               bytes = minlen;
+               ret2 = search_bitmap(ctl, entry, &start, &bytes);
+               if (ret2 || start >= end) {
+                       spin_unlock(&ctl->tree_lock);
+                       next_bitmap = true;
+                       goto next;
+               }
+
+               bytes = min(bytes, end - start);
+               if (bytes < minlen) {
+                       spin_unlock(&ctl->tree_lock);
+                       goto next;
+               }
+
+               bitmap_clear_bits(ctl, entry, start, bytes);
+               if (entry->bytes == 0)
+                       free_bitmap(ctl, entry);
+
+               spin_unlock(&ctl->tree_lock);
+
+               ret = do_trimming(block_group, total_trimmed, start, bytes,
+                                 start, bytes);
+               if (ret)
+                       break;
+next:
+               if (next_bitmap) {
+                       offset += BITS_PER_BITMAP * ctl->unit;
+               } else {
+                       start += bytes;
+                       if (start >= offset + BITS_PER_BITMAP * ctl->unit)
+                               offset += BITS_PER_BITMAP * ctl->unit;
                }
-               start += bytes;
-               bytes = 0;
 
                if (fatal_signal_pending(current)) {
                        ret = -ERESTARTSYS;
@@ -2696,6 +2775,22 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
        return ret;
 }
 
+int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
+                          u64 *trimmed, u64 start, u64 end, u64 minlen)
+{
+       int ret;
+
+       *trimmed = 0;
+
+       ret = trim_no_bitmap(block_group, trimmed, start, end, minlen);
+       if (ret)
+               return ret;
+
+       ret = trim_bitmaps(block_group, trimmed, start, end, minlen);
+
+       return ret;
+}
+
 /*
  * Find the left-most item in the cache tree, and then return the
  * smallest inode number in the item.
index f8962a957d656b385d0f99d65f300598e419db4d..213ffa86ce1b81f30a5f4ad50753c6d2ac6435aa 100644 (file)
@@ -438,6 +438,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
                                          trans->bytes_reserved);
        if (ret)
                goto out;
+       trace_btrfs_space_reservation(root->fs_info, "ino_cache", (u64)trans,
+                                     trans->bytes_reserved, 1);
 again:
        inode = lookup_free_ino_inode(root, path);
        if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
@@ -498,6 +500,8 @@ again:
 out_put:
        iput(inode);
 out_release:
+       trace_btrfs_space_reservation(root->fs_info, "ino_cache", (u64)trans,
+                                     trans->bytes_reserved, 0);
        btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
 out:
        trans->block_rsv = rsv;
index 81b235a61f8c4149dd880d1d7d1238ab690a4e09..0da19a0ea00d5ac1e854cfe1a861ee828ccca15f 100644 (file)
@@ -1951,12 +1951,28 @@ enum btrfs_orphan_cleanup_state {
 void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root)
 {
+       struct btrfs_block_rsv *block_rsv;
        int ret;
 
        if (!list_empty(&root->orphan_list) ||
            root->orphan_cleanup_state != ORPHAN_CLEANUP_DONE)
                return;
 
+       spin_lock(&root->orphan_lock);
+       if (!list_empty(&root->orphan_list)) {
+               spin_unlock(&root->orphan_lock);
+               return;
+       }
+
+       if (root->orphan_cleanup_state != ORPHAN_CLEANUP_DONE) {
+               spin_unlock(&root->orphan_lock);
+               return;
+       }
+
+       block_rsv = root->orphan_block_rsv;
+       root->orphan_block_rsv = NULL;
+       spin_unlock(&root->orphan_lock);
+
        if (root->orphan_item_inserted &&
            btrfs_root_refs(&root->root_item) > 0) {
                ret = btrfs_del_orphan_item(trans, root->fs_info->tree_root,
@@ -1965,10 +1981,9 @@ void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans,
                root->orphan_item_inserted = 0;
        }
 
-       if (root->orphan_block_rsv) {
-               WARN_ON(root->orphan_block_rsv->size > 0);
-               btrfs_free_block_rsv(root, root->orphan_block_rsv);
-               root->orphan_block_rsv = NULL;
+       if (block_rsv) {
+               WARN_ON(block_rsv->size > 0);
+               btrfs_free_block_rsv(root, block_rsv);
        }
 }
 
@@ -2224,14 +2239,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
                                continue;
                        }
                        nr_truncate++;
-                       /*
-                        * Need to hold the imutex for reservation purposes, not
-                        * a huge deal here but I have a WARN_ON in
-                        * btrfs_delalloc_reserve_space to catch offenders.
-                        */
-                       mutex_lock(&inode->i_mutex);
                        ret = btrfs_truncate(inode);
-                       mutex_unlock(&inode->i_mutex);
                } else {
                        nr_unlink++;
                }
@@ -2845,7 +2853,7 @@ static void __unlink_end_trans(struct btrfs_trans_handle *trans,
                BUG_ON(!root->fs_info->enospc_unlink);
                root->fs_info->enospc_unlink = 0;
        }
-       btrfs_end_transaction_throttle(trans, root);
+       btrfs_end_transaction(trans, root);
 }
 
 static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
@@ -3009,7 +3017,6 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
        int pending_del_nr = 0;
        int pending_del_slot = 0;
        int extent_type = -1;
-       int encoding;
        int ret;
        int err = 0;
        u64 ino = btrfs_ino(inode);
@@ -3059,7 +3066,6 @@ search_again:
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
                found_type = btrfs_key_type(&found_key);
-               encoding = 0;
 
                if (found_key.objectid != ino)
                        break;
@@ -3072,10 +3078,6 @@ search_again:
                        fi = btrfs_item_ptr(leaf, path->slots[0],
                                            struct btrfs_file_extent_item);
                        extent_type = btrfs_file_extent_type(leaf, fi);
-                       encoding = btrfs_file_extent_compression(leaf, fi);
-                       encoding |= btrfs_file_extent_encryption(leaf, fi);
-                       encoding |= btrfs_file_extent_other_encoding(leaf, fi);
-
                        if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
                                item_end +=
                                    btrfs_file_extent_num_bytes(leaf, fi);
@@ -3103,7 +3105,7 @@ search_again:
                if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
                        u64 num_dec;
                        extent_start = btrfs_file_extent_disk_bytenr(leaf, fi);
-                       if (!del_item && !encoding) {
+                       if (!del_item) {
                                u64 orig_num_bytes =
                                        btrfs_file_extent_num_bytes(leaf, fi);
                                extent_num_bytes = new_size -
@@ -3179,7 +3181,7 @@ delete:
                        ret = btrfs_free_extent(trans, root, extent_start,
                                                extent_num_bytes, 0,
                                                btrfs_header_owner(leaf),
-                                               ino, extent_offset);
+                                               ino, extent_offset, 0);
                        BUG_ON(ret);
                }
 
@@ -3434,7 +3436,7 @@ static int btrfs_setsize(struct inode *inode, loff_t newsize)
                i_size_write(inode, newsize);
                btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL);
                ret = btrfs_update_inode(trans, root, inode);
-               btrfs_end_transaction_throttle(trans, root);
+               btrfs_end_transaction(trans, root);
        } else {
 
                /*
@@ -4655,7 +4657,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
        }
 out_unlock:
        nr = trans->blocks_used;
-       btrfs_end_transaction_throttle(trans, root);
+       btrfs_end_transaction(trans, root);
        btrfs_btree_balance_dirty(root, nr);
        if (drop_inode) {
                inode_dec_link_count(inode);
@@ -4723,7 +4725,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
        }
 out_unlock:
        nr = trans->blocks_used;
-       btrfs_end_transaction_throttle(trans, root);
+       btrfs_end_transaction(trans, root);
        if (drop_inode) {
                inode_dec_link_count(inode);
                iput(inode);
@@ -4782,7 +4784,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        }
 
        nr = trans->blocks_used;
-       btrfs_end_transaction_throttle(trans, root);
+       btrfs_end_transaction(trans, root);
 fail:
        if (drop_inode) {
                inode_dec_link_count(inode);
@@ -4848,7 +4850,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 
 out_fail:
        nr = trans->blocks_used;
-       btrfs_end_transaction_throttle(trans, root);
+       btrfs_end_transaction(trans, root);
        if (drop_on_err)
                iput(inode);
        btrfs_btree_balance_dirty(root, nr);
@@ -5121,7 +5123,7 @@ again:
                        }
                        flush_dcache_page(page);
                } else if (create && PageUptodate(page)) {
-                       WARN_ON(1);
+                       BUG();
                        if (!trans) {
                                kunmap(page);
                                free_extent_map(em);
@@ -6402,10 +6404,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        u64 page_start;
        u64 page_end;
 
-       /* Need this to keep space reservations serialized */
-       mutex_lock(&inode->i_mutex);
        ret  = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
-       mutex_unlock(&inode->i_mutex);
        if (!ret)
                ret = btrfs_update_time(vma->vm_file);
        if (ret) {
@@ -6494,8 +6493,8 @@ out_unlock:
        if (!ret)
                return VM_FAULT_LOCKED;
        unlock_page(page);
-       btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
 out:
+       btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
        return ret;
 }
 
@@ -6668,7 +6667,7 @@ end_trans:
                        err = ret;
 
                nr = trans->blocks_used;
-               ret = btrfs_end_transaction_throttle(trans, root);
+               ret = btrfs_end_transaction(trans, root);
                btrfs_btree_balance_dirty(root, nr);
        }
 
@@ -6749,6 +6748,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        extent_io_tree_init(&ei->io_tree, &inode->i_data);
        extent_io_tree_init(&ei->io_failure_tree, &inode->i_data);
        mutex_init(&ei->log_mutex);
+       mutex_init(&ei->delalloc_mutex);
        btrfs_ordered_inode_tree_init(&ei->ordered_tree);
        INIT_LIST_HEAD(&ei->i_orphan);
        INIT_LIST_HEAD(&ei->delalloc_inodes);
@@ -7074,7 +7074,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                btrfs_end_log_trans(root);
        }
 out_fail:
-       btrfs_end_transaction_throttle(trans, root);
+       btrfs_end_transaction(trans, root);
 out_notrans:
        if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
                up_read(&root->fs_info->subvol_sem);
@@ -7246,7 +7246,7 @@ out_unlock:
        if (!err)
                d_instantiate(dentry, inode);
        nr = trans->blocks_used;
-       btrfs_end_transaction_throttle(trans, root);
+       btrfs_end_transaction(trans, root);
        if (drop_inode) {
                inode_dec_link_count(inode);
                iput(inode);
index 5441ff1480fdbbd9ce9fe4c9caa6fc0c62392a3c..ab620014bcc3a5bd4782f948251bb25a166b6a78 100644 (file)
@@ -176,6 +176,8 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
        struct btrfs_trans_handle *trans;
        unsigned int flags, oldflags;
        int ret;
+       u64 ip_oldflags;
+       unsigned int i_oldflags;
 
        if (btrfs_root_readonly(root))
                return -EROFS;
@@ -192,6 +194,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
 
        mutex_lock(&inode->i_mutex);
 
+       ip_oldflags = ip->flags;
+       i_oldflags = inode->i_flags;
+
        flags = btrfs_mask_flags(inode->i_mode, flags);
        oldflags = btrfs_flags_to_ioctl(ip->flags);
        if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
@@ -249,19 +254,24 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
                ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS);
        }
 
-       trans = btrfs_join_transaction(root);
-       BUG_ON(IS_ERR(trans));
+       trans = btrfs_start_transaction(root, 1);
+       if (IS_ERR(trans)) {
+               ret = PTR_ERR(trans);
+               goto out_drop;
+       }
 
        btrfs_update_iflags(inode);
        inode->i_ctime = CURRENT_TIME;
        ret = btrfs_update_inode(trans, root, inode);
-       BUG_ON(ret);
 
        btrfs_end_transaction(trans, root);
+ out_drop:
+       if (ret) {
+               ip->flags = ip_oldflags;
+               inode->i_flags = i_oldflags;
+       }
 
        mnt_drop_write_file(file);
-
-       ret = 0;
  out_unlock:
        mutex_unlock(&inode->i_mutex);
        return ret;
@@ -276,14 +286,13 @@ static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
 
 static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
 {
-       struct btrfs_root *root = fdentry(file)->d_sb->s_fs_info;
-       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_fs_info *fs_info = btrfs_sb(fdentry(file)->d_sb);
        struct btrfs_device *device;
        struct request_queue *q;
        struct fstrim_range range;
        u64 minlen = ULLONG_MAX;
        u64 num_devices = 0;
-       u64 total_bytes = btrfs_super_total_bytes(root->fs_info->super_copy);
+       u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy);
        int ret;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -312,7 +321,7 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
 
        range.len = min(range.len, total_bytes - range.start);
        range.minlen = max(range.minlen, minlen);
-       ret = btrfs_trim_fs(root, &range);
+       ret = btrfs_trim_fs(fs_info->tree_root, &range);
        if (ret < 0)
                return ret;
 
@@ -358,7 +367,7 @@ static noinline int create_subvol(struct btrfs_root *root,
                return PTR_ERR(trans);
 
        leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
-                                     0, objectid, NULL, 0, 0, 0);
+                                     0, objectid, NULL, 0, 0, 0, 0);
        if (IS_ERR(leaf)) {
                ret = PTR_ERR(leaf);
                goto fail;
@@ -858,10 +867,8 @@ static int cluster_pages_for_defrag(struct inode *inode,
                return 0;
        file_end = (isize - 1) >> PAGE_CACHE_SHIFT;
 
-       mutex_lock(&inode->i_mutex);
        ret = btrfs_delalloc_reserve_space(inode,
                                           num_pages << PAGE_CACHE_SHIFT);
-       mutex_unlock(&inode->i_mutex);
        if (ret)
                return ret;
 again:
@@ -1203,13 +1210,21 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
+       mutex_lock(&root->fs_info->volume_mutex);
+       if (root->fs_info->balance_ctl) {
+               printk(KERN_INFO "btrfs: balance in progress\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
        vol_args = memdup_user(arg, sizeof(*vol_args));
-       if (IS_ERR(vol_args))
-               return PTR_ERR(vol_args);
+       if (IS_ERR(vol_args)) {
+               ret = PTR_ERR(vol_args);
+               goto out;
+       }
 
        vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
 
-       mutex_lock(&root->fs_info->volume_mutex);
        sizestr = vol_args->name;
        devstr = strchr(sizestr, ':');
        if (devstr) {
@@ -1226,7 +1241,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
                printk(KERN_INFO "btrfs: resizer unable to find device %llu\n",
                       (unsigned long long)devid);
                ret = -EINVAL;
-               goto out_unlock;
+               goto out_free;
        }
        if (!strcmp(sizestr, "max"))
                new_size = device->bdev->bd_inode->i_size;
@@ -1241,7 +1256,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
                new_size = memparse(sizestr, NULL);
                if (new_size == 0) {
                        ret = -EINVAL;
-                       goto out_unlock;
+                       goto out_free;
                }
        }
 
@@ -1250,7 +1265,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
        if (mod < 0) {
                if (new_size > old_size) {
                        ret = -EINVAL;
-                       goto out_unlock;
+                       goto out_free;
                }
                new_size = old_size - new_size;
        } else if (mod > 0) {
@@ -1259,11 +1274,11 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
 
        if (new_size < 256 * 1024 * 1024) {
                ret = -EINVAL;
-               goto out_unlock;
+               goto out_free;
        }
        if (new_size > device->bdev->bd_inode->i_size) {
                ret = -EFBIG;
-               goto out_unlock;
+               goto out_free;
        }
 
        do_div(new_size, root->sectorsize);
@@ -1276,7 +1291,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
                trans = btrfs_start_transaction(root, 0);
                if (IS_ERR(trans)) {
                        ret = PTR_ERR(trans);
-                       goto out_unlock;
+                       goto out_free;
                }
                ret = btrfs_grow_device(trans, device, new_size);
                btrfs_commit_transaction(trans, root);
@@ -1284,9 +1299,10 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
                ret = btrfs_shrink_device(device, new_size);
        }
 
-out_unlock:
-       mutex_unlock(&root->fs_info->volume_mutex);
+out_free:
        kfree(vol_args);
+out:
+       mutex_unlock(&root->fs_info->volume_mutex);
        return ret;
 }
 
@@ -2052,14 +2068,25 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
+       mutex_lock(&root->fs_info->volume_mutex);
+       if (root->fs_info->balance_ctl) {
+               printk(KERN_INFO "btrfs: balance in progress\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
        vol_args = memdup_user(arg, sizeof(*vol_args));
-       if (IS_ERR(vol_args))
-               return PTR_ERR(vol_args);
+       if (IS_ERR(vol_args)) {
+               ret = PTR_ERR(vol_args);
+               goto out;
+       }
 
        vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
        ret = btrfs_init_new_device(root, vol_args->name);
 
        kfree(vol_args);
+out:
+       mutex_unlock(&root->fs_info->volume_mutex);
        return ret;
 }
 
@@ -2074,14 +2101,25 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
        if (root->fs_info->sb->s_flags & MS_RDONLY)
                return -EROFS;
 
+       mutex_lock(&root->fs_info->volume_mutex);
+       if (root->fs_info->balance_ctl) {
+               printk(KERN_INFO "btrfs: balance in progress\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
        vol_args = memdup_user(arg, sizeof(*vol_args));
-       if (IS_ERR(vol_args))
-               return PTR_ERR(vol_args);
+       if (IS_ERR(vol_args)) {
+               ret = PTR_ERR(vol_args);
+               goto out;
+       }
 
        vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
        ret = btrfs_rm_device(root, vol_args->name);
 
        kfree(vol_args);
+out:
+       mutex_unlock(&root->fs_info->volume_mutex);
        return ret;
 }
 
@@ -2427,7 +2465,8 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                                        disko, diskl, 0,
                                                        root->root_key.objectid,
                                                        btrfs_ino(inode),
-                                                       new_key.offset - datao);
+                                                       new_key.offset - datao,
+                                                       0);
                                        BUG_ON(ret);
                                }
                        } else if (type == BTRFS_FILE_EXTENT_INLINE) {
@@ -2977,7 +3016,7 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
 {
        int ret = 0;
        int size;
-       u64 extent_offset;
+       u64 extent_item_pos;
        struct btrfs_ioctl_logical_ino_args *loi;
        struct btrfs_data_container *inodes = NULL;
        struct btrfs_path *path = NULL;
@@ -3008,15 +3047,17 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
        }
 
        ret = extent_from_logical(root->fs_info, loi->logical, path, &key);
+       btrfs_release_path(path);
 
        if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK)
                ret = -ENOENT;
        if (ret < 0)
                goto out;
 
-       extent_offset = loi->logical - key.objectid;
+       extent_item_pos = loi->logical - key.objectid;
        ret = iterate_extent_inodes(root->fs_info, path, key.objectid,
-                                       extent_offset, build_ino_list, inodes);
+                                       extent_item_pos, build_ino_list,
+                                       inodes);
 
        if (ret < 0)
                goto out;
@@ -3034,6 +3075,163 @@ out:
        return ret;
 }
 
+void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock,
+                              struct btrfs_ioctl_balance_args *bargs)
+{
+       struct btrfs_balance_control *bctl = fs_info->balance_ctl;
+
+       bargs->flags = bctl->flags;
+
+       if (atomic_read(&fs_info->balance_running))
+               bargs->state |= BTRFS_BALANCE_STATE_RUNNING;
+       if (atomic_read(&fs_info->balance_pause_req))
+               bargs->state |= BTRFS_BALANCE_STATE_PAUSE_REQ;
+       if (atomic_read(&fs_info->balance_cancel_req))
+               bargs->state |= BTRFS_BALANCE_STATE_CANCEL_REQ;
+
+       memcpy(&bargs->data, &bctl->data, sizeof(bargs->data));
+       memcpy(&bargs->meta, &bctl->meta, sizeof(bargs->meta));
+       memcpy(&bargs->sys, &bctl->sys, sizeof(bargs->sys));
+
+       if (lock) {
+               spin_lock(&fs_info->balance_lock);
+               memcpy(&bargs->stat, &bctl->stat, sizeof(bargs->stat));
+               spin_unlock(&fs_info->balance_lock);
+       } else {
+               memcpy(&bargs->stat, &bctl->stat, sizeof(bargs->stat));
+       }
+}
+
+static long btrfs_ioctl_balance(struct btrfs_root *root, void __user *arg)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_ioctl_balance_args *bargs;
+       struct btrfs_balance_control *bctl;
+       int ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (fs_info->sb->s_flags & MS_RDONLY)
+               return -EROFS;
+
+       mutex_lock(&fs_info->volume_mutex);
+       mutex_lock(&fs_info->balance_mutex);
+
+       if (arg) {
+               bargs = memdup_user(arg, sizeof(*bargs));
+               if (IS_ERR(bargs)) {
+                       ret = PTR_ERR(bargs);
+                       goto out;
+               }
+
+               if (bargs->flags & BTRFS_BALANCE_RESUME) {
+                       if (!fs_info->balance_ctl) {
+                               ret = -ENOTCONN;
+                               goto out_bargs;
+                       }
+
+                       bctl = fs_info->balance_ctl;
+                       spin_lock(&fs_info->balance_lock);
+                       bctl->flags |= BTRFS_BALANCE_RESUME;
+                       spin_unlock(&fs_info->balance_lock);
+
+                       goto do_balance;
+               }
+       } else {
+               bargs = NULL;
+       }
+
+       if (fs_info->balance_ctl) {
+               ret = -EINPROGRESS;
+               goto out_bargs;
+       }
+
+       bctl = kzalloc(sizeof(*bctl), GFP_NOFS);
+       if (!bctl) {
+               ret = -ENOMEM;
+               goto out_bargs;
+       }
+
+       bctl->fs_info = fs_info;
+       if (arg) {
+               memcpy(&bctl->data, &bargs->data, sizeof(bctl->data));
+               memcpy(&bctl->meta, &bargs->meta, sizeof(bctl->meta));
+               memcpy(&bctl->sys, &bargs->sys, sizeof(bctl->sys));
+
+               bctl->flags = bargs->flags;
+       } else {
+               /* balance everything - no filters */
+               bctl->flags |= BTRFS_BALANCE_TYPE_MASK;
+       }
+
+do_balance:
+       ret = btrfs_balance(bctl, bargs);
+       /*
+        * bctl is freed in __cancel_balance or in free_fs_info if
+        * restriper was paused all the way until unmount
+        */
+       if (arg) {
+               if (copy_to_user(arg, bargs, sizeof(*bargs)))
+                       ret = -EFAULT;
+       }
+
+out_bargs:
+       kfree(bargs);
+out:
+       mutex_unlock(&fs_info->balance_mutex);
+       mutex_unlock(&fs_info->volume_mutex);
+       return ret;
+}
+
+static long btrfs_ioctl_balance_ctl(struct btrfs_root *root, int cmd)
+{
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       switch (cmd) {
+       case BTRFS_BALANCE_CTL_PAUSE:
+               return btrfs_pause_balance(root->fs_info);
+       case BTRFS_BALANCE_CTL_CANCEL:
+               return btrfs_cancel_balance(root->fs_info);
+       }
+
+       return -EINVAL;
+}
+
+static long btrfs_ioctl_balance_progress(struct btrfs_root *root,
+                                        void __user *arg)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_ioctl_balance_args *bargs;
+       int ret = 0;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       mutex_lock(&fs_info->balance_mutex);
+       if (!fs_info->balance_ctl) {
+               ret = -ENOTCONN;
+               goto out;
+       }
+
+       bargs = kzalloc(sizeof(*bargs), GFP_NOFS);
+       if (!bargs) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       update_ioctl_balance_args(fs_info, 1, bargs);
+
+       if (copy_to_user(arg, bargs, sizeof(*bargs)))
+               ret = -EFAULT;
+
+       kfree(bargs);
+out:
+       mutex_unlock(&fs_info->balance_mutex);
+       return ret;
+}
+
 long btrfs_ioctl(struct file *file, unsigned int
                cmd, unsigned long arg)
 {
@@ -3078,7 +3276,7 @@ long btrfs_ioctl(struct file *file, unsigned int
        case BTRFS_IOC_DEV_INFO:
                return btrfs_ioctl_dev_info(root, argp);
        case BTRFS_IOC_BALANCE:
-               return btrfs_balance(root->fs_info->dev_root);
+               return btrfs_ioctl_balance(root, NULL);
        case BTRFS_IOC_CLONE:
                return btrfs_ioctl_clone(file, arg, 0, 0, 0);
        case BTRFS_IOC_CLONE_RANGE:
@@ -3110,6 +3308,12 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_scrub_cancel(root, argp);
        case BTRFS_IOC_SCRUB_PROGRESS:
                return btrfs_ioctl_scrub_progress(root, argp);
+       case BTRFS_IOC_BALANCE_V2:
+               return btrfs_ioctl_balance(root, argp);
+       case BTRFS_IOC_BALANCE_CTL:
+               return btrfs_ioctl_balance_ctl(root, arg);
+       case BTRFS_IOC_BALANCE_PROGRESS:
+               return btrfs_ioctl_balance_progress(root, argp);
        }
 
        return -ENOTTY;
index 252ae9915de8fcfa4b6b7a3a502735c28d1819f6..4f69028a68c486268bf5bcfc097a5412dbdd2ad0 100644 (file)
@@ -109,6 +109,55 @@ struct btrfs_ioctl_fs_info_args {
        __u64 reserved[124];                    /* pad to 1k */
 };
 
+/* balance control ioctl modes */
+#define BTRFS_BALANCE_CTL_PAUSE                1
+#define BTRFS_BALANCE_CTL_CANCEL       2
+
+/*
+ * this is packed, because it should be exactly the same as its disk
+ * byte order counterpart (struct btrfs_disk_balance_args)
+ */
+struct btrfs_balance_args {
+       __u64 profiles;
+       __u64 usage;
+       __u64 devid;
+       __u64 pstart;
+       __u64 pend;
+       __u64 vstart;
+       __u64 vend;
+
+       __u64 target;
+
+       __u64 flags;
+
+       __u64 unused[8];
+} __attribute__ ((__packed__));
+
+/* report balance progress to userspace */
+struct btrfs_balance_progress {
+       __u64 expected;         /* estimated # of chunks that will be
+                                * relocated to fulfill the request */
+       __u64 considered;       /* # of chunks we have considered so far */
+       __u64 completed;        /* # of chunks relocated so far */
+};
+
+#define BTRFS_BALANCE_STATE_RUNNING    (1ULL << 0)
+#define BTRFS_BALANCE_STATE_PAUSE_REQ  (1ULL << 1)
+#define BTRFS_BALANCE_STATE_CANCEL_REQ (1ULL << 2)
+
+struct btrfs_ioctl_balance_args {
+       __u64 flags;                            /* in/out */
+       __u64 state;                            /* out */
+
+       struct btrfs_balance_args data;         /* in/out */
+       struct btrfs_balance_args meta;         /* in/out */
+       struct btrfs_balance_args sys;          /* in/out */
+
+       struct btrfs_balance_progress stat;     /* out */
+
+       __u64 unused[72];                       /* pad to 1k */
+};
+
 #define BTRFS_INO_LOOKUP_PATH_MAX 4080
 struct btrfs_ioctl_ino_lookup_args {
        __u64 treeid;
@@ -272,6 +321,11 @@ struct btrfs_ioctl_logical_ino_args {
                                 struct btrfs_ioctl_dev_info_args)
 #define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
                               struct btrfs_ioctl_fs_info_args)
+#define BTRFS_IOC_BALANCE_V2 _IOWR(BTRFS_IOCTL_MAGIC, 32, \
+                                  struct btrfs_ioctl_balance_args)
+#define BTRFS_IOC_BALANCE_CTL _IOW(BTRFS_IOCTL_MAGIC, 33, int)
+#define BTRFS_IOC_BALANCE_PROGRESS _IOR(BTRFS_IOCTL_MAGIC, 34, \
+                                       struct btrfs_ioctl_balance_args)
 #define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \
                                        struct btrfs_ioctl_ino_path_args)
 #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
index d77b67c4b275731417c11e04ad38b3dc9c4d456b..5e178d8f7167f496e928613b6c1f0000c2ea242e 100644 (file)
@@ -33,6 +33,14 @@ void btrfs_assert_tree_read_locked(struct extent_buffer *eb);
  */
 void btrfs_set_lock_blocking_rw(struct extent_buffer *eb, int rw)
 {
+       if (eb->lock_nested) {
+               read_lock(&eb->lock);
+               if (eb->lock_nested && current->pid == eb->lock_owner) {
+                       read_unlock(&eb->lock);
+                       return;
+               }
+               read_unlock(&eb->lock);
+       }
        if (rw == BTRFS_WRITE_LOCK) {
                if (atomic_read(&eb->blocking_writers) == 0) {
                        WARN_ON(atomic_read(&eb->spinning_writers) != 1);
@@ -57,6 +65,14 @@ void btrfs_set_lock_blocking_rw(struct extent_buffer *eb, int rw)
  */
 void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw)
 {
+       if (eb->lock_nested) {
+               read_lock(&eb->lock);
+               if (&eb->lock_nested && current->pid == eb->lock_owner) {
+                       read_unlock(&eb->lock);
+                       return;
+               }
+               read_unlock(&eb->lock);
+       }
        if (rw == BTRFS_WRITE_LOCK_BLOCKING) {
                BUG_ON(atomic_read(&eb->blocking_writers) != 1);
                write_lock(&eb->lock);
@@ -81,12 +97,25 @@ void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw)
 void btrfs_tree_read_lock(struct extent_buffer *eb)
 {
 again:
+       read_lock(&eb->lock);
+       if (atomic_read(&eb->blocking_writers) &&
+           current->pid == eb->lock_owner) {
+               /*
+                * This extent is already write-locked by our thread. We allow
+                * an additional read lock to be added because it's for the same
+                * thread. btrfs_find_all_roots() depends on this as it may be
+                * called on a partly (write-)locked tree.
+                */
+               BUG_ON(eb->lock_nested);
+               eb->lock_nested = 1;
+               read_unlock(&eb->lock);
+               return;
+       }
+       read_unlock(&eb->lock);
        wait_event(eb->write_lock_wq, atomic_read(&eb->blocking_writers) == 0);
        read_lock(&eb->lock);
        if (atomic_read(&eb->blocking_writers)) {
                read_unlock(&eb->lock);
-               wait_event(eb->write_lock_wq,
-                          atomic_read(&eb->blocking_writers) == 0);
                goto again;
        }
        atomic_inc(&eb->read_locks);
@@ -129,6 +158,7 @@ int btrfs_try_tree_write_lock(struct extent_buffer *eb)
        }
        atomic_inc(&eb->write_locks);
        atomic_inc(&eb->spinning_writers);
+       eb->lock_owner = current->pid;
        return 1;
 }
 
@@ -137,6 +167,15 @@ int btrfs_try_tree_write_lock(struct extent_buffer *eb)
  */
 void btrfs_tree_read_unlock(struct extent_buffer *eb)
 {
+       if (eb->lock_nested) {
+               read_lock(&eb->lock);
+               if (eb->lock_nested && current->pid == eb->lock_owner) {
+                       eb->lock_nested = 0;
+                       read_unlock(&eb->lock);
+                       return;
+               }
+               read_unlock(&eb->lock);
+       }
        btrfs_assert_tree_read_locked(eb);
        WARN_ON(atomic_read(&eb->spinning_readers) == 0);
        atomic_dec(&eb->spinning_readers);
@@ -149,6 +188,15 @@ void btrfs_tree_read_unlock(struct extent_buffer *eb)
  */
 void btrfs_tree_read_unlock_blocking(struct extent_buffer *eb)
 {
+       if (eb->lock_nested) {
+               read_lock(&eb->lock);
+               if (eb->lock_nested && current->pid == eb->lock_owner) {
+                       eb->lock_nested = 0;
+                       read_unlock(&eb->lock);
+                       return;
+               }
+               read_unlock(&eb->lock);
+       }
        btrfs_assert_tree_read_locked(eb);
        WARN_ON(atomic_read(&eb->blocking_readers) == 0);
        if (atomic_dec_and_test(&eb->blocking_readers))
@@ -181,6 +229,7 @@ again:
        WARN_ON(atomic_read(&eb->spinning_writers));
        atomic_inc(&eb->spinning_writers);
        atomic_inc(&eb->write_locks);
+       eb->lock_owner = current->pid;
        return 0;
 }
 
index cfb55434a46981fa64416e68fa3fd29cf58238f5..8c1aae2c845d49960fe352c809033f1bdf5ffb74 100644 (file)
@@ -1604,12 +1604,12 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
                ret = btrfs_inc_extent_ref(trans, root, new_bytenr,
                                           num_bytes, parent,
                                           btrfs_header_owner(leaf),
-                                          key.objectid, key.offset);
+                                          key.objectid, key.offset, 1);
                BUG_ON(ret);
 
                ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
                                        parent, btrfs_header_owner(leaf),
-                                       key.objectid, key.offset);
+                                       key.objectid, key.offset, 1);
                BUG_ON(ret);
        }
        if (dirty)
@@ -1778,21 +1778,23 @@ again:
 
                ret = btrfs_inc_extent_ref(trans, src, old_bytenr, blocksize,
                                        path->nodes[level]->start,
-                                       src->root_key.objectid, level - 1, 0);
+                                       src->root_key.objectid, level - 1, 0,
+                                       1);
                BUG_ON(ret);
                ret = btrfs_inc_extent_ref(trans, dest, new_bytenr, blocksize,
                                        0, dest->root_key.objectid, level - 1,
-                                       0);
+                                       0, 1);
                BUG_ON(ret);
 
                ret = btrfs_free_extent(trans, src, new_bytenr, blocksize,
                                        path->nodes[level]->start,
-                                       src->root_key.objectid, level - 1, 0);
+                                       src->root_key.objectid, level - 1, 0,
+                                       1);
                BUG_ON(ret);
 
                ret = btrfs_free_extent(trans, dest, old_bytenr, blocksize,
                                        0, dest->root_key.objectid, level - 1,
-                                       0);
+                                       0, 1);
                BUG_ON(ret);
 
                btrfs_unlock_up_safe(path, 0);
@@ -2244,7 +2246,7 @@ again:
                } else {
                        list_del_init(&reloc_root->root_list);
                }
-               btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0);
+               btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0, 1);
        }
 
        if (found) {
@@ -2558,7 +2560,7 @@ static int do_relocation(struct btrfs_trans_handle *trans,
                                                node->eb->start, blocksize,
                                                upper->eb->start,
                                                btrfs_header_owner(upper->eb),
-                                               node->level, 0);
+                                               node->level, 0, 1);
                        BUG_ON(ret);
 
                        ret = btrfs_drop_subtree(trans, root, eb, upper->eb);
@@ -2947,9 +2949,7 @@ static int relocate_file_extent_cluster(struct inode *inode,
        index = (cluster->start - offset) >> PAGE_CACHE_SHIFT;
        last_index = (cluster->end - offset) >> PAGE_CACHE_SHIFT;
        while (index <= last_index) {
-               mutex_lock(&inode->i_mutex);
                ret = btrfs_delalloc_reserve_metadata(inode, PAGE_CACHE_SIZE);
-               mutex_unlock(&inode->i_mutex);
                if (ret)
                        goto out;
 
index ddf2c90d3fc0c475cbfabf6397c84f734abcc5e8..9770cc5bfb76c6829f96924bb82f9b3b564ca646 100644 (file)
@@ -25,6 +25,7 @@
 #include "transaction.h"
 #include "backref.h"
 #include "extent_io.h"
+#include "check-integrity.h"
 
 /*
  * This is only the first step towards a full-features scrub. It reads all
@@ -309,7 +310,7 @@ static void scrub_print_warning(const char *errstr, struct scrub_bio *sbio,
        u8 ref_level;
        unsigned long ptr = 0;
        const int bufsize = 4096;
-       u64 extent_offset;
+       u64 extent_item_pos;
 
        path = btrfs_alloc_path();
 
@@ -329,12 +330,13 @@ static void scrub_print_warning(const char *errstr, struct scrub_bio *sbio,
        if (ret < 0)
                goto out;
 
-       extent_offset = swarn.logical - found_key.objectid;
+       extent_item_pos = swarn.logical - found_key.objectid;
        swarn.extent_item_size = found_key.offset;
 
        eb = path->nodes[0];
        ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
        item_size = btrfs_item_size_nr(eb, path->slots[0]);
+       btrfs_release_path(path);
 
        if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
                do {
@@ -351,7 +353,7 @@ static void scrub_print_warning(const char *errstr, struct scrub_bio *sbio,
        } else {
                swarn.path = path;
                iterate_extent_inodes(fs_info, path, found_key.objectid,
-                                       extent_offset,
+                                       extent_item_pos,
                                        scrub_print_warning_inode, &swarn);
        }
 
@@ -732,7 +734,7 @@ static int scrub_fixup_io(int rw, struct block_device *bdev, sector_t sector,
        bio_add_page(bio, page, PAGE_SIZE, 0);
        bio->bi_end_io = scrub_fixup_end_io;
        bio->bi_private = &complete;
-       submit_bio(rw, bio);
+       btrfsic_submit_bio(rw, bio);
 
        /* this will also unplug the queue */
        wait_for_completion(&complete);
@@ -958,7 +960,7 @@ static int scrub_submit(struct scrub_dev *sdev)
        sdev->curr = -1;
        atomic_inc(&sdev->in_flight);
 
-       submit_bio(READ, sbio->bio);
+       btrfsic_submit_bio(READ, sbio->bio);
 
        return 0;
 }
index ae488aa1966a1b32d6a3c4438424eb690740d4c9..3ce97b217cbeae21ef23e57fe2a605ed11572af1 100644 (file)
@@ -147,13 +147,13 @@ void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
 
 static void btrfs_put_super(struct super_block *sb)
 {
-       struct btrfs_root *root = btrfs_sb(sb);
-       int ret;
-
-       ret = close_ctree(root);
-       sb->s_fs_info = NULL;
-
-       (void)ret; /* FIXME: need to fix VFS to return error? */
+       (void)close_ctree(btrfs_sb(sb)->tree_root);
+       /* FIXME: need to fix VFS to return error? */
+       /* AV: return it _where_?  ->put_super() can be triggered by any number
+        * of async events, up to and including delivery of SIGKILL to the
+        * last process that kept it busy.  Or segfault in the aforementioned
+        * process...  Whom would you report that to?
+        */
 }
 
 enum {
@@ -163,8 +163,11 @@ enum {
        Opt_compress_type, Opt_compress_force, Opt_compress_force_type,
        Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard,
        Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed,
-       Opt_enospc_debug, Opt_subvolrootid, Opt_defrag,
-       Opt_inode_cache, Opt_no_space_cache, Opt_recovery, Opt_err,
+       Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, Opt_inode_cache,
+       Opt_no_space_cache, Opt_recovery, Opt_skip_balance,
+       Opt_check_integrity, Opt_check_integrity_including_extent_data,
+       Opt_check_integrity_print_mask,
+       Opt_err,
 };
 
 static match_table_t tokens = {
@@ -199,6 +202,10 @@ static match_table_t tokens = {
        {Opt_inode_cache, "inode_cache"},
        {Opt_no_space_cache, "nospace_cache"},
        {Opt_recovery, "recovery"},
+       {Opt_skip_balance, "skip_balance"},
+       {Opt_check_integrity, "check_int"},
+       {Opt_check_integrity_including_extent_data, "check_int_data"},
+       {Opt_check_integrity_print_mask, "check_int_print_mask=%d"},
        {Opt_err, NULL},
 };
 
@@ -397,6 +404,40 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                        printk(KERN_INFO "btrfs: enabling auto recovery");
                        btrfs_set_opt(info->mount_opt, RECOVERY);
                        break;
+               case Opt_skip_balance:
+                       btrfs_set_opt(info->mount_opt, SKIP_BALANCE);
+                       break;
+#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+               case Opt_check_integrity_including_extent_data:
+                       printk(KERN_INFO "btrfs: enabling check integrity"
+                              " including extent data\n");
+                       btrfs_set_opt(info->mount_opt,
+                                     CHECK_INTEGRITY_INCLUDING_EXTENT_DATA);
+                       btrfs_set_opt(info->mount_opt, CHECK_INTEGRITY);
+                       break;
+               case Opt_check_integrity:
+                       printk(KERN_INFO "btrfs: enabling check integrity\n");
+                       btrfs_set_opt(info->mount_opt, CHECK_INTEGRITY);
+                       break;
+               case Opt_check_integrity_print_mask:
+                       intarg = 0;
+                       match_int(&args[0], &intarg);
+                       if (intarg) {
+                               info->check_integrity_print_mask = intarg;
+                               printk(KERN_INFO "btrfs:"
+                                      " check_integrity_print_mask 0x%x\n",
+                                      info->check_integrity_print_mask);
+                       }
+                       break;
+#else
+               case Opt_check_integrity_including_extent_data:
+               case Opt_check_integrity:
+               case Opt_check_integrity_print_mask:
+                       printk(KERN_ERR "btrfs: support for check_integrity*"
+                              " not compiled in!\n");
+                       ret = -EINVAL;
+                       goto out;
+#endif
                case Opt_err:
                        printk(KERN_INFO "btrfs: unrecognized mount option "
                               "'%s'\n", p);
@@ -500,7 +541,8 @@ out:
 static struct dentry *get_default_root(struct super_block *sb,
                                       u64 subvol_objectid)
 {
-       struct btrfs_root *root = sb->s_fs_info;
+       struct btrfs_fs_info *fs_info = btrfs_sb(sb);
+       struct btrfs_root *root = fs_info->tree_root;
        struct btrfs_root *new_root;
        struct btrfs_dir_item *di;
        struct btrfs_path *path;
@@ -530,7 +572,7 @@ static struct dentry *get_default_root(struct super_block *sb,
         * will mount by default if we haven't been given a specific subvolume
         * to mount.
         */
-       dir_id = btrfs_super_root_dir(root->fs_info->super_copy);
+       dir_id = btrfs_super_root_dir(fs_info->super_copy);
        di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0);
        if (IS_ERR(di)) {
                btrfs_free_path(path);
@@ -544,7 +586,7 @@ static struct dentry *get_default_root(struct super_block *sb,
                 */
                btrfs_free_path(path);
                dir_id = BTRFS_FIRST_FREE_OBJECTID;
-               new_root = root->fs_info->fs_root;
+               new_root = fs_info->fs_root;
                goto setup_root;
        }
 
@@ -552,7 +594,7 @@ static struct dentry *get_default_root(struct super_block *sb,
        btrfs_free_path(path);
 
 find_root:
-       new_root = btrfs_read_fs_root_no_name(root->fs_info, &location);
+       new_root = btrfs_read_fs_root_no_name(fs_info, &location);
        if (IS_ERR(new_root))
                return ERR_CAST(new_root);
 
@@ -588,7 +630,7 @@ static int btrfs_fill_super(struct super_block *sb,
 {
        struct inode *inode;
        struct dentry *root_dentry;
-       struct btrfs_root *tree_root;
+       struct btrfs_fs_info *fs_info = btrfs_sb(sb);
        struct btrfs_key key;
        int err;
 
@@ -603,18 +645,16 @@ static int btrfs_fill_super(struct super_block *sb,
        sb->s_flags |= MS_POSIXACL;
 #endif
 
-       tree_root = open_ctree(sb, fs_devices, (char *)data);
-
-       if (IS_ERR(tree_root)) {
+       err = open_ctree(sb, fs_devices, (char *)data);
+       if (err) {
                printk("btrfs: open_ctree failed\n");
-               return PTR_ERR(tree_root);
+               return err;
        }
-       sb->s_fs_info = tree_root;
 
        key.objectid = BTRFS_FIRST_FREE_OBJECTID;
        key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
-       inode = btrfs_iget(sb, &key, tree_root->fs_info->fs_root, NULL);
+       inode = btrfs_iget(sb, &key, fs_info->fs_root, NULL);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                goto fail_close;
@@ -631,23 +671,25 @@ static int btrfs_fill_super(struct super_block *sb,
 
        save_mount_options(sb, data);
        cleancache_init_fs(sb);
+       sb->s_flags |= MS_ACTIVE;
        return 0;
 
 fail_close:
-       close_ctree(tree_root);
+       close_ctree(fs_info->tree_root);
        return err;
 }
 
 int btrfs_sync_fs(struct super_block *sb, int wait)
 {
        struct btrfs_trans_handle *trans;
-       struct btrfs_root *root = btrfs_sb(sb);
+       struct btrfs_fs_info *fs_info = btrfs_sb(sb);
+       struct btrfs_root *root = fs_info->tree_root;
        int ret;
 
        trace_btrfs_sync_fs(wait);
 
        if (!wait) {
-               filemap_flush(root->fs_info->btree_inode->i_mapping);
+               filemap_flush(fs_info->btree_inode->i_mapping);
                return 0;
        }
 
@@ -663,8 +705,8 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
 
 static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
 {
-       struct btrfs_root *root = btrfs_sb(dentry->d_sb);
-       struct btrfs_fs_info *info = root->fs_info;
+       struct btrfs_fs_info *info = btrfs_sb(dentry->d_sb);
+       struct btrfs_root *root = info->tree_root;
        char *compress_type;
 
        if (btrfs_test_opt(root, DEGRADED))
@@ -722,28 +764,25 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
                seq_puts(seq, ",autodefrag");
        if (btrfs_test_opt(root, INODE_MAP_CACHE))
                seq_puts(seq, ",inode_cache");
+       if (btrfs_test_opt(root, SKIP_BALANCE))
+               seq_puts(seq, ",skip_balance");
        return 0;
 }
 
 static int btrfs_test_super(struct super_block *s, void *data)
 {
-       struct btrfs_root *test_root = data;
-       struct btrfs_root *root = btrfs_sb(s);
+       struct btrfs_fs_info *p = data;
+       struct btrfs_fs_info *fs_info = btrfs_sb(s);
 
-       /*
-        * If this super block is going away, return false as it
-        * can't match as an existing super block.
-        */
-       if (!atomic_read(&s->s_active))
-               return 0;
-       return root->fs_info->fs_devices == test_root->fs_info->fs_devices;
+       return fs_info->fs_devices == p->fs_devices;
 }
 
 static int btrfs_set_super(struct super_block *s, void *data)
 {
-       s->s_fs_info = data;
-
-       return set_anon_super(s, data);
+       int err = set_anon_super(s, data);
+       if (!err)
+               s->s_fs_info = data;
+       return err;
 }
 
 /*
@@ -903,12 +942,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
        if (!fs_info)
                return ERR_PTR(-ENOMEM);
 
-       fs_info->tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS);
-       if (!fs_info->tree_root) {
-               error = -ENOMEM;
-               goto error_fs_info;
-       }
-       fs_info->tree_root->fs_info = fs_info;
        fs_info->fs_devices = fs_devices;
 
        fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);
@@ -928,43 +961,30 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
        }
 
        bdev = fs_devices->latest_bdev;
-       s = sget(fs_type, btrfs_test_super, btrfs_set_super,
-                fs_info->tree_root);
+       s = sget(fs_type, btrfs_test_super, btrfs_set_super, fs_info);
        if (IS_ERR(s)) {
                error = PTR_ERR(s);
                goto error_close_devices;
        }
 
        if (s->s_root) {
-               if ((flags ^ s->s_flags) & MS_RDONLY) {
-                       deactivate_locked_super(s);
-                       error = -EBUSY;
-                       goto error_close_devices;
-               }
-
                btrfs_close_devices(fs_devices);
                free_fs_info(fs_info);
+               if ((flags ^ s->s_flags) & MS_RDONLY)
+                       error = -EBUSY;
        } else {
                char b[BDEVNAME_SIZE];
 
                s->s_flags = flags | MS_NOSEC;
                strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
-               btrfs_sb(s)->fs_info->bdev_holder = fs_type;
+               btrfs_sb(s)->bdev_holder = fs_type;
                error = btrfs_fill_super(s, fs_devices, data,
                                         flags & MS_SILENT ? 1 : 0);
-               if (error) {
-                       deactivate_locked_super(s);
-                       return ERR_PTR(error);
-               }
-
-               s->s_flags |= MS_ACTIVE;
        }
 
-       root = get_default_root(s, subvol_objectid);
-       if (IS_ERR(root)) {
+       root = !error ? get_default_root(s, subvol_objectid) : ERR_PTR(error);
+       if (IS_ERR(root))
                deactivate_locked_super(s);
-               return root;
-       }
 
        return root;
 
@@ -977,7 +997,8 @@ error_fs_info:
 
 static int btrfs_remount(struct super_block *sb, int *flags, char *data)
 {
-       struct btrfs_root *root = btrfs_sb(sb);
+       struct btrfs_fs_info *fs_info = btrfs_sb(sb);
+       struct btrfs_root *root = fs_info->tree_root;
        int ret;
 
        ret = btrfs_parse_options(root, data);
@@ -993,13 +1014,13 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                ret =  btrfs_commit_super(root);
                WARN_ON(ret);
        } else {
-               if (root->fs_info->fs_devices->rw_devices == 0)
+               if (fs_info->fs_devices->rw_devices == 0)
                        return -EACCES;
 
-               if (btrfs_super_log_root(root->fs_info->super_copy) != 0)
+               if (btrfs_super_log_root(fs_info->super_copy) != 0)
                        return -EINVAL;
 
-               ret = btrfs_cleanup_fs_roots(root->fs_info);
+               ret = btrfs_cleanup_fs_roots(fs_info);
                WARN_ON(ret);
 
                /* recover relocation */
@@ -1168,18 +1189,18 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
 
 static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
-       struct btrfs_root *root = btrfs_sb(dentry->d_sb);
-       struct btrfs_super_block *disk_super = root->fs_info->super_copy;
-       struct list_head *head = &root->fs_info->space_info;
+       struct btrfs_fs_info *fs_info = btrfs_sb(dentry->d_sb);
+       struct btrfs_super_block *disk_super = fs_info->super_copy;
+       struct list_head *head = &fs_info->space_info;
        struct btrfs_space_info *found;
        u64 total_used = 0;
        u64 total_free_data = 0;
        int bits = dentry->d_sb->s_blocksize_bits;
-       __be32 *fsid = (__be32 *)root->fs_info->fsid;
+       __be32 *fsid = (__be32 *)fs_info->fsid;
        int ret;
 
        /* holding chunk_muext to avoid allocating new chunks */
-       mutex_lock(&root->fs_info->chunk_mutex);
+       mutex_lock(&fs_info->chunk_mutex);
        rcu_read_lock();
        list_for_each_entry_rcu(found, head, list) {
                if (found->flags & BTRFS_BLOCK_GROUP_DATA) {
@@ -1198,14 +1219,14 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bsize = dentry->d_sb->s_blocksize;
        buf->f_type = BTRFS_SUPER_MAGIC;
        buf->f_bavail = total_free_data;
-       ret = btrfs_calc_avail_data_space(root, &total_free_data);
+       ret = btrfs_calc_avail_data_space(fs_info->tree_root, &total_free_data);
        if (ret) {
-               mutex_unlock(&root->fs_info->chunk_mutex);
+               mutex_unlock(&fs_info->chunk_mutex);
                return ret;
        }
        buf->f_bavail += total_free_data;
        buf->f_bavail = buf->f_bavail >> bits;
-       mutex_unlock(&root->fs_info->chunk_mutex);
+       mutex_unlock(&fs_info->chunk_mutex);
 
        /* We treat it as constant endianness (it doesn't matter _which_)
           because we want the fsid to come out the same whether mounted
@@ -1219,11 +1240,18 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        return 0;
 }
 
+static void btrfs_kill_super(struct super_block *sb)
+{
+       struct btrfs_fs_info *fs_info = btrfs_sb(sb);
+       kill_anon_super(sb);
+       free_fs_info(fs_info);
+}
+
 static struct file_system_type btrfs_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "btrfs",
        .mount          = btrfs_mount,
-       .kill_sb        = kill_anon_super,
+       .kill_sb        = btrfs_kill_super,
        .fs_flags       = FS_REQUIRES_DEV,
 };
 
@@ -1257,17 +1285,17 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
 
 static int btrfs_freeze(struct super_block *sb)
 {
-       struct btrfs_root *root = btrfs_sb(sb);
-       mutex_lock(&root->fs_info->transaction_kthread_mutex);
-       mutex_lock(&root->fs_info->cleaner_mutex);
+       struct btrfs_fs_info *fs_info = btrfs_sb(sb);
+       mutex_lock(&fs_info->transaction_kthread_mutex);
+       mutex_lock(&fs_info->cleaner_mutex);
        return 0;
 }
 
 static int btrfs_unfreeze(struct super_block *sb)
 {
-       struct btrfs_root *root = btrfs_sb(sb);
-       mutex_unlock(&root->fs_info->cleaner_mutex);
-       mutex_unlock(&root->fs_info->transaction_kthread_mutex);
+       struct btrfs_fs_info *fs_info = btrfs_sb(sb);
+       mutex_unlock(&fs_info->cleaner_mutex);
+       mutex_unlock(&fs_info->transaction_kthread_mutex);
        return 0;
 }
 
index 81376d94cd3c6a4639ebef35df501dbefbfb2435..287a6728b1ad6ddc726b64122223bfc71e7e165d 100644 (file)
@@ -36,6 +36,8 @@ static noinline void put_transaction(struct btrfs_transaction *transaction)
        WARN_ON(atomic_read(&transaction->use_count) == 0);
        if (atomic_dec_and_test(&transaction->use_count)) {
                BUG_ON(!list_empty(&transaction->list));
+               WARN_ON(transaction->delayed_refs.root.rb_node);
+               WARN_ON(!list_empty(&transaction->delayed_refs.seq_head));
                memset(transaction, 0, sizeof(*transaction));
                kmem_cache_free(btrfs_transaction_cachep, transaction);
        }
@@ -108,8 +110,11 @@ loop:
        cur_trans->delayed_refs.num_heads = 0;
        cur_trans->delayed_refs.flushing = 0;
        cur_trans->delayed_refs.run_delayed_start = 0;
+       cur_trans->delayed_refs.seq = 1;
+       init_waitqueue_head(&cur_trans->delayed_refs.seq_wait);
        spin_lock_init(&cur_trans->commit_lock);
        spin_lock_init(&cur_trans->delayed_refs.lock);
+       INIT_LIST_HEAD(&cur_trans->delayed_refs.seq_head);
 
        INIT_LIST_HEAD(&cur_trans->pending_snapshots);
        list_add_tail(&cur_trans->list, &root->fs_info->trans_list);
@@ -321,6 +326,8 @@ again:
        }
 
        if (num_bytes) {
+               trace_btrfs_space_reservation(root->fs_info, "transaction",
+                                             (u64)h, num_bytes, 1);
                h->block_rsv = &root->fs_info->trans_block_rsv;
                h->bytes_reserved = num_bytes;
        }
@@ -467,19 +474,12 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
 
        btrfs_trans_release_metadata(trans, root);
        trans->block_rsv = NULL;
-       while (count < 4) {
+       while (count < 2) {
                unsigned long cur = trans->delayed_ref_updates;
                trans->delayed_ref_updates = 0;
                if (cur &&
                    trans->transaction->delayed_refs.num_heads_ready > 64) {
                        trans->delayed_ref_updates = 0;
-
-                       /*
-                        * do a full flush if the transaction is trying
-                        * to close
-                        */
-                       if (trans->transaction->delayed_refs.flushing)
-                               cur = 0;
                        btrfs_run_delayed_refs(trans, root, cur);
                } else {
                        break;
@@ -1393,9 +1393,9 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root)
 
                if (btrfs_header_backref_rev(root->node) <
                    BTRFS_MIXED_BACKREF_REV)
-                       btrfs_drop_snapshot(root, NULL, 0);
+                       btrfs_drop_snapshot(root, NULL, 0, 0);
                else
-                       btrfs_drop_snapshot(root, NULL, 1);
+                       btrfs_drop_snapshot(root, NULL, 1, 0);
        }
        return 0;
 }
index 3568374d419da8ee50eb17f4af5319964750614d..cb877e0886a71b80e0f44f60e0d884f57203a597 100644 (file)
@@ -589,7 +589,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
                                ret = btrfs_inc_extent_ref(trans, root,
                                                ins.objectid, ins.offset,
                                                0, root->root_key.objectid,
-                                               key->objectid, offset);
+                                               key->objectid, offset, 0);
                                BUG_ON(ret);
                        } else {
                                /*
diff --git a/fs/btrfs/ulist.c b/fs/btrfs/ulist.c
new file mode 100644 (file)
index 0000000..12f5147
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2011 STRATO AG
+ * written by Arne Jansen <sensille@gmx.net>
+ * Distributed under the GNU GPL license version 2.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include "ulist.h"
+
+/*
+ * ulist is a generic data structure to hold a collection of unique u64
+ * values. The only operations it supports is adding to the list and
+ * enumerating it.
+ * It is possible to store an auxiliary value along with the key.
+ *
+ * The implementation is preliminary and can probably be sped up
+ * significantly. A first step would be to store the values in an rbtree
+ * as soon as ULIST_SIZE is exceeded.
+ *
+ * A sample usage for ulists is the enumeration of directed graphs without
+ * visiting a node twice. The pseudo-code could look like this:
+ *
+ * ulist = ulist_alloc();
+ * ulist_add(ulist, root);
+ * elem = NULL;
+ *
+ * while ((elem = ulist_next(ulist, elem)) {
+ *     for (all child nodes n in elem)
+ *             ulist_add(ulist, n);
+ *     do something useful with the node;
+ * }
+ * ulist_free(ulist);
+ *
+ * This assumes the graph nodes are adressable by u64. This stems from the
+ * usage for tree enumeration in btrfs, where the logical addresses are
+ * 64 bit.
+ *
+ * It is also useful for tree enumeration which could be done elegantly
+ * recursively, but is not possible due to kernel stack limitations. The
+ * loop would be similar to the above.
+ */
+
+/**
+ * ulist_init - freshly initialize a ulist
+ * @ulist:     the ulist to initialize
+ *
+ * Note: don't use this function to init an already used ulist, use
+ * ulist_reinit instead.
+ */
+void ulist_init(struct ulist *ulist)
+{
+       ulist->nnodes = 0;
+       ulist->nodes = ulist->int_nodes;
+       ulist->nodes_alloced = ULIST_SIZE;
+}
+EXPORT_SYMBOL(ulist_init);
+
+/**
+ * ulist_fini - free up additionally allocated memory for the ulist
+ * @ulist:     the ulist from which to free the additional memory
+ *
+ * This is useful in cases where the base 'struct ulist' has been statically
+ * allocated.
+ */
+void ulist_fini(struct ulist *ulist)
+{
+       /*
+        * The first ULIST_SIZE elements are stored inline in struct ulist.
+        * Only if more elements are alocated they need to be freed.
+        */
+       if (ulist->nodes_alloced > ULIST_SIZE)
+               kfree(ulist->nodes);
+       ulist->nodes_alloced = 0;       /* in case ulist_fini is called twice */
+}
+EXPORT_SYMBOL(ulist_fini);
+
+/**
+ * ulist_reinit - prepare a ulist for reuse
+ * @ulist:     ulist to be reused
+ *
+ * Free up all additional memory allocated for the list elements and reinit
+ * the ulist.
+ */
+void ulist_reinit(struct ulist *ulist)
+{
+       ulist_fini(ulist);
+       ulist_init(ulist);
+}
+EXPORT_SYMBOL(ulist_reinit);
+
+/**
+ * ulist_alloc - dynamically allocate a ulist
+ * @gfp_mask:  allocation flags to for base allocation
+ *
+ * The allocated ulist will be returned in an initialized state.
+ */
+struct ulist *ulist_alloc(unsigned long gfp_mask)
+{
+       struct ulist *ulist = kmalloc(sizeof(*ulist), gfp_mask);
+
+       if (!ulist)
+               return NULL;
+
+       ulist_init(ulist);
+
+       return ulist;
+}
+EXPORT_SYMBOL(ulist_alloc);
+
+/**
+ * ulist_free - free dynamically allocated ulist
+ * @ulist:     ulist to free
+ *
+ * It is not necessary to call ulist_fini before.
+ */
+void ulist_free(struct ulist *ulist)
+{
+       if (!ulist)
+               return;
+       ulist_fini(ulist);
+       kfree(ulist);
+}
+EXPORT_SYMBOL(ulist_free);
+
+/**
+ * ulist_add - add an element to the ulist
+ * @ulist:     ulist to add the element to
+ * @val:       value to add to ulist
+ * @aux:       auxiliary value to store along with val
+ * @gfp_mask:  flags to use for allocation
+ *
+ * Note: locking must be provided by the caller. In case of rwlocks write
+ *       locking is needed
+ *
+ * Add an element to a ulist. The @val will only be added if it doesn't
+ * already exist. If it is added, the auxiliary value @aux is stored along with
+ * it. In case @val already exists in the ulist, @aux is ignored, even if
+ * it differs from the already stored value.
+ *
+ * ulist_add returns 0 if @val already exists in ulist and 1 if @val has been
+ * inserted.
+ * In case of allocation failure -ENOMEM is returned and the ulist stays
+ * unaltered.
+ */
+int ulist_add(struct ulist *ulist, u64 val, unsigned long aux,
+             unsigned long gfp_mask)
+{
+       int i;
+
+       for (i = 0; i < ulist->nnodes; ++i) {
+               if (ulist->nodes[i].val == val)
+                       return 0;
+       }
+
+       if (ulist->nnodes >= ulist->nodes_alloced) {
+               u64 new_alloced = ulist->nodes_alloced + 128;
+               struct ulist_node *new_nodes;
+               void *old = NULL;
+
+               /*
+                * if nodes_alloced == ULIST_SIZE no memory has been allocated
+                * yet, so pass NULL to krealloc
+                */
+               if (ulist->nodes_alloced > ULIST_SIZE)
+                       old = ulist->nodes;
+
+               new_nodes = krealloc(old, sizeof(*new_nodes) * new_alloced,
+                                    gfp_mask);
+               if (!new_nodes)
+                       return -ENOMEM;
+
+               if (!old)
+                       memcpy(new_nodes, ulist->int_nodes,
+                              sizeof(ulist->int_nodes));
+
+               ulist->nodes = new_nodes;
+               ulist->nodes_alloced = new_alloced;
+       }
+       ulist->nodes[ulist->nnodes].val = val;
+       ulist->nodes[ulist->nnodes].aux = aux;
+       ++ulist->nnodes;
+
+       return 1;
+}
+EXPORT_SYMBOL(ulist_add);
+
+/**
+ * ulist_next - iterate ulist
+ * @ulist:     ulist to iterate
+ * @prev:      previously returned element or %NULL to start iteration
+ *
+ * Note: locking must be provided by the caller. In case of rwlocks only read
+ *       locking is needed
+ *
+ * This function is used to iterate an ulist. The iteration is started with
+ * @prev = %NULL. It returns the next element from the ulist or %NULL when the
+ * end is reached. No guarantee is made with respect to the order in which
+ * the elements are returned. They might neither be returned in order of
+ * addition nor in ascending order.
+ * It is allowed to call ulist_add during an enumeration. Newly added items
+ * are guaranteed to show up in the running enumeration.
+ */
+struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_node *prev)
+{
+       int next;
+
+       if (ulist->nnodes == 0)
+               return NULL;
+
+       if (!prev)
+               return &ulist->nodes[0];
+
+       next = (prev - ulist->nodes) + 1;
+       if (next < 0 || next >= ulist->nnodes)
+               return NULL;
+
+       return &ulist->nodes[next];
+}
+EXPORT_SYMBOL(ulist_next);
diff --git a/fs/btrfs/ulist.h b/fs/btrfs/ulist.h
new file mode 100644 (file)
index 0000000..2e25dec
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 STRATO AG
+ * written by Arne Jansen <sensille@gmx.net>
+ * Distributed under the GNU GPL license version 2.
+ *
+ */
+
+#ifndef __ULIST__
+#define __ULIST__
+
+/*
+ * ulist is a generic data structure to hold a collection of unique u64
+ * values. The only operations it supports is adding to the list and
+ * enumerating it.
+ * It is possible to store an auxiliary value along with the key.
+ *
+ * The implementation is preliminary and can probably be sped up
+ * significantly. A first step would be to store the values in an rbtree
+ * as soon as ULIST_SIZE is exceeded.
+ */
+
+/*
+ * number of elements statically allocated inside struct ulist
+ */
+#define ULIST_SIZE 16
+
+/*
+ * element of the list
+ */
+struct ulist_node {
+       u64 val;                /* value to store */
+       unsigned long aux;      /* auxiliary value saved along with the val */
+};
+
+struct ulist {
+       /*
+        * number of elements stored in list
+        */
+       unsigned long nnodes;
+
+       /*
+        * number of nodes we already have room for
+        */
+       unsigned long nodes_alloced;
+
+       /*
+        * pointer to the array storing the elements. The first ULIST_SIZE
+        * elements are stored inline. In this case the it points to int_nodes.
+        * After exceeding ULIST_SIZE, dynamic memory is allocated.
+        */
+       struct ulist_node *nodes;
+
+       /*
+        * inline storage space for the first ULIST_SIZE entries
+        */
+       struct ulist_node int_nodes[ULIST_SIZE];
+};
+
+void ulist_init(struct ulist *ulist);
+void ulist_fini(struct ulist *ulist);
+void ulist_reinit(struct ulist *ulist);
+struct ulist *ulist_alloc(unsigned long gfp_mask);
+void ulist_free(struct ulist *ulist);
+int ulist_add(struct ulist *ulist, u64 val, unsigned long aux,
+             unsigned long gfp_mask);
+struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_node *prev);
+
+#endif
index f4b839fd3c9dd5cd854cb7bada4e3831d8ea1713..0b4e2af7954d3c209d8f1e581d4ee26c0cb60c2f 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/random.h>
 #include <linux/iocontext.h>
 #include <linux/capability.h>
+#include <linux/kthread.h>
 #include <asm/div64.h>
 #include "compat.h"
 #include "ctree.h"
@@ -32,6 +33,7 @@
 #include "print-tree.h"
 #include "volumes.h"
 #include "async-thread.h"
+#include "check-integrity.h"
 
 static int init_first_rw_device(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root,
@@ -246,7 +248,7 @@ loop_lock:
                        sync_pending = 0;
                }
 
-               submit_bio(cur->bi_rw, cur);
+               btrfsic_submit_bio(cur->bi_rw, cur);
                num_run++;
                batch_run++;
                if (need_resched())
@@ -706,8 +708,6 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
        u64 devid;
        u64 transid;
 
-       mutex_lock(&uuid_mutex);
-
        flags |= FMODE_EXCL;
        bdev = blkdev_get_by_path(path, flags, holder);
 
@@ -716,6 +716,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
                goto error;
        }
 
+       mutex_lock(&uuid_mutex);
        ret = set_blocksize(bdev, 4096);
        if (ret)
                goto error_close;
@@ -737,9 +738,9 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
 
        brelse(bh);
 error_close:
+       mutex_unlock(&uuid_mutex);
        blkdev_put(bdev, flags);
 error:
-       mutex_unlock(&uuid_mutex);
        return ret;
 }
 
@@ -829,7 +830,6 @@ out:
 
 /*
  * find_free_dev_extent - find free space in the specified device
- * @trans:     transaction handler
  * @device:    the device which we search the free space in
  * @num_bytes: the size of the free space that we need
  * @start:     store the start of the free space.
@@ -848,8 +848,7 @@ out:
  * But if we don't find suitable free space, it is used to store the size of
  * the max free space.
  */
-int find_free_dev_extent(struct btrfs_trans_handle *trans,
-                        struct btrfs_device *device, u64 num_bytes,
+int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
                         u64 *start, u64 *len)
 {
        struct btrfs_key key;
@@ -893,7 +892,7 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
        key.offset = search_start;
        key.type = BTRFS_DEV_EXTENT_KEY;
 
-       ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
+       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
        if (ret < 0)
                goto out;
        if (ret > 0) {
@@ -1282,7 +1281,6 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
        bool clear_super = false;
 
        mutex_lock(&uuid_mutex);
-       mutex_lock(&root->fs_info->volume_mutex);
 
        all_avail = root->fs_info->avail_data_alloc_bits |
                root->fs_info->avail_system_alloc_bits |
@@ -1452,7 +1450,6 @@ error_close:
        if (bdev)
                blkdev_put(bdev, FMODE_READ | FMODE_EXCL);
 out:
-       mutex_unlock(&root->fs_info->volume_mutex);
        mutex_unlock(&uuid_mutex);
        return ret;
 error_undo:
@@ -1469,8 +1466,7 @@ error_undo:
 /*
  * does all the dirty work required for changing file system's UUID.
  */
-static int btrfs_prepare_sprout(struct btrfs_trans_handle *trans,
-                               struct btrfs_root *root)
+static int btrfs_prepare_sprout(struct btrfs_root *root)
 {
        struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
        struct btrfs_fs_devices *old_devices;
@@ -1629,7 +1625,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        }
 
        filemap_write_and_wait(bdev->bd_inode->i_mapping);
-       mutex_lock(&root->fs_info->volume_mutex);
 
        devices = &root->fs_info->fs_devices->devices;
        /*
@@ -1695,7 +1690,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 
        if (seeding_dev) {
                sb->s_flags &= ~MS_RDONLY;
-               ret = btrfs_prepare_sprout(trans, root);
+               ret = btrfs_prepare_sprout(root);
                BUG_ON(ret);
        }
 
@@ -1757,8 +1752,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
                ret = btrfs_relocate_sys_chunks(root);
                BUG_ON(ret);
        }
-out:
-       mutex_unlock(&root->fs_info->volume_mutex);
+
        return ret;
 error:
        blkdev_put(bdev, FMODE_EXCL);
@@ -1766,7 +1760,7 @@ error:
                mutex_unlock(&uuid_mutex);
                up_write(&sb->s_umount);
        }
-       goto out;
+       return ret;
 }
 
 static noinline int btrfs_update_device(struct btrfs_trans_handle *trans,
@@ -2077,6 +2071,362 @@ error:
        return ret;
 }
 
+static int insert_balance_item(struct btrfs_root *root,
+                              struct btrfs_balance_control *bctl)
+{
+       struct btrfs_trans_handle *trans;
+       struct btrfs_balance_item *item;
+       struct btrfs_disk_balance_args disk_bargs;
+       struct btrfs_path *path;
+       struct extent_buffer *leaf;
+       struct btrfs_key key;
+       int ret, err;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               btrfs_free_path(path);
+               return PTR_ERR(trans);
+       }
+
+       key.objectid = BTRFS_BALANCE_OBJECTID;
+       key.type = BTRFS_BALANCE_ITEM_KEY;
+       key.offset = 0;
+
+       ret = btrfs_insert_empty_item(trans, root, path, &key,
+                                     sizeof(*item));
+       if (ret)
+               goto out;
+
+       leaf = path->nodes[0];
+       item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_balance_item);
+
+       memset_extent_buffer(leaf, 0, (unsigned long)item, sizeof(*item));
+
+       btrfs_cpu_balance_args_to_disk(&disk_bargs, &bctl->data);
+       btrfs_set_balance_data(leaf, item, &disk_bargs);
+       btrfs_cpu_balance_args_to_disk(&disk_bargs, &bctl->meta);
+       btrfs_set_balance_meta(leaf, item, &disk_bargs);
+       btrfs_cpu_balance_args_to_disk(&disk_bargs, &bctl->sys);
+       btrfs_set_balance_sys(leaf, item, &disk_bargs);
+
+       btrfs_set_balance_flags(leaf, item, bctl->flags);
+
+       btrfs_mark_buffer_dirty(leaf);
+out:
+       btrfs_free_path(path);
+       err = btrfs_commit_transaction(trans, root);
+       if (err && !ret)
+               ret = err;
+       return ret;
+}
+
+static int del_balance_item(struct btrfs_root *root)
+{
+       struct btrfs_trans_handle *trans;
+       struct btrfs_path *path;
+       struct btrfs_key key;
+       int ret, err;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               btrfs_free_path(path);
+               return PTR_ERR(trans);
+       }
+
+       key.objectid = BTRFS_BALANCE_OBJECTID;
+       key.type = BTRFS_BALANCE_ITEM_KEY;
+       key.offset = 0;
+
+       ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
+       if (ret < 0)
+               goto out;
+       if (ret > 0) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       ret = btrfs_del_item(trans, root, path);
+out:
+       btrfs_free_path(path);
+       err = btrfs_commit_transaction(trans, root);
+       if (err && !ret)
+               ret = err;
+       return ret;
+}
+
+/*
+ * This is a heuristic used to reduce the number of chunks balanced on
+ * resume after balance was interrupted.
+ */
+static void update_balance_args(struct btrfs_balance_control *bctl)
+{
+       /*
+        * Turn on soft mode for chunk types that were being converted.
+        */
+       if (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT)
+               bctl->data.flags |= BTRFS_BALANCE_ARGS_SOFT;
+       if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT)
+               bctl->sys.flags |= BTRFS_BALANCE_ARGS_SOFT;
+       if (bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT)
+               bctl->meta.flags |= BTRFS_BALANCE_ARGS_SOFT;
+
+       /*
+        * Turn on usage filter if is not already used.  The idea is
+        * that chunks that we have already balanced should be
+        * reasonably full.  Don't do it for chunks that are being
+        * converted - that will keep us from relocating unconverted
+        * (albeit full) chunks.
+        */
+       if (!(bctl->data.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+           !(bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT)) {
+               bctl->data.flags |= BTRFS_BALANCE_ARGS_USAGE;
+               bctl->data.usage = 90;
+       }
+       if (!(bctl->sys.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+           !(bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT)) {
+               bctl->sys.flags |= BTRFS_BALANCE_ARGS_USAGE;
+               bctl->sys.usage = 90;
+       }
+       if (!(bctl->meta.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+           !(bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT)) {
+               bctl->meta.flags |= BTRFS_BALANCE_ARGS_USAGE;
+               bctl->meta.usage = 90;
+       }
+}
+
+/*
+ * Should be called with both balance and volume mutexes held to
+ * serialize other volume operations (add_dev/rm_dev/resize) with
+ * restriper.  Same goes for unset_balance_control.
+ */
+static void set_balance_control(struct btrfs_balance_control *bctl)
+{
+       struct btrfs_fs_info *fs_info = bctl->fs_info;
+
+       BUG_ON(fs_info->balance_ctl);
+
+       spin_lock(&fs_info->balance_lock);
+       fs_info->balance_ctl = bctl;
+       spin_unlock(&fs_info->balance_lock);
+}
+
+static void unset_balance_control(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_balance_control *bctl = fs_info->balance_ctl;
+
+       BUG_ON(!fs_info->balance_ctl);
+
+       spin_lock(&fs_info->balance_lock);
+       fs_info->balance_ctl = NULL;
+       spin_unlock(&fs_info->balance_lock);
+
+       kfree(bctl);
+}
+
+/*
+ * Balance filters.  Return 1 if chunk should be filtered out
+ * (should not be balanced).
+ */
+static int chunk_profiles_filter(u64 chunk_profile,
+                                struct btrfs_balance_args *bargs)
+{
+       chunk_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK;
+
+       if (chunk_profile == 0)
+               chunk_profile = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
+
+       if (bargs->profiles & chunk_profile)
+               return 0;
+
+       return 1;
+}
+
+static u64 div_factor_fine(u64 num, int factor)
+{
+       if (factor <= 0)
+               return 0;
+       if (factor >= 100)
+               return num;
+
+       num *= factor;
+       do_div(num, 100);
+       return num;
+}
+
+static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
+                             struct btrfs_balance_args *bargs)
+{
+       struct btrfs_block_group_cache *cache;
+       u64 chunk_used, user_thresh;
+       int ret = 1;
+
+       cache = btrfs_lookup_block_group(fs_info, chunk_offset);
+       chunk_used = btrfs_block_group_used(&cache->item);
+
+       user_thresh = div_factor_fine(cache->key.offset, bargs->usage);
+       if (chunk_used < user_thresh)
+               ret = 0;
+
+       btrfs_put_block_group(cache);
+       return ret;
+}
+
+static int chunk_devid_filter(struct extent_buffer *leaf,
+                             struct btrfs_chunk *chunk,
+                             struct btrfs_balance_args *bargs)
+{
+       struct btrfs_stripe *stripe;
+       int num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
+       int i;
+
+       for (i = 0; i < num_stripes; i++) {
+               stripe = btrfs_stripe_nr(chunk, i);
+               if (btrfs_stripe_devid(leaf, stripe) == bargs->devid)
+                       return 0;
+       }
+
+       return 1;
+}
+
+/* [pstart, pend) */
+static int chunk_drange_filter(struct extent_buffer *leaf,
+                              struct btrfs_chunk *chunk,
+                              u64 chunk_offset,
+                              struct btrfs_balance_args *bargs)
+{
+       struct btrfs_stripe *stripe;
+       int num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
+       u64 stripe_offset;
+       u64 stripe_length;
+       int factor;
+       int i;
+
+       if (!(bargs->flags & BTRFS_BALANCE_ARGS_DEVID))
+               return 0;
+
+       if (btrfs_chunk_type(leaf, chunk) & (BTRFS_BLOCK_GROUP_DUP |
+            BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10))
+               factor = 2;
+       else
+               factor = 1;
+       factor = num_stripes / factor;
+
+       for (i = 0; i < num_stripes; i++) {
+               stripe = btrfs_stripe_nr(chunk, i);
+               if (btrfs_stripe_devid(leaf, stripe) != bargs->devid)
+                       continue;
+
+               stripe_offset = btrfs_stripe_offset(leaf, stripe);
+               stripe_length = btrfs_chunk_length(leaf, chunk);
+               do_div(stripe_length, factor);
+
+               if (stripe_offset < bargs->pend &&
+                   stripe_offset + stripe_length > bargs->pstart)
+                       return 0;
+       }
+
+       return 1;
+}
+
+/* [vstart, vend) */
+static int chunk_vrange_filter(struct extent_buffer *leaf,
+                              struct btrfs_chunk *chunk,
+                              u64 chunk_offset,
+                              struct btrfs_balance_args *bargs)
+{
+       if (chunk_offset < bargs->vend &&
+           chunk_offset + btrfs_chunk_length(leaf, chunk) > bargs->vstart)
+               /* at least part of the chunk is inside this vrange */
+               return 0;
+
+       return 1;
+}
+
+static int chunk_soft_convert_filter(u64 chunk_profile,
+                                    struct btrfs_balance_args *bargs)
+{
+       if (!(bargs->flags & BTRFS_BALANCE_ARGS_CONVERT))
+               return 0;
+
+       chunk_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK;
+
+       if (chunk_profile == 0)
+               chunk_profile = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
+
+       if (bargs->target & chunk_profile)
+               return 1;
+
+       return 0;
+}
+
+static int should_balance_chunk(struct btrfs_root *root,
+                               struct extent_buffer *leaf,
+                               struct btrfs_chunk *chunk, u64 chunk_offset)
+{
+       struct btrfs_balance_control *bctl = root->fs_info->balance_ctl;
+       struct btrfs_balance_args *bargs = NULL;
+       u64 chunk_type = btrfs_chunk_type(leaf, chunk);
+
+       /* type filter */
+       if (!((chunk_type & BTRFS_BLOCK_GROUP_TYPE_MASK) &
+             (bctl->flags & BTRFS_BALANCE_TYPE_MASK))) {
+               return 0;
+       }
+
+       if (chunk_type & BTRFS_BLOCK_GROUP_DATA)
+               bargs = &bctl->data;
+       else if (chunk_type & BTRFS_BLOCK_GROUP_SYSTEM)
+               bargs = &bctl->sys;
+       else if (chunk_type & BTRFS_BLOCK_GROUP_METADATA)
+               bargs = &bctl->meta;
+
+       /* profiles filter */
+       if ((bargs->flags & BTRFS_BALANCE_ARGS_PROFILES) &&
+           chunk_profiles_filter(chunk_type, bargs)) {
+               return 0;
+       }
+
+       /* usage filter */
+       if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE) &&
+           chunk_usage_filter(bctl->fs_info, chunk_offset, bargs)) {
+               return 0;
+       }
+
+       /* devid filter */
+       if ((bargs->flags & BTRFS_BALANCE_ARGS_DEVID) &&
+           chunk_devid_filter(leaf, chunk, bargs)) {
+               return 0;
+       }
+
+       /* drange filter, makes sense only with devid filter */
+       if ((bargs->flags & BTRFS_BALANCE_ARGS_DRANGE) &&
+           chunk_drange_filter(leaf, chunk, chunk_offset, bargs)) {
+               return 0;
+       }
+
+       /* vrange filter */
+       if ((bargs->flags & BTRFS_BALANCE_ARGS_VRANGE) &&
+           chunk_vrange_filter(leaf, chunk, chunk_offset, bargs)) {
+               return 0;
+       }
+
+       /* soft profile changing mode */
+       if ((bargs->flags & BTRFS_BALANCE_ARGS_SOFT) &&
+           chunk_soft_convert_filter(chunk_type, bargs)) {
+               return 0;
+       }
+
+       return 1;
+}
+
 static u64 div_factor(u64 num, int factor)
 {
        if (factor == 10)
@@ -2086,29 +2436,28 @@ static u64 div_factor(u64 num, int factor)
        return num;
 }
 
-int btrfs_balance(struct btrfs_root *dev_root)
+static int __btrfs_balance(struct btrfs_fs_info *fs_info)
 {
-       int ret;
-       struct list_head *devices = &dev_root->fs_info->fs_devices->devices;
+       struct btrfs_balance_control *bctl = fs_info->balance_ctl;
+       struct btrfs_root *chunk_root = fs_info->chunk_root;
+       struct btrfs_root *dev_root = fs_info->dev_root;
+       struct list_head *devices;
        struct btrfs_device *device;
        u64 old_size;
        u64 size_to_free;
+       struct btrfs_chunk *chunk;
        struct btrfs_path *path;
        struct btrfs_key key;
-       struct btrfs_root *chunk_root = dev_root->fs_info->chunk_root;
-       struct btrfs_trans_handle *trans;
        struct btrfs_key found_key;
-
-       if (dev_root->fs_info->sb->s_flags & MS_RDONLY)
-               return -EROFS;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       mutex_lock(&dev_root->fs_info->volume_mutex);
-       dev_root = dev_root->fs_info->dev_root;
+       struct btrfs_trans_handle *trans;
+       struct extent_buffer *leaf;
+       int slot;
+       int ret;
+       int enospc_errors = 0;
+       bool counting = true;
 
        /* step one make some room on all the devices */
+       devices = &fs_info->fs_devices->devices;
        list_for_each_entry(device, devices, dev_list) {
                old_size = device->total_bytes;
                size_to_free = div_factor(old_size, 1);
@@ -2137,11 +2486,23 @@ int btrfs_balance(struct btrfs_root *dev_root)
                ret = -ENOMEM;
                goto error;
        }
+
+       /* zero out stat counters */
+       spin_lock(&fs_info->balance_lock);
+       memset(&bctl->stat, 0, sizeof(bctl->stat));
+       spin_unlock(&fs_info->balance_lock);
+again:
        key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
        key.offset = (u64)-1;
        key.type = BTRFS_CHUNK_ITEM_KEY;
 
        while (1) {
+               if ((!counting && atomic_read(&fs_info->balance_pause_req)) ||
+                   atomic_read(&fs_info->balance_cancel_req)) {
+                       ret = -ECANCELED;
+                       goto error;
+               }
+
                ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0);
                if (ret < 0)
                        goto error;
@@ -2151,15 +2512,19 @@ int btrfs_balance(struct btrfs_root *dev_root)
                 * failed
                 */
                if (ret == 0)
-                       break;
+                       BUG(); /* FIXME break ? */
 
                ret = btrfs_previous_item(chunk_root, path, 0,
                                          BTRFS_CHUNK_ITEM_KEY);
-               if (ret)
+               if (ret) {
+                       ret = 0;
                        break;
+               }
+
+               leaf = path->nodes[0];
+               slot = path->slots[0];
+               btrfs_item_key_to_cpu(leaf, &found_key, slot);
 
-               btrfs_item_key_to_cpu(path->nodes[0], &found_key,
-                                     path->slots[0]);
                if (found_key.objectid != key.objectid)
                        break;
 
@@ -2167,22 +2532,375 @@ int btrfs_balance(struct btrfs_root *dev_root)
                if (found_key.offset == 0)
                        break;
 
+               chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
+
+               if (!counting) {
+                       spin_lock(&fs_info->balance_lock);
+                       bctl->stat.considered++;
+                       spin_unlock(&fs_info->balance_lock);
+               }
+
+               ret = should_balance_chunk(chunk_root, leaf, chunk,
+                                          found_key.offset);
                btrfs_release_path(path);
+               if (!ret)
+                       goto loop;
+
+               if (counting) {
+                       spin_lock(&fs_info->balance_lock);
+                       bctl->stat.expected++;
+                       spin_unlock(&fs_info->balance_lock);
+                       goto loop;
+               }
+
                ret = btrfs_relocate_chunk(chunk_root,
                                           chunk_root->root_key.objectid,
                                           found_key.objectid,
                                           found_key.offset);
                if (ret && ret != -ENOSPC)
                        goto error;
+               if (ret == -ENOSPC) {
+                       enospc_errors++;
+               } else {
+                       spin_lock(&fs_info->balance_lock);
+                       bctl->stat.completed++;
+                       spin_unlock(&fs_info->balance_lock);
+               }
+loop:
                key.offset = found_key.offset - 1;
        }
-       ret = 0;
+
+       if (counting) {
+               btrfs_release_path(path);
+               counting = false;
+               goto again;
+       }
 error:
        btrfs_free_path(path);
-       mutex_unlock(&dev_root->fs_info->volume_mutex);
+       if (enospc_errors) {
+               printk(KERN_INFO "btrfs: %d enospc errors during balance\n",
+                      enospc_errors);
+               if (!ret)
+                       ret = -ENOSPC;
+       }
+
        return ret;
 }
 
+static inline int balance_need_close(struct btrfs_fs_info *fs_info)
+{
+       /* cancel requested || normal exit path */
+       return atomic_read(&fs_info->balance_cancel_req) ||
+               (atomic_read(&fs_info->balance_pause_req) == 0 &&
+                atomic_read(&fs_info->balance_cancel_req) == 0);
+}
+
+static void __cancel_balance(struct btrfs_fs_info *fs_info)
+{
+       int ret;
+
+       unset_balance_control(fs_info);
+       ret = del_balance_item(fs_info->tree_root);
+       BUG_ON(ret);
+}
+
+void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock,
+                              struct btrfs_ioctl_balance_args *bargs);
+
+/*
+ * Should be called with both balance and volume mutexes held
+ */
+int btrfs_balance(struct btrfs_balance_control *bctl,
+                 struct btrfs_ioctl_balance_args *bargs)
+{
+       struct btrfs_fs_info *fs_info = bctl->fs_info;
+       u64 allowed;
+       int ret;
+
+       if (btrfs_fs_closing(fs_info) ||
+           atomic_read(&fs_info->balance_pause_req) ||
+           atomic_read(&fs_info->balance_cancel_req)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /*
+        * In case of mixed groups both data and meta should be picked,
+        * and identical options should be given for both of them.
+        */
+       allowed = btrfs_super_incompat_flags(fs_info->super_copy);
+       if ((allowed & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) &&
+           (bctl->flags & (BTRFS_BALANCE_DATA | BTRFS_BALANCE_METADATA))) {
+               if (!(bctl->flags & BTRFS_BALANCE_DATA) ||
+                   !(bctl->flags & BTRFS_BALANCE_METADATA) ||
+                   memcmp(&bctl->data, &bctl->meta, sizeof(bctl->data))) {
+                       printk(KERN_ERR "btrfs: with mixed groups data and "
+                              "metadata balance options must be the same\n");
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       /*
+        * Profile changing sanity checks.  Skip them if a simple
+        * balance is requested.
+        */
+       if (!((bctl->data.flags | bctl->sys.flags | bctl->meta.flags) &
+             BTRFS_BALANCE_ARGS_CONVERT))
+               goto do_balance;
+
+       allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
+       if (fs_info->fs_devices->num_devices == 1)
+               allowed |= BTRFS_BLOCK_GROUP_DUP;
+       else if (fs_info->fs_devices->num_devices < 4)
+               allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1);
+       else
+               allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
+                               BTRFS_BLOCK_GROUP_RAID10);
+
+       if (!profile_is_valid(bctl->data.target, 1) ||
+           bctl->data.target & ~allowed) {
+               printk(KERN_ERR "btrfs: unable to start balance with target "
+                      "data profile %llu\n",
+                      (unsigned long long)bctl->data.target);
+               ret = -EINVAL;
+               goto out;
+       }
+       if (!profile_is_valid(bctl->meta.target, 1) ||
+           bctl->meta.target & ~allowed) {
+               printk(KERN_ERR "btrfs: unable to start balance with target "
+                      "metadata profile %llu\n",
+                      (unsigned long long)bctl->meta.target);
+               ret = -EINVAL;
+               goto out;
+       }
+       if (!profile_is_valid(bctl->sys.target, 1) ||
+           bctl->sys.target & ~allowed) {
+               printk(KERN_ERR "btrfs: unable to start balance with target "
+                      "system profile %llu\n",
+                      (unsigned long long)bctl->sys.target);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (bctl->data.target & BTRFS_BLOCK_GROUP_DUP) {
+               printk(KERN_ERR "btrfs: dup for data is not allowed\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* allow to reduce meta or sys integrity only if force set */
+       allowed = BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 |
+                       BTRFS_BLOCK_GROUP_RAID10;
+       if (((bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
+            (fs_info->avail_system_alloc_bits & allowed) &&
+            !(bctl->sys.target & allowed)) ||
+           ((bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
+            (fs_info->avail_metadata_alloc_bits & allowed) &&
+            !(bctl->meta.target & allowed))) {
+               if (bctl->flags & BTRFS_BALANCE_FORCE) {
+                       printk(KERN_INFO "btrfs: force reducing metadata "
+                              "integrity\n");
+               } else {
+                       printk(KERN_ERR "btrfs: balance will reduce metadata "
+                              "integrity, use force if you want this\n");
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+do_balance:
+       ret = insert_balance_item(fs_info->tree_root, bctl);
+       if (ret && ret != -EEXIST)
+               goto out;
+
+       if (!(bctl->flags & BTRFS_BALANCE_RESUME)) {
+               BUG_ON(ret == -EEXIST);
+               set_balance_control(bctl);
+       } else {
+               BUG_ON(ret != -EEXIST);
+               spin_lock(&fs_info->balance_lock);
+               update_balance_args(bctl);
+               spin_unlock(&fs_info->balance_lock);
+       }
+
+       atomic_inc(&fs_info->balance_running);
+       mutex_unlock(&fs_info->balance_mutex);
+
+       ret = __btrfs_balance(fs_info);
+
+       mutex_lock(&fs_info->balance_mutex);
+       atomic_dec(&fs_info->balance_running);
+
+       if (bargs) {
+               memset(bargs, 0, sizeof(*bargs));
+               update_ioctl_balance_args(fs_info, 0, bargs);
+       }
+
+       if ((ret && ret != -ECANCELED && ret != -ENOSPC) ||
+           balance_need_close(fs_info)) {
+               __cancel_balance(fs_info);
+       }
+
+       wake_up(&fs_info->balance_wait_q);
+
+       return ret;
+out:
+       if (bctl->flags & BTRFS_BALANCE_RESUME)
+               __cancel_balance(fs_info);
+       else
+               kfree(bctl);
+       return ret;
+}
+
+static int balance_kthread(void *data)
+{
+       struct btrfs_balance_control *bctl =
+                       (struct btrfs_balance_control *)data;
+       struct btrfs_fs_info *fs_info = bctl->fs_info;
+       int ret = 0;
+
+       mutex_lock(&fs_info->volume_mutex);
+       mutex_lock(&fs_info->balance_mutex);
+
+       set_balance_control(bctl);
+
+       if (btrfs_test_opt(fs_info->tree_root, SKIP_BALANCE)) {
+               printk(KERN_INFO "btrfs: force skipping balance\n");
+       } else {
+               printk(KERN_INFO "btrfs: continuing balance\n");
+               ret = btrfs_balance(bctl, NULL);
+       }
+
+       mutex_unlock(&fs_info->balance_mutex);
+       mutex_unlock(&fs_info->volume_mutex);
+       return ret;
+}
+
+int btrfs_recover_balance(struct btrfs_root *tree_root)
+{
+       struct task_struct *tsk;
+       struct btrfs_balance_control *bctl;
+       struct btrfs_balance_item *item;
+       struct btrfs_disk_balance_args disk_bargs;
+       struct btrfs_path *path;
+       struct extent_buffer *leaf;
+       struct btrfs_key key;
+       int ret;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       bctl = kzalloc(sizeof(*bctl), GFP_NOFS);
+       if (!bctl) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       key.objectid = BTRFS_BALANCE_OBJECTID;
+       key.type = BTRFS_BALANCE_ITEM_KEY;
+       key.offset = 0;
+
+       ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
+       if (ret < 0)
+               goto out_bctl;
+       if (ret > 0) { /* ret = -ENOENT; */
+               ret = 0;
+               goto out_bctl;
+       }
+
+       leaf = path->nodes[0];
+       item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_balance_item);
+
+       bctl->fs_info = tree_root->fs_info;
+       bctl->flags = btrfs_balance_flags(leaf, item) | BTRFS_BALANCE_RESUME;
+
+       btrfs_balance_data(leaf, item, &disk_bargs);
+       btrfs_disk_balance_args_to_cpu(&bctl->data, &disk_bargs);
+       btrfs_balance_meta(leaf, item, &disk_bargs);
+       btrfs_disk_balance_args_to_cpu(&bctl->meta, &disk_bargs);
+       btrfs_balance_sys(leaf, item, &disk_bargs);
+       btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs);
+
+       tsk = kthread_run(balance_kthread, bctl, "btrfs-balance");
+       if (IS_ERR(tsk))
+               ret = PTR_ERR(tsk);
+       else
+               goto out;
+
+out_bctl:
+       kfree(bctl);
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+int btrfs_pause_balance(struct btrfs_fs_info *fs_info)
+{
+       int ret = 0;
+
+       mutex_lock(&fs_info->balance_mutex);
+       if (!fs_info->balance_ctl) {
+               mutex_unlock(&fs_info->balance_mutex);
+               return -ENOTCONN;
+       }
+
+       if (atomic_read(&fs_info->balance_running)) {
+               atomic_inc(&fs_info->balance_pause_req);
+               mutex_unlock(&fs_info->balance_mutex);
+
+               wait_event(fs_info->balance_wait_q,
+                          atomic_read(&fs_info->balance_running) == 0);
+
+               mutex_lock(&fs_info->balance_mutex);
+               /* we are good with balance_ctl ripped off from under us */
+               BUG_ON(atomic_read(&fs_info->balance_running));
+               atomic_dec(&fs_info->balance_pause_req);
+       } else {
+               ret = -ENOTCONN;
+       }
+
+       mutex_unlock(&fs_info->balance_mutex);
+       return ret;
+}
+
+int btrfs_cancel_balance(struct btrfs_fs_info *fs_info)
+{
+       mutex_lock(&fs_info->balance_mutex);
+       if (!fs_info->balance_ctl) {
+               mutex_unlock(&fs_info->balance_mutex);
+               return -ENOTCONN;
+       }
+
+       atomic_inc(&fs_info->balance_cancel_req);
+       /*
+        * if we are running just wait and return, balance item is
+        * deleted in btrfs_balance in this case
+        */
+       if (atomic_read(&fs_info->balance_running)) {
+               mutex_unlock(&fs_info->balance_mutex);
+               wait_event(fs_info->balance_wait_q,
+                          atomic_read(&fs_info->balance_running) == 0);
+               mutex_lock(&fs_info->balance_mutex);
+       } else {
+               /* __cancel_balance needs volume_mutex */
+               mutex_unlock(&fs_info->balance_mutex);
+               mutex_lock(&fs_info->volume_mutex);
+               mutex_lock(&fs_info->balance_mutex);
+
+               if (fs_info->balance_ctl)
+                       __cancel_balance(fs_info);
+
+               mutex_unlock(&fs_info->volume_mutex);
+       }
+
+       BUG_ON(fs_info->balance_ctl || atomic_read(&fs_info->balance_running));
+       atomic_dec(&fs_info->balance_cancel_req);
+       mutex_unlock(&fs_info->balance_mutex);
+       return 0;
+}
+
 /*
  * shrinking a device means finding all of the device extents past
  * the new size, and then following the back refs to the chunks.
@@ -2323,8 +3041,7 @@ done:
        return ret;
 }
 
-static int btrfs_add_system_chunk(struct btrfs_trans_handle *trans,
-                          struct btrfs_root *root,
+static int btrfs_add_system_chunk(struct btrfs_root *root,
                           struct btrfs_key *key,
                           struct btrfs_chunk *chunk, int item_size)
 {
@@ -2441,10 +3158,14 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                max_stripe_size = 1024 * 1024 * 1024;
                max_chunk_size = 10 * max_stripe_size;
        } else if (type & BTRFS_BLOCK_GROUP_METADATA) {
-               max_stripe_size = 256 * 1024 * 1024;
+               /* for larger filesystems, use larger metadata chunks */
+               if (fs_devices->total_rw_bytes > 50ULL * 1024 * 1024 * 1024)
+                       max_stripe_size = 1024 * 1024 * 1024;
+               else
+                       max_stripe_size = 256 * 1024 * 1024;
                max_chunk_size = max_stripe_size;
        } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
-               max_stripe_size = 8 * 1024 * 1024;
+               max_stripe_size = 32 * 1024 * 1024;
                max_chunk_size = 2 * max_stripe_size;
        } else {
                printk(KERN_ERR "btrfs: invalid chunk type 0x%llx requested\n",
@@ -2496,7 +3217,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                if (total_avail == 0)
                        continue;
 
-               ret = find_free_dev_extent(trans, device,
+               ret = find_free_dev_extent(device,
                                           max_stripe_size * dev_stripes,
                                           &dev_offset, &max_avail);
                if (ret && ret != -ENOSPC)
@@ -2687,7 +3408,7 @@ static int __finish_chunk_alloc(struct btrfs_trans_handle *trans,
        BUG_ON(ret);
 
        if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) {
-               ret = btrfs_add_system_chunk(trans, chunk_root, &key, chunk,
+               ret = btrfs_add_system_chunk(chunk_root, &key, chunk,
                                             item_size);
                BUG_ON(ret);
        }
@@ -2752,8 +3473,7 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans,
                return ret;
 
        alloc_profile = BTRFS_BLOCK_GROUP_METADATA |
-                       (fs_info->metadata_alloc_profile &
-                        fs_info->avail_metadata_alloc_bits);
+                               fs_info->avail_metadata_alloc_bits;
        alloc_profile = btrfs_reduce_alloc_profile(root, alloc_profile);
 
        ret = __btrfs_alloc_chunk(trans, extent_root, &map, &chunk_size,
@@ -2763,8 +3483,7 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans,
        sys_chunk_offset = chunk_offset + chunk_size;
 
        alloc_profile = BTRFS_BLOCK_GROUP_SYSTEM |
-                       (fs_info->system_alloc_profile &
-                        fs_info->avail_system_alloc_bits);
+                               fs_info->avail_system_alloc_bits;
        alloc_profile = btrfs_reduce_alloc_profile(root, alloc_profile);
 
        ret = __btrfs_alloc_chunk(trans, extent_root, &sys_map,
@@ -2901,26 +3620,13 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
        u64 stripe_nr;
        u64 stripe_nr_orig;
        u64 stripe_nr_end;
-       int stripes_allocated = 8;
-       int stripes_required = 1;
        int stripe_index;
        int i;
+       int ret = 0;
        int num_stripes;
        int max_errors = 0;
        struct btrfs_bio *bbio = NULL;
 
-       if (bbio_ret && !(rw & (REQ_WRITE | REQ_DISCARD)))
-               stripes_allocated = 1;
-again:
-       if (bbio_ret) {
-               bbio = kzalloc(btrfs_bio_size(stripes_allocated),
-                               GFP_NOFS);
-               if (!bbio)
-                       return -ENOMEM;
-
-               atomic_set(&bbio->error, 0);
-       }
-
        read_lock(&em_tree->lock);
        em = lookup_extent_mapping(em_tree, logical, *length);
        read_unlock(&em_tree->lock);
@@ -2939,32 +3645,6 @@ again:
        if (mirror_num > map->num_stripes)
                mirror_num = 0;
 
-       /* if our btrfs_bio struct is too small, back off and try again */
-       if (rw & REQ_WRITE) {
-               if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
-                                BTRFS_BLOCK_GROUP_DUP)) {
-                       stripes_required = map->num_stripes;
-                       max_errors = 1;
-               } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
-                       stripes_required = map->sub_stripes;
-                       max_errors = 1;
-               }
-       }
-       if (rw & REQ_DISCARD) {
-               if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
-                                BTRFS_BLOCK_GROUP_RAID1 |
-                                BTRFS_BLOCK_GROUP_DUP |
-                                BTRFS_BLOCK_GROUP_RAID10)) {
-                       stripes_required = map->num_stripes;
-               }
-       }
-       if (bbio_ret && (rw & (REQ_WRITE | REQ_DISCARD)) &&
-           stripes_allocated < stripes_required) {
-               stripes_allocated = map->num_stripes;
-               free_extent_map(em);
-               kfree(bbio);
-               goto again;
-       }
        stripe_nr = offset;
        /*
         * stripe_nr counts the total number of stripes we have to stride
@@ -2980,10 +3660,7 @@ again:
 
        if (rw & REQ_DISCARD)
                *length = min_t(u64, em->len - offset, *length);
-       else if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
-                             BTRFS_BLOCK_GROUP_RAID1 |
-                             BTRFS_BLOCK_GROUP_RAID10 |
-                             BTRFS_BLOCK_GROUP_DUP)) {
+       else if (map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
                /* we limit the length of each bio to what fits in a stripe */
                *length = min_t(u64, em->len - offset,
                                map->stripe_len - stripe_offset);
@@ -3059,81 +3736,55 @@ again:
        }
        BUG_ON(stripe_index >= map->num_stripes);
 
+       bbio = kzalloc(btrfs_bio_size(num_stripes), GFP_NOFS);
+       if (!bbio) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       atomic_set(&bbio->error, 0);
+
        if (rw & REQ_DISCARD) {
+               int factor = 0;
+               int sub_stripes = 0;
+               u64 stripes_per_dev = 0;
+               u32 remaining_stripes = 0;
+
+               if (map->type &
+                   (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) {
+                       if (map->type & BTRFS_BLOCK_GROUP_RAID0)
+                               sub_stripes = 1;
+                       else
+                               sub_stripes = map->sub_stripes;
+
+                       factor = map->num_stripes / sub_stripes;
+                       stripes_per_dev = div_u64_rem(stripe_nr_end -
+                                                     stripe_nr_orig,
+                                                     factor,
+                                                     &remaining_stripes);
+               }
+
                for (i = 0; i < num_stripes; i++) {
                        bbio->stripes[i].physical =
                                map->stripes[stripe_index].physical +
                                stripe_offset + stripe_nr * map->stripe_len;
                        bbio->stripes[i].dev = map->stripes[stripe_index].dev;
 
-                       if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
-                               u64 stripes;
-                               u32 last_stripe = 0;
-                               int j;
-
-                               div_u64_rem(stripe_nr_end - 1,
-                                           map->num_stripes,
-                                           &last_stripe);
-
-                               for (j = 0; j < map->num_stripes; j++) {
-                                       u32 test;
-
-                                       div_u64_rem(stripe_nr_end - 1 - j,
-                                                   map->num_stripes, &test);
-                                       if (test == stripe_index)
-                                               break;
-                               }
-                               stripes = stripe_nr_end - 1 - j;
-                               do_div(stripes, map->num_stripes);
-                               bbio->stripes[i].length = map->stripe_len *
-                                       (stripes - stripe_nr + 1);
-
-                               if (i == 0) {
-                                       bbio->stripes[i].length -=
-                                               stripe_offset;
-                                       stripe_offset = 0;
-                               }
-                               if (stripe_index == last_stripe)
-                                       bbio->stripes[i].length -=
-                                               stripe_end_offset;
-                       } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
-                               u64 stripes;
-                               int j;
-                               int factor = map->num_stripes /
-                                            map->sub_stripes;
-                               u32 last_stripe = 0;
-
-                               div_u64_rem(stripe_nr_end - 1,
-                                           factor, &last_stripe);
-                               last_stripe *= map->sub_stripes;
-
-                               for (j = 0; j < factor; j++) {
-                                       u32 test;
-
-                                       div_u64_rem(stripe_nr_end - 1 - j,
-                                                   factor, &test);
-
-                                       if (test ==
-                                           stripe_index / map->sub_stripes)
-                                               break;
-                               }
-                               stripes = stripe_nr_end - 1 - j;
-                               do_div(stripes, factor);
-                               bbio->stripes[i].length = map->stripe_len *
-                                       (stripes - stripe_nr + 1);
-
-                               if (i < map->sub_stripes) {
+                       if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
+                                        BTRFS_BLOCK_GROUP_RAID10)) {
+                               bbio->stripes[i].length = stripes_per_dev *
+                                                         map->stripe_len;
+                               if (i / sub_stripes < remaining_stripes)
+                                       bbio->stripes[i].length +=
+                                               map->stripe_len;
+                               if (i < sub_stripes)
                                        bbio->stripes[i].length -=
                                                stripe_offset;
-                                       if (i == map->sub_stripes - 1)
-                                               stripe_offset = 0;
-                               }
-                               if (stripe_index >= last_stripe &&
-                                   stripe_index <= (last_stripe +
-                                                    map->sub_stripes - 1)) {
+                               if ((i / sub_stripes + 1) %
+                                   sub_stripes == remaining_stripes)
                                        bbio->stripes[i].length -=
                                                stripe_end_offset;
-                               }
+                               if (i == sub_stripes - 1)
+                                       stripe_offset = 0;
                        } else
                                bbio->stripes[i].length = *length;
 
@@ -3155,15 +3806,22 @@ again:
                        stripe_index++;
                }
        }
-       if (bbio_ret) {
-               *bbio_ret = bbio;
-               bbio->num_stripes = num_stripes;
-               bbio->max_errors = max_errors;
-               bbio->mirror_num = mirror_num;
+
+       if (rw & REQ_WRITE) {
+               if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
+                                BTRFS_BLOCK_GROUP_RAID10 |
+                                BTRFS_BLOCK_GROUP_DUP)) {
+                       max_errors = 1;
+               }
        }
+
+       *bbio_ret = bbio;
+       bbio->num_stripes = num_stripes;
+       bbio->max_errors = max_errors;
+       bbio->mirror_num = mirror_num;
 out:
        free_extent_map(em);
-       return 0;
+       return ret;
 }
 
 int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
@@ -3304,7 +3962,7 @@ static noinline int schedule_bio(struct btrfs_root *root,
        /* don't bother with additional async steps for reads, right now */
        if (!(rw & REQ_WRITE)) {
                bio_get(bio);
-               submit_bio(rw, bio);
+               btrfsic_submit_bio(rw, bio);
                bio_put(bio);
                return 0;
        }
@@ -3399,7 +4057,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
                        if (async_submit)
                                schedule_bio(root, dev, rw, bio);
                        else
-                               submit_bio(rw, bio);
+                               btrfsic_submit_bio(rw, bio);
                } else {
                        bio->bi_bdev = root->fs_info->fs_devices->latest_bdev;
                        bio->bi_sector = logical >> 9;
@@ -3568,7 +4226,7 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid)
        struct btrfs_fs_devices *fs_devices;
        int ret;
 
-       mutex_lock(&uuid_mutex);
+       BUG_ON(!mutex_is_locked(&uuid_mutex));
 
        fs_devices = root->fs_info->fs_devices->seed;
        while (fs_devices) {
@@ -3606,7 +4264,6 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid)
        fs_devices->seed = root->fs_info->fs_devices->seed;
        root->fs_info->fs_devices->seed = fs_devices;
 out:
-       mutex_unlock(&uuid_mutex);
        return ret;
 }
 
@@ -3749,6 +4406,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root)
        if (!path)
                return -ENOMEM;
 
+       mutex_lock(&uuid_mutex);
+       lock_chunks(root);
+
        /* first we search for all of the device items, and then we
         * read in all of the chunk items.  This way we can create chunk
         * mappings that reference all of the devices that are afound
@@ -3799,6 +4459,9 @@ again:
        }
        ret = 0;
 error:
+       unlock_chunks(root);
+       mutex_unlock(&uuid_mutex);
+
        btrfs_free_path(path);
        return ret;
 }
index 78f2d4d4f37fe81317395688a8b090b71e53a612..19ac95048b88596e44b6dd667b050fb796ab20e7 100644 (file)
@@ -186,6 +186,51 @@ struct map_lookup {
 #define map_lookup_size(n) (sizeof(struct map_lookup) + \
                            (sizeof(struct btrfs_bio_stripe) * (n)))
 
+/*
+ * Restriper's general type filter
+ */
+#define BTRFS_BALANCE_DATA             (1ULL << 0)
+#define BTRFS_BALANCE_SYSTEM           (1ULL << 1)
+#define BTRFS_BALANCE_METADATA         (1ULL << 2)
+
+#define BTRFS_BALANCE_TYPE_MASK                (BTRFS_BALANCE_DATA |       \
+                                        BTRFS_BALANCE_SYSTEM |     \
+                                        BTRFS_BALANCE_METADATA)
+
+#define BTRFS_BALANCE_FORCE            (1ULL << 3)
+#define BTRFS_BALANCE_RESUME           (1ULL << 4)
+
+/*
+ * Balance filters
+ */
+#define BTRFS_BALANCE_ARGS_PROFILES    (1ULL << 0)
+#define BTRFS_BALANCE_ARGS_USAGE       (1ULL << 1)
+#define BTRFS_BALANCE_ARGS_DEVID       (1ULL << 2)
+#define BTRFS_BALANCE_ARGS_DRANGE      (1ULL << 3)
+#define BTRFS_BALANCE_ARGS_VRANGE      (1ULL << 4)
+
+/*
+ * Profile changing flags.  When SOFT is set we won't relocate chunk if
+ * it already has the target profile (even though it may be
+ * half-filled).
+ */
+#define BTRFS_BALANCE_ARGS_CONVERT     (1ULL << 8)
+#define BTRFS_BALANCE_ARGS_SOFT                (1ULL << 9)
+
+struct btrfs_balance_args;
+struct btrfs_balance_progress;
+struct btrfs_balance_control {
+       struct btrfs_fs_info *fs_info;
+
+       struct btrfs_balance_args data;
+       struct btrfs_balance_args meta;
+       struct btrfs_balance_args sys;
+
+       u64 flags;
+
+       struct btrfs_balance_progress stat;
+};
+
 int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
                                   u64 end, u64 *length);
 
@@ -228,9 +273,12 @@ struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid,
                                       u8 *uuid, u8 *fsid);
 int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
 int btrfs_init_new_device(struct btrfs_root *root, char *path);
-int btrfs_balance(struct btrfs_root *dev_root);
+int btrfs_balance(struct btrfs_balance_control *bctl,
+                 struct btrfs_ioctl_balance_args *bargs);
+int btrfs_recover_balance(struct btrfs_root *tree_root);
+int btrfs_pause_balance(struct btrfs_fs_info *fs_info);
+int btrfs_cancel_balance(struct btrfs_fs_info *fs_info);
 int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
-int find_free_dev_extent(struct btrfs_trans_handle *trans,
-                        struct btrfs_device *device, u64 num_bytes,
+int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
                         u64 *start, u64 *max_avail);
 #endif
index 3848b04e310e4800f6768160c6ef5111734ad1d5..e7a5659087e66f93769bc750562d21294c9bd2b6 100644 (file)
@@ -200,7 +200,7 @@ int __btrfs_setxattr(struct btrfs_trans_handle *trans,
        ret = btrfs_update_inode(trans, root, inode);
        BUG_ON(ret);
 out:
-       btrfs_end_transaction_throttle(trans, root);
+       btrfs_end_transaction(trans, root);
        return ret;
 }
 
index 74fd74719dc2c5769b0c2982dab7d2b968bf25d5..618246bc2196eee020f6c53ccf789d784603e090 100644 (file)
@@ -973,7 +973,7 @@ static int dentry_lease_is_valid(struct dentry *dentry)
 
        spin_lock(&dentry->d_lock);
        di = ceph_dentry(dentry);
-       if (di && di->lease_session) {
+       if (di->lease_session) {
                s = di->lease_session;
                spin_lock(&s->s_cap_lock);
                gen = s->s_cap_gen;
@@ -1072,13 +1072,11 @@ static void ceph_d_release(struct dentry *dentry)
        struct ceph_dentry_info *di = ceph_dentry(dentry);
 
        dout("d_release %p\n", dentry);
-       if (di) {
-               ceph_dentry_lru_del(dentry);
-               if (di->lease_session)
-                       ceph_put_mds_session(di->lease_session);
-               kmem_cache_free(ceph_dentry_cachep, di);
-               dentry->d_fsdata = NULL;
-       }
+       ceph_dentry_lru_del(dentry);
+       if (di->lease_session)
+               ceph_put_mds_session(di->lease_session);
+       kmem_cache_free(ceph_dentry_cachep, di);
+       dentry->d_fsdata = NULL;
 }
 
 static int ceph_snapdir_d_revalidate(struct dentry *dentry,
@@ -1096,17 +1094,36 @@ static int ceph_snapdir_d_revalidate(struct dentry *dentry,
  */
 void ceph_dir_set_complete(struct inode *inode)
 {
-       /* not yet implemented */
+       struct dentry *dentry = d_find_any_alias(inode);
+       
+       if (dentry && ceph_dentry(dentry) &&
+           ceph_test_mount_opt(ceph_sb_to_client(dentry->d_sb), DCACHE)) {
+               dout(" marking %p (%p) complete\n", inode, dentry);
+               set_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags);
+       }
+       dput(dentry);
 }
 
 void ceph_dir_clear_complete(struct inode *inode)
 {
-       /* not yet implemented */
+       struct dentry *dentry = d_find_any_alias(inode);
+
+       if (dentry && ceph_dentry(dentry)) {
+               dout(" marking %p (%p) complete\n", inode, dentry);
+               set_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags);
+       }
+       dput(dentry);
 }
 
 bool ceph_dir_test_complete(struct inode *inode)
 {
-       /* not yet implemented */
+       struct dentry *dentry = d_find_any_alias(inode);
+
+       if (dentry && ceph_dentry(dentry)) {
+               dout(" marking %p (%p) NOT complete\n", inode, dentry);
+               clear_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags);
+       }
+       dput(dentry);
        return false;
 }
 
@@ -1220,6 +1237,7 @@ static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end,
        do {
                ceph_mdsc_get_request(req);
                spin_unlock(&ci->i_unsafe_lock);
+
                dout("dir_fsync %p wait on tid %llu (until %llu)\n",
                     inode, req->r_tid, last_tid);
                if (req->r_timeout) {
@@ -1232,9 +1250,9 @@ static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end,
                } else {
                        wait_for_completion(&req->r_safe_completion);
                }
-               spin_lock(&ci->i_unsafe_lock);
                ceph_mdsc_put_request(req);
 
+               spin_lock(&ci->i_unsafe_lock);
                if (ret || list_empty(head))
                        break;
                req = list_entry(head->next,
@@ -1259,13 +1277,11 @@ void ceph_dentry_lru_add(struct dentry *dn)
 
        dout("dentry_lru_add %p %p '%.*s'\n", di, dn,
             dn->d_name.len, dn->d_name.name);
-       if (di) {
-               mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
-               spin_lock(&mdsc->dentry_lru_lock);
-               list_add_tail(&di->lru, &mdsc->dentry_lru);
-               mdsc->num_dentry++;
-               spin_unlock(&mdsc->dentry_lru_lock);
-       }
+       mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
+       spin_lock(&mdsc->dentry_lru_lock);
+       list_add_tail(&di->lru, &mdsc->dentry_lru);
+       mdsc->num_dentry++;
+       spin_unlock(&mdsc->dentry_lru_lock);
 }
 
 void ceph_dentry_lru_touch(struct dentry *dn)
@@ -1275,12 +1291,10 @@ void ceph_dentry_lru_touch(struct dentry *dn)
 
        dout("dentry_lru_touch %p %p '%.*s' (offset %lld)\n", di, dn,
             dn->d_name.len, dn->d_name.name, di->offset);
-       if (di) {
-               mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
-               spin_lock(&mdsc->dentry_lru_lock);
-               list_move_tail(&di->lru, &mdsc->dentry_lru);
-               spin_unlock(&mdsc->dentry_lru_lock);
-       }
+       mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
+       spin_lock(&mdsc->dentry_lru_lock);
+       list_move_tail(&di->lru, &mdsc->dentry_lru);
+       spin_unlock(&mdsc->dentry_lru_lock);
 }
 
 void ceph_dentry_lru_del(struct dentry *dn)
@@ -1290,13 +1304,11 @@ void ceph_dentry_lru_del(struct dentry *dn)
 
        dout("dentry_lru_del %p %p '%.*s'\n", di, dn,
             dn->d_name.len, dn->d_name.name);
-       if (di) {
-               mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
-               spin_lock(&mdsc->dentry_lru_lock);
-               list_del_init(&di->lru);
-               mdsc->num_dentry--;
-               spin_unlock(&mdsc->dentry_lru_lock);
-       }
+       mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
+       spin_lock(&mdsc->dentry_lru_lock);
+       list_del_init(&di->lru);
+       mdsc->num_dentry--;
+       spin_unlock(&mdsc->dentry_lru_lock);
 }
 
 /*
index 9fbcdecaaccdc1ef2edfa9a8578b60c6a9b64118..fbb2a643ef10a1f75c4918f165c9e3a22a603a86 100644 (file)
@@ -56,9 +56,7 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
                return -EINVAL;
 
        spin_lock(&dentry->d_lock);
-       parent = dget(dentry->d_parent);
-       spin_unlock(&dentry->d_lock);
-
+       parent = dentry->d_parent;
        if (*max_len >= connected_handle_length) {
                dout("encode_fh %p connectable\n", dentry);
                cfh->ino = ceph_ino(dentry->d_inode);
@@ -81,7 +79,7 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
                *max_len = handle_length;
                type = 255;
        }
-       dput(parent);
+       spin_unlock(&dentry->d_lock);
        return type;
 }
 
index 25283e7a37f81ecf8ba3606a957a1efc7481afa3..2c489378b4cd6b470d06ecc9f3c60fc67ea6e1cf 100644 (file)
@@ -850,11 +850,12 @@ static void ceph_set_dentry_offset(struct dentry *dn)
 {
        struct dentry *dir = dn->d_parent;
        struct inode *inode = dir->d_inode;
-       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_inode_info *ci;
        struct ceph_dentry_info *di;
 
        BUG_ON(!inode);
 
+       ci = ceph_inode(inode);
        di = ceph_dentry(dn);
 
        spin_lock(&ci->i_ceph_lock);
index 6203d805eb45061d20b5d8e08222f97aae6cd0a6..23ab6a3f1825e85cb839f508535a56cdc0cc55fe 100644 (file)
@@ -2772,7 +2772,7 @@ static void handle_lease(struct ceph_mds_client *mdsc,
        di = ceph_dentry(dentry);
        switch (h->action) {
        case CEPH_MDS_LEASE_REVOKE:
-               if (di && di->lease_session == session) {
+               if (di->lease_session == session) {
                        if (ceph_seq_cmp(di->lease_seq, seq) > 0)
                                h->seq = cpu_to_le32(di->lease_seq);
                        __ceph_mdsc_drop_dentry_lease(dentry);
@@ -2781,7 +2781,7 @@ static void handle_lease(struct ceph_mds_client *mdsc,
                break;
 
        case CEPH_MDS_LEASE_RENEW:
-               if (di && di->lease_session == session &&
+               if (di->lease_session == session &&
                    di->lease_gen == session->s_cap_gen &&
                    di->lease_renew_from &&
                    di->lease_renew_after == 0) {
index 48f61a12af66eecdd57f792c2b5da44d5c86468f..00de2c9568cd89b13af544b87bc2f43acefa8b30 100644 (file)
@@ -131,6 +131,8 @@ enum {
        Opt_rbytes,
        Opt_norbytes,
        Opt_noasyncreaddir,
+       Opt_dcache,
+       Opt_nodcache,
        Opt_ino32,
 };
 
@@ -152,6 +154,8 @@ static match_table_t fsopt_tokens = {
        {Opt_rbytes, "rbytes"},
        {Opt_norbytes, "norbytes"},
        {Opt_noasyncreaddir, "noasyncreaddir"},
+       {Opt_dcache, "dcache"},
+       {Opt_nodcache, "nodcache"},
        {Opt_ino32, "ino32"},
        {-1, NULL}
 };
@@ -231,6 +235,12 @@ static int parse_fsopt_token(char *c, void *private)
        case Opt_noasyncreaddir:
                fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR;
                break;
+       case Opt_dcache:
+               fsopt->flags |= CEPH_MOUNT_OPT_DCACHE;
+               break;
+       case Opt_nodcache:
+               fsopt->flags &= ~CEPH_MOUNT_OPT_DCACHE;
+               break;
        case Opt_ino32:
                fsopt->flags |= CEPH_MOUNT_OPT_INO32;
                break;
@@ -377,6 +387,10 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
                seq_puts(m, ",norbytes");
        if (fsopt->flags & CEPH_MOUNT_OPT_NOASYNCREADDIR)
                seq_puts(m, ",noasyncreaddir");
+       if (fsopt->flags & CEPH_MOUNT_OPT_DCACHE)
+               seq_puts(m, ",dcache");
+       else
+               seq_puts(m, ",nodcache");
 
        if (fsopt->wsize)
                seq_printf(m, ",wsize=%d", fsopt->wsize);
@@ -647,10 +661,10 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
                                root = ERR_PTR(-ENOMEM);
                                goto out;
                        }
-                       ceph_init_dentry(root);
                } else {
                        root = d_obtain_alias(inode);
                }
+               ceph_init_dentry(root);
                dout("open_root_inode success, root dentry is %p\n", root);
        } else {
                root = ERR_PTR(err);
index cb3652b37271fbc383f784ff35c48bb48c17ff32..1421f3d875a22e34e1449bde4d46327678d114fe 100644 (file)
@@ -28,6 +28,7 @@
 #define CEPH_MOUNT_OPT_RBYTES          (1<<5) /* dir st_bytes = rbytes */
 #define CEPH_MOUNT_OPT_NOASYNCREADDIR  (1<<7) /* no dcache readdir */
 #define CEPH_MOUNT_OPT_INO32           (1<<8) /* 32 bit inos */
+#define CEPH_MOUNT_OPT_DCACHE          (1<<9) /* use dcache for readdir etc */
 
 #define CEPH_MOUNT_OPT_DEFAULT    (CEPH_MOUNT_OPT_RBYTES)
 
index a5e36e4488a7d6e9f6dc0b9a5b9d440b4229e9c1..857214ae8c0893181c85c6fb081ef13ae171f0e7 100644 (file)
@@ -818,6 +818,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
        struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
        int issued;
        int err;
+       int required_blob_size;
        int dirty;
 
        if (ceph_snap(inode) != CEPH_NOSNAP)
@@ -833,14 +834,34 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
                        return -EOPNOTSUPP;
        }
 
+       err = -ENOMEM;
        spin_lock(&ci->i_ceph_lock);
        __build_xattrs(inode);
+retry:
        issued = __ceph_caps_issued(ci, NULL);
        dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued));
 
        if (!(issued & CEPH_CAP_XATTR_EXCL))
                goto do_sync;
 
+       required_blob_size = __get_required_blob_size(ci, 0, 0);
+
+       if (!ci->i_xattrs.prealloc_blob ||
+           required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
+               struct ceph_buffer *blob;
+
+               spin_unlock(&ci->i_ceph_lock);
+               dout(" preaallocating new blob size=%d\n", required_blob_size);
+               blob = ceph_buffer_new(required_blob_size, GFP_NOFS);
+               if (!blob)
+                       goto out;
+               spin_lock(&ci->i_ceph_lock);
+               if (ci->i_xattrs.prealloc_blob)
+                       ceph_buffer_put(ci->i_xattrs.prealloc_blob);
+               ci->i_xattrs.prealloc_blob = blob;
+               goto retry;
+       }
+
        err = __remove_xattr_by_name(ceph_inode(inode), name);
        dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
        ci->i_xattrs.dirty = true;
@@ -853,6 +874,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
 do_sync:
        spin_unlock(&ci->i_ceph_lock);
        err = ceph_send_removexattr(dentry, name);
+out:
        return err;
 }
 
index a10e428b32b4a62dfc22d515d29c423b7e130a01..a26bea10e81bae5c9ee1890102ce86b7929bde28 100644 (file)
 
 #include <linux/hiddev.h>
 
+#define __DVB_CORE__
 #include <linux/dvb/audio.h>
 #include <linux/dvb/dmx.h>
 #include <linux/dvb/frontend.h>
index 616fedff011a7080c36b6446a33b3479c9c7e7d9..16a53cc2cc02e079554742bfcd95c1f92d3608d4 100644 (file)
@@ -1475,7 +1475,14 @@ static struct dentry * __d_find_any_alias(struct inode *inode)
        return alias;
 }
 
-static struct dentry * d_find_any_alias(struct inode *inode)
+/**
+ * d_find_any_alias - find any alias for a given inode
+ * @inode: inode to find an alias for
+ *
+ * If any aliases exist for the given inode, take and return a
+ * reference for one of them.  If no aliases exist, return %NULL.
+ */
+struct dentry *d_find_any_alias(struct inode *inode)
 {
        struct dentry *de;
 
@@ -1484,7 +1491,7 @@ static struct dentry * d_find_any_alias(struct inode *inode)
        spin_unlock(&inode->i_lock);
        return de;
 }
-
+EXPORT_SYMBOL(d_find_any_alias);
 
 /**
  * d_obtain_alias - find or allocate a dentry for a given inode
index d740ab67ff6e1bd581218fb149eb7a58c40fa3f3..4a588dbd11bfa57926b647e1e66bdd35a446cad4 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/rwsem.h>
 #include <linux/uio.h>
 #include <linux/atomic.h>
+#include <linux/prefetch.h>
 
 /*
  * How many user pages to map in one call to get_user_pages().  This determines
@@ -580,9 +581,8 @@ static int get_more_blocks(struct dio *dio, struct dio_submit *sdio,
 {
        int ret;
        sector_t fs_startblk;   /* Into file, in filesystem-sized blocks */
+       sector_t fs_endblk;     /* Into file, in filesystem-sized blocks */
        unsigned long fs_count; /* Number of filesystem-sized blocks */
-       unsigned long dio_count;/* Number of dio_block-sized blocks */
-       unsigned long blkmask;
        int create;
 
        /*
@@ -593,11 +593,9 @@ static int get_more_blocks(struct dio *dio, struct dio_submit *sdio,
        if (ret == 0) {
                BUG_ON(sdio->block_in_file >= sdio->final_block_in_request);
                fs_startblk = sdio->block_in_file >> sdio->blkfactor;
-               dio_count = sdio->final_block_in_request - sdio->block_in_file;
-               fs_count = dio_count >> sdio->blkfactor;
-               blkmask = (1 << sdio->blkfactor) - 1;
-               if (dio_count & blkmask)        
-                       fs_count++;
+               fs_endblk = (sdio->final_block_in_request - 1) >>
+                                       sdio->blkfactor;
+               fs_count = fs_endblk - fs_startblk + 1;
 
                map_bh->b_state = 0;
                map_bh->b_size = fs_count << dio->inode->i_blkbits;
@@ -1090,8 +1088,8 @@ static inline int drop_refcount(struct dio *dio)
  * individual fields and will generate much worse code. This is important
  * for the whole file.
  */
-ssize_t
-__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
+static inline ssize_t
+do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        struct block_device *bdev, const struct iovec *iov, loff_t offset, 
        unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
        dio_submit_t submit_io, int flags)
@@ -1100,7 +1098,6 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        size_t size;
        unsigned long addr;
        unsigned blkbits = inode->i_blkbits;
-       unsigned bdev_blkbits = 0;
        unsigned blocksize_mask = (1 << blkbits) - 1;
        ssize_t retval = -EINVAL;
        loff_t end = offset;
@@ -1113,12 +1110,14 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        if (rw & WRITE)
                rw = WRITE_ODIRECT;
 
-       if (bdev)
-               bdev_blkbits = blksize_bits(bdev_logical_block_size(bdev));
+       /*
+        * Avoid references to bdev if not absolutely needed to give
+        * the early prefetch in the caller enough time.
+        */
 
        if (offset & blocksize_mask) {
                if (bdev)
-                        blkbits = bdev_blkbits;
+                       blkbits = blksize_bits(bdev_logical_block_size(bdev));
                blocksize_mask = (1 << blkbits) - 1;
                if (offset & blocksize_mask)
                        goto out;
@@ -1129,11 +1128,13 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
                addr = (unsigned long)iov[seg].iov_base;
                size = iov[seg].iov_len;
                end += size;
-               if ((addr & blocksize_mask) || (size & blocksize_mask))  {
+               if (unlikely((addr & blocksize_mask) ||
+                            (size & blocksize_mask))) {
                        if (bdev)
-                                blkbits = bdev_blkbits;
+                               blkbits = blksize_bits(
+                                        bdev_logical_block_size(bdev));
                        blocksize_mask = (1 << blkbits) - 1;
-                       if ((addr & blocksize_mask) || (size & blocksize_mask))  
+                       if ((addr & blocksize_mask) || (size & blocksize_mask))
                                goto out;
                }
        }
@@ -1316,6 +1317,30 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
 out:
        return retval;
 }
+
+ssize_t
+__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
+       struct block_device *bdev, const struct iovec *iov, loff_t offset,
+       unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
+       dio_submit_t submit_io, int flags)
+{
+       /*
+        * The block device state is needed in the end to finally
+        * submit everything.  Since it's likely to be cache cold
+        * prefetch it here as first thing to hide some of the
+        * latency.
+        *
+        * Attempt to prefetch the pieces we likely need later.
+        */
+       prefetch(&bdev->bd_disk->part_tbl);
+       prefetch(bdev->bd_queue);
+       prefetch((char *)bdev->bd_queue + SMP_CACHE_BYTES);
+
+       return do_blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
+                                    nr_segs, get_block, end_io,
+                                    submit_io, flags);
+}
+
 EXPORT_SYMBOL(__blockdev_direct_IO);
 
 static __init int dio_init(void)
index 828e750af23a7923cb9782c9cd3c3b87ed6b4964..aabdfc38cf2499817f150eace1efe8e8f08f1f8f 100644 (file)
@@ -197,6 +197,12 @@ struct eventpoll {
 
        /* The user that created the eventpoll descriptor */
        struct user_struct *user;
+
+       struct file *file;
+
+       /* used to optimize loop detection check */
+       int visited;
+       struct list_head visited_list_link;
 };
 
 /* Wait structure used by the poll hooks */
@@ -255,6 +261,15 @@ static struct kmem_cache *epi_cache __read_mostly;
 /* Slab cache used to allocate "struct eppoll_entry" */
 static struct kmem_cache *pwq_cache __read_mostly;
 
+/* Visited nodes during ep_loop_check(), so we can unset them when we finish */
+static LIST_HEAD(visited_list);
+
+/*
+ * List of files with newly added links, where we may need to limit the number
+ * of emanating paths. Protected by the epmutex.
+ */
+static LIST_HEAD(tfile_check_list);
+
 #ifdef CONFIG_SYSCTL
 
 #include <linux/sysctl.h>
@@ -276,6 +291,12 @@ ctl_table epoll_table[] = {
 };
 #endif /* CONFIG_SYSCTL */
 
+static const struct file_operations eventpoll_fops;
+
+static inline int is_file_epoll(struct file *f)
+{
+       return f->f_op == &eventpoll_fops;
+}
 
 /* Setup the structure that is used as key for the RB tree */
 static inline void ep_set_ffd(struct epoll_filefd *ffd,
@@ -711,12 +732,6 @@ static const struct file_operations eventpoll_fops = {
        .llseek         = noop_llseek,
 };
 
-/* Fast test to see if the file is an eventpoll file */
-static inline int is_file_epoll(struct file *f)
-{
-       return f->f_op == &eventpoll_fops;
-}
-
 /*
  * This is called from eventpoll_release() to unlink files from the eventpoll
  * interface. We need to have this facility to cleanup correctly files that are
@@ -926,6 +941,99 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi)
        rb_insert_color(&epi->rbn, &ep->rbr);
 }
 
+
+
+#define PATH_ARR_SIZE 5
+/*
+ * These are the number paths of length 1 to 5, that we are allowing to emanate
+ * from a single file of interest. For example, we allow 1000 paths of length
+ * 1, to emanate from each file of interest. This essentially represents the
+ * potential wakeup paths, which need to be limited in order to avoid massive
+ * uncontrolled wakeup storms. The common use case should be a single ep which
+ * is connected to n file sources. In this case each file source has 1 path
+ * of length 1. Thus, the numbers below should be more than sufficient. These
+ * path limits are enforced during an EPOLL_CTL_ADD operation, since a modify
+ * and delete can't add additional paths. Protected by the epmutex.
+ */
+static const int path_limits[PATH_ARR_SIZE] = { 1000, 500, 100, 50, 10 };
+static int path_count[PATH_ARR_SIZE];
+
+static int path_count_inc(int nests)
+{
+       if (++path_count[nests] > path_limits[nests])
+               return -1;
+       return 0;
+}
+
+static void path_count_init(void)
+{
+       int i;
+
+       for (i = 0; i < PATH_ARR_SIZE; i++)
+               path_count[i] = 0;
+}
+
+static int reverse_path_check_proc(void *priv, void *cookie, int call_nests)
+{
+       int error = 0;
+       struct file *file = priv;
+       struct file *child_file;
+       struct epitem *epi;
+
+       list_for_each_entry(epi, &file->f_ep_links, fllink) {
+               child_file = epi->ep->file;
+               if (is_file_epoll(child_file)) {
+                       if (list_empty(&child_file->f_ep_links)) {
+                               if (path_count_inc(call_nests)) {
+                                       error = -1;
+                                       break;
+                               }
+                       } else {
+                               error = ep_call_nested(&poll_loop_ncalls,
+                                                       EP_MAX_NESTS,
+                                                       reverse_path_check_proc,
+                                                       child_file, child_file,
+                                                       current);
+                       }
+                       if (error != 0)
+                               break;
+               } else {
+                       printk(KERN_ERR "reverse_path_check_proc: "
+                               "file is not an ep!\n");
+               }
+       }
+       return error;
+}
+
+/**
+ * reverse_path_check - The tfile_check_list is list of file *, which have
+ *                      links that are proposed to be newly added. We need to
+ *                      make sure that those added links don't add too many
+ *                      paths such that we will spend all our time waking up
+ *                      eventpoll objects.
+ *
+ * Returns: Returns zero if the proposed links don't create too many paths,
+ *         -1 otherwise.
+ */
+static int reverse_path_check(void)
+{
+       int length = 0;
+       int error = 0;
+       struct file *current_file;
+
+       /* let's call this for all tfiles */
+       list_for_each_entry(current_file, &tfile_check_list, f_tfile_llink) {
+               length++;
+               path_count_init();
+               error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
+                                       reverse_path_check_proc, current_file,
+                                       current_file, current);
+               if (error)
+                       break;
+       }
+       return error;
+}
+
 /*
  * Must be called with "mtx" held.
  */
@@ -987,6 +1095,11 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
         */
        ep_rbtree_insert(ep, epi);
 
+       /* now check if we've created too many backpaths */
+       error = -EINVAL;
+       if (reverse_path_check())
+               goto error_remove_epi;
+
        /* We have to drop the new item inside our item list to keep track of it */
        spin_lock_irqsave(&ep->lock, flags);
 
@@ -1011,6 +1124,14 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
 
        return 0;
 
+error_remove_epi:
+       spin_lock(&tfile->f_lock);
+       if (ep_is_linked(&epi->fllink))
+               list_del_init(&epi->fllink);
+       spin_unlock(&tfile->f_lock);
+
+       rb_erase(&epi->rbn, &ep->rbr);
+
 error_unregister:
        ep_unregister_pollwait(ep, epi);
 
@@ -1275,18 +1396,36 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
        int error = 0;
        struct file *file = priv;
        struct eventpoll *ep = file->private_data;
+       struct eventpoll *ep_tovisit;
        struct rb_node *rbp;
        struct epitem *epi;
 
        mutex_lock_nested(&ep->mtx, call_nests + 1);
+       ep->visited = 1;
+       list_add(&ep->visited_list_link, &visited_list);
        for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
                epi = rb_entry(rbp, struct epitem, rbn);
                if (unlikely(is_file_epoll(epi->ffd.file))) {
+                       ep_tovisit = epi->ffd.file->private_data;
+                       if (ep_tovisit->visited)
+                               continue;
                        error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
-                                              ep_loop_check_proc, epi->ffd.file,
-                                              epi->ffd.file->private_data, current);
+                                       ep_loop_check_proc, epi->ffd.file,
+                                       ep_tovisit, current);
                        if (error != 0)
                                break;
+               } else {
+                       /*
+                        * If we've reached a file that is not associated with
+                        * an ep, then we need to check if the newly added
+                        * links are going to add too many wakeup paths. We do
+                        * this by adding it to the tfile_check_list, if it's
+                        * not already there, and calling reverse_path_check()
+                        * during ep_insert().
+                        */
+                       if (list_empty(&epi->ffd.file->f_tfile_llink))
+                               list_add(&epi->ffd.file->f_tfile_llink,
+                                        &tfile_check_list);
                }
        }
        mutex_unlock(&ep->mtx);
@@ -1307,8 +1446,31 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
  */
 static int ep_loop_check(struct eventpoll *ep, struct file *file)
 {
-       return ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
+       int ret;
+       struct eventpoll *ep_cur, *ep_next;
+
+       ret = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
                              ep_loop_check_proc, file, ep, current);
+       /* clear visited list */
+       list_for_each_entry_safe(ep_cur, ep_next, &visited_list,
+                                                       visited_list_link) {
+               ep_cur->visited = 0;
+               list_del(&ep_cur->visited_list_link);
+       }
+       return ret;
+}
+
+static void clear_tfile_check_list(void)
+{
+       struct file *file;
+
+       /* first clear the tfile_check_list */
+       while (!list_empty(&tfile_check_list)) {
+               file = list_first_entry(&tfile_check_list, struct file,
+                                       f_tfile_llink);
+               list_del_init(&file->f_tfile_llink);
+       }
+       INIT_LIST_HEAD(&tfile_check_list);
 }
 
 /*
@@ -1316,8 +1478,9 @@ static int ep_loop_check(struct eventpoll *ep, struct file *file)
  */
 SYSCALL_DEFINE1(epoll_create1, int, flags)
 {
-       int error;
+       int error, fd;
        struct eventpoll *ep = NULL;
+       struct file *file;
 
        /* Check the EPOLL_* constant for consistency.  */
        BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC);
@@ -1334,11 +1497,25 @@ SYSCALL_DEFINE1(epoll_create1, int, flags)
         * Creates all the items needed to setup an eventpoll file. That is,
         * a file structure and a free file descriptor.
         */
-       error = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep,
+       fd = get_unused_fd_flags(O_RDWR | (flags & O_CLOEXEC));
+       if (fd < 0) {
+               error = fd;
+               goto out_free_ep;
+       }
+       file = anon_inode_getfile("[eventpoll]", &eventpoll_fops, ep,
                                 O_RDWR | (flags & O_CLOEXEC));
-       if (error < 0)
-               ep_free(ep);
-
+       if (IS_ERR(file)) {
+               error = PTR_ERR(file);
+               goto out_free_fd;
+       }
+       fd_install(fd, file);
+       ep->file = file;
+       return fd;
+
+out_free_fd:
+       put_unused_fd(fd);
+out_free_ep:
+       ep_free(ep);
        return error;
 }
 
@@ -1404,21 +1581,27 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
        /*
         * When we insert an epoll file descriptor, inside another epoll file
         * descriptor, there is the change of creating closed loops, which are
-        * better be handled here, than in more critical paths.
+        * better be handled here, than in more critical paths. While we are
+        * checking for loops we also determine the list of files reachable
+        * and hang them on the tfile_check_list, so we can check that we
+        * haven't created too many possible wakeup paths.
         *
-        * We hold epmutex across the loop check and the insert in this case, in
-        * order to prevent two separate inserts from racing and each doing the
-        * insert "at the same time" such that ep_loop_check passes on both
-        * before either one does the insert, thereby creating a cycle.
+        * We need to hold the epmutex across both ep_insert and ep_remove
+        * b/c we want to make sure we are looking at a coherent view of
+        * epoll network.
         */
-       if (unlikely(is_file_epoll(tfile) && op == EPOLL_CTL_ADD)) {
+       if (op == EPOLL_CTL_ADD || op == EPOLL_CTL_DEL) {
                mutex_lock(&epmutex);
                did_lock_epmutex = 1;
-               error = -ELOOP;
-               if (ep_loop_check(ep, tfile) != 0)
-                       goto error_tgt_fput;
        }
-
+       if (op == EPOLL_CTL_ADD) {
+               if (is_file_epoll(tfile)) {
+                       error = -ELOOP;
+                       if (ep_loop_check(ep, tfile) != 0)
+                               goto error_tgt_fput;
+               } else
+                       list_add(&tfile->f_tfile_llink, &tfile_check_list);
+       }
 
        mutex_lock_nested(&ep->mtx, 0);
 
@@ -1437,6 +1620,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
                        error = ep_insert(ep, &epds, tfile, fd);
                } else
                        error = -EEXIST;
+               clear_tfile_check_list();
                break;
        case EPOLL_CTL_DEL:
                if (epi)
@@ -1455,7 +1639,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
        mutex_unlock(&ep->mtx);
 
 error_tgt_fput:
-       if (unlikely(did_lock_epmutex))
+       if (did_lock_epmutex)
                mutex_unlock(&epmutex);
 
        fput(tfile);
index 2aaf3eaaf13da03e328ac3523fe16ca09a60c690..5f3368ab0fa9d44ff8b5121db33d158ef5989da9 100644 (file)
@@ -1378,7 +1378,59 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
        down_read(&fc->killsb);
        err = -ENOENT;
        if (fc->sb)
-               err = fuse_reverse_inval_entry(fc->sb, outarg.parent, &name);
+               err = fuse_reverse_inval_entry(fc->sb, outarg.parent, 0, &name);
+       up_read(&fc->killsb);
+       kfree(buf);
+       return err;
+
+err:
+       kfree(buf);
+       fuse_copy_finish(cs);
+       return err;
+}
+
+static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size,
+                             struct fuse_copy_state *cs)
+{
+       struct fuse_notify_delete_out outarg;
+       int err = -ENOMEM;
+       char *buf;
+       struct qstr name;
+
+       buf = kzalloc(FUSE_NAME_MAX + 1, GFP_KERNEL);
+       if (!buf)
+               goto err;
+
+       err = -EINVAL;
+       if (size < sizeof(outarg))
+               goto err;
+
+       err = fuse_copy_one(cs, &outarg, sizeof(outarg));
+       if (err)
+               goto err;
+
+       err = -ENAMETOOLONG;
+       if (outarg.namelen > FUSE_NAME_MAX)
+               goto err;
+
+       err = -EINVAL;
+       if (size != sizeof(outarg) + outarg.namelen + 1)
+               goto err;
+
+       name.name = buf;
+       name.len = outarg.namelen;
+       err = fuse_copy_one(cs, buf, outarg.namelen + 1);
+       if (err)
+               goto err;
+       fuse_copy_finish(cs);
+       buf[outarg.namelen] = 0;
+       name.hash = full_name_hash(name.name, name.len);
+
+       down_read(&fc->killsb);
+       err = -ENOENT;
+       if (fc->sb)
+               err = fuse_reverse_inval_entry(fc->sb, outarg.parent,
+                                              outarg.child, &name);
        up_read(&fc->killsb);
        kfree(buf);
        return err;
@@ -1597,6 +1649,9 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
        case FUSE_NOTIFY_RETRIEVE:
                return fuse_notify_retrieve(fc, size, cs);
 
+       case FUSE_NOTIFY_DELETE:
+               return fuse_notify_delete(fc, size, cs);
+
        default:
                fuse_copy_finish(cs);
                return -EINVAL;
index 5ddd6ea8f839a87c3824c993a8c520b570706d04..206632887bb40ccf48bb80b96e497c2107c172d9 100644 (file)
@@ -868,7 +868,7 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat,
 }
 
 int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
-                            struct qstr *name)
+                            u64 child_nodeid, struct qstr *name)
 {
        int err = -ENOTDIR;
        struct inode *parent;
@@ -895,8 +895,36 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
 
        fuse_invalidate_attr(parent);
        fuse_invalidate_entry(entry);
+
+       if (child_nodeid != 0 && entry->d_inode) {
+               mutex_lock(&entry->d_inode->i_mutex);
+               if (get_node_id(entry->d_inode) != child_nodeid) {
+                       err = -ENOENT;
+                       goto badentry;
+               }
+               if (d_mountpoint(entry)) {
+                       err = -EBUSY;
+                       goto badentry;
+               }
+               if (S_ISDIR(entry->d_inode->i_mode)) {
+                       shrink_dcache_parent(entry);
+                       if (!simple_empty(entry)) {
+                               err = -ENOTEMPTY;
+                               goto badentry;
+                       }
+                       entry->d_inode->i_flags |= S_DEAD;
+               }
+               dont_mount(entry);
+               clear_nlink(entry->d_inode);
+               err = 0;
+ badentry:
+               mutex_unlock(&entry->d_inode->i_mutex);
+               if (!err)
+                       d_delete(entry);
+       } else {
+               err = 0;
+       }
        dput(entry);
-       err = 0;
 
  unlock:
        mutex_unlock(&parent->i_mutex);
@@ -1182,6 +1210,30 @@ static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end,
        return fuse_fsync_common(file, start, end, datasync, 1);
 }
 
+static long fuse_dir_ioctl(struct file *file, unsigned int cmd,
+                           unsigned long arg)
+{
+       struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host);
+
+       /* FUSE_IOCTL_DIR only supported for API version >= 7.18 */
+       if (fc->minor < 18)
+               return -ENOTTY;
+
+       return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_DIR);
+}
+
+static long fuse_dir_compat_ioctl(struct file *file, unsigned int cmd,
+                                  unsigned long arg)
+{
+       struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host);
+
+       if (fc->minor < 18)
+               return -ENOTTY;
+
+       return fuse_ioctl_common(file, cmd, arg,
+                                FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR);
+}
+
 static bool update_mtime(unsigned ivalid)
 {
        /* Always update if mtime is explicitly set  */
@@ -1596,6 +1648,8 @@ static const struct file_operations fuse_dir_operations = {
        .open           = fuse_dir_open,
        .release        = fuse_dir_release,
        .fsync          = fuse_dir_fsync,
+       .unlocked_ioctl = fuse_dir_ioctl,
+       .compat_ioctl   = fuse_dir_compat_ioctl,
 };
 
 static const struct inode_operations fuse_common_inode_operations = {
index 0c84100acd4492966e2fa48de6fbfacca0f10172..4a199fd93fbddaace1a65f74bc3872bfcbb76cc5 100644 (file)
@@ -1555,48 +1555,16 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin)
        loff_t retval;
        struct inode *inode = file->f_path.dentry->d_inode;
 
-       mutex_lock(&inode->i_mutex);
-       if (origin != SEEK_CUR && origin != SEEK_SET) {
-               retval = fuse_update_attributes(inode, NULL, file, NULL);
-               if (retval)
-                       goto exit;
-       }
+       /* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */
+       if (origin == SEEK_CUR || origin == SEEK_SET)
+               return generic_file_llseek(file, offset, origin);
 
-       switch (origin) {
-       case SEEK_END:
-               offset += i_size_read(inode);
-               break;
-       case SEEK_CUR:
-               if (offset == 0) {
-                       retval = file->f_pos;
-                       goto exit;
-               }
-               offset += file->f_pos;
-               break;
-       case SEEK_DATA:
-               if (offset >= i_size_read(inode)) {
-                       retval = -ENXIO;
-                       goto exit;
-               }
-               break;
-       case SEEK_HOLE:
-               if (offset >= i_size_read(inode)) {
-                       retval = -ENXIO;
-                       goto exit;
-               }
-               offset = i_size_read(inode);
-               break;
-       }
-       retval = -EINVAL;
-       if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
-               if (offset != file->f_pos) {
-                       file->f_pos = offset;
-                       file->f_version = 0;
-               }
-               retval = offset;
-       }
-exit:
+       mutex_lock(&inode->i_mutex);
+       retval = fuse_update_attributes(inode, NULL, file, NULL);
+       if (!retval)
+               retval = generic_file_llseek(file, offset, origin);
        mutex_unlock(&inode->i_mutex);
+
        return retval;
 }
 
@@ -1808,7 +1776,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
        BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE);
 
        err = -ENOMEM;
-       pages = kzalloc(sizeof(pages[0]) * FUSE_MAX_PAGES_PER_REQ, GFP_KERNEL);
+       pages = kcalloc(FUSE_MAX_PAGES_PER_REQ, sizeof(pages[0]), GFP_KERNEL);
        iov_page = (struct iovec *) __get_free_page(GFP_KERNEL);
        if (!pages || !iov_page)
                goto out;
@@ -1958,8 +1926,8 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
 }
 EXPORT_SYMBOL_GPL(fuse_do_ioctl);
 
-static long fuse_file_ioctl_common(struct file *file, unsigned int cmd,
-                                  unsigned long arg, unsigned int flags)
+long fuse_ioctl_common(struct file *file, unsigned int cmd,
+                      unsigned long arg, unsigned int flags)
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct fuse_conn *fc = get_fuse_conn(inode);
@@ -1976,13 +1944,13 @@ static long fuse_file_ioctl_common(struct file *file, unsigned int cmd,
 static long fuse_file_ioctl(struct file *file, unsigned int cmd,
                            unsigned long arg)
 {
-       return fuse_file_ioctl_common(file, cmd, arg, 0);
+       return fuse_ioctl_common(file, cmd, arg, 0);
 }
 
 static long fuse_file_compat_ioctl(struct file *file, unsigned int cmd,
                                   unsigned long arg)
 {
-       return fuse_file_ioctl_common(file, cmd, arg, FUSE_IOCTL_COMPAT);
+       return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_COMPAT);
 }
 
 /*
index 1964da0257d9bbeac2852ffa52a04ecaebbc7b08..572cefc7801296ce1b15cba6223f09d9a9826072 100644 (file)
@@ -755,9 +755,15 @@ int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
 /**
  * File-system tells the kernel to invalidate parent attributes and
  * the dentry matching parent/name.
+ *
+ * If the child_nodeid is non-zero and:
+ *    - matches the inode number for the dentry matching parent/name,
+ *    - is not a mount point
+ *    - is a file or oan empty directory
+ * then the dentry is unhashed (d_delete()).
  */
 int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
-                            struct qstr *name);
+                            u64 child_nodeid, struct qstr *name);
 
 int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
                 bool isdir);
@@ -765,6 +771,8 @@ ssize_t fuse_direct_io(struct file *file, const char __user *buf,
                       size_t count, loff_t *ppos, int write);
 long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
                   unsigned int flags);
+long fuse_ioctl_common(struct file *file, unsigned int cmd,
+                      unsigned long arg, unsigned int flags);
 unsigned fuse_file_poll(struct file *file, poll_table *wait);
 int fuse_dev_release(struct inode *inode, struct file *file);
 
index 88e8a23d0026375c52bf6fd3b69bfd2a87fca598..376816fcd04084f0cad9ad522aab51d8ce0ff7f1 100644 (file)
@@ -1353,7 +1353,7 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret)
        spin_lock(&gl->gl_spin);
        gl->gl_reply = ret;
 
-       if (unlikely(test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags))) {
+       if (unlikely(test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags))) {
                if (gfs2_should_freeze(gl)) {
                        set_bit(GLF_FROZEN, &gl->gl_flags);
                        spin_unlock(&gl->gl_spin);
index 2553b858a72e8374b04ea765938da1eacb7d925c..307ac31df781ea80ac8f77e01bfe5f4970710cb3 100644 (file)
@@ -121,8 +121,11 @@ enum {
 
 struct lm_lockops {
        const char *lm_proto_name;
-       int (*lm_mount) (struct gfs2_sbd *sdp, const char *fsname);
-       void (*lm_unmount) (struct gfs2_sbd *sdp);
+       int (*lm_mount) (struct gfs2_sbd *sdp, const char *table);
+       void (*lm_first_done) (struct gfs2_sbd *sdp);
+       void (*lm_recovery_result) (struct gfs2_sbd *sdp, unsigned int jid,
+                                   unsigned int result);
+       void (*lm_unmount) (struct gfs2_sbd *sdp);
        void (*lm_withdraw) (struct gfs2_sbd *sdp);
        void (*lm_put_lock) (struct gfs2_glock *gl);
        int (*lm_lock) (struct gfs2_glock *gl, unsigned int req_state,
index e1d3bb59945c7e2794880095ba330cc36cfeca1c..97742a7ea9ccf02e58c7ae8f64228790fdf0c8d7 100644 (file)
@@ -139,8 +139,45 @@ struct gfs2_bufdata {
 #define GDLM_STRNAME_BYTES     25
 #define GDLM_LVB_SIZE          32
 
+/*
+ * ls_recover_flags:
+ *
+ * DFL_BLOCK_LOCKS: dlm is in recovery and will grant locks that had been
+ * held by failed nodes whose journals need recovery.  Those locks should
+ * only be used for journal recovery until the journal recovery is done.
+ * This is set by the dlm recover_prep callback and cleared by the
+ * gfs2_control thread when journal recovery is complete.  To avoid
+ * races between recover_prep setting and gfs2_control clearing, recover_spin
+ * is held while changing this bit and reading/writing recover_block
+ * and recover_start.
+ *
+ * DFL_NO_DLM_OPS: dlm lockspace ops/callbacks are not being used.
+ *
+ * DFL_FIRST_MOUNT: this node is the first to mount this fs and is doing
+ * recovery of all journals before allowing other nodes to mount the fs.
+ * This is cleared when FIRST_MOUNT_DONE is set.
+ *
+ * DFL_FIRST_MOUNT_DONE: this node was the first mounter, and has finished
+ * recovery of all journals, and now allows other nodes to mount the fs.
+ *
+ * DFL_MOUNT_DONE: gdlm_mount has completed successfully and cleared
+ * BLOCK_LOCKS for the first time.  The gfs2_control thread should now
+ * control clearing BLOCK_LOCKS for further recoveries.
+ *
+ * DFL_UNMOUNT: gdlm_unmount sets to keep sdp off gfs2_control_wq.
+ *
+ * DFL_DLM_RECOVERY: set while dlm is in recovery, between recover_prep()
+ * and recover_done(), i.e. set while recover_block == recover_start.
+ */
+
 enum {
        DFL_BLOCK_LOCKS         = 0,
+       DFL_NO_DLM_OPS          = 1,
+       DFL_FIRST_MOUNT         = 2,
+       DFL_FIRST_MOUNT_DONE    = 3,
+       DFL_MOUNT_DONE          = 4,
+       DFL_UNMOUNT             = 5,
+       DFL_DLM_RECOVERY        = 6,
 };
 
 struct lm_lockname {
@@ -392,6 +429,7 @@ struct gfs2_jdesc {
 #define JDF_RECOVERY 1
        unsigned int jd_jid;
        unsigned int jd_blocks;
+       int jd_recover_error;
 };
 
 struct gfs2_statfs_change_host {
@@ -461,6 +499,7 @@ enum {
        SDF_NORECOVERY          = 4,
        SDF_DEMOTE              = 5,
        SDF_NOJOURNALID         = 6,
+       SDF_RORECOVERY          = 7, /* read only recovery */
 };
 
 #define GFS2_FSNAME_LEN                256
@@ -499,14 +538,26 @@ struct gfs2_sb_host {
 struct lm_lockstruct {
        int ls_jid;
        unsigned int ls_first;
-       unsigned int ls_first_done;
        unsigned int ls_nodir;
        const struct lm_lockops *ls_ops;
-       unsigned long ls_flags;
        dlm_lockspace_t *ls_dlm;
 
-       int ls_recover_jid_done;
-       int ls_recover_jid_status;
+       int ls_recover_jid_done;   /* These two are deprecated, */
+       int ls_recover_jid_status; /* used previously by gfs_controld */
+
+       struct dlm_lksb ls_mounted_lksb; /* mounted_lock */
+       struct dlm_lksb ls_control_lksb; /* control_lock */
+       char ls_control_lvb[GDLM_LVB_SIZE]; /* control_lock lvb */
+       struct completion ls_sync_wait; /* {control,mounted}_{lock,unlock} */
+
+       spinlock_t ls_recover_spin; /* protects following fields */
+       unsigned long ls_recover_flags; /* DFL_ */
+       uint32_t ls_recover_mount; /* gen in first recover_done cb */
+       uint32_t ls_recover_start; /* gen in last recover_done cb */
+       uint32_t ls_recover_block; /* copy recover_start in last recover_prep */
+       uint32_t ls_recover_size; /* size of recover_submit, recover_result */
+       uint32_t *ls_recover_submit; /* gen in last recover_slot cb per jid */
+       uint32_t *ls_recover_result; /* result of last jid recovery */
 };
 
 struct gfs2_sbd {
@@ -544,6 +595,7 @@ struct gfs2_sbd {
        wait_queue_head_t sd_glock_wait;
        atomic_t sd_glock_disposal;
        struct completion sd_locking_init;
+       struct delayed_work sd_control_work;
 
        /* Inode Stuff */
 
index 017960cf1d7aaa198bef71664bdfed82a6fa7f9b..a7d611b93f0fca912ce716736df2524cad7b40be 100644 (file)
@@ -599,9 +599,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
        error = gfs2_meta_inode_buffer(ip, &dibh);
        if (error)
                goto fail_end_trans;
-       inc_nlink(&ip->i_inode);
-       if (S_ISDIR(ip->i_inode.i_mode))
-               inc_nlink(&ip->i_inode);
+       set_nlink(&ip->i_inode, S_ISDIR(ip->i_inode.i_mode) ? 2 : 1);
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
        gfs2_dinode_out(ip, dibh->b_data);
        brelse(dibh);
index ce85b62bc0a27f4ad0e06a0714c93a8d4a9f634c..8944d1e32ab55c09073ae0b0d0a25280491ff631 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc.  All rights reserved.
+ * Copyright 2004-2011 Red Hat, Inc.
  *
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
 #include <linux/dlm.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/delay.h>
 #include <linux/gfs2_ondisk.h>
 
 #include "incore.h"
 #include "glock.h"
 #include "util.h"
+#include "sys.h"
 
+extern struct workqueue_struct *gfs2_control_wq;
 
 static void gdlm_ast(void *arg)
 {
@@ -185,34 +188,1002 @@ static void gdlm_cancel(struct gfs2_glock *gl)
        dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_CANCEL, NULL, gl);
 }
 
-static int gdlm_mount(struct gfs2_sbd *sdp, const char *fsname)
+/*
+ * dlm/gfs2 recovery coordination using dlm_recover callbacks
+ *
+ *  1. dlm_controld sees lockspace members change
+ *  2. dlm_controld blocks dlm-kernel locking activity
+ *  3. dlm_controld within dlm-kernel notifies gfs2 (recover_prep)
+ *  4. dlm_controld starts and finishes its own user level recovery
+ *  5. dlm_controld starts dlm-kernel dlm_recoverd to do kernel recovery
+ *  6. dlm_recoverd notifies gfs2 of failed nodes (recover_slot)
+ *  7. dlm_recoverd does its own lock recovery
+ *  8. dlm_recoverd unblocks dlm-kernel locking activity
+ *  9. dlm_recoverd notifies gfs2 when done (recover_done with new generation)
+ * 10. gfs2_control updates control_lock lvb with new generation and jid bits
+ * 11. gfs2_control enqueues journals for gfs2_recover to recover (maybe none)
+ * 12. gfs2_recover dequeues and recovers journals of failed nodes
+ * 13. gfs2_recover provides recovery results to gfs2_control (recovery_result)
+ * 14. gfs2_control updates control_lock lvb jid bits for recovered journals
+ * 15. gfs2_control unblocks normal locking when all journals are recovered
+ *
+ * - failures during recovery
+ *
+ * recover_prep() may set BLOCK_LOCKS (step 3) again before gfs2_control
+ * clears BLOCK_LOCKS (step 15), e.g. another node fails while still
+ * recovering for a prior failure.  gfs2_control needs a way to detect
+ * this so it can leave BLOCK_LOCKS set in step 15.  This is managed using
+ * the recover_block and recover_start values.
+ *
+ * recover_done() provides a new lockspace generation number each time it
+ * is called (step 9).  This generation number is saved as recover_start.
+ * When recover_prep() is called, it sets BLOCK_LOCKS and sets
+ * recover_block = recover_start.  So, while recover_block is equal to
+ * recover_start, BLOCK_LOCKS should remain set.  (recover_spin must
+ * be held around the BLOCK_LOCKS/recover_block/recover_start logic.)
+ *
+ * - more specific gfs2 steps in sequence above
+ *
+ *  3. recover_prep sets BLOCK_LOCKS and sets recover_block = recover_start
+ *  6. recover_slot records any failed jids (maybe none)
+ *  9. recover_done sets recover_start = new generation number
+ * 10. gfs2_control sets control_lock lvb = new gen + bits for failed jids
+ * 12. gfs2_recover does journal recoveries for failed jids identified above
+ * 14. gfs2_control clears control_lock lvb bits for recovered jids
+ * 15. gfs2_control checks if recover_block == recover_start (step 3 occured
+ *     again) then do nothing, otherwise if recover_start > recover_block
+ *     then clear BLOCK_LOCKS.
+ *
+ * - parallel recovery steps across all nodes
+ *
+ * All nodes attempt to update the control_lock lvb with the new generation
+ * number and jid bits, but only the first to get the control_lock EX will
+ * do so; others will see that it's already done (lvb already contains new
+ * generation number.)
+ *
+ * . All nodes get the same recover_prep/recover_slot/recover_done callbacks
+ * . All nodes attempt to set control_lock lvb gen + bits for the new gen
+ * . One node gets control_lock first and writes the lvb, others see it's done
+ * . All nodes attempt to recover jids for which they see control_lock bits set
+ * . One node succeeds for a jid, and that one clears the jid bit in the lvb
+ * . All nodes will eventually see all lvb bits clear and unblock locks
+ *
+ * - is there a problem with clearing an lvb bit that should be set
+ *   and missing a journal recovery?
+ *
+ * 1. jid fails
+ * 2. lvb bit set for step 1
+ * 3. jid recovered for step 1
+ * 4. jid taken again (new mount)
+ * 5. jid fails (for step 4)
+ * 6. lvb bit set for step 5 (will already be set)
+ * 7. lvb bit cleared for step 3
+ *
+ * This is not a problem because the failure in step 5 does not
+ * require recovery, because the mount in step 4 could not have
+ * progressed far enough to unblock locks and access the fs.  The
+ * control_mount() function waits for all recoveries to be complete
+ * for the latest lockspace generation before ever unblocking locks
+ * and returning.  The mount in step 4 waits until the recovery in
+ * step 1 is done.
+ *
+ * - special case of first mounter: first node to mount the fs
+ *
+ * The first node to mount a gfs2 fs needs to check all the journals
+ * and recover any that need recovery before other nodes are allowed
+ * to mount the fs.  (Others may begin mounting, but they must wait
+ * for the first mounter to be done before taking locks on the fs
+ * or accessing the fs.)  This has two parts:
+ *
+ * 1. The mounted_lock tells a node it's the first to mount the fs.
+ * Each node holds the mounted_lock in PR while it's mounted.
+ * Each node tries to acquire the mounted_lock in EX when it mounts.
+ * If a node is granted the mounted_lock EX it means there are no
+ * other mounted nodes (no PR locks exist), and it is the first mounter.
+ * The mounted_lock is demoted to PR when first recovery is done, so
+ * others will fail to get an EX lock, but will get a PR lock.
+ *
+ * 2. The control_lock blocks others in control_mount() while the first
+ * mounter is doing first mount recovery of all journals.
+ * A mounting node needs to acquire control_lock in EX mode before
+ * it can proceed.  The first mounter holds control_lock in EX while doing
+ * the first mount recovery, blocking mounts from other nodes, then demotes
+ * control_lock to NL when it's done (others_may_mount/first_done),
+ * allowing other nodes to continue mounting.
+ *
+ * first mounter:
+ * control_lock EX/NOQUEUE success
+ * mounted_lock EX/NOQUEUE success (no other PR, so no other mounters)
+ * set first=1
+ * do first mounter recovery
+ * mounted_lock EX->PR
+ * control_lock EX->NL, write lvb generation
+ *
+ * other mounter:
+ * control_lock EX/NOQUEUE success (if fail -EAGAIN, retry)
+ * mounted_lock EX/NOQUEUE fail -EAGAIN (expected due to other mounters PR)
+ * mounted_lock PR/NOQUEUE success
+ * read lvb generation
+ * control_lock EX->NL
+ * set first=0
+ *
+ * - mount during recovery
+ *
+ * If a node mounts while others are doing recovery (not first mounter),
+ * the mounting node will get its initial recover_done() callback without
+ * having seen any previous failures/callbacks.
+ *
+ * It must wait for all recoveries preceding its mount to be finished
+ * before it unblocks locks.  It does this by repeating the "other mounter"
+ * steps above until the lvb generation number is >= its mount generation
+ * number (from initial recover_done) and all lvb bits are clear.
+ *
+ * - control_lock lvb format
+ *
+ * 4 bytes generation number: the latest dlm lockspace generation number
+ * from recover_done callback.  Indicates the jid bitmap has been updated
+ * to reflect all slot failures through that generation.
+ * 4 bytes unused.
+ * GDLM_LVB_SIZE-8 bytes of jid bit map. If bit N is set, it indicates
+ * that jid N needs recovery.
+ */
+
+#define JID_BITMAP_OFFSET 8 /* 4 byte generation number + 4 byte unused */
+
+static void control_lvb_read(struct lm_lockstruct *ls, uint32_t *lvb_gen,
+                            char *lvb_bits)
+{
+       uint32_t gen;
+       memcpy(lvb_bits, ls->ls_control_lvb, GDLM_LVB_SIZE);
+       memcpy(&gen, lvb_bits, sizeof(uint32_t));
+       *lvb_gen = le32_to_cpu(gen);
+}
+
+static void control_lvb_write(struct lm_lockstruct *ls, uint32_t lvb_gen,
+                             char *lvb_bits)
+{
+       uint32_t gen;
+       memcpy(ls->ls_control_lvb, lvb_bits, GDLM_LVB_SIZE);
+       gen = cpu_to_le32(lvb_gen);
+       memcpy(ls->ls_control_lvb, &gen, sizeof(uint32_t));
+}
+
+static int all_jid_bits_clear(char *lvb)
+{
+       int i;
+       for (i = JID_BITMAP_OFFSET; i < GDLM_LVB_SIZE; i++) {
+               if (lvb[i])
+                       return 0;
+       }
+       return 1;
+}
+
+static void sync_wait_cb(void *arg)
+{
+       struct lm_lockstruct *ls = arg;
+       complete(&ls->ls_sync_wait);
+}
+
+static int sync_unlock(struct gfs2_sbd *sdp, struct dlm_lksb *lksb, char *name)
 {
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
        int error;
 
-       if (fsname == NULL) {
-               fs_info(sdp, "no fsname found\n");
-               return -EINVAL;
+       error = dlm_unlock(ls->ls_dlm, lksb->sb_lkid, 0, lksb, ls);
+       if (error) {
+               fs_err(sdp, "%s lkid %x error %d\n",
+                      name, lksb->sb_lkid, error);
+               return error;
+       }
+
+       wait_for_completion(&ls->ls_sync_wait);
+
+       if (lksb->sb_status != -DLM_EUNLOCK) {
+               fs_err(sdp, "%s lkid %x status %d\n",
+                      name, lksb->sb_lkid, lksb->sb_status);
+               return -1;
+       }
+       return 0;
+}
+
+static int sync_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags,
+                    unsigned int num, struct dlm_lksb *lksb, char *name)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       char strname[GDLM_STRNAME_BYTES];
+       int error, status;
+
+       memset(strname, 0, GDLM_STRNAME_BYTES);
+       snprintf(strname, GDLM_STRNAME_BYTES, "%8x%16x", LM_TYPE_NONDISK, num);
+
+       error = dlm_lock(ls->ls_dlm, mode, lksb, flags,
+                        strname, GDLM_STRNAME_BYTES - 1,
+                        0, sync_wait_cb, ls, NULL);
+       if (error) {
+               fs_err(sdp, "%s lkid %x flags %x mode %d error %d\n",
+                      name, lksb->sb_lkid, flags, mode, error);
+               return error;
+       }
+
+       wait_for_completion(&ls->ls_sync_wait);
+
+       status = lksb->sb_status;
+
+       if (status && status != -EAGAIN) {
+               fs_err(sdp, "%s lkid %x flags %x mode %d status %d\n",
+                      name, lksb->sb_lkid, flags, mode, status);
+       }
+
+       return status;
+}
+
+static int mounted_unlock(struct gfs2_sbd *sdp)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sync_unlock(sdp, &ls->ls_mounted_lksb, "mounted_lock");
+}
+
+static int mounted_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sync_lock(sdp, mode, flags, GFS2_MOUNTED_LOCK,
+                        &ls->ls_mounted_lksb, "mounted_lock");
+}
+
+static int control_unlock(struct gfs2_sbd *sdp)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sync_unlock(sdp, &ls->ls_control_lksb, "control_lock");
+}
+
+static int control_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sync_lock(sdp, mode, flags, GFS2_CONTROL_LOCK,
+                        &ls->ls_control_lksb, "control_lock");
+}
+
+static void gfs2_control_func(struct work_struct *work)
+{
+       struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, sd_control_work.work);
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       char lvb_bits[GDLM_LVB_SIZE];
+       uint32_t block_gen, start_gen, lvb_gen, flags;
+       int recover_set = 0;
+       int write_lvb = 0;
+       int recover_size;
+       int i, error;
+
+       spin_lock(&ls->ls_recover_spin);
+       /*
+        * No MOUNT_DONE means we're still mounting; control_mount()
+        * will set this flag, after which this thread will take over
+        * all further clearing of BLOCK_LOCKS.
+        *
+        * FIRST_MOUNT means this node is doing first mounter recovery,
+        * for which recovery control is handled by
+        * control_mount()/control_first_done(), not this thread.
+        */
+       if (!test_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags) ||
+            test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) {
+               spin_unlock(&ls->ls_recover_spin);
+               return;
+       }
+       block_gen = ls->ls_recover_block;
+       start_gen = ls->ls_recover_start;
+       spin_unlock(&ls->ls_recover_spin);
+
+       /*
+        * Equal block_gen and start_gen implies we are between
+        * recover_prep and recover_done callbacks, which means
+        * dlm recovery is in progress and dlm locking is blocked.
+        * There's no point trying to do any work until recover_done.
+        */
+
+       if (block_gen == start_gen)
+               return;
+
+       /*
+        * Propagate recover_submit[] and recover_result[] to lvb:
+        * dlm_recoverd adds to recover_submit[] jids needing recovery
+        * gfs2_recover adds to recover_result[] journal recovery results
+        *
+        * set lvb bit for jids in recover_submit[] if the lvb has not
+        * yet been updated for the generation of the failure
+        *
+        * clear lvb bit for jids in recover_result[] if the result of
+        * the journal recovery is SUCCESS
+        */
+
+       error = control_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_VALBLK);
+       if (error) {
+               fs_err(sdp, "control lock EX error %d\n", error);
+               return;
+       }
+
+       control_lvb_read(ls, &lvb_gen, lvb_bits);
+
+       spin_lock(&ls->ls_recover_spin);
+       if (block_gen != ls->ls_recover_block ||
+           start_gen != ls->ls_recover_start) {
+               fs_info(sdp, "recover generation %u block1 %u %u\n",
+                       start_gen, block_gen, ls->ls_recover_block);
+               spin_unlock(&ls->ls_recover_spin);
+               control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT);
+               return;
+       }
+
+       recover_size = ls->ls_recover_size;
+
+       if (lvb_gen <= start_gen) {
+               /*
+                * Clear lvb bits for jids we've successfully recovered.
+                * Because all nodes attempt to recover failed journals,
+                * a journal can be recovered multiple times successfully
+                * in succession.  Only the first will really do recovery,
+                * the others find it clean, but still report a successful
+                * recovery.  So, another node may have already recovered
+                * the jid and cleared the lvb bit for it.
+                */
+               for (i = 0; i < recover_size; i++) {
+                       if (ls->ls_recover_result[i] != LM_RD_SUCCESS)
+                               continue;
+
+                       ls->ls_recover_result[i] = 0;
+
+                       if (!test_bit_le(i, lvb_bits + JID_BITMAP_OFFSET))
+                               continue;
+
+                       __clear_bit_le(i, lvb_bits + JID_BITMAP_OFFSET);
+                       write_lvb = 1;
+               }
+       }
+
+       if (lvb_gen == start_gen) {
+               /*
+                * Failed slots before start_gen are already set in lvb.
+                */
+               for (i = 0; i < recover_size; i++) {
+                       if (!ls->ls_recover_submit[i])
+                               continue;
+                       if (ls->ls_recover_submit[i] < lvb_gen)
+                               ls->ls_recover_submit[i] = 0;
+               }
+       } else if (lvb_gen < start_gen) {
+               /*
+                * Failed slots before start_gen are not yet set in lvb.
+                */
+               for (i = 0; i < recover_size; i++) {
+                       if (!ls->ls_recover_submit[i])
+                               continue;
+                       if (ls->ls_recover_submit[i] < start_gen) {
+                               ls->ls_recover_submit[i] = 0;
+                               __set_bit_le(i, lvb_bits + JID_BITMAP_OFFSET);
+                       }
+               }
+               /* even if there are no bits to set, we need to write the
+                  latest generation to the lvb */
+               write_lvb = 1;
+       } else {
+               /*
+                * we should be getting a recover_done() for lvb_gen soon
+                */
+       }
+       spin_unlock(&ls->ls_recover_spin);
+
+       if (write_lvb) {
+               control_lvb_write(ls, start_gen, lvb_bits);
+               flags = DLM_LKF_CONVERT | DLM_LKF_VALBLK;
+       } else {
+               flags = DLM_LKF_CONVERT;
+       }
+
+       error = control_lock(sdp, DLM_LOCK_NL, flags);
+       if (error) {
+               fs_err(sdp, "control lock NL error %d\n", error);
+               return;
+       }
+
+       /*
+        * Everyone will see jid bits set in the lvb, run gfs2_recover_set(),
+        * and clear a jid bit in the lvb if the recovery is a success.
+        * Eventually all journals will be recovered, all jid bits will
+        * be cleared in the lvb, and everyone will clear BLOCK_LOCKS.
+        */
+
+       for (i = 0; i < recover_size; i++) {
+               if (test_bit_le(i, lvb_bits + JID_BITMAP_OFFSET)) {
+                       fs_info(sdp, "recover generation %u jid %d\n",
+                               start_gen, i);
+                       gfs2_recover_set(sdp, i);
+                       recover_set++;
+               }
+       }
+       if (recover_set)
+               return;
+
+       /*
+        * No more jid bits set in lvb, all recovery is done, unblock locks
+        * (unless a new recover_prep callback has occured blocking locks
+        * again while working above)
+        */
+
+       spin_lock(&ls->ls_recover_spin);
+       if (ls->ls_recover_block == block_gen &&
+           ls->ls_recover_start == start_gen) {
+               clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
+               spin_unlock(&ls->ls_recover_spin);
+               fs_info(sdp, "recover generation %u done\n", start_gen);
+               gfs2_glock_thaw(sdp);
+       } else {
+               fs_info(sdp, "recover generation %u block2 %u %u\n",
+                       start_gen, block_gen, ls->ls_recover_block);
+               spin_unlock(&ls->ls_recover_spin);
+       }
+}
+
+static int control_mount(struct gfs2_sbd *sdp)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       char lvb_bits[GDLM_LVB_SIZE];
+       uint32_t start_gen, block_gen, mount_gen, lvb_gen;
+       int mounted_mode;
+       int retries = 0;
+       int error;
+
+       memset(&ls->ls_mounted_lksb, 0, sizeof(struct dlm_lksb));
+       memset(&ls->ls_control_lksb, 0, sizeof(struct dlm_lksb));
+       memset(&ls->ls_control_lvb, 0, GDLM_LVB_SIZE);
+       ls->ls_control_lksb.sb_lvbptr = ls->ls_control_lvb;
+       init_completion(&ls->ls_sync_wait);
+
+       set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
+
+       error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_VALBLK);
+       if (error) {
+               fs_err(sdp, "control_mount control_lock NL error %d\n", error);
+               return error;
+       }
+
+       error = mounted_lock(sdp, DLM_LOCK_NL, 0);
+       if (error) {
+               fs_err(sdp, "control_mount mounted_lock NL error %d\n", error);
+               control_unlock(sdp);
+               return error;
+       }
+       mounted_mode = DLM_LOCK_NL;
+
+restart:
+       if (retries++ && signal_pending(current)) {
+               error = -EINTR;
+               goto fail;
+       }
+
+       /*
+        * We always start with both locks in NL. control_lock is
+        * demoted to NL below so we don't need to do it here.
+        */
+
+       if (mounted_mode != DLM_LOCK_NL) {
+               error = mounted_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT);
+               if (error)
+                       goto fail;
+               mounted_mode = DLM_LOCK_NL;
+       }
+
+       /*
+        * Other nodes need to do some work in dlm recovery and gfs2_control
+        * before the recover_done and control_lock will be ready for us below.
+        * A delay here is not required but often avoids having to retry.
+        */
+
+       msleep_interruptible(500);
+
+       /*
+        * Acquire control_lock in EX and mounted_lock in either EX or PR.
+        * control_lock lvb keeps track of any pending journal recoveries.
+        * mounted_lock indicates if any other nodes have the fs mounted.
+        */
+
+       error = control_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE|DLM_LKF_VALBLK);
+       if (error == -EAGAIN) {
+               goto restart;
+       } else if (error) {
+               fs_err(sdp, "control_mount control_lock EX error %d\n", error);
+               goto fail;
+       }
+
+       error = mounted_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE);
+       if (!error) {
+               mounted_mode = DLM_LOCK_EX;
+               goto locks_done;
+       } else if (error != -EAGAIN) {
+               fs_err(sdp, "control_mount mounted_lock EX error %d\n", error);
+               goto fail;
+       }
+
+       error = mounted_lock(sdp, DLM_LOCK_PR, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE);
+       if (!error) {
+               mounted_mode = DLM_LOCK_PR;
+               goto locks_done;
+       } else {
+               /* not even -EAGAIN should happen here */
+               fs_err(sdp, "control_mount mounted_lock PR error %d\n", error);
+               goto fail;
+       }
+
+locks_done:
+       /*
+        * If we got both locks above in EX, then we're the first mounter.
+        * If not, then we need to wait for the control_lock lvb to be
+        * updated by other mounted nodes to reflect our mount generation.
+        *
+        * In simple first mounter cases, first mounter will see zero lvb_gen,
+        * but in cases where all existing nodes leave/fail before mounting
+        * nodes finish control_mount, then all nodes will be mounting and
+        * lvb_gen will be non-zero.
+        */
+
+       control_lvb_read(ls, &lvb_gen, lvb_bits);
+
+       if (lvb_gen == 0xFFFFFFFF) {
+               /* special value to force mount attempts to fail */
+               fs_err(sdp, "control_mount control_lock disabled\n");
+               error = -EINVAL;
+               goto fail;
+       }
+
+       if (mounted_mode == DLM_LOCK_EX) {
+               /* first mounter, keep both EX while doing first recovery */
+               spin_lock(&ls->ls_recover_spin);
+               clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
+               set_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags);
+               set_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags);
+               spin_unlock(&ls->ls_recover_spin);
+               fs_info(sdp, "first mounter control generation %u\n", lvb_gen);
+               return 0;
+       }
+
+       error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT);
+       if (error)
+               goto fail;
+
+       /*
+        * We are not first mounter, now we need to wait for the control_lock
+        * lvb generation to be >= the generation from our first recover_done
+        * and all lvb bits to be clear (no pending journal recoveries.)
+        */
+
+       if (!all_jid_bits_clear(lvb_bits)) {
+               /* journals need recovery, wait until all are clear */
+               fs_info(sdp, "control_mount wait for journal recovery\n");
+               goto restart;
+       }
+
+       spin_lock(&ls->ls_recover_spin);
+       block_gen = ls->ls_recover_block;
+       start_gen = ls->ls_recover_start;
+       mount_gen = ls->ls_recover_mount;
+
+       if (lvb_gen < mount_gen) {
+               /* wait for mounted nodes to update control_lock lvb to our
+                  generation, which might include new recovery bits set */
+               fs_info(sdp, "control_mount wait1 block %u start %u mount %u "
+                       "lvb %u flags %lx\n", block_gen, start_gen, mount_gen,
+                       lvb_gen, ls->ls_recover_flags);
+               spin_unlock(&ls->ls_recover_spin);
+               goto restart;
+       }
+
+       if (lvb_gen != start_gen) {
+               /* wait for mounted nodes to update control_lock lvb to the
+                  latest recovery generation */
+               fs_info(sdp, "control_mount wait2 block %u start %u mount %u "
+                       "lvb %u flags %lx\n", block_gen, start_gen, mount_gen,
+                       lvb_gen, ls->ls_recover_flags);
+               spin_unlock(&ls->ls_recover_spin);
+               goto restart;
+       }
+
+       if (block_gen == start_gen) {
+               /* dlm recovery in progress, wait for it to finish */
+               fs_info(sdp, "control_mount wait3 block %u start %u mount %u "
+                       "lvb %u flags %lx\n", block_gen, start_gen, mount_gen,
+                       lvb_gen, ls->ls_recover_flags);
+               spin_unlock(&ls->ls_recover_spin);
+               goto restart;
        }
 
-       error = dlm_new_lockspace(fsname, NULL, 
-                                 DLM_LSFL_FS | DLM_LSFL_NEWEXCL |
-                                 (ls->ls_nodir ? DLM_LSFL_NODIR : 0),
-                                 GDLM_LVB_SIZE, NULL, NULL, NULL, &ls->ls_dlm);
+       clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
+       set_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags);
+       memset(ls->ls_recover_submit, 0, ls->ls_recover_size*sizeof(uint32_t));
+       memset(ls->ls_recover_result, 0, ls->ls_recover_size*sizeof(uint32_t));
+       spin_unlock(&ls->ls_recover_spin);
+       return 0;
+
+fail:
+       mounted_unlock(sdp);
+       control_unlock(sdp);
+       return error;
+}
+
+static int dlm_recovery_wait(void *word)
+{
+       schedule();
+       return 0;
+}
+
+static int control_first_done(struct gfs2_sbd *sdp)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       char lvb_bits[GDLM_LVB_SIZE];
+       uint32_t start_gen, block_gen;
+       int error;
+
+restart:
+       spin_lock(&ls->ls_recover_spin);
+       start_gen = ls->ls_recover_start;
+       block_gen = ls->ls_recover_block;
+
+       if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags) ||
+           !test_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags) ||
+           !test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) {
+               /* sanity check, should not happen */
+               fs_err(sdp, "control_first_done start %u block %u flags %lx\n",
+                      start_gen, block_gen, ls->ls_recover_flags);
+               spin_unlock(&ls->ls_recover_spin);
+               control_unlock(sdp);
+               return -1;
+       }
+
+       if (start_gen == block_gen) {
+               /*
+                * Wait for the end of a dlm recovery cycle to switch from
+                * first mounter recovery.  We can ignore any recover_slot
+                * callbacks between the recover_prep and next recover_done
+                * because we are still the first mounter and any failed nodes
+                * have not fully mounted, so they don't need recovery.
+                */
+               spin_unlock(&ls->ls_recover_spin);
+               fs_info(sdp, "control_first_done wait gen %u\n", start_gen);
+
+               wait_on_bit(&ls->ls_recover_flags, DFL_DLM_RECOVERY,
+                           dlm_recovery_wait, TASK_UNINTERRUPTIBLE);
+               goto restart;
+       }
+
+       clear_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags);
+       set_bit(DFL_FIRST_MOUNT_DONE, &ls->ls_recover_flags);
+       memset(ls->ls_recover_submit, 0, ls->ls_recover_size*sizeof(uint32_t));
+       memset(ls->ls_recover_result, 0, ls->ls_recover_size*sizeof(uint32_t));
+       spin_unlock(&ls->ls_recover_spin);
+
+       memset(lvb_bits, 0, sizeof(lvb_bits));
+       control_lvb_write(ls, start_gen, lvb_bits);
+
+       error = mounted_lock(sdp, DLM_LOCK_PR, DLM_LKF_CONVERT);
+       if (error)
+               fs_err(sdp, "control_first_done mounted PR error %d\n", error);
+
+       error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT|DLM_LKF_VALBLK);
        if (error)
-               printk(KERN_ERR "dlm_new_lockspace error %d", error);
+               fs_err(sdp, "control_first_done control NL error %d\n", error);
 
        return error;
 }
 
+/*
+ * Expand static jid arrays if necessary (by increments of RECOVER_SIZE_INC)
+ * to accomodate the largest slot number.  (NB dlm slot numbers start at 1,
+ * gfs2 jids start at 0, so jid = slot - 1)
+ */
+
+#define RECOVER_SIZE_INC 16
+
+static int set_recover_size(struct gfs2_sbd *sdp, struct dlm_slot *slots,
+                           int num_slots)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       uint32_t *submit = NULL;
+       uint32_t *result = NULL;
+       uint32_t old_size, new_size;
+       int i, max_jid;
+
+       max_jid = 0;
+       for (i = 0; i < num_slots; i++) {
+               if (max_jid < slots[i].slot - 1)
+                       max_jid = slots[i].slot - 1;
+       }
+
+       old_size = ls->ls_recover_size;
+
+       if (old_size >= max_jid + 1)
+               return 0;
+
+       new_size = old_size + RECOVER_SIZE_INC;
+
+       submit = kzalloc(new_size * sizeof(uint32_t), GFP_NOFS);
+       result = kzalloc(new_size * sizeof(uint32_t), GFP_NOFS);
+       if (!submit || !result) {
+               kfree(submit);
+               kfree(result);
+               return -ENOMEM;
+       }
+
+       spin_lock(&ls->ls_recover_spin);
+       memcpy(submit, ls->ls_recover_submit, old_size * sizeof(uint32_t));
+       memcpy(result, ls->ls_recover_result, old_size * sizeof(uint32_t));
+       kfree(ls->ls_recover_submit);
+       kfree(ls->ls_recover_result);
+       ls->ls_recover_submit = submit;
+       ls->ls_recover_result = result;
+       ls->ls_recover_size = new_size;
+       spin_unlock(&ls->ls_recover_spin);
+       return 0;
+}
+
+static void free_recover_size(struct lm_lockstruct *ls)
+{
+       kfree(ls->ls_recover_submit);
+       kfree(ls->ls_recover_result);
+       ls->ls_recover_submit = NULL;
+       ls->ls_recover_result = NULL;
+       ls->ls_recover_size = 0;
+}
+
+/* dlm calls before it does lock recovery */
+
+static void gdlm_recover_prep(void *arg)
+{
+       struct gfs2_sbd *sdp = arg;
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+
+       spin_lock(&ls->ls_recover_spin);
+       ls->ls_recover_block = ls->ls_recover_start;
+       set_bit(DFL_DLM_RECOVERY, &ls->ls_recover_flags);
+
+       if (!test_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags) ||
+            test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) {
+               spin_unlock(&ls->ls_recover_spin);
+               return;
+       }
+       set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
+       spin_unlock(&ls->ls_recover_spin);
+}
+
+/* dlm calls after recover_prep has been completed on all lockspace members;
+   identifies slot/jid of failed member */
+
+static void gdlm_recover_slot(void *arg, struct dlm_slot *slot)
+{
+       struct gfs2_sbd *sdp = arg;
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       int jid = slot->slot - 1;
+
+       spin_lock(&ls->ls_recover_spin);
+       if (ls->ls_recover_size < jid + 1) {
+               fs_err(sdp, "recover_slot jid %d gen %u short size %d",
+                      jid, ls->ls_recover_block, ls->ls_recover_size);
+               spin_unlock(&ls->ls_recover_spin);
+               return;
+       }
+
+       if (ls->ls_recover_submit[jid]) {
+               fs_info(sdp, "recover_slot jid %d gen %u prev %u",
+                       jid, ls->ls_recover_block, ls->ls_recover_submit[jid]);
+       }
+       ls->ls_recover_submit[jid] = ls->ls_recover_block;
+       spin_unlock(&ls->ls_recover_spin);
+}
+
+/* dlm calls after recover_slot and after it completes lock recovery */
+
+static void gdlm_recover_done(void *arg, struct dlm_slot *slots, int num_slots,
+                             int our_slot, uint32_t generation)
+{
+       struct gfs2_sbd *sdp = arg;
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+
+       /* ensure the ls jid arrays are large enough */
+       set_recover_size(sdp, slots, num_slots);
+
+       spin_lock(&ls->ls_recover_spin);
+       ls->ls_recover_start = generation;
+
+       if (!ls->ls_recover_mount) {
+               ls->ls_recover_mount = generation;
+               ls->ls_jid = our_slot - 1;
+       }
+
+       if (!test_bit(DFL_UNMOUNT, &ls->ls_recover_flags))
+               queue_delayed_work(gfs2_control_wq, &sdp->sd_control_work, 0);
+
+       clear_bit(DFL_DLM_RECOVERY, &ls->ls_recover_flags);
+       smp_mb__after_clear_bit();
+       wake_up_bit(&ls->ls_recover_flags, DFL_DLM_RECOVERY);
+       spin_unlock(&ls->ls_recover_spin);
+}
+
+/* gfs2_recover thread has a journal recovery result */
+
+static void gdlm_recovery_result(struct gfs2_sbd *sdp, unsigned int jid,
+                                unsigned int result)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+
+       if (test_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags))
+               return;
+
+       /* don't care about the recovery of own journal during mount */
+       if (jid == ls->ls_jid)
+               return;
+
+       spin_lock(&ls->ls_recover_spin);
+       if (test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) {
+               spin_unlock(&ls->ls_recover_spin);
+               return;
+       }
+       if (ls->ls_recover_size < jid + 1) {
+               fs_err(sdp, "recovery_result jid %d short size %d",
+                      jid, ls->ls_recover_size);
+               spin_unlock(&ls->ls_recover_spin);
+               return;
+       }
+
+       fs_info(sdp, "recover jid %d result %s\n", jid,
+               result == LM_RD_GAVEUP ? "busy" : "success");
+
+       ls->ls_recover_result[jid] = result;
+
+       /* GAVEUP means another node is recovering the journal; delay our
+          next attempt to recover it, to give the other node a chance to
+          finish before trying again */
+
+       if (!test_bit(DFL_UNMOUNT, &ls->ls_recover_flags))
+               queue_delayed_work(gfs2_control_wq, &sdp->sd_control_work,
+                                  result == LM_RD_GAVEUP ? HZ : 0);
+       spin_unlock(&ls->ls_recover_spin);
+}
+
+const struct dlm_lockspace_ops gdlm_lockspace_ops = {
+       .recover_prep = gdlm_recover_prep,
+       .recover_slot = gdlm_recover_slot,
+       .recover_done = gdlm_recover_done,
+};
+
+static int gdlm_mount(struct gfs2_sbd *sdp, const char *table)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       char cluster[GFS2_LOCKNAME_LEN];
+       const char *fsname;
+       uint32_t flags;
+       int error, ops_result;
+
+       /*
+        * initialize everything
+        */
+
+       INIT_DELAYED_WORK(&sdp->sd_control_work, gfs2_control_func);
+       spin_lock_init(&ls->ls_recover_spin);
+       ls->ls_recover_flags = 0;
+       ls->ls_recover_mount = 0;
+       ls->ls_recover_start = 0;
+       ls->ls_recover_block = 0;
+       ls->ls_recover_size = 0;
+       ls->ls_recover_submit = NULL;
+       ls->ls_recover_result = NULL;
+
+       error = set_recover_size(sdp, NULL, 0);
+       if (error)
+               goto fail;
+
+       /*
+        * prepare dlm_new_lockspace args
+        */
+
+       fsname = strchr(table, ':');
+       if (!fsname) {
+               fs_info(sdp, "no fsname found\n");
+               error = -EINVAL;
+               goto fail_free;
+       }
+       memset(cluster, 0, sizeof(cluster));
+       memcpy(cluster, table, strlen(table) - strlen(fsname));
+       fsname++;
+
+       flags = DLM_LSFL_FS | DLM_LSFL_NEWEXCL;
+       if (ls->ls_nodir)
+               flags |= DLM_LSFL_NODIR;
+
+       /*
+        * create/join lockspace
+        */
+
+       error = dlm_new_lockspace(fsname, cluster, flags, GDLM_LVB_SIZE,
+                                 &gdlm_lockspace_ops, sdp, &ops_result,
+                                 &ls->ls_dlm);
+       if (error) {
+               fs_err(sdp, "dlm_new_lockspace error %d\n", error);
+               goto fail_free;
+       }
+
+       if (ops_result < 0) {
+               /*
+                * dlm does not support ops callbacks,
+                * old dlm_controld/gfs_controld are used, try without ops.
+                */
+               fs_info(sdp, "dlm lockspace ops not used\n");
+               free_recover_size(ls);
+               set_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags);
+               return 0;
+       }
+
+       if (!test_bit(SDF_NOJOURNALID, &sdp->sd_flags)) {
+               fs_err(sdp, "dlm lockspace ops disallow jid preset\n");
+               error = -EINVAL;
+               goto fail_release;
+       }
+
+       /*
+        * control_mount() uses control_lock to determine first mounter,
+        * and for later mounts, waits for any recoveries to be cleared.
+        */
+
+       error = control_mount(sdp);
+       if (error) {
+               fs_err(sdp, "mount control error %d\n", error);
+               goto fail_release;
+       }
+
+       ls->ls_first = !!test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags);
+       clear_bit(SDF_NOJOURNALID, &sdp->sd_flags);
+       smp_mb__after_clear_bit();
+       wake_up_bit(&sdp->sd_flags, SDF_NOJOURNALID);
+       return 0;
+
+fail_release:
+       dlm_release_lockspace(ls->ls_dlm, 2);
+fail_free:
+       free_recover_size(ls);
+fail:
+       return error;
+}
+
+static void gdlm_first_done(struct gfs2_sbd *sdp)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       int error;
+
+       if (test_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags))
+               return;
+
+       error = control_first_done(sdp);
+       if (error)
+               fs_err(sdp, "mount first_done error %d\n", error);
+}
+
 static void gdlm_unmount(struct gfs2_sbd *sdp)
 {
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
 
+       if (test_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags))
+               goto release;
+
+       /* wait for gfs2_control_wq to be done with this mount */
+
+       spin_lock(&ls->ls_recover_spin);
+       set_bit(DFL_UNMOUNT, &ls->ls_recover_flags);
+       spin_unlock(&ls->ls_recover_spin);
+       flush_delayed_work_sync(&sdp->sd_control_work);
+
+       /* mounted_lock and control_lock will be purged in dlm recovery */
+release:
        if (ls->ls_dlm) {
                dlm_release_lockspace(ls->ls_dlm, 2);
                ls->ls_dlm = NULL;
        }
+
+       free_recover_size(ls);
 }
 
 static const match_table_t dlm_tokens = {
@@ -226,6 +1197,8 @@ static const match_table_t dlm_tokens = {
 const struct lm_lockops gfs2_dlm_ops = {
        .lm_proto_name = "lock_dlm",
        .lm_mount = gdlm_mount,
+       .lm_first_done = gdlm_first_done,
+       .lm_recovery_result = gdlm_recovery_result,
        .lm_unmount = gdlm_unmount,
        .lm_put_lock = gdlm_put_lock,
        .lm_lock = gdlm_lock,
index c150298e2d8e022d18e71ccec7d6c68d38864e10..a8d9bcd0e19cbbb5c050b89e963b00651d50acb1 100644 (file)
@@ -28,6 +28,8 @@
 #include "recovery.h"
 #include "dir.h"
 
+struct workqueue_struct *gfs2_control_wq;
+
 static struct shrinker qd_shrinker = {
        .shrink = gfs2_shrink_qd_memory,
        .seeks = DEFAULT_SEEKS,
@@ -146,12 +148,19 @@ static int __init init_gfs2_fs(void)
        if (!gfs_recovery_wq)
                goto fail_wq;
 
+       gfs2_control_wq = alloc_workqueue("gfs2_control",
+                              WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE, 0);
+       if (!gfs2_control_wq)
+               goto fail_control;
+
        gfs2_register_debugfs();
 
        printk("GFS2 installed\n");
 
        return 0;
 
+fail_control:
+       destroy_workqueue(gfs_recovery_wq);
 fail_wq:
        unregister_filesystem(&gfs2meta_fs_type);
 fail_unregister:
@@ -195,6 +204,7 @@ static void __exit exit_gfs2_fs(void)
        unregister_filesystem(&gfs2_fs_type);
        unregister_filesystem(&gfs2meta_fs_type);
        destroy_workqueue(gfs_recovery_wq);
+       destroy_workqueue(gfs2_control_wq);
 
        rcu_barrier();
 
index fe72e79e6ff98ed66678d56c3b4be50243fd67eb..6aacf3f230a29d934347d2d2b130547769b2004e 100644 (file)
@@ -562,8 +562,12 @@ static void gfs2_others_may_mount(struct gfs2_sbd *sdp)
 {
        char *message = "FIRSTMOUNT=Done";
        char *envp[] = { message, NULL };
-       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
-       ls->ls_first_done = 1;
+
+       fs_info(sdp, "first mount done, others may mount\n");
+
+       if (sdp->sd_lockstruct.ls_ops->lm_first_done)
+               sdp->sd_lockstruct.ls_ops->lm_first_done(sdp);
+
        kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
 }
 
@@ -944,7 +948,6 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
        struct gfs2_args *args = &sdp->sd_args;
        const char *proto = sdp->sd_proto_name;
        const char *table = sdp->sd_table_name;
-       const char *fsname;
        char *o, *options;
        int ret;
 
@@ -1004,21 +1007,12 @@ hostdata_error:
                }
        }
 
-       if (sdp->sd_args.ar_spectator)
-               snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s", table);
-       else
-               snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table,
-                        sdp->sd_lockstruct.ls_jid);
-
-       fsname = strchr(table, ':');
-       if (fsname)
-               fsname++;
        if (lm->lm_mount == NULL) {
                fs_info(sdp, "Now mounting FS...\n");
                complete_all(&sdp->sd_locking_init);
                return 0;
        }
-       ret = lm->lm_mount(sdp, fsname);
+       ret = lm->lm_mount(sdp, table);
        if (ret == 0)
                fs_info(sdp, "Joined cluster. Now mounting FS...\n");
        complete_all(&sdp->sd_locking_init);
@@ -1084,7 +1078,7 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
 
        if (sdp->sd_args.ar_spectator) {
                 sb->s_flags |= MS_RDONLY;
-               set_bit(SDF_NORECOVERY, &sdp->sd_flags);
+               set_bit(SDF_RORECOVERY, &sdp->sd_flags);
        }
        if (sdp->sd_args.ar_posix_acl)
                sb->s_flags |= MS_POSIXACL;
@@ -1124,6 +1118,8 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
        if (error)
                goto fail;
 
+       snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s", sdp->sd_table_name);
+
        gfs2_create_debugfs_file(sdp);
 
        error = gfs2_sys_fs_add(sdp);
@@ -1160,6 +1156,13 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
                goto fail_sb;
        }
 
+       if (sdp->sd_args.ar_spectator)
+               snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s",
+                        sdp->sd_table_name);
+       else
+               snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u",
+                        sdp->sd_table_name, sdp->sd_lockstruct.ls_jid);
+
        error = init_inodes(sdp, DO);
        if (error)
                goto fail_sb;
index f2a02edcac8f43e9de1dd22fd4c72ac7347f39a5..963b2d75200c7fc5ae62591f458133540178db30 100644 (file)
@@ -436,12 +436,16 @@ static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
        char env_status[20];
        char *envp[] = { env_jid, env_status, NULL };
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+
         ls->ls_recover_jid_done = jid;
         ls->ls_recover_jid_status = message;
        sprintf(env_jid, "JID=%d", jid);
        sprintf(env_status, "RECOVERY=%s",
                message == LM_RD_SUCCESS ? "Done" : "Failed");
         kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
+
+       if (sdp->sd_lockstruct.ls_ops->lm_recovery_result)
+               sdp->sd_lockstruct.ls_ops->lm_recovery_result(sdp, jid, message);
 }
 
 void gfs2_recover_func(struct work_struct *work)
@@ -512,7 +516,9 @@ void gfs2_recover_func(struct work_struct *work)
                if (error)
                        goto fail_gunlock_ji;
 
-               if (test_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags)) {
+               if (test_bit(SDF_RORECOVERY, &sdp->sd_flags)) {
+                       ro = 1;
+               } else if (test_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags)) {
                        if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
                                ro = 1;
                } else {
@@ -577,6 +583,7 @@ fail_gunlock_j:
 
        fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done");
 fail:
+       jd->jd_recover_error = error;
        gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP);
 done:
        clear_bit(JDF_RECOVERY, &jd->jd_flags);
@@ -605,6 +612,6 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd, bool wait)
                wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait,
                            TASK_UNINTERRUPTIBLE);
 
-       return 0;
+       return wait ? jd->jd_recover_error : 0;
 }
 
index 22234627f684462b9c5bc2fbb6110b4496b2cc5a..981bfa32121a16c11c53fea23f0e734617755bfa 100644 (file)
@@ -1108,9 +1108,9 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
 {
        struct gfs2_blkreserv *rs = ip->i_res;
 
-       gfs2_blkrsv_put(ip);
        if (rs->rs_rgd_gh.gh_gl)
                gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
+       gfs2_blkrsv_put(ip);
 }
 
 /**
index 443cabcfcd23f834f64bc800c6c4cd518a0e58db..d33172c291bad63064dba6eebdddc8daba16b3f6 100644 (file)
@@ -298,7 +298,7 @@ static ssize_t block_show(struct gfs2_sbd *sdp, char *buf)
        ssize_t ret;
        int val = 0;
 
-       if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags))
+       if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags))
                val = 1;
        ret = sprintf(buf, "%d\n", val);
        return ret;
@@ -313,9 +313,9 @@ static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
        val = simple_strtol(buf, NULL, 0);
 
        if (val == 1)
-               set_bit(DFL_BLOCK_LOCKS, &ls->ls_flags);
+               set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
        else if (val == 0) {
-               clear_bit(DFL_BLOCK_LOCKS, &ls->ls_flags);
+               clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
                smp_mb__after_clear_bit();
                gfs2_glock_thaw(sdp);
        } else {
@@ -350,8 +350,8 @@ static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
                goto out;
        if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
                goto out;
-        sdp->sd_lockstruct.ls_first = first;
-        rv = 0;
+       sdp->sd_lockstruct.ls_first = first;
+       rv = 0;
 out:
         spin_unlock(&sdp->sd_jindex_spin);
         return rv ? rv : len;
@@ -360,19 +360,14 @@ out:
 static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf)
 {
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
-       return sprintf(buf, "%d\n", ls->ls_first_done);
+       return sprintf(buf, "%d\n", !!test_bit(DFL_FIRST_MOUNT_DONE, &ls->ls_recover_flags));
 }
 
-static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid)
 {
-       unsigned jid;
        struct gfs2_jdesc *jd;
        int rv;
 
-       rv = sscanf(buf, "%u", &jid);
-       if (rv != 1)
-               return -EINVAL;
-
        rv = -ESHUTDOWN;
        spin_lock(&sdp->sd_jindex_spin);
        if (test_bit(SDF_NORECOVERY, &sdp->sd_flags))
@@ -389,6 +384,20 @@ static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
        }
 out:
        spin_unlock(&sdp->sd_jindex_spin);
+       return rv;
+}
+
+static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+       unsigned jid;
+       int rv;
+
+       rv = sscanf(buf, "%u", &jid);
+       if (rv != 1)
+               return -EINVAL;
+
+       rv = gfs2_recover_set(sdp, jid);
+
        return rv ? rv : len;
 }
 
index e94560e836d79d008eb33100e00826952cea6efb..79182d6ad6ac01c4cdae76f564c39626f4a7c287 100644 (file)
@@ -19,5 +19,7 @@ void gfs2_sys_fs_del(struct gfs2_sbd *sdp);
 int gfs2_sys_init(void);
 void gfs2_sys_uninit(void);
 
+int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid);
+
 #endif /* __SYS_DOT_H__ */
 
index e425ad9d049008fb23d8f65cf5c1a9147154f69c..1e85a7ac021759da6a3ad118b5c1734db0bd1cc0 100644 (file)
@@ -583,7 +583,8 @@ static int hugetlbfs_set_page_dirty(struct page *page)
 }
 
 static int hugetlbfs_migrate_page(struct address_space *mapping,
-                               struct page *newpage, struct page *page)
+                               struct page *newpage, struct page *page,
+                               enum migrate_mode mode)
 {
        int rc;
 
index 4fa4f0916af9047ef57d8db43315244d92fef427..fb10d86ffad70f8c4ded56ff664470d71f06dc48 100644 (file)
@@ -322,9 +322,6 @@ EXPORT_SYMBOL(clear_nlink);
 void set_nlink(struct inode *inode, unsigned int nlink)
 {
        if (!nlink) {
-               printk_ratelimited(KERN_INFO
-                       "set_nlink() clearing i_nlink on %s inode %li\n",
-                       inode->i_sb->s_type->name, inode->i_ino);
                clear_nlink(inode);
        } else {
                /* Yes, some filesystems do change nlink from zero to one */
index f79dab83e17b304b123fa725124372561f03e349..f84b380d65e5d1a1898248bdb7a77dd3bc8b5aa4 100644 (file)
@@ -48,28 +48,12 @@ int set_task_ioprio(struct task_struct *task, int ioprio)
        if (err)
                return err;
 
-       task_lock(task);
-       do {
-               ioc = task->io_context;
-               /* see wmb() in current_io_context() */
-               smp_read_barrier_depends();
-               if (ioc)
-                       break;
-
-               ioc = alloc_io_context(GFP_ATOMIC, -1);
-               if (!ioc) {
-                       err = -ENOMEM;
-                       break;
-               }
-               task->io_context = ioc;
-       } while (1);
-
-       if (!err) {
-               ioc->ioprio = ioprio;
-               ioc->ioprio_changed = 1;
+       ioc = get_task_io_context(task, GFP_ATOMIC, NUMA_NO_NODE);
+       if (ioc) {
+               ioc_ioprio_changed(ioc, ioprio);
+               put_io_context(ioc, NULL);
        }
 
-       task_unlock(task);
        return err;
 }
 EXPORT_SYMBOL_GPL(set_task_ioprio);
index 23d7451b2938226c879be67208d2431166ea3466..65ba36b80a9e1a482f838d0846a07d0ec800b015 100644 (file)
@@ -55,7 +55,7 @@ static                                DEFINE_SPINLOCK(nsm_lock);
  * Local NSM state
  */
 u32    __read_mostly           nsm_local_state;
-int    __read_mostly           nsm_use_hostnames;
+bool   __read_mostly           nsm_use_hostnames;
 
 static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm)
 {
index fdfae9fa98cda52f26b730ab6786db084124d279..643e9f55ef297860cbbd52ab48d548e578191846 100644 (file)
@@ -371,9 +371,6 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages,
        sector_t last_block_in_bio = 0;
        struct buffer_head map_bh;
        unsigned long first_logical_block = 0;
-       struct blk_plug plug;
-
-       blk_start_plug(&plug);
 
        map_bh.b_state = 0;
        map_bh.b_size = 0;
@@ -395,7 +392,6 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages,
        BUG_ON(!list_empty(pages));
        if (bio)
                mpage_bio_submit(READ, bio);
-       blk_finish_plug(&plug);
        return 0;
 }
 EXPORT_SYMBOL(mpage_readpages);
index c283a1ec008ee3cd40bb7a6bb106ac5df9f52f41..208c6aa4a989dade864a0ca6fcd3bd4b21ba8252 100644 (file)
@@ -140,21 +140,19 @@ static int do_getname(const char __user *filename, char *page)
 
 static char *getname_flags(const char __user *filename, int flags, int *empty)
 {
-       char *tmp, *result;
-
-       result = ERR_PTR(-ENOMEM);
-       tmp = __getname();
-       if (tmp)  {
-               int retval = do_getname(filename, tmp);
-
-               result = tmp;
-               if (retval < 0) {
-                       if (retval == -ENOENT && empty)
-                               *empty = 1;
-                       if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) {
-                               __putname(tmp);
-                               result = ERR_PTR(retval);
-                       }
+       char *result = __getname();
+       int retval;
+
+       if (!result)
+               return ERR_PTR(-ENOMEM);
+
+       retval = do_getname(filename, result);
+       if (retval < 0) {
+               if (retval == -ENOENT && empty)
+                       *empty = 1;
+               if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) {
+                       __putname(result);
+                       return ERR_PTR(retval);
                }
        }
        audit_getname(result);
index 281ae95932c923f3df37fbe8df53b10509974ef4..48cfac31f64ce2b3679362b91f324ff9afc4e262 100644 (file)
@@ -90,9 +90,9 @@ static int is_writable(struct pnfs_block_extent *be, sector_t isect)
  */
 struct parallel_io {
        struct kref refcnt;
-       struct rpc_call_ops call_ops;
-       void (*pnfs_callback) (void *data);
+       void (*pnfs_callback) (void *data, int num_se);
        void *data;
+       int bse_count;
 };
 
 static inline struct parallel_io *alloc_parallel(void *data)
@@ -103,6 +103,7 @@ static inline struct parallel_io *alloc_parallel(void *data)
        if (rv) {
                rv->data = data;
                kref_init(&rv->refcnt);
+               rv->bse_count = 0;
        }
        return rv;
 }
@@ -117,7 +118,7 @@ static void destroy_parallel(struct kref *kref)
        struct parallel_io *p = container_of(kref, struct parallel_io, refcnt);
 
        dprintk("%s enter\n", __func__);
-       p->pnfs_callback(p->data);
+       p->pnfs_callback(p->data, p->bse_count);
        kfree(p);
 }
 
@@ -146,14 +147,19 @@ static struct bio *bl_alloc_init_bio(int npg, sector_t isect,
 {
        struct bio *bio;
 
+       npg = min(npg, BIO_MAX_PAGES);
        bio = bio_alloc(GFP_NOIO, npg);
-       if (!bio)
-               return NULL;
+       if (!bio && (current->flags & PF_MEMALLOC)) {
+               while (!bio && (npg /= 2))
+                       bio = bio_alloc(GFP_NOIO, npg);
+       }
 
-       bio->bi_sector = isect - be->be_f_offset + be->be_v_offset;
-       bio->bi_bdev = be->be_mdev;
-       bio->bi_end_io = end_io;
-       bio->bi_private = par;
+       if (bio) {
+               bio->bi_sector = isect - be->be_f_offset + be->be_v_offset;
+               bio->bi_bdev = be->be_mdev;
+               bio->bi_end_io = end_io;
+               bio->bi_private = par;
+       }
        return bio;
 }
 
@@ -212,22 +218,15 @@ static void bl_read_cleanup(struct work_struct *work)
 }
 
 static void
-bl_end_par_io_read(void *data)
+bl_end_par_io_read(void *data, int unused)
 {
        struct nfs_read_data *rdata = data;
 
+       rdata->task.tk_status = rdata->pnfs_error;
        INIT_WORK(&rdata->task.u.tk_work, bl_read_cleanup);
        schedule_work(&rdata->task.u.tk_work);
 }
 
-/* We don't want normal .rpc_call_done callback used, so we replace it
- * with this stub.
- */
-static void bl_rpc_do_nothing(struct rpc_task *task, void *calldata)
-{
-       return;
-}
-
 static enum pnfs_try_status
 bl_read_pagelist(struct nfs_read_data *rdata)
 {
@@ -247,8 +246,6 @@ bl_read_pagelist(struct nfs_read_data *rdata)
        par = alloc_parallel(rdata);
        if (!par)
                goto use_mds;
-       par->call_ops = *rdata->mds_ops;
-       par->call_ops.rpc_call_done = bl_rpc_do_nothing;
        par->pnfs_callback = bl_end_par_io_read;
        /* At this point, we can no longer jump to use_mds */
 
@@ -322,6 +319,7 @@ static void mark_extents_written(struct pnfs_block_layout *bl,
 {
        sector_t isect, end;
        struct pnfs_block_extent *be;
+       struct pnfs_block_short_extent *se;
 
        dprintk("%s(%llu, %u)\n", __func__, offset, count);
        if (count == 0)
@@ -334,8 +332,11 @@ static void mark_extents_written(struct pnfs_block_layout *bl,
                be = bl_find_get_extent(bl, isect, NULL);
                BUG_ON(!be); /* FIXME */
                len = min(end, be->be_f_offset + be->be_length) - isect;
-               if (be->be_state == PNFS_BLOCK_INVALID_DATA)
-                       bl_mark_for_commit(be, isect, len); /* What if fails? */
+               if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
+                       se = bl_pop_one_short_extent(be->be_inval);
+                       BUG_ON(!se);
+                       bl_mark_for_commit(be, isect, len, se);
+               }
                isect += len;
                bl_put_extent(be);
        }
@@ -357,7 +358,8 @@ static void bl_end_io_write_zero(struct bio *bio, int err)
                end_page_writeback(page);
                page_cache_release(page);
        } while (bvec >= bio->bi_io_vec);
-       if (!uptodate) {
+
+       if (unlikely(!uptodate)) {
                if (!wdata->pnfs_error)
                        wdata->pnfs_error = -EIO;
                pnfs_set_lo_fail(wdata->lseg);
@@ -366,7 +368,6 @@ static void bl_end_io_write_zero(struct bio *bio, int err)
        put_parallel(par);
 }
 
-/* This is basically copied from mpage_end_io_read */
 static void bl_end_io_write(struct bio *bio, int err)
 {
        struct parallel_io *par = bio->bi_private;
@@ -392,7 +393,7 @@ static void bl_write_cleanup(struct work_struct *work)
        dprintk("%s enter\n", __func__);
        task = container_of(work, struct rpc_task, u.tk_work);
        wdata = container_of(task, struct nfs_write_data, task);
-       if (!wdata->pnfs_error) {
+       if (likely(!wdata->pnfs_error)) {
                /* Marks for LAYOUTCOMMIT */
                mark_extents_written(BLK_LSEG2EXT(wdata->lseg),
                                     wdata->args.offset, wdata->args.count);
@@ -401,11 +402,16 @@ static void bl_write_cleanup(struct work_struct *work)
 }
 
 /* Called when last of bios associated with a bl_write_pagelist call finishes */
-static void bl_end_par_io_write(void *data)
+static void bl_end_par_io_write(void *data, int num_se)
 {
        struct nfs_write_data *wdata = data;
 
-       wdata->task.tk_status = 0;
+       if (unlikely(wdata->pnfs_error)) {
+               bl_free_short_extents(&BLK_LSEG2EXT(wdata->lseg)->bl_inval,
+                                       num_se);
+       }
+
+       wdata->task.tk_status = wdata->pnfs_error;
        wdata->verf.committed = NFS_FILE_SYNC;
        INIT_WORK(&wdata->task.u.tk_work, bl_write_cleanup);
        schedule_work(&wdata->task.u.tk_work);
@@ -484,6 +490,55 @@ cleanup:
        return ret;
 }
 
+/* Find or create a zeroing page marked being writeback.
+ * Return ERR_PTR on error, NULL to indicate skip this page and page itself
+ * to indicate write out.
+ */
+static struct page *
+bl_find_get_zeroing_page(struct inode *inode, pgoff_t index,
+                       struct pnfs_block_extent *cow_read)
+{
+       struct page *page;
+       int locked = 0;
+       page = find_get_page(inode->i_mapping, index);
+       if (page)
+               goto check_page;
+
+       page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
+       if (unlikely(!page)) {
+               dprintk("%s oom\n", __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+       locked = 1;
+
+check_page:
+       /* PageDirty: Other will write this out
+        * PageWriteback: Other is writing this out
+        * PageUptodate: It was read before
+        */
+       if (PageDirty(page) || PageWriteback(page)) {
+               print_page(page);
+               if (locked)
+                       unlock_page(page);
+               page_cache_release(page);
+               return NULL;
+       }
+
+       if (!locked) {
+               lock_page(page);
+               locked = 1;
+               goto check_page;
+       }
+       if (!PageUptodate(page)) {
+               /* New page, readin or zero it */
+               init_page_for_write(page, cow_read);
+       }
+       set_page_writeback(page);
+       unlock_page(page);
+
+       return page;
+}
+
 static enum pnfs_try_status
 bl_write_pagelist(struct nfs_write_data *wdata, int sync)
 {
@@ -508,9 +563,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
         */
        par = alloc_parallel(wdata);
        if (!par)
-               return PNFS_NOT_ATTEMPTED;
-       par->call_ops = *wdata->mds_ops;
-       par->call_ops.rpc_call_done = bl_rpc_do_nothing;
+               goto out_mds;
        par->pnfs_callback = bl_end_par_io_write;
        /* At this point, have to be more careful with error handling */
 
@@ -518,12 +571,15 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync)
        be = bl_find_get_extent(BLK_LSEG2EXT(wdata->lseg), isect, &cow_read);
        if (!be || !is_writable(be, isect)) {
                dprintk("%s no matching extents!\n", __func__);
-               wdata->pnfs_error = -EINVAL;
-               goto out;
+               goto out_mds;
        }
 
        /* First page inside INVALID extent */
        if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
+               if (likely(!bl_push_one_short_extent(be->be_inval)))
+                       par->bse_count++;
+               else
+                       goto out_mds;
                temp = offset >> PAGE_CACHE_SHIFT;
                npg_zero = do_div(temp, npg_per_block);
                isect = (sector_t) (((offset - npg_zero * PAGE_CACHE_SIZE) &
@@ -543,36 +599,16 @@ fill_invalid_ext:
                        dprintk("%s zero %dth page: index %lu isect %llu\n",
                                __func__, npg_zero, index,
                                (unsigned long long)isect);
-                       page =
-                           find_or_create_page(wdata->inode->i_mapping, index,
-                                               GFP_NOFS);
-                       if (!page) {
-                               dprintk("%s oom\n", __func__);
-                               wdata->pnfs_error = -ENOMEM;
+                       page = bl_find_get_zeroing_page(wdata->inode, index,
+                                                       cow_read);
+                       if (unlikely(IS_ERR(page))) {
+                               wdata->pnfs_error = PTR_ERR(page);
                                goto out;
-                       }
-
-                       /* PageDirty: Other will write this out
-                        * PageWriteback: Other is writing this out
-                        * PageUptodate: It was read before
-                        * sector_initialized: already written out
-                        */
-                       if (PageDirty(page) || PageWriteback(page)) {
-                               print_page(page);
-                               unlock_page(page);
-                               page_cache_release(page);
+                       } else if (page == NULL)
                                goto next_page;
-                       }
-                       if (!PageUptodate(page)) {
-                               /* New page, readin or zero it */
-                               init_page_for_write(page, cow_read);
-                       }
-                       set_page_writeback(page);
-                       unlock_page(page);
 
                        ret = bl_mark_sectors_init(be->be_inval, isect,
-                                                      PAGE_CACHE_SECTORS,
-                                                      NULL);
+                                                      PAGE_CACHE_SECTORS);
                        if (unlikely(ret)) {
                                dprintk("%s bl_mark_sectors_init fail %d\n",
                                        __func__, ret);
@@ -581,6 +617,19 @@ fill_invalid_ext:
                                wdata->pnfs_error = ret;
                                goto out;
                        }
+                       if (likely(!bl_push_one_short_extent(be->be_inval)))
+                               par->bse_count++;
+                       else {
+                               end_page_writeback(page);
+                               page_cache_release(page);
+                               wdata->pnfs_error = -ENOMEM;
+                               goto out;
+                       }
+                       /* FIXME: This should be done in bi_end_io */
+                       mark_extents_written(BLK_LSEG2EXT(wdata->lseg),
+                                            page->index << PAGE_CACHE_SHIFT,
+                                            PAGE_CACHE_SIZE);
+
                        bio = bl_add_page_to_bio(bio, npg_zero, WRITE,
                                                 isect, page, be,
                                                 bl_end_io_write_zero, par);
@@ -589,10 +638,6 @@ fill_invalid_ext:
                                bio = NULL;
                                goto out;
                        }
-                       /* FIXME: This should be done in bi_end_io */
-                       mark_extents_written(BLK_LSEG2EXT(wdata->lseg),
-                                            page->index << PAGE_CACHE_SHIFT,
-                                            PAGE_CACHE_SIZE);
 next_page:
                        isect += PAGE_CACHE_SECTORS;
                        extent_length -= PAGE_CACHE_SECTORS;
@@ -616,13 +661,21 @@ next_page:
                                wdata->pnfs_error = -EINVAL;
                                goto out;
                        }
+                       if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
+                               if (likely(!bl_push_one_short_extent(
+                                                               be->be_inval)))
+                                       par->bse_count++;
+                               else {
+                                       wdata->pnfs_error = -ENOMEM;
+                                       goto out;
+                               }
+                       }
                        extent_length = be->be_length -
                            (isect - be->be_f_offset);
                }
                if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
                        ret = bl_mark_sectors_init(be->be_inval, isect,
-                                                      PAGE_CACHE_SECTORS,
-                                                      NULL);
+                                                      PAGE_CACHE_SECTORS);
                        if (unlikely(ret)) {
                                dprintk("%s bl_mark_sectors_init fail %d\n",
                                        __func__, ret);
@@ -664,6 +717,10 @@ out:
        bl_submit_bio(WRITE, bio);
        put_parallel(par);
        return PNFS_ATTEMPTED;
+out_mds:
+       bl_put_extent(be);
+       kfree(par);
+       return PNFS_NOT_ATTEMPTED;
 }
 
 /* FIXME - range ignored */
@@ -690,11 +747,17 @@ static void
 release_inval_marks(struct pnfs_inval_markings *marks)
 {
        struct pnfs_inval_tracking *pos, *temp;
+       struct pnfs_block_short_extent *se, *stemp;
 
        list_for_each_entry_safe(pos, temp, &marks->im_tree.mtt_stub, it_link) {
                list_del(&pos->it_link);
                kfree(pos);
        }
+
+       list_for_each_entry_safe(se, stemp, &marks->im_extents, bse_node) {
+               list_del(&se->bse_node);
+               kfree(se);
+       }
        return;
 }
 
@@ -779,16 +842,13 @@ bl_cleanup_layoutcommit(struct nfs4_layoutcommit_data *lcdata)
 static void free_blk_mountid(struct block_mount_id *mid)
 {
        if (mid) {
-               struct pnfs_block_dev *dev;
-               spin_lock(&mid->bm_lock);
-               while (!list_empty(&mid->bm_devlist)) {
-                       dev = list_first_entry(&mid->bm_devlist,
-                                              struct pnfs_block_dev,
-                                              bm_node);
+               struct pnfs_block_dev *dev, *tmp;
+
+               /* No need to take bm_lock as we are last user freeing bm_devlist */
+               list_for_each_entry_safe(dev, tmp, &mid->bm_devlist, bm_node) {
                        list_del(&dev->bm_node);
                        bl_free_block_dev(dev);
                }
-               spin_unlock(&mid->bm_lock);
                kfree(mid);
        }
 }
index 42acf7ef59926d61ce0b4a12e208585d928a9aad..e31a2df28e70aca040560b8d94403d85d67cd170 100644 (file)
@@ -70,6 +70,7 @@ struct pnfs_inval_markings {
        spinlock_t      im_lock;
        struct my_tree  im_tree;        /* Sectors that need LAYOUTCOMMIT */
        sector_t        im_block_size;  /* Server blocksize in sectors */
+       struct list_head im_extents;    /* Short extents for INVAL->RW conversion */
 };
 
 struct pnfs_inval_tracking {
@@ -105,6 +106,7 @@ BL_INIT_INVAL_MARKS(struct pnfs_inval_markings *marks, sector_t blocksize)
 {
        spin_lock_init(&marks->im_lock);
        INIT_LIST_HEAD(&marks->im_tree.mtt_stub);
+       INIT_LIST_HEAD(&marks->im_extents);
        marks->im_block_size = blocksize;
        marks->im_tree.mtt_step_size = min((sector_t)PAGE_CACHE_SECTORS,
                                           blocksize);
@@ -186,8 +188,7 @@ struct pnfs_block_extent *
 bl_find_get_extent(struct pnfs_block_layout *bl, sector_t isect,
                struct pnfs_block_extent **cow_read);
 int bl_mark_sectors_init(struct pnfs_inval_markings *marks,
-                            sector_t offset, sector_t length,
-                            sector_t **pages);
+                            sector_t offset, sector_t length);
 void bl_put_extent(struct pnfs_block_extent *be);
 struct pnfs_block_extent *bl_alloc_extent(void);
 int bl_is_sector_init(struct pnfs_inval_markings *marks, sector_t isect);
@@ -200,6 +201,11 @@ void clean_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
 int bl_add_merge_extent(struct pnfs_block_layout *bl,
                         struct pnfs_block_extent *new);
 int bl_mark_for_commit(struct pnfs_block_extent *be,
-                       sector_t offset, sector_t length);
+                       sector_t offset, sector_t length,
+                       struct pnfs_block_short_extent *new);
+int bl_push_one_short_extent(struct pnfs_inval_markings *marks);
+struct pnfs_block_short_extent *
+bl_pop_one_short_extent(struct pnfs_inval_markings *marks);
+void bl_free_short_extents(struct pnfs_inval_markings *marks, int num_to_free);
 
 #endif /* FS_NFS_NFS4BLOCKLAYOUT_H */
index 19fa7b0b8c00d8d2fdebef8b25e59a1b5b0598de..1abac09f7cd5f9fd46cc07401873067e49a4b7f7 100644 (file)
@@ -110,13 +110,7 @@ static int _add_entry(struct my_tree *tree, u64 s, int32_t tag,
                return 0;
        } else {
                struct pnfs_inval_tracking *new;
-               if (storage)
-                       new = storage;
-               else {
-                       new = kmalloc(sizeof(*new), GFP_NOFS);
-                       if (!new)
-                               return -ENOMEM;
-               }
+               new = storage;
                new->it_sector = s;
                new->it_tags = (1 << tag);
                list_add(&new->it_link, &pos->it_link);
@@ -139,11 +133,13 @@ static int _set_range(struct my_tree *tree, int32_t tag, u64 s, u64 length)
 }
 
 /* Ensure that future operations on given range of tree will not malloc */
-static int _preload_range(struct my_tree *tree, u64 offset, u64 length)
+static int _preload_range(struct pnfs_inval_markings *marks,
+               u64 offset, u64 length)
 {
        u64 start, end, s;
        int count, i, used = 0, status = -ENOMEM;
        struct pnfs_inval_tracking **storage;
+       struct my_tree  *tree = &marks->im_tree;
 
        dprintk("%s(%llu, %llu) enter\n", __func__, offset, length);
        start = normalize(offset, tree->mtt_step_size);
@@ -161,12 +157,11 @@ static int _preload_range(struct my_tree *tree, u64 offset, u64 length)
                        goto out_cleanup;
        }
 
-       /* Now need lock - HOW??? */
-
+       spin_lock_bh(&marks->im_lock);
        for (s = start; s < end; s += tree->mtt_step_size)
                used += _add_entry(tree, s, INTERNAL_EXISTS, storage[used]);
+       spin_unlock_bh(&marks->im_lock);
 
-       /* Unlock - HOW??? */
        status = 0;
 
  out_cleanup:
@@ -179,41 +174,14 @@ static int _preload_range(struct my_tree *tree, u64 offset, u64 length)
        return status;
 }
 
-static void set_needs_init(sector_t *array, sector_t offset)
-{
-       sector_t *p = array;
-
-       dprintk("%s enter\n", __func__);
-       if (!p)
-               return;
-       while (*p < offset)
-               p++;
-       if (*p == offset)
-               return;
-       else if (*p == ~0) {
-               *p++ = offset;
-               *p = ~0;
-               return;
-       } else {
-               sector_t *save = p;
-               dprintk("%s Adding %llu\n", __func__, (u64)offset);
-               while (*p != ~0)
-                       p++;
-               p++;
-               memmove(save + 1, save, (char *)p - (char *)save);
-               *save = offset;
-               return;
-       }
-}
-
 /* We are relying on page lock to serialize this */
 int bl_is_sector_init(struct pnfs_inval_markings *marks, sector_t isect)
 {
        int rv;
 
-       spin_lock(&marks->im_lock);
+       spin_lock_bh(&marks->im_lock);
        rv = _has_tag(&marks->im_tree, isect, EXTENT_INITIALIZED);
-       spin_unlock(&marks->im_lock);
+       spin_unlock_bh(&marks->im_lock);
        return rv;
 }
 
@@ -253,78 +221,39 @@ static int is_range_written(struct pnfs_inval_markings *marks,
 {
        int rv;
 
-       spin_lock(&marks->im_lock);
+       spin_lock_bh(&marks->im_lock);
        rv = _range_has_tag(&marks->im_tree, start, end, EXTENT_WRITTEN);
-       spin_unlock(&marks->im_lock);
+       spin_unlock_bh(&marks->im_lock);
        return rv;
 }
 
 /* Marks sectors in [offest, offset_length) as having been initialized.
  * All lengths are step-aligned, where step is min(pagesize, blocksize).
- * Notes where partial block is initialized, and helps prepare it for
- * complete initialization later.
+ * Currently assumes offset is page-aligned
  */
-/* Currently assumes offset is page-aligned */
 int bl_mark_sectors_init(struct pnfs_inval_markings *marks,
-                            sector_t offset, sector_t length,
-                            sector_t **pages)
+                            sector_t offset, sector_t length)
 {
-       sector_t s, start, end;
-       sector_t *array = NULL; /* Pages to mark */
+       sector_t start, end;
 
        dprintk("%s(offset=%llu,len=%llu) enter\n",
                __func__, (u64)offset, (u64)length);
-       s = max((sector_t) 3,
-               2 * (marks->im_block_size / (PAGE_CACHE_SECTORS)));
-       dprintk("%s set max=%llu\n", __func__, (u64)s);
-       if (pages) {
-               array = kmalloc(s * sizeof(sector_t), GFP_NOFS);
-               if (!array)
-                       goto outerr;
-               array[0] = ~0;
-       }
 
        start = normalize(offset, marks->im_block_size);
        end = normalize_up(offset + length, marks->im_block_size);
-       if (_preload_range(&marks->im_tree, start, end - start))
+       if (_preload_range(marks, start, end - start))
                goto outerr;
 
-       spin_lock(&marks->im_lock);
-
-       for (s = normalize_up(start, PAGE_CACHE_SECTORS);
-            s < offset; s += PAGE_CACHE_SECTORS) {
-               dprintk("%s pre-area pages\n", __func__);
-               /* Portion of used block is not initialized */
-               if (!_has_tag(&marks->im_tree, s, EXTENT_INITIALIZED))
-                       set_needs_init(array, s);
-       }
+       spin_lock_bh(&marks->im_lock);
        if (_set_range(&marks->im_tree, EXTENT_INITIALIZED, offset, length))
                goto out_unlock;
-       for (s = normalize_up(offset + length, PAGE_CACHE_SECTORS);
-            s < end; s += PAGE_CACHE_SECTORS) {
-               dprintk("%s post-area pages\n", __func__);
-               if (!_has_tag(&marks->im_tree, s, EXTENT_INITIALIZED))
-                       set_needs_init(array, s);
-       }
-
-       spin_unlock(&marks->im_lock);
+       spin_unlock_bh(&marks->im_lock);
 
-       if (pages) {
-               if (array[0] == ~0) {
-                       kfree(array);
-                       *pages = NULL;
-               } else
-                       *pages = array;
-       }
        return 0;
 
- out_unlock:
-       spin_unlock(&marks->im_lock);
- outerr:
-       if (pages) {
-               kfree(array);
-               *pages = NULL;
-       }
+out_unlock:
+       spin_unlock_bh(&marks->im_lock);
+outerr:
        return -ENOMEM;
 }
 
@@ -338,9 +267,9 @@ static int mark_written_sectors(struct pnfs_inval_markings *marks,
 
        dprintk("%s(offset=%llu,len=%llu) enter\n", __func__,
                (u64)offset, (u64)length);
-       spin_lock(&marks->im_lock);
+       spin_lock_bh(&marks->im_lock);
        status = _set_range(&marks->im_tree, EXTENT_WRITTEN, offset, length);
-       spin_unlock(&marks->im_lock);
+       spin_unlock_bh(&marks->im_lock);
        return status;
 }
 
@@ -440,20 +369,18 @@ static void add_to_commitlist(struct pnfs_block_layout *bl,
 
 /* Note the range described by offset, length is guaranteed to be contained
  * within be.
+ * new will be freed, either by this function or add_to_commitlist if they
+ * decide not to use it, or after LAYOUTCOMMIT uses it in the commitlist.
  */
 int bl_mark_for_commit(struct pnfs_block_extent *be,
-                   sector_t offset, sector_t length)
+                   sector_t offset, sector_t length,
+                   struct pnfs_block_short_extent *new)
 {
        sector_t new_end, end = offset + length;
-       struct pnfs_block_short_extent *new;
        struct pnfs_block_layout *bl = container_of(be->be_inval,
                                                    struct pnfs_block_layout,
                                                    bl_inval);
 
-       new = kmalloc(sizeof(*new), GFP_NOFS);
-       if (!new)
-               return -ENOMEM;
-
        mark_written_sectors(be->be_inval, offset, length);
        /* We want to add the range to commit list, but it must be
         * block-normalized, and verified that the normalized range has
@@ -483,9 +410,6 @@ int bl_mark_for_commit(struct pnfs_block_extent *be,
        new->bse_mdev = be->be_mdev;
 
        spin_lock(&bl->bl_ext_lock);
-       /* new will be freed, either by add_to_commitlist if it decides not
-        * to use it, or after LAYOUTCOMMIT uses it in the commitlist.
-        */
        add_to_commitlist(bl, new);
        spin_unlock(&bl->bl_ext_lock);
        return 0;
@@ -933,3 +857,53 @@ clean_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
                }
        }
 }
+
+int bl_push_one_short_extent(struct pnfs_inval_markings *marks)
+{
+       struct pnfs_block_short_extent *new;
+
+       new = kmalloc(sizeof(*new), GFP_NOFS);
+       if (unlikely(!new))
+               return -ENOMEM;
+
+       spin_lock_bh(&marks->im_lock);
+       list_add(&new->bse_node, &marks->im_extents);
+       spin_unlock_bh(&marks->im_lock);
+
+       return 0;
+}
+
+struct pnfs_block_short_extent *
+bl_pop_one_short_extent(struct pnfs_inval_markings *marks)
+{
+       struct pnfs_block_short_extent *rv = NULL;
+
+       spin_lock_bh(&marks->im_lock);
+       if (!list_empty(&marks->im_extents)) {
+               rv = list_entry((&marks->im_extents)->next,
+                               struct pnfs_block_short_extent, bse_node);
+               list_del_init(&rv->bse_node);
+       }
+       spin_unlock_bh(&marks->im_lock);
+
+       return rv;
+}
+
+void bl_free_short_extents(struct pnfs_inval_markings *marks, int num_to_free)
+{
+       struct pnfs_block_short_extent *se = NULL, *tmp;
+
+       if (num_to_free <= 0)
+               return;
+
+       spin_lock(&marks->im_lock);
+       list_for_each_entry_safe(se, tmp, &marks->im_extents, bse_node) {
+               list_del(&se->bse_node);
+               kfree(se);
+               if (--num_to_free == 0)
+                       break;
+       }
+       spin_unlock(&marks->im_lock);
+
+       BUG_ON(num_to_free > 0);
+}
index 07df5f1d85e5188b16d51f13049dd925870b5238..c89d3b9e483c463cb1b9232e4b97520a7b7e1eaf 100644 (file)
@@ -162,7 +162,7 @@ struct cb_layoutrecallargs {
        };
 };
 
-extern unsigned nfs4_callback_layoutrecall(
+extern __be32 nfs4_callback_layoutrecall(
        struct cb_layoutrecallargs *args,
        void *dummy, struct cb_process_state *cps);
 
index 726e59a9e50f6ad20471895793efdb171aed7dd7..d50b2742f23baeb20d54c44d6919ed126faf74c8 100644 (file)
@@ -305,6 +305,10 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
        n = ntohl(*p++);
        if (n <= 0)
                goto out;
+       if (n > ULONG_MAX / sizeof(*args->devs)) {
+               status = htonl(NFS4ERR_BADXDR);
+               goto out;
+       }
 
        args->devs = kmalloc(n * sizeof(*args->devs), GFP_KERNEL);
        if (!args->devs) {
index 277dfaf2e99ac063dee95c4eddbfb8bb9afbfe1e..31778f74357de4bb3f923f6fb6d37382b598ddd1 100644 (file)
@@ -84,7 +84,7 @@ retry:
 /*
  * Turn off NFSv4 uid/gid mapping when using AUTH_SYS
  */
-static int nfs4_disable_idmapping = 1;
+static bool nfs4_disable_idmapping = true;
 
 /*
  * RPC cruft for NFS
index 25c3bfad7953645309272c324ba442680546eef3..f649fba8c38489e2cae05eb60e4ead032aca963d 100644 (file)
@@ -57,7 +57,7 @@
 #define NFS_64_BIT_INODE_NUMBERS_ENABLED       1
 
 /* Default is to see 64-bit inode numbers */
-static int enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED;
+static bool enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED;
 
 static void nfs_invalidate_inode(struct inode *);
 static int nfs_update_inode(struct inode *, struct nfs_fattr *);
index 5ee92538b06317059a7e9b16d449c22c896208bf..8102db9b926c2eb56d9035126fa27b33058d711f 100644 (file)
@@ -332,7 +332,7 @@ void nfs_commit_release_pages(struct nfs_write_data *data);
 
 #ifdef CONFIG_MIGRATION
 extern int nfs_migrate_page(struct address_space *,
-               struct page *, struct page *);
+               struct page *, struct page *, enum migrate_mode);
 #else
 #define nfs_migrate_page NULL
 #endif
index ed388aae96893628dfcecb25743acac320b8a1b4..8ae91908f5aa6fa38c128348beb272ddb6226a3b 100644 (file)
@@ -382,7 +382,7 @@ decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags)
 {
        struct nfs4_pnfs_ds_addr *da = NULL;
        char *buf, *portstr;
-       u32 port;
+       __be16 port;
        int nlen, rlen;
        int tmp[2];
        __be32 *p;
index 75366dc89686d88655c6569f4840a1651ca98690..f0c849c98fe4bfb49208ed6a34f0714257431e75 100644 (file)
@@ -3587,7 +3587,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
                res.acl_flags |= NFS4_ACL_LEN_REQUEST;
        resp_buf = page_address(pages[0]);
 
-       dprintk("%s  buf %p buflen %ld npages %d args.acl_len %ld\n",
+       dprintk("%s  buf %p buflen %zu npages %d args.acl_len %zu\n",
                __func__, buf, buflen, npages, args.acl_len);
        ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode),
                             &msg, &args.seq_args, &res.seq_res, 0);
index 0c3885255f97cf985b8b8091dc5b2a2f0eebc59f..834f0fe96f89f4acf707df504e1a244fc56d466b 100644 (file)
@@ -1688,7 +1688,7 @@ out_error:
 
 #ifdef CONFIG_MIGRATION
 int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
-               struct page *page)
+               struct page *page, enum migrate_mode mode)
 {
        /*
         * If PagePrivate is set, then the page is currently associated with
@@ -1703,7 +1703,7 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
 
        nfs_fscache_release_page(page, GFP_KERNEL);
 
-       return migrate_page(mapping, newpage, page);
+       return migrate_page(mapping, newpage, page, mode);
 }
 #endif
 
index 10e6366608f284d71eea25717392c275f18274ed..8df1ea4a6ff988b5aeda534c5310c23b048ebde8 100644 (file)
@@ -80,3 +80,13 @@ config NFSD_V4
          available from http://linux-nfs.org/.
 
          If unsure, say N.
+
+config NFSD_FAULT_INJECTION
+       bool "NFS server manual fault injection"
+       depends on NFSD_V4 && DEBUG_KERNEL
+       help
+         This option enables support for manually injecting faults
+         into the NFS server.  This is intended to be used for
+         testing error recovery on the NFS client.
+
+         If unsure, say N.
index 9b118ee2019371e151b69089061b67c3722b52c6..af32ef06b4fec76f0528b3deaee25aaf28837be8 100644 (file)
@@ -6,6 +6,7 @@ obj-$(CONFIG_NFSD)      += nfsd.o
 
 nfsd-y                         := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
                           export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o
+nfsd-$(CONFIG_NFSD_FAULT_INJECTION) += fault_inject.o
 nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
 nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
 nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
index 62f3b9074e8490897af08811ec184cacc9ad554b..cf8a6bd062fa9dc4eccdf3ecc464d83b2a8a6366 100644 (file)
@@ -87,7 +87,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
        struct svc_expkey key;
        struct svc_expkey *ek = NULL;
 
-       if (mesg[mlen-1] != '\n')
+       if (mlen < 1 || mesg[mlen-1] != '\n')
                return -EINVAL;
        mesg[mlen-1] = 0;
 
@@ -1226,12 +1226,12 @@ nfsd_export_init(void)
        int rv;
        dprintk("nfsd: initializing export module.\n");
 
-       rv = cache_register(&svc_export_cache);
+       rv = cache_register_net(&svc_export_cache, &init_net);
        if (rv)
                return rv;
-       rv = cache_register(&svc_expkey_cache);
+       rv = cache_register_net(&svc_expkey_cache, &init_net);
        if (rv)
-               cache_unregister(&svc_export_cache);
+               cache_unregister_net(&svc_export_cache, &init_net);
        return rv;
 
 }
@@ -1255,8 +1255,8 @@ nfsd_export_shutdown(void)
 
        dprintk("nfsd: shutting down export module.\n");
 
-       cache_unregister(&svc_expkey_cache);
-       cache_unregister(&svc_export_cache);
+       cache_unregister_net(&svc_expkey_cache, &init_net);
+       cache_unregister_net(&svc_export_cache, &init_net);
        svcauth_unix_purge();
 
        dprintk("nfsd: export shutdown complete.\n");
diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
new file mode 100644 (file)
index 0000000..ce7f075
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
+ *
+ * Uses debugfs to create fault injection points for client testing
+ */
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+#include "state.h"
+#include "fault_inject.h"
+
+struct nfsd_fault_inject_op {
+       char *file;
+       void (*func)(u64);
+};
+
+static struct nfsd_fault_inject_op inject_ops[] = {
+       {
+               .file   = "forget_clients",
+               .func   = nfsd_forget_clients,
+       },
+       {
+               .file   = "forget_locks",
+               .func   = nfsd_forget_locks,
+       },
+       {
+               .file   = "forget_openowners",
+               .func   = nfsd_forget_openowners,
+       },
+       {
+               .file   = "forget_delegations",
+               .func   = nfsd_forget_delegations,
+       },
+       {
+               .file   = "recall_delegations",
+               .func   = nfsd_recall_delegations,
+       },
+};
+
+static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op);
+static struct dentry *debug_dir;
+
+static int nfsd_inject_set(void *op_ptr, u64 val)
+{
+       struct nfsd_fault_inject_op *op = op_ptr;
+
+       if (val == 0)
+               printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file);
+       else
+               printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val);
+
+       op->func(val);
+       return 0;
+}
+
+static int nfsd_inject_get(void *data, u64 *val)
+{
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_nfsd, nfsd_inject_get, nfsd_inject_set, "%llu\n");
+
+void nfsd_fault_inject_cleanup(void)
+{
+       debugfs_remove_recursive(debug_dir);
+}
+
+int nfsd_fault_inject_init(void)
+{
+       unsigned int i;
+       struct nfsd_fault_inject_op *op;
+       mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+
+       debug_dir = debugfs_create_dir("nfsd", NULL);
+       if (!debug_dir)
+               goto fail;
+
+       for (i = 0; i < NUM_INJECT_OPS; i++) {
+               op = &inject_ops[i];
+               if (!debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd))
+                       goto fail;
+       }
+       return 0;
+
+fail:
+       nfsd_fault_inject_cleanup();
+       return -ENOMEM;
+}
diff --git a/fs/nfsd/fault_inject.h b/fs/nfsd/fault_inject.h
new file mode 100644 (file)
index 0000000..90bd057
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
+ *
+ * Function definitions for fault injection
+ */
+
+#ifndef LINUX_NFSD_FAULT_INJECT_H
+#define LINUX_NFSD_FAULT_INJECT_H
+
+#ifdef CONFIG_NFSD_FAULT_INJECTION
+int nfsd_fault_inject_init(void);
+void nfsd_fault_inject_cleanup(void);
+void nfsd_forget_clients(u64);
+void nfsd_forget_locks(u64);
+void nfsd_forget_openowners(u64);
+void nfsd_forget_delegations(u64);
+void nfsd_recall_delegations(u64);
+#else /* CONFIG_NFSD_FAULT_INJECTION */
+static inline int nfsd_fault_inject_init(void) { return 0; }
+static inline void nfsd_fault_inject_cleanup(void) {}
+static inline void nfsd_forget_clients(u64 num) {}
+static inline void nfsd_forget_locks(u64 num) {}
+static inline void nfsd_forget_openowners(u64 num) {}
+static inline void nfsd_forget_delegations(u64 num) {}
+static inline void nfsd_recall_delegations(u64 num) {}
+#endif /* CONFIG_NFSD_FAULT_INJECTION */
+
+#endif /* LINUX_NFSD_FAULT_INJECT_H */
index 55780a22fdbdcc02b0dcfb05bfadb3dc2417347e..94096273cd6cb37b17aa727b55d62a8c8a75a13d 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/seq_file.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <net/net_namespace.h>
 #include "idmap.h"
 #include "nfsd.h"
 
@@ -466,20 +467,20 @@ nfsd_idmap_init(void)
 {
        int rv;
 
-       rv = cache_register(&idtoname_cache);
+       rv = cache_register_net(&idtoname_cache, &init_net);
        if (rv)
                return rv;
-       rv = cache_register(&nametoid_cache);
+       rv = cache_register_net(&nametoid_cache, &init_net);
        if (rv)
-               cache_unregister(&idtoname_cache);
+               cache_unregister_net(&idtoname_cache, &init_net);
        return rv;
 }
 
 void
 nfsd_idmap_shutdown(void)
 {
-       cache_unregister(&idtoname_cache);
-       cache_unregister(&nametoid_cache);
+       cache_unregister_net(&idtoname_cache, &init_net);
+       cache_unregister_net(&nametoid_cache, &init_net);
 }
 
 static int
index c5e28ed8bca07a7fa4ab4e624cd05648d130cae2..896da74ec5634fd92739e0284f5d0768c8f12437 100644 (file)
@@ -266,10 +266,6 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_
 {
        __be32 status;
 
-       /* Only reclaims from previously confirmed clients are valid */
-       if ((status = nfs4_check_open_reclaim(&open->op_clientid)))
-               return status;
-
        /* We don't know the target directory, and therefore can not
        * set the change info
        */
@@ -373,6 +369,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        break;
                case NFS4_OPEN_CLAIM_PREVIOUS:
                        open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
+                       status = nfs4_check_open_reclaim(&open->op_clientid);
+                       if (status)
+                               goto out;
                case NFS4_OPEN_CLAIM_FH:
                case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
                        status = do_open_fhandle(rqstp, &cstate->current_fh,
index 80a0be9ed008a6db484d81303379d0a599c5dad7..0b3e875d1abd5e4cd962d5ed5df29f22c7ca546d 100644 (file)
@@ -117,8 +117,7 @@ out_no_tfm:
        return status;
 }
 
-int
-nfsd4_create_clid_dir(struct nfs4_client *clp)
+void nfsd4_create_clid_dir(struct nfs4_client *clp)
 {
        const struct cred *original_cred;
        char *dname = clp->cl_recdir;
@@ -127,13 +126,14 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
 
        dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
 
-       if (!rec_file || clp->cl_firststate)
-               return 0;
-
+       if (clp->cl_firststate)
+               return;
        clp->cl_firststate = 1;
+       if (!rec_file)
+               return;
        status = nfs4_save_creds(&original_cred);
        if (status < 0)
-               return status;
+               return;
 
        dir = rec_file->f_path.dentry;
        /* lock the parent */
@@ -144,8 +144,15 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
                status = PTR_ERR(dentry);
                goto out_unlock;
        }
-       status = -EEXIST;
        if (dentry->d_inode)
+               /*
+                * In the 4.1 case, where we're called from
+                * reclaim_complete(), records from the previous reboot
+                * may still be left, so this is OK.
+                *
+                * In the 4.0 case, we should never get here; but we may
+                * as well be forgiving and just succeed silently.
+                */
                goto out_put;
        status = mnt_want_write_file(rec_file);
        if (status)
@@ -164,7 +171,6 @@ out_unlock:
                                " and is writeable", status,
                                user_recovery_dirname);
        nfs4_reset_creds(original_cred);
-       return status;
 }
 
 typedef int (recdir_func)(struct dentry *, struct dentry *);
index 9ca16dc09e04878bd89bf4e471e5364f719d3aef..e8c98f0096706c04e70456c35af2f8123241af7a 100644 (file)
 time_t nfsd4_lease = 90;     /* default lease time */
 time_t nfsd4_grace = 90;
 static time_t boot_time;
-static stateid_t zerostateid;             /* bits all 0 */
-static stateid_t onestateid;              /* bits all 1 */
+
+#define all_ones {{~0,~0},~0}
+static const stateid_t one_stateid = {
+       .si_generation = ~0,
+       .si_opaque = all_ones,
+};
+static const stateid_t zero_stateid = {
+       /* all fields zero */
+};
+
 static u64 current_sessionid = 1;
 
-#define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t)))
-#define ONE_STATEID(stateid)  (!memcmp((stateid), &onestateid, sizeof(stateid_t)))
+#define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
+#define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
 
 /* forward declarations */
 static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
@@ -133,21 +141,21 @@ unsigned int max_delegations;
  * Open owner state (share locks)
  */
 
-/* hash tables for open owners */
-#define OPEN_OWNER_HASH_BITS              8
-#define OPEN_OWNER_HASH_SIZE             (1 << OPEN_OWNER_HASH_BITS)
-#define OPEN_OWNER_HASH_MASK             (OPEN_OWNER_HASH_SIZE - 1)
+/* hash tables for lock and open owners */
+#define OWNER_HASH_BITS              8
+#define OWNER_HASH_SIZE             (1 << OWNER_HASH_BITS)
+#define OWNER_HASH_MASK             (OWNER_HASH_SIZE - 1)
 
-static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
+static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
 {
        unsigned int ret;
 
        ret = opaque_hashval(ownername->data, ownername->len);
        ret += clientid;
-       return ret & OPEN_OWNER_HASH_MASK;
+       return ret & OWNER_HASH_MASK;
 }
 
-static struct list_head        open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE];
+static struct list_head        ownerstr_hashtbl[OWNER_HASH_SIZE];
 
 /* hash table for nfs4_file */
 #define FILE_HASH_BITS                   8
@@ -514,6 +522,7 @@ static void unhash_lockowner(struct nfs4_lockowner *lo)
 
        list_del(&lo->lo_owner.so_strhash);
        list_del(&lo->lo_perstateid);
+       list_del(&lo->lo_owner_ino_hash);
        while (!list_empty(&lo->lo_owner.so_stateids)) {
                stp = list_first_entry(&lo->lo_owner.so_stateids,
                                struct nfs4_ol_stateid, st_perstateowner);
@@ -985,12 +994,11 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
        clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
        if (clp == NULL)
                return NULL;
-       clp->cl_name.data = kmalloc(name.len, GFP_KERNEL);
+       clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL);
        if (clp->cl_name.data == NULL) {
                kfree(clp);
                return NULL;
        }
-       memcpy(clp->cl_name.data, name.data, name.len);
        clp->cl_name.len = name.len;
        return clp;
 }
@@ -1058,7 +1066,6 @@ expire_client(struct nfs4_client *clp)
        spin_unlock(&recall_lock);
        while (!list_empty(&reaplist)) {
                dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
-               list_del_init(&dp->dl_recall_lru);
                unhash_delegation(dp);
        }
        while (!list_empty(&clp->cl_openowners)) {
@@ -2301,7 +2308,7 @@ nfsd4_free_slabs(void)
        nfsd4_free_slab(&deleg_slab);
 }
 
-static int
+int
 nfsd4_init_slabs(void)
 {
        openowner_slab = kmem_cache_create("nfsd4_openowners",
@@ -2373,7 +2380,7 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj
 
 static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
 {
-       list_add(&oo->oo_owner.so_strhash, &open_ownerstr_hashtbl[strhashval]);
+       list_add(&oo->oo_owner.so_strhash, &ownerstr_hashtbl[strhashval]);
        list_add(&oo->oo_perclient, &clp->cl_openowners);
 }
 
@@ -2436,7 +2443,9 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
        struct nfs4_stateowner *so;
        struct nfs4_openowner *oo;
 
-       list_for_each_entry(so, &open_ownerstr_hashtbl[hashval], so_strhash) {
+       list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
+               if (!so->so_is_open_owner)
+                       continue;
                if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {
                        oo = openowner(so);
                        renew_client(oo->oo_owner.so_client);
@@ -2580,7 +2589,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
        if (open->op_file == NULL)
                return nfserr_jukebox;
 
-       strhashval = open_ownerstr_hashval(clientid->cl_id, &open->op_owner);
+       strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner);
        oo = find_openstateowner_str(strhashval, open);
        open->op_openowner = oo;
        if (!oo) {
@@ -3123,7 +3132,6 @@ nfs4_laundromat(void)
        spin_unlock(&recall_lock);
        list_for_each_safe(pos, next, &reaplist) {
                dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
-               list_del_init(&dp->dl_recall_lru);
                unhash_delegation(dp);
        }
        test_val = nfsd4_lease;
@@ -3718,13 +3726,11 @@ out:
 }
 
 
-/* 
- * Lock owner state (byte-range locks)
- */
 #define LOFF_OVERFLOW(start, len)      ((u64)(len) > ~(u64)(start))
-#define LOCK_HASH_BITS              8
-#define LOCK_HASH_SIZE             (1 << LOCK_HASH_BITS)
-#define LOCK_HASH_MASK             (LOCK_HASH_SIZE - 1)
+
+#define LOCKOWNER_INO_HASH_BITS 8
+#define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS)
+#define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1)
 
 static inline u64
 end_offset(u64 start, u64 len)
@@ -3746,16 +3752,14 @@ last_byte_offset(u64 start, u64 len)
        return end > start ? end - 1: NFS4_MAX_UINT64;
 }
 
-static inline unsigned int
-lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
-               struct xdr_netobj *ownername)
+static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct xdr_netobj *ownername)
 {
        return (file_hashval(inode) + cl_id
                        + opaque_hashval(ownername->data, ownername->len))
-               & LOCK_HASH_MASK;
+               & LOCKOWNER_INO_HASH_MASK;
 }
 
-static struct list_head        lock_ownerstr_hashtbl[LOCK_HASH_SIZE];
+static struct list_head lockowner_ino_hashtbl[LOCKOWNER_INO_HASH_SIZE];
 
 /*
  * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
@@ -3809,23 +3813,39 @@ nevermind:
                deny->ld_type = NFS4_WRITE_LT;
 }
 
+static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, clientid_t *clid, struct xdr_netobj *owner)
+{
+       struct nfs4_ol_stateid *lst;
+
+       if (!same_owner_str(&lo->lo_owner, owner, clid))
+               return false;
+       lst = list_first_entry(&lo->lo_owner.so_stateids,
+                              struct nfs4_ol_stateid, st_perstateowner);
+       return lst->st_file->fi_inode == inode;
+}
+
 static struct nfs4_lockowner *
 find_lockowner_str(struct inode *inode, clientid_t *clid,
                struct xdr_netobj *owner)
 {
-       unsigned int hashval = lock_ownerstr_hashval(inode, clid->cl_id, owner);
-       struct nfs4_stateowner *op;
+       unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner);
+       struct nfs4_lockowner *lo;
 
-       list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) {
-               if (same_owner_str(op, owner, clid))
-                       return lockowner(op);
+       list_for_each_entry(lo, &lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) {
+               if (same_lockowner_ino(lo, inode, clid, owner))
+                       return lo;
        }
        return NULL;
 }
 
 static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
 {
-       list_add(&lo->lo_owner.so_strhash, &lock_ownerstr_hashtbl[strhashval]);
+       struct inode *inode = open_stp->st_file->fi_inode;
+       unsigned int inohash = lockowner_ino_hashval(inode,
+                       clp->cl_clientid.cl_id, &lo->lo_owner.so_owner);
+
+       list_add(&lo->lo_owner.so_strhash, &ownerstr_hashtbl[strhashval]);
+       list_add(&lo->lo_owner_ino_hash, &lockowner_ino_hashtbl[inohash]);
        list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
 }
 
@@ -3834,7 +3854,7 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s
  * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 
  * occurred. 
  *
- * strhashval = lock_ownerstr_hashval 
+ * strhashval = ownerstr_hashval
  */
 
 static struct nfs4_lockowner *
@@ -3892,6 +3912,37 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
        __set_bit(access, &lock_stp->st_access_bmap);
 }
 
+__be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new)
+{
+       struct nfs4_file *fi = ost->st_file;
+       struct nfs4_openowner *oo = openowner(ost->st_stateowner);
+       struct nfs4_client *cl = oo->oo_owner.so_client;
+       struct nfs4_lockowner *lo;
+       unsigned int strhashval;
+
+       lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, &lock->v.new.owner);
+       if (lo) {
+               if (!cstate->minorversion)
+                       return nfserr_bad_seqid;
+               /* XXX: a lockowner always has exactly one stateid: */
+               *lst = list_first_entry(&lo->lo_owner.so_stateids,
+                               struct nfs4_ol_stateid, st_perstateowner);
+               return nfs_ok;
+       }
+       strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
+                       &lock->v.new.owner);
+       lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
+       if (lo == NULL)
+               return nfserr_jukebox;
+       *lst = alloc_init_lock_stateid(lo, fi, ost);
+       if (*lst == NULL) {
+               release_lockowner(lo);
+               return nfserr_jukebox;
+       }
+       *new = true;
+       return nfs_ok;
+}
+
 /*
  *  LOCK operation 
  */
@@ -3907,7 +3958,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        struct file_lock file_lock;
        struct file_lock conflock;
        __be32 status = 0;
-       unsigned int strhashval;
+       bool new_state = false;
        int lkflg;
        int err;
 
@@ -3933,10 +3984,15 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                 * lock stateid.
                 */
                struct nfs4_ol_stateid *open_stp = NULL;
-               
+
+               if (nfsd4_has_session(cstate))
+                       /* See rfc 5661 18.10.3: given clientid is ignored: */
+                       memcpy(&lock->v.new.clientid,
+                               &cstate->session->se_client->cl_clientid,
+                               sizeof(clientid_t));
+
                status = nfserr_stale_clientid;
-               if (!nfsd4_has_session(cstate) &&
-                   STALE_CLIENTID(&lock->lk_new_clientid))
+               if (STALE_CLIENTID(&lock->lk_new_clientid))
                        goto out;
 
                /* validate and update open stateid and open seqid */
@@ -3948,25 +4004,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        goto out;
                open_sop = openowner(open_stp->st_stateowner);
                status = nfserr_bad_stateid;
-               if (!nfsd4_has_session(cstate) &&
-                       !same_clid(&open_sop->oo_owner.so_client->cl_clientid,
+               if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
                                                &lock->v.new.clientid))
                        goto out;
-               /* create lockowner and lock stateid */
-               fp = open_stp->st_file;
-               strhashval = lock_ownerstr_hashval(fp->fi_inode,
-                               open_sop->oo_owner.so_client->cl_clientid.cl_id,
-                               &lock->v.new.owner);
-               /* XXX: Do we need to check for duplicate stateowners on
-                * the same file, or should they just be allowed (and
-                * create new stateids)? */
-               status = nfserr_jukebox;
-               lock_sop = alloc_init_lock_stateowner(strhashval,
-                               open_sop->oo_owner.so_client, open_stp, lock);
-               if (lock_sop == NULL)
-                       goto out;
-               lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp);
-               if (lock_stp == NULL)
+               status = lookup_or_create_lock_state(cstate, open_stp, lock,
+                                                       &lock_stp, &new_state);
+               if (status)
                        goto out;
        } else {
                /* lock (lock owner + lock stateid) already exists */
@@ -3976,10 +4019,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                                       NFS4_LOCK_STID, &lock_stp);
                if (status)
                        goto out;
-               lock_sop = lockowner(lock_stp->st_stateowner);
-               fp = lock_stp->st_file;
        }
-       /* lock_sop and lock_stp have been created or found */
+       lock_sop = lockowner(lock_stp->st_stateowner);
+       fp = lock_stp->st_file;
 
        lkflg = setlkflg(lock->lk_type);
        status = nfs4_check_openmode(lock_stp, lkflg);
@@ -4054,7 +4096,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                break;
        }
 out:
-       if (status && lock->lk_is_new && lock_sop)
+       if (status && new_state)
                release_lockowner(lock_sop);
        if (!cstate->replay_owner)
                nfs4_unlock_state();
@@ -4251,7 +4293,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
        struct nfs4_ol_stateid *stp;
        struct xdr_netobj *owner = &rlockowner->rl_owner;
        struct list_head matches;
-       int i;
+       unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
        __be32 status;
 
        dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
@@ -4266,22 +4308,19 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
        nfs4_lock_state();
 
        status = nfserr_locks_held;
-       /* XXX: we're doing a linear search through all the lockowners.
-        * Yipes!  For now we'll just hope clients aren't really using
-        * release_lockowner much, but eventually we have to fix these
-        * data structures. */
        INIT_LIST_HEAD(&matches);
-       for (i = 0; i < LOCK_HASH_SIZE; i++) {
-               list_for_each_entry(sop, &lock_ownerstr_hashtbl[i], so_strhash) {
-                       if (!same_owner_str(sop, owner, clid))
-                               continue;
-                       list_for_each_entry(stp, &sop->so_stateids,
-                                       st_perstateowner) {
-                               lo = lockowner(sop);
-                               if (check_for_locks(stp->st_file, lo))
-                                       goto out;
-                               list_add(&lo->lo_list, &matches);
-                       }
+
+       list_for_each_entry(sop, &ownerstr_hashtbl[hashval], so_strhash) {
+               if (sop->so_is_open_owner)
+                       continue;
+               if (!same_owner_str(sop, owner, clid))
+                       continue;
+               list_for_each_entry(stp, &sop->so_stateids,
+                               st_perstateowner) {
+                       lo = lockowner(sop);
+                       if (check_for_locks(stp->st_file, lo))
+                               goto out;
+                       list_add(&lo->lo_list, &matches);
                }
        }
        /* Clients probably won't expect us to return with some (but not all)
@@ -4394,16 +4433,127 @@ nfs4_check_open_reclaim(clientid_t *clid)
        return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad;
 }
 
+#ifdef CONFIG_NFSD_FAULT_INJECTION
+
+void nfsd_forget_clients(u64 num)
+{
+       struct nfs4_client *clp, *next;
+       int count = 0;
+
+       nfs4_lock_state();
+       list_for_each_entry_safe(clp, next, &client_lru, cl_lru) {
+               nfsd4_remove_clid_dir(clp);
+               expire_client(clp);
+               if (++count == num)
+                       break;
+       }
+       nfs4_unlock_state();
+
+       printk(KERN_INFO "NFSD: Forgot %d clients", count);
+}
+
+static void release_lockowner_sop(struct nfs4_stateowner *sop)
+{
+       release_lockowner(lockowner(sop));
+}
+
+static void release_openowner_sop(struct nfs4_stateowner *sop)
+{
+       release_openowner(openowner(sop));
+}
+
+static int nfsd_release_n_owners(u64 num, bool is_open_owner,
+                               void (*release_sop)(struct nfs4_stateowner *))
+{
+       int i, count = 0;
+       struct nfs4_stateowner *sop, *next;
+
+       for (i = 0; i < OWNER_HASH_SIZE; i++) {
+               list_for_each_entry_safe(sop, next, &ownerstr_hashtbl[i], so_strhash) {
+                       if (sop->so_is_open_owner != is_open_owner)
+                               continue;
+                       release_sop(sop);
+                       if (++count == num)
+                               return count;
+               }
+       }
+       return count;
+}
+
+void nfsd_forget_locks(u64 num)
+{
+       int count;
+
+       nfs4_lock_state();
+       count = nfsd_release_n_owners(num, false, release_lockowner_sop);
+       nfs4_unlock_state();
+
+       printk(KERN_INFO "NFSD: Forgot %d locks", count);
+}
+
+void nfsd_forget_openowners(u64 num)
+{
+       int count;
+
+       nfs4_lock_state();
+       count = nfsd_release_n_owners(num, true, release_openowner_sop);
+       nfs4_unlock_state();
+
+       printk(KERN_INFO "NFSD: Forgot %d open owners", count);
+}
+
+int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegation *))
+{
+       int i, count = 0;
+       struct nfs4_file *fp, *fnext;
+       struct nfs4_delegation *dp, *dnext;
+
+       for (i = 0; i < FILE_HASH_SIZE; i++) {
+               list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) {
+                       list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) {
+                               deleg_func(dp);
+                               if (++count == num)
+                                       return count;
+                       }
+               }
+       }
+
+       return count;
+}
+
+void nfsd_forget_delegations(u64 num)
+{
+       unsigned int count;
+
+       nfs4_lock_state();
+       count = nfsd_process_n_delegations(num, unhash_delegation);
+       nfs4_unlock_state();
+
+       printk(KERN_INFO "NFSD: Forgot %d delegations", count);
+}
+
+void nfsd_recall_delegations(u64 num)
+{
+       unsigned int count;
+
+       nfs4_lock_state();
+       spin_lock(&recall_lock);
+       count = nfsd_process_n_delegations(num, nfsd_break_one_deleg);
+       spin_unlock(&recall_lock);
+       nfs4_unlock_state();
+
+       printk(KERN_INFO "NFSD: Recalled %d delegations", count);
+}
+
+#endif /* CONFIG_NFSD_FAULT_INJECTION */
+
 /* initialization to perform at module load time: */
 
-int
+void
 nfs4_state_init(void)
 {
-       int i, status;
+       int i;
 
-       status = nfsd4_init_slabs();
-       if (status)
-               return status;
        for (i = 0; i < CLIENT_HASH_SIZE; i++) {
                INIT_LIST_HEAD(&conf_id_hashtbl[i]);
                INIT_LIST_HEAD(&conf_str_hashtbl[i]);
@@ -4416,18 +4566,15 @@ nfs4_state_init(void)
        for (i = 0; i < FILE_HASH_SIZE; i++) {
                INIT_LIST_HEAD(&file_hashtbl[i]);
        }
-       for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) {
-               INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]);
-       }
-       for (i = 0; i < LOCK_HASH_SIZE; i++) {
-               INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]);
+       for (i = 0; i < OWNER_HASH_SIZE; i++) {
+               INIT_LIST_HEAD(&ownerstr_hashtbl[i]);
        }
-       memset(&onestateid, ~0, sizeof(stateid_t));
+       for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++)
+               INIT_LIST_HEAD(&lockowner_ino_hashtbl[i]);
        INIT_LIST_HEAD(&close_lru);
        INIT_LIST_HEAD(&client_lru);
        INIT_LIST_HEAD(&del_recall_lru);
        reclaim_str_hashtbl_size = 0;
-       return 0;
 }
 
 static void
@@ -4526,7 +4673,6 @@ __nfs4_state_shutdown(void)
        spin_unlock(&recall_lock);
        list_for_each_safe(pos, next, &reaplist) {
                dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
-               list_del_init(&dp->dl_recall_lru);
                unhash_delegation(dp);
        }
 
index b6fa792d6b858b5950c483092e7c05ca8c583446..0ec5a1b9700e5e8d59196cfa387f608aa5c7f0ce 100644 (file)
@@ -215,10 +215,9 @@ defer_free(struct nfsd4_compoundargs *argp,
 static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
 {
        if (p == argp->tmp) {
-               p = kmalloc(nbytes, GFP_KERNEL);
+               p = kmemdup(argp->tmp, nbytes, GFP_KERNEL);
                if (!p)
                        return NULL;
-               memcpy(p, argp->tmp, nbytes);
        } else {
                BUG_ON(p != argp->tmpp);
                argp->tmpp = NULL;
index bb4a11d58a5aac3e6f1e8121ab94e2121c9a3290..748eda93ce590d1ad1e4f7892f29e25f8ad8856a 100644 (file)
@@ -18,6 +18,7 @@
 #include "idmap.h"
 #include "nfsd.h"
 #include "cache.h"
+#include "fault_inject.h"
 
 /*
  *     We have a single directory with several nodes in it.
@@ -1128,9 +1129,13 @@ static int __init init_nfsd(void)
        int retval;
        printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
 
-       retval = nfs4_state_init(); /* nfs4 locking state */
+       retval = nfsd4_init_slabs();
        if (retval)
                return retval;
+       nfs4_state_init();
+       retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
+       if (retval)
+               goto out_free_slabs;
        nfsd_stat_init();       /* Statistics */
        retval = nfsd_reply_cache_init();
        if (retval)
@@ -1161,6 +1166,8 @@ out_free_cache:
        nfsd_reply_cache_shutdown();
 out_free_stat:
        nfsd_stat_shutdown();
+       nfsd_fault_inject_cleanup();
+out_free_slabs:
        nfsd4_free_slabs();
        return retval;
 }
@@ -1175,6 +1182,7 @@ static void __exit exit_nfsd(void)
        nfsd_lockd_shutdown();
        nfsd_idmap_shutdown();
        nfsd4_free_slabs();
+       nfsd_fault_inject_cleanup();
        unregister_filesystem(&nfsd_fs_type);
 }
 
index 58134a23fdfbaebfbb0482e510e2d0e73bc7e44e..1d1e8589b4ce6ec02ad08dfbdd8848a051e67c2f 100644 (file)
@@ -104,14 +104,16 @@ static inline int nfsd_v4client(struct svc_rqst *rq)
  */
 #ifdef CONFIG_NFSD_V4
 extern unsigned int max_delegations;
-int nfs4_state_init(void);
+void nfs4_state_init(void);
+int nfsd4_init_slabs(void);
 void nfsd4_free_slabs(void);
 int nfs4_state_start(void);
 void nfs4_state_shutdown(void);
 void nfs4_reset_lease(time_t leasetime);
 int nfs4_reset_recoverydir(char *recdir);
 #else
-static inline int nfs4_state_init(void) { return 0; }
+static inline void nfs4_state_init(void) { }
+static inline int nfsd4_init_slabs(void) { return 0; }
 static inline void nfsd4_free_slabs(void) { }
 static inline int nfs4_state_start(void) { return 0; }
 static inline void nfs4_state_shutdown(void) { }
@@ -338,15 +340,15 @@ static inline u32 nfsd_suppattrs2(u32 minorversion)
 }
 
 /* These will return ERR_INVAL if specified in GETATTR or READDIR. */
-#define NFSD_WRITEONLY_ATTRS_WORD1                                                         \
-(FATTR4_WORD1_TIME_ACCESS_SET   | FATTR4_WORD1_TIME_MODIFY_SET)
+#define NFSD_WRITEONLY_ATTRS_WORD1 \
+       (FATTR4_WORD1_TIME_ACCESS_SET   | FATTR4_WORD1_TIME_MODIFY_SET)
 
 /* These are the only attrs allowed in CREATE/OPEN/SETATTR. */
-#define NFSD_WRITEABLE_ATTRS_WORD0                                                          \
-(FATTR4_WORD0_SIZE              | FATTR4_WORD0_ACL                                         )
-#define NFSD_WRITEABLE_ATTRS_WORD1                                                          \
-(FATTR4_WORD1_MODE              | FATTR4_WORD1_OWNER         | FATTR4_WORD1_OWNER_GROUP     \
- | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
+#define NFSD_WRITEABLE_ATTRS_WORD0 \
+       (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL)
+#define NFSD_WRITEABLE_ATTRS_WORD1 \
+       (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
      | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
 #define NFSD_WRITEABLE_ATTRS_WORD2 0
 
 #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
index a3cf38476a1b74f611cc35fff2dfc7f40e0d5e77..ffb5df1db94ff86558aff1340a6b07af2af29b79 100644 (file)
@@ -366,6 +366,7 @@ struct nfs4_openowner {
 
 struct nfs4_lockowner {
        struct nfs4_stateowner  lo_owner; /* must be first element */
+       struct list_head        lo_owner_ino_hash; /* hash by owner,file */
        struct list_head        lo_perstateid; /* for lockowners only */
        struct list_head        lo_list; /* for temporary uses */
 };
@@ -482,7 +483,7 @@ extern void nfsd4_shutdown_recdir(void);
 extern int nfs4_client_to_reclaim(const char *name);
 extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
 extern void nfsd4_recdir_purge_old(void);
-extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
+extern void nfsd4_create_clid_dir(struct nfs4_client *clp);
 extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
 extern void release_session_client(struct nfsd4_session *);
 extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
index d25a723b68ada457a3ae58973fd98e427c609b53..edf6d3ed87778822d85c32929cab580c93ed3c7a 100644 (file)
@@ -594,8 +594,19 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac
        return error;
 }
 
-#define NFSD_XATTR_JUNCTION_PREFIX XATTR_TRUSTED_PREFIX "junction."
-#define NFSD_XATTR_JUNCTION_TYPE NFSD_XATTR_JUNCTION_PREFIX "type"
+/*
+ * NFS junction information is stored in an extended attribute.
+ */
+#define NFSD_JUNCTION_XATTR_NAME       XATTR_TRUSTED_PREFIX "junction.nfs"
+
+/**
+ * nfsd4_is_junction - Test if an object could be an NFS junction
+ *
+ * @dentry: object to test
+ *
+ * Returns 1 if "dentry" appears to contain NFS junction information.
+ * Otherwise 0 is returned.
+ */
 int nfsd4_is_junction(struct dentry *dentry)
 {
        struct inode *inode = dentry->d_inode;
@@ -606,7 +617,7 @@ int nfsd4_is_junction(struct dentry *dentry)
                return 0;
        if (!(inode->i_mode & S_ISVTX))
                return 0;
-       if (vfs_getxattr(dentry, NFSD_XATTR_JUNCTION_TYPE, NULL, 0) <= 0)
+       if (vfs_getxattr(dentry, NFSD_JUNCTION_XATTR_NAME, NULL, 0) <= 0)
                return 0;
        return 1;
 }
index e14587d55689dae3cedccd1d2afeb1242ab0947c..f104d565b6823aa75ab39c5c0717e9e3fd9382f3 100644 (file)
@@ -135,9 +135,6 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)
 
        mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
 
-       /* 1 from caller and 1 for being on i_list/g_list */
-       BUG_ON(atomic_read(&mark->refcnt) < 2);
-
        spin_lock(&group->mark_lock);
 
        if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) {
@@ -181,6 +178,11 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)
        if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED))
                iput(inode);
 
+       /*
+        * 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.
+        */
+
        /*
         * it's possible that this group tried to destroy itself, but this
         * this mark was simultaneously being freed by inode.  If that's the
index 608be45160912944ccfc630a5e28bb5ae50eca45..5a4a8af5c406a20e51d57807400a572e3bcbf6bc 100644 (file)
@@ -3198,7 +3198,7 @@ MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2011 Anton Altaparm
 MODULE_VERSION(NTFS_VERSION);
 MODULE_LICENSE("GPL");
 #ifdef DEBUG
-module_param(debug_msgs, bool, 0);
+module_param(debug_msgs, bint, 0);
 MODULE_PARM_DESC(debug_msgs, "Enable debug messages.");
 #endif
 
index f0e485d54e6475fbbce59a2876f6163086031395..a932ced92a1609b6466dab7a77f0ad4cbc14e256 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1137,7 +1137,7 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages)
        if (nr_pages < pipe->nrbufs)
                return -EBUSY;
 
-       bufs = kcalloc(nr_pages, sizeof(struct pipe_buffer), GFP_KERNEL);
+       bufs = kcalloc(nr_pages, sizeof(*bufs), GFP_KERNEL | __GFP_NOWARN);
        if (unlikely(!bufs))
                return -ENOMEM;
 
index 8c344f037bd0195b8fad3a0630190cf32428883c..c602b8d20f06bf3aa09d97b6114b005671776582 100644 (file)
@@ -380,7 +380,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
 
        state = *get_task_state(task);
        vsize = eip = esp = 0;
-       permitted = ptrace_may_access(task, PTRACE_MODE_READ);
+       permitted = ptrace_may_access(task, PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT);
        mm = get_task_mm(task);
        if (mm) {
                vsize = task_vsize(mm);
@@ -464,7 +464,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
 
        seq_printf(m, "%d (%s) %c %d %d %d %d %d %u %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld %lu %lu %lu\n",
                pid_nr_ns(pid, ns),
                tcomm,
                state,
@@ -511,7 +511,10 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
                task->policy,
                (unsigned long long)delayacct_blkio_ticks(task),
                cputime_to_clock_t(gtime),
-               cputime_to_clock_t(cgtime));
+               cputime_to_clock_t(cgtime),
+               (mm && permitted) ? mm->start_data : 0,
+               (mm && permitted) ? mm->end_data : 0,
+               (mm && permitted) ? mm->start_brk : 0);
        if (mm)
                mmput(mm);
        return 0;
index 8173dfd89cb262ac506e64e475fa5c0cd9742c8e..9cde9edf9c4d40a4a3c20e3fb1c3758518092f98 100644 (file)
@@ -198,65 +198,7 @@ static int proc_root_link(struct dentry *dentry, struct path *path)
        return result;
 }
 
-static struct mm_struct *__check_mem_permission(struct task_struct *task)
-{
-       struct mm_struct *mm;
-
-       mm = get_task_mm(task);
-       if (!mm)
-               return ERR_PTR(-EINVAL);
-
-       /*
-        * A task can always look at itself, in case it chooses
-        * to use system calls instead of load instructions.
-        */
-       if (task == current)
-               return mm;
-
-       /*
-        * If current is actively ptrace'ing, and would also be
-        * permitted to freshly attach with ptrace now, permit it.
-        */
-       if (task_is_stopped_or_traced(task)) {
-               int match;
-               rcu_read_lock();
-               match = (ptrace_parent(task) == current);
-               rcu_read_unlock();
-               if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH))
-                       return mm;
-       }
-
-       /*
-        * No one else is allowed.
-        */
-       mmput(mm);
-       return ERR_PTR(-EPERM);
-}
-
-/*
- * If current may access user memory in @task return a reference to the
- * corresponding mm, otherwise ERR_PTR.
- */
-static struct mm_struct *check_mem_permission(struct task_struct *task)
-{
-       struct mm_struct *mm;
-       int err;
-
-       /*
-        * Avoid racing if task exec's as we might get a new mm but validate
-        * against old credentials.
-        */
-       err = mutex_lock_killable(&task->signal->cred_guard_mutex);
-       if (err)
-               return ERR_PTR(err);
-
-       mm = __check_mem_permission(task);
-       mutex_unlock(&task->signal->cred_guard_mutex);
-
-       return mm;
-}
-
-struct mm_struct *mm_for_maps(struct task_struct *task)
+static struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
 {
        struct mm_struct *mm;
        int err;
@@ -267,7 +209,7 @@ struct mm_struct *mm_for_maps(struct task_struct *task)
 
        mm = get_task_mm(task);
        if (mm && mm != current->mm &&
-                       !ptrace_may_access(task, PTRACE_MODE_READ)) {
+                       !ptrace_may_access(task, mode)) {
                mmput(mm);
                mm = ERR_PTR(-EACCES);
        }
@@ -276,6 +218,11 @@ struct mm_struct *mm_for_maps(struct task_struct *task)
        return mm;
 }
 
+struct mm_struct *mm_for_maps(struct task_struct *task)
+{
+       return mm_access(task, PTRACE_MODE_READ);
+}
+
 static int proc_pid_cmdline(struct task_struct *task, char * buffer)
 {
        int res = 0;
@@ -654,6 +601,8 @@ static int proc_pid_permission(struct inode *inode, int mask)
        bool has_perms;
 
        task = get_proc_task(inode);
+       if (!task)
+               return -ESRCH;
        has_perms = has_pid_permissions(pid, task, 1);
        put_task_struct(task);
 
@@ -750,38 +699,39 @@ static const struct file_operations proc_single_file_operations = {
 
 static int mem_open(struct inode* inode, struct file* file)
 {
-       file->private_data = (void*)((long)current->self_exec_id);
+       struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
+       struct mm_struct *mm;
+
+       if (!task)
+               return -ESRCH;
+
+       mm = mm_access(task, PTRACE_MODE_ATTACH);
+       put_task_struct(task);
+
+       if (IS_ERR(mm))
+               return PTR_ERR(mm);
+
        /* OK to pass negative loff_t, we can catch out-of-range */
        file->f_mode |= FMODE_UNSIGNED_OFFSET;
+       file->private_data = mm;
+
        return 0;
 }
 
 static ssize_t mem_read(struct file * file, char __user * buf,
                        size_t count, loff_t *ppos)
 {
-       struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
+       int ret;
        char *page;
        unsigned long src = *ppos;
-       int ret = -ESRCH;
-       struct mm_struct *mm;
+       struct mm_struct *mm = file->private_data;
 
-       if (!task)
-               goto out_no_task;
+       if (!mm)
+               return 0;
 
-       ret = -ENOMEM;
        page = (char *)__get_free_page(GFP_TEMPORARY);
        if (!page)
-               goto out;
-
-       mm = check_mem_permission(task);
-       ret = PTR_ERR(mm);
-       if (IS_ERR(mm))
-               goto out_free;
-
-       ret = -EIO;
-       if (file->private_data != (void*)((long)current->self_exec_id))
-               goto out_put;
+               return -ENOMEM;
 
        ret = 0;
  
@@ -808,13 +758,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
        }
        *ppos = src;
 
-out_put:
-       mmput(mm);
-out_free:
        free_page((unsigned long) page);
-out:
-       put_task_struct(task);
-out_no_task:
        return ret;
 }
 
@@ -823,27 +767,15 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
 {
        int copied;
        char *page;
-       struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
        unsigned long dst = *ppos;
-       struct mm_struct *mm;
+       struct mm_struct *mm = file->private_data;
 
-       copied = -ESRCH;
-       if (!task)
-               goto out_no_task;
+       if (!mm)
+               return 0;
 
-       copied = -ENOMEM;
        page = (char *)__get_free_page(GFP_TEMPORARY);
        if (!page)
-               goto out_task;
-
-       mm = check_mem_permission(task);
-       copied = PTR_ERR(mm);
-       if (IS_ERR(mm))
-               goto out_free;
-
-       copied = -EIO;
-       if (file->private_data != (void *)((long)current->self_exec_id))
-               goto out_mm;
+               return -ENOMEM;
 
        copied = 0;
        while (count > 0) {
@@ -867,13 +799,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
        }
        *ppos = dst;
 
-out_mm:
-       mmput(mm);
-out_free:
        free_page((unsigned long) page);
-out_task:
-       put_task_struct(task);
-out_no_task:
        return copied;
 }
 
@@ -893,11 +819,20 @@ loff_t mem_lseek(struct file *file, loff_t offset, int orig)
        return file->f_pos;
 }
 
+static int mem_release(struct inode *inode, struct file *file)
+{
+       struct mm_struct *mm = file->private_data;
+
+       mmput(mm);
+       return 0;
+}
+
 static const struct file_operations proc_mem_operations = {
        .llseek         = mem_lseek,
        .read           = mem_read,
        .write          = mem_write,
        .open           = mem_open,
+       .release        = mem_release,
 };
 
 static ssize_t environ_read(struct file *file, char __user *buf,
@@ -1197,9 +1132,6 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
        ssize_t length;
        uid_t loginuid;
 
-       if (!capable(CAP_AUDIT_CONTROL))
-               return -EPERM;
-
        rcu_read_lock();
        if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) {
                rcu_read_unlock();
@@ -1228,7 +1160,7 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
                goto out_free_page;
 
        }
-       length = audit_set_loginuid(current, loginuid);
+       length = audit_set_loginuid(loginuid);
        if (likely(length == 0))
                length = count;
 
index d76ca6ae2b1b0bd91becd9a80b9a5480e2abb478..121f77cfef76ce0da7b96d8ae475db38943e4f8b 100644 (file)
@@ -77,6 +77,8 @@ static int show_stat(struct seq_file *p, void *v)
                steal += kcpustat_cpu(i).cpustat[CPUTIME_STEAL];
                guest += kcpustat_cpu(i).cpustat[CPUTIME_GUEST];
                guest_nice += kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE];
+               sum += kstat_cpu_irqs_sum(i);
+               sum += arch_irq_stat_cpu(i);
 
                for (j = 0; j < NR_SOFTIRQS; j++) {
                        unsigned int softirq_stat = kstat_softirqs_cpu(j, i);
index 2bfd987f4853407be1027ede89bc940460346bf8..6b009548d2e0380dbbbd8c061570f2805371bf4d 100644 (file)
@@ -179,47 +179,33 @@ static const char *qnx4_checkroot(struct super_block *sb)
        struct qnx4_inode_entry *rootdir;
        int rd, rl;
        int i, j;
-       int found = 0;
 
-       if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') {
+       if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/')
                return "no qnx4 filesystem (no root dir).";
-       } else {
-               QNX4DEBUG((KERN_NOTICE "QNX4 filesystem found on dev %s.\n", sb->s_id));
-               rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1;
-               rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size);
-               for (j = 0; j < rl; j++) {
-                       bh = sb_bread(sb, rd + j);      /* root dir, first block */
-                       if (bh == NULL) {
-                               return "unable to read root entry.";
-                       }
-                       for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) {
-                               rootdir = (struct qnx4_inode_entry *) (bh->b_data + i * QNX4_DIR_ENTRY_SIZE);
-                               if (rootdir->di_fname != NULL) {
-                                       QNX4DEBUG((KERN_INFO "rootdir entry found : [%s]\n", rootdir->di_fname));
-                                       if (!strcmp(rootdir->di_fname,
-                                                   QNX4_BMNAME)) {
-                                               found = 1;
-                                               qnx4_sb(sb)->BitMap = kmemdup(rootdir,
-                                                                             sizeof(struct qnx4_inode_entry),
-                                                                             GFP_KERNEL);
-                                               if (!qnx4_sb(sb)->BitMap) {
-                                                       brelse (bh);
-                                                       return "not enough memory for bitmap inode";
-                                               }/* keep bitmap inode known */
-                                               break;
-                                       }
-                               }
-                       }
+       QNX4DEBUG((KERN_NOTICE "QNX4 filesystem found on dev %s.\n", sb->s_id));
+       rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1;
+       rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size);
+       for (j = 0; j < rl; j++) {
+               bh = sb_bread(sb, rd + j);      /* root dir, first block */
+               if (bh == NULL)
+                       return "unable to read root entry.";
+               rootdir = (struct qnx4_inode_entry *) bh->b_data;
+               for (i = 0; i < QNX4_INODES_PER_BLOCK; i++, rootdir++) {
+                       QNX4DEBUG((KERN_INFO "rootdir entry found : [%s]\n", rootdir->di_fname));
+                       if (strcmp(rootdir->di_fname, QNX4_BMNAME) != 0)
+                               continue;
+                       qnx4_sb(sb)->BitMap = kmemdup(rootdir,
+                                                     sizeof(struct qnx4_inode_entry),
+                                                     GFP_KERNEL);
                        brelse(bh);
-                       if (found != 0) {
-                               break;
-                       }
-               }
-               if (found == 0) {
-                       return "bitmap file not found.";
+                       if (!qnx4_sb(sb)->BitMap)
+                               return "not enough memory for bitmap inode";
+                       /* keep bitmap inode known */
+                       return NULL;
                }
+               brelse(bh);
        }
-       return NULL;
+       return "bitmap file not found.";
 }
 
 static int qnx4_fill_super(struct super_block *s, void *data, int silent)
@@ -270,7 +256,7 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
        if (IS_ERR(root)) {
                printk(KERN_ERR "qnx4: get inode failed\n");
                ret = PTR_ERR(root);
-               goto out;
+               goto outb;
        }
 
        ret = -ENOMEM;
@@ -283,6 +269,8 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
 
       outi:
        iput(root);
+      outb:
+       kfree(qs->BitMap);
       out:
        brelse(bh);
       outnobh:
index f744be98cd5abc8dd6d93cf4a699981491f8e811..af0b738025929b1c18ac884734131ea5e843e40c 100644 (file)
@@ -70,11 +70,15 @@ struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb,
        spin_lock(&cache->lock);
 
        while (1) {
-               for (i = 0; i < cache->entries; i++)
-                       if (cache->entry[i].block == block)
+               for (i = cache->curr_blk, n = 0; n < cache->entries; n++) {
+                       if (cache->entry[i].block == block) {
+                               cache->curr_blk = i;
                                break;
+                       }
+                       i = (i + 1) % cache->entries;
+               }
 
-               if (i == cache->entries) {
+               if (n == cache->entries) {
                        /*
                         * Block not in cache, if all cache entries are used
                         * go to sleep waiting for one to become available.
@@ -245,6 +249,7 @@ struct squashfs_cache *squashfs_cache_init(char *name, int entries,
                goto cleanup;
        }
 
+       cache->curr_blk = 0;
        cache->next_blk = 0;
        cache->unused = entries;
        cache->entries = entries;
@@ -332,17 +337,20 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer,
                u64 *block, int *offset, int length)
 {
        struct squashfs_sb_info *msblk = sb->s_fs_info;
-       int bytes, copied = length;
+       int bytes, res = length;
        struct squashfs_cache_entry *entry;
 
        TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset);
 
        while (length) {
                entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0);
-               if (entry->error)
-                       return entry->error;
-               else if (*offset >= entry->length)
-                       return -EIO;
+               if (entry->error) {
+                       res = entry->error;
+                       goto error;
+               } else if (*offset >= entry->length) {
+                       res = -EIO;
+                       goto error;
+               }
 
                bytes = squashfs_copy_data(buffer, entry, *offset, length);
                if (buffer)
@@ -358,7 +366,11 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer,
                squashfs_cache_put(entry);
        }
 
-       return copied;
+       return res;
+
+error:
+       squashfs_cache_put(entry);
+       return res;
 }
 
 
index fd7b3b3bda136fa720c75421b3551815417affd7..81afbccfa8432ba49a644a16c2c0a0526da31ea5 100644 (file)
@@ -208,8 +208,8 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                inode->i_op = &squashfs_inode_ops;
                inode->i_fop = &generic_ro_fops;
                inode->i_mode |= S_IFREG;
-               inode->i_blocks = ((inode->i_size -
-                               le64_to_cpu(sqsh_ino->sparse) - 1) >> 9) + 1;
+               inode->i_blocks = (inode->i_size -
+                               le64_to_cpu(sqsh_ino->sparse) + 511) >> 9;
 
                squashfs_i(inode)->fragment_block = frag_blk;
                squashfs_i(inode)->fragment_size = frag_size;
index 651f0b31d2966318bfd5ec7ce6ee4bd152486c8e..52934a22f29665a00f082b24aa57ce915e875913 100644 (file)
@@ -28,6 +28,7 @@
 struct squashfs_cache {
        char                    *name;
        int                     entries;
+       int                     curr_blk;
        int                     next_blk;
        int                     num_waiters;
        int                     unused;
index d0858c2d9a47f7d4d38f131b14a1be7bf4c5f406..ecaa2f7bdb8f16ebac1a00896cc9d1a870351788 100644 (file)
@@ -290,7 +290,7 @@ handle_fragments:
 
 check_directory_table:
        /* Sanity check directory_table */
-       if (msblk->directory_table >= next_table) {
+       if (msblk->directory_table > next_table) {
                err = -EINVAL;
                goto failed_mount;
        }
index de41e1e46f0970b3c262fb577e0b6f332c6a59e5..6015c02296b7ad2adba75c7946b8fb4762a62265 100644 (file)
@@ -1186,6 +1186,8 @@ int freeze_super(struct super_block *sb)
                        printk(KERN_ERR
                                "VFS:Filesystem freeze failed\n");
                        sb->s_frozen = SB_UNFROZEN;
+                       smp_wmb();
+                       wake_up(&sb->s_wait_unfrozen);
                        deactivate_locked_super(sb);
                        return ret;
                }
index b09ba2dd8b625efc12130e7a20572560072d8b3b..f922cbacdb96e3e6f4f238cf7360079162452147 100644 (file)
@@ -38,9 +38,6 @@
 
 DEFINE_SPINLOCK(dbg_lock);
 
-static char dbg_key_buf0[128];
-static char dbg_key_buf1[128];
-
 static const char *get_key_fmt(int fmt)
 {
        switch (fmt) {
@@ -103,8 +100,8 @@ static const char *get_dent_type(int type)
        }
 }
 
-static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
-                       char *buffer)
+const char *dbg_snprintf_key(const struct ubifs_info *c,
+                            const union ubifs_key *key, char *buffer, int len)
 {
        char *p = buffer;
        int type = key_type(c, key);
@@ -112,45 +109,34 @@ static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
        if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) {
                switch (type) {
                case UBIFS_INO_KEY:
-                       sprintf(p, "(%lu, %s)", (unsigned long)key_inum(c, key),
-                              get_key_type(type));
+                       len -= snprintf(p, len, "(%lu, %s)",
+                                       (unsigned long)key_inum(c, key),
+                                       get_key_type(type));
                        break;
                case UBIFS_DENT_KEY:
                case UBIFS_XENT_KEY:
-                       sprintf(p, "(%lu, %s, %#08x)",
-                               (unsigned long)key_inum(c, key),
-                               get_key_type(type), key_hash(c, key));
+                       len -= snprintf(p, len, "(%lu, %s, %#08x)",
+                                       (unsigned long)key_inum(c, key),
+                                       get_key_type(type), key_hash(c, key));
                        break;
                case UBIFS_DATA_KEY:
-                       sprintf(p, "(%lu, %s, %u)",
-                               (unsigned long)key_inum(c, key),
-                               get_key_type(type), key_block(c, key));
+                       len -= snprintf(p, len, "(%lu, %s, %u)",
+                                       (unsigned long)key_inum(c, key),
+                                       get_key_type(type), key_block(c, key));
                        break;
                case UBIFS_TRUN_KEY:
-                       sprintf(p, "(%lu, %s)",
-                               (unsigned long)key_inum(c, key),
-                               get_key_type(type));
+                       len -= snprintf(p, len, "(%lu, %s)",
+                                       (unsigned long)key_inum(c, key),
+                                       get_key_type(type));
                        break;
                default:
-                       sprintf(p, "(bad key type: %#08x, %#08x)",
-                               key->u32[0], key->u32[1]);
+                       len -= snprintf(p, len, "(bad key type: %#08x, %#08x)",
+                                       key->u32[0], key->u32[1]);
                }
        } else
-               sprintf(p, "bad key format %d", c->key_fmt);
-}
-
-const char *dbg_key_str0(const struct ubifs_info *c, const union ubifs_key *key)
-{
-       /* dbg_lock must be held */
-       sprintf_key(c, key, dbg_key_buf0);
-       return dbg_key_buf0;
-}
-
-const char *dbg_key_str1(const struct ubifs_info *c, const union ubifs_key *key)
-{
-       /* dbg_lock must be held */
-       sprintf_key(c, key, dbg_key_buf1);
-       return dbg_key_buf1;
+               len -= snprintf(p, len, "bad key format %d", c->key_fmt);
+       ubifs_assert(len > 0);
+       return p;
 }
 
 const char *dbg_ntype(int type)
@@ -319,6 +305,7 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
        int i, n;
        union ubifs_key key;
        const struct ubifs_ch *ch = node;
+       char key_buf[DBG_KEY_BUF_LEN];
 
        if (dbg_is_tst_rcvry(c))
                return;
@@ -474,7 +461,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                const struct ubifs_ino_node *ino = node;
 
                key_read(c, &ino->key, &key);
-               printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+               printk(KERN_DEBUG "\tkey            %s\n",
+                      dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
                printk(KERN_DEBUG "\tcreat_sqnum    %llu\n",
                       (unsigned long long)le64_to_cpu(ino->creat_sqnum));
                printk(KERN_DEBUG "\tsize           %llu\n",
@@ -517,7 +505,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                int nlen = le16_to_cpu(dent->nlen);
 
                key_read(c, &dent->key, &key);
-               printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+               printk(KERN_DEBUG "\tkey            %s\n",
+                      dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
                printk(KERN_DEBUG "\tinum           %llu\n",
                       (unsigned long long)le64_to_cpu(dent->inum));
                printk(KERN_DEBUG "\ttype           %d\n", (int)dent->type);
@@ -541,7 +530,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
 
                key_read(c, &dn->key, &key);
-               printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+               printk(KERN_DEBUG "\tkey            %s\n",
+                      dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
                printk(KERN_DEBUG "\tsize           %u\n",
                       le32_to_cpu(dn->size));
                printk(KERN_DEBUG "\tcompr_typ      %d\n",
@@ -582,7 +572,9 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                        key_read(c, &br->key, &key);
                        printk(KERN_DEBUG "\t%d: LEB %d:%d len %d key %s\n",
                               i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs),
-                              le32_to_cpu(br->len), DBGKEY(&key));
+                              le32_to_cpu(br->len),
+                              dbg_snprintf_key(c, &key, key_buf,
+                                               DBG_KEY_BUF_LEN));
                }
                break;
        }
@@ -934,6 +926,7 @@ void dbg_dump_znode(const struct ubifs_info *c,
 {
        int n;
        const struct ubifs_zbranch *zbr;
+       char key_buf[DBG_KEY_BUF_LEN];
 
        spin_lock(&dbg_lock);
        if (znode->parent)
@@ -958,12 +951,16 @@ void dbg_dump_znode(const struct ubifs_info *c,
                        printk(KERN_DEBUG "\t%d: znode %p LEB %d:%d len %d key "
                                          "%s\n", n, zbr->znode, zbr->lnum,
                                          zbr->offs, zbr->len,
-                                         DBGKEY(&zbr->key));
+                                         dbg_snprintf_key(c, &zbr->key,
+                                                          key_buf,
+                                                          DBG_KEY_BUF_LEN));
                else
                        printk(KERN_DEBUG "\t%d: LNC %p LEB %d:%d len %d key "
                                          "%s\n", n, zbr->znode, zbr->lnum,
                                          zbr->offs, zbr->len,
-                                         DBGKEY(&zbr->key));
+                                         dbg_snprintf_key(c, &zbr->key,
+                                                          key_buf,
+                                                          DBG_KEY_BUF_LEN));
        }
        spin_unlock(&dbg_lock);
 }
@@ -1260,6 +1257,7 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
        int err, nlen1, nlen2, cmp;
        struct ubifs_dent_node *dent1, *dent2;
        union ubifs_key key;
+       char key_buf[DBG_KEY_BUF_LEN];
 
        ubifs_assert(!keys_cmp(c, &zbr1->key, &zbr2->key));
        dent1 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
@@ -1290,9 +1288,11 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
        key_read(c, &dent1->key, &key);
        if (keys_cmp(c, &zbr1->key, &key)) {
                dbg_err("1st entry at %d:%d has key %s", zbr1->lnum,
-                       zbr1->offs, DBGKEY(&key));
+                       zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
+                                                    DBG_KEY_BUF_LEN));
                dbg_err("but it should have key %s according to tnc",
-                       DBGKEY(&zbr1->key));
+                       dbg_snprintf_key(c, &zbr1->key, key_buf,
+                                        DBG_KEY_BUF_LEN));
                dbg_dump_node(c, dent1);
                goto out_free;
        }
@@ -1300,9 +1300,11 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
        key_read(c, &dent2->key, &key);
        if (keys_cmp(c, &zbr2->key, &key)) {
                dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum,
-                       zbr1->offs, DBGKEY(&key));
+                       zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
+                                                    DBG_KEY_BUF_LEN));
                dbg_err("but it should have key %s according to tnc",
-                       DBGKEY(&zbr2->key));
+                       dbg_snprintf_key(c, &zbr2->key, key_buf,
+                                        DBG_KEY_BUF_LEN));
                dbg_dump_node(c, dent2);
                goto out_free;
        }
@@ -1319,7 +1321,7 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
                dbg_err("2 xent/dent nodes with the same name");
        else
                dbg_err("bad order of colliding key %s",
-                       DBGKEY(&key));
+                       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
 
        ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
        dbg_dump_node(c, dent1);
index 8d9c46810189a1db050d047a11b521c8fe145dba..ad1a6fee6010ba9d17c9e2e0e8616734a9960b04 100644 (file)
@@ -169,40 +169,39 @@ struct ubifs_global_debug_info {
        spin_unlock(&dbg_lock);                                                \
 } while (0)
 
-const char *dbg_key_str0(const struct ubifs_info *c,
-                        const union ubifs_key *key);
-const char *dbg_key_str1(const struct ubifs_info *c,
-                        const union ubifs_key *key);
-
-/*
- * DBGKEY macros require @dbg_lock to be held, which it is in the dbg message
- * macros.
- */
-#define DBGKEY(key) dbg_key_str0(c, (key))
-#define DBGKEY1(key) dbg_key_str1(c, (key))
-
-extern spinlock_t dbg_lock;
-
-#define ubifs_dbg_msg(type, fmt, ...) do {                        \
-       spin_lock(&dbg_lock);                                     \
-       pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \
-       spin_unlock(&dbg_lock);                                   \
+#define ubifs_dbg_msg(type, fmt, ...) \
+       pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__)
+
+#define DBG_KEY_BUF_LEN 32
+#define ubifs_dbg_msg_key(type, key, fmt, ...) do {                            \
+       char __tmp_key_buf[DBG_KEY_BUF_LEN];                                   \
+       pr_debug("UBIFS DBG " type ": " fmt "%s\n", ##__VA_ARGS__,             \
+                dbg_snprintf_key(c, key, __tmp_key_buf, DBG_KEY_BUF_LEN));    \
 } while (0)
 
 /* Just a debugging messages not related to any specific UBIFS subsystem */
-#define dbg_msg(fmt, ...)   ubifs_dbg_msg("msg", fmt, ##__VA_ARGS__)
+#define dbg_msg(fmt, ...)                                                      \
+       printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid,   \
+              __func__, ##__VA_ARGS__)
+
 /* General messages */
 #define dbg_gen(fmt, ...)   ubifs_dbg_msg("gen", fmt, ##__VA_ARGS__)
 /* Additional journal messages */
 #define dbg_jnl(fmt, ...)   ubifs_dbg_msg("jnl", fmt, ##__VA_ARGS__)
+#define dbg_jnlk(key, fmt, ...) \
+       ubifs_dbg_msg_key("jnl", key, fmt, ##__VA_ARGS__)
 /* Additional TNC messages */
 #define dbg_tnc(fmt, ...)   ubifs_dbg_msg("tnc", fmt, ##__VA_ARGS__)
+#define dbg_tnck(key, fmt, ...) \
+       ubifs_dbg_msg_key("tnc", key, fmt, ##__VA_ARGS__)
 /* Additional lprops messages */
 #define dbg_lp(fmt, ...)    ubifs_dbg_msg("lp", fmt, ##__VA_ARGS__)
 /* Additional LEB find messages */
 #define dbg_find(fmt, ...)  ubifs_dbg_msg("find", fmt, ##__VA_ARGS__)
 /* Additional mount messages */
 #define dbg_mnt(fmt, ...)   ubifs_dbg_msg("mnt", fmt, ##__VA_ARGS__)
+#define dbg_mntk(key, fmt, ...) \
+       ubifs_dbg_msg_key("mnt", key, fmt, ##__VA_ARGS__)
 /* Additional I/O messages */
 #define dbg_io(fmt, ...)    ubifs_dbg_msg("io", fmt, ##__VA_ARGS__)
 /* Additional commit messages */
@@ -218,6 +217,7 @@ extern spinlock_t dbg_lock;
 /* Additional recovery messages */
 #define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
 
+extern spinlock_t dbg_lock;
 extern struct ubifs_global_debug_info ubifs_dbg;
 
 static inline int dbg_is_chk_gen(const struct ubifs_info *c)
@@ -258,6 +258,8 @@ const char *dbg_cstate(int cmt_state);
 const char *dbg_jhead(int jhead);
 const char *dbg_get_key_dump(const struct ubifs_info *c,
                             const union ubifs_key *key);
+const char *dbg_snprintf_key(const struct ubifs_info *c,
+                            const union ubifs_key *key, char *buffer, int len);
 void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode);
 void dbg_dump_node(const struct ubifs_info *c, const void *node);
 void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
@@ -345,20 +347,23 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
 #define dbg_dump_stack()
 #define ubifs_assert_cmt_locked(c)
 
-#define dbg_msg(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_gen(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_jnl(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_tnc(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_lp(fmt, ...)    ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_find(fmt, ...)  ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_mnt(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_io(fmt, ...)    ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_cmt(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_budg(fmt, ...)  ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_log(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_gc(fmt, ...)    ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_scan(fmt, ...)  ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_rcvry(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_msg(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_gen(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_jnl(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_jnlk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_tnc(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_tnck(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_lp(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_find(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_mnt(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_mntk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_io(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_cmt(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_budg(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_log(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_gc(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_scan(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_rcvry(fmt, ...)     ubifs_dbg_msg(fmt, ##__VA_ARGS__)
 
 static inline int ubifs_debugging_init(struct ubifs_info *c)      { return 0; }
 static inline void ubifs_debugging_exit(struct ubifs_info *c)     { return; }
@@ -368,6 +373,10 @@ static inline const char *dbg_jhead(int jhead)                    { return ""; }
 static inline const char *
 dbg_get_key_dump(const struct ubifs_info *c,
                 const union ubifs_key *key)                      { return ""; }
+static inline const char *
+dbg_snprintf_key(const struct ubifs_info *c,
+                const union ubifs_key *key, char *buffer,
+                int len)                                         { return ""; }
 static inline void dbg_dump_inode(struct ubifs_info *c,
                                  const struct inode *inode)      { return; }
 static inline void dbg_dump_node(const struct ubifs_info *c,
index cef0460f4c54651bbe5c432d8fc4e3307ee45d07..2f438ab2e7a2730f2dfff7498ad8c3301f425479 100644 (file)
@@ -697,9 +697,8 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
        int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
        struct ubifs_inode *ui = ubifs_inode(inode);
 
-       dbg_jnl("ino %lu, blk %u, len %d, key %s",
-               (unsigned long)key_inum(c, key), key_block(c, key), len,
-               DBGKEY(key));
+       dbg_jnlk(key, "ino %lu, blk %u, len %d, key ",
+               (unsigned long)key_inum(c, key), key_block(c, key), len);
        ubifs_assert(len <= UBIFS_BLOCK_SIZE);
 
        data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN);
@@ -1177,7 +1176,7 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
                dn = (void *)trun + UBIFS_TRUN_NODE_SZ;
                blk = new_size >> UBIFS_BLOCK_SHIFT;
                data_key_init(c, &key, inum, blk);
-               dbg_jnl("last block key %s", DBGKEY(&key));
+               dbg_jnlk(&key, "last block key ");
                err = ubifs_tnc_lookup(c, &key, dn);
                if (err == -ENOENT)
                        dlen = 0; /* Not found (so it is a hole) */
index ccabaf1164b333a1fd276a2fff5beabdaa0bda1d..b007637f040662b836d98e15ec9143ad5c05cf3f 100644 (file)
@@ -221,8 +221,8 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
 {
        int err;
 
-       dbg_mnt("LEB %d:%d len %d deletion %d sqnum %llu %s", r->lnum,
-               r->offs, r->len, r->deletion, r->sqnum, DBGKEY(&r->key));
+       dbg_mntk(&r->key, "LEB %d:%d len %d deletion %d sqnum %llu key ",
+                r->lnum, r->offs, r->len, r->deletion, r->sqnum);
 
        /* Set c->replay_sqnum to help deal with dangling branches. */
        c->replay_sqnum = r->sqnum;
@@ -361,7 +361,7 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
 {
        struct replay_entry *r;
 
-       dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+       dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs);
 
        if (key_inum(c, key) >= c->highest_inum)
                c->highest_inum = key_inum(c, key);
@@ -409,7 +409,7 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
        struct replay_entry *r;
        char *nbuf;
 
-       dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+       dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs);
        if (key_inum(c, key) >= c->highest_inum)
                c->highest_inum = key_inum(c, key);
 
index e14ee53159db36b0ecade9b31ad6466678db6b74..16ad84d8402f31a5729f86c3b15f20a129f49efd 100644 (file)
@@ -505,7 +505,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
 {
        int ret;
 
-       dbg_tnc("LEB %d:%d, key %s", zbr->lnum, zbr->offs, DBGKEY(key));
+       dbg_tnck(key, "LEB %d:%d, key ", zbr->lnum, zbr->offs);
 
        ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum,
                            zbr->offs);
@@ -519,8 +519,8 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
                        ret = 0;
        }
        if (ret == 0 && c->replaying)
-               dbg_mnt("dangling branch LEB %d:%d len %d, key %s",
-                       zbr->lnum, zbr->offs, zbr->len, DBGKEY(key));
+               dbg_mntk(key, "dangling branch LEB %d:%d len %d, key ",
+                       zbr->lnum, zbr->offs, zbr->len);
        return ret;
 }
 
@@ -995,9 +995,9 @@ static int fallible_resolve_collision(struct ubifs_info *c,
        if (adding || !o_znode)
                return 0;
 
-       dbg_mnt("dangling match LEB %d:%d len %d %s",
+       dbg_mntk(key, "dangling match LEB %d:%d len %d key ",
                o_znode->zbranch[o_n].lnum, o_znode->zbranch[o_n].offs,
-               o_znode->zbranch[o_n].len, DBGKEY(key));
+               o_znode->zbranch[o_n].len);
        *zn = o_znode;
        *n = o_n;
        return 1;
@@ -1179,7 +1179,7 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
        struct ubifs_znode *znode;
        unsigned long time = get_seconds();
 
-       dbg_tnc("search key %s", DBGKEY(key));
+       dbg_tnck(key, "search key ");
        ubifs_assert(key_type(c, key) < UBIFS_INVALID_KEY);
 
        znode = c->zroot.znode;
@@ -1315,7 +1315,7 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
        struct ubifs_znode *znode;
        unsigned long time = get_seconds();
 
-       dbg_tnc("search and dirty key %s", DBGKEY(key));
+       dbg_tnck(key, "search and dirty key ");
 
        znode = c->zroot.znode;
        if (unlikely(!znode)) {
@@ -1722,8 +1722,8 @@ static int validate_data_node(struct ubifs_info *c, void *buf,
        if (!keys_eq(c, &zbr->key, &key1)) {
                ubifs_err("bad key in node at LEB %d:%d",
                          zbr->lnum, zbr->offs);
-               dbg_tnc("looked for key %s found node's key %s",
-                       DBGKEY(&zbr->key), DBGKEY1(&key1));
+               dbg_tnck(&zbr->key, "looked for key ");
+               dbg_tnck(&key1, "found node's key ");
                goto out_err;
        }
 
@@ -1776,7 +1776,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
                ubifs_err("failed to read from LEB %d:%d, error %d",
                          lnum, offs, err);
                dbg_dump_stack();
-               dbg_tnc("key %s", DBGKEY(&bu->key));
+               dbg_tnck(&bu->key, "key ");
                return err;
        }
 
@@ -1811,7 +1811,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
        int found, n, err;
        struct ubifs_znode *znode;
 
-       dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key));
+       dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
        mutex_lock(&c->tnc_mutex);
        found = ubifs_lookup_level0(c, key, &znode, &n);
        if (!found) {
@@ -1985,8 +1985,7 @@ again:
        zp = znode->parent;
        if (znode->child_cnt < c->fanout) {
                ubifs_assert(n != c->fanout);
-               dbg_tnc("inserted at %d level %d, key %s", n, znode->level,
-                       DBGKEY(key));
+               dbg_tnck(key, "inserted at %d level %d, key ", n, znode->level);
 
                insert_zbranch(znode, zbr, n);
 
@@ -2001,7 +2000,7 @@ again:
         * Unfortunately, @znode does not have more empty slots and we have to
         * split it.
         */
-       dbg_tnc("splitting level %d, key %s", znode->level, DBGKEY(key));
+       dbg_tnck(key, "splitting level %d, key ", znode->level);
 
        if (znode->alt)
                /*
@@ -2095,7 +2094,7 @@ do_split:
        }
 
        /* Insert new key and branch */
-       dbg_tnc("inserting at %d level %d, key %s", n, zn->level, DBGKEY(key));
+       dbg_tnck(key, "inserting at %d level %d, key ", n, zn->level);
 
        insert_zbranch(zi, zbr, n);
 
@@ -2171,7 +2170,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       dbg_tnc("%d:%d, len %d, key %s", lnum, offs, len, DBGKEY(key));
+       dbg_tnck(key, "%d:%d, len %d, key ", lnum, offs, len);
        found = lookup_level0_dirty(c, key, &znode, &n);
        if (!found) {
                struct ubifs_zbranch zbr;
@@ -2220,8 +2219,8 @@ int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       dbg_tnc("old LEB %d:%d, new LEB %d:%d, len %d, key %s", old_lnum,
-               old_offs, lnum, offs, len, DBGKEY(key));
+       dbg_tnck(key, "old LEB %d:%d, new LEB %d:%d, len %d, key ", old_lnum,
+                old_offs, lnum, offs, len);
        found = lookup_level0_dirty(c, key, &znode, &n);
        if (found < 0) {
                err = found;
@@ -2303,8 +2302,8 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       dbg_tnc("LEB %d:%d, name '%.*s', key %s", lnum, offs, nm->len, nm->name,
-               DBGKEY(key));
+       dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
+                lnum, offs, nm->len, nm->name);
        found = lookup_level0_dirty(c, key, &znode, &n);
        if (found < 0) {
                err = found;
@@ -2397,7 +2396,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
        /* Delete without merge for now */
        ubifs_assert(znode->level == 0);
        ubifs_assert(n >= 0 && n < c->fanout);
-       dbg_tnc("deleting %s", DBGKEY(&znode->zbranch[n].key));
+       dbg_tnck(&znode->zbranch[n].key, "deleting key ");
 
        zbr = &znode->zbranch[n];
        lnc_free(zbr);
@@ -2507,7 +2506,7 @@ int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key)
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       dbg_tnc("key %s", DBGKEY(key));
+       dbg_tnck(key, "key ");
        found = lookup_level0_dirty(c, key, &znode, &n);
        if (found < 0) {
                err = found;
@@ -2538,7 +2537,7 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       dbg_tnc("%.*s, key %s", nm->len, nm->name, DBGKEY(key));
+       dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
        err = lookup_level0_dirty(c, key, &znode, &n);
        if (err < 0)
                goto out_unlock;
@@ -2653,7 +2652,7 @@ int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
                                dbg_dump_znode(c, znode);
                                goto out_unlock;
                        }
-                       dbg_tnc("removing %s", DBGKEY(key));
+                       dbg_tnck(key, "removing key ");
                }
                if (k) {
                        for (i = n + 1 + k; i < znode->child_cnt; i++)
@@ -2773,7 +2772,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
        struct ubifs_zbranch *zbr;
        union ubifs_key *dkey;
 
-       dbg_tnc("%s %s", nm->name ? (char *)nm->name : "(lowest)", DBGKEY(key));
+       dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
        ubifs_assert(is_hash_key(c, key));
 
        mutex_lock(&c->tnc_mutex);
@@ -3332,9 +3331,9 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
 
 out_dump:
        block = key_block(c, key);
-       ubifs_err("inode %lu has size %lld, but there are data at offset %lld "
-                 "(data key %s)", (unsigned long)inode->i_ino, size,
-                 ((loff_t)block) << UBIFS_BLOCK_SHIFT, DBGKEY(key));
+       ubifs_err("inode %lu has size %lld, but there are data at offset %lld",
+                 (unsigned long)inode->i_ino, size,
+                 ((loff_t)block) << UBIFS_BLOCK_SHIFT);
        mutex_unlock(&c->tnc_mutex);
        dbg_dump_inode(c, inode);
        dbg_dump_stack();
index b48db999903e6d34b40c5066a9f30844723b70f8..dc28fe6ec07a31bff2471bd731ed828363f85062 100644 (file)
@@ -328,8 +328,8 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
                case UBIFS_XENT_KEY:
                        break;
                default:
-                       dbg_msg("bad key type at slot %d: %s", i,
-                               DBGKEY(&zbr->key));
+                       dbg_msg("bad key type at slot %d: %d",
+                               i, key_type(c, &zbr->key));
                        err = 3;
                        goto out_dump;
                }
@@ -475,7 +475,7 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
                                      zbr->offs);
 
        if (err) {
-               dbg_tnc("key %s", DBGKEY(key));
+               dbg_tnck(key, "key ");
                return err;
        }
 
@@ -484,8 +484,8 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
        if (!keys_eq(c, key, &key1)) {
                ubifs_err("bad key in node at LEB %d:%d",
                          zbr->lnum, zbr->offs);
-               dbg_tnc("looked for key %s found node's key %s",
-                       DBGKEY(key), DBGKEY1(&key1));
+               dbg_tnck(key, "looked for key ");
+               dbg_tnck(&key1, "but found node's key ");
                dbg_dump_node(c, node);
                return -EINVAL;
        }
index 574d4ee9b6253ea3d589f23288aa7385907642bb..74b9baf36ac39038f827c8e262ea62aa33d81de8 100644 (file)
@@ -111,8 +111,7 @@ xfs_ioend_new_eof(
        xfs_fsize_t             bsize;
 
        bsize = ioend->io_offset + ioend->io_size;
-       isize = MAX(ip->i_size, ip->i_new_size);
-       isize = MIN(isize, bsize);
+       isize = MIN(i_size_read(VFS_I(ip)), bsize);
        return isize > ip->i_d.di_size ? isize : 0;
 }
 
@@ -126,11 +125,7 @@ static inline bool xfs_ioend_is_append(struct xfs_ioend *ioend)
 }
 
 /*
- * Update on-disk file size now that data has been written to disk.  The
- * current in-memory file size is i_size.  If a write is beyond eof i_new_size
- * will be the intended file size until i_size is updated.  If this write does
- * not extend all the way to the valid file size then restrict this update to
- * the end of the write.
+ * Update on-disk file size now that data has been written to disk.
  *
  * This function does not block as blocking on the inode lock in IO completion
  * can lead to IO completion order dependency deadlocks.. If it can't get the
@@ -1278,6 +1273,15 @@ xfs_end_io_direct_write(
 {
        struct xfs_ioend        *ioend = iocb->private;
 
+       /*
+        * While the generic direct I/O code updates the inode size, it does
+        * so only after the end_io handler is called, which means our
+        * end_io handler thinks the on-disk size is outside the in-core
+        * size.  To prevent this just update it a little bit earlier here.
+        */
+       if (offset + size > i_size_read(ioend->io_inode))
+               i_size_write(ioend->io_inode, offset + size);
+
        /*
         * blockdev_direct_IO can return an error even after the I/O
         * completion handler was called.  Thus we need to protect
@@ -1340,12 +1344,11 @@ xfs_vm_write_failed(
 
        if (to > inode->i_size) {
                /*
-                * punch out the delalloc blocks we have already allocated. We
-                * don't call xfs_setattr() to do this as we may be in the
-                * middle of a multi-iovec write and so the vfs inode->i_size
-                * will not match the xfs ip->i_size and so it will zero too
-                * much. Hence we jus truncate the page cache to zero what is
-                * necessary and punch the delalloc blocks directly.
+                * Punch out the delalloc blocks we have already allocated.
+                *
+                * Don't bother with xfs_setattr given that nothing can have
+                * made it to disk yet as the page is still locked at this
+                * point.
                 */
                struct xfs_inode        *ip = XFS_I(inode);
                xfs_fileoff_t           start_fsb;
index 1e5d97f86ea819493b9acfd1584696fc7ce5d733..08b9ac644c3140f6f6cc007f6f3eab05331ff35b 100644 (file)
@@ -827,10 +827,6 @@ xfs_attr_inactive(xfs_inode_t *dp)
        if (error)
                goto out;
 
-       /*
-        * Commit the last in the sequence of transactions.
-        */
-       xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE);
        error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES);
        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 
index c1b55e5965517a9407f678610b62f29fdabf33b3..d25eafd4d28de31d326078dbfdc21140c69b5acb 100644 (file)
@@ -271,10 +271,6 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
        dp = args->dp;
        mp = dp->i_mount;
        dp->i_d.di_forkoff = forkoff;
-       dp->i_df.if_ext_max =
-               XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
-       dp->i_afp->if_ext_max =
-               XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
 
        ifp = dp->i_afp;
        ASSERT(ifp->if_flags & XFS_IFINLINE);
@@ -326,7 +322,6 @@ xfs_attr_fork_reset(
        ASSERT(ip->i_d.di_anextents == 0);
        ASSERT(ip->i_afp == NULL);
 
-       ip->i_df.if_ext_max = XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 }
 
@@ -389,10 +384,6 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
                                (args->op_flags & XFS_DA_OP_ADDNAME) ||
                                !(mp->m_flags & XFS_MOUNT_ATTR2) ||
                                dp->i_d.di_format == XFS_DINODE_FMT_BTREE);
-               dp->i_afp->if_ext_max =
-                       XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
-               dp->i_df.if_ext_max =
-                       XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
                xfs_trans_log_inode(args->trans, dp,
                                        XFS_ILOG_CORE | XFS_ILOG_ADATA);
        }
index d0ab78837057815f17605150d31a633c2eeb2739..188ef2fbd62880614a29ea0432e20707d5cf45a2 100644 (file)
@@ -249,7 +249,27 @@ xfs_bmbt_lookup_ge(
 }
 
 /*
-* Update the record referred to by cur to the value given
+ * Check if the inode needs to be converted to btree format.
+ */
+static inline bool xfs_bmap_needs_btree(struct xfs_inode *ip, int whichfork)
+{
+       return XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
+               XFS_IFORK_NEXTENTS(ip, whichfork) >
+                       XFS_IFORK_MAXEXT(ip, whichfork);
+}
+
+/*
+ * Check if the inode should be converted to extent format.
+ */
+static inline bool xfs_bmap_wants_extents(struct xfs_inode *ip, int whichfork)
+{
+       return XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE &&
+               XFS_IFORK_NEXTENTS(ip, whichfork) <=
+                       XFS_IFORK_MAXEXT(ip, whichfork);
+}
+
+/*
+ * Update the record referred to by cur to the value given
  * by [off, bno, len, state].
  * This either works (return 0) or gets an EFSCORRUPTED error.
  */
@@ -683,8 +703,8 @@ xfs_bmap_add_extent_delay_real(
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
-               if (bma->ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
-                   bma->ip->i_d.di_nextents > bma->ip->i_df.if_ext_max) {
+
+               if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) {
                        error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
                                        bma->firstblock, bma->flist,
                                        &bma->cur, 1, &tmp_rval, XFS_DATA_FORK);
@@ -767,8 +787,8 @@ xfs_bmap_add_extent_delay_real(
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
-               if (bma->ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
-                   bma->ip->i_d.di_nextents > bma->ip->i_df.if_ext_max) {
+
+               if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) {
                        error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
                                bma->firstblock, bma->flist, &bma->cur, 1,
                                &tmp_rval, XFS_DATA_FORK);
@@ -836,8 +856,8 @@ xfs_bmap_add_extent_delay_real(
                                goto done;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, done);
                }
-               if (bma->ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
-                   bma->ip->i_d.di_nextents > bma->ip->i_df.if_ext_max) {
+
+               if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) {
                        error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
                                        bma->firstblock, bma->flist, &bma->cur,
                                        1, &tmp_rval, XFS_DATA_FORK);
@@ -884,8 +904,7 @@ xfs_bmap_add_extent_delay_real(
        }
 
        /* convert to a btree if necessary */
-       if (XFS_IFORK_FORMAT(bma->ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS &&
-           XFS_IFORK_NEXTENTS(bma->ip, XFS_DATA_FORK) > ifp->if_ext_max) {
+       if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) {
                int     tmp_logflags;   /* partial log flag return val */
 
                ASSERT(bma->cur == NULL);
@@ -1421,8 +1440,7 @@ xfs_bmap_add_extent_unwritten_real(
        }
 
        /* convert to a btree if necessary */
-       if (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS &&
-           XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > ifp->if_ext_max) {
+       if (xfs_bmap_needs_btree(ip, XFS_DATA_FORK)) {
                int     tmp_logflags;   /* partial log flag return val */
 
                ASSERT(cur == NULL);
@@ -1812,8 +1830,7 @@ xfs_bmap_add_extent_hole_real(
        }
 
        /* convert to a btree if necessary */
-       if (XFS_IFORK_FORMAT(bma->ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
-           XFS_IFORK_NEXTENTS(bma->ip, whichfork) > ifp->if_ext_max) {
+       if (xfs_bmap_needs_btree(bma->ip, whichfork)) {
                int     tmp_logflags;   /* partial log flag return val */
 
                ASSERT(bma->cur == NULL);
@@ -3037,8 +3054,7 @@ xfs_bmap_extents_to_btree(
 
        ifp = XFS_IFORK_PTR(ip, whichfork);
        ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS);
-       ASSERT(ifp->if_ext_max ==
-              XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
+
        /*
         * Make space in the inode incore.
         */
@@ -3184,13 +3200,8 @@ xfs_bmap_forkoff_reset(
            ip->i_d.di_format != XFS_DINODE_FMT_BTREE) {
                uint    dfl_forkoff = xfs_default_attroffset(ip) >> 3;
 
-               if (dfl_forkoff > ip->i_d.di_forkoff) {
+               if (dfl_forkoff > ip->i_d.di_forkoff)
                        ip->i_d.di_forkoff = dfl_forkoff;
-                       ip->i_df.if_ext_max =
-                               XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t);
-                       ip->i_afp->if_ext_max =
-                               XFS_IFORK_ASIZE(ip) / sizeof(xfs_bmbt_rec_t);
-               }
        }
 }
 
@@ -3430,8 +3441,6 @@ xfs_bmap_add_attrfork(
        int                     error;          /* error return value */
 
        ASSERT(XFS_IFORK_Q(ip) == 0);
-       ASSERT(ip->i_df.if_ext_max ==
-              XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t));
 
        mp = ip->i_mount;
        ASSERT(!XFS_NOT_DQATTACHED(mp, ip));
@@ -3486,12 +3495,9 @@ xfs_bmap_add_attrfork(
                error = XFS_ERROR(EINVAL);
                goto error1;
        }
-       ip->i_df.if_ext_max =
-               XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
+
        ASSERT(ip->i_afp == NULL);
        ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
-       ip->i_afp->if_ext_max =
-               XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
        ip->i_afp->if_flags = XFS_IFEXTENTS;
        logflags = 0;
        xfs_bmap_init(&flist, &firstblock);
@@ -3535,20 +3541,17 @@ xfs_bmap_add_attrfork(
                } else
                        spin_unlock(&mp->m_sb_lock);
        }
-       if ((error = xfs_bmap_finish(&tp, &flist, &committed)))
+
+       error = xfs_bmap_finish(&tp, &flist, &committed);
+       if (error)
                goto error2;
-       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       ASSERT(ip->i_df.if_ext_max ==
-              XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t));
-       return error;
+       return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 error2:
        xfs_bmap_cancel(&flist);
 error1:
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
 error0:
        xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
-       ASSERT(ip->i_df.if_ext_max ==
-              XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t));
        return error;
 }
 
@@ -3994,11 +3997,8 @@ xfs_bmap_one_block(
        xfs_bmbt_irec_t s;              /* internal version of extent */
 
 #ifndef DEBUG
-       if (whichfork == XFS_DATA_FORK) {
-               return S_ISREG(ip->i_d.di_mode) ?
-                       (ip->i_size == ip->i_mount->m_sb.sb_blocksize) :
-                       (ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize);
-       }
+       if (whichfork == XFS_DATA_FORK)
+               return XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize;
 #endif /* !DEBUG */
        if (XFS_IFORK_NEXTENTS(ip, whichfork) != 1)
                return 0;
@@ -4010,7 +4010,7 @@ xfs_bmap_one_block(
        xfs_bmbt_get_all(ep, &s);
        rval = s.br_startoff == 0 && s.br_blockcount == 1;
        if (rval && whichfork == XFS_DATA_FORK)
-               ASSERT(ip->i_size == ip->i_mount->m_sb.sb_blocksize);
+               ASSERT(XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize);
        return rval;
 }
 
@@ -4379,8 +4379,6 @@ xfs_bmapi_read(
        XFS_STATS_INC(xs_blk_mapr);
 
        ifp = XFS_IFORK_PTR(ip, whichfork);
-       ASSERT(ifp->if_ext_max ==
-              XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
 
        if (!(ifp->if_flags & XFS_IFEXTENTS)) {
                error = xfs_iread_extents(NULL, ip, whichfork);
@@ -4871,8 +4869,6 @@ xfs_bmapi_write(
                return XFS_ERROR(EIO);
 
        ifp = XFS_IFORK_PTR(ip, whichfork);
-       ASSERT(ifp->if_ext_max ==
-              XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
 
        XFS_STATS_INC(xs_blk_mapw);
 
@@ -4981,8 +4977,7 @@ xfs_bmapi_write(
        /*
         * Transform from btree to extents, give it cur.
         */
-       if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE &&
-           XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) {
+       if (xfs_bmap_wants_extents(ip, whichfork)) {
                int             tmp_logflags = 0;
 
                ASSERT(bma.cur);
@@ -4992,10 +4987,10 @@ xfs_bmapi_write(
                if (error)
                        goto error0;
        }
-       ASSERT(ifp->if_ext_max ==
-              XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
+
        ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE ||
-              XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max);
+              XFS_IFORK_NEXTENTS(ip, whichfork) >
+               XFS_IFORK_MAXEXT(ip, whichfork));
        error = 0;
 error0:
        /*
@@ -5095,8 +5090,7 @@ xfs_bunmapi(
 
        ASSERT(len > 0);
        ASSERT(nexts >= 0);
-       ASSERT(ifp->if_ext_max ==
-              XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
+
        if (!(ifp->if_flags & XFS_IFEXTENTS) &&
            (error = xfs_iread_extents(tp, ip, whichfork)))
                return error;
@@ -5322,7 +5316,8 @@ xfs_bunmapi(
                 */
                if (!wasdel && xfs_trans_get_block_res(tp) == 0 &&
                    XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
-                   XFS_IFORK_NEXTENTS(ip, whichfork) >= ifp->if_ext_max &&
+                   XFS_IFORK_NEXTENTS(ip, whichfork) >= /* Note the >= */
+                       XFS_IFORK_MAXEXT(ip, whichfork) &&
                    del.br_startoff > got.br_startoff &&
                    del.br_startoff + del.br_blockcount <
                    got.br_startoff + got.br_blockcount) {
@@ -5353,13 +5348,11 @@ nodelete:
                }
        }
        *done = bno == (xfs_fileoff_t)-1 || bno < start || lastx < 0;
-       ASSERT(ifp->if_ext_max ==
-              XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
+
        /*
         * Convert to a btree if necessary.
         */
-       if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
-           XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) {
+       if (xfs_bmap_needs_btree(ip, whichfork)) {
                ASSERT(cur == NULL);
                error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist,
                        &cur, 0, &tmp_logflags, whichfork);
@@ -5370,8 +5363,7 @@ nodelete:
        /*
         * transform from btree to extents, give it cur
         */
-       else if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE &&
-                XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) {
+       else if (xfs_bmap_wants_extents(ip, whichfork)) {
                ASSERT(cur != NULL);
                error = xfs_bmap_btree_to_extents(tp, ip, cur, &tmp_logflags,
                        whichfork);
@@ -5382,8 +5374,6 @@ nodelete:
        /*
         * transform from extents to local?
         */
-       ASSERT(ifp->if_ext_max ==
-              XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
        error = 0;
 error0:
        /*
@@ -5434,7 +5424,7 @@ xfs_getbmapx_fix_eof_hole(
        if (startblock == HOLESTARTBLOCK) {
                mp = ip->i_mount;
                out->bmv_block = -1;
-               fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, ip->i_size));
+               fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, XFS_ISIZE(ip)));
                fixlen -= out->bmv_offset;
                if (prealloced && out->bmv_offset + out->bmv_length == end) {
                        /* Came to hole at EOF. Trim it. */
@@ -5522,7 +5512,7 @@ xfs_getbmap(
                        fixlen = XFS_MAXIOFFSET(mp);
                } else {
                        prealloced = 0;
-                       fixlen = ip->i_size;
+                       fixlen = XFS_ISIZE(ip);
                }
        }
 
@@ -5551,7 +5541,7 @@ xfs_getbmap(
 
        xfs_ilock(ip, XFS_IOLOCK_SHARED);
        if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) {
-               if (ip->i_delayed_blks || ip->i_size > ip->i_d.di_size) {
+               if (ip->i_delayed_blks || XFS_ISIZE(ip) > ip->i_d.di_size) {
                        error = xfs_flush_pages(ip, 0, -1, 0, FI_REMAPF);
                        if (error)
                                goto out_unlock_iolock;
index 654dc6f05bac7781f288f63fbcb1a5a970b06faa..dd974a55c77daee6de56a44c527e871d7cfe7fca 100644 (file)
@@ -163,12 +163,14 @@ xfs_swap_extents_check_format(
 
        /* Check temp in extent form to max in target */
        if (tip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
-           XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) > ip->i_df.if_ext_max)
+           XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) >
+                       XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK))
                return EINVAL;
 
        /* Check target in extent form to max in temp */
        if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
-           XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > tip->i_df.if_ext_max)
+           XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) >
+                       XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK))
                return EINVAL;
 
        /*
@@ -180,18 +182,25 @@ xfs_swap_extents_check_format(
         * (a common defrag case) which will occur when the temp inode is in
         * extent format...
         */
-       if (tip->i_d.di_format == XFS_DINODE_FMT_BTREE &&
-           ((XFS_IFORK_BOFF(ip) &&
-             tip->i_df.if_broot_bytes > XFS_IFORK_BOFF(ip)) ||
-            XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) <= ip->i_df.if_ext_max))
-               return EINVAL;
+       if (tip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
+               if (XFS_IFORK_BOFF(ip) &&
+                   tip->i_df.if_broot_bytes > XFS_IFORK_BOFF(ip))
+                       return EINVAL;
+               if (XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) <=
+                   XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK))
+                       return EINVAL;
+       }
 
        /* Reciprocal target->temp btree format checks */
-       if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE &&
-           ((XFS_IFORK_BOFF(tip) &&
-             ip->i_df.if_broot_bytes > XFS_IFORK_BOFF(tip)) ||
-            XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) <= tip->i_df.if_ext_max))
-               return EINVAL;
+       if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
+               if (XFS_IFORK_BOFF(tip) &&
+                   ip->i_df.if_broot_bytes > XFS_IFORK_BOFF(tip))
+                       return EINVAL;
+
+               if (XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) <=
+                   XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK))
+                       return EINVAL;
+       }
 
        return 0;
 }
@@ -348,16 +357,6 @@ xfs_swap_extents(
        *ifp = *tifp;           /* struct copy */
        *tifp = *tempifp;       /* struct copy */
 
-       /*
-        * Fix the in-memory data fork values that are dependent on the fork
-        * offset in the inode. We can't assume they remain the same as attr2
-        * has dynamic fork offsets.
-        */
-       ifp->if_ext_max = XFS_IFORK_SIZE(ip, XFS_DATA_FORK) /
-                                       (uint)sizeof(xfs_bmbt_rec_t);
-       tifp->if_ext_max = XFS_IFORK_SIZE(tip, XFS_DATA_FORK) /
-                                       (uint)sizeof(xfs_bmbt_rec_t);
-
        /*
         * Fix the on-disk inode values
         */
index f675f3d9d7b3b3693cfabc0437d52ca31a4f598a..7e5bc872f2b4fb12d67f3da3796f3c5b86ac162c 100644 (file)
@@ -327,7 +327,7 @@ xfs_file_aio_read(
                                mp->m_rtdev_targp : mp->m_ddev_targp;
                if ((iocb->ki_pos & target->bt_smask) ||
                    (size & target->bt_smask)) {
-                       if (iocb->ki_pos == ip->i_size)
+                       if (iocb->ki_pos == i_size_read(inode))
                                return 0;
                        return -XFS_ERROR(EINVAL);
                }
@@ -412,51 +412,6 @@ xfs_file_splice_read(
        return ret;
 }
 
-STATIC void
-xfs_aio_write_isize_update(
-       struct inode    *inode,
-       loff_t          *ppos,
-       ssize_t         bytes_written)
-{
-       struct xfs_inode        *ip = XFS_I(inode);
-       xfs_fsize_t             isize = i_size_read(inode);
-
-       if (bytes_written > 0)
-               XFS_STATS_ADD(xs_write_bytes, bytes_written);
-
-       if (unlikely(bytes_written < 0 && bytes_written != -EFAULT &&
-                                       *ppos > isize))
-               *ppos = isize;
-
-       if (*ppos > ip->i_size) {
-               xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
-               if (*ppos > ip->i_size)
-                       ip->i_size = *ppos;
-               xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
-       }
-}
-
-/*
- * If this was a direct or synchronous I/O that failed (such as ENOSPC) then
- * part of the I/O may have been written to disk before the error occurred.  In
- * this case the on-disk file size may have been adjusted beyond the in-memory
- * file size and now needs to be truncated back.
- */
-STATIC void
-xfs_aio_write_newsize_update(
-       struct xfs_inode        *ip,
-       xfs_fsize_t             new_size)
-{
-       if (new_size == ip->i_new_size) {
-               xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
-               if (new_size == ip->i_new_size)
-                       ip->i_new_size = 0;
-               if (ip->i_d.di_size > ip->i_size)
-                       ip->i_d.di_size = ip->i_size;
-               xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
-       }
-}
-
 /*
  * xfs_file_splice_write() does not use xfs_rw_ilock() because
  * generic_file_splice_write() takes the i_mutex itself. This, in theory,
@@ -475,7 +430,6 @@ xfs_file_splice_write(
 {
        struct inode            *inode = outfilp->f_mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
-       xfs_fsize_t             new_size;
        int                     ioflags = 0;
        ssize_t                 ret;
 
@@ -489,19 +443,12 @@ xfs_file_splice_write(
 
        xfs_ilock(ip, XFS_IOLOCK_EXCL);
 
-       new_size = *ppos + count;
-
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       if (new_size > ip->i_size)
-               ip->i_new_size = new_size;
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-
        trace_xfs_file_splice_write(ip, count, *ppos, ioflags);
 
        ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags);
+       if (ret > 0)
+               XFS_STATS_ADD(xs_write_bytes, ret);
 
-       xfs_aio_write_isize_update(inode, ppos, ret);
-       xfs_aio_write_newsize_update(ip, new_size);
        xfs_iunlock(ip, XFS_IOLOCK_EXCL);
        return ret;
 }
@@ -689,28 +636,26 @@ out_lock:
 /*
  * Common pre-write limit and setup checks.
  *
- * Returns with iolock held according to @iolock.
+ * Called with the iolocked held either shared and exclusive according to
+ * @iolock, and returns with it held.  Might upgrade the iolock to exclusive
+ * if called for a direct write beyond i_size.
  */
 STATIC ssize_t
 xfs_file_aio_write_checks(
        struct file             *file,
        loff_t                  *pos,
        size_t                  *count,
-       xfs_fsize_t             *new_sizep,
        int                     *iolock)
 {
        struct inode            *inode = file->f_mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
-       xfs_fsize_t             new_size;
        int                     error = 0;
 
        xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
-       *new_sizep = 0;
 restart:
        error = generic_write_checks(file, pos, count, S_ISBLK(inode->i_mode));
        if (error) {
-               xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock);
-               *iolock = 0;
+               xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
                return error;
        }
 
@@ -720,36 +665,21 @@ restart:
        /*
         * If the offset is beyond the size of the file, we need to zero any
         * blocks that fall between the existing EOF and the start of this
-        * write. There is no need to issue zeroing if another in-flght IO ends
-        * at or before this one If zeronig is needed and we are currently
-        * holding the iolock shared, we need to update it to exclusive which
-        * involves dropping all locks and relocking to maintain correct locking
-        * order. If we do this, restart the function to ensure all checks and
-        * values are still valid.
+        * write.  If zeroing is needed and we are currently holding the
+        * iolock shared, we need to update it to exclusive which involves
+        * dropping all locks and relocking to maintain correct locking order.
+        * If we do this, restart the function to ensure all checks and values
+        * are still valid.
         */
-       if ((ip->i_new_size && *pos > ip->i_new_size) ||
-           (!ip->i_new_size && *pos > ip->i_size)) {
+       if (*pos > i_size_read(inode)) {
                if (*iolock == XFS_IOLOCK_SHARED) {
                        xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock);
                        *iolock = XFS_IOLOCK_EXCL;
                        xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock);
                        goto restart;
                }
-               error = -xfs_zero_eof(ip, *pos, ip->i_size);
+               error = -xfs_zero_eof(ip, *pos, i_size_read(inode));
        }
-
-       /*
-        * If this IO extends beyond EOF, we may need to update ip->i_new_size.
-        * We have already zeroed space beyond EOF (if necessary).  Only update
-        * ip->i_new_size if this IO ends beyond any other in-flight writes.
-        */
-       new_size = *pos + *count;
-       if (new_size > ip->i_size) {
-               if (new_size > ip->i_new_size)
-                       ip->i_new_size = new_size;
-               *new_sizep = new_size;
-       }
-
        xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
        if (error)
                return error;
@@ -794,9 +724,7 @@ xfs_file_dio_aio_write(
        const struct iovec      *iovp,
        unsigned long           nr_segs,
        loff_t                  pos,
-       size_t                  ocount,
-       xfs_fsize_t             *new_size,
-       int                     *iolock)
+       size_t                  ocount)
 {
        struct file             *file = iocb->ki_filp;
        struct address_space    *mapping = file->f_mapping;
@@ -806,10 +734,10 @@ xfs_file_dio_aio_write(
        ssize_t                 ret = 0;
        size_t                  count = ocount;
        int                     unaligned_io = 0;
+       int                     iolock;
        struct xfs_buftarg      *target = XFS_IS_REALTIME_INODE(ip) ?
                                        mp->m_rtdev_targp : mp->m_ddev_targp;
 
-       *iolock = 0;
        if ((pos & target->bt_smask) || (count & target->bt_smask))
                return -XFS_ERROR(EINVAL);
 
@@ -824,31 +752,31 @@ xfs_file_dio_aio_write(
         * EOF zeroing cases and fill out the new inode size as appropriate.
         */
        if (unaligned_io || mapping->nrpages)
-               *iolock = XFS_IOLOCK_EXCL;
+               iolock = XFS_IOLOCK_EXCL;
        else
-               *iolock = XFS_IOLOCK_SHARED;
-       xfs_rw_ilock(ip, *iolock);
+               iolock = XFS_IOLOCK_SHARED;
+       xfs_rw_ilock(ip, iolock);
 
        /*
         * Recheck if there are cached pages that need invalidate after we got
         * the iolock to protect against other threads adding new pages while
         * we were waiting for the iolock.
         */
-       if (mapping->nrpages && *iolock == XFS_IOLOCK_SHARED) {
-               xfs_rw_iunlock(ip, *iolock);
-               *iolock = XFS_IOLOCK_EXCL;
-               xfs_rw_ilock(ip, *iolock);
+       if (mapping->nrpages && iolock == XFS_IOLOCK_SHARED) {
+               xfs_rw_iunlock(ip, iolock);
+               iolock = XFS_IOLOCK_EXCL;
+               xfs_rw_ilock(ip, iolock);
        }
 
-       ret = xfs_file_aio_write_checks(file, &pos, &count, new_size, iolock);
+       ret = xfs_file_aio_write_checks(file, &pos, &count, &iolock);
        if (ret)
-               return ret;
+               goto out;
 
        if (mapping->nrpages) {
                ret = -xfs_flushinval_pages(ip, (pos & PAGE_CACHE_MASK), -1,
                                                        FI_REMAPF_LOCKED);
                if (ret)
-                       return ret;
+                       goto out;
        }
 
        /*
@@ -857,15 +785,18 @@ xfs_file_dio_aio_write(
         */
        if (unaligned_io)
                inode_dio_wait(inode);
-       else if (*iolock == XFS_IOLOCK_EXCL) {
+       else if (iolock == XFS_IOLOCK_EXCL) {
                xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL);
-               *iolock = XFS_IOLOCK_SHARED;
+               iolock = XFS_IOLOCK_SHARED;
        }
 
        trace_xfs_file_direct_write(ip, count, iocb->ki_pos, 0);
        ret = generic_file_direct_write(iocb, iovp,
                        &nr_segs, pos, &iocb->ki_pos, count, ocount);
 
+out:
+       xfs_rw_iunlock(ip, iolock);
+
        /* No fallback to buffered IO on errors for XFS. */
        ASSERT(ret < 0 || ret == count);
        return ret;
@@ -877,9 +808,7 @@ xfs_file_buffered_aio_write(
        const struct iovec      *iovp,
        unsigned long           nr_segs,
        loff_t                  pos,
-       size_t                  ocount,
-       xfs_fsize_t             *new_size,
-       int                     *iolock)
+       size_t                  ocount)
 {
        struct file             *file = iocb->ki_filp;
        struct address_space    *mapping = file->f_mapping;
@@ -887,14 +816,14 @@ xfs_file_buffered_aio_write(
        struct xfs_inode        *ip = XFS_I(inode);
        ssize_t                 ret;
        int                     enospc = 0;
+       int                     iolock = XFS_IOLOCK_EXCL;
        size_t                  count = ocount;
 
-       *iolock = XFS_IOLOCK_EXCL;
-       xfs_rw_ilock(ip, *iolock);
+       xfs_rw_ilock(ip, iolock);
 
-       ret = xfs_file_aio_write_checks(file, &pos, &count, new_size, iolock);
+       ret = xfs_file_aio_write_checks(file, &pos, &count, &iolock);
        if (ret)
-               return ret;
+               goto out;
 
        /* We can write back this queue in page reclaim */
        current->backing_dev_info = mapping->backing_dev_info;
@@ -908,13 +837,15 @@ write_retry:
         * page locks and retry *once*
         */
        if (ret == -ENOSPC && !enospc) {
-               ret = -xfs_flush_pages(ip, 0, -1, 0, FI_NONE);
-               if (ret)
-                       return ret;
                enospc = 1;
-               goto write_retry;
+               ret = -xfs_flush_pages(ip, 0, -1, 0, FI_NONE);
+               if (!ret)
+                       goto write_retry;
        }
+
        current->backing_dev_info = NULL;
+out:
+       xfs_rw_iunlock(ip, iolock);
        return ret;
 }
 
@@ -930,9 +861,7 @@ xfs_file_aio_write(
        struct inode            *inode = mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
        ssize_t                 ret;
-       int                     iolock;
        size_t                  ocount = 0;
-       xfs_fsize_t             new_size = 0;
 
        XFS_STATS_INC(xs_write_calls);
 
@@ -951,33 +880,22 @@ xfs_file_aio_write(
                return -EIO;
 
        if (unlikely(file->f_flags & O_DIRECT))
-               ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos,
-                                               ocount, &new_size, &iolock);
+               ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos, ocount);
        else
                ret = xfs_file_buffered_aio_write(iocb, iovp, nr_segs, pos,
-                                               ocount, &new_size, &iolock);
-
-       xfs_aio_write_isize_update(inode, &iocb->ki_pos, ret);
+                                                 ocount);
 
-       if (ret <= 0)
-               goto out_unlock;
+       if (ret > 0) {
+               ssize_t err;
 
-       /* Handle various SYNC-type writes */
-       if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
-               loff_t end = pos + ret - 1;
-               int error;
+               XFS_STATS_ADD(xs_write_bytes, ret);
 
-               xfs_rw_iunlock(ip, iolock);
-               error = xfs_file_fsync(file, pos, end,
-                                     (file->f_flags & __O_SYNC) ? 0 : 1);
-               xfs_rw_ilock(ip, iolock);
-               if (error)
-                       ret = error;
+               /* Handle various SYNC-type writes */
+               err = generic_write_sync(file, pos, ret);
+               if (err < 0)
+                       ret = err;
        }
 
-out_unlock:
-       xfs_aio_write_newsize_update(ip, new_size);
-       xfs_rw_iunlock(ip, iolock);
        return ret;
 }
 
index ed88ed16811c6ba33c1d211b3195bd1dcea18484..652b875a9d4c441bd3c759df185c153dfee0e8f5 100644 (file)
@@ -90,7 +90,7 @@ xfs_wait_on_pages(
 
        if (mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK)) {
                return -filemap_fdatawait_range(mapping, first,
-                                       last == -1 ? ip->i_size - 1 : last);
+                                       last == -1 ? XFS_ISIZE(ip) - 1 : last);
        }
        return 0;
 }
index 3960a066d7ffcb06a02aadaa34d874a92c0b643b..8c3e46394d484c3fbd798913c6862d90b3f820e7 100644 (file)
@@ -77,7 +77,7 @@ xfs_inode_alloc(
 
        ASSERT(atomic_read(&ip->i_pincount) == 0);
        ASSERT(!spin_is_locked(&ip->i_flags_lock));
-       ASSERT(completion_done(&ip->i_flush));
+       ASSERT(!xfs_isiflocked(ip));
        ASSERT(ip->i_ino == 0);
 
        mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino);
@@ -94,8 +94,6 @@ xfs_inode_alloc(
        ip->i_update_core = 0;
        ip->i_delayed_blks = 0;
        memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));
-       ip->i_size = 0;
-       ip->i_new_size = 0;
 
        return ip;
 }
@@ -150,7 +148,7 @@ xfs_inode_free(
        /* asserts to verify all state is correct here */
        ASSERT(atomic_read(&ip->i_pincount) == 0);
        ASSERT(!spin_is_locked(&ip->i_flags_lock));
-       ASSERT(completion_done(&ip->i_flush));
+       ASSERT(!xfs_isiflocked(ip));
 
        /*
         * Because we use RCU freeing we need to ensure the inode always
@@ -450,8 +448,6 @@ again:
 
        *ipp = ip;
 
-       ASSERT(ip->i_df.if_ext_max ==
-              XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t));
        /*
         * If we have a real type for an on-disk inode, we can set ops(&unlock)
         * now.  If it's a new inode being created, xfs_ialloc will handle it.
@@ -715,3 +711,19 @@ xfs_isilocked(
        return 0;
 }
 #endif
+
+void
+__xfs_iflock(
+       struct xfs_inode        *ip)
+{
+       wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IFLOCK_BIT);
+       DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IFLOCK_BIT);
+
+       do {
+               prepare_to_wait_exclusive(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
+               if (xfs_isiflocked(ip))
+                       io_schedule();
+       } while (!xfs_iflock_nowait(ip));
+
+       finish_wait(wq, &wait.wait);
+}
index 9dda7cc328485014eb86baf48a013f3833faf27f..b21022499c2e8f302699f80ca2af344301fee941 100644 (file)
@@ -299,11 +299,8 @@ xfs_iformat(
 {
        xfs_attr_shortform_t    *atp;
        int                     size;
-       int                     error;
+       int                     error = 0;
        xfs_fsize_t             di_size;
-       ip->i_df.if_ext_max =
-               XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
-       error = 0;
 
        if (unlikely(be32_to_cpu(dip->di_nextents) +
                     be16_to_cpu(dip->di_anextents) >
@@ -350,7 +347,6 @@ xfs_iformat(
                        return XFS_ERROR(EFSCORRUPTED);
                }
                ip->i_d.di_size = 0;
-               ip->i_size = 0;
                ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip);
                break;
 
@@ -409,10 +405,10 @@ xfs_iformat(
        }
        if (!XFS_DFORK_Q(dip))
                return 0;
+
        ASSERT(ip->i_afp == NULL);
        ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS);
-       ip->i_afp->if_ext_max =
-               XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
+
        switch (dip->di_aformat) {
        case XFS_DINODE_FMT_LOCAL:
                atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
@@ -604,10 +600,11 @@ xfs_iformat_btree(
         * or the number of extents is greater than the number of
         * blocks.
         */
-       if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max
-           || XFS_BMDR_SPACE_CALC(nrecs) >
-                       XFS_DFORK_SIZE(dip, ip->i_mount, whichfork)
-           || XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) {
+       if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <=
+                       XFS_IFORK_MAXEXT(ip, whichfork) ||
+                    XFS_BMDR_SPACE_CALC(nrecs) >
+                       XFS_DFORK_SIZE(dip, ip->i_mount, whichfork) ||
+                    XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) {
                xfs_warn(ip->i_mount, "corrupt inode %Lu (btree).",
                        (unsigned long long) ip->i_ino);
                XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW,
@@ -835,12 +832,6 @@ xfs_iread(
                 * with the uninitialized part of it.
                 */
                ip->i_d.di_mode = 0;
-               /*
-                * Initialize the per-fork minima and maxima for a new
-                * inode here.  xfs_iformat will do it for old inodes.
-                */
-               ip->i_df.if_ext_max =
-                       XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
        }
 
        /*
@@ -861,7 +852,6 @@ xfs_iread(
        }
 
        ip->i_delayed_blks = 0;
-       ip->i_size = ip->i_d.di_size;
 
        /*
         * Mark the buffer containing the inode as something to keep
@@ -1051,7 +1041,6 @@ xfs_ialloc(
        }
 
        ip->i_d.di_size = 0;
-       ip->i_size = 0;
        ip->i_d.di_nextents = 0;
        ASSERT(ip->i_d.di_nblocks == 0);
 
@@ -1165,52 +1154,6 @@ xfs_ialloc(
        return 0;
 }
 
-/*
- * Check to make sure that there are no blocks allocated to the
- * file beyond the size of the file.  We don't check this for
- * files with fixed size extents or real time extents, but we
- * at least do it for regular files.
- */
-#ifdef DEBUG
-STATIC void
-xfs_isize_check(
-       struct xfs_inode        *ip,
-       xfs_fsize_t             isize)
-{
-       struct xfs_mount        *mp = ip->i_mount;
-       xfs_fileoff_t           map_first;
-       int                     nimaps;
-       xfs_bmbt_irec_t         imaps[2];
-       int                     error;
-
-       if (!S_ISREG(ip->i_d.di_mode))
-               return;
-
-       if (XFS_IS_REALTIME_INODE(ip))
-               return;
-
-       if (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)
-               return;
-
-       nimaps = 2;
-       map_first = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize);
-       /*
-        * The filesystem could be shutting down, so bmapi may return
-        * an error.
-        */
-       error = xfs_bmapi_read(ip, map_first,
-                        (XFS_B_TO_FSB(mp,
-                              (xfs_ufsize_t)XFS_MAXIOFFSET(mp)) - map_first),
-                        imaps, &nimaps, XFS_BMAPI_ENTIRE);
-       if (error)
-               return;
-       ASSERT(nimaps == 1);
-       ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK);
-}
-#else  /* DEBUG */
-#define xfs_isize_check(ip, isize)
-#endif /* DEBUG */
-
 /*
  * Free up the underlying blocks past new_size.  The new size must be smaller
  * than the current size.  This routine can be used both for the attribute and
@@ -1252,12 +1195,14 @@ xfs_itruncate_extents(
        int                     done = 0;
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
-       ASSERT(new_size <= ip->i_size);
+       ASSERT(new_size <= XFS_ISIZE(ip));
        ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
        ASSERT(ip->i_itemp != NULL);
        ASSERT(ip->i_itemp->ili_lock_flags == 0);
        ASSERT(!XFS_NOT_DQATTACHED(mp, ip));
 
+       trace_xfs_itruncate_extents_start(ip, new_size);
+
        /*
         * Since it is possible for space to become allocated beyond
         * the end of the file (in a crash where the space is allocated
@@ -1325,6 +1270,14 @@ xfs_itruncate_extents(
                        goto out;
        }
 
+       /*
+        * Always re-log the inode so that our permanent transaction can keep
+        * on rolling it forward in the log.
+        */
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+       trace_xfs_itruncate_extents_end(ip, new_size);
+
 out:
        *tpp = tp;
        return error;
@@ -1338,74 +1291,6 @@ out_bmap_cancel:
        goto out;
 }
 
-int
-xfs_itruncate_data(
-       struct xfs_trans        **tpp,
-       struct xfs_inode        *ip,
-       xfs_fsize_t             new_size)
-{
-       int                     error;
-
-       trace_xfs_itruncate_data_start(ip, new_size);
-
-       /*
-        * The first thing we do is set the size to new_size permanently on
-        * disk.  This way we don't have to worry about anyone ever being able
-        * to look at the data being freed even in the face of a crash.
-        * What we're getting around here is the case where we free a block, it
-        * is allocated to another file, it is written to, and then we crash.
-        * If the new data gets written to the file but the log buffers
-        * containing the free and reallocation don't, then we'd end up with
-        * garbage in the blocks being freed.  As long as we make the new_size
-        * permanent before actually freeing any blocks it doesn't matter if
-        * they get written to.
-        */
-       if (ip->i_d.di_nextents > 0) {
-               /*
-                * If we are not changing the file size then do not update
-                * the on-disk file size - we may be called from
-                * xfs_inactive_free_eofblocks().  If we update the on-disk
-                * file size and then the system crashes before the contents
-                * of the file are flushed to disk then the files may be
-                * full of holes (ie NULL files bug).
-                */
-               if (ip->i_size != new_size) {
-                       ip->i_d.di_size = new_size;
-                       ip->i_size = new_size;
-                       xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE);
-               }
-       }
-
-       error = xfs_itruncate_extents(tpp, ip, XFS_DATA_FORK, new_size);
-       if (error)
-               return error;
-
-       /*
-        * If we are not changing the file size then do not update the on-disk
-        * file size - we may be called from xfs_inactive_free_eofblocks().
-        * If we update the on-disk file size and then the system crashes
-        * before the contents of the file are flushed to disk then the files
-        * may be full of holes (ie NULL files bug).
-        */
-       xfs_isize_check(ip, new_size);
-       if (ip->i_size != new_size) {
-               ip->i_d.di_size = new_size;
-               ip->i_size = new_size;
-       }
-
-       ASSERT(new_size != 0 || ip->i_delayed_blks == 0);
-       ASSERT(new_size != 0 || ip->i_d.di_nextents == 0);
-
-       /*
-        * Always re-log the inode so that our permanent transaction can keep
-        * on rolling it forward in the log.
-        */
-       xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE);
-
-       trace_xfs_itruncate_data_end(ip, new_size);
-       return 0;
-}
-
 /*
  * This is called when the inode's link count goes to 0.
  * We place the on-disk inode on a list in the AGI.  It
@@ -1824,8 +1709,7 @@ xfs_ifree(
        ASSERT(ip->i_d.di_nlink == 0);
        ASSERT(ip->i_d.di_nextents == 0);
        ASSERT(ip->i_d.di_anextents == 0);
-       ASSERT((ip->i_d.di_size == 0 && ip->i_size == 0) ||
-              (!S_ISREG(ip->i_d.di_mode)));
+       ASSERT(ip->i_d.di_size == 0 || !S_ISREG(ip->i_d.di_mode));
        ASSERT(ip->i_d.di_nblocks == 0);
 
        /*
@@ -1844,8 +1728,6 @@ xfs_ifree(
        ip->i_d.di_flags = 0;
        ip->i_d.di_dmevmask = 0;
        ip->i_d.di_forkoff = 0;         /* mark the attr fork not in use */
-       ip->i_df.if_ext_max =
-               XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
        ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
        ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
        /*
@@ -2151,7 +2033,7 @@ xfs_idestroy_fork(
  * once someone is waiting for it to be unpinned.
  */
 static void
-xfs_iunpin_nowait(
+xfs_iunpin(
        struct xfs_inode        *ip)
 {
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
@@ -2163,14 +2045,29 @@ xfs_iunpin_nowait(
 
 }
 
+static void
+__xfs_iunpin_wait(
+       struct xfs_inode        *ip)
+{
+       wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IPINNED_BIT);
+       DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IPINNED_BIT);
+
+       xfs_iunpin(ip);
+
+       do {
+               prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
+               if (xfs_ipincount(ip))
+                       io_schedule();
+       } while (xfs_ipincount(ip));
+       finish_wait(wq, &wait.wait);
+}
+
 void
 xfs_iunpin_wait(
        struct xfs_inode        *ip)
 {
-       if (xfs_ipincount(ip)) {
-               xfs_iunpin_nowait(ip);
-               wait_event(ip->i_ipin_wait, (xfs_ipincount(ip) == 0));
-       }
+       if (xfs_ipincount(ip))
+               __xfs_iunpin_wait(ip);
 }
 
 /*
@@ -2510,9 +2407,9 @@ xfs_iflush(
        XFS_STATS_INC(xs_iflush_count);
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
-       ASSERT(!completion_done(&ip->i_flush));
+       ASSERT(xfs_isiflocked(ip));
        ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
-              ip->i_d.di_nextents > ip->i_df.if_ext_max);
+              ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK));
 
        iip = ip->i_itemp;
        mp = ip->i_mount;
@@ -2529,7 +2426,7 @@ xfs_iflush(
         * out for us if they occur after the log force completes.
         */
        if (!(flags & SYNC_WAIT) && xfs_ipincount(ip)) {
-               xfs_iunpin_nowait(ip);
+               xfs_iunpin(ip);
                xfs_ifunlock(ip);
                return EAGAIN;
        }
@@ -2626,9 +2523,9 @@ xfs_iflush_int(
 #endif
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
-       ASSERT(!completion_done(&ip->i_flush));
+       ASSERT(xfs_isiflocked(ip));
        ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
-              ip->i_d.di_nextents > ip->i_df.if_ext_max);
+              ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK));
 
        iip = ip->i_itemp;
        mp = ip->i_mount;
index f0e6b151ba37e4d0c8cc92f12a84ac03848dd0a1..2f27b745408520b73bab9bd8a1a2ca4ed1f96ea0 100644 (file)
@@ -66,7 +66,6 @@ typedef struct xfs_ifork {
        struct xfs_btree_block  *if_broot;      /* file's incore btree root */
        short                   if_broot_bytes; /* bytes allocated for root */
        unsigned char           if_flags;       /* per-fork flags */
-       unsigned char           if_ext_max;     /* max # of extent records */
        union {
                xfs_bmbt_rec_host_t *if_extents;/* linear map file exts */
                xfs_ext_irec_t  *if_ext_irec;   /* irec map file exts */
@@ -206,12 +205,12 @@ typedef struct xfs_icdinode {
        ((w) == XFS_DATA_FORK ? \
                ((ip)->i_d.di_nextents = (n)) : \
                ((ip)->i_d.di_anextents = (n)))
-
+#define XFS_IFORK_MAXEXT(ip, w) \
+       (XFS_IFORK_SIZE(ip, w) / sizeof(xfs_bmbt_rec_t))
 
 
 #ifdef __KERNEL__
 
-struct bhv_desc;
 struct xfs_buf;
 struct xfs_bmap_free;
 struct xfs_bmbt_irec;
@@ -220,12 +219,6 @@ struct xfs_mount;
 struct xfs_trans;
 struct xfs_dquot;
 
-typedef struct dm_attrs_s {
-       __uint32_t      da_dmevmask;    /* DMIG event mask */
-       __uint16_t      da_dmstate;     /* DMIG state info */
-       __uint16_t      da_pad;         /* DMIG extra padding */
-} dm_attrs_t;
-
 typedef struct xfs_inode {
        /* Inode linking and identification information. */
        struct xfs_mount        *i_mount;       /* fs mount struct ptr */
@@ -244,27 +237,19 @@ typedef struct xfs_inode {
        struct xfs_inode_log_item *i_itemp;     /* logging information */
        mrlock_t                i_lock;         /* inode lock */
        mrlock_t                i_iolock;       /* inode IO lock */
-       struct completion       i_flush;        /* inode flush completion q */
        atomic_t                i_pincount;     /* inode pin count */
-       wait_queue_head_t       i_ipin_wait;    /* inode pinning wait queue */
        spinlock_t              i_flags_lock;   /* inode i_flags lock */
        /* Miscellaneous state. */
-       unsigned short          i_flags;        /* see defined flags below */
+       unsigned long           i_flags;        /* see defined flags below */
        unsigned char           i_update_core;  /* timestamps/size is dirty */
        unsigned int            i_delayed_blks; /* count of delay alloc blks */
 
        xfs_icdinode_t          i_d;            /* most of ondisk inode */
 
-       xfs_fsize_t             i_size;         /* in-memory size */
-       xfs_fsize_t             i_new_size;     /* size when write completes */
-
        /* VFS inode */
        struct inode            i_vnode;        /* embedded VFS inode */
 } xfs_inode_t;
 
-#define XFS_ISIZE(ip)  S_ISREG((ip)->i_d.di_mode) ? \
-                               (ip)->i_size : (ip)->i_d.di_size;
-
 /* Convert from vfs inode to xfs inode */
 static inline struct xfs_inode *XFS_I(struct inode *inode)
 {
@@ -277,6 +262,18 @@ static inline struct inode *VFS_I(struct xfs_inode *ip)
        return &ip->i_vnode;
 }
 
+/*
+ * For regular files we only update the on-disk filesize when actually
+ * writing data back to disk.  Until then only the copy in the VFS inode
+ * is uptodate.
+ */
+static inline xfs_fsize_t XFS_ISIZE(struct xfs_inode *ip)
+{
+       if (S_ISREG(ip->i_d.di_mode))
+               return i_size_read(VFS_I(ip));
+       return ip->i_d.di_size;
+}
+
 /*
  * i_flags helper functions
  */
@@ -331,6 +328,19 @@ xfs_iflags_test_and_clear(xfs_inode_t *ip, unsigned short flags)
        return ret;
 }
 
+static inline int
+xfs_iflags_test_and_set(xfs_inode_t *ip, unsigned short flags)
+{
+       int ret;
+
+       spin_lock(&ip->i_flags_lock);
+       ret = ip->i_flags & flags;
+       if (!ret)
+               ip->i_flags |= flags;
+       spin_unlock(&ip->i_flags_lock);
+       return ret;
+}
+
 /*
  * Project quota id helpers (previously projid was 16bit only
  * and using two 16bit values to hold new 32bit projid was chosen
@@ -350,36 +360,20 @@ xfs_set_projid(struct xfs_inode *ip,
        ip->i_d.di_projid_lo = (__uint16_t) (projid & 0xffff);
 }
 
-/*
- * Manage the i_flush queue embedded in the inode.  This completion
- * queue synchronizes processes attempting to flush the in-core
- * inode back to disk.
- */
-static inline void xfs_iflock(xfs_inode_t *ip)
-{
-       wait_for_completion(&ip->i_flush);
-}
-
-static inline int xfs_iflock_nowait(xfs_inode_t *ip)
-{
-       return try_wait_for_completion(&ip->i_flush);
-}
-
-static inline void xfs_ifunlock(xfs_inode_t *ip)
-{
-       complete(&ip->i_flush);
-}
-
 /*
  * In-core inode flags.
  */
-#define XFS_IRECLAIM           0x0001  /* started reclaiming this inode */
-#define XFS_ISTALE             0x0002  /* inode has been staled */
-#define XFS_IRECLAIMABLE       0x0004  /* inode can be reclaimed */
-#define XFS_INEW               0x0008  /* inode has just been allocated */
-#define XFS_IFILESTREAM                0x0010  /* inode is in a filestream directory */
-#define XFS_ITRUNCATED         0x0020  /* truncated down so flush-on-close */
-#define XFS_IDIRTY_RELEASE     0x0040  /* dirty release already seen */
+#define XFS_IRECLAIM           (1 << 0) /* started reclaiming this inode */
+#define XFS_ISTALE             (1 << 1) /* inode has been staled */
+#define XFS_IRECLAIMABLE       (1 << 2) /* inode can be reclaimed */
+#define XFS_INEW               (1 << 3) /* inode has just been allocated */
+#define XFS_IFILESTREAM                (1 << 4) /* inode is in a filestream dir. */
+#define XFS_ITRUNCATED         (1 << 5) /* truncated down so flush-on-close */
+#define XFS_IDIRTY_RELEASE     (1 << 6) /* dirty release already seen */
+#define __XFS_IFLOCK_BIT       7        /* inode is being flushed right now */
+#define XFS_IFLOCK             (1 << __XFS_IFLOCK_BIT)
+#define __XFS_IPINNED_BIT      8        /* wakeup key for zero pin count */
+#define XFS_IPINNED            (1 << __XFS_IPINNED_BIT)
 
 /*
  * Per-lifetime flags need to be reset when re-using a reclaimable inode during
@@ -391,6 +385,34 @@ static inline void xfs_ifunlock(xfs_inode_t *ip)
         XFS_IDIRTY_RELEASE | XFS_ITRUNCATED | \
         XFS_IFILESTREAM);
 
+/*
+ * Synchronize processes attempting to flush the in-core inode back to disk.
+ */
+
+extern void __xfs_iflock(struct xfs_inode *ip);
+
+static inline int xfs_iflock_nowait(struct xfs_inode *ip)
+{
+       return !xfs_iflags_test_and_set(ip, XFS_IFLOCK);
+}
+
+static inline void xfs_iflock(struct xfs_inode *ip)
+{
+       if (!xfs_iflock_nowait(ip))
+               __xfs_iflock(ip);
+}
+
+static inline void xfs_ifunlock(struct xfs_inode *ip)
+{
+       xfs_iflags_clear(ip, XFS_IFLOCK);
+       wake_up_bit(&ip->i_flags, __XFS_IFLOCK_BIT);
+}
+
+static inline int xfs_isiflocked(struct xfs_inode *ip)
+{
+       return xfs_iflags_test(ip, XFS_IFLOCK);
+}
+
 /*
  * Flags for inode locking.
  * Bit ranges: 1<<1  - 1<<16-1 -- iolock/ilock modes (bitfield)
@@ -491,8 +513,6 @@ int         xfs_ifree(struct xfs_trans *, xfs_inode_t *,
                           struct xfs_bmap_free *);
 int            xfs_itruncate_extents(struct xfs_trans **, struct xfs_inode *,
                                      int, xfs_fsize_t);
-int            xfs_itruncate_data(struct xfs_trans **, struct xfs_inode *,
-                                  xfs_fsize_t);
 int            xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
 
 void           xfs_iext_realloc(xfs_inode_t *, int, int);
index cfd6c7f8cc3c09450e1ad6dfff372f12938d1d42..91d71dcd4852eed6339bd1ceb54a8dbdf04cd27a 100644 (file)
@@ -79,8 +79,6 @@ xfs_inode_item_size(
                break;
 
        case XFS_DINODE_FMT_BTREE:
-               ASSERT(ip->i_df.if_ext_max ==
-                      XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t));
                iip->ili_format.ilf_fields &=
                        ~(XFS_ILOG_DDATA | XFS_ILOG_DEXT |
                          XFS_ILOG_DEV | XFS_ILOG_UUID);
@@ -557,7 +555,7 @@ xfs_inode_item_unpin(
        trace_xfs_inode_unpin(ip, _RET_IP_);
        ASSERT(atomic_read(&ip->i_pincount) > 0);
        if (atomic_dec_and_test(&ip->i_pincount))
-               wake_up(&ip->i_ipin_wait);
+               wake_up_bit(&ip->i_flags, __XFS_IPINNED_BIT);
 }
 
 /*
@@ -719,7 +717,7 @@ xfs_inode_item_pushbuf(
         * If a flush is not in progress anymore, chances are that the
         * inode was taken off the AIL. So, just get out.
         */
-       if (completion_done(&ip->i_flush) ||
+       if (!xfs_isiflocked(ip) ||
            !(lip->li_flags & XFS_LI_IN_AIL)) {
                xfs_iunlock(ip, XFS_ILOCK_SHARED);
                return true;
@@ -752,7 +750,7 @@ xfs_inode_item_push(
        struct xfs_inode        *ip = iip->ili_inode;
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
-       ASSERT(!completion_done(&ip->i_flush));
+       ASSERT(xfs_isiflocked(ip));
 
        /*
         * Since we were able to lock the inode's flush lock and
index 9afa282aa937b473aad0d90fc6f2a0bfb659dd29..246c7d57c6f96c876778128e8d21c90fca692ce9 100644 (file)
@@ -57,26 +57,26 @@ xfs_iomap_eof_align_last_fsb(
        xfs_fileoff_t   *last_fsb)
 {
        xfs_fileoff_t   new_last_fsb = 0;
-       xfs_extlen_t    align;
+       xfs_extlen_t    align = 0;
        int             eof, error;
 
-       if (XFS_IS_REALTIME_INODE(ip))
-               ;
-       /*
-        * If mounted with the "-o swalloc" option, roundup the allocation
-        * request to a stripe width boundary if the file size is >=
-        * stripe width and we are allocating past the allocation eof.
-        */
-       else if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC) &&
-               (ip->i_size >= XFS_FSB_TO_B(mp, mp->m_swidth)))
-               new_last_fsb = roundup_64(*last_fsb, mp->m_swidth);
-       /*
-        * Roundup the allocation request to a stripe unit (m_dalign) boundary
-        * if the file size is >= stripe unit size, and we are allocating past
-        * the allocation eof.
-        */
-       else if (mp->m_dalign && (ip->i_size >= XFS_FSB_TO_B(mp, mp->m_dalign)))
-               new_last_fsb = roundup_64(*last_fsb, mp->m_dalign);
+       if (!XFS_IS_REALTIME_INODE(ip)) {
+               /*
+                * Round up the allocation request to a stripe unit
+                * (m_dalign) boundary if the file size is >= stripe unit
+                * size, and we are allocating past the allocation eof.
+                *
+                * If mounted with the "-o swalloc" option the alignment is
+                * increased from the strip unit size to the stripe width.
+                */
+               if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC))
+                       align = mp->m_swidth;
+               else if (mp->m_dalign)
+                       align = mp->m_dalign;
+
+               if (align && XFS_ISIZE(ip) >= XFS_FSB_TO_B(mp, align))
+                       new_last_fsb = roundup_64(*last_fsb, align);
+       }
 
        /*
         * Always round up the allocation request to an extent boundary
@@ -154,7 +154,7 @@ xfs_iomap_write_direct(
 
        offset_fsb = XFS_B_TO_FSBT(mp, offset);
        last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
-       if ((offset + count) > ip->i_size) {
+       if ((offset + count) > XFS_ISIZE(ip)) {
                error = xfs_iomap_eof_align_last_fsb(mp, ip, extsz, &last_fsb);
                if (error)
                        goto error_out;
@@ -211,7 +211,7 @@ xfs_iomap_write_direct(
        xfs_trans_ijoin(tp, ip, 0);
 
        bmapi_flag = 0;
-       if (offset < ip->i_size || extsz)
+       if (offset < XFS_ISIZE(ip) || extsz)
                bmapi_flag |= XFS_BMAPI_PREALLOC;
 
        /*
@@ -286,7 +286,7 @@ xfs_iomap_eof_want_preallocate(
        int             found_delalloc = 0;
 
        *prealloc = 0;
-       if ((offset + count) <= ip->i_size)
+       if (offset + count <= XFS_ISIZE(ip))
                return 0;
 
        /*
@@ -340,7 +340,7 @@ xfs_iomap_prealloc_size(
                 * if we pass in alloc_blocks = 0. Hence the "+ 1" to
                 * ensure we always pass in a non-zero value.
                 */
-               alloc_blocks = XFS_B_TO_FSB(mp, ip->i_size) + 1;
+               alloc_blocks = XFS_B_TO_FSB(mp, XFS_ISIZE(ip)) + 1;
                alloc_blocks = XFS_FILEOFF_MIN(MAXEXTLEN,
                                        rounddown_pow_of_two(alloc_blocks));
 
@@ -564,7 +564,7 @@ xfs_iomap_write_allocate(
                         * back....
                         */
                        nimaps = 1;
-                       end_fsb = XFS_B_TO_FSB(mp, ip->i_size);
+                       end_fsb = XFS_B_TO_FSB(mp, XFS_ISIZE(ip));
                        error = xfs_bmap_last_offset(NULL, ip, &last_block,
                                                        XFS_DATA_FORK);
                        if (error)
index f9babd17922377e422024ac07d9910cb78bc1708..ab302539e5b9603b8a67bb9f4399c03625fe1fd7 100644 (file)
@@ -750,6 +750,7 @@ xfs_setattr_size(
        struct xfs_mount        *mp = ip->i_mount;
        struct inode            *inode = VFS_I(ip);
        int                     mask = iattr->ia_valid;
+       xfs_off_t               oldsize, newsize;
        struct xfs_trans        *tp;
        int                     error;
        uint                    lock_flags;
@@ -777,11 +778,13 @@ xfs_setattr_size(
                lock_flags |= XFS_IOLOCK_EXCL;
        xfs_ilock(ip, lock_flags);
 
+       oldsize = inode->i_size;
+       newsize = iattr->ia_size;
+
        /*
         * Short circuit the truncate case for zero length files.
         */
-       if (iattr->ia_size == 0 &&
-           ip->i_size == 0 && ip->i_d.di_nextents == 0) {
+       if (newsize == 0 && oldsize == 0 && ip->i_d.di_nextents == 0) {
                if (!(mask & (ATTR_CTIME|ATTR_MTIME)))
                        goto out_unlock;
 
@@ -807,14 +810,14 @@ xfs_setattr_size(
         * the inode to the transaction, because the inode cannot be unlocked
         * once it is a part of the transaction.
         */
-       if (iattr->ia_size > ip->i_size) {
+       if (newsize > oldsize) {
                /*
                 * Do the first part of growing a file: zero any data in the
                 * last block that is beyond the old EOF.  We need to do this
                 * before the inode is joined to the transaction to modify
                 * i_size.
                 */
-               error = xfs_zero_eof(ip, iattr->ia_size, ip->i_size);
+               error = xfs_zero_eof(ip, newsize, oldsize);
                if (error)
                        goto out_unlock;
        }
@@ -833,8 +836,8 @@ xfs_setattr_size(
         * here and prevents waiting for other data not within the range we
         * care about here.
         */
-       if (ip->i_size != ip->i_d.di_size && iattr->ia_size > ip->i_d.di_size) {
-               error = xfs_flush_pages(ip, ip->i_d.di_size, iattr->ia_size, 0,
+       if (oldsize != ip->i_d.di_size && newsize > ip->i_d.di_size) {
+               error = xfs_flush_pages(ip, ip->i_d.di_size, newsize, 0,
                                        FI_NONE);
                if (error)
                        goto out_unlock;
@@ -845,8 +848,7 @@ xfs_setattr_size(
         */
        inode_dio_wait(inode);
 
-       error = -block_truncate_page(inode->i_mapping, iattr->ia_size,
-                                    xfs_get_blocks);
+       error = -block_truncate_page(inode->i_mapping, newsize, xfs_get_blocks);
        if (error)
                goto out_unlock;
 
@@ -857,7 +859,7 @@ xfs_setattr_size(
        if (error)
                goto out_trans_cancel;
 
-       truncate_setsize(inode, iattr->ia_size);
+       truncate_setsize(inode, newsize);
 
        commit_flags = XFS_TRANS_RELEASE_LOG_RES;
        lock_flags |= XFS_ILOCK_EXCL;
@@ -876,19 +878,29 @@ xfs_setattr_size(
         * these flags set.  For all other operations the VFS set these flags
         * explicitly if it wants a timestamp update.
         */
-       if (iattr->ia_size != ip->i_size &&
-           (!(mask & (ATTR_CTIME | ATTR_MTIME)))) {
+       if (newsize != oldsize && (!(mask & (ATTR_CTIME | ATTR_MTIME)))) {
                iattr->ia_ctime = iattr->ia_mtime =
                        current_fs_time(inode->i_sb);
                mask |= ATTR_CTIME | ATTR_MTIME;
        }
 
-       if (iattr->ia_size > ip->i_size) {
-               ip->i_d.di_size = iattr->ia_size;
-               ip->i_size = iattr->ia_size;
-       } else if (iattr->ia_size <= ip->i_size ||
-                  (iattr->ia_size == 0 && ip->i_d.di_nextents)) {
-               error = xfs_itruncate_data(&tp, ip, iattr->ia_size);
+       /*
+        * The first thing we do is set the size to new_size permanently on
+        * disk.  This way we don't have to worry about anyone ever being able
+        * to look at the data being freed even in the face of a crash.
+        * What we're getting around here is the case where we free a block, it
+        * is allocated to another file, it is written to, and then we crash.
+        * If the new data gets written to the file but the log buffers
+        * containing the free and reallocation don't, then we'd end up with
+        * garbage in the blocks being freed.  As long as we make the new size
+        * permanent before actually freeing any blocks it doesn't matter if
+        * they get written to.
+        */
+       ip->i_d.di_size = newsize;
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+       if (newsize <= oldsize) {
+               error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, newsize);
                if (error)
                        goto out_trans_abort;
 
index 5cc3dde1bc9039de237a102c466b1fb4aa249cf8..eafbcff81f3af43c9dae0a73175bc71abba4a7c5 100644 (file)
@@ -31,6 +31,7 @@
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_inode.h"
+#include "xfs_inode_item.h"
 #include "xfs_itable.h"
 #include "xfs_bmap.h"
 #include "xfs_rtalloc.h"
@@ -263,13 +264,18 @@ xfs_qm_scall_trunc_qfile(
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, 0);
 
-       error = xfs_itruncate_data(&tp, ip, 0);
+       ip->i_d.di_size = 0;
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+       error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
        if (error) {
                xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
                                     XFS_TRANS_ABORT);
                goto out_unlock;
        }
 
+       ASSERT(ip->i_d.di_nextents == 0);
+
        xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 
index 281961c1d81a73df18ab8dcf31c39e6be3d94588..ee5b695c99a700275683d26ac78acd6351c9cc1f 100644 (file)
@@ -828,14 +828,6 @@ xfs_fs_inode_init_once(
        /* xfs inode */
        atomic_set(&ip->i_pincount, 0);
        spin_lock_init(&ip->i_flags_lock);
-       init_waitqueue_head(&ip->i_ipin_wait);
-       /*
-        * Because we want to use a counting completion, complete
-        * the flush completion once to allow a single access to
-        * the flush completion without blocking.
-        */
-       init_completion(&ip->i_flush);
-       complete(&ip->i_flush);
 
        mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER,
                     "xfsino", ip->i_ino);
index 72c01a1c16e7d16ca0a49e284addf7d884dbfea6..40b75eecd2b4b376253e0e9408e42bc475e63f9b 100644 (file)
@@ -707,14 +707,13 @@ xfs_reclaim_inode_grab(
                return 1;
 
        /*
-        * do some unlocked checks first to avoid unnecessary lock traffic.
-        * The first is a flush lock check, the second is a already in reclaim
-        * check. Only do these checks if we are not going to block on locks.
+        * If we are asked for non-blocking operation, do unlocked checks to
+        * see if the inode already is being flushed or in reclaim to avoid
+        * lock traffic.
         */
        if ((flags & SYNC_TRYLOCK) &&
-           (!ip->i_flush.done || __xfs_iflags_test(ip, XFS_IRECLAIM))) {
+           __xfs_iflags_test(ip, XFS_IFLOCK | XFS_IRECLAIM))
                return 1;
-       }
 
        /*
         * The radix tree lock here protects a thread in xfs_iget from racing
index a9d5b1e06efee95920e0bc0dd7b75c6f867b537b..6b6df5802e957009f8c3f657411bf6e6e89cfad6 100644 (file)
@@ -891,7 +891,6 @@ DECLARE_EVENT_CLASS(xfs_file_class,
                __field(dev_t, dev)
                __field(xfs_ino_t, ino)
                __field(xfs_fsize_t, size)
-               __field(xfs_fsize_t, new_size)
                __field(loff_t, offset)
                __field(size_t, count)
                __field(int, flags)
@@ -900,17 +899,15 @@ DECLARE_EVENT_CLASS(xfs_file_class,
                __entry->dev = VFS_I(ip)->i_sb->s_dev;
                __entry->ino = ip->i_ino;
                __entry->size = ip->i_d.di_size;
-               __entry->new_size = ip->i_new_size;
                __entry->offset = offset;
                __entry->count = count;
                __entry->flags = flags;
        ),
-       TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx "
+       TP_printk("dev %d:%d ino 0x%llx size 0x%llx "
                  "offset 0x%llx count 0x%zx ioflags %s",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  __entry->ino,
                  __entry->size,
-                 __entry->new_size,
                  __entry->offset,
                  __entry->count,
                  __print_flags(__entry->flags, "|", XFS_IO_FLAGS))
@@ -978,7 +975,6 @@ DECLARE_EVENT_CLASS(xfs_imap_class,
                __field(dev_t, dev)
                __field(xfs_ino_t, ino)
                __field(loff_t, size)
-               __field(loff_t, new_size)
                __field(loff_t, offset)
                __field(size_t, count)
                __field(int, type)
@@ -990,7 +986,6 @@ DECLARE_EVENT_CLASS(xfs_imap_class,
                __entry->dev = VFS_I(ip)->i_sb->s_dev;
                __entry->ino = ip->i_ino;
                __entry->size = ip->i_d.di_size;
-               __entry->new_size = ip->i_new_size;
                __entry->offset = offset;
                __entry->count = count;
                __entry->type = type;
@@ -998,13 +993,11 @@ DECLARE_EVENT_CLASS(xfs_imap_class,
                __entry->startblock = irec ? irec->br_startblock : 0;
                __entry->blockcount = irec ? irec->br_blockcount : 0;
        ),
-       TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx "
-                 "offset 0x%llx count %zd type %s "
-                 "startoff 0x%llx startblock %lld blockcount 0x%llx",
+       TP_printk("dev %d:%d ino 0x%llx size 0x%llx offset 0x%llx count %zd "
+                 "type %s startoff 0x%llx startblock %lld blockcount 0x%llx",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  __entry->ino,
                  __entry->size,
-                 __entry->new_size,
                  __entry->offset,
                  __entry->count,
                  __print_symbolic(__entry->type, XFS_IO_TYPES),
@@ -1031,26 +1024,23 @@ DECLARE_EVENT_CLASS(xfs_simple_io_class,
                __field(xfs_ino_t, ino)
                __field(loff_t, isize)
                __field(loff_t, disize)
-               __field(loff_t, new_size)
                __field(loff_t, offset)
                __field(size_t, count)
        ),
        TP_fast_assign(
                __entry->dev = VFS_I(ip)->i_sb->s_dev;
                __entry->ino = ip->i_ino;
-               __entry->isize = ip->i_size;
+               __entry->isize = VFS_I(ip)->i_size;
                __entry->disize = ip->i_d.di_size;
-               __entry->new_size = ip->i_new_size;
                __entry->offset = offset;
                __entry->count = count;
        ),
-       TP_printk("dev %d:%d ino 0x%llx isize 0x%llx disize 0x%llx new_size 0x%llx "
+       TP_printk("dev %d:%d ino 0x%llx isize 0x%llx disize 0x%llx "
                  "offset 0x%llx count %zd",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  __entry->ino,
                  __entry->isize,
                  __entry->disize,
-                 __entry->new_size,
                  __entry->offset,
                  __entry->count)
 );
@@ -1090,8 +1080,8 @@ DECLARE_EVENT_CLASS(xfs_itrunc_class,
 DEFINE_EVENT(xfs_itrunc_class, name, \
        TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size), \
        TP_ARGS(ip, new_size))
-DEFINE_ITRUNC_EVENT(xfs_itruncate_data_start);
-DEFINE_ITRUNC_EVENT(xfs_itruncate_data_end);
+DEFINE_ITRUNC_EVENT(xfs_itruncate_extents_start);
+DEFINE_ITRUNC_EVENT(xfs_itruncate_extents_end);
 
 TRACE_EVENT(xfs_pagecache_inval,
        TP_PROTO(struct xfs_inode *ip, xfs_off_t start, xfs_off_t finish),
@@ -1568,7 +1558,6 @@ DECLARE_EVENT_CLASS(xfs_swap_extent_class,
                __field(xfs_ino_t, ino)
                __field(int, format)
                __field(int, nex)
-               __field(int, max_nex)
                __field(int, broot_size)
                __field(int, fork_off)
        ),
@@ -1578,18 +1567,16 @@ DECLARE_EVENT_CLASS(xfs_swap_extent_class,
                __entry->ino = ip->i_ino;
                __entry->format = ip->i_d.di_format;
                __entry->nex = ip->i_d.di_nextents;
-               __entry->max_nex = ip->i_df.if_ext_max;
                __entry->broot_size = ip->i_df.if_broot_bytes;
                __entry->fork_off = XFS_IFORK_BOFF(ip);
        ),
        TP_printk("dev %d:%d ino 0x%llx (%s), %s format, num_extents %d, "
-                 "Max in-fork extents %d, broot size %d, fork offset %d",
+                 "broot size %d, fork offset %d",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  __entry->ino,
                  __print_symbolic(__entry->which, XFS_SWAPEXT_INODES),
                  __print_symbolic(__entry->format, XFS_INODE_FORMAT_STR),
                  __entry->nex,
-                 __entry->max_nex,
                  __entry->broot_size,
                  __entry->fork_off)
 )
index f2fea868d4db5da562804b2a0a9bd212608af058..0cf52da9d2468a547a614f55cf0191a396f82574 100644 (file)
@@ -175,7 +175,7 @@ xfs_free_eofblocks(
         * Figure out if there are any blocks beyond the end
         * of the file.  If not, then there is nothing to do.
         */
-       end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_size));
+       end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip));
        last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
        if (last_fsb <= end_fsb)
                return 0;
@@ -226,7 +226,14 @@ xfs_free_eofblocks(
                xfs_ilock(ip, XFS_ILOCK_EXCL);
                xfs_trans_ijoin(tp, ip, 0);
 
-               error = xfs_itruncate_data(&tp, ip, ip->i_size);
+               /*
+                * Do not update the on-disk file size.  If we update the
+                * on-disk file size and then the system crashes before the
+                * contents of the file are flushed to disk then the files
+                * may be full of holes (ie NULL files bug).
+                */
+               error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK,
+                                             XFS_ISIZE(ip));
                if (error) {
                        /*
                         * If we get an error at this point we simply don't
@@ -540,8 +547,8 @@ xfs_release(
                return 0;
 
        if ((S_ISREG(ip->i_d.di_mode) &&
-            ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 ||
-              ip->i_delayed_blks > 0)) &&
+            (VFS_I(ip)->i_size > 0 ||
+             (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) &&
             (ip->i_df.if_flags & XFS_IFEXTENTS))  &&
            (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) {
 
@@ -618,7 +625,7 @@ xfs_inactive(
         * only one with a reference to the inode.
         */
        truncate = ((ip->i_d.di_nlink == 0) &&
-           ((ip->i_d.di_size != 0) || (ip->i_size != 0) ||
+           ((ip->i_d.di_size != 0) || XFS_ISIZE(ip) != 0 ||
             (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) &&
            S_ISREG(ip->i_d.di_mode));
 
@@ -632,12 +639,12 @@ xfs_inactive(
 
        if (ip->i_d.di_nlink != 0) {
                if ((S_ISREG(ip->i_d.di_mode) &&
-                     ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 ||
-                       ip->i_delayed_blks > 0)) &&
-                     (ip->i_df.if_flags & XFS_IFEXTENTS) &&
-                    (!(ip->i_d.di_flags &
+                   (VFS_I(ip)->i_size > 0 ||
+                    (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) &&
+                   (ip->i_df.if_flags & XFS_IFEXTENTS) &&
+                   (!(ip->i_d.di_flags &
                                (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||
-                     (ip->i_delayed_blks != 0)))) {
+                    ip->i_delayed_blks != 0))) {
                        error = xfs_free_eofblocks(mp, ip, 0);
                        if (error)
                                return VN_INACTIVE_CACHE;
@@ -670,13 +677,18 @@ xfs_inactive(
                xfs_ilock(ip, XFS_ILOCK_EXCL);
                xfs_trans_ijoin(tp, ip, 0);
 
-               error = xfs_itruncate_data(&tp, ip, 0);
+               ip->i_d.di_size = 0;
+               xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+               error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
                if (error) {
                        xfs_trans_cancel(tp,
                                XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
                        xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
                        return VN_INACTIVE_CACHE;
                }
+
+               ASSERT(ip->i_d.di_nextents == 0);
        } else if (S_ISLNK(ip->i_d.di_mode)) {
 
                /*
@@ -1961,11 +1973,11 @@ xfs_zero_remaining_bytes(
         * since nothing can read beyond eof.  The space will
         * be zeroed when the file is extended anyway.
         */
-       if (startoff >= ip->i_size)
+       if (startoff >= XFS_ISIZE(ip))
                return 0;
 
-       if (endoff > ip->i_size)
-               endoff = ip->i_size;
+       if (endoff > XFS_ISIZE(ip))
+               endoff = XFS_ISIZE(ip);
 
        bp = xfs_buf_get_uncached(XFS_IS_REALTIME_INODE(ip) ?
                                        mp->m_rtdev_targp : mp->m_ddev_targp,
@@ -2260,7 +2272,7 @@ xfs_change_file_space(
                bf->l_start += offset;
                break;
        case 2: /*SEEK_END*/
-               bf->l_start += ip->i_size;
+               bf->l_start += XFS_ISIZE(ip);
                break;
        default:
                return XFS_ERROR(EINVAL);
@@ -2277,7 +2289,7 @@ xfs_change_file_space(
        bf->l_whence = 0;
 
        startoffset = bf->l_start;
-       fsize = ip->i_size;
+       fsize = XFS_ISIZE(ip);
 
        /*
         * XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve
index fc1575fd4596e484c0fc44c7614e6decb5e8c6b6..5b5af0d30a9738a7cb938a04b839c3d6a5f5727e 100644 (file)
@@ -58,6 +58,7 @@
 #define METHOD_NAME__PRT        "_PRT"
 #define METHOD_NAME__CRS        "_CRS"
 #define METHOD_NAME__PRS        "_PRS"
+#define METHOD_NAME__AEI        "_AEI"
 #define METHOD_NAME__PRW        "_PRW"
 #define METHOD_NAME__SRS        "_SRS"
 
index 173972672175588c181718aef6cf7f1537c37758..451823cb88372b2130793abbbb4e17869af34faf 100644 (file)
@@ -15,6 +15,7 @@ extern int pxm_to_node(int);
 extern int node_to_pxm(int);
 extern void __acpi_map_pxm_to_node(int, int);
 extern int acpi_map_pxm_to_node(int);
+extern unsigned char acpi_srat_revision;
 
 #endif                         /* CONFIG_ACPI_NUMA */
 #endif                         /* __ACP_NUMA_H */
index 83062ed0ef2f7177285e6688a07e81db8c1a90e4..2fe8639b3ae74f8ef8ed93626391256d0528c991 100644 (file)
@@ -238,13 +238,6 @@ acpi_os_write_pci_configuration(struct acpi_pci_id *pci_id,
 /*
  * Miscellaneous
  */
-acpi_status
-acpi_os_validate_address(u8 space_id, acpi_physical_address address,
-                        acpi_size length, char *name);
-acpi_status
-acpi_os_invalidate_address(u8 space_id, acpi_physical_address address,
-                        acpi_size length);
-
 u64 acpi_os_get_timer(void);
 
 acpi_status acpi_os_signal(u32 function, void *info);
index f554a9313b43d7b2bbc50d599cb5f9363bfe8868..a28da35ba45ee3f1fd3bcdf2b8a7f64bbe5d2391 100644 (file)
@@ -47,7 +47,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20110623
+#define ACPI_CA_VERSION                 0x20120111
 
 #include "actypes.h"
 #include "actbl.h"
@@ -66,7 +66,7 @@ extern u8 acpi_gbl_create_osi_method;
 extern u8 acpi_gbl_use_default_register_widths;
 extern acpi_name acpi_gbl_trace_method_name;
 extern u32 acpi_gbl_trace_flags;
-extern u32 acpi_gbl_enable_aml_debug_object;
+extern bool acpi_gbl_enable_aml_debug_object;
 extern u8 acpi_gbl_copy_dsdt_locally;
 extern u8 acpi_gbl_truncate_io_addresses;
 extern u8 acpi_gbl_disable_auto_repair;
@@ -74,6 +74,7 @@ extern u8 acpi_gbl_disable_auto_repair;
 extern u32 acpi_current_gpe_count;
 extern struct acpi_table_fadt acpi_gbl_FADT;
 extern u8 acpi_gbl_system_awake_and_running;
+extern u8 acpi_gbl_reduced_hardware;   /* ACPI 5.0 */
 
 extern u32 acpi_rsdt_forced;
 /*
@@ -111,6 +112,11 @@ acpi_status acpi_install_interface(acpi_string interface_name);
 
 acpi_status acpi_remove_interface(acpi_string interface_name);
 
+u32
+acpi_check_address_range(acpi_adr_space_type space_id,
+                        acpi_physical_address address,
+                        acpi_size length, u8 warn);
+
 /*
  * ACPI Memory management
  */
@@ -276,12 +282,23 @@ acpi_status acpi_install_exception_handler(acpi_exception_handler handler);
 acpi_status acpi_install_interface_handler(acpi_interface_handler handler);
 
 /*
- * Event interfaces
+ * Global Lock interfaces
  */
 acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle);
 
 acpi_status acpi_release_global_lock(u32 handle);
 
+/*
+ * Interfaces to AML mutex objects
+ */
+acpi_status
+acpi_acquire_mutex(acpi_handle handle, acpi_string pathname, u16 timeout);
+
+acpi_status acpi_release_mutex(acpi_handle handle, acpi_string pathname);
+
+/*
+ * Fixed Event interfaces
+ */
 acpi_status acpi_enable_event(u32 event, u32 flags);
 
 acpi_status acpi_disable_event(u32 event, u32 flags);
@@ -291,7 +308,7 @@ acpi_status acpi_clear_event(u32 event);
 acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status);
 
 /*
- * GPE Interfaces
+ * General Purpose Event (GPE) Interfaces
  */
 acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number);
 
@@ -345,6 +362,10 @@ acpi_status
 acpi_get_possible_resources(acpi_handle device, struct acpi_buffer *ret_buffer);
 #endif
 
+acpi_status
+acpi_get_event_resources(acpi_handle device_handle,
+                        struct acpi_buffer *ret_buffer);
+
 acpi_status
 acpi_walk_resources(acpi_handle device,
                    char *name,
@@ -360,6 +381,11 @@ acpi_status
 acpi_resource_to_address64(struct acpi_resource *resource,
                           struct acpi_resource_address64 *out);
 
+acpi_status
+acpi_buffer_to_resource(u8 *aml_buffer,
+                       u16 aml_buffer_length,
+                       struct acpi_resource **resource_ptr);
+
 /*
  * Hardware (ACPI device) interfaces
  */
index 0a66cc45dd6b79a0fdb17be3368b87cdd1c646f5..3506e39a66b15962a5d6de4ab54a8117ff0267bb 100644 (file)
@@ -61,11 +61,14 @@ typedef u32 acpi_rsdesc_size;       /* Max Resource Descriptor size is (Length+3) = (6
 #define ACPI_WRITE_COMBINING_MEMORY     (u8) 0x02
 #define ACPI_PREFETCHABLE_MEMORY        (u8) 0x03
 
+/*! [Begin] no source code translation */
 /*
  * IO Attributes
- * The ISA IO ranges are:     n000-n0_fFh, n400-n4_fFh, n800-n8_fFh, n_c00-n_cFFh.
- * The non-ISA IO ranges are: n100-n3_fFh, n500-n7_fFh, n900-n_bFFh, n_cd0-n_fFFh.
+ * The ISA IO ranges are:     n000-n0FFh,  n400-n4FFh, n800-n8FFh, nC00-nCFFh.
+ * The non-ISA IO ranges are: n100-n3FFh,  n500-n7FFh, n900-nBFFh, nCD0-nFFFh.
  */
+/*! [End] no source code translation !*/
+
 #define ACPI_NON_ISA_ONLY_RANGES        (u8) 0x01
 #define ACPI_ISA_ONLY_RANGES            (u8) 0x02
 #define ACPI_ENTIRE_RANGE               (ACPI_NON_ISA_ONLY_RANGES | ACPI_ISA_ONLY_RANGES)
@@ -81,16 +84,26 @@ typedef u32 acpi_rsdesc_size;       /* Max Resource Descriptor size is (Length+3) = (6
 #define ACPI_DECODE_16                  (u8) 0x01      /* 16-bit IO address decode */
 
 /*
- * IRQ Attributes
+ * Interrupt attributes - used in multiple descriptors
  */
+
+/* Triggering */
+
 #define ACPI_LEVEL_SENSITIVE            (u8) 0x00
 #define ACPI_EDGE_SENSITIVE             (u8) 0x01
 
+/* Polarity */
+
 #define ACPI_ACTIVE_HIGH                (u8) 0x00
 #define ACPI_ACTIVE_LOW                 (u8) 0x01
+#define ACPI_ACTIVE_BOTH                (u8) 0x02
+
+/* Sharing */
 
 #define ACPI_EXCLUSIVE                  (u8) 0x00
 #define ACPI_SHARED                     (u8) 0x01
+#define ACPI_EXCLUSIVE_AND_WAKE         (u8) 0x02
+#define ACPI_SHARED_AND_WAKE            (u8) 0x03
 
 /*
  * DMA Attributes
@@ -127,6 +140,8 @@ typedef u32 acpi_rsdesc_size;       /* Max Resource Descriptor size is (Length+3) = (6
 #define ACPI_POS_DECODE                 (u8) 0x00
 #define ACPI_SUB_DECODE                 (u8) 0x01
 
+/* Producer/Consumer */
+
 #define ACPI_PRODUCER                   (u8) 0x00
 #define ACPI_CONSUMER                   (u8) 0x01
 
@@ -192,6 +207,21 @@ struct acpi_resource_fixed_io {
        u8 address_length;
 };
 
+struct acpi_resource_fixed_dma {
+       u16 request_lines;
+       u16 channels;
+       u8 width;
+};
+
+/* Values for Width field above */
+
+#define ACPI_DMA_WIDTH8                         0
+#define ACPI_DMA_WIDTH16                        1
+#define ACPI_DMA_WIDTH32                        2
+#define ACPI_DMA_WIDTH64                        3
+#define ACPI_DMA_WIDTH128                       4
+#define ACPI_DMA_WIDTH256                       5
+
 struct acpi_resource_vendor {
        u16 byte_length;
        u8 byte_data[1];
@@ -329,6 +359,166 @@ struct acpi_resource_generic_register {
        u64 address;
 };
 
+struct acpi_resource_gpio {
+       u8 revision_id;
+       u8 connection_type;
+       u8 producer_consumer;   /* For values, see Producer/Consumer above */
+       u8 pin_config;
+       u8 sharable;            /* For values, see Interrupt Attributes above */
+       u8 io_restriction;
+       u8 triggering;          /* For values, see Interrupt Attributes above */
+       u8 polarity;            /* For values, see Interrupt Attributes above */
+       u16 drive_strength;
+       u16 debounce_timeout;
+       u16 pin_table_length;
+       u16 vendor_length;
+       struct acpi_resource_source resource_source;
+       u16 *pin_table;
+       u8 *vendor_data;
+};
+
+/* Values for GPIO connection_type field above */
+
+#define ACPI_RESOURCE_GPIO_TYPE_INT             0
+#define ACPI_RESOURCE_GPIO_TYPE_IO              1
+
+/* Values for pin_config field above */
+
+#define ACPI_PIN_CONFIG_DEFAULT                 0
+#define ACPI_PIN_CONFIG_PULLUP                  1
+#define ACPI_PIN_CONFIG_PULLDOWN                2
+#define ACPI_PIN_CONFIG_NOPULL                  3
+
+/* Values for io_restriction field above */
+
+#define ACPI_IO_RESTRICT_NONE                   0
+#define ACPI_IO_RESTRICT_INPUT                  1
+#define ACPI_IO_RESTRICT_OUTPUT                 2
+#define ACPI_IO_RESTRICT_NONE_PRESERVE          3
+
+/* Common structure for I2C, SPI, and UART serial descriptors */
+
+#define ACPI_RESOURCE_SERIAL_COMMON \
+       u8                                      revision_id; \
+       u8                                      type; \
+       u8                                      producer_consumer;   /* For values, see Producer/Consumer above */\
+       u8                                      slave_mode; \
+       u8                                      type_revision_id; \
+       u16                                     type_data_length; \
+       u16                                     vendor_length; \
+       struct acpi_resource_source             resource_source; \
+       u8                                      *vendor_data;
+
+struct acpi_resource_common_serialbus {
+ACPI_RESOURCE_SERIAL_COMMON};
+
+/* Values for the Type field above */
+
+#define ACPI_RESOURCE_SERIAL_TYPE_I2C           1
+#define ACPI_RESOURCE_SERIAL_TYPE_SPI           2
+#define ACPI_RESOURCE_SERIAL_TYPE_UART          3
+
+/* Values for slave_mode field above */
+
+#define ACPI_CONTROLLER_INITIATED               0
+#define ACPI_DEVICE_INITIATED                   1
+
+struct acpi_resource_i2c_serialbus {
+       ACPI_RESOURCE_SERIAL_COMMON u8 access_mode;
+       u16 slave_address;
+       u32 connection_speed;
+};
+
+/* Values for access_mode field above */
+
+#define ACPI_I2C_7BIT_MODE                      0
+#define ACPI_I2C_10BIT_MODE                     1
+
+struct acpi_resource_spi_serialbus {
+       ACPI_RESOURCE_SERIAL_COMMON u8 wire_mode;
+       u8 device_polarity;
+       u8 data_bit_length;
+       u8 clock_phase;
+       u8 clock_polarity;
+       u16 device_selection;
+       u32 connection_speed;
+};
+
+/* Values for wire_mode field above */
+
+#define ACPI_SPI_4WIRE_MODE                     0
+#define ACPI_SPI_3WIRE_MODE                     1
+
+/* Values for device_polarity field above */
+
+#define ACPI_SPI_ACTIVE_LOW                     0
+#define ACPI_SPI_ACTIVE_HIGH                    1
+
+/* Values for clock_phase field above */
+
+#define ACPI_SPI_FIRST_PHASE                    0
+#define ACPI_SPI_SECOND_PHASE                   1
+
+/* Values for clock_polarity field above */
+
+#define ACPI_SPI_START_LOW                      0
+#define ACPI_SPI_START_HIGH                     1
+
+struct acpi_resource_uart_serialbus {
+       ACPI_RESOURCE_SERIAL_COMMON u8 endian;
+       u8 data_bits;
+       u8 stop_bits;
+       u8 flow_control;
+       u8 parity;
+       u8 lines_enabled;
+       u16 rx_fifo_size;
+       u16 tx_fifo_size;
+       u32 default_baud_rate;
+};
+
+/* Values for Endian field above */
+
+#define ACPI_UART_LITTLE_ENDIAN                 0
+#define ACPI_UART_BIG_ENDIAN                    1
+
+/* Values for data_bits field above */
+
+#define ACPI_UART_5_DATA_BITS                   0
+#define ACPI_UART_6_DATA_BITS                   1
+#define ACPI_UART_7_DATA_BITS                   2
+#define ACPI_UART_8_DATA_BITS                   3
+#define ACPI_UART_9_DATA_BITS                   4
+
+/* Values for stop_bits field above */
+
+#define ACPI_UART_NO_STOP_BITS                  0
+#define ACPI_UART_1_STOP_BIT                    1
+#define ACPI_UART_1P5_STOP_BITS                 2
+#define ACPI_UART_2_STOP_BITS                   3
+
+/* Values for flow_control field above */
+
+#define ACPI_UART_FLOW_CONTROL_NONE             0
+#define ACPI_UART_FLOW_CONTROL_HW               1
+#define ACPI_UART_FLOW_CONTROL_XON_XOFF         2
+
+/* Values for Parity field above */
+
+#define ACPI_UART_PARITY_NONE                   0
+#define ACPI_UART_PARITY_EVEN                   1
+#define ACPI_UART_PARITY_ODD                    2
+#define ACPI_UART_PARITY_MARK                   3
+#define ACPI_UART_PARITY_SPACE                  4
+
+/* Values for lines_enabled bitfield above */
+
+#define ACPI_UART_CARRIER_DETECT                (1<<2)
+#define ACPI_UART_RING_INDICATOR                (1<<3)
+#define ACPI_UART_DATA_SET_READY                (1<<4)
+#define ACPI_UART_DATA_TERMINAL_READY           (1<<5)
+#define ACPI_UART_CLEAR_TO_SEND                 (1<<6)
+#define ACPI_UART_REQUEST_TO_SEND               (1<<7)
+
 /* ACPI_RESOURCE_TYPEs */
 
 #define ACPI_RESOURCE_TYPE_IRQ                  0
@@ -348,7 +538,10 @@ struct acpi_resource_generic_register {
 #define ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64   14     /* ACPI 3.0 */
 #define ACPI_RESOURCE_TYPE_EXTENDED_IRQ         15
 #define ACPI_RESOURCE_TYPE_GENERIC_REGISTER     16
-#define ACPI_RESOURCE_TYPE_MAX                  16
+#define ACPI_RESOURCE_TYPE_GPIO                 17     /* ACPI 5.0 */
+#define ACPI_RESOURCE_TYPE_FIXED_DMA            18     /* ACPI 5.0 */
+#define ACPI_RESOURCE_TYPE_SERIAL_BUS           19     /* ACPI 5.0 */
+#define ACPI_RESOURCE_TYPE_MAX                  19
 
 /* Master union for resource descriptors */
 
@@ -358,6 +551,7 @@ union acpi_resource_data {
        struct acpi_resource_start_dependent start_dpf;
        struct acpi_resource_io io;
        struct acpi_resource_fixed_io fixed_io;
+       struct acpi_resource_fixed_dma fixed_dma;
        struct acpi_resource_vendor vendor;
        struct acpi_resource_vendor_typed vendor_typed;
        struct acpi_resource_end_tag end_tag;
@@ -370,6 +564,11 @@ union acpi_resource_data {
        struct acpi_resource_extended_address64 ext_address64;
        struct acpi_resource_extended_irq extended_irq;
        struct acpi_resource_generic_register generic_reg;
+       struct acpi_resource_gpio gpio;
+       struct acpi_resource_i2c_serialbus i2c_serial_bus;
+       struct acpi_resource_spi_serialbus spi_serial_bus;
+       struct acpi_resource_uart_serialbus uart_serial_bus;
+       struct acpi_resource_common_serialbus common_serial_bus;
 
        /* Common fields */
 
index f1380287ed4d821474f58a39c372fca6cb5909a1..8e1b92f6f650332e6130486d6b7e7a5bd3f1b3f8 100644 (file)
@@ -255,6 +255,8 @@ struct acpi_table_fadt {
        struct acpi_generic_address xpm_timer_block;    /* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */
        struct acpi_generic_address xgpe0_block;        /* 64-bit Extended General Purpose Event 0 Reg Blk address */
        struct acpi_generic_address xgpe1_block;        /* 64-bit Extended General Purpose Event 1 Reg Blk address */
+       struct acpi_generic_address sleep_control;      /* 64-bit Sleep Control register */
+       struct acpi_generic_address sleep_status;       /* 64-bit Sleep Status register */
 };
 
 /* Masks for FADT Boot Architecture Flags (boot_flags) */
@@ -264,6 +266,7 @@ struct acpi_table_fadt {
 #define ACPI_FADT_NO_VGA            (1<<2)     /* 02: [V4] It is not safe to probe for VGA hardware */
 #define ACPI_FADT_NO_MSI            (1<<3)     /* 03: [V4] Message Signaled Interrupts (MSI) must not be enabled */
 #define ACPI_FADT_NO_ASPM           (1<<4)     /* 04: [V4] PCIe ASPM control must not be enabled */
+#define ACPI_FADT_NO_CMOS_RTC       (1<<5)     /* 05: [V5] No CMOS real-time clock present */
 
 #define FADT2_REVISION_ID               3
 
@@ -289,6 +292,8 @@ struct acpi_table_fadt {
 #define ACPI_FADT_REMOTE_POWER_ON   (1<<17)    /* 17: [V4] System is compatible with remote power on (ACPI 3.0) */
 #define ACPI_FADT_APIC_CLUSTER      (1<<18)    /* 18: [V4] All local APICs must use cluster model (ACPI 3.0) */
 #define ACPI_FADT_APIC_PHYSICAL     (1<<19)    /* 19: [V4] All local x_aPICs must use physical dest mode (ACPI 3.0) */
+#define ACPI_FADT_HW_REDUCED        (1<<20)    /* 20: [V5] ACPI hardware is not implemented (ACPI 5.0) */
+#define ACPI_FADT_LOW_POWER_S0      (1<<21)    /* 21: [V5] S0 power savings are equal or better than S3 (ACPI 5.0) */
 
 /* Values for preferred_profile (Preferred Power Management Profiles) */
 
@@ -299,14 +304,16 @@ enum acpi_prefered_pm_profiles {
        PM_WORKSTATION = 3,
        PM_ENTERPRISE_SERVER = 4,
        PM_SOHO_SERVER = 5,
-       PM_APPLIANCE_PC = 6
+       PM_APPLIANCE_PC = 6,
+       PM_PERFORMANCE_SERVER = 7,
+       PM_TABLET = 8
 };
 
 /* Reset to default packing */
 
 #pragma pack()
 
-#define ACPI_FADT_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_fadt, f)
+#define ACPI_FADT_OFFSET(f)             (u16) ACPI_OFFSET (struct acpi_table_fadt, f)
 
 /*
  * Internal table-related structures
@@ -342,6 +349,7 @@ struct acpi_table_desc {
 
 #include <acpi/actbl1.h>
 #include <acpi/actbl2.h>
+#include <acpi/actbl3.h>
 
 /*
  * Sizes of the various flavors of FADT. We need to look closely
@@ -351,12 +359,15 @@ struct acpi_table_desc {
  * FADT is the bottom line as to what the version really is.
  *
  * For reference, the values below are as follows:
- *     FADT V1  size: 0x74
- *     FADT V2  size: 0x84
- *     FADT V3+ size: 0xF4
+ *     FADT V1  size: 0x074
+ *     FADT V2  size: 0x084
+ *     FADT V3  size: 0x0F4
+ *     FADT V4  size: 0x0F4
+ *     FADT V5  size: 0x10C
  */
 #define ACPI_FADT_V1_SIZE       (u32) (ACPI_FADT_OFFSET (flags) + 4)
 #define ACPI_FADT_V2_SIZE       (u32) (ACPI_FADT_OFFSET (reserved4[0]) + 3)
-#define ACPI_FADT_V3_SIZE       (u32) (sizeof (struct acpi_table_fadt))
+#define ACPI_FADT_V3_SIZE       (u32) (ACPI_FADT_OFFSET (sleep_control))
+#define ACPI_FADT_V5_SIZE       (u32) (sizeof (struct acpi_table_fadt))
 
 #endif                         /* __ACTBL_H__ */
index 7504bc99b29b7359f9ec503a6c0def183c98c2c9..71e747beac8f3e016fa3719f4b75e7706a3b64fb 100644 (file)
@@ -228,7 +228,8 @@ enum acpi_einj_actions {
        ACPI_EINJ_EXECUTE_OPERATION = 5,
        ACPI_EINJ_CHECK_BUSY_STATUS = 6,
        ACPI_EINJ_GET_COMMAND_STATUS = 7,
-       ACPI_EINJ_ACTION_RESERVED = 8,  /* 8 and greater are reserved */
+       ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS = 8,
+       ACPI_EINJ_ACTION_RESERVED = 9,  /* 9 and greater are reserved */
        ACPI_EINJ_TRIGGER_ERROR = 0xFF  /* Except for this value */
 };
 
@@ -240,7 +241,27 @@ enum acpi_einj_instructions {
        ACPI_EINJ_WRITE_REGISTER = 2,
        ACPI_EINJ_WRITE_REGISTER_VALUE = 3,
        ACPI_EINJ_NOOP = 4,
-       ACPI_EINJ_INSTRUCTION_RESERVED = 5      /* 5 and greater are reserved */
+       ACPI_EINJ_FLUSH_CACHELINE = 5,
+       ACPI_EINJ_INSTRUCTION_RESERVED = 6      /* 6 and greater are reserved */
+};
+
+struct acpi_einj_error_type_with_addr {
+       u32 error_type;
+       u32 vendor_struct_offset;
+       u32 flags;
+       u32 apic_id;
+       u64 address;
+       u64 range;
+       u32 pcie_id;
+};
+
+struct acpi_einj_vendor {
+       u32 length;
+       u32 pcie_id;
+       u16 vendor_id;
+       u16 device_id;
+       u8 revision_id;
+       u8 reserved[3];
 };
 
 /* EINJ Trigger Error Action Table */
@@ -275,6 +296,7 @@ enum acpi_einj_command_status {
 #define ACPI_EINJ_PLATFORM_CORRECTABLE      (1<<9)
 #define ACPI_EINJ_PLATFORM_UNCORRECTABLE    (1<<10)
 #define ACPI_EINJ_PLATFORM_FATAL            (1<<11)
+#define ACPI_EINJ_VENDOR_DEFINED            (1<<31)
 
 /*******************************************************************************
  *
@@ -631,7 +653,9 @@ enum acpi_madt_type {
        ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8,
        ACPI_MADT_TYPE_LOCAL_X2APIC = 9,
        ACPI_MADT_TYPE_LOCAL_X2APIC_NMI = 10,
-       ACPI_MADT_TYPE_RESERVED = 11    /* 11 and greater are reserved */
+       ACPI_MADT_TYPE_GENERIC_INTERRUPT = 11,
+       ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR = 12,
+       ACPI_MADT_TYPE_RESERVED = 13    /* 13 and greater are reserved */
 };
 
 /*
@@ -752,11 +776,36 @@ struct acpi_madt_local_x2apic_nmi {
        u8 reserved[3];
 };
 
+/* 11: Generic Interrupt (ACPI 5.0) */
+
+struct acpi_madt_generic_interrupt {
+       struct acpi_subtable_header header;
+       u16 reserved;           /* Reserved - must be zero */
+       u32 gic_id;
+       u32 uid;
+       u32 flags;
+       u32 parking_version;
+       u32 performance_interrupt;
+       u64 parked_address;
+       u64 base_address;
+};
+
+/* 12: Generic Distributor (ACPI 5.0) */
+
+struct acpi_madt_generic_distributor {
+       struct acpi_subtable_header header;
+       u16 reserved;           /* Reserved - must be zero */
+       u32 gic_id;
+       u64 base_address;
+       u32 global_irq_base;
+       u32 reserved2;          /* Reserved - must be zero */
+};
+
 /*
  * Common flags fields for MADT subtables
  */
 
-/* MADT Local APIC flags (lapic_flags) */
+/* MADT Local APIC flags (lapic_flags) and GIC flags */
 
 #define ACPI_MADT_ENABLED           (1)        /* 00: Processor is usable if set */
 
diff --git a/include/acpi/actbl3.h b/include/acpi/actbl3.h
new file mode 100644 (file)
index 0000000..c22ce80
--- /dev/null
@@ -0,0 +1,552 @@
+/******************************************************************************
+ *
+ * Name: actbl3.h - ACPI Table Definitions
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2011, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#ifndef __ACTBL3_H__
+#define __ACTBL3_H__
+
+/*******************************************************************************
+ *
+ * Additional ACPI Tables (3)
+ *
+ * These tables are not consumed directly by the ACPICA subsystem, but are
+ * included here to support device drivers and the AML disassembler.
+ *
+ * The tables in this file are fully defined within the ACPI specification.
+ *
+ ******************************************************************************/
+
+/*
+ * Values for description table header signatures for tables defined in this
+ * file. Useful because they make it more difficult to inadvertently type in
+ * the wrong signature.
+ */
+#define ACPI_SIG_BGRT           "BGRT" /* Boot Graphics Resource Table */
+#define ACPI_SIG_DRTM           "DRTM" /* Dynamic Root of Trust for Measurement table */
+#define ACPI_SIG_FPDT           "FPDT" /* Firmware Performance Data Table */
+#define ACPI_SIG_GTDT           "GTDT" /* Generic Timer Description Table */
+#define ACPI_SIG_MPST           "MPST" /* Memory Power State Table */
+#define ACPI_SIG_PCCT           "PCCT" /* Platform Communications Channel Table */
+#define ACPI_SIG_PMTT           "PMTT" /* Platform Memory Topology Table */
+#define ACPI_SIG_RASF           "RASF" /* RAS Feature table */
+
+#define ACPI_SIG_S3PT           "S3PT" /* S3 Performance (sub)Table */
+#define ACPI_SIG_PCCS           "PCC"  /* PCC Shared Memory Region */
+
+/* Reserved table signatures */
+
+#define ACPI_SIG_CSRT           "CSRT" /* Core System Resources Table */
+#define ACPI_SIG_DBG2           "DBG2" /* Debug Port table 2 */
+#define ACPI_SIG_MATR           "MATR" /* Memory Address Translation Table */
+#define ACPI_SIG_MSDM           "MSDM" /* Microsoft Data Management Table */
+#define ACPI_SIG_WPBT           "WPBT" /* Windows Platform Binary Table */
+
+/*
+ * All tables must be byte-packed to match the ACPI specification, since
+ * the tables are provided by the system BIOS.
+ */
+#pragma pack(1)
+
+/*
+ * Note about bitfields: The u8 type is used for bitfields in ACPI tables.
+ * This is the only type that is even remotely portable. Anything else is not
+ * portable, so do not use any other bitfield types.
+ */
+
+/*******************************************************************************
+ *
+ * BGRT - Boot Graphics Resource Table (ACPI 5.0)
+ *        Version 1
+ *
+ ******************************************************************************/
+
+struct acpi_table_bgrt {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u16 version;
+       u8 status;
+       u8 image_type;
+       u64 image_address;
+       u32 image_offset_x;
+       u32 image_offset_y;
+};
+
+/*******************************************************************************
+ *
+ * DRTM - Dynamic Root of Trust for Measurement table
+ *
+ ******************************************************************************/
+
+struct acpi_table_drtm {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u64 entry_base_address;
+       u64 entry_length;
+       u32 entry_address32;
+       u64 entry_address64;
+       u64 exit_address;
+       u64 log_area_address;
+       u32 log_area_length;
+       u64 arch_dependent_address;
+       u32 flags;
+};
+
+/* 1) Validated Tables List */
+
+struct acpi_drtm_vtl_list {
+       u32 validated_table_list_count;
+};
+
+/* 2) Resources List */
+
+struct acpi_drtm_resource_list {
+       u32 resource_list_count;
+};
+
+/* 3) Platform-specific Identifiers List */
+
+struct acpi_drtm_id_list {
+       u32 id_list_count;
+};
+
+/*******************************************************************************
+ *
+ * FPDT - Firmware Performance Data Table (ACPI 5.0)
+ *        Version 1
+ *
+ ******************************************************************************/
+
+struct acpi_table_fpdt {
+       struct acpi_table_header header;        /* Common ACPI table header */
+};
+
+/* FPDT subtable header */
+
+struct acpi_fpdt_header {
+       u16 type;
+       u8 length;
+       u8 revision;
+};
+
+/* Values for Type field above */
+
+enum acpi_fpdt_type {
+       ACPI_FPDT_TYPE_BOOT = 0,
+       ACPI_FPDT_TYPE_S3PERF = 1,
+};
+
+/*
+ * FPDT subtables
+ */
+
+/* 0: Firmware Basic Boot Performance Record */
+
+struct acpi_fpdt_boot {
+       struct acpi_fpdt_header header;
+       u8 reserved[4];
+       u64 reset_end;
+       u64 load_start;
+       u64 startup_start;
+       u64 exit_services_entry;
+       u64 exit_services_exit;
+};
+
+/* 1: S3 Performance Table Pointer Record */
+
+struct acpi_fpdt_s3pt_ptr {
+       struct acpi_fpdt_header header;
+       u8 reserved[4];
+       u64 address;
+};
+
+/*
+ * S3PT - S3 Performance Table. This table is pointed to by the
+ * FPDT S3 Pointer Record above.
+ */
+struct acpi_table_s3pt {
+       u8 signature[4];        /* "S3PT" */
+       u32 length;
+};
+
+/*
+ * S3PT Subtables
+ */
+struct acpi_s3pt_header {
+       u16 type;
+       u8 length;
+       u8 revision;
+};
+
+/* Values for Type field above */
+
+enum acpi_s3pt_type {
+       ACPI_S3PT_TYPE_RESUME = 0,
+       ACPI_S3PT_TYPE_SUSPEND = 1,
+};
+
+struct acpi_s3pt_resume {
+       struct acpi_s3pt_header header;
+       u32 resume_count;
+       u64 full_resume;
+       u64 average_resume;
+};
+
+struct acpi_s3pt_suspend {
+       struct acpi_s3pt_header header;
+       u64 suspend_start;
+       u64 suspend_end;
+};
+
+/*******************************************************************************
+ *
+ * GTDT - Generic Timer Description Table (ACPI 5.0)
+ *        Version 1
+ *
+ ******************************************************************************/
+
+struct acpi_table_gtdt {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u64 address;
+       u32 flags;
+       u32 secure_pl1_interrupt;
+       u32 secure_pl1_flags;
+       u32 non_secure_pl1_interrupt;
+       u32 non_secure_pl1_flags;
+       u32 virtual_timer_interrupt;
+       u32 virtual_timer_flags;
+       u32 non_secure_pl2_interrupt;
+       u32 non_secure_pl2_flags;
+};
+
+/* Values for Flags field above */
+
+#define ACPI_GTDT_MAPPED_BLOCK_PRESENT      1
+
+/* Values for all "TimerFlags" fields above */
+
+#define ACPI_GTDT_INTERRUPT_MODE            1
+#define ACPI_GTDT_INTERRUPT_POLARITY        2
+
+/*******************************************************************************
+ *
+ * MPST - Memory Power State Table (ACPI 5.0)
+ *        Version 1
+ *
+ ******************************************************************************/
+
+#define ACPI_MPST_CHANNEL_INFO \
+       u16                             reserved1; \
+       u8                              channel_id; \
+       u8                              reserved2; \
+       u16                             power_node_count;
+
+/* Main table */
+
+struct acpi_table_mpst {
+       struct acpi_table_header header;        /* Common ACPI table header */
+        ACPI_MPST_CHANNEL_INFO /* Platform Communication Channel */
+};
+
+/* Memory Platform Communication Channel Info */
+
+struct acpi_mpst_channel {
+       ACPI_MPST_CHANNEL_INFO  /* Platform Communication Channel */
+};
+
+/* Memory Power Node Structure */
+
+struct acpi_mpst_power_node {
+       u8 flags;
+       u8 reserved1;
+       u16 node_id;
+       u32 length;
+       u64 range_address;
+       u64 range_length;
+       u8 num_power_states;
+       u8 num_physical_components;
+       u16 reserved2;
+};
+
+/* Values for Flags field above */
+
+#define ACPI_MPST_ENABLED               1
+#define ACPI_MPST_POWER_MANAGED         2
+#define ACPI_MPST_HOT_PLUG_CAPABLE      4
+
+/* Memory Power State Structure (follows POWER_NODE above) */
+
+struct acpi_mpst_power_state {
+       u8 power_state;
+       u8 info_index;
+};
+
+/* Physical Component ID Structure (follows POWER_STATE above) */
+
+struct acpi_mpst_component {
+       u16 component_id;
+};
+
+/* Memory Power State Characteristics Structure (follows all POWER_NODEs) */
+
+struct acpi_mpst_data_hdr {
+       u16 characteristics_count;
+};
+
+struct acpi_mpst_power_data {
+       u8 revision;
+       u8 flags;
+       u16 reserved1;
+       u32 average_power;
+       u32 power_saving;
+       u64 exit_latency;
+       u64 reserved2;
+};
+
+/* Values for Flags field above */
+
+#define ACPI_MPST_PRESERVE              1
+#define ACPI_MPST_AUTOENTRY             2
+#define ACPI_MPST_AUTOEXIT              4
+
+/* Shared Memory Region (not part of an ACPI table) */
+
+struct acpi_mpst_shared {
+       u32 signature;
+       u16 pcc_command;
+       u16 pcc_status;
+       u16 command_register;
+       u16 status_register;
+       u16 power_state_id;
+       u16 power_node_id;
+       u64 energy_consumed;
+       u64 average_power;
+};
+
+/*******************************************************************************
+ *
+ * PCCT - Platform Communications Channel Table (ACPI 5.0)
+ *        Version 1
+ *
+ ******************************************************************************/
+
+struct acpi_table_pcct {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u32 flags;
+       u32 latency;
+       u32 reserved;
+};
+
+/* Values for Flags field above */
+
+#define ACPI_PCCT_DOORBELL              1
+
+/*
+ * PCCT subtables
+ */
+
+/* 0: Generic Communications Subspace */
+
+struct acpi_pcct_subspace {
+       struct acpi_subtable_header header;
+       u8 reserved[6];
+       u64 base_address;
+       u64 length;
+       struct acpi_generic_address doorbell_register;
+       u64 preserve_mask;
+       u64 write_mask;
+};
+
+/*
+ * PCC memory structures (not part of the ACPI table)
+ */
+
+/* Shared Memory Region */
+
+struct acpi_pcct_shared_memory {
+       u32 signature;
+       u16 command;
+       u16 status;
+};
+
+/*******************************************************************************
+ *
+ * PMTT - Platform Memory Topology Table (ACPI 5.0)
+ *        Version 1
+ *
+ ******************************************************************************/
+
+struct acpi_table_pmtt {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u32 reserved;
+};
+
+/* Common header for PMTT subtables that follow main table */
+
+struct acpi_pmtt_header {
+       u8 type;
+       u8 reserved1;
+       u16 length;
+       u16 flags;
+       u16 reserved2;
+};
+
+/* Values for Type field above */
+
+#define ACPI_PMTT_TYPE_SOCKET           0
+#define ACPI_PMTT_TYPE_CONTROLLER       1
+#define ACPI_PMTT_TYPE_DIMM             2
+#define ACPI_PMTT_TYPE_RESERVED         3      /* 0x03-0xFF are reserved */
+
+/* Values for Flags field above */
+
+#define ACPI_PMTT_TOP_LEVEL             0x0001
+#define ACPI_PMTT_PHYSICAL              0x0002
+#define ACPI_PMTT_MEMORY_TYPE           0x000C
+
+/*
+ * PMTT subtables, correspond to Type in struct acpi_pmtt_header
+ */
+
+/* 0: Socket Structure */
+
+struct acpi_pmtt_socket {
+       struct acpi_pmtt_header header;
+       u16 socket_id;
+       u16 reserved;
+};
+
+/* 1: Memory Controller subtable */
+
+struct acpi_pmtt_controller {
+       struct acpi_pmtt_header header;
+       u32 read_latency;
+       u32 write_latency;
+       u32 read_bandwidth;
+       u32 write_bandwidth;
+       u16 access_width;
+       u16 alignment;
+       u16 reserved;
+       u16 domain_count;
+};
+
+/* 1a: Proximity Domain substructure */
+
+struct acpi_pmtt_domain {
+       u32 proximity_domain;
+};
+
+/* 2: Physical Component Identifier (DIMM) */
+
+struct acpi_pmtt_physical_component {
+       struct acpi_pmtt_header header;
+       u16 component_id;
+       u16 reserved;
+       u32 memory_size;
+       u32 bios_handle;
+};
+
+/*******************************************************************************
+ *
+ * RASF - RAS Feature Table (ACPI 5.0)
+ *        Version 1
+ *
+ ******************************************************************************/
+
+struct acpi_table_rasf {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u8 channel_id[12];
+};
+
+/* RASF Platform Communication Channel Shared Memory Region */
+
+struct acpi_rasf_shared_memory {
+       u32 signature;
+       u16 command;
+       u16 status;
+       u64 requested_address;
+       u64 requested_length;
+       u64 actual_address;
+       u64 actual_length;
+       u16 flags;
+       u8 speed;
+};
+
+/* Masks for Flags and Speed fields above */
+
+#define ACPI_RASF_SCRUBBER_RUNNING      1
+#define ACPI_RASF_SPEED                 (7<<1)
+
+/* Channel Commands */
+
+enum acpi_rasf_commands {
+       ACPI_RASF_GET_RAS_CAPABILITIES = 1,
+       ACPI_RASF_GET_PATROL_PARAMETERS = 2,
+       ACPI_RASF_START_PATROL_SCRUBBER = 3,
+       ACPI_RASF_STOP_PATROL_SCRUBBER = 4
+};
+
+/* Channel Command flags */
+
+#define ACPI_RASF_GENERATE_SCI          (1<<15)
+
+/* Status values */
+
+enum acpi_rasf_status {
+       ACPI_RASF_SUCCESS = 0,
+       ACPI_RASF_NOT_VALID = 1,
+       ACPI_RASF_NOT_SUPPORTED = 2,
+       ACPI_RASF_BUSY = 3,
+       ACPI_RASF_FAILED = 4,
+       ACPI_RASF_ABORTED = 5,
+       ACPI_RASF_INVALID_DATA = 6
+};
+
+/* Status flags */
+
+#define ACPI_RASF_COMMAND_COMPLETE      (1)
+#define ACPI_RASF_SCI_DOORBELL          (1<<1)
+#define ACPI_RASF_ERROR                 (1<<2)
+#define ACPI_RASF_STATUS                (0x1F<<3)
+
+/* Reset to default packing */
+
+#pragma pack()
+
+#endif                         /* __ACTBL3_H__ */
index ed73f6705c860d2bc8c28db91b7191c13c144b31..d5dee7ce9474ee88c4bf3cda01339e74067311ad 100644 (file)
@@ -712,8 +712,10 @@ typedef u8 acpi_adr_space_type;
 #define ACPI_ADR_SPACE_CMOS             (acpi_adr_space_type) 5
 #define ACPI_ADR_SPACE_PCI_BAR_TARGET   (acpi_adr_space_type) 6
 #define ACPI_ADR_SPACE_IPMI             (acpi_adr_space_type) 7
+#define ACPI_ADR_SPACE_GPIO             (acpi_adr_space_type) 8
+#define ACPI_ADR_SPACE_GSBUS            (acpi_adr_space_type) 9
 
-#define ACPI_NUM_PREDEFINED_REGIONS     8
+#define ACPI_NUM_PREDEFINED_REGIONS     10
 
 /*
  * Special Address Spaces
@@ -957,6 +959,14 @@ acpi_status(*acpi_adr_space_handler) (u32 function,
 
 #define ACPI_DEFAULT_HANDLER            NULL
 
+/* Special Context data for generic_serial_bus/general_purpose_io (ACPI 5.0) */
+
+struct acpi_connection_info {
+       u8 *connection;
+       u16 length;
+       u8 access_length;
+};
+
 typedef
 acpi_status(*acpi_adr_space_setup) (acpi_handle region_handle,
                                    u32 function,
index 51a527d24a8a8b03879dfaa3b059d59d32c8991b..04f349d8da7339427002e82b887f903f96e0157e 100644 (file)
 
 #ifdef __KERNEL__
 
-extern int hest_disable;
+extern bool hest_disable;
 extern int erst_disable;
 #ifdef CONFIG_ACPI_APEI_GHES
-extern int ghes_disable;
+extern bool ghes_disable;
 #else
 #define ghes_disable 1
 #endif
index d466c8d8826de5f65cd8b1f5d60e04e125a41799..1ff4e221cb4dfc705e58ff7155835c0c68459dc9 100644 (file)
@@ -177,6 +177,10 @@ extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *labe
 extern int gpio_request_array(const struct gpio *array, size_t num);
 extern void gpio_free_array(const struct gpio *array, size_t num);
 
+/* bindings for managed devices that want to request gpios */
+int devm_gpio_request(struct device *dev, unsigned gpio, const char *label);
+void devm_gpio_free(struct device *dev, unsigned int gpio);
+
 #ifdef CONFIG_GPIO_SYSFS
 
 /*
index cdf8251bfb6cfc33d559a358ed0fe17d1de9c2d6..835632a3b468f3c69432db1ea8729ed7dbf13e01 100644 (file)
@@ -1,12 +1,6 @@
 #ifndef __ASM_GENERIC_PARAM_H
 #define __ASM_GENERIC_PARAM_H
 
-#ifdef __KERNEL__
-# define HZ            CONFIG_HZ       /* Internal kernel timer frequency */
-# define USER_HZ       100             /* some user interfaces are */
-# define CLOCKS_PER_SEC        (USER_HZ)       /* in "ticks" like times() */
-#endif
-
 #ifndef HZ
 #define HZ 100
 #endif
 
 #define MAXHOSTNAMELEN 64      /* max length of hostname */
 
+#ifdef __KERNEL__
+# undef HZ
+# define HZ            CONFIG_HZ       /* Internal kernel timer frequency */
+# define USER_HZ       100             /* some user interfaces are */
+# define CLOCKS_PER_SEC        (USER_HZ)       /* in "ticks" like times() */
+#endif
+
 #endif /* __ASM_GENERIC_PARAM_H */
index e58fa777fa09abe91831026852bfe21bdfa4f8d4..f96a5b58a975c6ccc1ebadecf746f84dd47a38ea 100644 (file)
@@ -139,6 +139,20 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
                __tlb_remove_tlb_entry(tlb, ptep, address);     \
        } while (0)
 
+/**
+ * tlb_remove_pmd_tlb_entry - remember a pmd mapping for later tlb invalidation
+ * This is a nop so far, because only x86 needs it.
+ */
+#ifndef __tlb_remove_pmd_tlb_entry
+#define __tlb_remove_pmd_tlb_entry(tlb, pmdp, address) do {} while (0)
+#endif
+
+#define tlb_remove_pmd_tlb_entry(tlb, pmdp, address)           \
+       do {                                                    \
+               tlb->need_flush = 1;                            \
+               __tlb_remove_pmd_tlb_entry(tlb, pmdp, address); \
+       } while (0)
+
 #define pte_free_tlb(tlb, ptep, address)                       \
        do {                                                    \
                tlb->need_flush = 1;                            \
index 63e4fce6728829bb98c9630220fc75f21d19814e..4cd4be26722c14fb58d7f86f0a2a4988798cda68 100644 (file)
@@ -453,7 +453,7 @@ struct drm_encoder_funcs {
 #define DRM_CONNECTOR_MAX_UMODES 16
 #define DRM_CONNECTOR_MAX_PROPERTY 16
 #define DRM_CONNECTOR_LEN 32
-#define DRM_CONNECTOR_MAX_ENCODER 2
+#define DRM_CONNECTOR_MAX_ENCODER 3
 
 /**
  * drm_encoder - central DRM encoder structure
index 3e4737fa6cce71710982762cb80efab516033319..d537aa0ec414a2dc70b84580a0799096e601ee3c 100644 (file)
@@ -146,6 +146,9 @@ extern void acct_exit_ns(struct pid_namespace *);
  *
  */
 
+#undef ACCT_VERSION
+#undef AHZ
+
 #ifdef CONFIG_BSD_PROCESS_ACCT_V3
 #define ACCT_VERSION   3
 #define AHZ            100
index 627a3a42e4d8e3ba015ad32a6bf01f779c356943..3f968665899b9cadeef825dab03666d04eac3c64 100644 (file)
@@ -310,6 +310,11 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
                                             u32 *mask, u32 req);
 extern void acpi_early_init(void);
 
+extern int acpi_nvs_register(__u64 start, __u64 size);
+
+extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
+                                   void *data);
+
 #else  /* !CONFIG_ACPI */
 
 #define acpi_disabled 1
@@ -352,15 +357,18 @@ static inline int acpi_table_parse(char *id,
 {
        return -1;
 }
-#endif /* !CONFIG_ACPI */
 
-#ifdef CONFIG_ACPI_SLEEP
-int suspend_nvs_register(unsigned long start, unsigned long size);
-#else
-static inline int suspend_nvs_register(unsigned long a, unsigned long b)
+static inline int acpi_nvs_register(__u64 start, __u64 size)
 {
        return 0;
 }
-#endif
+
+static inline int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
+                                          void *data)
+{
+       return 0;
+}
+
+#endif /* !CONFIG_ACPI */
 
 #endif /*_LINUX_ACPI_H*/
index 4afd7102459d7fbdef49be451141e16b0591f5e7..b0ffa219993ec2be82a01854718d5e1269ef05bb 100644 (file)
@@ -12,4 +12,7 @@ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
 
 void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size);
 
+int acpi_os_map_generic_address(struct acpi_generic_address *addr);
+void acpi_os_unmap_generic_address(struct acpi_generic_address *addr);
+
 #endif
index 21114810c7c0b687afa01f188e50d99bdbdafecb..0101e9c17fa1ec022c75f3655646c16aca9dd948 100644 (file)
@@ -30,6 +30,7 @@ struct dma_chan;
  * @cd_invert: true if the gpio_cd pin value is active low
  * @capabilities: the capabilities of the block as implemented in
  * this platform, signify anything MMC_CAP_* from mmc/host.h
+ * @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h
  * @dma_filter: function used to select an appropriate RX and TX
  * DMA channel to be used for DMA, if and only if you're deploying the
  * generic DMA engine
@@ -52,6 +53,7 @@ struct mmci_platform_data {
        int     gpio_cd;
        bool    cd_invert;
        unsigned long capabilities;
+       unsigned long capabilities2;
        bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
        void *dma_rx_param;
        void *dma_tx_param;
index 2412af944f1f584dcc611e17b910e8f55eb79cfc..fb83c0453489930064067d975104b916eef674a0 100644 (file)
@@ -7,7 +7,7 @@ struct pl061_platform_data {
        unsigned        gpio_base;
 
        /* number of the first IRQ.
-        * If the IRQ functionality in not desired this must be set to NO_IRQ.
+        * If the IRQ functionality in not desired this must be set to 0.
         */
        unsigned        irq_base;
 
index 9eabffbc4e50c4b2ae7a1049970d7f7bc39f12ed..033f6aa670de5086ba64dcde7ee6ab7c80e269a7 100644 (file)
@@ -134,7 +134,7 @@ struct pl08x_txd {
        struct dma_async_tx_descriptor tx;
        struct list_head node;
        struct list_head dsg_list;
-       enum dma_data_direction direction;
+       enum dma_transfer_direction direction;
        dma_addr_t llis_bus;
        struct pl08x_lli *llis_va;
        /* Default cctl value for LLIs */
@@ -197,7 +197,7 @@ struct pl08x_dma_chan {
        dma_addr_t dst_addr;
        u32 src_cctl;
        u32 dst_cctl;
-       enum dma_data_direction runtime_direction;
+       enum dma_transfer_direction runtime_direction;
        dma_cookie_t lc;
        struct list_head pend_list;
        struct pl08x_txd *at;
index 426ab9f4dd853b18d3e8df1b6a3fd2831fec0a57..9ff7a2c48b508103576d175d88fed1c5b3593592 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <linux/types.h>
 #include <linux/elf-em.h>
+#include <linux/ptrace.h>
 
 /* The netlink messages for the audit system is divided into blocks:
  * 1000 - 1099 are for commanding the audit system
  * AUDIT_UNUSED_BITS is updated if need be. */
 #define AUDIT_UNUSED_BITS      0x07FFFC00
 
+/* AUDIT_FIELD_COMPARE rule list */
+#define AUDIT_COMPARE_UID_TO_OBJ_UID   1
+#define AUDIT_COMPARE_GID_TO_OBJ_GID   2
+#define AUDIT_COMPARE_EUID_TO_OBJ_UID  3
+#define AUDIT_COMPARE_EGID_TO_OBJ_GID  4
+#define AUDIT_COMPARE_AUID_TO_OBJ_UID  5
+#define AUDIT_COMPARE_SUID_TO_OBJ_UID  6
+#define AUDIT_COMPARE_SGID_TO_OBJ_GID  7
+#define AUDIT_COMPARE_FSUID_TO_OBJ_UID 8
+#define AUDIT_COMPARE_FSGID_TO_OBJ_GID 9
+
+#define AUDIT_COMPARE_UID_TO_AUID      10
+#define AUDIT_COMPARE_UID_TO_EUID      11
+#define AUDIT_COMPARE_UID_TO_FSUID     12
+#define AUDIT_COMPARE_UID_TO_SUID      13
+
+#define AUDIT_COMPARE_AUID_TO_FSUID    14
+#define AUDIT_COMPARE_AUID_TO_SUID     15
+#define AUDIT_COMPARE_AUID_TO_EUID     16
+
+#define AUDIT_COMPARE_EUID_TO_SUID     17
+#define AUDIT_COMPARE_EUID_TO_FSUID    18
+
+#define AUDIT_COMPARE_SUID_TO_FSUID    19
+
+#define AUDIT_COMPARE_GID_TO_EGID      20
+#define AUDIT_COMPARE_GID_TO_FSGID     21
+#define AUDIT_COMPARE_GID_TO_SGID      22
+
+#define AUDIT_COMPARE_EGID_TO_FSGID    23
+#define AUDIT_COMPARE_EGID_TO_SGID     24
+#define AUDIT_COMPARE_SGID_TO_FSGID    25
+
+#define AUDIT_MAX_FIELD_COMPARE                AUDIT_COMPARE_SGID_TO_FSGID
 
 /* Rule fields */
                                /* These are useful when checking the
 #define AUDIT_PERM     106
 #define AUDIT_DIR      107
 #define AUDIT_FILETYPE 108
+#define AUDIT_OBJ_UID  109
+#define AUDIT_OBJ_GID  110
+#define AUDIT_FIELD_COMPARE    111
 
 #define AUDIT_ARG0      200
 #define AUDIT_ARG1      (AUDIT_ARG0+1)
@@ -408,28 +446,24 @@ struct audit_field {
        void                            *lsm_rule;
 };
 
-#define AUDITSC_INVALID 0
-#define AUDITSC_SUCCESS 1
-#define AUDITSC_FAILURE 2
-#define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS )
 extern int __init audit_register_class(int class, unsigned *list);
 extern int audit_classify_syscall(int abi, unsigned syscall);
 extern int audit_classify_arch(int arch);
 #ifdef CONFIG_AUDITSYSCALL
 /* These are defined in auditsc.c */
                                /* Public API */
-extern void audit_finish_fork(struct task_struct *child);
 extern int  audit_alloc(struct task_struct *task);
-extern void audit_free(struct task_struct *task);
-extern void audit_syscall_entry(int arch,
-                               int major, unsigned long a0, unsigned long a1,
-                               unsigned long a2, unsigned long a3);
-extern void audit_syscall_exit(int failed, long return_code);
+extern void __audit_free(struct task_struct *task);
+extern void __audit_syscall_entry(int arch,
+                                 int major, unsigned long a0, unsigned long a1,
+                                 unsigned long a2, unsigned long a3);
+extern void __audit_syscall_exit(int ret_success, long ret_value);
 extern void __audit_getname(const char *name);
 extern void audit_putname(const char *name);
 extern void __audit_inode(const char *name, const struct dentry *dentry);
 extern void __audit_inode_child(const struct dentry *dentry,
                                const struct inode *parent);
+extern void __audit_seccomp(unsigned long syscall);
 extern void __audit_ptrace(struct task_struct *t);
 
 static inline int audit_dummy_context(void)
@@ -437,6 +471,27 @@ static inline int audit_dummy_context(void)
        void *p = current->audit_context;
        return !p || *(int *)p;
 }
+static inline void audit_free(struct task_struct *task)
+{
+       if (unlikely(task->audit_context))
+               __audit_free(task);
+}
+static inline void audit_syscall_entry(int arch, int major, unsigned long a0,
+                                      unsigned long a1, unsigned long a2,
+                                      unsigned long a3)
+{
+       if (unlikely(!audit_dummy_context()))
+               __audit_syscall_entry(arch, major, a0, a1, a2, a3);
+}
+static inline void audit_syscall_exit(void *pt_regs)
+{
+       if (unlikely(current->audit_context)) {
+               int success = is_syscall_success(pt_regs);
+               int return_code = regs_return_value(pt_regs);
+
+               __audit_syscall_exit(success, return_code);
+       }
+}
 static inline void audit_getname(const char *name)
 {
        if (unlikely(!audit_dummy_context()))
@@ -453,6 +508,12 @@ static inline void audit_inode_child(const struct dentry *dentry,
 }
 void audit_core_dumps(long signr);
 
+static inline void audit_seccomp(unsigned long syscall)
+{
+       if (unlikely(!audit_dummy_context()))
+               __audit_seccomp(syscall);
+}
+
 static inline void audit_ptrace(struct task_struct *t)
 {
        if (unlikely(!audit_dummy_context()))
@@ -463,17 +524,16 @@ static inline void audit_ptrace(struct task_struct *t)
 extern unsigned int audit_serial(void);
 extern int auditsc_get_stamp(struct audit_context *ctx,
                              struct timespec *t, unsigned int *serial);
-extern int  audit_set_loginuid(struct task_struct *task, uid_t loginuid);
+extern int  audit_set_loginuid(uid_t loginuid);
 #define audit_get_loginuid(t) ((t)->loginuid)
 #define audit_get_sessionid(t) ((t)->sessionid)
 extern void audit_log_task_context(struct audit_buffer *ab);
 extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp);
 extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode);
-extern int audit_bprm(struct linux_binprm *bprm);
-extern void audit_socketcall(int nargs, unsigned long *args);
-extern int audit_sockaddr(int len, void *addr);
+extern int __audit_bprm(struct linux_binprm *bprm);
+extern void __audit_socketcall(int nargs, unsigned long *args);
+extern int __audit_sockaddr(int len, void *addr);
 extern void __audit_fd_pair(int fd1, int fd2);
-extern int audit_set_macxattr(const char *name);
 extern void __audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr);
 extern void __audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout);
 extern void __audit_mq_notify(mqd_t mqdes, const struct sigevent *notification);
@@ -499,6 +559,23 @@ static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid
        if (unlikely(!audit_dummy_context()))
                __audit_ipc_set_perm(qbytes, uid, gid, mode);
 }
+static inline int audit_bprm(struct linux_binprm *bprm)
+{
+       if (unlikely(!audit_dummy_context()))
+               return __audit_bprm(bprm);
+       return 0;
+}
+static inline void audit_socketcall(int nargs, unsigned long *args)
+{
+       if (unlikely(!audit_dummy_context()))
+               __audit_socketcall(nargs, args);
+}
+static inline int audit_sockaddr(int len, void *addr)
+{
+       if (unlikely(!audit_dummy_context()))
+               return __audit_sockaddr(len, addr);
+       return 0;
+}
 static inline void audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr)
 {
        if (unlikely(!audit_dummy_context()))
@@ -544,12 +621,11 @@ static inline void audit_mmap_fd(int fd, int flags)
 
 extern int audit_n_rules;
 extern int audit_signals;
-#else
-#define audit_finish_fork(t)
+#else /* CONFIG_AUDITSYSCALL */
 #define audit_alloc(t) ({ 0; })
 #define audit_free(t) do { ; } while (0)
 #define audit_syscall_entry(ta,a,b,c,d,e) do { ; } while (0)
-#define audit_syscall_exit(f,r) do { ; } while (0)
+#define audit_syscall_exit(r) do { ; } while (0)
 #define audit_dummy_context() 1
 #define audit_getname(n) do { ; } while (0)
 #define audit_putname(n) do { ; } while (0)
@@ -558,6 +634,7 @@ extern int audit_signals;
 #define audit_inode(n,d) do { (void)(d); } while (0)
 #define audit_inode_child(i,p) do { ; } while (0)
 #define audit_core_dumps(i) do { ; } while (0)
+#define audit_seccomp(i) do { ; } while (0)
 #define auditsc_get_stamp(c,t,s) (0)
 #define audit_get_loginuid(t) (-1)
 #define audit_get_sessionid(t) (-1)
@@ -568,7 +645,6 @@ extern int audit_signals;
 #define audit_socketcall(n,a) ((void)0)
 #define audit_fd_pair(n,a) ((void)0)
 #define audit_sockaddr(len, addr) ({ 0; })
-#define audit_set_macxattr(n) do { ; } while (0)
 #define audit_mq_open(o,m,a) ((void)0)
 #define audit_mq_sendrecv(d,l,p,t) ((void)0)
 #define audit_mq_notify(d,n) ((void)0)
@@ -579,7 +655,7 @@ extern int audit_signals;
 #define audit_ptrace(t) ((void)0)
 #define audit_n_rules 0
 #define audit_signals 0
-#endif
+#endif /* CONFIG_AUDITSYSCALL */
 
 #ifdef CONFIG_AUDIT
 /* These are defined in audit.c */
index f4b8346b1a331f90fc9f29431b84b9176e4e6acb..83c209f39493adf3ef4ae659c2cc46b3770c2948 100644 (file)
@@ -162,7 +162,7 @@ struct bcma_driver {
 
        int (*probe)(struct bcma_device *dev);
        void (*remove)(struct bcma_device *dev);
-       int (*suspend)(struct bcma_device *dev, pm_message_t state);
+       int (*suspend)(struct bcma_device *dev);
        int (*resume)(struct bcma_device *dev);
        void (*shutdown)(struct bcma_device *dev);
 
index 847994aef0e9755a3a39d76dd42f87c9f43d23be..129a9c097958f098827abe2243ab6fe1c033ca95 100644 (file)
@@ -515,24 +515,64 @@ extern void bio_integrity_init(void);
 
 #else /* CONFIG_BLK_DEV_INTEGRITY */
 
-#define bio_integrity(a)               (0)
-#define bioset_integrity_create(a, b)  (0)
-#define bio_integrity_prep(a)          (0)
-#define bio_integrity_enabled(a)       (0)
+static inline int bio_integrity(struct bio *bio)
+{
+       return 0;
+}
+
+static inline int bio_integrity_enabled(struct bio *bio)
+{
+       return 0;
+}
+
+static inline int bioset_integrity_create(struct bio_set *bs, int pool_size)
+{
+       return 0;
+}
+
+static inline void bioset_integrity_free (struct bio_set *bs)
+{
+       return;
+}
+
+static inline int bio_integrity_prep(struct bio *bio)
+{
+       return 0;
+}
+
+static inline void bio_integrity_free(struct bio *bio, struct bio_set *bs)
+{
+       return;
+}
+
 static inline int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
                                      gfp_t gfp_mask, struct bio_set *bs)
 {
        return 0;
 }
-#define bioset_integrity_free(a)       do { } while (0)
-#define bio_integrity_free(a, b)       do { } while (0)
-#define bio_integrity_endio(a, b)      do { } while (0)
-#define bio_integrity_advance(a, b)    do { } while (0)
-#define bio_integrity_trim(a, b, c)    do { } while (0)
-#define bio_integrity_split(a, b, c)   do { } while (0)
-#define bio_integrity_set_tag(a, b, c) do { } while (0)
-#define bio_integrity_get_tag(a, b, c) do { } while (0)
-#define bio_integrity_init(a)          do { } while (0)
+
+static inline void bio_integrity_split(struct bio *bio, struct bio_pair *bp,
+                                      int sectors)
+{
+       return;
+}
+
+static inline void bio_integrity_advance(struct bio *bio,
+                                        unsigned int bytes_done)
+{
+       return;
+}
+
+static inline void bio_integrity_trim(struct bio *bio, unsigned int offset,
+                                     unsigned int sectors)
+{
+       return;
+}
+
+static inline void bio_integrity_init(void)
+{
+       return;
+}
 
 #endif /* CONFIG_BLK_DEV_INTEGRITY */
 
index 94acd8172b5bfcb0986014916533501f90ac047d..6c6a1f008065984821435a50f12fd4c08d17fe42 100644 (file)
@@ -111,10 +111,14 @@ struct request {
         * Three pointers are available for the IO schedulers, if they need
         * more they have to dynamically allocate it.  Flush requests are
         * never put on the IO scheduler. So let the flush fields share
-        * space with the three elevator_private pointers.
+        * space with the elevator data.
         */
        union {
-               void *elevator_private[3];
+               struct {
+                       struct io_cq            *icq;
+                       void                    *priv[2];
+               } elv;
+
                struct {
                        unsigned int            seq;
                        struct list_head        list;
@@ -310,6 +314,12 @@ struct request_queue {
         */
        unsigned long           queue_flags;
 
+       /*
+        * ida allocated id for this queue.  Used to index queues from
+        * ioctx.
+        */
+       int                     id;
+
        /*
         * queue needs bounce pages for pages above this limit
         */
@@ -351,6 +361,8 @@ struct request_queue {
        struct timer_list       timeout;
        struct list_head        timeout_list;
 
+       struct list_head        icq_list;
+
        struct queue_limits     limits;
 
        /*
@@ -387,6 +399,9 @@ struct request_queue {
        /* Throttle data */
        struct throtl_data *td;
 #endif
+#ifdef CONFIG_LOCKDEP
+       int                     ioc_release_depth;
+#endif
 };
 
 #define QUEUE_FLAG_QUEUED      1       /* uses generic tag queueing */
@@ -481,6 +496,7 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q)
 
 #define blk_queue_tagged(q)    test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags)
 #define blk_queue_stopped(q)   test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags)
+#define blk_queue_dead(q)      test_bit(QUEUE_FLAG_DEAD, &(q)->queue_flags)
 #define blk_queue_nomerges(q)  test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags)
 #define blk_queue_noxmerges(q) \
        test_bit(QUEUE_FLAG_NOXMERGES, &(q)->queue_flags)
@@ -660,7 +676,6 @@ extern void __blk_put_request(struct request_queue *, struct request *);
 extern struct request *blk_get_request(struct request_queue *, int, gfp_t);
 extern struct request *blk_make_request(struct request_queue *, struct bio *,
                                        gfp_t);
-extern void blk_insert_request(struct request_queue *, struct request *, int, void *);
 extern void blk_requeue_request(struct request_queue *, struct request *);
 extern void blk_add_request_payload(struct request *rq, struct page *page,
                unsigned int len);
@@ -675,6 +690,9 @@ extern int blk_insert_cloned_request(struct request_queue *q,
                                     struct request *rq);
 extern void blk_delay_queue(struct request_queue *, unsigned long);
 extern void blk_recount_segments(struct request_queue *, struct bio *);
+extern int scsi_verify_blk_ioctl(struct block_device *, unsigned int);
+extern int scsi_cmd_blk_ioctl(struct block_device *, fmode_t,
+                             unsigned int, void __user *);
 extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t,
                          unsigned int, void __user *);
 extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,
@@ -826,6 +844,7 @@ extern void blk_queue_io_min(struct request_queue *q, unsigned int min);
 extern void blk_limits_io_opt(struct queue_limits *limits, unsigned int opt);
 extern void blk_queue_io_opt(struct request_queue *q, unsigned int opt);
 extern void blk_set_default_limits(struct queue_limits *lim);
+extern void blk_set_stacking_limits(struct queue_limits *lim);
 extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                            sector_t offset);
 extern int bdev_stack_limits(struct queue_limits *t, struct block_device *bdev,
@@ -856,7 +875,7 @@ extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatte
 extern void blk_dump_rq_flags(struct request *, char *);
 extern long nr_blockdev_pages(void);
 
-int blk_get_queue(struct request_queue *);
+bool __must_check blk_get_queue(struct request_queue *);
 struct request_queue *blk_alloc_queue(gfp_t);
 struct request_queue *blk_alloc_queue_node(gfp_t, int);
 extern void blk_put_queue(struct request_queue *);
@@ -1279,19 +1298,70 @@ queue_max_integrity_segments(struct request_queue *q)
 
 #else /* CONFIG_BLK_DEV_INTEGRITY */
 
-#define blk_integrity_rq(rq)                   (0)
-#define blk_rq_count_integrity_sg(a, b)                (0)
-#define blk_rq_map_integrity_sg(a, b, c)       (0)
-#define bdev_get_integrity(a)                  (0)
-#define blk_get_integrity(a)                   (0)
-#define blk_integrity_compare(a, b)            (0)
-#define blk_integrity_register(a, b)           (0)
-#define blk_integrity_unregister(a)            do { } while (0)
-#define blk_queue_max_integrity_segments(a, b) do { } while (0)
-#define queue_max_integrity_segments(a)                (0)
-#define blk_integrity_merge_rq(a, b, c)                (0)
-#define blk_integrity_merge_bio(a, b, c)       (0)
-#define blk_integrity_is_initialized(a)                (0)
+struct bio;
+struct block_device;
+struct gendisk;
+struct blk_integrity;
+
+static inline int blk_integrity_rq(struct request *rq)
+{
+       return 0;
+}
+static inline int blk_rq_count_integrity_sg(struct request_queue *q,
+                                           struct bio *b)
+{
+       return 0;
+}
+static inline int blk_rq_map_integrity_sg(struct request_queue *q,
+                                         struct bio *b,
+                                         struct scatterlist *s)
+{
+       return 0;
+}
+static inline struct blk_integrity *bdev_get_integrity(struct block_device *b)
+{
+       return 0;
+}
+static inline struct blk_integrity *blk_get_integrity(struct gendisk *disk)
+{
+       return NULL;
+}
+static inline int blk_integrity_compare(struct gendisk *a, struct gendisk *b)
+{
+       return 0;
+}
+static inline int blk_integrity_register(struct gendisk *d,
+                                        struct blk_integrity *b)
+{
+       return 0;
+}
+static inline void blk_integrity_unregister(struct gendisk *d)
+{
+}
+static inline void blk_queue_max_integrity_segments(struct request_queue *q,
+                                                   unsigned int segs)
+{
+}
+static inline unsigned short queue_max_integrity_segments(struct request_queue *q)
+{
+       return 0;
+}
+static inline int blk_integrity_merge_rq(struct request_queue *rq,
+                                        struct request *r1,
+                                        struct request *r2)
+{
+       return 0;
+}
+static inline int blk_integrity_merge_bio(struct request_queue *rq,
+                                         struct request *r,
+                                         struct bio *b)
+{
+       return 0;
+}
+static inline bool blk_integrity_is_initialized(struct gendisk *g)
+{
+       return 0;
+}
 
 #endif /* CONFIG_BLK_DEV_INTEGRITY */
 
index a63d13d84ad8289efc8b4ceda7049441a0fd6f5b..12d52dedb2290f6789c7dbf621f93b3620a2fbd2 100644 (file)
@@ -380,7 +380,6 @@ struct user_namespace;
 struct user_namespace *current_user_ns(void);
 
 extern const kernel_cap_t __cap_empty_set;
-extern const kernel_cap_t __cap_full_set;
 extern const kernel_cap_t __cap_init_eff_set;
 
 /*
@@ -544,9 +543,10 @@ extern bool has_capability(struct task_struct *t, int cap);
 extern bool has_ns_capability(struct task_struct *t,
                              struct user_namespace *ns, int cap);
 extern bool has_capability_noaudit(struct task_struct *t, int cap);
+extern bool has_ns_capability_noaudit(struct task_struct *t,
+                                     struct user_namespace *ns, int cap);
 extern bool capable(int cap);
 extern bool ns_capable(struct user_namespace *ns, int cap);
-extern bool task_ns_capable(struct task_struct *t, int cap);
 extern bool nsown_capable(int cap);
 
 /* audit system wants to get cap info from files as well */
index 59e4028e833d0ffe7c1fa11844cc5ebd027886f9..3fd17c24922150bc4f3936335baf008d2170e2a6 100644 (file)
 # define inline                inline          __attribute__((always_inline))
 # define __inline__    __inline__      __attribute__((always_inline))
 # define __inline      __inline        __attribute__((always_inline))
+#else
+/* A lot of inline functions can cause havoc with function tracing */
+# define inline                inline          notrace
+# define __inline__    __inline__      notrace
+# define __inline      __inline        notrace
 #endif
 
 #define __deprecated                   __attribute__((deprecated))
index 7453cfd593c813632c3cf103ea918c471266613e..7201ce4280caceb594e4cd11cf6ca4e7a072efee 100644 (file)
@@ -152,7 +152,7 @@ extern int braille_register_console(struct console *, int index,
                char *console_options, char *braille_options);
 extern int braille_unregister_console(struct console *);
 extern void console_sysfs_notify(void);
-extern int console_suspend_enabled;
+extern bool console_suspend_enabled;
 
 /* Suspend and resume console messages over PM events */
 extern void suspend_console(void);
index 23f81de518298dda6349ee3f44d425045cf9f62b..712abcc205ae0f4a68bda6c4da51e22a7b4000d3 100644 (file)
@@ -186,7 +186,14 @@ struct cpuidle_governor {
 extern int cpuidle_register_governor(struct cpuidle_governor *gov);
 extern void cpuidle_unregister_governor(struct cpuidle_governor *gov);
 
+#ifdef CONFIG_INTEL_IDLE
+extern int intel_idle_cpu_init(int cpu);
 #else
+static inline int intel_idle_cpu_init(int cpu) { return -1; }
+#endif
+
+#else
+static inline int intel_idle_cpu_init(int cpu) { return -1; }
 
 static inline int cpuidle_register_governor(struct cpuidle_governor *gov)
 {return 0;}
index 5c4abce94ad1665803c79fd61a501e6969477029..b936763f2236be16254d23380e49d99f08f82dc4 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/kexec.h>
 #include <linux/device.h>
 #include <linux/proc_fs.h>
+#include <linux/elf.h>
 
 #define ELFCORE_ADDR_MAX       (-1ULL)
 #define ELFCORE_ADDR_ERR       (-2ULL)
index 40308969ed005239b1b27889c8eccf3f89d6fcbe..adadf71a73271347a5c170df3b1c5490da073910 100644 (file)
@@ -358,10 +358,12 @@ static inline void put_cred(const struct cred *_cred)
 #define current_security()     (current_cred_xxx(security))
 
 #ifdef CONFIG_USER_NS
-#define current_user_ns() (current_cred_xxx(user_ns))
+#define current_user_ns()      (current_cred_xxx(user_ns))
+#define task_user_ns(task)     (task_cred_xxx((task), user_ns))
 #else
 extern struct user_namespace init_user_ns;
-#define current_user_ns() (&init_user_ns)
+#define current_user_ns()      (&init_user_ns)
+#define task_user_ns(task)     (&init_user_ns)
 #endif
 
 
index 6a3e6385d3f38fb63a113847b2e36bc51ebf8c33..9f9865ff781e3d69915b1839394e302874bd6462 100644 (file)
@@ -5,6 +5,9 @@
  * Copyright (C) 1996 Paul Mackerras.
  */
 
+#ifndef _LINUX_CUDA_H
+#define _LINUX_CUDA_H
+
 /* CUDA commands (2nd byte) */
 #define CUDA_WARM_START                0
 #define CUDA_AUTOPOLL          1
@@ -34,3 +37,5 @@ extern int cuda_request(struct adb_request *req,
 extern void cuda_poll(void);
 
 #endif /* __KERNEL */
+
+#endif /* _LINUX_CUDA_H */
index 31f73220e7d71a888e0fcb895f2de54b25ecea29..d64a55b23afda64f4b490ef475e092edcf3c32b7 100644 (file)
@@ -242,6 +242,7 @@ extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
 extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *);
 extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
 extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
+extern struct dentry *d_find_any_alias(struct inode *inode);
 extern struct dentry * d_obtain_alias(struct inode *);
 extern void shrink_dcache_sb(struct super_block *);
 extern void shrink_dcache_parent(struct dentry *);
index efae755017d7de93d4bc40b28c29488aa959bf46..b01558b15814f6d94be21272d385df3a1c4d23b5 100644 (file)
@@ -46,7 +46,7 @@ struct signature_hdr {
        char            mpi[0];
 } __packed;
 
-#if defined(CONFIG_DIGSIG) || defined(CONFIG_DIGSIG_MODULE)
+#if defined(CONFIG_SIGNATURE) || defined(CONFIG_SIGNATURE_MODULE)
 
 int digsig_verify(struct key *keyring, const char *sig, int siglen,
                                        const char *digest, int digestlen);
@@ -59,6 +59,6 @@ static inline int digsig_verify(struct key *keyring, const char *sig,
        return -EOPNOTSUPP;
 }
 
-#endif /* CONFIG_DIGSIG */
+#endif /* CONFIG_SIGNATURE */
 
 #endif /* _DIGSIG_H */
diff --git a/include/linux/display.h b/include/linux/display.h
deleted file mode 100644 (file)
index 3bf70d6..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *  Copyright (C) 2006 James Simmons <jsimmons@infradead.org>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or (at
- *  your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#ifndef _LINUX_DISPLAY_H
-#define _LINUX_DISPLAY_H
-
-#include <linux/device.h>
-
-struct display_device;
-
-/* This structure defines all the properties of a Display. */
-struct display_driver {
-       int  (*set_contrast)(struct display_device *, unsigned int);
-       int  (*get_contrast)(struct display_device *);
-       void (*suspend)(struct display_device *, pm_message_t state);
-       void (*resume)(struct display_device *);
-       int  (*probe)(struct display_device *, void *);
-       int  (*remove)(struct display_device *);
-       int  max_contrast;
-};
-
-struct display_device {
-       struct module *owner;                   /* Owner module */
-       struct display_driver *driver;
-       struct device *parent;                  /* This is the parent */
-       struct device *dev;                     /* This is this display device */
-       struct mutex lock;
-       void *priv_data;
-       char type[16];
-       char *name;
-       int idx;
-};
-
-extern struct display_device *display_device_register(struct display_driver *driver,
-                                       struct device *dev, void *devdata);
-extern void display_device_unregister(struct display_device *dev);
-
-extern int probe_edid(struct display_device *dev, void *devdata);
-
-#define to_display_device(obj) container_of(obj, struct display_device, class_dev)
-
-#endif
index 75f53f874b24a0c0abb790f501f2f60ace48e17e..679b349d9b66695f65bb3597b2a530e3e9709600 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <linux/device.h>
 #include <linux/uio.h>
-#include <linux/dma-direction.h>
 #include <linux/scatterlist.h>
 #include <linux/bitmap.h>
 #include <asm/page.h>
@@ -72,11 +71,93 @@ enum dma_transaction_type {
        DMA_ASYNC_TX,
        DMA_SLAVE,
        DMA_CYCLIC,
+       DMA_INTERLEAVE,
+/* last transaction type for creation of the capabilities mask */
+       DMA_TX_TYPE_END,
 };
 
-/* last transaction type for creation of the capabilities mask */
-#define DMA_TX_TYPE_END (DMA_CYCLIC + 1)
+/**
+ * enum dma_transfer_direction - dma transfer mode and direction indicator
+ * @DMA_MEM_TO_MEM: Async/Memcpy mode
+ * @DMA_MEM_TO_DEV: Slave mode & From Memory to Device
+ * @DMA_DEV_TO_MEM: Slave mode & From Device to Memory
+ * @DMA_DEV_TO_DEV: Slave mode & From Device to Device
+ */
+enum dma_transfer_direction {
+       DMA_MEM_TO_MEM,
+       DMA_MEM_TO_DEV,
+       DMA_DEV_TO_MEM,
+       DMA_DEV_TO_DEV,
+       DMA_TRANS_NONE,
+};
+
+/**
+ * Interleaved Transfer Request
+ * ----------------------------
+ * A chunk is collection of contiguous bytes to be transfered.
+ * The gap(in bytes) between two chunks is called inter-chunk-gap(ICG).
+ * ICGs may or maynot change between chunks.
+ * A FRAME is the smallest series of contiguous {chunk,icg} pairs,
+ *  that when repeated an integral number of times, specifies the transfer.
+ * A transfer template is specification of a Frame, the number of times
+ *  it is to be repeated and other per-transfer attributes.
+ *
+ * Practically, a client driver would have ready a template for each
+ *  type of transfer it is going to need during its lifetime and
+ *  set only 'src_start' and 'dst_start' before submitting the requests.
+ *
+ *
+ *  |      Frame-1        |       Frame-2       | ~ |       Frame-'numf'  |
+ *  |====....==.===...=...|====....==.===...=...| ~ |====....==.===...=...|
+ *
+ *    ==  Chunk size
+ *    ... ICG
+ */
+
+/**
+ * struct data_chunk - Element of scatter-gather list that makes a frame.
+ * @size: Number of bytes to read from source.
+ *       size_dst := fn(op, size_src), so doesn't mean much for destination.
+ * @icg: Number of bytes to jump after last src/dst address of this
+ *      chunk and before first src/dst address for next chunk.
+ *      Ignored for dst(assumed 0), if dst_inc is true and dst_sgl is false.
+ *      Ignored for src(assumed 0), if src_inc is true and src_sgl is false.
+ */
+struct data_chunk {
+       size_t size;
+       size_t icg;
+};
 
+/**
+ * struct dma_interleaved_template - Template to convey DMAC the transfer pattern
+ *      and attributes.
+ * @src_start: Bus address of source for the first chunk.
+ * @dst_start: Bus address of destination for the first chunk.
+ * @dir: Specifies the type of Source and Destination.
+ * @src_inc: If the source address increments after reading from it.
+ * @dst_inc: If the destination address increments after writing to it.
+ * @src_sgl: If the 'icg' of sgl[] applies to Source (scattered read).
+ *             Otherwise, source is read contiguously (icg ignored).
+ *             Ignored if src_inc is false.
+ * @dst_sgl: If the 'icg' of sgl[] applies to Destination (scattered write).
+ *             Otherwise, destination is filled contiguously (icg ignored).
+ *             Ignored if dst_inc is false.
+ * @numf: Number of frames in this template.
+ * @frame_size: Number of chunks in a frame i.e, size of sgl[].
+ * @sgl: Array of {chunk,icg} pairs that make up a frame.
+ */
+struct dma_interleaved_template {
+       dma_addr_t src_start;
+       dma_addr_t dst_start;
+       enum dma_transfer_direction dir;
+       bool src_inc;
+       bool dst_inc;
+       bool src_sgl;
+       bool dst_sgl;
+       size_t numf;
+       size_t frame_size;
+       struct data_chunk sgl[0];
+};
 
 /**
  * enum dma_ctrl_flags - DMA flags to augment operation preparation,
@@ -269,7 +350,7 @@ enum dma_slave_buswidth {
  * struct, if applicable.
  */
 struct dma_slave_config {
-       enum dma_data_direction direction;
+       enum dma_transfer_direction direction;
        dma_addr_t src_addr;
        dma_addr_t dst_addr;
        enum dma_slave_buswidth src_addr_width;
@@ -433,6 +514,7 @@ struct dma_tx_state {
  * @device_prep_dma_cyclic: prepare a cyclic dma operation suitable for audio.
  *     The function takes a buffer of size buf_len. The callback function will
  *     be called after period_len bytes have been transferred.
+ * @device_prep_interleaved_dma: Transfer expression in a generic way.
  * @device_control: manipulate all pending operations on a channel, returns
  *     zero or error code
  * @device_tx_status: poll for transaction completion, the optional
@@ -492,11 +574,14 @@ struct dma_device {
 
        struct dma_async_tx_descriptor *(*device_prep_slave_sg)(
                struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned int sg_len, enum dma_transfer_direction direction,
                unsigned long flags);
        struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(
                struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
-               size_t period_len, enum dma_data_direction direction);
+               size_t period_len, enum dma_transfer_direction direction);
+       struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)(
+               struct dma_chan *chan, struct dma_interleaved_template *xt,
+               unsigned long flags);
        int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                unsigned long arg);
 
@@ -522,7 +607,7 @@ static inline int dmaengine_slave_config(struct dma_chan *chan,
 
 static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single(
        struct dma_chan *chan, void *buf, size_t len,
-       enum dma_data_direction dir, unsigned long flags)
+       enum dma_transfer_direction dir, unsigned long flags)
 {
        struct scatterlist sg;
        sg_init_one(&sg, buf, len);
index 1b1094c35e4fd979f6b49d35b9f6c725ee0eac9b..cb4428ab81ed5627bf2ea7ed3dc2c4ea414bfce9 100644 (file)
@@ -72,7 +72,7 @@ typedef enum fe_caps {
 
 struct dvb_frontend_info {
        char       name[128];
-       fe_type_t  type;
+       fe_type_t  type;                        /* DEPRECATED. Use DTV_ENUM_DELSYS instead */
        __u32      frequency_min;
        __u32      frequency_max;
        __u32      frequency_stepsize;
@@ -181,6 +181,7 @@ typedef enum fe_transmit_mode {
        TRANSMISSION_MODE_32K,
 } fe_transmit_mode_t;
 
+#if defined(__DVB_CORE__) || !defined (__KERNEL__)
 typedef enum fe_bandwidth {
        BANDWIDTH_8_MHZ,
        BANDWIDTH_7_MHZ,
@@ -190,7 +191,7 @@ typedef enum fe_bandwidth {
        BANDWIDTH_10_MHZ,
        BANDWIDTH_1_712_MHZ,
 } fe_bandwidth_t;
-
+#endif
 
 typedef enum fe_guard_interval {
        GUARD_INTERVAL_1_32,
@@ -213,6 +214,7 @@ typedef enum fe_hierarchy {
 } fe_hierarchy_t;
 
 
+#if defined(__DVB_CORE__) || !defined (__KERNEL__)
 struct dvb_qpsk_parameters {
        __u32           symbol_rate;  /* symbol rate in Symbols per second */
        fe_code_rate_t  fec_inner;    /* forward error correction (see above) */
@@ -251,11 +253,11 @@ struct dvb_frontend_parameters {
        } u;
 };
 
-
 struct dvb_frontend_event {
        fe_status_t status;
        struct dvb_frontend_parameters parameters;
 };
+#endif
 
 /* S2API Commands */
 #define DTV_UNDEFINED          0
@@ -316,7 +318,9 @@ struct dvb_frontend_event {
 
 #define DTV_DVBT2_PLP_ID       43
 
-#define DTV_MAX_COMMAND                                DTV_DVBT2_PLP_ID
+#define DTV_ENUM_DELSYS                44
+
+#define DTV_MAX_COMMAND                                DTV_ENUM_DELSYS
 
 typedef enum fe_pilot {
        PILOT_ON,
@@ -333,7 +337,7 @@ typedef enum fe_rolloff {
 
 typedef enum fe_delivery_system {
        SYS_UNDEFINED,
-       SYS_DVBC_ANNEX_AC,
+       SYS_DVBC_ANNEX_A,
        SYS_DVBC_ANNEX_B,
        SYS_DVBT,
        SYS_DSS,
@@ -350,8 +354,13 @@ typedef enum fe_delivery_system {
        SYS_DAB,
        SYS_DVBT2,
        SYS_TURBO,
+       SYS_DVBC_ANNEX_C,
 } fe_delivery_system_t;
 
+
+#define SYS_DVBC_ANNEX_AC      SYS_DVBC_ANNEX_A
+
+
 struct dtv_cmds_h {
        char    *name;          /* A display name for debugging purposes */
 
index 66594b1d5d7b01a766c359ce96d3e6dbc290c984..0559e2bd38f96e54df84936a78bac5cc7fba5365 100644 (file)
@@ -24,6 +24,6 @@
 #define _DVBVERSION_H_
 
 #define DVB_API_VERSION 5
-#define DVB_API_VERSION_MINOR 4
+#define DVB_API_VERSION_MINOR 5
 
 #endif /*_DVBVERSION_H_*/
index 4bfe0a2f7d50cc218bce24040154286a582aaf94..f2c64f92c4a006394e21e022bcf6b5c03590c930 100644 (file)
@@ -127,7 +127,7 @@ struct dw_cyclic_desc {
 
 struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
                dma_addr_t buf_addr, size_t buf_len, size_t period_len,
-               enum dma_data_direction direction);
+               enum dma_transfer_direction direction);
 void dw_dma_cyclic_free(struct dma_chan *chan);
 int dw_dma_cyclic_start(struct dma_chan *chan);
 void dw_dma_cyclic_stop(struct dma_chan *chan);
index 1d0f7a2ff73b22c0dc38a2a88a11081980e5a5be..c24f3d7fbf1e4543f3159155618cab9186e600d9 100644 (file)
@@ -5,6 +5,8 @@
 
 #ifdef CONFIG_BLOCK
 
+struct io_cq;
+
 typedef int (elevator_merge_fn) (struct request_queue *, struct request **,
                                 struct bio *);
 
@@ -24,6 +26,8 @@ typedef struct request *(elevator_request_list_fn) (struct request_queue *, stru
 typedef void (elevator_completed_req_fn) (struct request_queue *, struct request *);
 typedef int (elevator_may_queue_fn) (struct request_queue *, int);
 
+typedef void (elevator_init_icq_fn) (struct io_cq *);
+typedef void (elevator_exit_icq_fn) (struct io_cq *);
 typedef int (elevator_set_req_fn) (struct request_queue *, struct request *, gfp_t);
 typedef void (elevator_put_req_fn) (struct request *);
 typedef void (elevator_activate_req_fn) (struct request_queue *, struct request *);
@@ -56,6 +60,9 @@ struct elevator_ops
        elevator_request_list_fn *elevator_former_req_fn;
        elevator_request_list_fn *elevator_latter_req_fn;
 
+       elevator_init_icq_fn *elevator_init_icq_fn;     /* see iocontext.h */
+       elevator_exit_icq_fn *elevator_exit_icq_fn;     /* ditto */
+
        elevator_set_req_fn *elevator_set_req_fn;
        elevator_put_req_fn *elevator_put_req_fn;
 
@@ -63,7 +70,6 @@ struct elevator_ops
 
        elevator_init_fn *elevator_init_fn;
        elevator_exit_fn *elevator_exit_fn;
-       void (*trim)(struct io_context *);
 };
 
 #define ELV_NAME_MAX   (16)
@@ -79,11 +85,20 @@ struct elv_fs_entry {
  */
 struct elevator_type
 {
-       struct list_head list;
+       /* managed by elevator core */
+       struct kmem_cache *icq_cache;
+
+       /* fields provided by elevator implementation */
        struct elevator_ops ops;
+       size_t icq_size;        /* see iocontext.h */
+       size_t icq_align;       /* ditto */
        struct elv_fs_entry *elevator_attrs;
        char elevator_name[ELV_NAME_MAX];
        struct module *elevator_owner;
+
+       /* managed by elevator core */
+       char icq_cache_name[ELV_NAME_MAX + 5];  /* elvname + "_io_cq" */
+       struct list_head list;
 };
 
 /*
@@ -91,10 +106,9 @@ struct elevator_type
  */
 struct elevator_queue
 {
-       struct elevator_ops *ops;
+       struct elevator_type *type;
        void *elevator_data;
        struct kobject kobj;
-       struct elevator_type *elevator_type;
        struct mutex sysfs_lock;
        struct hlist_head *hash;
        unsigned int registered:1;
@@ -129,7 +143,7 @@ extern void elv_drain_elevator(struct request_queue *);
 /*
  * io scheduler registration
  */
-extern void elv_register(struct elevator_type *);
+extern int elv_register(struct elevator_type *);
 extern void elv_unregister(struct elevator_type *);
 
 /*
@@ -197,22 +211,5 @@ enum {
        INIT_LIST_HEAD(&(rq)->csd.list);        \
        } while (0)
 
-/*
- * io context count accounting
- */
-#define elv_ioc_count_mod(name, __val) this_cpu_add(name, __val)
-#define elv_ioc_count_inc(name)        this_cpu_inc(name)
-#define elv_ioc_count_dec(name)        this_cpu_dec(name)
-
-#define elv_ioc_count_read(name)                               \
-({                                                             \
-       unsigned long __val = 0;                                \
-       int __cpu;                                              \
-       smp_wmb();                                              \
-       for_each_possible_cpu(__cpu)                            \
-               __val += per_cpu(name, __cpu);                  \
-       __val;                                                  \
-})
-
 #endif /* CONFIG_BLOCK */
 #endif
index 31f0508d7da7a3274e207cc3389edb824ed77fd3..999b4f52e8e5c88b84fafb9e439bb5a931ef118c 100644 (file)
@@ -7,15 +7,6 @@
 #include <asm/elf.h>
 #endif
 
-struct file;
-
-#ifndef elf_read_implies_exec
-  /* Executables for which elf_read_implies_exec() returns TRUE will
-     have the READ_IMPLIES_EXEC personality flag set automatically.
-     Override in asm/elf.h as needed.  */
-# define elf_read_implies_exec(ex, have_pt_gnu_stack)  0
-#endif
-
 /* 32-bit ELF base types. */
 typedef __u32  Elf32_Addr;
 typedef __u16  Elf32_Half;
@@ -414,6 +405,13 @@ typedef struct elf64_note {
 } Elf64_Nhdr;
 
 #ifdef __KERNEL__
+#ifndef elf_read_implies_exec
+  /* Executables for which elf_read_implies_exec() returns TRUE will
+     have the READ_IMPLIES_EXEC personality flag set automatically.
+     Override in asm/elf.h as needed.  */
+# define elf_read_implies_exec(ex, have_pt_gnu_stack)  0
+#endif
+
 #if ELF_CLASS == ELFCLASS32
 
 extern Elf32_Dyn _DYNAMIC [];
@@ -437,6 +435,8 @@ extern Elf64_Dyn _DYNAMIC [];
 #endif
 
 /* Optional callbacks to write extra ELF notes. */
+struct file;
+
 #ifndef ARCH_HAVE_EXTRA_ELF_NOTES
 static inline int elf_coredump_extra_notes_size(void) { return 0; }
 static inline int elf_coredump_extra_notes_write(struct file *file,
index f362733186a5a6f4a1657b0a85ee32e158095ed2..657ab55beda014c15b33833e84dc7e1496d06abf 100644 (file)
@@ -61,6 +61,7 @@ struct file;
 static inline void eventpoll_init_file(struct file *file)
 {
        INIT_LIST_HEAD(&file->f_ep_links);
+       INIT_LIST_HEAD(&file->f_tfile_llink);
 }
 
 
index 1d6836c498ddc626dab613da7099aed0244a1e17..c18122f40543406a46ceb8ac3802a92ec4d2869b 100644 (file)
@@ -45,6 +45,7 @@
 #define FB_TYPE_INTERLEAVED_PLANES     2       /* Interleaved planes   */
 #define FB_TYPE_TEXT                   3       /* Text/attributes      */
 #define FB_TYPE_VGA_PLANES             4       /* EGA/VGA planes       */
+#define FB_TYPE_FOURCC                 5       /* Type identified by a V4L2 FOURCC */
 
 #define FB_AUX_TEXT_MDA                0       /* Monochrome text */
 #define FB_AUX_TEXT_CGA                1       /* CGA/EGA/VGA Color text */
@@ -69,6 +70,7 @@
 #define FB_VISUAL_PSEUDOCOLOR          3       /* Pseudo color (like atari) */
 #define FB_VISUAL_DIRECTCOLOR          4       /* Direct color */
 #define FB_VISUAL_STATIC_PSEUDOCOLOR   5       /* Pseudo color readonly */
+#define FB_VISUAL_FOURCC               6       /* Visual identified by a V4L2 FOURCC */
 
 #define FB_ACCEL_NONE          0       /* no hardware accelerator      */
 #define FB_ACCEL_ATARIBLITT    1       /* Atari Blitter                */
 
 #define FB_ACCEL_PUV3_UNIGFX   0xa0    /* PKUnity-v3 Unigfx            */
 
+#define FB_CAP_FOURCC          1       /* Device supports FOURCC-based formats */
+
 struct fb_fix_screeninfo {
        char id[16];                    /* identification string eg "TT Builtin" */
        unsigned long smem_start;       /* Start of frame buffer mem */
@@ -171,7 +175,8 @@ struct fb_fix_screeninfo {
        __u32 mmio_len;                 /* Length of Memory Mapped I/O  */
        __u32 accel;                    /* Indicate to driver which     */
                                        /*  specific chip/card we have  */
-       __u16 reserved[3];              /* Reserved for future compatibility */
+       __u16 capabilities;             /* see FB_CAP_*                 */
+       __u16 reserved[2];              /* Reserved for future compatibility */
 };
 
 /* Interpretation of offset for color fields: All offsets are from the right,
@@ -246,8 +251,8 @@ struct fb_var_screeninfo {
        __u32 yoffset;                  /* resolution                   */
 
        __u32 bits_per_pixel;           /* guess what                   */
-       __u32 grayscale;                /* != 0 Graylevels instead of colors */
-
+       __u32 grayscale;                /* 0 = color, 1 = grayscale,    */
+                                       /* >1 = FOURCC                  */
        struct fb_bitfield red;         /* bitfield in fb mem if true color, */
        struct fb_bitfield green;       /* else only length is significant */
        struct fb_bitfield blue;
@@ -273,7 +278,8 @@ struct fb_var_screeninfo {
        __u32 sync;                     /* see FB_SYNC_*                */
        __u32 vmode;                    /* see FB_VMODE_*               */
        __u32 rotate;                   /* angle we rotate counter clockwise */
-       __u32 reserved[5];              /* Reserved for future compatibility */
+       __u32 colorspace;               /* colorspace for FOURCC-based modes */
+       __u32 reserved[4];              /* Reserved for future compatibility */
 };
 
 struct fb_cmap {
index 7aacf31418fed291df3591c07ef252a26aa4c62c..0244082d42c5794ba7c2b7b5a3d6a0181f73c6b9 100644 (file)
@@ -319,6 +319,7 @@ struct inodes_stat_t {
 #define BLKPBSZGET _IO(0x12,123)
 #define BLKDISCARDZEROES _IO(0x12,124)
 #define BLKSECDISCARD _IO(0x12,125)
+#define BLKROTATIONAL _IO(0x12,126)
 
 #define BMAP_IOCTL 1           /* obsolete - kept for compatibility */
 #define FIBMAP    _IO(0x00,1)  /* bmap access */
@@ -525,6 +526,7 @@ enum positive_aop_returns {
 struct page;
 struct address_space;
 struct writeback_control;
+enum migrate_mode;
 
 struct iov_iter {
        const struct iovec *iov;
@@ -609,9 +611,12 @@ struct address_space_operations {
                        loff_t offset, unsigned long nr_segs);
        int (*get_xip_mem)(struct address_space *, pgoff_t, int,
                                                void **, unsigned long *);
-       /* migrate the contents of a page to the specified target */
+       /*
+        * migrate the contents of a page to the specified target. If sync
+        * is false, it must not block.
+        */
        int (*migratepage) (struct address_space *,
-                       struct page *, struct page *);
+                       struct page *, struct page *, enum migrate_mode);
        int (*launder_page) (struct page *);
        int (*is_partially_uptodate) (struct page *, read_descriptor_t *,
                                        unsigned long);
@@ -656,6 +661,7 @@ struct address_space {
         * must be enforced here for CRIS, to let the least significant bit
         * of struct page's "mapping" pointer be used for PAGE_MAPPING_ANON.
         */
+struct request_queue;
 
 struct block_device {
        dev_t                   bd_dev;  /* not a kdev_t - it's a search key */
@@ -678,6 +684,7 @@ struct block_device {
        unsigned                bd_part_count;
        int                     bd_invalidated;
        struct gendisk *        bd_disk;
+       struct request_queue *  bd_queue;
        struct list_head        bd_list;
        /*
         * Private data.  You must have bd_claim'ed the block_device
@@ -1001,6 +1008,7 @@ struct file {
 #ifdef CONFIG_EPOLL
        /* Used by fs/eventpoll.c to link all the hooks to this file */
        struct list_head        f_ep_links;
+       struct list_head        f_tfile_llink;
 #endif /* #ifdef CONFIG_EPOLL */
        struct address_space    *f_mapping;
 #ifdef CONFIG_DEBUG_WRITECOUNT
@@ -2536,7 +2544,8 @@ extern int generic_check_addressable(unsigned, u64);
 
 #ifdef CONFIG_MIGRATION
 extern int buffer_migrate_page(struct address_space *,
-                               struct page *, struct page *);
+                               struct page *, struct page *,
+                               enum migrate_mode);
 #else
 #define buffer_migrate_page NULL
 #endif
index 26eafcef75be715b0e59d29429bc3a680c6b9bc0..028e26f0bf0817b3b37f874d59d17991c9007d1e 100644 (file)
@@ -133,6 +133,8 @@ struct ftrace_func_command {
 int ftrace_arch_code_modify_prepare(void);
 int ftrace_arch_code_modify_post_process(void);
 
+void ftrace_bug(int err, unsigned long ip);
+
 struct seq_file;
 
 struct ftrace_probe_ops {
@@ -161,7 +163,6 @@ extern int ftrace_text_reserved(void *start, void *end);
 
 enum {
        FTRACE_FL_ENABLED       = (1 << 30),
-       FTRACE_FL_FREE          = (1 << 31),
 };
 
 #define FTRACE_FL_MASK         (0x3UL << 30)
@@ -172,10 +173,7 @@ struct dyn_ftrace {
                unsigned long           ip; /* address of mcount call-site */
                struct dyn_ftrace       *freelist;
        };
-       union {
-               unsigned long           flags;
-               struct dyn_ftrace       *newlist;
-       };
+       unsigned long           flags;
        struct dyn_arch_ftrace          arch;
 };
 
@@ -190,6 +188,56 @@ void ftrace_set_global_notrace(unsigned char *buf, int len, int reset);
 int register_ftrace_command(struct ftrace_func_command *cmd);
 int unregister_ftrace_command(struct ftrace_func_command *cmd);
 
+enum {
+       FTRACE_UPDATE_CALLS             = (1 << 0),
+       FTRACE_DISABLE_CALLS            = (1 << 1),
+       FTRACE_UPDATE_TRACE_FUNC        = (1 << 2),
+       FTRACE_START_FUNC_RET           = (1 << 3),
+       FTRACE_STOP_FUNC_RET            = (1 << 4),
+};
+
+enum {
+       FTRACE_UPDATE_IGNORE,
+       FTRACE_UPDATE_MAKE_CALL,
+       FTRACE_UPDATE_MAKE_NOP,
+};
+
+enum {
+       FTRACE_ITER_FILTER      = (1 << 0),
+       FTRACE_ITER_NOTRACE     = (1 << 1),
+       FTRACE_ITER_PRINTALL    = (1 << 2),
+       FTRACE_ITER_DO_HASH     = (1 << 3),
+       FTRACE_ITER_HASH        = (1 << 4),
+       FTRACE_ITER_ENABLED     = (1 << 5),
+};
+
+void arch_ftrace_update_code(int command);
+
+struct ftrace_rec_iter;
+
+struct ftrace_rec_iter *ftrace_rec_iter_start(void);
+struct ftrace_rec_iter *ftrace_rec_iter_next(struct ftrace_rec_iter *iter);
+struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter);
+
+int ftrace_update_record(struct dyn_ftrace *rec, int enable);
+int ftrace_test_record(struct dyn_ftrace *rec, int enable);
+void ftrace_run_stop_machine(int command);
+int ftrace_location(unsigned long ip);
+
+extern ftrace_func_t ftrace_trace_function;
+
+int ftrace_regex_open(struct ftrace_ops *ops, int flag,
+                 struct inode *inode, struct file *file);
+ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf,
+                           size_t cnt, loff_t *ppos);
+ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf,
+                            size_t cnt, loff_t *ppos);
+loff_t ftrace_regex_lseek(struct file *file, loff_t offset, int origin);
+int ftrace_regex_release(struct inode *inode, struct file *file);
+
+void __init
+ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable);
+
 /* defined in arch */
 extern int ftrace_ip_converted(unsigned long ip);
 extern int ftrace_dyn_arch_init(void *data);
@@ -284,6 +332,25 @@ static inline int ftrace_text_reserved(void *start, void *end)
 {
        return 0;
 }
+
+/*
+ * Again users of functions that have ftrace_ops may not
+ * have them defined when ftrace is not enabled, but these
+ * functions may still be called. Use a macro instead of inline.
+ */
+#define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; })
+#define ftrace_set_early_filter(ops, buf, enable) do { } while (0)
+
+static inline ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf,
+                           size_t cnt, loff_t *ppos) { return -ENODEV; }
+static inline ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf,
+                            size_t cnt, loff_t *ppos) { return -ENODEV; }
+static inline loff_t ftrace_regex_lseek(struct file *file, loff_t offset, int origin)
+{
+       return -ENODEV;
+}
+static inline int
+ftrace_regex_release(struct inode *inode, struct file *file) { return -ENODEV; }
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
 /* totally disable ftrace - can not re-enable after this */
index 464cff52686092c0f862f551b2db53ed3050b629..8ba2c9460b28fb90bfee024aa8f73601f6c4cf68 100644 (file)
  *
  * 7.17
  *  - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK
+ *
+ * 7.18
+ *  - add FUSE_IOCTL_DIR flag
+ *  - add FUSE_NOTIFY_DELETE
  */
 
 #ifndef _LINUX_FUSE_H
@@ -81,7 +85,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 17
+#define FUSE_KERNEL_MINOR_VERSION 18
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -214,6 +218,7 @@ struct fuse_file_lock {
  * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
  * FUSE_IOCTL_RETRY: retry with new iovecs
  * FUSE_IOCTL_32BIT: 32bit ioctl
+ * FUSE_IOCTL_DIR: is a directory
  *
  * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
  */
@@ -221,6 +226,7 @@ struct fuse_file_lock {
 #define FUSE_IOCTL_UNRESTRICTED        (1 << 1)
 #define FUSE_IOCTL_RETRY       (1 << 2)
 #define FUSE_IOCTL_32BIT       (1 << 3)
+#define FUSE_IOCTL_DIR         (1 << 4)
 
 #define FUSE_IOCTL_MAX_IOV     256
 
@@ -283,6 +289,7 @@ enum fuse_notify_code {
        FUSE_NOTIFY_INVAL_ENTRY = 3,
        FUSE_NOTIFY_STORE = 4,
        FUSE_NOTIFY_RETRIEVE = 5,
+       FUSE_NOTIFY_DELETE = 6,
        FUSE_NOTIFY_CODE_MAX,
 };
 
@@ -606,6 +613,13 @@ struct fuse_notify_inval_entry_out {
        __u32   padding;
 };
 
+struct fuse_notify_delete_out {
+       __u64   parent;
+       __u64   child;
+       __u32   namelen;
+       __u32   padding;
+};
+
 struct fuse_notify_store_out {
        __u64   nodeid;
        __u64   offset;
index 4f4462974c142cd47e00eddabf4e8d64802a72f3..b148087f49a62921d40b66b39224d33239047626 100644 (file)
@@ -22,6 +22,8 @@
 #define GFS2_LIVE_LOCK         1
 #define GFS2_TRANS_LOCK                2
 #define GFS2_RENAME_LOCK       3
+#define GFS2_CONTROL_LOCK      4
+#define GFS2_MOUNTED_LOCK      5
 
 /* Format numbers for various metadata types */
 
index a9ace9c32507e31a851bcd719d0a56759b3a4428..1b921299abc420f1e258b614aa319964cd98942c 100644 (file)
@@ -18,7 +18,7 @@ extern struct page *follow_trans_huge_pmd(struct mm_struct *mm,
                                          unsigned int flags);
 extern int zap_huge_pmd(struct mmu_gather *tlb,
                        struct vm_area_struct *vma,
-                       pmd_t *pmd);
+                       pmd_t *pmd, unsigned long addr);
 extern int mincore_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                        unsigned long addr, unsigned long end,
                        unsigned char *vec);
index 114c0f6fc63d8f7c818f79459995c6844736993a..78d3465251d6cd8e38e47903622cd0e3bad9e42d 100644 (file)
@@ -652,10 +652,12 @@ struct twl4030_power_data {
        unsigned num;
        struct twl4030_resconfig *resource_config;
 #define TWL4030_RESCONFIG_UNDEF        ((u8)-1)
+       bool use_poweroff;      /* Board is wired for TWL poweroff */
 };
 
 extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
 extern int twl4030_remove_script(u8 flags);
+extern void twl4030_power_off(void);
 
 struct twl4030_codec_data {
        unsigned int digimic_delay; /* in ms */
index 34e8d52c192509ec3908bd74376410f7170a8628..f1362b5447fcbcf6935e49aec748675562eb0b12 100644 (file)
@@ -22,7 +22,7 @@ struct inet_diag_sockid {
 
 /* Request structure */
 
-struct inet_diag_req_compat {
+struct inet_diag_req {
        __u8    idiag_family;           /* Family of addresses. */
        __u8    idiag_src_len;
        __u8    idiag_dst_len;
@@ -34,7 +34,7 @@ struct inet_diag_req_compat {
        __u32   idiag_dbs;              /* Tables to dump (NI) */
 };
 
-struct inet_diag_req {
+struct inet_diag_req_v2 {
        __u8    sdiag_family;
        __u8    sdiag_protocol;
        __u8    idiag_ext;
@@ -143,12 +143,12 @@ struct netlink_callback;
 struct inet_diag_handler {
        void                    (*dump)(struct sk_buff *skb,
                                        struct netlink_callback *cb,
-                                       struct inet_diag_req *r,
+                                       struct inet_diag_req_v2 *r,
                                        struct nlattr *bc);
 
        int                     (*dump_one)(struct sk_buff *in_skb,
                                        const struct nlmsghdr *nlh,
-                                       struct inet_diag_req *req);
+                                       struct inet_diag_req_v2 *req);
 
        void                    (*idiag_get_info)(struct sock *sk,
                                                  struct inet_diag_msg *r,
@@ -158,15 +158,15 @@ struct inet_diag_handler {
 
 struct inet_connection_sock;
 int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
-                             struct sk_buff *skb, struct inet_diag_req *req,
+                             struct sk_buff *skb, struct inet_diag_req_v2 *req,
                              u32 pid, u32 seq, u16 nlmsg_flags,
                              const struct nlmsghdr *unlh);
 void inet_diag_dump_icsk(struct inet_hashinfo *h, struct sk_buff *skb,
-               struct netlink_callback *cb, struct inet_diag_req *r,
+               struct netlink_callback *cb, struct inet_diag_req_v2 *r,
                struct nlattr *bc);
 int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo,
                struct sk_buff *in_skb, const struct nlmsghdr *nlh,
-               struct inet_diag_req *req);
+               struct inet_diag_req_v2 *req);
 
 int inet_diag_bc_sk(const struct nlattr *_bc, struct sock *sk);
 
index 9146f39cdddfe97bd61473d54a72a33bfad3a04f..6b951095a42f606e8d48fa948047bfaaf6771c4f 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_INIT_H
 
 #include <linux/compiler.h>
+#include <linux/types.h>
 
 /* These macros are used to mark some functions or 
  * initialized data (doesn't apply to uninitialized data)
@@ -156,7 +157,7 @@ void prepare_namespace(void);
 
 extern void (*late_time_init)(void);
 
-extern int initcall_debug;
+extern bool initcall_debug;
 
 #endif
   
index 5037a0ad231245b3b2779c81bf76f912df467879..7e1371c4bccf93143e6234e15b11924b4375274f 100644 (file)
@@ -3,32 +3,92 @@
 
 #include <linux/radix-tree.h>
 #include <linux/rcupdate.h>
+#include <linux/workqueue.h>
 
-struct cfq_queue;
-struct cfq_ttime {
-       unsigned long last_end_request;
-
-       unsigned long ttime_total;
-       unsigned long ttime_samples;
-       unsigned long ttime_mean;
+enum {
+       ICQ_IOPRIO_CHANGED,
+       ICQ_CGROUP_CHANGED,
 };
 
-struct cfq_io_context {
-       void *key;
-
-       struct cfq_queue *cfqq[2];
-
-       struct io_context *ioc;
-
-       struct cfq_ttime ttime;
-
-       struct list_head queue_list;
-       struct hlist_node cic_list;
-
-       void (*dtor)(struct io_context *); /* destructor */
-       void (*exit)(struct io_context *); /* called on task exit */
+/*
+ * An io_cq (icq) is association between an io_context (ioc) and a
+ * request_queue (q).  This is used by elevators which need to track
+ * information per ioc - q pair.
+ *
+ * Elevator can request use of icq by setting elevator_type->icq_size and
+ * ->icq_align.  Both size and align must be larger than that of struct
+ * io_cq and elevator can use the tail area for private information.  The
+ * recommended way to do this is defining a struct which contains io_cq as
+ * the first member followed by private members and using its size and
+ * align.  For example,
+ *
+ *     struct snail_io_cq {
+ *             struct io_cq    icq;
+ *             int             poke_snail;
+ *             int             feed_snail;
+ *     };
+ *
+ *     struct elevator_type snail_elv_type {
+ *             .ops =          { ... },
+ *             .icq_size =     sizeof(struct snail_io_cq),
+ *             .icq_align =    __alignof__(struct snail_io_cq),
+ *             ...
+ *     };
+ *
+ * If icq_size is set, block core will manage icq's.  All requests will
+ * have its ->elv.icq field set before elevator_ops->elevator_set_req_fn()
+ * is called and be holding a reference to the associated io_context.
+ *
+ * Whenever a new icq is created, elevator_ops->elevator_init_icq_fn() is
+ * called and, on destruction, ->elevator_exit_icq_fn().  Both functions
+ * are called with both the associated io_context and queue locks held.
+ *
+ * Elevator is allowed to lookup icq using ioc_lookup_icq() while holding
+ * queue lock but the returned icq is valid only until the queue lock is
+ * released.  Elevators can not and should not try to create or destroy
+ * icq's.
+ *
+ * As icq's are linked from both ioc and q, the locking rules are a bit
+ * complex.
+ *
+ * - ioc lock nests inside q lock.
+ *
+ * - ioc->icq_list and icq->ioc_node are protected by ioc lock.
+ *   q->icq_list and icq->q_node by q lock.
+ *
+ * - ioc->icq_tree and ioc->icq_hint are protected by ioc lock, while icq
+ *   itself is protected by q lock.  However, both the indexes and icq
+ *   itself are also RCU managed and lookup can be performed holding only
+ *   the q lock.
+ *
+ * - icq's are not reference counted.  They are destroyed when either the
+ *   ioc or q goes away.  Each request with icq set holds an extra
+ *   reference to ioc to ensure it stays until the request is completed.
+ *
+ * - Linking and unlinking icq's are performed while holding both ioc and q
+ *   locks.  Due to the lock ordering, q exit is simple but ioc exit
+ *   requires reverse-order double lock dance.
+ */
+struct io_cq {
+       struct request_queue    *q;
+       struct io_context       *ioc;
 
-       struct rcu_head rcu_head;
+       /*
+        * q_node and ioc_node link io_cq through icq_list of q and ioc
+        * respectively.  Both fields are unused once ioc_exit_icq() is
+        * called and shared with __rcu_icq_cache and __rcu_head which are
+        * used for RCU free of io_cq.
+        */
+       union {
+               struct list_head        q_node;
+               struct kmem_cache       *__rcu_icq_cache;
+       };
+       union {
+               struct hlist_node       ioc_node;
+               struct rcu_head         __rcu_head;
+       };
+
+       unsigned long           changed;
 };
 
 /*
@@ -43,11 +103,6 @@ struct io_context {
        spinlock_t lock;
 
        unsigned short ioprio;
-       unsigned short ioprio_changed;
-
-#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE)
-       unsigned short cgroup_changed;
-#endif
 
        /*
         * For request batching
@@ -55,9 +110,11 @@ struct io_context {
        int nr_batch_requests;     /* Number of requests left in the batch */
        unsigned long last_waited; /* Time last woken after wait for request */
 
-       struct radix_tree_root radix_root;
-       struct hlist_head cic_list;
-       void __rcu *ioc_data;
+       struct radix_tree_root  icq_tree;
+       struct io_cq __rcu      *icq_hint;
+       struct hlist_head       icq_list;
+
+       struct work_struct release_work;
 };
 
 static inline struct io_context *ioc_task_link(struct io_context *ioc)
@@ -76,20 +133,17 @@ static inline struct io_context *ioc_task_link(struct io_context *ioc)
 
 struct task_struct;
 #ifdef CONFIG_BLOCK
-int put_io_context(struct io_context *ioc);
+void put_io_context(struct io_context *ioc, struct request_queue *locked_q);
 void exit_io_context(struct task_struct *task);
-struct io_context *get_io_context(gfp_t gfp_flags, int node);
-struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
+struct io_context *get_task_io_context(struct task_struct *task,
+                                      gfp_t gfp_flags, int node);
+void ioc_ioprio_changed(struct io_context *ioc, int ioprio);
+void ioc_cgroup_changed(struct io_context *ioc);
 #else
-static inline void exit_io_context(struct task_struct *task)
-{
-}
-
 struct io_context;
-static inline int put_io_context(struct io_context *ioc)
-{
-       return 1;
-}
+static inline void put_io_context(struct io_context *ioc,
+                                 struct request_queue *locked_q) { }
+static inline void exit_io_context(struct task_struct *task) { }
 #endif
 
 #endif
index 07821ca5955f42872e5b2748272cc7bf73bc2c4c..a5a50f52380784115f5a1def2e76ac103055408f 100644 (file)
@@ -10,6 +10,8 @@
  *
  */
 
+#ifndef _LINUX_ISDN_DIVERTIF_H
+#define _LINUX_ISDN_DIVERTIF_H
 
 /***********************************************************/
 /* magic value is also used to control version information */
@@ -45,3 +47,5 @@ typedef struct
 /*********************/
 extern int DIVERT_REG_NAME(isdn_divert_if *);
 #endif
+
+#endif /* _LINUX_ISDN_DIVERTIF_H */
index d0a7a0c7166101e266a3008e65fd89969ab3b8a2..e8343422240a8ca981dbd5b5971ccef6c30d1382 100644 (file)
@@ -185,16 +185,17 @@ static inline void might_fault(void)
 
 extern struct atomic_notifier_head panic_notifier_list;
 extern long (*panic_blink)(int state);
-NORET_TYPE void panic(const char * fmt, ...)
-       __attribute__ ((NORET_AND format (printf, 1, 2))) __cold;
+__printf(1, 2)
+void panic(const char *fmt, ...)
+       __noreturn __cold;
 extern void oops_enter(void);
 extern void oops_exit(void);
 void print_oops_end_marker(void);
 extern int oops_may_print(void);
-NORET_TYPE void do_exit(long error_code)
-       ATTRIB_NORET;
-NORET_TYPE void complete_and_exit(struct completion *, long)
-       ATTRIB_NORET;
+void do_exit(long error_code)
+       __noreturn;
+void complete_and_exit(struct completion *, long)
+       __noreturn;
 
 /* Internal, do not use. */
 int __must_check _kstrtoul(const char *s, unsigned int base, unsigned long *res);
index 183a6af7715d341bb5ffa9c8ebb3428d44f93cc8..5253471cd2ea32ec8459ef5023432b745b395771 100644 (file)
@@ -271,7 +271,7 @@ extern int keyring_add_key(struct key *keyring,
 
 extern struct key *key_lookup(key_serial_t id);
 
-static inline key_serial_t key_serial(struct key *key)
+static inline key_serial_t key_serial(const struct key *key)
 {
        return key ? key->serial : 0;
 }
@@ -293,6 +293,9 @@ static inline bool key_is_instantiated(const struct key *key)
        (rcu_dereference_protected((KEY)->payload.rcudata,              \
                                   rwsem_is_locked(&((struct key *)(KEY))->sem)))
 
+#define rcu_assign_keypointer(KEY, PAYLOAD)                            \
+       (rcu_assign_pointer((KEY)->payload.rcudata, PAYLOAD))
+
 #ifdef CONFIG_SYSCTL
 extern ctl_table key_sysctls[];
 #endif
index 99d9a6766f7ec055feca4a25d7d5e4c89fd9b058..2a5e5548a1d29c0577d75e6492eddfc241375444 100644 (file)
 extern void kmemleak_init(void) __ref;
 extern void kmemleak_alloc(const void *ptr, size_t size, int min_count,
                           gfp_t gfp) __ref;
+extern void kmemleak_alloc_percpu(const void __percpu *ptr, size_t size) __ref;
 extern void kmemleak_free(const void *ptr) __ref;
 extern void kmemleak_free_part(const void *ptr, size_t size) __ref;
+extern void kmemleak_free_percpu(const void __percpu *ptr) __ref;
 extern void kmemleak_padding(const void *ptr, unsigned long offset,
                             size_t size) __ref;
 extern void kmemleak_not_leak(const void *ptr) __ref;
@@ -68,6 +70,9 @@ static inline void kmemleak_alloc_recursive(const void *ptr, size_t size,
                                            gfp_t gfp)
 {
 }
+static inline void kmemleak_alloc_percpu(const void __percpu *ptr, size_t size)
+{
+}
 static inline void kmemleak_free(const void *ptr)
 {
 }
@@ -77,6 +82,9 @@ static inline void kmemleak_free_part(const void *ptr, size_t size)
 static inline void kmemleak_free_recursive(const void *ptr, unsigned long flags)
 {
 }
+static inline void kmemleak_free_percpu(const void __percpu *ptr)
+{
+}
 static inline void kmemleak_not_leak(const void *ptr)
 {
 }
index ee0c952188de2c99281fd7567f701893e90a47dd..fee66317e071547a4a75e0b90b61399b97249ed2 100644 (file)
@@ -18,7 +18,6 @@
 enum kmsg_dump_reason {
        KMSG_DUMP_OOPS,
        KMSG_DUMP_PANIC,
-       KMSG_DUMP_KEXEC,
        KMSG_DUMP_RESTART,
        KMSG_DUMP_HALT,
        KMSG_DUMP_POWEROFF,
index abc0120b09b772ff90fe539016295a00dfb08107..9c07dcebded747493041c8e6a5c18d68bc43fabf 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/bug.h>
 #include <linux/atomic.h>
+#include <linux/kernel.h>
 
 struct kref {
        atomic_t refcount;
index 3f46aedea42fbb5024f8e9896e380d0051c74132..807f1e5332267e6bd776f9591f106b723e1c02ab 100644 (file)
@@ -88,8 +88,4 @@
 
 #endif
 
-#define NORET_TYPE    /**/
-#define ATTRIB_NORET  __attribute__((noreturn))
-#define NORET_AND     noreturn,
-
 #endif
index 90b0656a869e319ba17b3537faffad1774ad2db7..88a114fce477ad5a42e5e5c3cb837ae7a8a1384e 100644 (file)
@@ -195,7 +195,7 @@ extern struct svc_procedure nlmsvc_procedures4[];
 #endif
 extern int                     nlmsvc_grace_period;
 extern unsigned long           nlmsvc_timeout;
-extern int                     nsm_use_hostnames;
+extern bool                    nsm_use_hostnames;
 extern u32                     nsm_local_state;
 
 /*
index f944591765eba3be0904bc820c4063c3c73183fd..4d34356fe644ee5dca447071829ae06ab68eeb60 100644 (file)
@@ -32,13 +32,11 @@ enum mem_cgroup_page_stat_item {
        MEMCG_NR_FILE_MAPPED, /* # of pages charged as file rss */
 };
 
-extern unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
-                                       struct list_head *dst,
-                                       unsigned long *scanned, int order,
-                                       isolate_mode_t mode,
-                                       struct zone *z,
-                                       struct mem_cgroup *mem_cont,
-                                       int active, int file);
+struct mem_cgroup_reclaim_cookie {
+       struct zone *zone;
+       int priority;
+       unsigned int generation;
+};
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
 /*
@@ -56,20 +54,21 @@ extern int mem_cgroup_newpage_charge(struct page *page, struct mm_struct *mm,
                                gfp_t gfp_mask);
 /* for swap handling */
 extern int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
-               struct page *page, gfp_t mask, struct mem_cgroup **ptr);
+               struct page *page, gfp_t mask, struct mem_cgroup **memcgp);
 extern void mem_cgroup_commit_charge_swapin(struct page *page,
-                                       struct mem_cgroup *ptr);
-extern void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *ptr);
+                                       struct mem_cgroup *memcg);
+extern void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *memcg);
 
 extern int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                                        gfp_t gfp_mask);
-extern void mem_cgroup_add_lru_list(struct page *page, enum lru_list lru);
-extern void mem_cgroup_del_lru_list(struct page *page, enum lru_list lru);
-extern void mem_cgroup_rotate_reclaimable_page(struct page *page);
-extern void mem_cgroup_rotate_lru_list(struct page *page, enum lru_list lru);
-extern void mem_cgroup_del_lru(struct page *page);
-extern void mem_cgroup_move_lists(struct page *page,
-                                 enum lru_list from, enum lru_list to);
+
+struct lruvec *mem_cgroup_zone_lruvec(struct zone *, struct mem_cgroup *);
+struct lruvec *mem_cgroup_lru_add_list(struct zone *, struct page *,
+                                      enum lru_list);
+void mem_cgroup_lru_del_list(struct page *, enum lru_list);
+void mem_cgroup_lru_del(struct page *);
+struct lruvec *mem_cgroup_lru_move_lists(struct zone *, struct page *,
+                                        enum lru_list, enum lru_list);
 
 /* For coalescing uncharge for reducing memcg' overhead*/
 extern void mem_cgroup_uncharge_start(void);
@@ -102,10 +101,15 @@ extern struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *memcg);
 
 extern int
 mem_cgroup_prepare_migration(struct page *page,
-       struct page *newpage, struct mem_cgroup **ptr, gfp_t gfp_mask);
+       struct page *newpage, struct mem_cgroup **memcgp, gfp_t gfp_mask);
 extern void mem_cgroup_end_migration(struct mem_cgroup *memcg,
        struct page *oldpage, struct page *newpage, bool migration_ok);
 
+struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *,
+                                  struct mem_cgroup *,
+                                  struct mem_cgroup_reclaim_cookie *);
+void mem_cgroup_iter_break(struct mem_cgroup *, struct mem_cgroup *);
+
 /*
  * For memory reclaim.
  */
@@ -122,7 +126,10 @@ struct zone_reclaim_stat*
 mem_cgroup_get_reclaim_stat_from_page(struct page *page);
 extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
                                        struct task_struct *p);
+extern void mem_cgroup_replace_page_cache(struct page *oldpage,
+                                       struct page *newpage);
 
+extern void mem_cgroup_reset_owner(struct page *page);
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
 extern int do_swap_account;
 #endif
@@ -157,7 +164,7 @@ u64 mem_cgroup_get_limit(struct mem_cgroup *memcg);
 
 void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx);
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail);
+void mem_cgroup_split_huge_fixup(struct page *head);
 #endif
 
 #ifdef CONFIG_DEBUG_VM
@@ -180,17 +187,17 @@ static inline int mem_cgroup_cache_charge(struct page *page,
 }
 
 static inline int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
-               struct page *page, gfp_t gfp_mask, struct mem_cgroup **ptr)
+               struct page *page, gfp_t gfp_mask, struct mem_cgroup **memcgp)
 {
        return 0;
 }
 
 static inline void mem_cgroup_commit_charge_swapin(struct page *page,
-                                         struct mem_cgroup *ptr)
+                                         struct mem_cgroup *memcg)
 {
 }
 
-static inline void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *ptr)
+static inline void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *memcg)
 {
 }
 
@@ -210,33 +217,33 @@ static inline void mem_cgroup_uncharge_cache_page(struct page *page)
 {
 }
 
-static inline void mem_cgroup_add_lru_list(struct page *page, int lru)
-{
-}
-
-static inline void mem_cgroup_del_lru_list(struct page *page, int lru)
+static inline struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone,
+                                                   struct mem_cgroup *memcg)
 {
-       return ;
+       return &zone->lruvec;
 }
 
-static inline void mem_cgroup_rotate_reclaimable_page(struct page *page)
+static inline struct lruvec *mem_cgroup_lru_add_list(struct zone *zone,
+                                                    struct page *page,
+                                                    enum lru_list lru)
 {
-       return ;
+       return &zone->lruvec;
 }
 
-static inline void mem_cgroup_rotate_lru_list(struct page *page, int lru)
+static inline void mem_cgroup_lru_del_list(struct page *page, enum lru_list lru)
 {
-       return ;
 }
 
-static inline void mem_cgroup_del_lru(struct page *page)
+static inline void mem_cgroup_lru_del(struct page *page)
 {
-       return ;
 }
 
-static inline void
-mem_cgroup_move_lists(struct page *page, enum lru_list from, enum lru_list to)
+static inline struct lruvec *mem_cgroup_lru_move_lists(struct zone *zone,
+                                                      struct page *page,
+                                                      enum lru_list from,
+                                                      enum lru_list to)
 {
+       return &zone->lruvec;
 }
 
 static inline struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page)
@@ -269,7 +276,7 @@ static inline struct cgroup_subsys_state
 
 static inline int
 mem_cgroup_prepare_migration(struct page *page, struct page *newpage,
-       struct mem_cgroup **ptr, gfp_t gfp_mask)
+       struct mem_cgroup **memcgp, gfp_t gfp_mask)
 {
        return 0;
 }
@@ -279,6 +286,19 @@ static inline void mem_cgroup_end_migration(struct mem_cgroup *memcg,
 {
 }
 
+static inline struct mem_cgroup *
+mem_cgroup_iter(struct mem_cgroup *root,
+               struct mem_cgroup *prev,
+               struct mem_cgroup_reclaim_cookie *reclaim)
+{
+       return NULL;
+}
+
+static inline void mem_cgroup_iter_break(struct mem_cgroup *root,
+                                        struct mem_cgroup *prev)
+{
+}
+
 static inline int mem_cgroup_get_reclaim_priority(struct mem_cgroup *memcg)
 {
        return 0;
@@ -360,8 +380,7 @@ u64 mem_cgroup_get_limit(struct mem_cgroup *memcg)
        return 0;
 }
 
-static inline void mem_cgroup_split_huge_fixup(struct page *head,
-                                               struct page *tail)
+static inline void mem_cgroup_split_huge_fixup(struct page *head)
 {
 }
 
@@ -369,6 +388,14 @@ static inline
 void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx)
 {
 }
+static inline void mem_cgroup_replace_page_cache(struct page *oldpage,
+                               struct page *newpage)
+{
+}
+
+static inline void mem_cgroup_reset_owner(struct page *page)
+{
+}
 #endif /* CONFIG_CGROUP_MEM_CONT */
 
 #if !defined(CONFIG_CGROUP_MEM_RES_CTLR) || !defined(CONFIG_DEBUG_VM)
index 63b4fb8e3b6f9aac05faef4534755a55dffc8733..92be3476c9f5560d8623ac5cae738e1471525f22 100644 (file)
@@ -297,10 +297,11 @@ enum {
 
 struct pm860x_chip {
        struct device           *dev;
-       struct mutex            io_lock;
        struct mutex            irq_lock;
        struct i2c_client       *client;
        struct i2c_client       *companion;     /* companion chip client */
+       struct regmap           *regmap;
+       struct regmap           *regmap_companion;
 
        int                     buck3_double;   /* DVC ramp slope double */
        unsigned short          companion_addr;
index b8e6d9449086e3bcc126e8191611e77bc6303d72..15b2392a56fbe4419c1caeb3986138249b2bc07b 100644 (file)
@@ -203,6 +203,8 @@ struct max8925_chip {
        int                     irq_base;
        int                     core_irq;
        int                     tsc_irq;
+
+       unsigned int            wakeup_flag;
 };
 
 struct max8925_backlight_pdata {
index 0bbd13dbe336bdbbcbb86b2caf9453feac4009fd..fff590521e5045beced56e80f207fcd178a9fa99 100644 (file)
@@ -77,6 +77,82 @@ struct max8997_regulator_data {
        struct regulator_init_data *initdata;
 };
 
+enum max8997_muic_usb_type {
+       MAX8997_USB_HOST,
+       MAX8997_USB_DEVICE,
+};
+
+enum max8997_muic_charger_type {
+       MAX8997_CHARGER_TYPE_NONE = 0,
+       MAX8997_CHARGER_TYPE_USB,
+       MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT,
+       MAX8997_CHARGER_TYPE_DEDICATED_CHG,
+       MAX8997_CHARGER_TYPE_500MA,
+       MAX8997_CHARGER_TYPE_1A,
+       MAX8997_CHARGER_TYPE_DEAD_BATTERY = 7,
+};
+
+struct max8997_muic_reg_data {
+       u8 addr;
+       u8 data;
+};
+
+/**
+ * struct max8997_muic_platform_data
+ * @usb_callback: callback function for USB
+ *               inform callee of USB type (HOST or DEVICE)
+ *               and attached state(true or false)
+ * @charger_callback: callback function for charger
+ *               inform callee of charger_type
+ *               and attached state(true or false)
+ * @deskdock_callback: callback function for desk dock
+ *               inform callee of attached state(true or false)
+ * @cardock_callback: callback function for car dock
+ *               inform callee of attached state(true or false)
+ * @mhl_callback: callback function for MHL (Mobile High-definition Link)
+ *               inform callee of attached state(true or false)
+ * @uart_callback: callback function for JIG UART
+ *                inform callee of attached state(true or false)
+ * @init_data: array of max8997_muic_reg_data
+ *            used for initializing registers of MAX8997 MUIC device
+ * @num_init_data: array size of init_data
+ */
+struct max8997_muic_platform_data {
+       void (*usb_callback)(enum max8997_muic_usb_type usb_type,
+               bool attached);
+       void (*charger_callback)(bool attached,
+               enum max8997_muic_charger_type charger_type);
+       void (*deskdock_callback) (bool attached);
+       void (*cardock_callback) (bool attached);
+       void (*mhl_callback) (bool attached);
+       void (*uart_callback) (bool attached);
+
+       struct max8997_muic_reg_data *init_data;
+       int num_init_data;
+};
+
+enum max8997_led_mode {
+       MAX8997_NONE,
+       MAX8997_FLASH_MODE,
+       MAX8997_MOVIE_MODE,
+       MAX8997_FLASH_PIN_CONTROL_MODE,
+       MAX8997_MOVIE_PIN_CONTROL_MODE,
+};
+
+/**
+ *  struct max8997_led_platform_data
+ *  The number of LED devices for MAX8997 is two
+ *  @mode: LED mode for each LED device
+ *  @brightness: initial brightness for each LED device
+ *     range:
+ *     [0 - 31]: MAX8997_FLASH_MODE and MAX8997_FLASH_PIN_CONTROL_MODE
+ *     [0 - 15]: MAX8997_MOVIE_MODE and MAX8997_MOVIE_PIN_CONTROL_MODE
+ */
+struct max8997_led_platform_data {
+       enum max8997_led_mode mode[2];
+       u8 brightness[2];
+};
+
 struct max8997_platform_data {
        /* IRQ */
        int irq_base;
@@ -113,10 +189,13 @@ struct max8997_platform_data {
        /* charge Full Timeout */
        int timeout; /* 0 (no timeout), 5, 6, 7 hours */
 
-       /* MUIC: Not implemented */
+       /* ---- MUIC ---- */
+       struct max8997_muic_platform_data *muic_pdata;
+
        /* HAPTIC: Not implemented */
        /* RTC: Not implemented */
-       /* Flash: Not implemented */
+       /* ---- LED ---- */
+       struct max8997_led_platform_data *led_pdata;
 };
 
 #endif /* __LINUX_MFD_MAX8998_H */
index a98e2a316d1f2e4235cc628e52b44058112ab976..b86ee45c8b03fc1b57f233543bbd0f0859167532 100644 (file)
@@ -174,6 +174,9 @@ struct mc13xxx_platform_data {
 #define MC13XXX_ADC_MODE_MULT_CHAN     3
 
 #define MC13XXX_ADC0           43
+#define MC13XXX_ADC0_LICELLCON         (1 << 0)
+#define MC13XXX_ADC0_CHRGICON          (1 << 1)
+#define MC13XXX_ADC0_BATICON           (1 << 2)
 #define MC13XXX_ADC0_ADREFEN           (1 << 10)
 #define MC13XXX_ADC0_TSMOD0            (1 << 12)
 #define MC13XXX_ADC0_TSMOD1            (1 << 13)
@@ -185,4 +188,9 @@ struct mc13xxx_platform_data {
                                        MC13XXX_ADC0_TSMOD1 | \
                                        MC13XXX_ADC0_TSMOD2)
 
+#define MC13XXX_ADC0_CONFIG_MASK       (MC13XXX_ADC0_TSMOD_MASK | \
+                                       MC13XXX_ADC0_LICELLCON | \
+                                       MC13XXX_ADC0_CHRGICON | \
+                                       MC13XXX_ADC0_BATICON)
+
 #endif /* ifndef __LINUX_MFD_MC13XXX_H */
index ee496708e38b9a0de245a3c9f59d67377dc6fd59..1515e64e3663abd1a557e339c0eb57d6f13d8117 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef MCP_H
 #define MCP_H
 
+#include <linux/mod_devicetable.h>
 #include <mach/dma.h>
 
 struct mcp_ops;
@@ -26,7 +27,7 @@ struct mcp {
        dma_device_t    dma_telco_rd;
        dma_device_t    dma_telco_wr;
        struct device   attached_device;
-       int             gpio_base;
+       const char      *codec;
 };
 
 struct mcp_ops {
@@ -44,10 +45,11 @@ void mcp_reg_write(struct mcp *, unsigned int, unsigned int);
 unsigned int mcp_reg_read(struct mcp *, unsigned int);
 void mcp_enable(struct mcp *);
 void mcp_disable(struct mcp *);
+const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp);
 #define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
 
 struct mcp *mcp_host_alloc(struct device *, size_t);
-int mcp_host_register(struct mcp *);
+int mcp_host_register(struct mcp *, void *);
 void mcp_host_unregister(struct mcp *);
 
 struct mcp_driver {
@@ -56,6 +58,7 @@ struct mcp_driver {
        void (*remove)(struct mcp *);
        int (*suspend)(struct mcp *, pm_message_t);
        int (*resume)(struct mcp *);
+       const struct mcp_device_id *id_table;
 };
 
 int mcp_driver_register(struct mcp_driver *);
diff --git a/include/linux/mfd/s5m87xx/s5m-core.h b/include/linux/mfd/s5m87xx/s5m-core.h
new file mode 100644 (file)
index 0000000..a7480b5
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * s5m-core.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_S5M_CORE_H
+#define __LINUX_MFD_S5M_CORE_H
+
+#define NUM_IRQ_REGS   4
+
+enum s5m_device_type {
+       S5M8751X,
+       S5M8763X,
+       S5M8767X,
+};
+
+/* S5M8767 registers */
+enum s5m8767_reg {
+       S5M8767_REG_ID,
+       S5M8767_REG_INT1,
+       S5M8767_REG_INT2,
+       S5M8767_REG_INT3,
+       S5M8767_REG_INT1M,
+       S5M8767_REG_INT2M,
+       S5M8767_REG_INT3M,
+       S5M8767_REG_STATUS1,
+       S5M8767_REG_STATUS2,
+       S5M8767_REG_STATUS3,
+       S5M8767_REG_CTRL1,
+       S5M8767_REG_CTRL2,
+       S5M8767_REG_LOWBAT1,
+       S5M8767_REG_LOWBAT2,
+       S5M8767_REG_BUCHG,
+       S5M8767_REG_DVSRAMP,
+       S5M8767_REG_DVSTIMER2 = 0x10,
+       S5M8767_REG_DVSTIMER3,
+       S5M8767_REG_DVSTIMER4,
+       S5M8767_REG_LDO1,
+       S5M8767_REG_LDO2,
+       S5M8767_REG_LDO3,
+       S5M8767_REG_LDO4,
+       S5M8767_REG_LDO5,
+       S5M8767_REG_LDO6,
+       S5M8767_REG_LDO7,
+       S5M8767_REG_LDO8,
+       S5M8767_REG_LDO9,
+       S5M8767_REG_LDO10,
+       S5M8767_REG_LDO11,
+       S5M8767_REG_LDO12,
+       S5M8767_REG_LDO13,
+       S5M8767_REG_LDO14 = 0x20,
+       S5M8767_REG_LDO15,
+       S5M8767_REG_LDO16,
+       S5M8767_REG_LDO17,
+       S5M8767_REG_LDO18,
+       S5M8767_REG_LDO19,
+       S5M8767_REG_LDO20,
+       S5M8767_REG_LDO21,
+       S5M8767_REG_LDO22,
+       S5M8767_REG_LDO23,
+       S5M8767_REG_LDO24,
+       S5M8767_REG_LDO25,
+       S5M8767_REG_LDO26,
+       S5M8767_REG_LDO27,
+       S5M8767_REG_LDO28,
+       S5M8767_REG_UVLO = 0x31,
+       S5M8767_REG_BUCK1CTRL1,
+       S5M8767_REG_BUCK1CTRL2,
+       S5M8767_REG_BUCK2CTRL,
+       S5M8767_REG_BUCK2DVS1,
+       S5M8767_REG_BUCK2DVS2,
+       S5M8767_REG_BUCK2DVS3,
+       S5M8767_REG_BUCK2DVS4,
+       S5M8767_REG_BUCK2DVS5,
+       S5M8767_REG_BUCK2DVS6,
+       S5M8767_REG_BUCK2DVS7,
+       S5M8767_REG_BUCK2DVS8,
+       S5M8767_REG_BUCK3CTRL,
+       S5M8767_REG_BUCK3DVS1,
+       S5M8767_REG_BUCK3DVS2,
+       S5M8767_REG_BUCK3DVS3,
+       S5M8767_REG_BUCK3DVS4,
+       S5M8767_REG_BUCK3DVS5,
+       S5M8767_REG_BUCK3DVS6,
+       S5M8767_REG_BUCK3DVS7,
+       S5M8767_REG_BUCK3DVS8,
+       S5M8767_REG_BUCK4CTRL,
+       S5M8767_REG_BUCK4DVS1,
+       S5M8767_REG_BUCK4DVS2,
+       S5M8767_REG_BUCK4DVS3,
+       S5M8767_REG_BUCK4DVS4,
+       S5M8767_REG_BUCK4DVS5,
+       S5M8767_REG_BUCK4DVS6,
+       S5M8767_REG_BUCK4DVS7,
+       S5M8767_REG_BUCK4DVS8,
+       S5M8767_REG_BUCK5CTRL1,
+       S5M8767_REG_BUCK5CTRL2,
+       S5M8767_REG_BUCK5CTRL3,
+       S5M8767_REG_BUCK5CTRL4,
+       S5M8767_REG_BUCK5CTRL5,
+       S5M8767_REG_BUCK6CTRL1,
+       S5M8767_REG_BUCK6CTRL2,
+       S5M8767_REG_BUCK7CTRL1,
+       S5M8767_REG_BUCK7CTRL2,
+       S5M8767_REG_BUCK8CTRL1,
+       S5M8767_REG_BUCK8CTRL2,
+       S5M8767_REG_BUCK9CTRL1,
+       S5M8767_REG_BUCK9CTRL2,
+       S5M8767_REG_LDO1CTRL,
+       S5M8767_REG_LDO2_1CTRL,
+       S5M8767_REG_LDO2_2CTRL,
+       S5M8767_REG_LDO2_3CTRL,
+       S5M8767_REG_LDO2_4CTRL,
+       S5M8767_REG_LDO3CTRL,
+       S5M8767_REG_LDO4CTRL,
+       S5M8767_REG_LDO5CTRL,
+       S5M8767_REG_LDO6CTRL,
+       S5M8767_REG_LDO7CTRL,
+       S5M8767_REG_LDO8CTRL,
+       S5M8767_REG_LDO9CTRL,
+       S5M8767_REG_LDO10CTRL,
+       S5M8767_REG_LDO11CTRL,
+       S5M8767_REG_LDO12CTRL,
+       S5M8767_REG_LDO13CTRL,
+       S5M8767_REG_LDO14CTRL,
+       S5M8767_REG_LDO15CTRL,
+       S5M8767_REG_LDO16CTRL,
+       S5M8767_REG_LDO17CTRL,
+       S5M8767_REG_LDO18CTRL,
+       S5M8767_REG_LDO19CTRL,
+       S5M8767_REG_LDO20CTRL,
+       S5M8767_REG_LDO21CTRL,
+       S5M8767_REG_LDO22CTRL,
+       S5M8767_REG_LDO23CTRL,
+       S5M8767_REG_LDO24CTRL,
+       S5M8767_REG_LDO25CTRL,
+       S5M8767_REG_LDO26CTRL,
+       S5M8767_REG_LDO27CTRL,
+       S5M8767_REG_LDO28CTRL,
+};
+
+/* S5M8763 registers */
+enum s5m8763_reg {
+       S5M8763_REG_IRQ1,
+       S5M8763_REG_IRQ2,
+       S5M8763_REG_IRQ3,
+       S5M8763_REG_IRQ4,
+       S5M8763_REG_IRQM1,
+       S5M8763_REG_IRQM2,
+       S5M8763_REG_IRQM3,
+       S5M8763_REG_IRQM4,
+       S5M8763_REG_STATUS1,
+       S5M8763_REG_STATUS2,
+       S5M8763_REG_STATUSM1,
+       S5M8763_REG_STATUSM2,
+       S5M8763_REG_CHGR1,
+       S5M8763_REG_CHGR2,
+       S5M8763_REG_LDO_ACTIVE_DISCHARGE1,
+       S5M8763_REG_LDO_ACTIVE_DISCHARGE2,
+       S5M8763_REG_BUCK_ACTIVE_DISCHARGE3,
+       S5M8763_REG_ONOFF1,
+       S5M8763_REG_ONOFF2,
+       S5M8763_REG_ONOFF3,
+       S5M8763_REG_ONOFF4,
+       S5M8763_REG_BUCK1_VOLTAGE1,
+       S5M8763_REG_BUCK1_VOLTAGE2,
+       S5M8763_REG_BUCK1_VOLTAGE3,
+       S5M8763_REG_BUCK1_VOLTAGE4,
+       S5M8763_REG_BUCK2_VOLTAGE1,
+       S5M8763_REG_BUCK2_VOLTAGE2,
+       S5M8763_REG_BUCK3,
+       S5M8763_REG_BUCK4,
+       S5M8763_REG_LDO1_LDO2,
+       S5M8763_REG_LDO3,
+       S5M8763_REG_LDO4,
+       S5M8763_REG_LDO5,
+       S5M8763_REG_LDO6,
+       S5M8763_REG_LDO7,
+       S5M8763_REG_LDO7_LDO8,
+       S5M8763_REG_LDO9_LDO10,
+       S5M8763_REG_LDO11,
+       S5M8763_REG_LDO12,
+       S5M8763_REG_LDO13,
+       S5M8763_REG_LDO14,
+       S5M8763_REG_LDO15,
+       S5M8763_REG_LDO16,
+       S5M8763_REG_BKCHR,
+       S5M8763_REG_LBCNFG1,
+       S5M8763_REG_LBCNFG2,
+};
+
+enum s5m8767_irq {
+       S5M8767_IRQ_PWRR,
+       S5M8767_IRQ_PWRF,
+       S5M8767_IRQ_PWR1S,
+       S5M8767_IRQ_JIGR,
+       S5M8767_IRQ_JIGF,
+       S5M8767_IRQ_LOWBAT2,
+       S5M8767_IRQ_LOWBAT1,
+
+       S5M8767_IRQ_MRB,
+       S5M8767_IRQ_DVSOK2,
+       S5M8767_IRQ_DVSOK3,
+       S5M8767_IRQ_DVSOK4,
+
+       S5M8767_IRQ_RTC60S,
+       S5M8767_IRQ_RTCA1,
+       S5M8767_IRQ_RTCA2,
+       S5M8767_IRQ_SMPL,
+       S5M8767_IRQ_RTC1S,
+       S5M8767_IRQ_WTSR,
+
+       S5M8767_IRQ_NR,
+};
+
+#define S5M8767_IRQ_PWRR_MASK          (1 << 0)
+#define S5M8767_IRQ_PWRF_MASK          (1 << 1)
+#define S5M8767_IRQ_PWR1S_MASK         (1 << 3)
+#define S5M8767_IRQ_JIGR_MASK          (1 << 4)
+#define S5M8767_IRQ_JIGF_MASK          (1 << 5)
+#define S5M8767_IRQ_LOWBAT2_MASK       (1 << 6)
+#define S5M8767_IRQ_LOWBAT1_MASK       (1 << 7)
+
+#define S5M8767_IRQ_MRB_MASK           (1 << 2)
+#define S5M8767_IRQ_DVSOK2_MASK                (1 << 3)
+#define S5M8767_IRQ_DVSOK3_MASK                (1 << 4)
+#define S5M8767_IRQ_DVSOK4_MASK                (1 << 5)
+
+#define S5M8767_IRQ_RTC60S_MASK                (1 << 0)
+#define S5M8767_IRQ_RTCA1_MASK         (1 << 1)
+#define S5M8767_IRQ_RTCA2_MASK         (1 << 2)
+#define S5M8767_IRQ_SMPL_MASK          (1 << 3)
+#define S5M8767_IRQ_RTC1S_MASK         (1 << 4)
+#define S5M8767_IRQ_WTSR_MASK          (1 << 5)
+
+enum s5m8763_irq {
+       S5M8763_IRQ_DCINF,
+       S5M8763_IRQ_DCINR,
+       S5M8763_IRQ_JIGF,
+       S5M8763_IRQ_JIGR,
+       S5M8763_IRQ_PWRONF,
+       S5M8763_IRQ_PWRONR,
+
+       S5M8763_IRQ_WTSREVNT,
+       S5M8763_IRQ_SMPLEVNT,
+       S5M8763_IRQ_ALARM1,
+       S5M8763_IRQ_ALARM0,
+
+       S5M8763_IRQ_ONKEY1S,
+       S5M8763_IRQ_TOPOFFR,
+       S5M8763_IRQ_DCINOVPR,
+       S5M8763_IRQ_CHGRSTF,
+       S5M8763_IRQ_DONER,
+       S5M8763_IRQ_CHGFAULT,
+
+       S5M8763_IRQ_LOBAT1,
+       S5M8763_IRQ_LOBAT2,
+
+       S5M8763_IRQ_NR,
+};
+
+#define S5M8763_IRQ_DCINF_MASK         (1 << 2)
+#define S5M8763_IRQ_DCINR_MASK         (1 << 3)
+#define S5M8763_IRQ_JIGF_MASK          (1 << 4)
+#define S5M8763_IRQ_JIGR_MASK          (1 << 5)
+#define S5M8763_IRQ_PWRONF_MASK                (1 << 6)
+#define S5M8763_IRQ_PWRONR_MASK                (1 << 7)
+
+#define S5M8763_IRQ_WTSREVNT_MASK      (1 << 0)
+#define S5M8763_IRQ_SMPLEVNT_MASK      (1 << 1)
+#define S5M8763_IRQ_ALARM1_MASK                (1 << 2)
+#define S5M8763_IRQ_ALARM0_MASK                (1 << 3)
+
+#define S5M8763_IRQ_ONKEY1S_MASK       (1 << 0)
+#define S5M8763_IRQ_TOPOFFR_MASK       (1 << 2)
+#define S5M8763_IRQ_DCINOVPR_MASK      (1 << 3)
+#define S5M8763_IRQ_CHGRSTF_MASK       (1 << 4)
+#define S5M8763_IRQ_DONER_MASK         (1 << 5)
+#define S5M8763_IRQ_CHGFAULT_MASK      (1 << 7)
+
+#define S5M8763_IRQ_LOBAT1_MASK                (1 << 0)
+#define S5M8763_IRQ_LOBAT2_MASK                (1 << 1)
+
+#define S5M8763_ENRAMP                  (1 << 4)
+
+/**
+ * struct s5m87xx_dev - s5m87xx master device for sub-drivers
+ * @dev: master device of the chip (can be used to access platform data)
+ * @i2c: i2c client private data for regulator
+ * @rtc: i2c client private data for rtc
+ * @iolock: mutex for serializing io access
+ * @irqlock: mutex for buslock
+ * @irq_base: base IRQ number for s5m87xx, required for IRQs
+ * @irq: generic IRQ number for s5m87xx
+ * @ono: power onoff IRQ number for s5m87xx
+ * @irq_masks_cur: currently active value
+ * @irq_masks_cache: cached hardware value
+ * @type: indicate which s5m87xx "variant" is used
+ */
+struct s5m87xx_dev {
+       struct device *dev;
+       struct regmap *regmap;
+       struct i2c_client *i2c;
+       struct i2c_client *rtc;
+       struct mutex iolock;
+       struct mutex irqlock;
+
+       int device_type;
+       int irq_base;
+       int irq;
+       int ono;
+       u8 irq_masks_cur[NUM_IRQ_REGS];
+       u8 irq_masks_cache[NUM_IRQ_REGS];
+       int type;
+       bool wakeup;
+};
+
+int s5m_irq_init(struct s5m87xx_dev *s5m87xx);
+void s5m_irq_exit(struct s5m87xx_dev *s5m87xx);
+int s5m_irq_resume(struct s5m87xx_dev *s5m87xx);
+
+extern int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest);
+extern int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf);
+extern int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value);
+extern int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf);
+extern int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask);
+
+struct s5m_platform_data {
+       struct s5m_regulator_data       *regulators;
+       int                             device_type;
+       int                             num_regulators;
+
+       int                             irq_base;
+       int                             (*cfg_pmic_irq)(void);
+
+       int                             ono;
+       bool                            wakeup;
+       bool                            buck_voltage_lock;
+
+       int                             buck_gpios[3];
+       int                             buck2_voltage[8];
+       bool                            buck2_gpiodvs;
+       int                             buck3_voltage[8];
+       bool                            buck3_gpiodvs;
+       int                             buck4_voltage[8];
+       bool                            buck4_gpiodvs;
+
+       int                             buck_set1;
+       int                             buck_set2;
+       int                             buck_set3;
+       int                             buck2_enable;
+       int                             buck3_enable;
+       int                             buck4_enable;
+       int                             buck_default_idx;
+       int                             buck2_default_idx;
+       int                             buck3_default_idx;
+       int                             buck4_default_idx;
+
+       int                             buck_ramp_delay;
+       bool                            buck2_ramp_enable;
+       bool                            buck3_ramp_enable;
+       bool                            buck4_ramp_enable;
+};
+
+#endif /*  __LINUX_MFD_S5M_CORE_H */
diff --git a/include/linux/mfd/s5m87xx/s5m-pmic.h b/include/linux/mfd/s5m87xx/s5m-pmic.h
new file mode 100644 (file)
index 0000000..a72a5d2
--- /dev/null
@@ -0,0 +1,100 @@
+/* s5m87xx.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __LINUX_MFD_S5M_PMIC_H
+#define __LINUX_MFD_S5M_PMIC_H
+
+#include <linux/regulator/machine.h>
+
+/* S5M8767 regulator ids */
+enum s5m8767_regulators {
+       S5M8767_LDO1,
+       S5M8767_LDO2,
+       S5M8767_LDO3,
+       S5M8767_LDO4,
+       S5M8767_LDO5,
+       S5M8767_LDO6,
+       S5M8767_LDO7,
+       S5M8767_LDO8,
+       S5M8767_LDO9,
+       S5M8767_LDO10,
+       S5M8767_LDO11,
+       S5M8767_LDO12,
+       S5M8767_LDO13,
+       S5M8767_LDO14,
+       S5M8767_LDO15,
+       S5M8767_LDO16,
+       S5M8767_LDO17,
+       S5M8767_LDO18,
+       S5M8767_LDO19,
+       S5M8767_LDO20,
+       S5M8767_LDO21,
+       S5M8767_LDO22,
+       S5M8767_LDO23,
+       S5M8767_LDO24,
+       S5M8767_LDO25,
+       S5M8767_LDO26,
+       S5M8767_LDO27,
+       S5M8767_LDO28,
+       S5M8767_BUCK1,
+       S5M8767_BUCK2,
+       S5M8767_BUCK3,
+       S5M8767_BUCK4,
+       S5M8767_BUCK5,
+       S5M8767_BUCK6,
+       S5M8767_BUCK7,
+       S5M8767_BUCK8,
+       S5M8767_BUCK9,
+       S5M8767_AP_EN32KHZ,
+       S5M8767_CP_EN32KHZ,
+
+       S5M8767_REG_MAX,
+};
+
+/* S5M8763 regulator ids */
+enum s5m8763_regulators {
+       S5M8763_LDO1,
+       S5M8763_LDO2,
+       S5M8763_LDO3,
+       S5M8763_LDO4,
+       S5M8763_LDO5,
+       S5M8763_LDO6,
+       S5M8763_LDO7,
+       S5M8763_LDO8,
+       S5M8763_LDO9,
+       S5M8763_LDO10,
+       S5M8763_LDO11,
+       S5M8763_LDO12,
+       S5M8763_LDO13,
+       S5M8763_LDO14,
+       S5M8763_LDO15,
+       S5M8763_LDO16,
+       S5M8763_BUCK1,
+       S5M8763_BUCK2,
+       S5M8763_BUCK3,
+       S5M8763_BUCK4,
+       S5M8763_AP_EN32KHZ,
+       S5M8763_CP_EN32KHZ,
+       S5M8763_ENCHGVI,
+       S5M8763_ESAFEUSB1,
+       S5M8763_ESAFEUSB2,
+};
+
+/**
+ * s5m87xx_regulator_data - regulator data
+ * @id: regulator id
+ * @initdata: regulator init data (contraints, supplies, ...)
+ */
+struct s5m_regulator_data {
+       int                             id;
+       struct regulator_init_data      *initdata;
+};
+
+#endif /*  __LINUX_MFD_S5M_PMIC_H */
diff --git a/include/linux/mfd/s5m87xx/s5m-rtc.h b/include/linux/mfd/s5m87xx/s5m-rtc.h
new file mode 100644 (file)
index 0000000..6ce8da2
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * s5m-rtc.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_S5M_RTC_H
+#define __LINUX_MFD_S5M_RTC_H
+
+enum s5m87xx_rtc_reg {
+       S5M87XX_RTC_SEC,
+       S5M87XX_RTC_MIN,
+       S5M87XX_RTC_HOUR,
+       S5M87XX_RTC_WEEKDAY,
+       S5M87XX_RTC_DATE,
+       S5M87XX_RTC_MONTH,
+       S5M87XX_RTC_YEAR1,
+       S5M87XX_RTC_YEAR2,
+       S5M87XX_ALARM0_SEC,
+       S5M87XX_ALARM0_MIN,
+       S5M87XX_ALARM0_HOUR,
+       S5M87XX_ALARM0_WEEKDAY,
+       S5M87XX_ALARM0_DATE,
+       S5M87XX_ALARM0_MONTH,
+       S5M87XX_ALARM0_YEAR1,
+       S5M87XX_ALARM0_YEAR2,
+       S5M87XX_ALARM1_SEC,
+       S5M87XX_ALARM1_MIN,
+       S5M87XX_ALARM1_HOUR,
+       S5M87XX_ALARM1_WEEKDAY,
+       S5M87XX_ALARM1_DATE,
+       S5M87XX_ALARM1_MONTH,
+       S5M87XX_ALARM1_YEAR1,
+       S5M87XX_ALARM1_YEAR2,
+       S5M87XX_ALARM0_CONF,
+       S5M87XX_ALARM1_CONF,
+       S5M87XX_RTC_STATUS,
+       S5M87XX_WTSR_SMPL_CNTL,
+       S5M87XX_RTC_UDR_CON,
+};
+
+#define RTC_I2C_ADDR           (0x0C >> 1)
+
+#define HOUR_12                        (1 << 7)
+#define HOUR_AMPM              (1 << 6)
+#define HOUR_PM                        (1 << 5)
+#define ALARM0_STATUS          (1 << 1)
+#define ALARM1_STATUS          (1 << 2)
+#define UPDATE_AD              (1 << 0)
+
+/* RTC Control Register */
+#define BCD_EN_SHIFT           0
+#define BCD_EN_MASK            (1 << BCD_EN_SHIFT)
+#define MODEL24_SHIFT          1
+#define MODEL24_MASK           (1 << MODEL24_SHIFT)
+/* RTC Update Register1 */
+#define RTC_UDR_SHIFT          0
+#define RTC_UDR_MASK           (1 << RTC_UDR_SHIFT)
+/* RTC Hour register */
+#define HOUR_PM_SHIFT          6
+#define HOUR_PM_MASK           (1 << HOUR_PM_SHIFT)
+/* RTC Alarm Enable */
+#define ALARM_ENABLE_SHIFT     7
+#define ALARM_ENABLE_MASK      (1 << ALARM_ENABLE_SHIFT)
+
+enum {
+       RTC_SEC = 0,
+       RTC_MIN,
+       RTC_HOUR,
+       RTC_WEEKDAY,
+       RTC_DATE,
+       RTC_MONTH,
+       RTC_YEAR1,
+       RTC_YEAR2,
+};
+
+#endif /*  __LINUX_MFD_S5M_RTC_H */
index be1af7c42e576ecd9881276401df8ee5a49d694f..ca1d7a3476004d6936c104a8a435dfd4ac4e5f52 100644 (file)
@@ -20,6 +20,8 @@ enum stmpe_block {
 };
 
 enum stmpe_partnum {
+       STMPE610,
+       STMPE801,
        STMPE811,
        STMPE1601,
        STMPE2401,
@@ -50,17 +52,20 @@ enum {
 
 
 struct stmpe_variant_info;
+struct stmpe_client_info;
 
 /**
  * struct stmpe - STMPE MFD structure
  * @lock: lock protecting I/O operations
  * @irq_lock: IRQ bus lock
  * @dev: device, mostly for dev_dbg()
- * @i2c: i2c client
+ * @client: client - i2c or spi
+ * @ci: client specific information
  * @partnum: part number
  * @variant: the detected STMPE model number
  * @regs: list of addresses of registers which are at different addresses on
  *       different variants.  Indexed by one of STMPE_IDX_*.
+ * @irq: irq number for stmpe
  * @irq_base: starting IRQ number for internal IRQs
  * @num_gpios: number of gpios, differs for variants
  * @ier: cache of IER registers for bus_lock
@@ -71,11 +76,13 @@ struct stmpe {
        struct mutex lock;
        struct mutex irq_lock;
        struct device *dev;
-       struct i2c_client *i2c;
+       void *client;
+       struct stmpe_client_info *ci;
        enum stmpe_partnum partnum;
        struct stmpe_variant_info *variant;
        const u8 *regs;
 
+       int irq;
        int irq_base;
        int num_gpios;
        u8 ier[2];
@@ -183,6 +190,9 @@ struct stmpe_ts_platform_data {
  * @autosleep_timeout: inactivity timeout in milliseconds for autosleep
  * @irq_base: base IRQ number.  %STMPE_NR_IRQS irqs will be used, or
  *           %STMPE_NR_INTERNAL_IRQS if the GPIO driver is not used.
+ * @irq_over_gpio: true if gpio is used to get irq
+ * @irq_gpio: gpio number over which irq will be requested (significant only if
+ *           irq_over_gpio is true)
  * @gpio: GPIO-specific platform data
  * @keypad: keypad-specific platform data
  * @ts: touchscreen-specific platform data
@@ -194,6 +204,8 @@ struct stmpe_platform_data {
        unsigned int irq_trigger;
        bool irq_invert_polarity;
        bool autosleep;
+       bool irq_over_gpio;
+       int irq_gpio;
        int autosleep_timeout;
 
        struct stmpe_gpio_platform_data *gpio;
index 4321f044d1e45e1ad5cdaf20eba1440427b1fb5e..bc19e5fb7ea8f1791960e961e7a9dab803f15a54 100644 (file)
 #define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
 #define UCB_MODE_AUD_OFF_CAN   (1 << 13)
 
+struct ucb1x00_plat_data {
+       int             gpio_base;
+};
 
 struct ucb1x00_irq {
        void *devid;
@@ -116,7 +119,7 @@ struct ucb1x00 {
        unsigned int            irq;
        struct semaphore        adc_sem;
        spinlock_t              io_lock;
-       u16                     id;
+       const struct mcp_device_id *id;
        u16                     io_dir;
        u16                     io_out;
        u16                     adc_cr;
index e39aeecfe9a21666a107bf02be780bacca1ba0f5..eaf867412f7adf26e96a3ad4eb3f002a418434e4 100644 (file)
@@ -6,18 +6,31 @@
 
 typedef struct page *new_page_t(struct page *, unsigned long private, int **);
 
+/*
+ * MIGRATE_ASYNC means never block
+ * MIGRATE_SYNC_LIGHT in the current implementation means to allow blocking
+ *     on most operations but not ->writepage as the potential stall time
+ *     is too significant
+ * MIGRATE_SYNC will block when migrating pages
+ */
+enum migrate_mode {
+       MIGRATE_ASYNC,
+       MIGRATE_SYNC_LIGHT,
+       MIGRATE_SYNC,
+};
+
 #ifdef CONFIG_MIGRATION
 #define PAGE_MIGRATION 1
 
 extern void putback_lru_pages(struct list_head *l);
 extern int migrate_page(struct address_space *,
-                       struct page *, struct page *);
+                       struct page *, struct page *, enum migrate_mode);
 extern int migrate_pages(struct list_head *l, new_page_t x,
                        unsigned long private, bool offlining,
-                       bool sync);
+                       enum migrate_mode mode);
 extern int migrate_huge_pages(struct list_head *l, new_page_t x,
                        unsigned long private, bool offlining,
-                       bool sync);
+                       enum migrate_mode mode);
 
 extern int fail_migrate_page(struct address_space *,
                        struct page *, struct page *);
@@ -36,10 +49,10 @@ extern int migrate_huge_page_move_mapping(struct address_space *mapping,
 static inline void putback_lru_pages(struct list_head *l) {}
 static inline int migrate_pages(struct list_head *l, new_page_t x,
                unsigned long private, bool offlining,
-               bool sync) { return -ENOSYS; }
+               enum migrate_mode mode) { return -ENOSYS; }
 static inline int migrate_huge_pages(struct list_head *l, new_page_t x,
                unsigned long private, bool offlining,
-               bool sync) { return -ENOSYS; }
+               enum migrate_mode mode) { return -ENOSYS; }
 
 static inline int migrate_prep(void) { return -ENOSYS; }
 static inline int migrate_prep_local(void) { return -ENOSYS; }
index 32085249e9cbf54d0d65ebc63e0e08cb8b6a132f..0549d2115507124405b06f5ea96f072880a3e475 100644 (file)
@@ -42,6 +42,7 @@
 #define AUTOFS_MINOR           235
 #define MAPPER_CTRL_MINOR      236
 #define LOOP_CTRL_MINOR                237
+#define VHOST_NET_MINOR                238
 #define MISC_DYNAMIC_MINOR     255
 
 struct device;
index 8f7d24712dc115790269442be6f8c245d4cf6145..227fd3e9a9c9370398478005d01344f5a42cb02d 100644 (file)
@@ -22,26 +22,21 @@ static inline int page_is_file_cache(struct page *page)
 }
 
 static inline void
-__add_page_to_lru_list(struct zone *zone, struct page *page, enum lru_list l,
-                      struct list_head *head)
+add_page_to_lru_list(struct zone *zone, struct page *page, enum lru_list lru)
 {
-       list_add(&page->lru, head);
-       __mod_zone_page_state(zone, NR_LRU_BASE + l, hpage_nr_pages(page));
-       mem_cgroup_add_lru_list(page, l);
-}
+       struct lruvec *lruvec;
 
-static inline void
-add_page_to_lru_list(struct zone *zone, struct page *page, enum lru_list l)
-{
-       __add_page_to_lru_list(zone, page, l, &zone->lru[l].list);
+       lruvec = mem_cgroup_lru_add_list(zone, page, lru);
+       list_add(&page->lru, &lruvec->lists[lru]);
+       __mod_zone_page_state(zone, NR_LRU_BASE + lru, hpage_nr_pages(page));
 }
 
 static inline void
-del_page_from_lru_list(struct zone *zone, struct page *page, enum lru_list l)
+del_page_from_lru_list(struct zone *zone, struct page *page, enum lru_list lru)
 {
+       mem_cgroup_lru_del_list(page, lru);
        list_del(&page->lru);
-       __mod_zone_page_state(zone, NR_LRU_BASE + l, -hpage_nr_pages(page));
-       mem_cgroup_del_lru_list(page, l);
+       __mod_zone_page_state(zone, NR_LRU_BASE + lru, -hpage_nr_pages(page));
 }
 
 /**
@@ -59,24 +54,28 @@ static inline enum lru_list page_lru_base_type(struct page *page)
        return LRU_INACTIVE_ANON;
 }
 
-static inline void
-del_page_from_lru(struct zone *zone, struct page *page)
+/**
+ * page_off_lru - which LRU list was page on? clearing its lru flags.
+ * @page: the page to test
+ *
+ * Returns the LRU list a page was on, as an index into the array of LRU
+ * lists; and clears its Unevictable or Active flags, ready for freeing.
+ */
+static inline enum lru_list page_off_lru(struct page *page)
 {
-       enum lru_list l;
+       enum lru_list lru;
 
-       list_del(&page->lru);
        if (PageUnevictable(page)) {
                __ClearPageUnevictable(page);
-               l = LRU_UNEVICTABLE;
+               lru = LRU_UNEVICTABLE;
        } else {
-               l = page_lru_base_type(page);
+               lru = page_lru_base_type(page);
                if (PageActive(page)) {
                        __ClearPageActive(page);
-                       l += LRU_ACTIVE;
+                       lru += LRU_ACTIVE;
                }
        }
-       __mod_zone_page_state(zone, NR_LRU_BASE + l, -hpage_nr_pages(page));
-       mem_cgroup_del_lru_list(page, l);
+       return lru;
 }
 
 /**
@@ -97,7 +96,6 @@ static inline enum lru_list page_lru(struct page *page)
                if (PageActive(page))
                        lru += LRU_ACTIVE;
        }
-
        return lru;
 }
 
index 5b42f1b34eb74b59964f9a717d436cad44481c05..3cc3062b37679d2bcb58d04c51c5b42073f61725 100644 (file)
@@ -151,12 +151,11 @@ struct page {
 #endif
 }
 /*
- * If another subsystem starts using the double word pairing for atomic
- * operations on struct page then it must change the #if to ensure
- * proper alignment of the page struct.
+ * The struct page can be forced to be double word aligned so that atomic ops
+ * on double words work. The SLUB allocator can make use of such a feature.
  */
-#if defined(CONFIG_SLUB) && defined(CONFIG_CMPXCHG_LOCAL)
-       __attribute__((__aligned__(2*sizeof(unsigned long))))
+#ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
+       __aligned(2 * sizeof(unsigned long))
 #endif
 ;
 
index c8ef9bc54d500d0df052d4bd433e4b24d1855bb1..9f22ba572de0a9a332ec4c2156560b0eac8726cc 100644 (file)
@@ -71,6 +71,8 @@ struct mmc_ext_csd {
        bool                    hpi_en;                 /* HPI enablebit */
        bool                    hpi;                    /* HPI support bit */
        unsigned int            hpi_cmd;                /* cmd used as HPI */
+       unsigned int            boot_ro_lock;           /* ro lock support */
+       bool                    boot_ro_lockable;
        u8                      raw_partition_support;  /* 160 */
        u8                      raw_erased_mem_count;   /* 181 */
        u8                      raw_ext_csd_structure;  /* 194 */
@@ -110,6 +112,7 @@ struct sd_ssr {
 struct sd_switch_caps {
        unsigned int            hs_max_dtr;
        unsigned int            uhs_max_dtr;
+#define HIGH_SPEED_MAX_DTR     50000000
 #define UHS_SDR104_MAX_DTR     208000000
 #define UHS_SDR50_MAX_DTR      100000000
 #define UHS_DDR50_MAX_DTR      50000000
@@ -117,11 +120,13 @@ struct sd_switch_caps {
 #define UHS_SDR12_MAX_DTR      25000000
        unsigned int            sd3_bus_mode;
 #define UHS_SDR12_BUS_SPEED    0
+#define HIGH_SPEED_BUS_SPEED   1
 #define UHS_SDR25_BUS_SPEED    1
 #define UHS_SDR50_BUS_SPEED    2
 #define UHS_SDR104_BUS_SPEED   3
 #define UHS_DDR50_BUS_SPEED    4
 
+#define SD_MODE_HIGH_SPEED     (1 << HIGH_SPEED_BUS_SPEED)
 #define SD_MODE_UHS_SDR12      (1 << UHS_SDR12_BUS_SPEED)
 #define SD_MODE_UHS_SDR25      (1 << UHS_SDR25_BUS_SPEED)
 #define SD_MODE_UHS_SDR50      (1 << UHS_SDR50_BUS_SPEED)
@@ -184,6 +189,10 @@ struct mmc_part {
        unsigned int    part_cfg;       /* partition type */
        char    name[MAX_MMC_PART_NAME_LEN];
        bool    force_ro;       /* to make boot parts RO by default */
+       unsigned int    area_type;
+#define MMC_BLK_DATA_AREA_MAIN (1<<0)
+#define MMC_BLK_DATA_AREA_BOOT (1<<1)
+#define MMC_BLK_DATA_AREA_GP   (1<<2)
 };
 
 /*
@@ -206,6 +215,8 @@ struct mmc_card {
 #define MMC_STATE_HIGHSPEED_DDR (1<<4)         /* card is in high speed mode */
 #define MMC_STATE_ULTRAHIGHSPEED (1<<5)                /* card is in ultra high speed mode */
 #define MMC_CARD_SDXC          (1<<6)          /* card is SDXC */
+#define MMC_CARD_REMOVED       (1<<7)          /* card has been removed */
+#define MMC_STATE_HIGHSPEED_200        (1<<8)          /* card is in HS200 mode */
        unsigned int            quirks;         /* card quirks */
 #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
@@ -261,12 +272,14 @@ struct mmc_card {
  * This function fill contents in mmc_part.
  */
 static inline void mmc_part_add(struct mmc_card *card, unsigned int size,
-                       unsigned int part_cfg, char *name, int idx, bool ro)
+                       unsigned int part_cfg, char *name, int idx, bool ro,
+                       int area_type)
 {
        card->part[card->nr_parts].size = size;
        card->part[card->nr_parts].part_cfg = part_cfg;
        sprintf(card->part[card->nr_parts].name, name, idx);
        card->part[card->nr_parts].force_ro = ro;
+       card->part[card->nr_parts].area_type = area_type;
        card->nr_parts++;
 }
 
@@ -362,18 +375,24 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_present(c)    ((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)  ((c)->state & MMC_STATE_HIGHSPEED)
+#define mmc_card_hs200(c)      ((c)->state & MMC_STATE_HIGHSPEED_200)
 #define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
 #define mmc_card_ddr_mode(c)   ((c)->state & MMC_STATE_HIGHSPEED_DDR)
-#define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
+#define mmc_card_uhs(c)                ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
+#define mmc_sd_card_uhs(c)     ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
+#define mmc_card_removed(c)    ((c) && ((c)->state & MMC_CARD_REMOVED))
 
 #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
+#define mmc_card_set_hs200(c)  ((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
 #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
+#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
+#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 
 /*
  * Quirk add/remove for MMC products.
diff --git a/include/linux/mmc/cd-gpio.h b/include/linux/mmc/cd-gpio.h
new file mode 100644 (file)
index 0000000..a8e4697
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Generic GPIO card-detect helper header
+ *
+ * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MMC_CD_GPIO_H
+#define MMC_CD_GPIO_H
+
+struct mmc_host;
+int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio,
+                       unsigned int irq, unsigned long flags);
+void mmc_cd_gpio_free(struct mmc_host *host);
+
+#endif
index 174a844a5dda67fae26d87514432a0080bf3d7b3..87a976cc5654d164361014849a8733c6733c18e9 100644 (file)
@@ -180,6 +180,8 @@ extern int mmc_try_claim_host(struct mmc_host *host);
 
 extern int mmc_flush_cache(struct mmc_card *);
 
+extern int mmc_detect_card_removed(struct mmc_host *host);
+
 /**
  *     mmc_claim_host - exclusively claim a host
  *     @host: mmc host to claim
index 6dc9b80568a0d7766d6b8e447ca19b9dbd1d802c..e8779c6d175923172a9f2d00e7213b9305fd1e4b 100644 (file)
@@ -214,6 +214,7 @@ struct dw_mci_board {
        unsigned int bus_hz; /* Bus speed */
 
        unsigned int caps;      /* Capabilities */
+       unsigned int caps2;     /* More capabilities */
        /*
         * Override fifo depth. If 0, autodetect it from the FIFOTH register,
         * but note that this may not be reliable after a bootloader has used
index a3ac9c48e5de60dc71fe71f3eb5d067e315ac4fb..0beba1e5e1ed4675ebbe35b42091394845be459e 100644 (file)
@@ -56,10 +56,13 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_SDR50   3
 #define MMC_TIMING_UHS_SDR104  4
 #define MMC_TIMING_UHS_DDR50   5
+#define MMC_TIMING_MMC_HS200   6
 
 #define MMC_SDR_MODE           0
 #define MMC_1_2V_DDR_MODE      1
 #define MMC_1_8V_DDR_MODE      2
+#define MMC_1_2V_SDR_MODE      3
+#define MMC_1_8V_SDR_MODE      4
 
        unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
 
@@ -148,7 +151,9 @@ struct mmc_host_ops {
        void    (*init_card)(struct mmc_host *host, struct mmc_card *card);
 
        int     (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
-       int     (*execute_tuning)(struct mmc_host *host);
+
+       /* The tuning command opcode value is different for SD and eMMC cards */
+       int     (*execute_tuning)(struct mmc_host *host, u32 opcode);
        void    (*enable_preset_value)(struct mmc_host *host, bool enable);
        int     (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
        void    (*hw_reset)(struct mmc_host *host);
@@ -167,6 +172,11 @@ struct mmc_async_req {
        int (*err_check) (struct mmc_card *, struct mmc_async_req *);
 };
 
+struct mmc_hotplug {
+       unsigned int irq;
+       void *handler_priv;
+};
+
 struct mmc_host {
        struct device           *parent;
        struct device           class_dev;
@@ -242,6 +252,11 @@ struct mmc_host {
 #define MMC_CAP2_CACHE_CTRL    (1 << 1)        /* Allow cache control */
 #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)      /* Notify poweroff supported */
 #define MMC_CAP2_NO_MULTI_READ (1 << 3)        /* Multiblock reads don't work */
+#define MMC_CAP2_NO_SLEEP_CMD  (1 << 4)        /* Don't allow sleep command */
+#define MMC_CAP2_HS200_1_8V_SDR        (1 << 5)        /* can support */
+#define MMC_CAP2_HS200_1_2V_SDR        (1 << 6)        /* can support */
+#define MMC_CAP2_HS200         (MMC_CAP2_HS200_1_8V_SDR | \
+                                MMC_CAP2_HS200_1_2V_SDR)
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
        unsigned int        power_notify_type;
@@ -253,10 +268,12 @@ struct mmc_host {
        int                     clk_requests;   /* internal reference counter */
        unsigned int            clk_delay;      /* number of MCI clk hold cycles */
        bool                    clk_gated;      /* clock gated */
-       struct work_struct      clk_gate_work; /* delayed clock gate */
+       struct delayed_work     clk_gate_work; /* delayed clock gate */
        unsigned int            clk_old;        /* old clock value cache */
        spinlock_t              clk_lock;       /* lock for clk fields */
        struct mutex            clk_gate_mutex; /* mutex for clock gating */
+       struct device_attribute clkgate_delay_attr;
+       unsigned long           clkgate_delay;
 #endif
 
        /* host specific block data */
@@ -297,6 +314,8 @@ struct mmc_host {
        int                     claim_cnt;      /* "claim" nesting count */
 
        struct delayed_work     detect;
+       int                     detect_change;  /* card detect flag */
+       struct mmc_hotplug      hotplug;
 
        const struct mmc_bus_ops *bus_ops;      /* current bus driver */
        unsigned int            bus_refs;       /* reference counter */
@@ -323,6 +342,8 @@ struct mmc_host {
        struct fault_attr       fail_mmc_request;
 #endif
 
+       unsigned int            actual_clock;   /* Actual HC clock rate */
+
        unsigned long           private[0] ____cacheline_aligned;
 };
 
@@ -396,7 +417,7 @@ static inline void mmc_set_disable_delay(struct mmc_host *host,
 }
 
 /* Module parameter */
-extern int mmc_assume_removable;
+extern bool mmc_assume_removable;
 
 static inline int mmc_card_is_removable(struct mmc_host *host)
 {
index 0e7135697d1110923d6553f35f51171806be2251..fb9f6e116e1c7e0b79a2b25d55db8a48255e4bbf 100644 (file)
@@ -51,6 +51,7 @@
 #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
 #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
 #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1  */
+#define MMC_SEND_TUNING_BLOCK_HS200    21      /* adtc R1  */
 
   /* class 3 */
 #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
@@ -280,6 +281,7 @@ struct _mmc_csd {
 #define EXT_CSD_RST_N_FUNCTION         162     /* R/W */
 #define EXT_CSD_SANITIZE_START         165     /* W */
 #define EXT_CSD_WR_REL_PARAM           166     /* RO */
+#define EXT_CSD_BOOT_WP                        173     /* R/W */
 #define EXT_CSD_ERASE_GROUP_DEF                175     /* R/W */
 #define EXT_CSD_PART_CONFIG            179     /* R/W */
 #define EXT_CSD_ERASED_MEM_CONT                181     /* RO */
@@ -321,6 +323,11 @@ struct _mmc_csd {
 
 #define EXT_CSD_WR_REL_PARAM_EN                (1<<2)
 
+#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS   (0x40)
+#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS  (0x10)
+#define EXT_CSD_BOOT_WP_B_PERM_WP_EN   (0x04)
+#define EXT_CSD_BOOT_WP_B_PWR_WP_EN    (0x01)
+
 #define EXT_CSD_PART_CONFIG_ACC_MASK   (0x7)
 #define EXT_CSD_PART_CONFIG_ACC_BOOT0  (0x1)
 #define EXT_CSD_PART_CONFIG_ACC_GP0    (0x4)
@@ -333,13 +340,76 @@ struct _mmc_csd {
 
 #define EXT_CSD_CARD_TYPE_26   (1<<0)  /* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_52   (1<<1)  /* Card can run at 52MHz */
-#define EXT_CSD_CARD_TYPE_MASK 0x    /* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_MASK 0x3F    /* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
                                             /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
                                             /* DDR mode @1.2V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
                                        | EXT_CSD_CARD_TYPE_DDR_1_2V)
+#define EXT_CSD_CARD_TYPE_SDR_1_8V     (1<<4)  /* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_SDR_1_2V     (1<<5)  /* Card can run at 200MHz */
+                                               /* SDR mode @1.2V I/O */
+
+#define EXT_CSD_CARD_TYPE_SDR_200      (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+                                        EXT_CSD_CARD_TYPE_SDR_1_2V)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL      (EXT_CSD_CARD_TYPE_SDR_200 | \
+                                        EXT_CSD_CARD_TYPE_52 | \
+                                        EXT_CSD_CARD_TYPE_26)
+
+#define        EXT_CSD_CARD_TYPE_SDR_1_2V_ALL  (EXT_CSD_CARD_TYPE_SDR_1_2V | \
+                                        EXT_CSD_CARD_TYPE_52 | \
+                                        EXT_CSD_CARD_TYPE_26)
+
+#define        EXT_CSD_CARD_TYPE_SDR_1_8V_ALL  (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+                                        EXT_CSD_CARD_TYPE_52 | \
+                                        EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V    (EXT_CSD_CARD_TYPE_SDR_1_2V | \
+                                                EXT_CSD_CARD_TYPE_DDR_1_8V | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V    (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+                                                EXT_CSD_CARD_TYPE_DDR_1_8V | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V    (EXT_CSD_CARD_TYPE_SDR_1_2V | \
+                                                EXT_CSD_CARD_TYPE_DDR_1_2V | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V    (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+                                                EXT_CSD_CARD_TYPE_DDR_1_2V | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52      (EXT_CSD_CARD_TYPE_SDR_1_2V | \
+                                                EXT_CSD_CARD_TYPE_DDR_52 | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52      (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+                                                EXT_CSD_CARD_TYPE_DDR_52 | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V     (EXT_CSD_CARD_TYPE_SDR_200 | \
+                                                EXT_CSD_CARD_TYPE_DDR_1_8V | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V     (EXT_CSD_CARD_TYPE_SDR_200 | \
+                                                EXT_CSD_CARD_TYPE_DDR_1_2V | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52       (EXT_CSD_CARD_TYPE_SDR_200 | \
+                                                EXT_CSD_CARD_TYPE_DDR_52 | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
 
 #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
diff --git a/include/linux/mmc/sdhci-pci-data.h b/include/linux/mmc/sdhci-pci-data.h
new file mode 100644 (file)
index 0000000..8959604
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef LINUX_MMC_SDHCI_PCI_DATA_H
+#define LINUX_MMC_SDHCI_PCI_DATA_H
+
+struct pci_dev;
+
+struct sdhci_pci_data {
+       struct pci_dev  *pdev;
+       int             slotno;
+       int             rst_n_gpio; /* Set to -EINVAL if unused */
+       int             cd_gpio;    /* Set to -EINVAL if unused */
+       int             (*setup)(struct sdhci_pci_data *data);
+       void            (*cleanup)(struct sdhci_pci_data *data);
+};
+
+extern struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev,
+                               int slotno);
+
+#endif
index e4b69353678d0c69a97af270e02911e756f44863..c750f85177d95cb7b849249ef9a0c007b7687992 100644 (file)
@@ -90,8 +90,6 @@ struct sdhci_host {
 
        unsigned int quirks2;   /* More deviations from spec. */
 
-#define SDHCI_QUIRK2_OWN_CARD_DETECTION                        (1<<0)
-
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
 
@@ -121,6 +119,7 @@ struct sdhci_host {
 #define SDHCI_AUTO_CMD23       (1<<7)  /* Auto CMD23 support */
 #define SDHCI_PV_ENABLED       (1<<8)  /* Preset value enabled */
 #define SDHCI_SDIO_IRQ_ENABLED (1<<9)  /* SDIO irq enabled */
+#define SDHCI_HS200_NEEDS_TUNING (1<<10)       /* HS200 needs tuning */
 
        unsigned int version;   /* SDHCI spec. version */
 
index e0b1123497b9b5adba34126bc8f187e6c7d98a91..c9fe66c58f8fc718e68b2147733a0acab750d5aa 100644 (file)
@@ -38,6 +38,7 @@
  *      [8:0] Byte/block count
  */
 
+#define R4_18V_PRESENT (1<<24)
 #define R4_MEMORY_PRESENT (1 << 27)
 
 /*
@@ -85,6 +86,7 @@
 #define  SDIO_SD_REV_1_01      0       /* SD Physical Spec Version 1.01 */
 #define  SDIO_SD_REV_1_10      1       /* SD Physical Spec Version 1.10 */
 #define  SDIO_SD_REV_2_00      2       /* SD Physical Spec Version 2.00 */
+#define  SDIO_SD_REV_3_00      3       /* SD Physical Spev Version 3.00 */
 
 #define SDIO_CCCR_IOEx         0x02
 #define SDIO_CCCR_IORx         0x03
 #define SDIO_CCCR_SPEED                0x13
 
 #define  SDIO_SPEED_SHS                0x01    /* Supports High-Speed mode */
-#define  SDIO_SPEED_EHS                0x02    /* Enable High-Speed mode */
-
+#define  SDIO_SPEED_BSS_SHIFT  1
+#define  SDIO_SPEED_BSS_MASK   (7<<SDIO_SPEED_BSS_SHIFT)
+#define  SDIO_SPEED_SDR12      (0<<SDIO_SPEED_BSS_SHIFT)
+#define  SDIO_SPEED_SDR25      (1<<SDIO_SPEED_BSS_SHIFT)
+#define  SDIO_SPEED_SDR50      (2<<SDIO_SPEED_BSS_SHIFT)
+#define  SDIO_SPEED_SDR104     (3<<SDIO_SPEED_BSS_SHIFT)
+#define  SDIO_SPEED_DDR50      (4<<SDIO_SPEED_BSS_SHIFT)
+#define  SDIO_SPEED_EHS                SDIO_SPEED_SDR25        /* Enable High-Speed */
+
+#define SDIO_CCCR_UHS          0x14
+#define  SDIO_UHS_SDR50                0x01
+#define  SDIO_UHS_SDR104       0x02
+#define  SDIO_UHS_DDR50                0x04
+
+#define SDIO_CCCR_DRIVE_STRENGTH 0x15
+#define  SDIO_SDTx_MASK                0x07
+#define  SDIO_DRIVE_SDTA       (1<<0)
+#define  SDIO_DRIVE_SDTC       (1<<1)
+#define  SDIO_DRIVE_SDTD       (1<<2)
+#define  SDIO_DRIVE_DTSx_MASK  0x03
+#define  SDIO_DRIVE_DTSx_SHIFT 4
+#define  SDIO_DTSx_SET_TYPE_B  (0 << SDIO_DRIVE_DTSx_SHIFT)
+#define  SDIO_DTSx_SET_TYPE_A  (1 << SDIO_DRIVE_DTSx_SHIFT)
+#define  SDIO_DTSx_SET_TYPE_C  (2 << SDIO_DRIVE_DTSx_SHIFT)
+#define  SDIO_DTSx_SET_TYPE_D  (3 << SDIO_DRIVE_DTSx_SHIFT)
 /*
  * Function Basic Registers (FBR)
  */
index ca6ca92418a6eedc96d76c120ffd4095624d0441..650ba2fb3301af5975fa1b027ebdb008cf573e61 100644 (file)
@@ -140,25 +140,29 @@ enum lru_list {
        NR_LRU_LISTS
 };
 
-#define for_each_lru(l) for (l = 0; l < NR_LRU_LISTS; l++)
+#define for_each_lru(lru) for (lru = 0; lru < NR_LRU_LISTS; lru++)
 
-#define for_each_evictable_lru(l) for (l = 0; l <= LRU_ACTIVE_FILE; l++)
+#define for_each_evictable_lru(lru) for (lru = 0; lru <= LRU_ACTIVE_FILE; lru++)
 
-static inline int is_file_lru(enum lru_list l)
+static inline int is_file_lru(enum lru_list lru)
 {
-       return (l == LRU_INACTIVE_FILE || l == LRU_ACTIVE_FILE);
+       return (lru == LRU_INACTIVE_FILE || lru == LRU_ACTIVE_FILE);
 }
 
-static inline int is_active_lru(enum lru_list l)
+static inline int is_active_lru(enum lru_list lru)
 {
-       return (l == LRU_ACTIVE_ANON || l == LRU_ACTIVE_FILE);
+       return (lru == LRU_ACTIVE_ANON || lru == LRU_ACTIVE_FILE);
 }
 
-static inline int is_unevictable_lru(enum lru_list l)
+static inline int is_unevictable_lru(enum lru_list lru)
 {
-       return (l == LRU_UNEVICTABLE);
+       return (lru == LRU_UNEVICTABLE);
 }
 
+struct lruvec {
+       struct list_head lists[NR_LRU_LISTS];
+};
+
 /* Mask used at gathering information at once (see memcontrol.c) */
 #define LRU_ALL_FILE (BIT(LRU_INACTIVE_FILE) | BIT(LRU_ACTIVE_FILE))
 #define LRU_ALL_ANON (BIT(LRU_INACTIVE_ANON) | BIT(LRU_ACTIVE_ANON))
@@ -173,6 +177,8 @@ static inline int is_unevictable_lru(enum lru_list l)
 #define ISOLATE_CLEAN          ((__force isolate_mode_t)0x4)
 /* Isolate unmapped file */
 #define ISOLATE_UNMAPPED       ((__force isolate_mode_t)0x8)
+/* Isolate for asynchronous migration */
+#define ISOLATE_ASYNC_MIGRATE  ((__force isolate_mode_t)0x10)
 
 /* LRU Isolation modes. */
 typedef unsigned __bitwise__ isolate_mode_t;
@@ -364,10 +370,8 @@ struct zone {
        ZONE_PADDING(_pad1_)
 
        /* Fields commonly accessed by the page reclaim scanner */
-       spinlock_t              lru_lock;       
-       struct zone_lru {
-               struct list_head list;
-       } lru[NR_LRU_LISTS];
+       spinlock_t              lru_lock;
+       struct lruvec           lruvec;
 
        struct zone_reclaim_stat reclaim_stat;
 
index 83ac0713ed0aa9a2a0c79b95013c5bfd42137d9c..b29e7f6f8fa580d9c4c39b4fca596a98e249b2d4 100644 (file)
@@ -436,6 +436,17 @@ struct spi_device_id {
                        __attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
+/* mcp */
+
+#define MCP_NAME_SIZE  20
+#define MCP_MODULE_PREFIX "mcp:"
+
+struct mcp_device_id {
+       char name[MCP_NAME_SIZE];
+       kernel_ulong_t driver_data      /* Data private to the driver */
+                       __attribute__((aligned(sizeof(kernel_ulong_t))));
+};
+
 /* dmi */
 enum dmi_field {
        DMI_NONE,
index 3cb7839a60b96ffc6e4fe9b28d0ddf491275b2f6..4598bf03e98b83756f4f8ecb5b4acdfafec379ad 100644 (file)
@@ -205,6 +205,20 @@ enum module_state
        MODULE_STATE_GOING,
 };
 
+/**
+ * struct module_ref - per cpu module reference counts
+ * @incs: number of module get on this cpu
+ * @decs: number of module put on this cpu
+ *
+ * We force an alignment on 8 or 16 bytes, so that alloc_percpu()
+ * put @incs/@decs in same cache line, with no extra memory cost,
+ * since alloc_percpu() is fine grained.
+ */
+struct module_ref {
+       unsigned long incs;
+       unsigned long decs;
+} __attribute((aligned(2 * sizeof(unsigned long))));
+
 struct module
 {
        enum module_state state;
@@ -347,10 +361,7 @@ struct module
        /* Destruction function. */
        void (*exit)(void);
 
-       struct module_ref {
-               unsigned int incs;
-               unsigned int decs;
-       } __percpu *refptr;
+       struct module_ref __percpu *refptr;
 #endif
 
 #ifdef CONFIG_CONSTRUCTORS
@@ -434,7 +445,7 @@ extern void __module_put_and_exit(struct module *mod, long code)
 #define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code);
 
 #ifdef CONFIG_MODULE_UNLOAD
-unsigned int module_refcount(struct module *mod);
+unsigned long module_refcount(struct module *mod);
 void __symbol_put(const char *symbol);
 #define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x)
 void symbol_put_addr(void *addr);
index 7939f636c8bae3c747b604c98472d34de620ab70..c47f4d60db0b0fb6cd05668212768efc439dc61d 100644 (file)
@@ -350,23 +350,23 @@ extern int param_set_charp(const char *val, const struct kernel_param *kp);
 extern int param_get_charp(char *buffer, const struct kernel_param *kp);
 #define param_check_charp(name, p) __param_check(name, p, char *)
 
-/* For historical reasons "bool" parameters can be (unsigned) "int". */
+/* We used to allow int as well as bool.  We're taking that away! */
 extern struct kernel_param_ops param_ops_bool;
 extern int param_set_bool(const char *val, const struct kernel_param *kp);
 extern int param_get_bool(char *buffer, const struct kernel_param *kp);
-#define param_check_bool(name, p)                                      \
-       static inline void __check_##name(void)                         \
-       {                                                               \
-               BUILD_BUG_ON(!__same_type((p), bool *) &&               \
-                            !__same_type((p), unsigned int *) &&       \
-                            !__same_type((p), int *));                 \
-       }
+#define param_check_bool(name, p) __param_check(name, p, bool)
 
 extern struct kernel_param_ops param_ops_invbool;
 extern int param_set_invbool(const char *val, const struct kernel_param *kp);
 extern int param_get_invbool(char *buffer, const struct kernel_param *kp);
 #define param_check_invbool(name, p) __param_check(name, p, bool)
 
+/* An int, which can only be set like a bool (though it shows as an int). */
+extern struct kernel_param_ops param_ops_bint;
+extern int param_set_bint(const char *val, const struct kernel_param *kp);
+#define param_get_bint param_get_int
+#define param_check_bint param_check_int
+
 /**
  * module_param_array - a parameter which is an array of some type
  * @name: the name of the array variable
@@ -395,6 +395,7 @@ extern int param_get_invbool(char *buffer, const struct kernel_param *kp);
  * module_param_named() for why this might be necessary.
  */
 #define module_param_array_named(name, array, type, nump, perm)                \
+       param_check_##type(name, &(array)[0]);                          \
        static const struct kparam_array __param_arr_##name             \
        = { .max = ARRAY_SIZE(array), .num = nump,                      \
            .ops = &param_ops_##type,                                   \
index a3759cb0ac10560bc58a30341d228041afcac8f7..6d8c7251eb8d4147968c6a146473868caa0eebbc 100644 (file)
@@ -43,9 +43,11 @@ typedef unsigned short mifi_t;
 typedef        __u32           if_mask;
 #define NIFBITS (sizeof(if_mask) * 8)        /* bits per mask */
 
-#if !defined(__KERNEL__) && !defined(DIV_ROUND_UP)
+#if !defined(__KERNEL__)
+#if !defined(DIV_ROUND_UP)
 #define        DIV_ROUND_UP(x,y)       (((x) + ((y) - 1)) / (y))
 #endif
+#endif
 
 typedef struct if_set {
        if_mask ifs_bits[DIV_ROUND_UP(IF_SETSIZE, NIFBITS)];
diff --git a/include/linux/mtd/gpmi-nand.h b/include/linux/mtd/gpmi-nand.h
new file mode 100644 (file)
index 0000000..69b6dbf
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __MACH_MXS_GPMI_NAND_H__
+#define __MACH_MXS_GPMI_NAND_H__
+
+/* The size of the resources is fixed. */
+#define GPMI_NAND_RES_SIZE     6
+
+/* Resource names for the GPMI NAND driver. */
+#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME  "GPMI NAND GPMI Registers"
+#define GPMI_NAND_GPMI_INTERRUPT_RES_NAME  "GPMI NAND GPMI Interrupt"
+#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME   "GPMI NAND BCH Registers"
+#define GPMI_NAND_BCH_INTERRUPT_RES_NAME   "GPMI NAND BCH Interrupt"
+#define GPMI_NAND_DMA_CHANNELS_RES_NAME    "GPMI NAND DMA Channels"
+#define GPMI_NAND_DMA_INTERRUPT_RES_NAME   "GPMI NAND DMA Interrupt"
+
+/**
+ * struct gpmi_nand_platform_data - GPMI NAND driver platform data.
+ *
+ * This structure communicates platform-specific information to the GPMI NAND
+ * driver that can't be expressed as resources.
+ *
+ * @platform_init:           A pointer to a function the driver will call to
+ *                           initialize the platform (e.g., set up the pin mux).
+ * @min_prop_delay_in_ns:    Minimum propagation delay of GPMI signals to and
+ *                           from the NAND Flash device, in nanoseconds.
+ * @max_prop_delay_in_ns:    Maximum propagation delay of GPMI signals to and
+ *                           from the NAND Flash device, in nanoseconds.
+ * @max_chip_count:          The maximum number of chips for which the driver
+ *                           should configure the hardware. This value most
+ *                           likely reflects the number of pins that are
+ *                           connected to a NAND Flash device. If this is
+ *                           greater than the SoC hardware can support, the
+ *                           driver will print a message and fail to initialize.
+ * @partitions:              An optional pointer to an array of partition
+ *                           descriptions.
+ * @partition_count:         The number of elements in the partitions array.
+ */
+struct gpmi_nand_platform_data {
+       /* SoC hardware information. */
+       int             (*platform_init)(void);
+
+       /* NAND Flash information. */
+       unsigned int    min_prop_delay_in_ns;
+       unsigned int    max_prop_delay_in_ns;
+       unsigned int    max_chip_count;
+
+       /* Medium information. */
+       struct          mtd_partition *partitions;
+       unsigned        partition_count;
+};
+#endif
index 9e3a2838291bfe6aee8f6b3e0d88b43ace455abf..0d3dd66322ecbb24529303f6634f36e5ce6f390d 100644 (file)
@@ -83,10 +83,6 @@ enum ip_conntrack_status {
        /* Conntrack is a fake untracked entry */
        IPS_UNTRACKED_BIT = 12,
        IPS_UNTRACKED = (1 << IPS_UNTRACKED_BIT),
-
-       /* Conntrack has a userspace helper. */
-       IPS_USERSPACE_HELPER_BIT = 13,
-       IPS_USERSPACE_HELPER = (1 << IPS_USERSPACE_HELPER_BIT),
 };
 
 /* Connection tracking event types */
index 6390f0992f36f0723393d282c6d39d3f68abb12e..b56e76811c04380e9779dbe82c2cfa4a5b0c6abd 100644 (file)
@@ -3,8 +3,7 @@
 
 #include <linux/types.h>
 
-#define XT_CT_NOTRACK          0x1
-#define XT_CT_USERSPACE_HELPER 0x2
+#define XT_CT_NOTRACK  0x1
 
 struct xt_ct_target_info {
        __u16 flags;
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
new file mode 100644 (file)
index 0000000..9490a00
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * Definitions for the NVM Express interface
+ * Copyright (c) 2011, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _LINUX_NVME_H
+#define _LINUX_NVME_H
+
+#include <linux/types.h>
+
+struct nvme_bar {
+       __u64                   cap;    /* Controller Capabilities */
+       __u32                   vs;     /* Version */
+       __u32                   intms;  /* Interrupt Mask Set */
+       __u32                   intmc;  /* Interrupt Mask Clear */
+       __u32                   cc;     /* Controller Configuration */
+       __u32                   rsvd1;  /* Reserved */
+       __u32                   csts;   /* Controller Status */
+       __u32                   rsvd2;  /* Reserved */
+       __u32                   aqa;    /* Admin Queue Attributes */
+       __u64                   asq;    /* Admin SQ Base Address */
+       __u64                   acq;    /* Admin CQ Base Address */
+};
+
+#define NVME_CAP_TIMEOUT(cap)  (((cap) >> 24) & 0xff)
+#define NVME_CAP_STRIDE(cap)   (((cap) >> 32) & 0xf)
+
+enum {
+       NVME_CC_ENABLE          = 1 << 0,
+       NVME_CC_CSS_NVM         = 0 << 4,
+       NVME_CC_MPS_SHIFT       = 7,
+       NVME_CC_ARB_RR          = 0 << 11,
+       NVME_CC_ARB_WRRU        = 1 << 11,
+       NVME_CC_ARB_VS          = 7 << 11,
+       NVME_CC_SHN_NONE        = 0 << 14,
+       NVME_CC_SHN_NORMAL      = 1 << 14,
+       NVME_CC_SHN_ABRUPT      = 2 << 14,
+       NVME_CC_IOSQES          = 6 << 16,
+       NVME_CC_IOCQES          = 4 << 20,
+       NVME_CSTS_RDY           = 1 << 0,
+       NVME_CSTS_CFS           = 1 << 1,
+       NVME_CSTS_SHST_NORMAL   = 0 << 2,
+       NVME_CSTS_SHST_OCCUR    = 1 << 2,
+       NVME_CSTS_SHST_CMPLT    = 2 << 2,
+};
+
+struct nvme_id_power_state {
+       __le16                  max_power;      /* centiwatts */
+       __u16                   rsvd2;
+       __le32                  entry_lat;      /* microseconds */
+       __le32                  exit_lat;       /* microseconds */
+       __u8                    read_tput;
+       __u8                    read_lat;
+       __u8                    write_tput;
+       __u8                    write_lat;
+       __u8                    rsvd16[16];
+};
+
+#define NVME_VS(major, minor)  (major << 16 | minor)
+
+struct nvme_id_ctrl {
+       __le16                  vid;
+       __le16                  ssvid;
+       char                    sn[20];
+       char                    mn[40];
+       char                    fr[8];
+       __u8                    rab;
+       __u8                    ieee[3];
+       __u8                    mic;
+       __u8                    mdts;
+       __u8                    rsvd78[178];
+       __le16                  oacs;
+       __u8                    acl;
+       __u8                    aerl;
+       __u8                    frmw;
+       __u8                    lpa;
+       __u8                    elpe;
+       __u8                    npss;
+       __u8                    rsvd264[248];
+       __u8                    sqes;
+       __u8                    cqes;
+       __u8                    rsvd514[2];
+       __le32                  nn;
+       __le16                  oncs;
+       __le16                  fuses;
+       __u8                    fna;
+       __u8                    vwc;
+       __le16                  awun;
+       __le16                  awupf;
+       __u8                    rsvd530[1518];
+       struct nvme_id_power_state      psd[32];
+       __u8                    vs[1024];
+};
+
+struct nvme_lbaf {
+       __le16                  ms;
+       __u8                    ds;
+       __u8                    rp;
+};
+
+struct nvme_id_ns {
+       __le64                  nsze;
+       __le64                  ncap;
+       __le64                  nuse;
+       __u8                    nsfeat;
+       __u8                    nlbaf;
+       __u8                    flbas;
+       __u8                    mc;
+       __u8                    dpc;
+       __u8                    dps;
+       __u8                    rsvd30[98];
+       struct nvme_lbaf        lbaf[16];
+       __u8                    rsvd192[192];
+       __u8                    vs[3712];
+};
+
+enum {
+       NVME_NS_FEAT_THIN       = 1 << 0,
+       NVME_LBAF_RP_BEST       = 0,
+       NVME_LBAF_RP_BETTER     = 1,
+       NVME_LBAF_RP_GOOD       = 2,
+       NVME_LBAF_RP_DEGRADED   = 3,
+};
+
+struct nvme_lba_range_type {
+       __u8                    type;
+       __u8                    attributes;
+       __u8                    rsvd2[14];
+       __u64                   slba;
+       __u64                   nlb;
+       __u8                    guid[16];
+       __u8                    rsvd48[16];
+};
+
+enum {
+       NVME_LBART_TYPE_FS      = 0x01,
+       NVME_LBART_TYPE_RAID    = 0x02,
+       NVME_LBART_TYPE_CACHE   = 0x03,
+       NVME_LBART_TYPE_SWAP    = 0x04,
+
+       NVME_LBART_ATTRIB_TEMP  = 1 << 0,
+       NVME_LBART_ATTRIB_HIDE  = 1 << 1,
+};
+
+/* I/O commands */
+
+enum nvme_opcode {
+       nvme_cmd_flush          = 0x00,
+       nvme_cmd_write          = 0x01,
+       nvme_cmd_read           = 0x02,
+       nvme_cmd_write_uncor    = 0x04,
+       nvme_cmd_compare        = 0x05,
+       nvme_cmd_dsm            = 0x09,
+};
+
+struct nvme_common_command {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __le32                  nsid;
+       __u32                   cdw2[2];
+       __le64                  metadata;
+       __le64                  prp1;
+       __le64                  prp2;
+       __u32                   cdw10[6];
+};
+
+struct nvme_rw_command {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __le32                  nsid;
+       __u64                   rsvd2;
+       __le64                  metadata;
+       __le64                  prp1;
+       __le64                  prp2;
+       __le64                  slba;
+       __le16                  length;
+       __le16                  control;
+       __le32                  dsmgmt;
+       __le32                  reftag;
+       __le16                  apptag;
+       __le16                  appmask;
+};
+
+enum {
+       NVME_RW_LR                      = 1 << 15,
+       NVME_RW_FUA                     = 1 << 14,
+       NVME_RW_DSM_FREQ_UNSPEC         = 0,
+       NVME_RW_DSM_FREQ_TYPICAL        = 1,
+       NVME_RW_DSM_FREQ_RARE           = 2,
+       NVME_RW_DSM_FREQ_READS          = 3,
+       NVME_RW_DSM_FREQ_WRITES         = 4,
+       NVME_RW_DSM_FREQ_RW             = 5,
+       NVME_RW_DSM_FREQ_ONCE           = 6,
+       NVME_RW_DSM_FREQ_PREFETCH       = 7,
+       NVME_RW_DSM_FREQ_TEMP           = 8,
+       NVME_RW_DSM_LATENCY_NONE        = 0 << 4,
+       NVME_RW_DSM_LATENCY_IDLE        = 1 << 4,
+       NVME_RW_DSM_LATENCY_NORM        = 2 << 4,
+       NVME_RW_DSM_LATENCY_LOW         = 3 << 4,
+       NVME_RW_DSM_SEQ_REQ             = 1 << 6,
+       NVME_RW_DSM_COMPRESSED          = 1 << 7,
+};
+
+/* Admin commands */
+
+enum nvme_admin_opcode {
+       nvme_admin_delete_sq            = 0x00,
+       nvme_admin_create_sq            = 0x01,
+       nvme_admin_get_log_page         = 0x02,
+       nvme_admin_delete_cq            = 0x04,
+       nvme_admin_create_cq            = 0x05,
+       nvme_admin_identify             = 0x06,
+       nvme_admin_abort_cmd            = 0x08,
+       nvme_admin_set_features         = 0x09,
+       nvme_admin_get_features         = 0x0a,
+       nvme_admin_async_event          = 0x0c,
+       nvme_admin_activate_fw          = 0x10,
+       nvme_admin_download_fw          = 0x11,
+       nvme_admin_format_nvm           = 0x80,
+       nvme_admin_security_send        = 0x81,
+       nvme_admin_security_recv        = 0x82,
+};
+
+enum {
+       NVME_QUEUE_PHYS_CONTIG  = (1 << 0),
+       NVME_CQ_IRQ_ENABLED     = (1 << 1),
+       NVME_SQ_PRIO_URGENT     = (0 << 1),
+       NVME_SQ_PRIO_HIGH       = (1 << 1),
+       NVME_SQ_PRIO_MEDIUM     = (2 << 1),
+       NVME_SQ_PRIO_LOW        = (3 << 1),
+       NVME_FEAT_ARBITRATION   = 0x01,
+       NVME_FEAT_POWER_MGMT    = 0x02,
+       NVME_FEAT_LBA_RANGE     = 0x03,
+       NVME_FEAT_TEMP_THRESH   = 0x04,
+       NVME_FEAT_ERR_RECOVERY  = 0x05,
+       NVME_FEAT_VOLATILE_WC   = 0x06,
+       NVME_FEAT_NUM_QUEUES    = 0x07,
+       NVME_FEAT_IRQ_COALESCE  = 0x08,
+       NVME_FEAT_IRQ_CONFIG    = 0x09,
+       NVME_FEAT_WRITE_ATOMIC  = 0x0a,
+       NVME_FEAT_ASYNC_EVENT   = 0x0b,
+       NVME_FEAT_SW_PROGRESS   = 0x0c,
+};
+
+struct nvme_identify {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __le32                  nsid;
+       __u64                   rsvd2[2];
+       __le64                  prp1;
+       __le64                  prp2;
+       __le32                  cns;
+       __u32                   rsvd11[5];
+};
+
+struct nvme_features {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __le32                  nsid;
+       __u64                   rsvd2[2];
+       __le64                  prp1;
+       __le64                  prp2;
+       __le32                  fid;
+       __le32                  dword11;
+       __u32                   rsvd12[4];
+};
+
+struct nvme_create_cq {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __u32                   rsvd1[5];
+       __le64                  prp1;
+       __u64                   rsvd8;
+       __le16                  cqid;
+       __le16                  qsize;
+       __le16                  cq_flags;
+       __le16                  irq_vector;
+       __u32                   rsvd12[4];
+};
+
+struct nvme_create_sq {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __u32                   rsvd1[5];
+       __le64                  prp1;
+       __u64                   rsvd8;
+       __le16                  sqid;
+       __le16                  qsize;
+       __le16                  sq_flags;
+       __le16                  cqid;
+       __u32                   rsvd12[4];
+};
+
+struct nvme_delete_queue {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __u32                   rsvd1[9];
+       __le16                  qid;
+       __u16                   rsvd10;
+       __u32                   rsvd11[5];
+};
+
+struct nvme_download_firmware {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __u32                   rsvd1[5];
+       __le64                  prp1;
+       __le64                  prp2;
+       __le32                  numd;
+       __le32                  offset;
+       __u32                   rsvd12[4];
+};
+
+struct nvme_command {
+       union {
+               struct nvme_common_command common;
+               struct nvme_rw_command rw;
+               struct nvme_identify identify;
+               struct nvme_features features;
+               struct nvme_create_cq create_cq;
+               struct nvme_create_sq create_sq;
+               struct nvme_delete_queue delete_queue;
+               struct nvme_download_firmware dlfw;
+       };
+};
+
+enum {
+       NVME_SC_SUCCESS                 = 0x0,
+       NVME_SC_INVALID_OPCODE          = 0x1,
+       NVME_SC_INVALID_FIELD           = 0x2,
+       NVME_SC_CMDID_CONFLICT          = 0x3,
+       NVME_SC_DATA_XFER_ERROR         = 0x4,
+       NVME_SC_POWER_LOSS              = 0x5,
+       NVME_SC_INTERNAL                = 0x6,
+       NVME_SC_ABORT_REQ               = 0x7,
+       NVME_SC_ABORT_QUEUE             = 0x8,
+       NVME_SC_FUSED_FAIL              = 0x9,
+       NVME_SC_FUSED_MISSING           = 0xa,
+       NVME_SC_INVALID_NS              = 0xb,
+       NVME_SC_LBA_RANGE               = 0x80,
+       NVME_SC_CAP_EXCEEDED            = 0x81,
+       NVME_SC_NS_NOT_READY            = 0x82,
+       NVME_SC_CQ_INVALID              = 0x100,
+       NVME_SC_QID_INVALID             = 0x101,
+       NVME_SC_QUEUE_SIZE              = 0x102,
+       NVME_SC_ABORT_LIMIT             = 0x103,
+       NVME_SC_ABORT_MISSING           = 0x104,
+       NVME_SC_ASYNC_LIMIT             = 0x105,
+       NVME_SC_FIRMWARE_SLOT           = 0x106,
+       NVME_SC_FIRMWARE_IMAGE          = 0x107,
+       NVME_SC_INVALID_VECTOR          = 0x108,
+       NVME_SC_INVALID_LOG_PAGE        = 0x109,
+       NVME_SC_INVALID_FORMAT          = 0x10a,
+       NVME_SC_BAD_ATTRIBUTES          = 0x180,
+       NVME_SC_WRITE_FAULT             = 0x280,
+       NVME_SC_READ_ERROR              = 0x281,
+       NVME_SC_GUARD_CHECK             = 0x282,
+       NVME_SC_APPTAG_CHECK            = 0x283,
+       NVME_SC_REFTAG_CHECK            = 0x284,
+       NVME_SC_COMPARE_FAILED          = 0x285,
+       NVME_SC_ACCESS_DENIED           = 0x286,
+};
+
+struct nvme_completion {
+       __le32  result;         /* Used by admin commands to return data */
+       __u32   rsvd;
+       __le16  sq_head;        /* how much of this queue may be reclaimed */
+       __le16  sq_id;          /* submission queue that generated this entry */
+       __u16   command_id;     /* of the command which completed */
+       __le16  status;         /* did the command fail, and if so, why? */
+};
+
+struct nvme_user_io {
+       __u8    opcode;
+       __u8    flags;
+       __u16   control;
+       __u16   nblocks;
+       __u16   rsvd;
+       __u64   metadata;
+       __u64   addr;
+       __u64   slba;
+       __u32   dsmgmt;
+       __u32   reftag;
+       __u16   apptag;
+       __u16   appmask;
+};
+
+struct nvme_admin_cmd {
+       __u8    opcode;
+       __u8    flags;
+       __u16   rsvd1;
+       __u32   nsid;
+       __u32   cdw2;
+       __u32   cdw3;
+       __u64   metadata;
+       __u64   addr;
+       __u32   metadata_len;
+       __u32   data_len;
+       __u32   cdw10;
+       __u32   cdw11;
+       __u32   cdw12;
+       __u32   cdw13;
+       __u32   cdw14;
+       __u32   cdw15;
+       __u32   timeout_ms;
+       __u32   result;
+};
+
+#define NVME_IOCTL_ID          _IO('N', 0x40)
+#define NVME_IOCTL_ADMIN_CMD   _IOWR('N', 0x41, struct nvme_admin_cmd)
+#define NVME_IOCTL_SUBMIT_IO   _IOW('N', 0x42, struct nvme_user_io)
+
+#endif /* _LINUX_NVME_H */
index 6f9d04a8533606afa788c351909c5dba74e54438..552fba9c7d5a5a17386901ba00c6f403513e636f 100644 (file)
@@ -43,7 +43,7 @@ enum oom_constraint {
 extern void compare_swap_oom_score_adj(int old_val, int new_val);
 extern int test_set_oom_score_adj(int new_val);
 
-extern unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
+extern unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
                        const nodemask_t *nodemask, unsigned long totalpages);
 extern int try_set_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_flags);
 extern void clear_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_flags);
index 961ecc7d30bc2ec69b87699c39e5db63a5aff0f7..a2d11771c84b1f4a8717670ddc6720f404a8820f 100644 (file)
@@ -10,8 +10,6 @@ enum {
        /* flags for mem_cgroup and file and I/O status */
        PCG_MOVE_LOCK, /* For race between move_account v.s. following bits */
        PCG_FILE_MAPPED, /* page is accounted as "mapped" */
-       /* No lock in page_cgroup */
-       PCG_ACCT_LRU, /* page has been accounted for (under lru_lock) */
        __NR_PCG_FLAGS,
 };
 
@@ -31,7 +29,6 @@ enum {
 struct page_cgroup {
        unsigned long flags;
        struct mem_cgroup *mem_cgroup;
-       struct list_head lru;           /* per cgroup LRU list */
 };
 
 void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat);
@@ -76,12 +73,6 @@ TESTPCGFLAG(Used, USED)
 CLEARPCGFLAG(Used, USED)
 SETPCGFLAG(Used, USED)
 
-SETPCGFLAG(AcctLRU, ACCT_LRU)
-CLEARPCGFLAG(AcctLRU, ACCT_LRU)
-TESTPCGFLAG(AcctLRU, ACCT_LRU)
-TESTCLEARPCGFLAG(AcctLRU, ACCT_LRU)
-
-
 SETPCGFLAG(FileMapped, FILE_MAPPED)
 CLEARPCGFLAG(FileMapped, FILE_MAPPED)
 TESTPCGFLAG(FileMapped, FILE_MAPPED)
@@ -122,39 +113,6 @@ static inline void move_unlock_page_cgroup(struct page_cgroup *pc,
        local_irq_restore(*flags);
 }
 
-#ifdef CONFIG_SPARSEMEM
-#define PCG_ARRAYID_WIDTH      SECTIONS_SHIFT
-#else
-#define PCG_ARRAYID_WIDTH      NODES_SHIFT
-#endif
-
-#if (PCG_ARRAYID_WIDTH > BITS_PER_LONG - NR_PCG_FLAGS)
-#error Not enough space left in pc->flags to store page_cgroup array IDs
-#endif
-
-/* pc->flags: ARRAY-ID | FLAGS */
-
-#define PCG_ARRAYID_MASK       ((1UL << PCG_ARRAYID_WIDTH) - 1)
-
-#define PCG_ARRAYID_OFFSET     (BITS_PER_LONG - PCG_ARRAYID_WIDTH)
-/*
- * Zero the shift count for non-existent fields, to prevent compiler
- * warnings and ensure references are optimized away.
- */
-#define PCG_ARRAYID_SHIFT      (PCG_ARRAYID_OFFSET * (PCG_ARRAYID_WIDTH != 0))
-
-static inline void set_page_cgroup_array_id(struct page_cgroup *pc,
-                                           unsigned long id)
-{
-       pc->flags &= ~(PCG_ARRAYID_MASK << PCG_ARRAYID_SHIFT);
-       pc->flags |= (id & PCG_ARRAYID_MASK) << PCG_ARRAYID_SHIFT;
-}
-
-static inline unsigned long page_cgroup_array_id(struct page_cgroup *pc)
-{
-       return (pc->flags >> PCG_ARRAYID_SHIFT) & PCG_ARRAYID_MASK;
-}
-
 #else /* CONFIG_CGROUP_MEM_RES_CTLR */
 struct page_cgroup;
 
@@ -183,7 +141,7 @@ static inline void __init page_cgroup_init_flatmem(void)
 extern unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
                                        unsigned short old, unsigned short new);
 extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id);
-extern unsigned short lookup_swap_cgroup(swp_entry_t ent);
+extern unsigned short lookup_swap_cgroup_id(swp_entry_t ent);
 extern int swap_cgroup_swapon(int type, unsigned long max_pages);
 extern void swap_cgroup_swapoff(int type);
 #else
@@ -195,7 +153,7 @@ unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
 }
 
 static inline
-unsigned short lookup_swap_cgroup(swp_entry_t ent)
+unsigned short lookup_swap_cgroup_id(swp_entry_t ent)
 {
        return 0;
 }
index ed17024d2ebee598044ec693632fc4cc1cd1eb7f..2aa12b8499c0446930ec46149d43e2c9bb8fe81d 100644 (file)
@@ -21,8 +21,7 @@ struct pagevec {
 };
 
 void __pagevec_release(struct pagevec *pvec);
-void ____pagevec_lru_add(struct pagevec *pvec, enum lru_list lru);
-void pagevec_strip(struct pagevec *pvec);
+void __pagevec_lru_add(struct pagevec *pvec, enum lru_list lru);
 unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
                pgoff_t start, unsigned nr_pages);
 unsigned pagevec_lookup_tag(struct pagevec *pvec,
@@ -59,7 +58,6 @@ static inline unsigned pagevec_add(struct pagevec *pvec, struct page *page)
        return pagevec_space(pvec);
 }
 
-
 static inline void pagevec_release(struct pagevec *pvec)
 {
        if (pagevec_count(pvec))
@@ -68,22 +66,22 @@ static inline void pagevec_release(struct pagevec *pvec)
 
 static inline void __pagevec_lru_add_anon(struct pagevec *pvec)
 {
-       ____pagevec_lru_add(pvec, LRU_INACTIVE_ANON);
+       __pagevec_lru_add(pvec, LRU_INACTIVE_ANON);
 }
 
 static inline void __pagevec_lru_add_active_anon(struct pagevec *pvec)
 {
-       ____pagevec_lru_add(pvec, LRU_ACTIVE_ANON);
+       __pagevec_lru_add(pvec, LRU_ACTIVE_ANON);
 }
 
 static inline void __pagevec_lru_add_file(struct pagevec *pvec)
 {
-       ____pagevec_lru_add(pvec, LRU_INACTIVE_FILE);
+       __pagevec_lru_add(pvec, LRU_INACTIVE_FILE);
 }
 
 static inline void __pagevec_lru_add_active_file(struct pagevec *pvec)
 {
-       ____pagevec_lru_add(pvec, LRU_ACTIVE_FILE);
+       __pagevec_lru_add(pvec, LRU_ACTIVE_FILE);
 }
 
 static inline void pagevec_lru_add_file(struct pagevec *pvec)
index d974a6e923721c05c457cfd5ba5147db9746497a..aefda0ec6e627d26d8ec7394f26d5aa01f0d37fd 100644 (file)
@@ -32,7 +32,8 @@
 #  else
 #    error "could not determine byte order"
 #  endif
-#elif defined(__BYTE_ORDER)
+#else
+#if defined(__BYTE_ORDER)
 #  if __BYTE_ORDER == __BIG_ENDIAN
 #    define _PATCHKEY(id) (0xfd00|id)
 #  elif __BYTE_ORDER == __LITTLE_ENDIAN
@@ -41,5 +42,6 @@
 #    error "could not determine byte order"
 #  endif
 #endif
+#endif
 
 #endif /* _LINUX_PATCHKEY_H */
index 79f337c47388ec759bd32190095a853afba978ce..c599f7eca1e7a4bb2f66ab1e644225c40cab8293 100644 (file)
@@ -129,7 +129,12 @@ struct mii_bus {
 };
 #define to_mii_bus(d) container_of(d, struct mii_bus, dev)
 
-struct mii_bus *mdiobus_alloc(void);
+struct mii_bus *mdiobus_alloc_size(size_t);
+static inline struct mii_bus *mdiobus_alloc(void)
+{
+       return mdiobus_alloc_size(0);
+}
+
 int mdiobus_register(struct mii_bus *bus);
 void mdiobus_unregister(struct mii_bus *bus);
 void mdiobus_free(struct mii_bus *bus);
index 8f1b928f777c34c02d203e6f29674cf94b2d9b4e..0d5b79365d0350cc73f185ae85f11235d56ac7cf 100644 (file)
@@ -162,10 +162,30 @@ struct tc_sfq_qopt {
        unsigned        flows;          /* Maximal number of flows  */
 };
 
+struct tc_sfqred_stats {
+       __u32           prob_drop;      /* Early drops, below max threshold */
+       __u32           forced_drop;    /* Early drops, after max threshold */
+       __u32           prob_mark;      /* Marked packets, below max threshold */
+       __u32           forced_mark;    /* Marked packets, after max threshold */
+       __u32           prob_mark_head; /* Marked packets, below max threshold */
+       __u32           forced_mark_head;/* Marked packets, after max threshold */
+};
+
 struct tc_sfq_qopt_v1 {
        struct tc_sfq_qopt v0;
        unsigned int    depth;          /* max number of packets per flow */
        unsigned int    headdrop;
+/* SFQRED parameters */
+       __u32           limit;          /* HARD maximal flow queue length (bytes) */
+       __u32           qth_min;        /* Min average length threshold (bytes) */
+       __u32           qth_max;        /* Max average length threshold (bytes) */
+       unsigned char   Wlog;           /* log(W)               */
+       unsigned char   Plog;           /* log(P_max/(qth_max-qth_min)) */
+       unsigned char   Scell_log;      /* cell size for idle damping */
+       unsigned char   flags;
+       __u32           max_P;          /* probability, high resolution */
+/* SFQRED stats */
+       struct tc_sfqred_stats stats;
 };
 
 
index cafe98d969480dff52bd1e32887319f771627a3b..84e6a55a1202d2d9b4db2e3dbb1f448ef78aab54 100644 (file)
@@ -6,6 +6,8 @@
  * Copyright (C) 1998 Paul Mackerras.
  */
 
+#ifndef _LINUX_PMU_H
+#define _LINUX_PMU_H
 
 #define PMU_DRIVER_VERSION     2
 
@@ -207,3 +209,5 @@ extern int pmu_sys_suspended;
 #endif
 
 #endif /* __KERNEL__ */
+
+#endif /* _LINUX_PMU_H */
index a3baeb2c216156831606a11c5bd8636d80b8b76c..7ddc7f1b480fd41318d94c0a39c8e2ff80f9c5f8 100644 (file)
 
 #define PR_MCE_KILL_GET 34
 
+/*
+ * Tune up process memory map specifics.
+ */
+#define PR_SET_MM              35
+# define PR_SET_MM_START_CODE          1
+# define PR_SET_MM_END_CODE            2
+# define PR_SET_MM_START_DATA          3
+# define PR_SET_MM_END_DATA            4
+# define PR_SET_MM_START_STACK         5
+# define PR_SET_MM_START_BRK           6
+# define PR_SET_MM_BRK                 7
+
 #endif /* _LINUX_PRCTL_H */
index 800f113bea66382fd16dc28c85eeae34e44761b0..c2f1f6a5fcb8a67f52c90c8397c7384534d3010a 100644 (file)
 
 #include <linux/compiler.h>            /* For unlikely.  */
 #include <linux/sched.h>               /* For struct task_struct.  */
+#include <linux/err.h>                 /* for IS_ERR_VALUE */
 
 
 extern long arch_ptrace(struct task_struct *child, long request,
@@ -127,8 +128,9 @@ extern void __ptrace_link(struct task_struct *child,
                          struct task_struct *new_parent);
 extern void __ptrace_unlink(struct task_struct *child);
 extern void exit_ptrace(struct task_struct *tracer);
-#define PTRACE_MODE_READ   1
-#define PTRACE_MODE_ATTACH 2
+#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. */
@@ -265,6 +267,15 @@ static inline void ptrace_release_task(struct task_struct *task)
 #define force_successful_syscall_return() do { } while (0)
 #endif
 
+#ifndef is_syscall_success
+/*
+ * On most systems we can tell if a syscall is a success based on if the retval
+ * is an error value.  On some systems like ia64 and powerpc they have different
+ * indicators of success/failure and must define their own.
+ */
+#define is_syscall_success(regs) (!IS_ERR_VALUE((unsigned long)(regs_return_value(regs))))
+#endif
+
 /*
  * <asm/ptrace.h> should define the following things inside #ifdef __KERNEL__.
  *
index 9d4539c52e53e5f3635345260049999ba90d735e..07e360b1b282b61b92c08fad6ebba553bc0bcb4d 100644 (file)
@@ -49,9 +49,6 @@
 #define RADIX_TREE_EXCEPTIONAL_ENTRY   2
 #define RADIX_TREE_EXCEPTIONAL_SHIFT   2
 
-#define radix_tree_indirect_to_ptr(ptr) \
-       radix_tree_indirect_to_ptr((void __force *)(ptr))
-
 static inline int radix_tree_is_indirect_ptr(void *ptr)
 {
        return (int)((unsigned long)ptr & RADIX_TREE_INDIRECT_PTR);
index 1afb9954bbf125fc3da62e2d9ef631b6508b5b89..1cdd62a2788a99436f666ec9d9e194f3c341e769 100644 (file)
@@ -158,7 +158,7 @@ static inline void page_dup_rmap(struct page *page)
  * Called from mm/vmscan.c to handle paging out
  */
 int page_referenced(struct page *, int is_locked,
-                       struct mem_cgroup *cnt, unsigned long *vm_flags);
+                       struct mem_cgroup *memcg, unsigned long *vm_flags);
 int page_referenced_one(struct page *, struct vm_area_struct *,
        unsigned long address, unsigned int *mapcount, unsigned long *vm_flags);
 
@@ -236,7 +236,7 @@ int rmap_walk(struct page *page, int (*rmap_one)(struct page *,
 #define anon_vma_link(vma)     do {} while (0)
 
 static inline int page_referenced(struct page *page, int is_locked,
-                                 struct mem_cgroup *cnt,
+                                 struct mem_cgroup *memcg,
                                  unsigned long *vm_flags)
 {
        *vm_flags = 0;
index 21cd0303af5107ef944b27c334750d6cedfb13ef..4032ec1cf836fe2055a422c8d2356a4ea620117a 100644 (file)
@@ -2275,7 +2275,7 @@ extern void __cleanup_sighand(struct sighand_struct *);
 extern void exit_itimers(struct signal_struct *);
 extern void flush_itimer_signals(void);
 
-extern NORET_TYPE void do_group_exit(int);
+extern void do_group_exit(int);
 
 extern void daemonize(const char *, ...);
 extern int allow_signal(int);
index 0ccceb9b104640f91e9738c7b467e0da1a74c7b8..83c18e8c846d399832c5ab3ab2e5500286b26186 100644 (file)
@@ -54,8 +54,8 @@ struct user_namespace;
  * These functions are in security/capability.c and are used
  * as the default capabilities functions
  */
-extern int cap_capable(struct task_struct *tsk, const struct cred *cred,
-                      struct user_namespace *ns, int cap, int audit);
+extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
+                      int cap, int audit);
 extern int cap_settime(const struct timespec *ts, const struct timezone *tz);
 extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode);
 extern int cap_ptrace_traceme(struct task_struct *parent);
@@ -96,7 +96,6 @@ struct xfrm_user_sec_ctx;
 struct seq_file;
 
 extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
-extern int cap_netlink_recv(struct sk_buff *skb, int cap);
 
 void reset_security_ops(void);
 
@@ -799,12 +798,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @skb contains the sk_buff structure for the netlink message.
  *     Return 0 if the information was successfully saved and message
  *     is allowed to be transmitted.
- * @netlink_recv:
- *     Check permission before processing the received netlink message in
- *     @skb.
- *     @skb contains the sk_buff structure for the netlink message.
- *     @cap indicates the capability required
- *     Return 0 if permission is granted.
  *
  * Security hooks for Unix domain networking.
  *
@@ -1268,7 +1261,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  * @capable:
  *     Check whether the @tsk process has the @cap capability in the indicated
  *     credentials.
- *     @tsk contains the task_struct for the process.
  *     @cred contains the credentials to use.
  *     @ns contains the user namespace we want the capability in
  *     @cap contains the capability <include/linux/capability.h>.
@@ -1392,8 +1384,8 @@ struct security_operations {
                       const kernel_cap_t *effective,
                       const kernel_cap_t *inheritable,
                       const kernel_cap_t *permitted);
-       int (*capable) (struct task_struct *tsk, const struct cred *cred,
-                       struct user_namespace *ns, int cap, int audit);
+       int (*capable) (const struct cred *cred, struct user_namespace *ns,
+                       int cap, int audit);
        int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
        int (*quota_on) (struct dentry *dentry);
        int (*syslog) (int type);
@@ -1563,7 +1555,6 @@ struct security_operations {
                          struct sembuf *sops, unsigned nsops, int alter);
 
        int (*netlink_send) (struct sock *sk, struct sk_buff *skb);
-       int (*netlink_recv) (struct sk_buff *skb, int cap);
 
        void (*d_instantiate) (struct dentry *dentry, struct inode *inode);
 
@@ -1675,12 +1666,10 @@ int security_capset(struct cred *new, const struct cred *old,
                    const kernel_cap_t *effective,
                    const kernel_cap_t *inheritable,
                    const kernel_cap_t *permitted);
-int security_capable(struct user_namespace *ns, const struct cred *cred,
-                       int cap);
-int security_real_capable(struct task_struct *tsk, struct user_namespace *ns,
+int security_capable(const struct cred *cred, struct user_namespace *ns,
                        int cap);
-int security_real_capable_noaudit(struct task_struct *tsk,
-                       struct user_namespace *ns, int cap);
+int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns,
+                            int cap);
 int security_quotactl(int cmds, int type, int id, struct super_block *sb);
 int security_quota_on(struct dentry *dentry);
 int security_syslog(int type);
@@ -1817,7 +1806,6 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode);
 int security_getprocattr(struct task_struct *p, char *name, char **value);
 int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
 int security_netlink_send(struct sock *sk, struct sk_buff *skb);
-int security_netlink_recv(struct sk_buff *skb, int cap);
 int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
 int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
 void security_release_secctx(char *secdata, u32 seclen);
@@ -1875,32 +1863,15 @@ static inline int security_capset(struct cred *new,
        return cap_capset(new, old, effective, inheritable, permitted);
 }
 
-static inline int security_capable(struct user_namespace *ns,
-                                  const struct cred *cred, int cap)
-{
-       return cap_capable(current, cred, ns, cap, SECURITY_CAP_AUDIT);
-}
-
-static inline int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, int cap)
+static inline int security_capable(const struct cred *cred,
+                                  struct user_namespace *ns, int cap)
 {
-       int ret;
-
-       rcu_read_lock();
-       ret = cap_capable(tsk, __task_cred(tsk), ns, cap, SECURITY_CAP_AUDIT);
-       rcu_read_unlock();
-       return ret;
+       return cap_capable(cred, ns, cap, SECURITY_CAP_AUDIT);
 }
 
-static inline
-int security_real_capable_noaudit(struct task_struct *tsk, struct user_namespace *ns, int cap)
-{
-       int ret;
-
-       rcu_read_lock();
-       ret = cap_capable(tsk, __task_cred(tsk), ns, cap,
-                              SECURITY_CAP_NOAUDIT);
-       rcu_read_unlock();
-       return ret;
+static inline int security_capable_noaudit(const struct cred *cred,
+                                          struct user_namespace *ns, int cap) {
+       return cap_capable(cred, ns, cap, SECURITY_CAP_NOAUDIT);
 }
 
 static inline int security_quotactl(int cmds, int type, int id,
@@ -2517,11 +2488,6 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
        return cap_netlink_send(sk, skb);
 }
 
-static inline int security_netlink_recv(struct sk_buff *skb, int cap)
-{
-       return cap_netlink_recv(skb, cap);
-}
-
 static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 {
        return -EOPNOTSUPP;
index b67305e3ad57a5078b79fec8bca9f060739e08e1..c91ace70c21d5c282f4b8b860f6fabefc2368d47 100644 (file)
 /* Xilinx PSS UART */
 #define PORT_XUARTPS   98
 
+/* Atheros AR933X SoC */
+#define PORT_AR933X    99
+
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
index cb2dd118cc0ffb91e62ad7746d230b0376f442dd..8cd7fe59cf1a6f957c9376f4c5b5333fdf4f817e 100644 (file)
@@ -30,7 +30,7 @@ struct sh_desc {
        struct sh_dmae_regs hw;
        struct list_head node;
        struct dma_async_tx_descriptor async_tx;
-       enum dma_data_direction direction;
+       enum dma_transfer_direction direction;
        dma_cookie_t cookie;
        size_t partial;
        int chunks;
@@ -48,6 +48,7 @@ struct sh_dmae_channel {
        unsigned int    offset;
        unsigned int    dmars;
        unsigned int    dmars_bit;
+       unsigned int    chclr_offset;
 };
 
 struct sh_dmae_pdata {
@@ -68,6 +69,7 @@ struct sh_dmae_pdata {
        unsigned int dmaor_is_32bit:1;
        unsigned int needs_tend_set:1;
        unsigned int no_dmars:1;
+       unsigned int chclr_present:1;
 };
 
 /* DMA register */
diff --git a/include/linux/sirfsoc_dma.h b/include/linux/sirfsoc_dma.h
new file mode 100644 (file)
index 0000000..29d9593
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _SIRFSOC_DMA_H_
+#define _SIRFSOC_DMA_H_
+
+bool sirfsoc_dma_filter_id(struct dma_chan *chan, void *chan_id);
+
+#endif
index 44dcf057043250362eb007650eecdf3d2003ca39..fae20ba01fbf8e431359b1080be9afec1ab11d6a 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef _LINUX_SOUND_H
+#define _LINUX_SOUND_H
 
 /*
  * Minor numbers for the sound driver.
@@ -42,3 +44,5 @@ extern void unregister_sound_mixer(int unit);
 extern void unregister_sound_midi(int unit);
 extern void unregister_sound_dsp(int unit);
 #endif /* __KERNEL__ */
+
+#endif /* _LINUX_SOUND_H */
index fe204fe39f7cae7a76164da83cb251f2c5dee7b4..dfcf86f013a9492624ba14874be39380199ed236 100644 (file)
@@ -198,7 +198,8 @@ typedef struct seq_event_rec {
 #  else
 #    error "could not determine byte order"
 #  endif
-#elif defined(__BYTE_ORDER)
+#else
+# if defined(__BYTE_ORDER)
 #  if __BYTE_ORDER == __BIG_ENDIAN
 #    define AFMT_S16_NE AFMT_S16_BE
 #  elif __BYTE_ORDER == __LITTLE_ENDIAN
@@ -206,6 +207,7 @@ typedef struct seq_event_rec {
 #  else
 #    error "could not determine byte order"
 #  endif
+# endif
 #endif
 
 /*
index 8620f79658d42e593e313124b189d22c1cde7a42..dfa900948af79a6fbd277bbbb5b56c0c7842cec4 100644 (file)
@@ -109,7 +109,7 @@ static inline int register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u
 
 int    svc_reg_xprt_class(struct svc_xprt_class *);
 void   svc_unreg_xprt_class(struct svc_xprt_class *);
-void   svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *,
+void   svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *,
                      struct svc_serv *);
 int    svc_create_xprt(struct svc_serv *, const char *, struct net *,
                        const int, const unsigned short, int);
@@ -118,7 +118,6 @@ void        svc_xprt_received(struct svc_xprt *);
 void   svc_xprt_put(struct svc_xprt *xprt);
 void   svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt);
 void   svc_close_xprt(struct svc_xprt *xprt);
-void   svc_delete_xprt(struct svc_xprt *xprt);
 int    svc_port_is_privileged(struct sockaddr *sin);
 int    svc_print_xprts(char *buf, int maxlen);
 struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
index 85c50b40759de9df4528077a64b6346a472f9dfb..c84e9741cb2a25471838c2c31503b8d550c8bfbf 100644 (file)
@@ -34,7 +34,7 @@ struct svc_sock {
 /*
  * Function prototypes.
  */
-void           svc_close_all(struct list_head *);
+void           svc_close_all(struct svc_serv *);
 int            svc_recv(struct svc_rqst *, long);
 int            svc_send(struct svc_rqst *);
 void           svc_drop(struct svc_rqst *);
index ecdaeb98b293727274b6511ee7ef523c00324564..5cf685086dd3f6d728b6a0374f096a080b1bfc1d 100644 (file)
@@ -312,7 +312,6 @@ struct tty_driver {
         */
        struct tty_struct **ttys;
        struct ktermios **termios;
-       struct ktermios **termios_locked;
        void *driver_state;
 
        /*
index 4b752d5ee80e8c7aca14f02eedc72dac6d7d3d8d..5e11f8a1f8674aa0465a310f862c7c3df9cc7cf0 100644 (file)
@@ -343,6 +343,8 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_NV21    v4l2_fourcc('N', 'V', '2', '1') /* 12  Y/CrCb 4:2:0  */
 #define V4L2_PIX_FMT_NV16    v4l2_fourcc('N', 'V', '1', '6') /* 16  Y/CbCr 4:2:2  */
 #define V4L2_PIX_FMT_NV61    v4l2_fourcc('N', 'V', '6', '1') /* 16  Y/CrCb 4:2:2  */
+#define V4L2_PIX_FMT_NV24    v4l2_fourcc('N', 'V', '2', '4') /* 24  Y/CbCr 4:4:4  */
+#define V4L2_PIX_FMT_NV42    v4l2_fourcc('N', 'V', '4', '2') /* 24  Y/CrCb 4:4:4  */
 
 /* two non contiguous planes - one Y, one Cr + Cb interleaved  */
 #define V4L2_PIX_FMT_NV12M   v4l2_fourcc('N', 'M', '1', '2') /* 12  Y/CbCr 4:2:0  */
@@ -401,6 +403,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_SPCA561  v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */
 #define V4L2_PIX_FMT_PAC207   v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */
 #define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
+#define V4L2_PIX_FMT_JL2005BCD v4l2_fourcc('J', 'L', '2', '0') /* compressed RGGB bayer */
 #define V4L2_PIX_FMT_SN9C2028 v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */
 #define V4L2_PIX_FMT_SQ905C   v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
 #define V4L2_PIX_FMT_PJPG     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
@@ -742,6 +745,48 @@ struct v4l2_crop {
        struct v4l2_rect        c;
 };
 
+/* Hints for adjustments of selection rectangle */
+#define V4L2_SEL_FLAG_GE       0x00000001
+#define V4L2_SEL_FLAG_LE       0x00000002
+
+/* Selection targets */
+
+/* current cropping area */
+#define V4L2_SEL_TGT_CROP_ACTIVE       0
+/* default cropping area */
+#define V4L2_SEL_TGT_CROP_DEFAULT      1
+/* cropping bounds */
+#define V4L2_SEL_TGT_CROP_BOUNDS       2
+/* current composing area */
+#define V4L2_SEL_TGT_COMPOSE_ACTIVE    256
+/* default composing area */
+#define V4L2_SEL_TGT_COMPOSE_DEFAULT   257
+/* composing bounds */
+#define V4L2_SEL_TGT_COMPOSE_BOUNDS    258
+/* current composing area plus all padding pixels */
+#define V4L2_SEL_TGT_COMPOSE_PADDED    259
+
+/**
+ * struct v4l2_selection - selection info
+ * @type:      buffer type (do not use *_MPLANE types)
+ * @target:    selection target, used to choose one of possible rectangles
+ * @flags:     constraints flags
+ * @r:         coordinates of selection window
+ * @reserved:  for future use, rounds structure size to 64 bytes, set to zero
+ *
+ * Hardware may use multiple helper window to process a video stream.
+ * The structure is used to exchange this selection areas between
+ * an application and a driver.
+ */
+struct v4l2_selection {
+       __u32                   type;
+       __u32                   target;
+       __u32                   flags;
+       struct v4l2_rect        r;
+       __u32                   reserved[9];
+};
+
+
 /*
  *      A N A L O G   V I D E O   S T A N D A R D
  */
@@ -1131,6 +1176,7 @@ struct v4l2_querymenu {
 #define V4L2_CTRL_FLAG_NEXT_CTRL       0x80000000
 
 /*  User-class control IDs defined by V4L2 */
+#define V4L2_CID_MAX_CTRLS             1024
 #define V4L2_CID_BASE                  (V4L2_CTRL_CLASS_USER | 0x900)
 #define V4L2_CID_USER_BASE             V4L2_CID_BASE
 /*  IDs reserved for driver specific controls */
@@ -1204,10 +1250,10 @@ enum v4l2_colorfx {
 #define V4L2_CID_MIN_BUFFERS_FOR_CAPTURE       (V4L2_CID_BASE+39)
 #define V4L2_CID_MIN_BUFFERS_FOR_OUTPUT                (V4L2_CID_BASE+40)
 
-/* last CID + 1 */
-#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+41)
+#define V4L2_CID_ALPHA_COMPONENT               (V4L2_CID_BASE+41)
 
-/* Minimum number of buffer neede by the device */
+/* last CID + 1 */
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+42)
 
 /*  MPEG-class control IDs defined by V4L2 */
 #define V4L2_CID_MPEG_BASE                     (V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -1682,6 +1728,8 @@ enum v4l2_flash_strobe_source {
 #define V4L2_FLASH_FAULT_TIMEOUT               (1 << 1)
 #define V4L2_FLASH_FAULT_OVER_TEMPERATURE      (1 << 2)
 #define V4L2_FLASH_FAULT_SHORT_CIRCUIT         (1 << 3)
+#define V4L2_FLASH_FAULT_OVER_CURRENT          (1 << 4)
+#define V4L2_FLASH_FAULT_INDICATOR             (1 << 5)
 
 #define V4L2_CID_FLASH_CHARGE                  (V4L2_CID_FLASH_CLASS_BASE + 11)
 #define V4L2_CID_FLASH_READY                   (V4L2_CID_FLASH_CLASS_BASE + 12)
@@ -2255,6 +2303,10 @@ struct v4l2_create_buffers {
 #define VIDIOC_CREATE_BUFS     _IOWR('V', 92, struct v4l2_create_buffers)
 #define VIDIOC_PREPARE_BUF     _IOWR('V', 93, struct v4l2_buffer)
 
+/* Experimental selection API */
+#define VIDIOC_G_SELECTION     _IOWR('V', 94, struct v4l2_selection)
+#define VIDIOC_S_SELECTION     _IOWR('V', 95, struct v4l2_selection)
+
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
 
index 4c069d8bd74038568acc37992c4eb111188f261b..d0018d27c281ffa3a7135c1aa1a8deffc1b900ca 100644 (file)
@@ -25,70 +25,18 @@ struct virtqueue {
        void *priv;
 };
 
-/**
- * operations for virtqueue
- * virtqueue_add_buf: expose buffer to other end
- *     vq: the struct virtqueue we're talking about.
- *     sg: the description of the buffer(s).
- *     out_num: the number of sg readable by other side
- *     in_num: the number of sg which are writable (after readable ones)
- *     data: the token identifying the buffer.
- *     gfp: how to do memory allocations (if necessary).
- *      Returns remaining capacity of queue (sg segments) or a negative error.
- * virtqueue_kick: update after add_buf
- *     vq: the struct virtqueue
- *     After one or more add_buf calls, invoke this to kick the other side.
- * virtqueue_get_buf: get the next used buffer
- *     vq: the struct virtqueue we're talking about.
- *     len: the length written into the buffer
- *     Returns NULL or the "data" token handed to add_buf.
- * virtqueue_disable_cb: disable callbacks
- *     vq: the struct virtqueue we're talking about.
- *     Note that this is not necessarily synchronous, hence unreliable and only
- *     useful as an optimization.
- * virtqueue_enable_cb: restart callbacks after disable_cb.
- *     vq: the struct virtqueue we're talking about.
- *     This re-enables callbacks; it returns "false" if there are pending
- *     buffers in the queue, to detect a possible race between the driver
- *     checking for more work, and enabling callbacks.
- * virtqueue_enable_cb_delayed: restart callbacks after disable_cb.
- *     vq: the struct virtqueue we're talking about.
- *     This re-enables callbacks but hints to the other side to delay
- *     interrupts until most of the available buffers have been processed;
- *     it returns "false" if there are many pending buffers in the queue,
- *     to detect a possible race between the driver checking for more work,
- *     and enabling callbacks.
- * virtqueue_detach_unused_buf: detach first unused buffer
- *     vq: the struct virtqueue we're talking about.
- *     Returns NULL or the "data" token handed to add_buf
- * virtqueue_get_vring_size: return the size of the virtqueue's vring
- *     vq: the struct virtqueue containing the vring of interest.
- *     Returns the size of the vring.
- *
- * Locking rules are straightforward: the driver is responsible for
- * locking.  No two operations may be invoked simultaneously, with the exception
- * of virtqueue_disable_cb.
- *
- * All operations can be called in any context.
- */
+int virtqueue_add_buf(struct virtqueue *vq,
+                     struct scatterlist sg[],
+                     unsigned int out_num,
+                     unsigned int in_num,
+                     void *data,
+                     gfp_t gfp);
 
-int virtqueue_add_buf_gfp(struct virtqueue *vq,
-                         struct scatterlist sg[],
-                         unsigned int out_num,
-                         unsigned int in_num,
-                         void *data,
-                         gfp_t gfp);
+void virtqueue_kick(struct virtqueue *vq);
 
-static inline int virtqueue_add_buf(struct virtqueue *vq,
-                                   struct scatterlist sg[],
-                                   unsigned int out_num,
-                                   unsigned int in_num,
-                                   void *data)
-{
-       return virtqueue_add_buf_gfp(vq, sg, out_num, in_num, data, GFP_ATOMIC);
-}
+bool virtqueue_kick_prepare(struct virtqueue *vq);
 
-void virtqueue_kick(struct virtqueue *vq);
+void virtqueue_notify(struct virtqueue *vq);
 
 void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
 
@@ -146,6 +94,11 @@ struct virtio_driver {
        int (*probe)(struct virtio_device *dev);
        void (*remove)(struct virtio_device *dev);
        void (*config_changed)(struct virtio_device *dev);
+#ifdef CONFIG_PM
+       int (*freeze)(struct virtio_device *dev);
+       int (*thaw)(struct virtio_device *dev);
+       int (*restore)(struct virtio_device *dev);
+#endif
 };
 
 int register_virtio_driver(struct virtio_driver *drv);
index 36be0f6e18a9cf9608c4288cb3343f618e329c87..e338730c2660f9e6efb593858bc672c486c8f996 100644 (file)
@@ -168,6 +168,7 @@ struct virtqueue;
 struct virtqueue *vring_new_virtqueue(unsigned int num,
                                      unsigned int vring_align,
                                      struct virtio_device *vdev,
+                                     bool weak_barriers,
                                      void *pages,
                                      void (*notify)(struct virtqueue *vq),
                                      void (*callback)(struct virtqueue *vq),
index 7e749088910d3ed2e926070eb9e7326c7753495b..74bc53bcfdcf6bf6d68ed6e799ca267790c9a66a 100644 (file)
 #define  ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM      ZORRO_ID(VILLAGE_TRONIC, 0x0B, 0)
 #define  ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG      ZORRO_ID(VILLAGE_TRONIC, 0x0C, 0)
 #define  ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_SEGMENTED_MODE   ZORRO_ID(VILLAGE_TRONIC, 0x0D, 0)
-#define  ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_MEM1          ZORRO_ID(VILLAGE_TRONIC, 0x15, 0)
-#define  ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_MEM2          ZORRO_ID(VILLAGE_TRONIC, 0x16, 0)
+#define  ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1          ZORRO_ID(VILLAGE_TRONIC, 0x15, 0)
+#define  ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2          ZORRO_ID(VILLAGE_TRONIC, 0x16, 0)
 #define  ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG           ZORRO_ID(VILLAGE_TRONIC, 0x17, 0)
 #define  ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3               ZORRO_ID(VILLAGE_TRONIC, 0x18, 0)
 #define  ZORRO_PROD_VILLAGE_TRONIC_ARIADNE                     ZORRO_ID(VILLAGE_TRONIC, 0xC9, 0)
diff --git a/include/media/as3645a.h b/include/media/as3645a.h
new file mode 100644 (file)
index 0000000..5075496
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * include/media/as3645a.h
+ *
+ * Copyright (C) 2008-2011 Nokia Corporation
+ *
+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __AS3645A_H__
+#define __AS3645A_H__
+
+#include <media/v4l2-subdev.h>
+
+#define AS3645A_NAME                           "as3645a"
+#define AS3645A_I2C_ADDR                       (0x60 >> 1) /* W:0x60, R:0x61 */
+
+#define AS3645A_FLASH_TIMEOUT_MIN              100000  /* us */
+#define AS3645A_FLASH_TIMEOUT_MAX              850000
+#define AS3645A_FLASH_TIMEOUT_STEP             50000
+
+#define AS3645A_FLASH_INTENSITY_MIN            200     /* mA */
+#define AS3645A_FLASH_INTENSITY_MAX_1LED       500
+#define AS3645A_FLASH_INTENSITY_MAX_2LEDS      400
+#define AS3645A_FLASH_INTENSITY_STEP           20
+
+#define AS3645A_TORCH_INTENSITY_MIN            20      /* mA */
+#define AS3645A_TORCH_INTENSITY_MAX            160
+#define AS3645A_TORCH_INTENSITY_STEP           20
+
+#define AS3645A_INDICATOR_INTENSITY_MIN                0       /* uA */
+#define AS3645A_INDICATOR_INTENSITY_MAX                10000
+#define AS3645A_INDICATOR_INTENSITY_STEP       2500
+
+/*
+ * as3645a_platform_data - Flash controller platform data
+ * @set_power: Set power callback
+ * @vref:      VREF offset (0=0V, 1=+0.3V, 2=-0.3V, 3=+0.6V)
+ * @peak:      Inductor peak current limit (0=1.25A, 1=1.5A, 2=1.75A, 3=2.0A)
+ * @ext_strobe:        True if external flash strobe can be used
+ * @flash_max_current: Max flash current (mA, <= AS3645A_FLASH_INTENSITY_MAX)
+ * @torch_max_current: Max torch current (mA, >= AS3645A_TORCH_INTENSITY_MAX)
+ * @timeout_max:       Max flash timeout (us, <= AS3645A_FLASH_TIMEOUT_MAX)
+ */
+struct as3645a_platform_data {
+       int (*set_power)(struct v4l2_subdev *subdev, int on);
+       unsigned int vref;
+       unsigned int peak;
+       bool ext_strobe;
+
+       /* Flash and torch currents and timeout limits */
+       unsigned int flash_max_current;
+       unsigned int torch_max_current;
+       unsigned int timeout_max;
+};
+
+#endif /* __AS3645A_H__ */
index 26cece5951218072e249327561ba5289c60575d7..656823075709d6728cc2b2ec182e4827d5b319f1 100644 (file)
@@ -110,10 +110,12 @@ struct isi_platform_data {
        u8 hsync_act_low;
        u8 vsync_act_low;
        u8 pclk_act_falling;
-       u8 isi_full_mode;
+       u8 full_mode;
        u32 data_width_flags;
        /* Using for ISI_CFG1 */
        u32 frate;
+       /* Using for ISI_MCK */
+       u32 mck_hz;
 };
 
 #endif /* __ATMEL_ISI_H__ */
index 46d1a141208ef5fc9e768615ce21ba5a05c1d510..783c5bdd63eb8132acc98cb4115986004ffce29a 100644 (file)
@@ -85,6 +85,7 @@ enum cx25840_video_input {
        CX25840_NONE1_CH3 = 0x800000c0,
        CX25840_SVIDEO_ON = 0x80000100,
        CX25840_COMPONENT_ON = 0x80000200,
+       CX25840_DIF_ON = 0x80000400,
 };
 
 enum cx25840_audio_input {
index 8b11fb0379801737b510f063a9a8c341caeeb991..8bc1b3c0e6790501d1853e59841867f5709afed4 100644 (file)
@@ -63,6 +63,7 @@ struct vpbe_output {
         * output basis. If per mode is needed, we may have to move this to
         * mode_info structure
         */
+       enum v4l2_mbus_pixelcode if_params;
 };
 
 /* encoder configuration info */
@@ -74,6 +75,15 @@ struct encoder_config_info {
        struct i2c_board_info board_info;
 };
 
+/*amplifier configuration info */
+struct amp_config_info {
+       char module_name[32];
+       /* Is this an i2c device ? */
+       unsigned int is_i2c:1;
+       /* i2c subdevice board info */
+       struct i2c_board_info board_info;
+};
+
 /* structure for defining vpbe display subsystem components */
 struct vpbe_config {
        char module_name[32];
@@ -84,6 +94,8 @@ struct vpbe_config {
        /* external encoder information goes here */
        int num_ext_encoders;
        struct encoder_config_info *ext_encoders;
+       /* amplifier information goes here */
+       struct amp_config_info *amp;
        int num_outputs;
        /* Order is venc outputs followed by LCD and then external encoders */
        struct vpbe_output *outputs;
@@ -158,6 +170,8 @@ struct vpbe_device {
        struct v4l2_subdev **encoders;
        /* current encoder index */
        int current_sd_index;
+       /* external amplifier v4l2 subdevice */
+       struct v4l2_subdev *amp;
        struct mutex lock;
        /* device initialized */
        int initialized;
@@ -165,6 +179,8 @@ struct vpbe_device {
        struct clk *dac_clk;
        /* osd_device pointer */
        struct osd_state *osd_device;
+       /* venc device pointer */
+       struct venc_platform_data *venc_device;
        /*
         * fields below are accessed by users of vpbe_device. Not the
         * ones above
index 426c205831a2f73681366f0293c3fdc27809b140..6b57334f402996341e584fcc0177054140663ba5 100644 (file)
 
 struct venc_platform_data {
        enum vpbe_version venc_type;
+       int (*setup_pinmux)(enum v4l2_mbus_pixelcode if_type,
+                           int field);
        int (*setup_clock)(enum vpbe_enc_timings_type type,
                           unsigned int mode);
+       int (*setup_if_config)(enum v4l2_mbus_pixelcode pixcode);
        /* Number of LCD outputs supported */
        int num_lcd_outputs;
+       struct vpbe_if_params *lcd_if_params;
 };
 
 enum venc_ioctls {
index cd8bca63a502975340839b9c54174bc44ba17f97..29e7bba78ffeb540f597e25ac3b221ed88001267 100644 (file)
@@ -98,7 +98,7 @@ struct media_entity {
 
                /* Sub-device specifications */
                /* Nothing needed yet */
-       };
+       } info;
 };
 
 static inline u32 media_entity_type(struct media_entity *entity)
index e917b1da65778088b3e2b00239587e589138be48..042849a34640994e34d49a6815702e1db102b029 100644 (file)
@@ -58,7 +58,7 @@ enum {
  *             ISP_LANE_SHIFT_4 - CAMEXT[13:4] -> CAM[9:0]
  *             ISP_LANE_SHIFT_6 - CAMEXT[13:6] -> CAM[7:0]
  * @clk_pol: Pixel clock polarity
- *             0 - Non Inverted, 1 - Inverted
+ *             0 - Sample on rising edge, 1 - Sample on falling edge
  * @hs_pol: Horizontal synchronization polarity
  *             0 - Active high, 1 - Active low
  * @vs_pol: Vertical synchronization polarity
diff --git a/include/media/pwc-ioctl.h b/include/media/pwc-ioctl.h
deleted file mode 100644 (file)
index 1ed1e61..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-#ifndef PWC_IOCTL_H
-#define PWC_IOCTL_H
-
-/* (C) 2001-2004 Nemosoft Unv.
-   (C) 2004-2006 Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   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
-*/
-
-/* This is pwc-ioctl.h belonging to PWC 10.0.10
-   It contains structures and defines to communicate from user space
-   directly to the driver.
- */
-
-/*
-   Changes
-   2001/08/03  Alvarado   Added ioctl constants to access methods for
-                         changing white balance and red/blue gains
-   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
-   2003/12/13  Nemosft Unv. Some modifications to make interfacing to
-              PWCX easier
-   2006/01/01  Luc Saillard Add raw format definition
- */
-
-/* These are private ioctl() commands, specific for the Philips webcams.
-   They contain functions not found in other webcams, and settings not
-   specified in the Video4Linux API.
-
-   The #define names are built up like follows:
-   VIDIOC              VIDeo IOCtl prefix
-        PWC            Philps WebCam
-           G           optional: Get
-           S           optional: Set
-            ...        the function
- */
-
-#include <linux/types.h>
-
-/* Enumeration of image sizes */
-#define PSZ_SQCIF      0x00
-#define PSZ_QSIF       0x01
-#define PSZ_QCIF       0x02
-#define PSZ_SIF                0x03
-#define PSZ_CIF                0x04
-#define PSZ_VGA                0x05
-#define PSZ_MAX                6
-
-
-/* The frame rate is encoded in the video_window.flags parameter using
-   the upper 16 bits, since some flags are defined nowadays. The following
-   defines provide a mask and shift to filter out this value.
-   This value can also be passing using the private flag when using v4l2 and
-   VIDIOC_S_FMT ioctl.
-
-   In 'Snapshot' mode the camera freezes its automatic exposure and colour
-   balance controls.
- */
-#define PWC_FPS_SHIFT          16
-#define PWC_FPS_MASK           0x00FF0000
-#define PWC_FPS_FRMASK         0x003F0000
-#define PWC_FPS_SNAPSHOT       0x00400000
-#define PWC_QLT_MASK           0x03000000
-#define PWC_QLT_SHIFT          24
-
-
-/* structure for transferring x & y coordinates */
-struct pwc_coord
-{
-       int x, y;               /* guess what */
-       int size;               /* size, or offset */
-};
-
-
-/* Used with VIDIOCPWCPROBE */
-struct pwc_probe
-{
-       char name[32];
-       int type;
-};
-
-struct pwc_serial
-{
-       char serial[30];        /* String with serial number. Contains terminating 0 */
-};
-
-/* pwc_whitebalance.mode values */
-#define PWC_WB_INDOOR          0
-#define PWC_WB_OUTDOOR         1
-#define PWC_WB_FL              2
-#define PWC_WB_MANUAL          3
-#define PWC_WB_AUTO            4
-
-/* Used with VIDIOCPWC[SG]AWB (Auto White Balance).
-   Set mode to one of the PWC_WB_* values above.
-   *red and *blue are the respective gains of these colour components inside
-   the camera; range 0..65535
-   When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read;
-   otherwise undefined.
-   'read_red' and 'read_blue' are read-only.
-*/
-struct pwc_whitebalance
-{
-       int mode;
-       int manual_red, manual_blue;    /* R/W */
-       int read_red, read_blue;        /* R/O */
-};
-
-/*
-   'control_speed' and 'control_delay' are used in automatic whitebalance mode,
-   and tell the camera how fast it should react to changes in lighting, and
-   with how much delay. Valid values are 0..65535.
-*/
-struct pwc_wb_speed
-{
-       int control_speed;
-       int control_delay;
-
-};
-
-/* Used with VIDIOCPWC[SG]LED */
-struct pwc_leds
-{
-       int led_on;                     /* Led on-time; range = 0..25000 */
-       int led_off;                    /* Led off-time; range = 0..25000  */
-};
-
-/* Image size (used with GREALSIZE) */
-struct pwc_imagesize
-{
-       int width;
-       int height;
-};
-
-/* Defines and structures for Motorized Pan & Tilt */
-#define PWC_MPT_PAN            0x01
-#define PWC_MPT_TILT           0x02
-#define PWC_MPT_TIMEOUT                0x04 /* for status */
-
-/* Set angles; when absolute != 0, the angle is absolute and the
-   driver calculates the relative offset for you. This can only
-   be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
-   absolute angles.
- */
-struct pwc_mpt_angles
-{
-       int absolute;           /* write-only */
-       int pan;                /* degrees * 100 */
-       int tilt;               /* degress * 100 */
-};
-
-/* Range of angles of the camera, both horizontally and vertically.
- */
-struct pwc_mpt_range
-{
-       int pan_min, pan_max;           /* degrees * 100 */
-       int tilt_min, tilt_max;
-};
-
-struct pwc_mpt_status
-{
-       int status;
-       int time_pan;
-       int time_tilt;
-};
-
-
-/* This is used for out-of-kernel decompression. With it, you can get
-   all the necessary information to initialize and use the decompressor
-   routines in standalone applications.
- */
-struct pwc_video_command
-{
-       int type;               /* camera type (645, 675, 730, etc.) */
-       int release;            /* release number */
-
-       int size;               /* one of PSZ_* */
-       int alternate;
-       int command_len;        /* length of USB video command */
-       unsigned char command_buf[13];  /* Actual USB video command */
-       int bandlength;         /* >0 = compressed */
-       int frame_size;         /* Size of one (un)compressed frame */
-};
-
-/* Flags for PWCX subroutines. Not all modules honour all flags. */
-#define PWCX_FLAG_PLANAR       0x0001
-#define PWCX_FLAG_BAYER                0x0008
-
-
-/* IOCTL definitions */
-
- /* Restore user settings */
-#define VIDIOCPWCRUSER         _IO('v', 192)
- /* Save user settings */
-#define VIDIOCPWCSUSER         _IO('v', 193)
- /* Restore factory settings */
-#define VIDIOCPWCFACTORY       _IO('v', 194)
-
- /* You can manipulate the compression factor. A compression preference of 0
-    means use uncompressed modes when available; 1 is low compression, 2 is
-    medium and 3 is high compression preferred. Of course, the higher the
-    compression, the lower the bandwidth used but more chance of artefacts
-    in the image. The driver automatically chooses a higher compression when
-    the preferred mode is not available.
-  */
- /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
-#define VIDIOCPWCSCQUAL                _IOW('v', 195, int)
- /* Get preferred compression quality */
-#define VIDIOCPWCGCQUAL                _IOR('v', 195, int)
-
-
-/* Retrieve serial number of camera */
-#define VIDIOCPWCGSERIAL       _IOR('v', 198, struct pwc_serial)
-
- /* This is a probe function; since so many devices are supported, it
-    becomes difficult to include all the names in programs that want to
-    check for the enhanced Philips stuff. So in stead, try this PROBE;
-    it returns a structure with the original name, and the corresponding
-    Philips type.
-    To use, fill the structure with zeroes, call PROBE and if that succeeds,
-    compare the name with that returned from VIDIOCGCAP; they should be the
-    same. If so, you can be assured it is a Philips (OEM) cam and the type
-    is valid.
- */
-#define VIDIOCPWCPROBE         _IOR('v', 199, struct pwc_probe)
-
- /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
-#define VIDIOCPWCSAGC          _IOW('v', 200, int)
- /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
-#define VIDIOCPWCGAGC          _IOR('v', 200, int)
- /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
-#define VIDIOCPWCSSHUTTER      _IOW('v', 201, int)
-
- /* Color compensation (Auto White Balance) */
-#define VIDIOCPWCSAWB           _IOW('v', 202, struct pwc_whitebalance)
-#define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
-
- /* Auto WB speed */
-#define VIDIOCPWCSAWBSPEED     _IOW('v', 203, struct pwc_wb_speed)
-#define VIDIOCPWCGAWBSPEED     _IOR('v', 203, struct pwc_wb_speed)
-
- /* LEDs on/off/blink; int range 0..65535 */
-#define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
-#define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
-
-  /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
-#define VIDIOCPWCSCONTOUR      _IOW('v', 206, int)
-#define VIDIOCPWCGCONTOUR      _IOR('v', 206, int)
-
-  /* Backlight compensation; 0 = off, otherwise on */
-#define VIDIOCPWCSBACKLIGHT    _IOW('v', 207, int)
-#define VIDIOCPWCGBACKLIGHT    _IOR('v', 207, int)
-
-  /* Flickerless mode; = 0 off, otherwise on */
-#define VIDIOCPWCSFLICKER      _IOW('v', 208, int)
-#define VIDIOCPWCGFLICKER      _IOR('v', 208, int)
-
-  /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
-#define VIDIOCPWCSDYNNOISE     _IOW('v', 209, int)
-#define VIDIOCPWCGDYNNOISE     _IOR('v', 209, int)
-
- /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
-#define VIDIOCPWCGREALSIZE     _IOR('v', 210, struct pwc_imagesize)
-
- /* Motorized pan & tilt functions */
-#define VIDIOCPWCMPTRESET      _IOW('v', 211, int)
-#define VIDIOCPWCMPTGRANGE     _IOR('v', 211, struct pwc_mpt_range)
-#define VIDIOCPWCMPTSANGLE     _IOW('v', 212, struct pwc_mpt_angles)
-#define VIDIOCPWCMPTGANGLE     _IOR('v', 212, struct pwc_mpt_angles)
-#define VIDIOCPWCMPTSTATUS     _IOR('v', 213, struct pwc_mpt_status)
-
- /* Get the USB set-video command; needed for initializing libpwcx */
-#define VIDIOCPWCGVIDCMD       _IOR('v', 215, struct pwc_video_command)
-struct pwc_table_init_buffer {
-   int len;
-   char *buffer;
-
-};
-#define VIDIOCPWCGVIDTABLE     _IOR('v', 216, struct pwc_table_init_buffer)
-
-/*
- * This is private command used when communicating with v4l2.
- * In the future all private ioctl will be remove/replace to
- * use interface offer by v4l2.
- */
-
-#define V4L2_CID_PRIVATE_SAVE_USER       (V4L2_CID_PRIVATE_BASE + 0)
-#define V4L2_CID_PRIVATE_RESTORE_USER    (V4L2_CID_PRIVATE_BASE + 1)
-#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2)
-#define V4L2_CID_PRIVATE_COLOUR_MODE     (V4L2_CID_PRIVATE_BASE + 3)
-#define V4L2_CID_PRIVATE_AUTOCONTOUR     (V4L2_CID_PRIVATE_BASE + 4)
-#define V4L2_CID_PRIVATE_CONTOUR         (V4L2_CID_PRIVATE_BASE + 5)
-#define V4L2_CID_PRIVATE_BACKLIGHT       (V4L2_CID_PRIVATE_BASE + 6)
-#define V4L2_CID_PRIVATE_FLICKERLESS     (V4L2_CID_PRIVATE_BASE + 7)
-#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8)
-
-struct pwc_raw_frame {
-   __le16 type;                /* type of the webcam */
-   __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */
-   __u8   cmd[4];      /* the four byte of the command (in case of nala,
-                          only the first 3 bytes is filled) */
-   __u8   rawframe[0]; /* frame_size = H/4*vbandlength */
-} __attribute__ ((packed));
-
-
-#endif
index 26a3bd0fe57ca7a393afe27c1004970f5354a701..f688bde61228ce8ec4d6f2753c2408a972dedb99 100644 (file)
 #define RC_TYPE_JVC    (1  << 3)       /* JVC protocol */
 #define RC_TYPE_SONY   (1  << 4)       /* Sony12/15/20 protocol */
 #define RC_TYPE_RC5_SZ (1  << 5)       /* RC5 variant used by Streamzap */
+#define RC_TYPE_SANYO   (1  << 6)      /* Sanyo protocol */
 #define RC_TYPE_MCE_KBD        (1  << 29)      /* RC6-ish MCE keyboard/mouse */
 #define RC_TYPE_LIRC   (1  << 30)      /* Pass raw IR to lirc userspace */
 #define RC_TYPE_OTHER  (1u << 31)
 
-#define RC_TYPE_ALL (RC_TYPE_RC5 | RC_TYPE_NEC  | RC_TYPE_RC6  | \
-                    RC_TYPE_JVC | RC_TYPE_SONY | RC_TYPE_LIRC | \
-                    RC_TYPE_RC5_SZ | RC_TYPE_MCE_KBD | RC_TYPE_OTHER)
+#define RC_TYPE_ALL (RC_TYPE_RC5    | RC_TYPE_NEC   | RC_TYPE_RC6     | \
+                    RC_TYPE_JVC    | RC_TYPE_SONY  | RC_TYPE_LIRC    | \
+                    RC_TYPE_RC5_SZ | RC_TYPE_SANYO | RC_TYPE_MCE_KBD | \
+                    RC_TYPE_OTHER)
 
 struct rc_map_table {
        u32     scancode;
@@ -145,7 +147,7 @@ void rc_map_init(void);
 #define RC_MAP_TREKSTOR                  "rc-trekstor"
 #define RC_MAP_TT_1500                   "rc-tt-1500"
 #define RC_MAP_TWINHAN_VP1027_DVBS       "rc-twinhan1027"
-#define RC_MAP_VIDEOMATE_M1F             "rc-videomate-m1f"
+#define RC_MAP_VIDEOMATE_K100            "rc-videomate-k100"
 #define RC_MAP_VIDEOMATE_S350            "rc-videomate-s350"
 #define RC_MAP_VIDEOMATE_TV_PVR          "rc-videomate-tv-pvr"
 #define RC_MAP_WINFAST                   "rc-winfast"
index 5fb2c3d10c05047a4c50fb2e4440e7862a6a9908..b5c2b6cb0d81078f23fb3a6c1c779e90e31b88ce 100644 (file)
@@ -94,7 +94,7 @@ struct soc_camera_host_ops {
                              struct soc_camera_device *);
        int (*reqbufs)(struct soc_camera_device *, struct v4l2_requestbuffers *);
        int (*querycap)(struct soc_camera_host *, struct v4l2_capability *);
-       int (*set_bus_param)(struct soc_camera_device *, __u32);
+       int (*set_bus_param)(struct soc_camera_device *);
        int (*get_parm)(struct soc_camera_device *, struct v4l2_streamparm *);
        int (*set_parm)(struct soc_camera_device *, struct v4l2_streamparm *);
        int (*enum_fsizes)(struct soc_camera_device *, struct v4l2_frmsizeenum *);
index 89c290b69a5c6bf345f7d6e27d3b1921301b87fc..29e1920e7339867124e3605e1afd1a2777d66e8a 100644 (file)
 #define TUNER_PHILIPS_FMD1216MEX_MK3   78
 #define TUNER_PHILIPS_FM1216MK5                79
 #define TUNER_PHILIPS_FQ1216LME_MK3    80      /* Active loopthrough, no FM */
-#define TUNER_XC4000                   81      /* Xceive Silicon Tuner */
 
 #define TUNER_PARTSNIC_PTI_5NF05       81
 #define TUNER_PHILIPS_CU1216L           82
 #define TUNER_PHILIPS_FQ1236_MK5       85      /* NTSC, TDA9885, no FM radio */
 #define TUNER_TENA_TNF_5337            86
 
+#define TUNER_XC4000                   87      /* Xceive Silicon Tuner */
+
 /* tv card specific */
 #define TDA9887_PRESENT                (1<<0)
 #define TDA9887_PORT1_INACTIVE                 (1<<1)
index 4d1c74ad4c84626b8fb6e96a9249dbb2b1c2cb33..3f5d60fc5df689845cfb731d61bee2b3f0e48673 100644 (file)
@@ -196,6 +196,10 @@ struct v4l2_ioctl_ops {
                                        struct v4l2_crop *a);
        int (*vidioc_s_crop)           (struct file *file, void *fh,
                                        struct v4l2_crop *a);
+       int (*vidioc_g_selection)      (struct file *file, void *fh,
+                                       struct v4l2_selection *s);
+       int (*vidioc_s_selection)      (struct file *file, void *fh,
+                                       struct v4l2_selection *s);
        /* Compression ioctls */
        int (*vidioc_g_jpegcomp)       (struct file *file, void *fh,
                                        struct v4l2_jpegcompression *a);
index 5e2e984584968f0e6beea90c8657eb1639a1cba2..ea9231f4935feba9ebd791e4d12287cc24284fd6 100644 (file)
@@ -127,7 +127,7 @@ struct hci_dev {
        __u8            major_class;
        __u8            minor_class;
        __u8            features[8];
-       __u8            extfeatures[8];
+       __u8            host_features[8];
        __u8            commands[64];
        __u8            ssp_mode;
        __u8            hci_ver;
@@ -676,7 +676,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define lmp_le_capable(dev)        ((dev)->features[4] & LMP_LE)
 
 /* ----- Extended LMP capabilities ----- */
-#define lmp_host_le_capable(dev)   ((dev)->extfeatures[0] & LMP_HOST_LE)
+#define lmp_host_le_capable(dev)   ((dev)->host_features[0] & LMP_HOST_LE)
 
 /* ----- HCI protocols ----- */
 static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
index da1f064a81b3744688545acef85fcaf507fe6c82..9b582437fbeab11535ef3d024ba11c381ea777b1 100644 (file)
@@ -78,7 +78,7 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
                                      __u32 mark, __u8 tos, __u8 scope,
                                      __u8 proto, __u8 flags,
                                      __be32 daddr, __be32 saddr,
-                                     __be16 dport, __be32 sport)
+                                     __be16 dport, __be16 sport)
 {
        fl4->flowi4_oif = oif;
        fl4->flowi4_iif = 0;
index baab385a47363e85765ebf4b1b829684ef6024db..28068ec614b24da11b9cb3e9a390abb7aea5f47a 100644 (file)
@@ -199,7 +199,8 @@ static inline void red_set_parms(struct red_parms *p,
        p->Scell_log    = Scell_log;
        p->Scell_max    = (255 << Scell_log);
 
-       memcpy(p->Stab, stab, sizeof(p->Stab));
+       if (stab)
+               memcpy(p->Stab, stab, sizeof(p->Stab));
 }
 
 static inline int red_is_idling(const struct red_vars *v)
index 5d1a758e05950a7669157914a15b6025da11a7cc..6a3922fe0be0b840c3d8a416cb6919aa28f78b7a 100644 (file)
@@ -857,7 +857,7 @@ struct fc_lport {
        enum fc_lport_state            state;
        unsigned long                  boot_time;
        struct fc_host_statistics      host_stats;
-       struct fcoe_dev_stats          *dev_stats;
+       struct fcoe_dev_stats __percpu *dev_stats;
        u8                             retry_count;
 
        /* Fabric information */
diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h
new file mode 100644 (file)
index 0000000..4866499
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef TARGET_CORE_BACKEND_H
+#define TARGET_CORE_BACKEND_H
+
+#define TRANSPORT_PLUGIN_PHBA_PDEV             1
+#define TRANSPORT_PLUGIN_VHBA_PDEV             2
+#define TRANSPORT_PLUGIN_VHBA_VDEV             3
+
+struct se_subsystem_api {
+       struct list_head sub_api_list;
+
+       char name[16];
+       struct module *owner;
+
+       u8 transport_type;
+
+       unsigned int fua_write_emulated : 1;
+       unsigned int write_cache_emulated : 1;
+
+       int (*attach_hba)(struct se_hba *, u32);
+       void (*detach_hba)(struct se_hba *);
+       int (*pmode_enable_hba)(struct se_hba *, unsigned long);
+       void *(*allocate_virtdevice)(struct se_hba *, const char *);
+       struct se_device *(*create_virtdevice)(struct se_hba *,
+                               struct se_subsystem_dev *, void *);
+       void (*free_device)(void *);
+       int (*transport_complete)(struct se_task *task);
+       struct se_task *(*alloc_task)(unsigned char *cdb);
+       int (*do_task)(struct se_task *);
+       int (*do_discard)(struct se_device *, sector_t, u32);
+       void (*do_sync_cache)(struct se_task *);
+       void (*free_task)(struct se_task *);
+       ssize_t (*check_configfs_dev_params)(struct se_hba *,
+                       struct se_subsystem_dev *);
+       ssize_t (*set_configfs_dev_params)(struct se_hba *,
+                       struct se_subsystem_dev *, const char *, ssize_t);
+       ssize_t (*show_configfs_dev_params)(struct se_hba *,
+                       struct se_subsystem_dev *, char *);
+       u32 (*get_device_rev)(struct se_device *);
+       u32 (*get_device_type)(struct se_device *);
+       sector_t (*get_blocks)(struct se_device *);
+       unsigned char *(*get_sense_buffer)(struct se_task *);
+};
+
+int    transport_subsystem_register(struct se_subsystem_api *);
+void   transport_subsystem_release(struct se_subsystem_api *);
+
+struct se_device *transport_add_device_to_core_hba(struct se_hba *,
+               struct se_subsystem_api *, struct se_subsystem_dev *, u32,
+               void *, struct se_dev_limits *, const char *, const char *);
+
+void   transport_complete_sync_cache(struct se_cmd *, int);
+void   transport_complete_task(struct se_task *, int);
+
+void   target_get_task_cdb(struct se_task *, unsigned char *);
+
+void   transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *);
+int    transport_set_vpd_assoc(struct t10_vpd *, unsigned char *);
+int    transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *);
+int    transport_set_vpd_ident(struct t10_vpd *, unsigned char *);
+
+/* core helpers also used by command snooping in pscsi */
+void   *transport_kmap_first_data_page(struct se_cmd *);
+void   transport_kunmap_first_data_page(struct se_cmd *);
+
+#endif /* TARGET_CORE_BACKEND_H */
index 6873c7dd9145d2a23f682d9e8d2c695a7571d656..daf532bc721a84b987cdf153d715c71864c2461a 100644 (file)
@@ -10,6 +10,7 @@
 #include <net/tcp.h>
 
 #define TARGET_CORE_MOD_VERSION                "v4.1.0-rc1-ml"
+#define TARGET_CORE_VERSION            TARGET_CORE_MOD_VERSION
 
 /* Maximum Number of LUNs per Target Portal Group */
 /* Don't raise above 511 or REPORT_LUNS needs to handle >1 page */
@@ -34,6 +35,7 @@
 #define TRANSPORT_SENSE_BUFFER                 SCSI_SENSE_BUFFERSIZE
 /* Used by transport_send_check_condition_and_sense() */
 #define SPC_SENSE_KEY_OFFSET                   2
+#define SPC_ADD_SENSE_LEN_OFFSET               7
 #define SPC_ASC_KEY_OFFSET                     12
 #define SPC_ASCQ_KEY_OFFSET                    13
 #define TRANSPORT_IQN_LEN                      224
 /* Used by transport_get_inquiry_vpd_device_ident() */
 #define INQUIRY_VPD_DEVICE_IDENTIFIER_LEN      254
 
+/* Attempts before moving from SHORT to LONG */
+#define PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD  3
+#define PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT 3  /* In milliseconds */
+#define PYX_TRANSPORT_WINDOW_CLOSED_WAIT_LONG  10 /* In milliseconds */
+
+#define PYX_TRANSPORT_STATUS_INTERVAL          5 /* In seconds */
+
+/*
+ * struct se_subsystem_dev->su_dev_flags
+*/
+#define SDF_FIRMWARE_VPD_UNIT_SERIAL           0x00000001
+#define SDF_EMULATED_VPD_UNIT_SERIAL           0x00000002
+#define SDF_USING_UDEV_PATH                    0x00000004
+#define SDF_USING_ALIAS                                0x00000008
+
+/*
+ * struct se_device->dev_flags
+ */
+#define DF_READ_ONLY                           0x00000001
+#define DF_SPC2_RESERVATIONS                   0x00000002
+#define DF_SPC2_RESERVATIONS_WITH_ISID         0x00000004
+
+/* struct se_dev_attrib sanity values */
+/* Default max_unmap_lba_count */
+#define DA_MAX_UNMAP_LBA_COUNT                 0
+/* Default max_unmap_block_desc_count */
+#define DA_MAX_UNMAP_BLOCK_DESC_COUNT          0
+/* Default unmap_granularity */
+#define DA_UNMAP_GRANULARITY_DEFAULT           0
+/* Default unmap_granularity_alignment */
+#define DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT 0
+/* Emulation for Direct Page Out */
+#define DA_EMULATE_DPO                         0
+/* Emulation for Forced Unit Access WRITEs */
+#define DA_EMULATE_FUA_WRITE                   1
+/* Emulation for Forced Unit Access READs */
+#define DA_EMULATE_FUA_READ                    0
+/* Emulation for WriteCache and SYNCHRONIZE_CACHE */
+#define DA_EMULATE_WRITE_CACHE                 0
+/* Emulation for UNIT ATTENTION Interlock Control */
+#define DA_EMULATE_UA_INTLLCK_CTRL             0
+/* Emulation for TASK_ABORTED status (TAS) by default */
+#define DA_EMULATE_TAS                         1
+/* Emulation for Thin Provisioning UNMAP using block/blk-lib.c:blkdev_issue_discard() */
+#define DA_EMULATE_TPU                         0
+/*
+ * Emulation for Thin Provisioning WRITE_SAME w/ UNMAP=1 bit using
+ * block/blk-lib.c:blkdev_issue_discard()
+ */
+#define DA_EMULATE_TPWS                                0
+/* No Emulation for PSCSI by default */
+#define DA_EMULATE_RESERVATIONS                        0
+/* No Emulation for PSCSI by default */
+#define DA_EMULATE_ALUA                                0
+/* Enforce SCSI Initiator Port TransportID with 'ISID' for PR */
+#define DA_ENFORCE_PR_ISIDS                    1
+#define DA_STATUS_MAX_SECTORS_MIN              16
+#define DA_STATUS_MAX_SECTORS_MAX              8192
+/* By default don't report non-rotating (solid state) medium */
+#define DA_IS_NONROT                           0
+/* Queue Algorithm Modifier default for restricted reordering in control mode page */
+#define DA_EMULATE_REST_REORD                  0
+
+#define SE_MODE_PAGE_BUF                       512
+
+
 /* struct se_hba->hba_flags */
 enum hba_flags_table {
        HBA_FLAGS_INTERNAL_USE  = 0x01,
@@ -71,11 +139,12 @@ enum transport_tpg_type_table {
        TRANSPORT_TPG_TYPE_DISCOVERY = 1,
 };
 
-/* Used for generate timer flags */
+/* struct se_task->task_flags */
 enum se_task_flags {
        TF_ACTIVE               = (1 << 0),
        TF_SENT                 = (1 << 1),
        TF_REQUEST_STOP         = (1 << 2),
+       TF_HAS_SENSE            = (1 << 3),
 };
 
 /* Special transport agnostic struct se_cmd->t_states */
@@ -158,9 +227,38 @@ enum tcm_sense_reason_table {
        TCM_RESERVATION_CONFLICT                = 0x10,
 };
 
+enum target_sc_flags_table {
+       TARGET_SCF_BIDI_OP              = 0x01,
+       TARGET_SCF_ACK_KREF             = 0x02,
+};
+
+/* fabric independent task management function values */
+enum tcm_tmreq_table {
+       TMR_ABORT_TASK          = 1,
+       TMR_ABORT_TASK_SET      = 2,
+       TMR_CLEAR_ACA           = 3,
+       TMR_CLEAR_TASK_SET      = 4,
+       TMR_LUN_RESET           = 5,
+       TMR_TARGET_WARM_RESET   = 6,
+       TMR_TARGET_COLD_RESET   = 7,
+       TMR_FABRIC_TMR          = 255,
+};
+
+/* fabric independent task management response values */
+enum tcm_tmrsp_table {
+       TMR_FUNCTION_COMPLETE           = 0,
+       TMR_TASK_DOES_NOT_EXIST         = 1,
+       TMR_LUN_DOES_NOT_EXIST          = 2,
+       TMR_TASK_STILL_ALLEGIANT        = 3,
+       TMR_TASK_FAILOVER_NOT_SUPPORTED = 4,
+       TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED    = 5,
+       TMR_FUNCTION_AUTHORIZATION_FAILED = 6,
+       TMR_FUNCTION_REJECTED           = 255,
+};
+
 struct se_obj {
        atomic_t obj_access_count;
-} ____cacheline_aligned;
+};
 
 /*
  * Used by TCM Core internally to signal if ALUA emulation is enabled or
@@ -207,7 +305,7 @@ struct t10_alua {
        struct config_group alua_tg_pt_gps_group;
        int (*alua_state_check)(struct se_cmd *, unsigned char *, u8 *);
        struct list_head tg_pt_gps_list;
-} ____cacheline_aligned;
+};
 
 struct t10_alua_lu_gp {
        u16     lu_gp_id;
@@ -218,7 +316,7 @@ struct t10_alua_lu_gp {
        struct config_group lu_gp_group;
        struct list_head lu_gp_node;
        struct list_head lu_gp_mem_list;
-} ____cacheline_aligned;
+};
 
 struct t10_alua_lu_gp_member {
        bool lu_gp_assoc;
@@ -227,7 +325,7 @@ struct t10_alua_lu_gp_member {
        struct t10_alua_lu_gp *lu_gp;
        struct se_device *lu_gp_mem_dev;
        struct list_head lu_gp_mem_list;
-} ____cacheline_aligned;
+};
 
 struct t10_alua_tg_pt_gp {
        u16     tg_pt_gp_id;
@@ -250,7 +348,7 @@ struct t10_alua_tg_pt_gp {
        struct config_group tg_pt_gp_group;
        struct list_head tg_pt_gp_list;
        struct list_head tg_pt_gp_mem_list;
-} ____cacheline_aligned;
+};
 
 struct t10_alua_tg_pt_gp_member {
        bool tg_pt_gp_assoc;
@@ -259,7 +357,7 @@ struct t10_alua_tg_pt_gp_member {
        struct t10_alua_tg_pt_gp *tg_pt_gp;
        struct se_port *tg_pt;
        struct list_head tg_pt_gp_mem_list;
-} ____cacheline_aligned;
+};
 
 struct t10_vpd {
        unsigned char device_identifier[INQUIRY_VPD_DEVICE_IDENTIFIER_LEN];
@@ -269,7 +367,7 @@ struct t10_vpd {
        u32 association;
        u32 device_identifier_type;
        struct list_head vpd_list;
-} ____cacheline_aligned;
+};
 
 struct t10_wwn {
        char vendor[8];
@@ -280,7 +378,7 @@ struct t10_wwn {
        struct se_subsystem_dev *t10_sub_dev;
        struct config_group t10_wwn_group;
        struct list_head t10_vpd_list;
-} ____cacheline_aligned;
+};
 
 
 /*
@@ -333,7 +431,7 @@ struct t10_pr_registration {
        struct list_head pr_reg_aptpl_list;
        struct list_head pr_reg_atp_list;
        struct list_head pr_reg_atp_mem_list;
-} ____cacheline_aligned;
+};
 
 /*
  * This set of function pointer ops is set based upon SPC3_PERSISTENT_RESERVATIONS,
@@ -374,20 +472,20 @@ struct t10_reservation {
        struct list_head registration_list;
        struct list_head aptpl_reg_list;
        struct t10_reservation_ops pr_ops;
-} ____cacheline_aligned;
+};
 
 struct se_queue_req {
        int                     state;
        struct se_cmd           *cmd;
        struct list_head        qr_list;
-} ____cacheline_aligned;
+};
 
 struct se_queue_obj {
        atomic_t                queue_cnt;
        spinlock_t              cmd_queue_lock;
        struct list_head        qobj_list;
        wait_queue_head_t       thread_wq;
-} ____cacheline_aligned;
+};
 
 struct se_task {
        unsigned long long      task_lba;
@@ -397,16 +495,14 @@ struct se_task {
        struct scatterlist      *task_sg;
        u32                     task_sg_nents;
        u16                     task_flags;
-       u8                      task_sense;
        u8                      task_scsi_status;
-       int                     task_error_status;
        enum dma_data_direction task_data_direction;
-       atomic_t                task_state_active;
        struct list_head        t_list;
        struct list_head        t_execute_list;
        struct list_head        t_state_list;
+       bool                    t_state_active;
        struct completion       task_stop_comp;
-} ____cacheline_aligned;
+};
 
 struct se_cmd {
        /* SAM response code being sent to initiator */
@@ -451,6 +547,7 @@ struct se_cmd {
        struct list_head        se_queue_node;
        struct list_head        se_cmd_list;
        struct completion       cmd_wait_comp;
+       struct kref             cmd_kref;
        struct target_core_fabric_ops *se_tfo;
        int (*execute_task)(struct se_task *);
        void (*transport_complete_callback)(struct se_cmd *);
@@ -492,7 +589,7 @@ struct se_cmd {
        struct list_head        t_task_list;
        u32                     t_task_list_num;
 
-} ____cacheline_aligned;
+};
 
 struct se_tmr_req {
        /* Task Management function to be preformed */
@@ -510,7 +607,7 @@ struct se_tmr_req {
        struct se_device        *tmr_dev;
        struct se_lun           *tmr_lun;
        struct list_head        tmr_list;
-} ____cacheline_aligned;
+};
 
 struct se_ua {
        u8                      ua_asc;
@@ -518,7 +615,7 @@ struct se_ua {
        struct se_node_acl      *ua_nacl;
        struct list_head        ua_dev_list;
        struct list_head        ua_nacl_list;
-} ____cacheline_aligned;
+};
 
 struct se_node_acl {
        char                    initiatorname[TRANSPORT_IQN_LEN];
@@ -545,7 +642,7 @@ struct se_node_acl {
        struct config_group     *acl_default_groups[5];
        struct list_head        acl_list;
        struct list_head        acl_sess_list;
-} ____cacheline_aligned;
+};
 
 struct se_session {
        unsigned                sess_tearing_down:1;
@@ -558,7 +655,7 @@ struct se_session {
        struct list_head        sess_cmd_list;
        struct list_head        sess_wait_list;
        spinlock_t              sess_cmd_lock;
-} ____cacheline_aligned;
+};
 
 struct se_device;
 struct se_transform_info;
@@ -578,7 +675,7 @@ struct se_lun_acl {
        struct list_head        lacl_list;
        struct config_group     se_lun_group;
        struct se_ml_stat_grps  ml_stat_grps;
-}  ____cacheline_aligned;
+};
 
 struct se_dev_entry {
        bool                    def_pr_registered;
@@ -603,7 +700,7 @@ struct se_dev_entry {
        struct se_lun           *se_lun;
        struct list_head        alua_port_list;
        struct list_head        ua_list;
-}  ____cacheline_aligned;
+};
 
 struct se_dev_limits {
        /* Max supported HW queue depth */
@@ -612,7 +709,7 @@ struct se_dev_limits {
        u32             queue_depth;
        /* From include/linux/blkdev.h for the other HW/SW limits. */
        struct queue_limits limits;
-} ____cacheline_aligned;
+};
 
 struct se_dev_attrib {
        int             emulate_dpo;
@@ -641,7 +738,7 @@ struct se_dev_attrib {
        u32             unmap_granularity_alignment;
        struct se_subsystem_dev *da_sub_dev;
        struct config_group da_group;
-} ____cacheline_aligned;
+};
 
 struct se_dev_stat_grps {
        struct config_group stat_group;
@@ -674,7 +771,7 @@ struct se_subsystem_dev {
        struct config_group se_dev_pr_group;
        /* For target_core_stat.c groups */
        struct se_dev_stat_grps dev_stat_grps;
-} ____cacheline_aligned;
+};
 
 struct se_device {
        /* RELATIVE TARGET PORT IDENTIFER Counter */
@@ -685,7 +782,6 @@ struct se_device {
        u32                     dev_port_count;
        /* See transport_device_status_table */
        u32                     dev_status;
-       u32                     dev_tcq_window_closed;
        /* Physical device queue depth */
        u32                     queue_depth;
        /* Used for SPC-2 reservations enforce of ISIDs */
@@ -702,7 +798,6 @@ struct se_device {
        spinlock_t              stats_lock;
        /* Active commands on this virtual SE device */
        atomic_t                simple_cmds;
-       atomic_t                depth_left;
        atomic_t                dev_ordered_id;
        atomic_t                execute_tasks;
        atomic_t                dev_ordered_sync;
@@ -740,7 +835,7 @@ struct se_device {
        struct se_subsystem_api *transport;
        /* Linked list for struct se_hba struct se_device list */
        struct list_head        dev_list;
-}  ____cacheline_aligned;
+};
 
 struct se_hba {
        u16                     hba_tpgt;
@@ -759,7 +854,7 @@ struct se_hba {
        struct config_group     hba_group;
        struct mutex            hba_access_mutex;
        struct se_subsystem_api *transport;
-}  ____cacheline_aligned;
+};
 
 struct se_port_stat_grps {
        struct config_group stat_group;
@@ -785,13 +880,13 @@ struct se_lun {
        struct se_port          *lun_sep;
        struct config_group     lun_group;
        struct se_port_stat_grps port_stat_grps;
-} ____cacheline_aligned;
+};
 
 struct scsi_port_stats {
        u64     cmd_pdus;
        u64     tx_data_octets;
        u64     rx_data_octets;
-} ____cacheline_aligned;
+};
 
 struct se_port {
        /* RELATIVE TARGET PORT IDENTIFER */
@@ -811,12 +906,12 @@ struct se_port {
        struct se_portal_group *sep_tpg;
        struct list_head sep_alua_list;
        struct list_head sep_list;
-} ____cacheline_aligned;
+};
 
 struct se_tpg_np {
        struct se_portal_group *tpg_np_parent;
        struct config_group     tpg_np_group;
-} ____cacheline_aligned;
+};
 
 struct se_portal_group {
        /* Type of target portal group, see transport_tpg_type_table */
@@ -849,13 +944,13 @@ struct se_portal_group {
        struct config_group     tpg_acl_group;
        struct config_group     tpg_attrib_group;
        struct config_group     tpg_param_group;
-} ____cacheline_aligned;
+};
 
 struct se_wwn {
        struct target_fabric_configfs *wwn_tf;
        struct config_group     wwn_group;
        struct config_group     *wwn_default_groups[2];
        struct config_group     fabric_stat_group;
-} ____cacheline_aligned;
+};
 
 #endif /* TARGET_CORE_BASE_H */
diff --git a/include/target/target_core_device.h b/include/target/target_core_device.h
deleted file mode 100644 (file)
index 2be31ff..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef TARGET_CORE_DEVICE_H
-#define TARGET_CORE_DEVICE_H
-
-extern int transport_lookup_cmd_lun(struct se_cmd *, u32);
-extern int transport_lookup_tmr_lun(struct se_cmd *, u32);
-extern struct se_dev_entry *core_get_se_deve_from_rtpi(
-                                       struct se_node_acl *, u16);
-extern int core_free_device_list_for_node(struct se_node_acl *,
-                                       struct se_portal_group *);
-extern void core_dec_lacl_count(struct se_node_acl *, struct se_cmd *);
-extern void core_update_device_list_access(u32, u32, struct se_node_acl *);
-extern int core_update_device_list_for_node(struct se_lun *, struct se_lun_acl *, u32,
-                                       u32, struct se_node_acl *,
-                                       struct se_portal_group *, int);
-extern void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *);
-extern int core_dev_export(struct se_device *, struct se_portal_group *,
-                                       struct se_lun *);
-extern void core_dev_unexport(struct se_device *, struct se_portal_group *,
-                                       struct se_lun *);
-extern int target_report_luns(struct se_task *);
-extern void se_release_device_for_hba(struct se_device *);
-extern void se_release_vpd_for_dev(struct se_device *);
-extern void se_clear_dev_ports(struct se_device *);
-extern int se_free_virtual_device(struct se_device *, struct se_hba *);
-extern int se_dev_check_online(struct se_device *);
-extern int se_dev_check_shutdown(struct se_device *);
-extern void se_dev_set_default_attribs(struct se_device *, struct se_dev_limits *);
-extern int se_dev_set_task_timeout(struct se_device *, u32);
-extern int se_dev_set_max_unmap_lba_count(struct se_device *, u32);
-extern int se_dev_set_max_unmap_block_desc_count(struct se_device *, u32);
-extern int se_dev_set_unmap_granularity(struct se_device *, u32);
-extern int se_dev_set_unmap_granularity_alignment(struct se_device *, u32);
-extern int se_dev_set_emulate_dpo(struct se_device *, int);
-extern int se_dev_set_emulate_fua_write(struct se_device *, int);
-extern int se_dev_set_emulate_fua_read(struct se_device *, int);
-extern int se_dev_set_emulate_write_cache(struct se_device *, int);
-extern int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *, int);
-extern int se_dev_set_emulate_tas(struct se_device *, int);
-extern int se_dev_set_emulate_tpu(struct se_device *, int);
-extern int se_dev_set_emulate_tpws(struct se_device *, int);
-extern int se_dev_set_enforce_pr_isids(struct se_device *, int);
-extern int se_dev_set_is_nonrot(struct se_device *, int);
-extern int se_dev_set_emulate_rest_reord(struct se_device *dev, int);
-extern int se_dev_set_queue_depth(struct se_device *, u32);
-extern int se_dev_set_max_sectors(struct se_device *, u32);
-extern int se_dev_set_optimal_sectors(struct se_device *, u32);
-extern int se_dev_set_block_size(struct se_device *, u32);
-extern struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_hba *,
-                                       struct se_device *, u32);
-extern int core_dev_del_lun(struct se_portal_group *, u32);
-extern struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32);
-extern struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *,
-                                                       u32, char *, int *);
-extern int core_dev_add_initiator_node_lun_acl(struct se_portal_group *,
-                                               struct se_lun_acl *, u32, u32);
-extern int core_dev_del_initiator_node_lun_acl(struct se_portal_group *,
-                                               struct se_lun *, struct se_lun_acl *);
-extern void core_dev_free_initiator_node_lun_acl(struct se_portal_group *,
-                                               struct se_lun_acl *lacl);
-extern int core_dev_setup_virtual_lun0(void);
-extern void core_dev_release_virtual_lun0(void);
-
-#endif /* TARGET_CORE_DEVICE_H */
similarity index 50%
rename from include/target/target_core_fabric_ops.h
rename to include/target/target_core_fabric.h
index 0256825f923dbd8d5e1824cb45c4af5d1ae3e197..523e8bc104d40e2bbe40c0adbe7210156f796214 100644 (file)
@@ -1,5 +1,5 @@
-/* Defined in target_core_configfs.h */
-struct target_fabric_configfs;
+#ifndef TARGET_CORE_FABRIC_H
+#define TARGET_CORE_FABRIC_H
 
 struct target_core_fabric_ops {
        struct configfs_subsystem *tf_subsys;
@@ -52,10 +52,6 @@ struct target_core_fabric_ops {
         * Returning 0 will signal a descriptor has not been released.
         */
        int (*check_stop_free)(struct se_cmd *);
-       /*
-        * Optional check for active I/O shutdown
-        */
-       int (*check_release_cmd)(struct se_cmd *);
        void (*release_cmd)(struct se_cmd *);
        /*
         * Called with spin_lock_bh(struct se_portal_group->session_lock held.
@@ -103,3 +99,89 @@ struct target_core_fabric_ops {
                                struct config_group *, const char *);
        void (*fabric_drop_nodeacl)(struct se_node_acl *);
 };
+
+struct se_session *transport_init_session(void);
+void   __transport_register_session(struct se_portal_group *,
+               struct se_node_acl *, struct se_session *, void *);
+void   transport_register_session(struct se_portal_group *,
+               struct se_node_acl *, struct se_session *, void *);
+void   transport_free_session(struct se_session *);
+void   transport_deregister_session_configfs(struct se_session *);
+void   transport_deregister_session(struct se_session *);
+
+
+void   transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *,
+               struct se_session *, u32, int, int, unsigned char *);
+int    transport_lookup_cmd_lun(struct se_cmd *, u32);
+int    transport_generic_allocate_tasks(struct se_cmd *, unsigned char *);
+int    target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *,
+               unsigned char *, u32, u32, int, int, int);
+int    transport_handle_cdb_direct(struct se_cmd *);
+int    transport_generic_handle_cdb_map(struct se_cmd *);
+int    transport_generic_handle_data(struct se_cmd *);
+int    transport_generic_map_mem_to_cmd(struct se_cmd *cmd,
+               struct scatterlist *, u32, struct scatterlist *, u32);
+void   transport_do_task_sg_chain(struct se_cmd *);
+int    transport_generic_new_cmd(struct se_cmd *);
+
+void   transport_generic_process_write(struct se_cmd *);
+
+void   transport_generic_free_cmd(struct se_cmd *, int);
+
+bool   transport_wait_for_tasks(struct se_cmd *);
+int    transport_check_aborted_status(struct se_cmd *, int);
+int    transport_send_check_condition_and_sense(struct se_cmd *, u8, int);
+
+void   target_get_sess_cmd(struct se_session *, struct se_cmd *, bool);
+int    target_put_sess_cmd(struct se_session *, struct se_cmd *);
+void   target_splice_sess_cmd_list(struct se_session *);
+void   target_wait_for_sess_cmds(struct se_session *, int);
+
+int    core_alua_check_nonop_delay(struct se_cmd *);
+
+struct se_tmr_req *core_tmr_alloc_req(struct se_cmd *, void *, u8, gfp_t);
+void   core_tmr_release_req(struct se_tmr_req *);
+int    transport_generic_handle_tmr(struct se_cmd *);
+int    transport_lookup_tmr_lun(struct se_cmd *, u32);
+
+struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *,
+               unsigned char *);
+void   core_tpg_clear_object_luns(struct se_portal_group *);
+struct se_node_acl *core_tpg_add_initiator_node_acl(struct se_portal_group *,
+               struct se_node_acl *, const char *, u32);
+int    core_tpg_del_initiator_node_acl(struct se_portal_group *,
+               struct se_node_acl *, int);
+int    core_tpg_set_initiator_node_queue_depth(struct se_portal_group *,
+               unsigned char *, u32, int);
+int    core_tpg_register(struct target_core_fabric_ops *, struct se_wwn *,
+               struct se_portal_group *, void *, int);
+int    core_tpg_deregister(struct se_portal_group *);
+
+/* SAS helpers */
+u8     sas_get_fabric_proto_ident(struct se_portal_group *);
+u32    sas_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *,
+               struct t10_pr_registration *, int *, unsigned char *);
+u32    sas_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *,
+               struct t10_pr_registration *, int *);
+char   *sas_parse_pr_out_transport_id(struct se_portal_group *, const char *,
+               u32 *, char **);
+
+/* FC helpers */
+u8     fc_get_fabric_proto_ident(struct se_portal_group *);
+u32    fc_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *,
+               struct t10_pr_registration *, int *, unsigned char *);
+u32    fc_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *,
+               struct t10_pr_registration *, int *);
+char   *fc_parse_pr_out_transport_id(struct se_portal_group *, const char *,
+               u32 *, char **);
+
+/* iSCSI helpers */
+u8     iscsi_get_fabric_proto_ident(struct se_portal_group *);
+u32    iscsi_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *,
+               struct t10_pr_registration *, int *, unsigned char *);
+u32    iscsi_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *,
+               struct t10_pr_registration *, int *);
+char   *iscsi_parse_pr_out_transport_id(struct se_portal_group *, const char *,
+               u32 *, char **);
+
+#endif /* TARGET_CORE_FABRICH */
diff --git a/include/target/target_core_fabric_lib.h b/include/target/target_core_fabric_lib.h
deleted file mode 100644 (file)
index c2f8d0e..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef TARGET_CORE_FABRIC_LIB_H
-#define TARGET_CORE_FABRIC_LIB_H
-
-extern u8 sas_get_fabric_proto_ident(struct se_portal_group *);
-extern u32 sas_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *,
-                       struct t10_pr_registration *, int *, unsigned char *);
-extern u32 sas_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *,
-                       struct t10_pr_registration *, int *);
-extern char *sas_parse_pr_out_transport_id(struct se_portal_group *,
-                       const char *, u32 *, char **);
-
-extern u8 fc_get_fabric_proto_ident(struct se_portal_group *);
-extern u32 fc_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *,
-                       struct t10_pr_registration *, int *, unsigned char *);
-extern u32 fc_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *,
-                       struct t10_pr_registration *, int *);
-extern char *fc_parse_pr_out_transport_id(struct se_portal_group *,
-                       const char *, u32 *, char **);
-
-extern u8 iscsi_get_fabric_proto_ident(struct se_portal_group *);
-extern u32 iscsi_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *,
-                       struct t10_pr_registration *, int *, unsigned char *);
-extern u32 iscsi_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *,
-                       struct t10_pr_registration *, int *);
-extern char *iscsi_parse_pr_out_transport_id(struct se_portal_group *,
-                       const char *, u32 *, char **);
-
-#endif /* TARGET_CORE_FABRIC_LIB_H */
diff --git a/include/target/target_core_tmr.h b/include/target/target_core_tmr.h
deleted file mode 100644 (file)
index d5876e1..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef TARGET_CORE_TMR_H
-#define TARGET_CORE_TMR_H
-
-/* fabric independent task management function values */
-enum tcm_tmreq_table {
-       TMR_ABORT_TASK          = 1,
-       TMR_ABORT_TASK_SET      = 2,
-       TMR_CLEAR_ACA           = 3,
-       TMR_CLEAR_TASK_SET      = 4,
-       TMR_LUN_RESET           = 5,
-       TMR_TARGET_WARM_RESET   = 6,
-       TMR_TARGET_COLD_RESET   = 7,
-       TMR_FABRIC_TMR          = 255,
-};
-
-/* fabric independent task management response values */
-enum tcm_tmrsp_table {
-       TMR_FUNCTION_COMPLETE           = 0,
-       TMR_TASK_DOES_NOT_EXIST         = 1,
-       TMR_LUN_DOES_NOT_EXIST          = 2,
-       TMR_TASK_STILL_ALLEGIANT        = 3,
-       TMR_TASK_FAILOVER_NOT_SUPPORTED = 4,
-       TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED    = 5,
-       TMR_FUNCTION_AUTHORIZATION_FAILED = 6,
-       TMR_FUNCTION_REJECTED           = 255,
-};
-
-extern struct kmem_cache *se_tmr_req_cache;
-
-extern struct se_tmr_req *core_tmr_alloc_req(struct se_cmd *, void *, u8, gfp_t);
-extern void core_tmr_release_req(struct se_tmr_req *);
-extern int core_tmr_lun_reset(struct se_device *, struct se_tmr_req *,
-                               struct list_head *, struct se_cmd *);
-
-#endif /* TARGET_CORE_TMR_H */
diff --git a/include/target/target_core_tpg.h b/include/target/target_core_tpg.h
deleted file mode 100644 (file)
index 77e1872..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef TARGET_CORE_TPG_H
-#define TARGET_CORE_TPG_H
-
-extern struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tpg,
-                                               const char *);
-extern struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg,
-                                               unsigned char *);
-extern void core_tpg_add_node_to_devs(struct se_node_acl *,
-                                               struct se_portal_group *);
-extern struct se_node_acl *core_tpg_check_initiator_node_acl(
-                                               struct se_portal_group *,
-                                               unsigned char *);
-extern void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *);
-extern void core_tpg_wait_for_mib_ref(struct se_node_acl *);
-extern void core_tpg_clear_object_luns(struct se_portal_group *);
-extern struct se_node_acl *core_tpg_add_initiator_node_acl(
-                                       struct se_portal_group *,
-                                       struct se_node_acl *,
-                                       const char *, u32);
-extern int core_tpg_del_initiator_node_acl(struct se_portal_group *,
-                                               struct se_node_acl *, int);
-extern int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *,
-                                               unsigned char *, u32, int);
-extern int core_tpg_register(struct target_core_fabric_ops *,
-                                       struct se_wwn *,
-                                       struct se_portal_group *, void *,
-                                       int);
-extern int core_tpg_deregister(struct se_portal_group *);
-extern struct se_lun *core_tpg_pre_addlun(struct se_portal_group *, u32);
-extern int core_tpg_post_addlun(struct se_portal_group *, struct se_lun *, u32,
-                               void *);
-extern struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32, int *);
-extern int core_tpg_post_dellun(struct se_portal_group *, struct se_lun *);
-
-#endif /* TARGET_CORE_TPG_H */
diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h
deleted file mode 100644 (file)
index dac4f2d..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-#ifndef TARGET_CORE_TRANSPORT_H
-#define TARGET_CORE_TRANSPORT_H
-
-#define TARGET_CORE_VERSION                    TARGET_CORE_MOD_VERSION
-
-/* Attempts before moving from SHORT to LONG */
-#define PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD  3
-#define PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT 3  /* In milliseconds */
-#define PYX_TRANSPORT_WINDOW_CLOSED_WAIT_LONG  10 /* In milliseconds */
-
-#define PYX_TRANSPORT_STATUS_INTERVAL          5 /* In seconds */
-
-#define TRANSPORT_PLUGIN_PHBA_PDEV             1
-#define TRANSPORT_PLUGIN_VHBA_PDEV             2
-#define TRANSPORT_PLUGIN_VHBA_VDEV             3
-
-/*
- * struct se_subsystem_dev->su_dev_flags
-*/
-#define SDF_FIRMWARE_VPD_UNIT_SERIAL           0x00000001
-#define SDF_EMULATED_VPD_UNIT_SERIAL           0x00000002
-#define SDF_USING_UDEV_PATH                    0x00000004
-#define SDF_USING_ALIAS                                0x00000008
-
-/*
- * struct se_device->dev_flags
- */
-#define DF_READ_ONLY                           0x00000001
-#define DF_SPC2_RESERVATIONS                   0x00000002
-#define DF_SPC2_RESERVATIONS_WITH_ISID         0x00000004
-
-/* struct se_dev_attrib sanity values */
-/* Default max_unmap_lba_count */
-#define DA_MAX_UNMAP_LBA_COUNT                 0
-/* Default max_unmap_block_desc_count */
-#define DA_MAX_UNMAP_BLOCK_DESC_COUNT          0
-/* Default unmap_granularity */
-#define DA_UNMAP_GRANULARITY_DEFAULT           0
-/* Default unmap_granularity_alignment */
-#define DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT 0
-/* Emulation for Direct Page Out */
-#define DA_EMULATE_DPO                         0
-/* Emulation for Forced Unit Access WRITEs */
-#define DA_EMULATE_FUA_WRITE                   1
-/* Emulation for Forced Unit Access READs */
-#define DA_EMULATE_FUA_READ                    0
-/* Emulation for WriteCache and SYNCHRONIZE_CACHE */
-#define DA_EMULATE_WRITE_CACHE                 0
-/* Emulation for UNIT ATTENTION Interlock Control */
-#define DA_EMULATE_UA_INTLLCK_CTRL             0
-/* Emulation for TASK_ABORTED status (TAS) by default */
-#define DA_EMULATE_TAS                         1
-/* Emulation for Thin Provisioning UNMAP using block/blk-lib.c:blkdev_issue_discard() */
-#define DA_EMULATE_TPU                         0
-/*
- * Emulation for Thin Provisioning WRITE_SAME w/ UNMAP=1 bit using
- * block/blk-lib.c:blkdev_issue_discard()
- */
-#define DA_EMULATE_TPWS                                0
-/* No Emulation for PSCSI by default */
-#define DA_EMULATE_RESERVATIONS                        0
-/* No Emulation for PSCSI by default */
-#define DA_EMULATE_ALUA                                0
-/* Enforce SCSI Initiator Port TransportID with 'ISID' for PR */
-#define DA_ENFORCE_PR_ISIDS                    1
-#define DA_STATUS_MAX_SECTORS_MIN              16
-#define DA_STATUS_MAX_SECTORS_MAX              8192
-/* By default don't report non-rotating (solid state) medium */
-#define DA_IS_NONROT                           0
-/* Queue Algorithm Modifier default for restricted reordering in control mode page */
-#define DA_EMULATE_REST_REORD                  0
-
-#define SE_MODE_PAGE_BUF                       512
-
-#define MOD_MAX_SECTORS(ms, bs)                        (ms % (PAGE_SIZE / bs))
-
-struct se_subsystem_api;
-
-extern int init_se_kmem_caches(void);
-extern void release_se_kmem_caches(void);
-extern u32 scsi_get_new_index(scsi_index_t);
-extern void transport_init_queue_obj(struct se_queue_obj *);
-extern void transport_subsystem_check_init(void);
-extern int transport_subsystem_register(struct se_subsystem_api *);
-extern void transport_subsystem_release(struct se_subsystem_api *);
-extern void transport_load_plugins(void);
-extern struct se_session *transport_init_session(void);
-extern void __transport_register_session(struct se_portal_group *,
-                                       struct se_node_acl *,
-                                       struct se_session *, void *);
-extern void transport_register_session(struct se_portal_group *,
-                                       struct se_node_acl *,
-                                       struct se_session *, void *);
-extern void transport_free_session(struct se_session *);
-extern void transport_deregister_session_configfs(struct se_session *);
-extern void transport_deregister_session(struct se_session *);
-extern void transport_cmd_finish_abort(struct se_cmd *, int);
-extern void transport_complete_sync_cache(struct se_cmd *, int);
-extern void transport_complete_task(struct se_task *, int);
-extern void transport_add_task_to_execute_queue(struct se_task *,
-                                               struct se_task *,
-                                               struct se_device *);
-extern void transport_remove_task_from_execute_queue(struct se_task *,
-                                               struct se_device *);
-extern void __transport_remove_task_from_execute_queue(struct se_task *,
-                                               struct se_device *);
-unsigned char *transport_dump_cmd_direction(struct se_cmd *);
-extern void transport_dump_dev_state(struct se_device *, char *, int *);
-extern void transport_dump_dev_info(struct se_device *, struct se_lun *,
-                                       unsigned long long, char *, int *);
-extern void transport_dump_vpd_proto_id(struct t10_vpd *,
-                                       unsigned char *, int);
-extern void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *);
-extern int transport_dump_vpd_assoc(struct t10_vpd *,
-                                       unsigned char *, int);
-extern int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *);
-extern int transport_dump_vpd_ident_type(struct t10_vpd *,
-                                       unsigned char *, int);
-extern int transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *);
-extern int transport_dump_vpd_ident(struct t10_vpd *,
-                                       unsigned char *, int);
-extern int transport_set_vpd_ident(struct t10_vpd *, unsigned char *);
-extern struct se_device *transport_add_device_to_core_hba(struct se_hba *,
-                                       struct se_subsystem_api *,
-                                       struct se_subsystem_dev *, u32,
-                                       void *, struct se_dev_limits *,
-                                       const char *, const char *);
-extern void transport_init_se_cmd(struct se_cmd *,
-                                       struct target_core_fabric_ops *,
-                                       struct se_session *, u32, int, int,
-                                       unsigned char *);
-void *transport_kmap_first_data_page(struct se_cmd *cmd);
-void transport_kunmap_first_data_page(struct se_cmd *cmd);
-extern int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *);
-extern int transport_handle_cdb_direct(struct se_cmd *);
-extern int transport_generic_handle_cdb_map(struct se_cmd *);
-extern int transport_generic_handle_data(struct se_cmd *);
-extern int transport_generic_handle_tmr(struct se_cmd *);
-extern bool target_stop_task(struct se_task *task, unsigned long *flags);
-extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32,
-                               struct scatterlist *, u32);
-extern int transport_clear_lun_from_sessions(struct se_lun *);
-extern bool transport_wait_for_tasks(struct se_cmd *);
-extern int transport_check_aborted_status(struct se_cmd *, int);
-extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int);
-extern void transport_send_task_abort(struct se_cmd *);
-extern void transport_release_cmd(struct se_cmd *);
-extern void transport_generic_free_cmd(struct se_cmd *, int);
-extern void target_get_sess_cmd(struct se_session *, struct se_cmd *);
-extern int target_put_sess_cmd(struct se_session *, struct se_cmd *);
-extern void target_splice_sess_cmd_list(struct se_session *);
-extern void target_wait_for_sess_cmds(struct se_session *, int);
-extern void transport_generic_wait_for_cmds(struct se_cmd *, int);
-extern void transport_do_task_sg_chain(struct se_cmd *);
-extern void transport_generic_process_write(struct se_cmd *);
-extern int transport_generic_new_cmd(struct se_cmd *);
-extern int transport_generic_do_tmr(struct se_cmd *);
-/* From target_core_alua.c */
-extern int core_alua_check_nonop_delay(struct se_cmd *);
-/* From target_core_cdb.c */
-extern int transport_emulate_control_cdb(struct se_task *);
-extern void target_get_task_cdb(struct se_task *task, unsigned char *cdb);
-
-/*
- * Each se_transport_task_t can have N number of possible struct se_task's
- * for the storage transport(s) to possibly execute.
- * Used primarily for splitting up CDBs that exceed the physical storage
- * HBA's maximum sector count per task.
- */
-struct se_mem {
-       struct page     *se_page;
-       u32             se_len;
-       u32             se_off;
-       struct list_head se_list;
-} ____cacheline_aligned;
-
-/*
- *     Each type of disk transport supported MUST have a template defined
- *     within its .h file.
- */
-struct se_subsystem_api {
-       /*
-        * The Name. :-)
-        */
-       char name[16];
-       /*
-        * Transport Type.
-        */
-       u8 transport_type;
-
-       unsigned int fua_write_emulated : 1;
-       unsigned int write_cache_emulated : 1;
-
-       /*
-        * struct module for struct se_hba references
-        */
-       struct module *owner;
-       /*
-        * Used for global se_subsystem_api list_head
-        */
-       struct list_head sub_api_list;
-       /*
-        * attach_hba():
-        */
-       int (*attach_hba)(struct se_hba *, u32);
-       /*
-        * detach_hba():
-        */
-       void (*detach_hba)(struct se_hba *);
-       /*
-        * pmode_hba(): Used for TCM/pSCSI subsystem plugin HBA ->
-        *              Linux/SCSI struct Scsi_Host passthrough
-       */
-       int (*pmode_enable_hba)(struct se_hba *, unsigned long);
-       /*
-        * allocate_virtdevice():
-        */
-       void *(*allocate_virtdevice)(struct se_hba *, const char *);
-       /*
-        * create_virtdevice(): Only for Virtual HBAs
-        */
-       struct se_device *(*create_virtdevice)(struct se_hba *,
-                               struct se_subsystem_dev *, void *);
-       /*
-        * free_device():
-        */
-       void (*free_device)(void *);
-
-       /*
-        * transport_complete():
-        *
-        * Use transport_generic_complete() for majority of DAS transport
-        * drivers.  Provided out of convenience.
-        */
-       int (*transport_complete)(struct se_task *task);
-       struct se_task *(*alloc_task)(unsigned char *cdb);
-       /*
-        * do_task():
-        */
-       int (*do_task)(struct se_task *);
-       /*
-        * Used by virtual subsystem plugins IBLOCK and FILEIO to emulate
-        * UNMAP and WRITE_SAME_* w/ UNMAP=1 <-> Linux/Block Discard
-        */
-       int (*do_discard)(struct se_device *, sector_t, u32);
-       /*
-        * Used  by virtual subsystem plugins IBLOCK and FILEIO to emulate
-        * SYNCHRONIZE_CACHE_* <-> Linux/Block blkdev_issue_flush()
-        */
-       void (*do_sync_cache)(struct se_task *);
-       /*
-        * free_task():
-        */
-       void (*free_task)(struct se_task *);
-       /*
-        * check_configfs_dev_params():
-        */
-       ssize_t (*check_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *);
-       /*
-        * set_configfs_dev_params():
-        */
-       ssize_t (*set_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *,
-                                               const char *, ssize_t);
-       /*
-        * show_configfs_dev_params():
-        */
-       ssize_t (*show_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *,
-                                               char *);
-       /*
-        * get_device_rev():
-        */
-       u32 (*get_device_rev)(struct se_device *);
-       /*
-        * get_device_type():
-        */
-       u32 (*get_device_type)(struct se_device *);
-       /*
-        * Get the sector_t from a subsystem backstore..
-        */
-       sector_t (*get_blocks)(struct se_device *);
-       /*
-        * get_sense_buffer():
-        */
-       unsigned char *(*get_sense_buffer)(struct se_task *);
-} ____cacheline_aligned;
-
-#endif /* TARGET_CORE_TRANSPORT_H */
index b31702ac15beb3f31ea7f2b5c1c36dd2b64b2f70..84f3001a568d9edf435c0465b7d421bbc74e858c 100644 (file)
@@ -16,6 +16,8 @@ struct btrfs_delayed_ref_node;
 struct btrfs_delayed_tree_ref;
 struct btrfs_delayed_data_ref;
 struct btrfs_delayed_ref_head;
+struct btrfs_block_group_cache;
+struct btrfs_free_cluster;
 struct map_lookup;
 struct extent_buffer;
 
@@ -44,6 +46,17 @@ struct extent_buffer;
        obj, ((obj >= BTRFS_DATA_RELOC_TREE_OBJECTID) ||                \
              (obj <= BTRFS_CSUM_TREE_OBJECTID )) ? __show_root_type(obj) : "-"
 
+#define BTRFS_GROUP_FLAGS      \
+       { BTRFS_BLOCK_GROUP_DATA,       "DATA"}, \
+       { BTRFS_BLOCK_GROUP_SYSTEM,     "SYSTEM"}, \
+       { BTRFS_BLOCK_GROUP_METADATA,   "METADATA"}, \
+       { BTRFS_BLOCK_GROUP_RAID0,      "RAID0"}, \
+       { BTRFS_BLOCK_GROUP_RAID1,      "RAID1"}, \
+       { BTRFS_BLOCK_GROUP_DUP,        "DUP"}, \
+       { BTRFS_BLOCK_GROUP_RAID10,     "RAID10"}
+
+#define BTRFS_UUID_SIZE 16
+
 TRACE_EVENT(btrfs_transaction_commit,
 
        TP_PROTO(struct btrfs_root *root),
@@ -621,6 +634,34 @@ TRACE_EVENT(btrfs_cow_block,
                  __entry->cow_level)
 );
 
+TRACE_EVENT(btrfs_space_reservation,
+
+       TP_PROTO(struct btrfs_fs_info *fs_info, char *type, u64 val,
+                u64 bytes, int reserve),
+
+       TP_ARGS(fs_info, type, val, bytes, reserve),
+
+       TP_STRUCT__entry(
+               __array(        u8,     fsid,   BTRFS_UUID_SIZE )
+               __string(       type,   type                    )
+               __field(        u64,    val                     )
+               __field(        u64,    bytes                   )
+               __field(        int,    reserve                 )
+       ),
+
+       TP_fast_assign(
+               memcpy(__entry->fsid, fs_info->fsid, BTRFS_UUID_SIZE);
+               __assign_str(type, type);
+               __entry->val            = val;
+               __entry->bytes          = bytes;
+               __entry->reserve        = reserve;
+       ),
+
+       TP_printk("%pU: %s: %Lu %s %Lu", __entry->fsid, __get_str(type),
+                 __entry->val, __entry->reserve ? "reserve" : "release",
+                 __entry->bytes)
+);
+
 DECLARE_EVENT_CLASS(btrfs__reserved_extent,
 
        TP_PROTO(struct btrfs_root *root, u64 start, u64 len),
@@ -659,6 +700,168 @@ DEFINE_EVENT(btrfs__reserved_extent,  btrfs_reserved_extent_free,
        TP_ARGS(root, start, len)
 );
 
+TRACE_EVENT(find_free_extent,
+
+       TP_PROTO(struct btrfs_root *root, u64 num_bytes, u64 empty_size,
+                u64 data),
+
+       TP_ARGS(root, num_bytes, empty_size, data),
+
+       TP_STRUCT__entry(
+               __field(        u64,    root_objectid           )
+               __field(        u64,    num_bytes               )
+               __field(        u64,    empty_size              )
+               __field(        u64,    data                    )
+       ),
+
+       TP_fast_assign(
+               __entry->root_objectid  = root->root_key.objectid;
+               __entry->num_bytes      = num_bytes;
+               __entry->empty_size     = empty_size;
+               __entry->data           = data;
+       ),
+
+       TP_printk("root = %Lu(%s), len = %Lu, empty_size = %Lu, "
+                 "flags = %Lu(%s)", show_root_type(__entry->root_objectid),
+                 __entry->num_bytes, __entry->empty_size, __entry->data,
+                 __print_flags((unsigned long)__entry->data, "|",
+                                BTRFS_GROUP_FLAGS))
+);
+
+DECLARE_EVENT_CLASS(btrfs__reserve_extent,
+
+       TP_PROTO(struct btrfs_root *root,
+                struct btrfs_block_group_cache *block_group, u64 start,
+                u64 len),
+
+       TP_ARGS(root, block_group, start, len),
+
+       TP_STRUCT__entry(
+               __field(        u64,    root_objectid           )
+               __field(        u64,    bg_objectid             )
+               __field(        u64,    flags                   )
+               __field(        u64,    start                   )
+               __field(        u64,    len                     )
+       ),
+
+       TP_fast_assign(
+               __entry->root_objectid  = root->root_key.objectid;
+               __entry->bg_objectid    = block_group->key.objectid;
+               __entry->flags          = block_group->flags;
+               __entry->start          = start;
+               __entry->len            = len;
+       ),
+
+       TP_printk("root = %Lu(%s), block_group = %Lu, flags = %Lu(%s), "
+                 "start = %Lu, len = %Lu",
+                 show_root_type(__entry->root_objectid), __entry->bg_objectid,
+                 __entry->flags, __print_flags((unsigned long)__entry->flags,
+                                               "|", BTRFS_GROUP_FLAGS),
+                 __entry->start, __entry->len)
+);
+
+DEFINE_EVENT(btrfs__reserve_extent, btrfs_reserve_extent,
+
+       TP_PROTO(struct btrfs_root *root,
+                struct btrfs_block_group_cache *block_group, u64 start,
+                u64 len),
+
+       TP_ARGS(root, block_group, start, len)
+);
+
+DEFINE_EVENT(btrfs__reserve_extent, btrfs_reserve_extent_cluster,
+
+       TP_PROTO(struct btrfs_root *root,
+                struct btrfs_block_group_cache *block_group, u64 start,
+                u64 len),
+
+       TP_ARGS(root, block_group, start, len)
+);
+
+TRACE_EVENT(btrfs_find_cluster,
+
+       TP_PROTO(struct btrfs_block_group_cache *block_group, u64 start,
+                u64 bytes, u64 empty_size, u64 min_bytes),
+
+       TP_ARGS(block_group, start, bytes, empty_size, min_bytes),
+
+       TP_STRUCT__entry(
+               __field(        u64,    bg_objectid             )
+               __field(        u64,    flags                   )
+               __field(        u64,    start                   )
+               __field(        u64,    bytes                   )
+               __field(        u64,    empty_size              )
+               __field(        u64,    min_bytes               )
+       ),
+
+       TP_fast_assign(
+               __entry->bg_objectid    = block_group->key.objectid;
+               __entry->flags          = block_group->flags;
+               __entry->start          = start;
+               __entry->bytes          = bytes;
+               __entry->empty_size     = empty_size;
+               __entry->min_bytes      = min_bytes;
+       ),
+
+       TP_printk("block_group = %Lu, flags = %Lu(%s), start = %Lu, len = %Lu,"
+                 " empty_size = %Lu, min_bytes = %Lu", __entry->bg_objectid,
+                 __entry->flags,
+                 __print_flags((unsigned long)__entry->flags, "|",
+                               BTRFS_GROUP_FLAGS), __entry->start,
+                 __entry->bytes, __entry->empty_size,  __entry->min_bytes)
+);
+
+TRACE_EVENT(btrfs_failed_cluster_setup,
+
+       TP_PROTO(struct btrfs_block_group_cache *block_group),
+
+       TP_ARGS(block_group),
+
+       TP_STRUCT__entry(
+               __field(        u64,    bg_objectid             )
+       ),
+
+       TP_fast_assign(
+               __entry->bg_objectid    = block_group->key.objectid;
+       ),
+
+       TP_printk("block_group = %Lu", __entry->bg_objectid)
+);
+
+TRACE_EVENT(btrfs_setup_cluster,
+
+       TP_PROTO(struct btrfs_block_group_cache *block_group,
+                struct btrfs_free_cluster *cluster, u64 size, int bitmap),
+
+       TP_ARGS(block_group, cluster, size, bitmap),
+
+       TP_STRUCT__entry(
+               __field(        u64,    bg_objectid             )
+               __field(        u64,    flags                   )
+               __field(        u64,    start                   )
+               __field(        u64,    max_size                )
+               __field(        u64,    size                    )
+               __field(        int,    bitmap                  )
+       ),
+
+       TP_fast_assign(
+               __entry->bg_objectid    = block_group->key.objectid;
+               __entry->flags          = block_group->flags;
+               __entry->start          = cluster->window_start;
+               __entry->max_size       = cluster->max_size;
+               __entry->size           = size;
+               __entry->bitmap         = bitmap;
+       ),
+
+       TP_printk("block_group = %Lu, flags = %Lu(%s), window_start = %Lu, "
+                 "size = %Lu, max_size = %Lu, bitmap = %d",
+                 __entry->bg_objectid,
+                 __entry->flags,
+                 __print_flags((unsigned long)__entry->flags, "|",
+                               BTRFS_GROUP_FLAGS), __entry->start,
+                 __entry->size, __entry->max_size, __entry->bitmap)
+);
+
 #endif /* _TRACE_BTRFS_H */
 
 /* This part must be outside protection */
index edc4b3d25a2d4e38917c83554eccd23a32fc8815..f64560e204bc1f84cd6c8ba5e6ba7f1f6938c656 100644 (file)
@@ -266,9 +266,10 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
                unsigned long nr_lumpy_taken,
                unsigned long nr_lumpy_dirty,
                unsigned long nr_lumpy_failed,
-               isolate_mode_t isolate_mode),
+               isolate_mode_t isolate_mode,
+               int file),
 
-       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode),
+       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode, file),
 
        TP_STRUCT__entry(
                __field(int, order)
@@ -279,6 +280,7 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
                __field(unsigned long, nr_lumpy_dirty)
                __field(unsigned long, nr_lumpy_failed)
                __field(isolate_mode_t, isolate_mode)
+               __field(int, file)
        ),
 
        TP_fast_assign(
@@ -290,9 +292,10 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
                __entry->nr_lumpy_dirty = nr_lumpy_dirty;
                __entry->nr_lumpy_failed = nr_lumpy_failed;
                __entry->isolate_mode = isolate_mode;
+               __entry->file = file;
        ),
 
-       TP_printk("isolate_mode=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu contig_taken=%lu contig_dirty=%lu contig_failed=%lu",
+       TP_printk("isolate_mode=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu contig_taken=%lu contig_dirty=%lu contig_failed=%lu file=%d",
                __entry->isolate_mode,
                __entry->order,
                __entry->nr_requested,
@@ -300,7 +303,8 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
                __entry->nr_taken,
                __entry->nr_lumpy_taken,
                __entry->nr_lumpy_dirty,
-               __entry->nr_lumpy_failed)
+               __entry->nr_lumpy_failed,
+               __entry->file)
 );
 
 DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_lru_isolate,
@@ -312,9 +316,10 @@ DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_lru_isolate,
                unsigned long nr_lumpy_taken,
                unsigned long nr_lumpy_dirty,
                unsigned long nr_lumpy_failed,
-               isolate_mode_t isolate_mode),
+               isolate_mode_t isolate_mode,
+               int file),
 
-       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode)
+       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode, file)
 
 );
 
@@ -327,9 +332,10 @@ DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_memcg_isolate,
                unsigned long nr_lumpy_taken,
                unsigned long nr_lumpy_dirty,
                unsigned long nr_lumpy_failed,
-               isolate_mode_t isolate_mode),
+               isolate_mode_t isolate_mode,
+               int file),
 
-       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode)
+       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode, file)
 
 );
 
index 928c342b33d65040be5d2bfd958447d21074e92f..c5f198704912d22844cfc411948ee1ae80078494 100644 (file)
@@ -1,16 +1,14 @@
 #ifndef __linux_video_edid_h__
 #define __linux_video_edid_h__
 
-#if !defined(__KERNEL__) || defined(CONFIG_X86)
-
 struct edid_info {
        unsigned char dummy[128];
 };
 
 #ifdef __KERNEL__
+#ifdef CONFIG_X86
 extern struct edid_info edid_info;
-#endif /* __KERNEL__ */
-
+#endif
 #endif
 
 #endif /* __linux_video_edid_h__ */
index 378c7ed6760be0563b501971df2a60e03a672ea7..062b3b24ff1071047f6c7fe26c80d19c112fe311 100644 (file)
@@ -200,6 +200,10 @@ enum omap_dss_clk_source {
        OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI,    /* OMAP4: PLL2_CLK2 */
 };
 
+enum omap_hdmi_flags {
+       OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP = 1 << 0,
+};
+
 /* RFBI */
 
 struct rfbi_timings {
@@ -294,8 +298,8 @@ int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
                u16 len);
 int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel);
 int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel);
-int dsi_video_mode_enable(struct omap_dss_device *dssdev, int channel);
-void dsi_video_mode_disable(struct omap_dss_device *dssdev, int channel);
+int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel);
+void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel);
 
 /* Board specific data */
 struct omap_dss_board_info {
@@ -309,6 +313,8 @@ struct omap_dss_board_info {
 
 /* Init with the board info */
 extern int omap_display_init(struct omap_dss_board_info *board_data);
+/* HDMI mux init*/
+extern int omap_hdmi_init(enum omap_hdmi_flags flags);
 
 struct omap_display_platform_data {
        struct omap_dss_board_info *board_data;
@@ -352,8 +358,6 @@ struct omap_dss_cpr_coefs {
 };
 
 struct omap_overlay_info {
-       bool enabled;
-
        u32 paddr;
        u32 p_uv_addr;  /* for NV12 format */
        u16 screen_width;
@@ -385,11 +389,21 @@ struct omap_overlay {
 
        /* dynamic fields */
        struct omap_overlay_manager *manager;
-       struct omap_overlay_info info;
 
-       bool manager_changed;
-       /* if true, info has been changed, but not applied() yet */
-       bool info_dirty;
+       /*
+        * The following functions do not block:
+        *
+        * is_enabled
+        * set_overlay_info
+        * get_overlay_info
+        *
+        * The rest of the functions may block and cannot be called from
+        * interrupt context
+        */
+
+       int (*enable)(struct omap_overlay *ovl);
+       int (*disable)(struct omap_overlay *ovl);
+       bool (*is_enabled)(struct omap_overlay *ovl);
 
        int (*set_manager)(struct omap_overlay *ovl,
                struct omap_overlay_manager *mgr);
@@ -418,23 +432,27 @@ struct omap_overlay_manager_info {
 
 struct omap_overlay_manager {
        struct kobject kobj;
-       struct list_head list;
 
        /* static fields */
        const char *name;
        enum omap_channel id;
        enum omap_overlay_manager_caps caps;
-       int num_overlays;
-       struct omap_overlay **overlays;
+       struct list_head overlays;
        enum omap_display_type supported_displays;
 
        /* dynamic fields */
        struct omap_dss_device *device;
-       struct omap_overlay_manager_info info;
 
-       bool device_changed;
-       /* if true, info has been changed but not applied() yet */
-       bool info_dirty;
+       /*
+        * The following functions do not block:
+        *
+        * set_manager_info
+        * get_manager_info
+        * apply
+        *
+        * The rest of the functions may block and cannot be called from
+        * interrupt context
+        */
 
        int (*set_device)(struct omap_overlay_manager *mgr,
                struct omap_dss_device *dssdev);
@@ -448,9 +466,6 @@ struct omap_overlay_manager {
        int (*apply)(struct omap_overlay_manager *mgr);
        int (*wait_for_go)(struct omap_overlay_manager *mgr);
        int (*wait_for_vsync)(struct omap_overlay_manager *mgr);
-
-       int (*enable)(struct omap_overlay_manager *mgr);
-       int (*disable)(struct omap_overlay_manager *mgr);
 };
 
 struct omap_dss_device {
@@ -662,12 +677,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
                bool enable);
 int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable);
 
-int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
-                                   u16 *x, u16 *y, u16 *w, u16 *h,
-                                   bool enlarge_update_area);
-int omap_dsi_update(struct omap_dss_device *dssdev,
-               int channel,
-               u16 x, u16 y, u16 w, u16 h,
+int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
                void (*callback)(int, void *), void *data);
 int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel);
 int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id);
index 6cb95c977de9c2455e7c5007a6cf641d0524f3e2..434d56b4a1a58db0ab4b4c08993b1630e70d235b 100644 (file)
@@ -28,14 +28,33 @@ enum sh_mipi_dsi_data_fmt {
 struct sh_mobile_lcdc_chan_cfg;
 
 #define SH_MIPI_DSI_HSABM      (1 << 0)
-#define SH_MIPI_DSI_HSPBM      (1 << 1)
+#define SH_MIPI_DSI_HBPBM      (1 << 1)
+#define SH_MIPI_DSI_HFPBM      (1 << 2)
+#define SH_MIPI_DSI_BL2E       (1 << 3)
+#define SH_MIPI_DSI_VSEE       (1 << 4)
+#define SH_MIPI_DSI_HSEE       (1 << 5)
+#define SH_MIPI_DSI_HSAE       (1 << 6)
+
+#define SH_MIPI_DSI_HSbyteCLK  (1 << 24)
+#define SH_MIPI_DSI_HS6divCLK  (1 << 25)
+#define SH_MIPI_DSI_HS4divCLK  (1 << 26)
+
+#define SH_MIPI_DSI_SYNC_PULSES_MODE   (SH_MIPI_DSI_VSEE | \
+                                        SH_MIPI_DSI_HSEE | \
+                                        SH_MIPI_DSI_HSAE)
+#define SH_MIPI_DSI_SYNC_EVENTS_MODE   (0)
+#define SH_MIPI_DSI_SYNC_BURST_MODE    (SH_MIPI_DSI_BL2E)
 
 struct sh_mipi_dsi_info {
        enum sh_mipi_dsi_data_fmt       data_format;
        struct sh_mobile_lcdc_chan_cfg  *lcd_chan;
+       int                             lane;
        unsigned long                   flags;
        u32                             clksrc;
        unsigned int                    vsynw_offset;
+       int     (*set_dot_clock)(struct platform_device *pdev,
+                                void __iomem *base,
+                                int enable);
 };
 
 #endif
index 8101b726b48a273240558cb57a8b7b348b222f24..fe30b759c51e68834508abb7f084a213e34c6824 100644 (file)
@@ -174,7 +174,8 @@ struct sh_mobile_lcdc_bl_info {
 
 struct sh_mobile_lcdc_chan_cfg {
        int chan;
-       int bpp;
+       int fourcc;
+       int colorspace;
        int interface_type; /* selects RGBn or SYSn I/F, see above */
        int clock_divider;
        unsigned long flags; /* LCDC_FLAGS_... */
@@ -184,7 +185,6 @@ struct sh_mobile_lcdc_chan_cfg {
        struct sh_mobile_lcdc_board_cfg board_cfg;
        struct sh_mobile_lcdc_bl_info bl_info;
        struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */
-       int nonstd;
        struct sh_mobile_meram_cfg *meram_cfg;
 };
 
index 9324488f23f0b2eaab58e50f7cdda0b6d4b152ef..ee338bfde18b25d45bb0252ff41ea4160095d6e7 100644 (file)
@@ -84,6 +84,21 @@ typedef uint64_t blkif_sector_t;
  *     e07154r6-Data_Set_Management_Proposal_for_ATA-ACS2.doc
  * http://www.seagate.com/staticfiles/support/disc/manuals/
  *     Interface%20manuals/100293068c.pdf
+ * The backend can optionally provide three extra XenBus attributes to
+ * further optimize the discard functionality:
+ * 'discard-aligment' - Devices that support discard functionality may
+ * internally allocate space in units that are bigger than the exported
+ * logical block size. The discard-alignment parameter indicates how many bytes
+ * the beginning of the partition is offset from the internal allocation unit's
+ * natural alignment.
+ * 'discard-granularity'  - Devices that support discard functionality may
+ * internally allocate space using units that are bigger than the logical block
+ * size. The discard-granularity parameter indicates the size of the internal
+ * allocation unit in bytes if reported by the device. Otherwise the
+ * discard-granularity will be set to match the device's physical block size.
+ * 'discard-secure' - All copies of the discarded sectors (potentially created
+ * by garbage collection) must also be erased.  To use this feature, the flag
+ * BLKIF_DISCARD_SECURE must be set in the blkif_request_trim.
  */
 #define BLKIF_OP_DISCARD           5
 
@@ -95,6 +110,12 @@ typedef uint64_t blkif_sector_t;
 #define BLKIF_MAX_SEGMENTS_PER_REQUEST 11
 
 struct blkif_request_rw {
+       uint8_t        nr_segments;  /* number of segments                   */
+       blkif_vdev_t   handle;       /* only for read/write requests         */
+#ifdef CONFIG_X86_64
+       uint32_t       _pad1;        /* offsetof(blkif_request,u.rw.id) == 8 */
+#endif
+       uint64_t       id;           /* private guest value, echoed in resp  */
        blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
        struct blkif_request_segment {
                grant_ref_t gref;        /* reference to I/O buffer frame        */
@@ -102,23 +123,28 @@ struct blkif_request_rw {
                /* @last_sect: last sector in frame to transfer (inclusive).     */
                uint8_t     first_sect, last_sect;
        } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-};
+} __attribute__((__packed__));
 
 struct blkif_request_discard {
+       uint8_t        flag;         /* BLKIF_DISCARD_SECURE or zero.        */
+#define BLKIF_DISCARD_SECURE (1<<0)  /* ignored if discard-secure=0          */
+       blkif_vdev_t   _pad1;        /* only for read/write requests         */
+#ifdef CONFIG_X86_64
+       uint32_t       _pad2;        /* offsetof(blkif_req..,u.discard.id)==8*/
+#endif
+       uint64_t       id;           /* private guest value, echoed in resp  */
        blkif_sector_t sector_number;
-       uint64_t nr_sectors;
-};
+       uint64_t       nr_sectors;
+       uint8_t        _pad3;
+} __attribute__((__packed__));
 
 struct blkif_request {
        uint8_t        operation;    /* BLKIF_OP_???                         */
-       uint8_t        nr_segments;  /* number of segments                   */
-       blkif_vdev_t   handle;       /* only for read/write requests         */
-       uint64_t       id;           /* private guest value, echoed in resp  */
        union {
                struct blkif_request_rw rw;
                struct blkif_request_discard discard;
        } u;
-};
+} __attribute__((__packed__));
 
 struct blkif_response {
        uint64_t        id;              /* copied from request */
index 018d206c21f74a8af5c9af7388c28b33c39d143c..3f42cd66f0f87a25510dd000aed37de5c0d5cc71 100644 (file)
@@ -355,7 +355,7 @@ config AUDIT
 
 config AUDITSYSCALL
        bool "Enable system-call auditing support"
-       depends on AUDIT && (X86 || PPC || S390 || IA64 || UML || SPARC64 || SUPERH)
+       depends on AUDIT && (X86 || PPC || S390 || IA64 || UML || SPARC64 || SUPERH || ARM)
        default y if SECURITY_SELINUX
        help
          Enable low-overhead system-call auditing infrastructure that
@@ -372,6 +372,20 @@ config AUDIT_TREE
        depends on AUDITSYSCALL
        select FSNOTIFY
 
+config AUDIT_LOGINUID_IMMUTABLE
+       bool "Make audit loginuid immutable"
+       depends on AUDIT
+       help
+         The config option toggles if a task setting its loginuid requires
+         CAP_SYS_AUDITCONTROL or if that task should require no special permissions
+         but should instead only allow setting its loginuid if it was never
+         previously set.  On systems which use systemd or a similar central
+         process to restart login services this should be set to true.  On older
+         systems in which an admin would typically have to directly stop and
+         start processes this should be set to false.  Setting this to true allows
+         one to drop potentially dangerous capabilites from the login tasks,
+         but may not be backwards compatible with older init systems.
+
 source "kernel/irq/Kconfig"
 
 menu "RCU Subsystem"
@@ -783,6 +797,17 @@ config DEBUG_BLK_CGROUP
 
 endif # CGROUPS
 
+config CHECKPOINT_RESTORE
+       bool "Checkpoint/restore support" if EXPERT
+       default n
+       help
+         Enables additional kernel features in a sake of checkpoint/restore.
+         In particular it adds auxiliary prctl codes to setup process text,
+         data and heap segment sizes, and a few additional /proc filesystem
+         entries.
+
+         If unsure, say N here.
+
 menuconfig NAMESPACES
        bool "Namespaces support" if EXPERT
        default !EXPERT
index 415548e808d2873fda39a123a202186b9968dd7f..ff49a6dacfbbdf673e38f4797127c5e4b8de8c73 100644 (file)
@@ -648,7 +648,7 @@ static void __init do_ctors(void)
 #endif
 }
 
-int initcall_debug;
+bool initcall_debug;
 core_param(initcall_debug, initcall_debug, bool, 0644);
 
 static char msgbuf[64];
index f70396e5a24b8cef95d994ed612aca85beaaac92..2d9de86b7e767f518e59183a98bf4c04e0038813 100644 (file)
@@ -23,6 +23,7 @@ CFLAGS_REMOVE_irq_work.o = -pg
 endif
 
 obj-y += sched/
+obj-y += power/
 
 obj-$(CONFIG_FREEZER) += freezer.o
 obj-$(CONFIG_PROFILING) += profile.o
@@ -52,8 +53,6 @@ obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
-obj-$(CONFIG_PM) += power/
-obj-$(CONFIG_FREEZER) += power/
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC) += kexec.o
 obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o
index 80b74b88fefe43076d2fbb0fc1d2d8c3d5b989fd..bd0c168a3bbe5134e1bd4c009947c2011e551340 100644 (file)
@@ -78,8 +78,6 @@ static DECLARE_WAIT_QUEUE_HEAD(async_done);
 
 static atomic_t entry_count;
 
-extern int initcall_debug;
-
 
 /*
  * MUST be called with the lock held!
index 2c1d6ab7106ee9921bc8456d0e9b5e11637a11f3..bb0eb5bb9a0a8761286dfc29cd1aa5b8587e2801 100644 (file)
@@ -601,13 +601,13 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
        case AUDIT_TTY_SET:
        case AUDIT_TRIM:
        case AUDIT_MAKE_EQUIV:
-               if (security_netlink_recv(skb, CAP_AUDIT_CONTROL))
+               if (!capable(CAP_AUDIT_CONTROL))
                        err = -EPERM;
                break;
        case AUDIT_USER:
        case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
        case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
-               if (security_netlink_recv(skb, CAP_AUDIT_WRITE))
+               if (!capable(CAP_AUDIT_WRITE))
                        err = -EPERM;
                break;
        default:  /* bad msg */
@@ -631,7 +631,7 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
        }
 
        *ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
-       audit_log_format(*ab, "user pid=%d uid=%u auid=%u ses=%u",
+       audit_log_format(*ab, "pid=%d uid=%u auid=%u ses=%u",
                         pid, uid, auid, ses);
        if (sid) {
                rc = security_secid_to_secctx(sid, &ctx, &len);
@@ -1423,7 +1423,7 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
        char *p, *pathname;
 
        if (prefix)
-               audit_log_format(ab, " %s", prefix);
+               audit_log_format(ab, "%s", prefix);
 
        /* We will allow 11 spaces for ' (deleted)' to be appended */
        pathname = kmalloc(PATH_MAX+11, ab->gfp_mask);
index 91e7071c4d2c4f06376e7ad5c485a2aa98294edd..81676680337158e20ce6077a522b64cdfa15f59f 100644 (file)
@@ -36,12 +36,8 @@ enum audit_state {
        AUDIT_DISABLED,         /* Do not create per-task audit_context.
                                 * No syscall-specific audit records can
                                 * be generated. */
-       AUDIT_SETUP_CONTEXT,    /* Create the per-task audit_context,
-                                * but don't necessarily fill it in at
-                                * syscall entry time (i.e., filter
-                                * instead). */
        AUDIT_BUILD_CONTEXT,    /* Create the per-task audit_context,
-                                * and always fill it in at syscall
+                                * and fill it in at syscall
                                 * entry time.  This makes a full
                                 * syscall record available if some
                                 * other part of the kernel decides it
index f8277c80d678bfeaefb74ad02805b0a4a2cebaa2..a6c3f1abd206c9d9736cbe5834483e36fd1d62ff 100644 (file)
@@ -235,13 +235,15 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
        switch(listnr) {
        default:
                goto exit_err;
-       case AUDIT_FILTER_USER:
-       case AUDIT_FILTER_TYPE:
 #ifdef CONFIG_AUDITSYSCALL
        case AUDIT_FILTER_ENTRY:
+               if (rule->action == AUDIT_ALWAYS)
+                       goto exit_err;
        case AUDIT_FILTER_EXIT:
        case AUDIT_FILTER_TASK:
 #endif
+       case AUDIT_FILTER_USER:
+       case AUDIT_FILTER_TYPE:
                ;
        }
        if (unlikely(rule->action == AUDIT_POSSIBLE)) {
@@ -385,7 +387,7 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
                                goto exit_free;
                        break;
                case AUDIT_FILETYPE:
-                       if ((f->val & ~S_IFMT) > S_IFMT)
+                       if (f->val & ~S_IFMT)
                                goto exit_free;
                        break;
                case AUDIT_INODE:
@@ -459,6 +461,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                case AUDIT_ARG1:
                case AUDIT_ARG2:
                case AUDIT_ARG3:
+               case AUDIT_OBJ_UID:
+               case AUDIT_OBJ_GID:
                        break;
                case AUDIT_ARCH:
                        entry->rule.arch_f = f;
@@ -522,7 +526,6 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                                goto exit_free;
                        break;
                case AUDIT_FILTERKEY:
-                       err = -EINVAL;
                        if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN)
                                goto exit_free;
                        str = audit_unpack_string(&bufp, &remain, f->val);
@@ -536,7 +539,11 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                                goto exit_free;
                        break;
                case AUDIT_FILETYPE:
-                       if ((f->val & ~S_IFMT) > S_IFMT)
+                       if (f->val & ~S_IFMT)
+                               goto exit_free;
+                       break;
+               case AUDIT_FIELD_COMPARE:
+                       if (f->val > AUDIT_MAX_FIELD_COMPARE)
                                goto exit_free;
                        break;
                default:
index e7fe2b0d29b3cd0676caccc6af116a76afee947e..caaea6e944f859595020a29265038e9669a2501f 100644 (file)
 
 #include "audit.h"
 
+/* flags stating the success for a syscall */
+#define AUDITSC_INVALID 0
+#define AUDITSC_SUCCESS 1
+#define AUDITSC_FAILURE 2
+
 /* AUDIT_NAMES is the number of slots we reserve in the audit_context
- * for saving names from getname(). */
-#define AUDIT_NAMES    20
+ * for saving names from getname().  If we get more names we will allocate
+ * a name dynamically and also add those to the list anchored by names_list. */
+#define AUDIT_NAMES    5
 
 /* Indicates that audit should log the full pathname. */
 #define AUDIT_NAME_FULL -1
@@ -101,9 +107,8 @@ struct audit_cap_data {
  *
  * Further, in fs/namei.c:path_lookup() we store the inode and device. */
 struct audit_names {
+       struct list_head list;          /* audit_context->names_list */
        const char      *name;
-       int             name_len;       /* number of name's characters to log */
-       unsigned        name_put;       /* call __putname() for this name */
        unsigned long   ino;
        dev_t           dev;
        umode_t         mode;
@@ -113,6 +118,14 @@ struct audit_names {
        u32             osid;
        struct audit_cap_data fcap;
        unsigned int    fcap_ver;
+       int             name_len;       /* number of name's characters to log */
+       bool            name_put;       /* call __putname() for this name */
+       /*
+        * This was an allocated audit_names and not from the array of
+        * names allocated in the task audit context.  Thus this name
+        * should be freed on syscall exit
+        */
+       bool            should_free;
 };
 
 struct audit_aux_data {
@@ -174,8 +187,17 @@ struct audit_context {
        long                return_code;/* syscall return code */
        u64                 prio;
        int                 return_valid; /* return code is valid */
-       int                 name_count;
-       struct audit_names  names[AUDIT_NAMES];
+       /*
+        * The names_list is the list of all audit_names collected during this
+        * syscall.  The first AUDIT_NAMES entries in the names_list will
+        * actually be from the preallocated_names array for performance
+        * reasons.  Except during allocation they should never be referenced
+        * through the preallocated_names array and should only be found/used
+        * by running the names_list.
+        */
+       struct audit_names  preallocated_names[AUDIT_NAMES];
+       int                 name_count; /* total records in names_list */
+       struct list_head    names_list; /* anchor for struct audit_names->list */
        char *              filterkey;  /* key for rule that triggered record */
        struct path         pwd;
        struct audit_context *previous; /* For nested syscalls */
@@ -305,21 +327,21 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
        }
 }
 
-static int audit_match_filetype(struct audit_context *ctx, int which)
+static int audit_match_filetype(struct audit_context *ctx, int val)
 {
-       unsigned index = which & ~S_IFMT;
-       umode_t mode = which & S_IFMT;
+       struct audit_names *n;
+       umode_t mode = (umode_t)val;
 
        if (unlikely(!ctx))
                return 0;
 
-       if (index >= ctx->name_count)
-               return 0;
-       if (ctx->names[index].ino == -1)
-               return 0;
-       if ((ctx->names[index].mode ^ mode) & S_IFMT)
-               return 0;
-       return 1;
+       list_for_each_entry(n, &ctx->names_list, list) {
+               if ((n->ino != -1) &&
+                   ((n->mode & S_IFMT) == mode))
+                       return 1;
+       }
+
+       return 0;
 }
 
 /*
@@ -441,6 +463,134 @@ static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree)
        return 0;
 }
 
+static int audit_compare_id(uid_t uid1,
+                           struct audit_names *name,
+                           unsigned long name_offset,
+                           struct audit_field *f,
+                           struct audit_context *ctx)
+{
+       struct audit_names *n;
+       unsigned long addr;
+       uid_t uid2;
+       int rc;
+
+       BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
+
+       if (name) {
+               addr = (unsigned long)name;
+               addr += name_offset;
+
+               uid2 = *(uid_t *)addr;
+               rc = audit_comparator(uid1, f->op, uid2);
+               if (rc)
+                       return rc;
+       }
+
+       if (ctx) {
+               list_for_each_entry(n, &ctx->names_list, list) {
+                       addr = (unsigned long)n;
+                       addr += name_offset;
+
+                       uid2 = *(uid_t *)addr;
+
+                       rc = audit_comparator(uid1, f->op, uid2);
+                       if (rc)
+                               return rc;
+               }
+       }
+       return 0;
+}
+
+static int audit_field_compare(struct task_struct *tsk,
+                              const struct cred *cred,
+                              struct audit_field *f,
+                              struct audit_context *ctx,
+                              struct audit_names *name)
+{
+       switch (f->val) {
+       /* process to file object comparisons */
+       case AUDIT_COMPARE_UID_TO_OBJ_UID:
+               return audit_compare_id(cred->uid,
+                                       name, offsetof(struct audit_names, uid),
+                                       f, ctx);
+       case AUDIT_COMPARE_GID_TO_OBJ_GID:
+               return audit_compare_id(cred->gid,
+                                       name, offsetof(struct audit_names, gid),
+                                       f, ctx);
+       case AUDIT_COMPARE_EUID_TO_OBJ_UID:
+               return audit_compare_id(cred->euid,
+                                       name, offsetof(struct audit_names, uid),
+                                       f, ctx);
+       case AUDIT_COMPARE_EGID_TO_OBJ_GID:
+               return audit_compare_id(cred->egid,
+                                       name, offsetof(struct audit_names, gid),
+                                       f, ctx);
+       case AUDIT_COMPARE_AUID_TO_OBJ_UID:
+               return audit_compare_id(tsk->loginuid,
+                                       name, offsetof(struct audit_names, uid),
+                                       f, ctx);
+       case AUDIT_COMPARE_SUID_TO_OBJ_UID:
+               return audit_compare_id(cred->suid,
+                                       name, offsetof(struct audit_names, uid),
+                                       f, ctx);
+       case AUDIT_COMPARE_SGID_TO_OBJ_GID:
+               return audit_compare_id(cred->sgid,
+                                       name, offsetof(struct audit_names, gid),
+                                       f, ctx);
+       case AUDIT_COMPARE_FSUID_TO_OBJ_UID:
+               return audit_compare_id(cred->fsuid,
+                                       name, offsetof(struct audit_names, uid),
+                                       f, ctx);
+       case AUDIT_COMPARE_FSGID_TO_OBJ_GID:
+               return audit_compare_id(cred->fsgid,
+                                       name, offsetof(struct audit_names, gid),
+                                       f, ctx);
+       /* uid comparisons */
+       case AUDIT_COMPARE_UID_TO_AUID:
+               return audit_comparator(cred->uid, f->op, tsk->loginuid);
+       case AUDIT_COMPARE_UID_TO_EUID:
+               return audit_comparator(cred->uid, f->op, cred->euid);
+       case AUDIT_COMPARE_UID_TO_SUID:
+               return audit_comparator(cred->uid, f->op, cred->suid);
+       case AUDIT_COMPARE_UID_TO_FSUID:
+               return audit_comparator(cred->uid, f->op, cred->fsuid);
+       /* auid comparisons */
+       case AUDIT_COMPARE_AUID_TO_EUID:
+               return audit_comparator(tsk->loginuid, f->op, cred->euid);
+       case AUDIT_COMPARE_AUID_TO_SUID:
+               return audit_comparator(tsk->loginuid, f->op, cred->suid);
+       case AUDIT_COMPARE_AUID_TO_FSUID:
+               return audit_comparator(tsk->loginuid, f->op, cred->fsuid);
+       /* euid comparisons */
+       case AUDIT_COMPARE_EUID_TO_SUID:
+               return audit_comparator(cred->euid, f->op, cred->suid);
+       case AUDIT_COMPARE_EUID_TO_FSUID:
+               return audit_comparator(cred->euid, f->op, cred->fsuid);
+       /* suid comparisons */
+       case AUDIT_COMPARE_SUID_TO_FSUID:
+               return audit_comparator(cred->suid, f->op, cred->fsuid);
+       /* gid comparisons */
+       case AUDIT_COMPARE_GID_TO_EGID:
+               return audit_comparator(cred->gid, f->op, cred->egid);
+       case AUDIT_COMPARE_GID_TO_SGID:
+               return audit_comparator(cred->gid, f->op, cred->sgid);
+       case AUDIT_COMPARE_GID_TO_FSGID:
+               return audit_comparator(cred->gid, f->op, cred->fsgid);
+       /* egid comparisons */
+       case AUDIT_COMPARE_EGID_TO_SGID:
+               return audit_comparator(cred->egid, f->op, cred->sgid);
+       case AUDIT_COMPARE_EGID_TO_FSGID:
+               return audit_comparator(cred->egid, f->op, cred->fsgid);
+       /* sgid comparison */
+       case AUDIT_COMPARE_SGID_TO_FSGID:
+               return audit_comparator(cred->sgid, f->op, cred->fsgid);
+       default:
+               WARN(1, "Missing AUDIT_COMPARE define.  Report as a bug\n");
+               return 0;
+       }
+       return 0;
+}
+
 /* Determine if any context name data matches a rule's watch data */
 /* Compare a task_struct with an audit_rule.  Return 1 on match, 0
  * otherwise.
@@ -457,13 +607,14 @@ static int audit_filter_rules(struct task_struct *tsk,
                              bool task_creation)
 {
        const struct cred *cred;
-       int i, j, need_sid = 1;
+       int i, need_sid = 1;
        u32 sid;
 
        cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation);
 
        for (i = 0; i < rule->field_count; i++) {
                struct audit_field *f = &rule->fields[i];
+               struct audit_names *n;
                int result = 0;
 
                switch (f->type) {
@@ -522,12 +673,14 @@ static int audit_filter_rules(struct task_struct *tsk,
                        }
                        break;
                case AUDIT_DEVMAJOR:
-                       if (name)
-                               result = audit_comparator(MAJOR(name->dev),
-                                                         f->op, f->val);
-                       else if (ctx) {
-                               for (j = 0; j < ctx->name_count; j++) {
-                                       if (audit_comparator(MAJOR(ctx->names[j].dev),  f->op, f->val)) {
+                       if (name) {
+                               if (audit_comparator(MAJOR(name->dev), f->op, f->val) ||
+                                   audit_comparator(MAJOR(name->rdev), f->op, f->val))
+                                       ++result;
+                       } else if (ctx) {
+                               list_for_each_entry(n, &ctx->names_list, list) {
+                                       if (audit_comparator(MAJOR(n->dev), f->op, f->val) ||
+                                           audit_comparator(MAJOR(n->rdev), f->op, f->val)) {
                                                ++result;
                                                break;
                                        }
@@ -535,12 +688,14 @@ static int audit_filter_rules(struct task_struct *tsk,
                        }
                        break;
                case AUDIT_DEVMINOR:
-                       if (name)
-                               result = audit_comparator(MINOR(name->dev),
-                                                         f->op, f->val);
-                       else if (ctx) {
-                               for (j = 0; j < ctx->name_count; j++) {
-                                       if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) {
+                       if (name) {
+                               if (audit_comparator(MINOR(name->dev), f->op, f->val) ||
+                                   audit_comparator(MINOR(name->rdev), f->op, f->val))
+                                       ++result;
+                       } else if (ctx) {
+                               list_for_each_entry(n, &ctx->names_list, list) {
+                                       if (audit_comparator(MINOR(n->dev), f->op, f->val) ||
+                                           audit_comparator(MINOR(n->rdev), f->op, f->val)) {
                                                ++result;
                                                break;
                                        }
@@ -551,8 +706,32 @@ static int audit_filter_rules(struct task_struct *tsk,
                        if (name)
                                result = (name->ino == f->val);
                        else if (ctx) {
-                               for (j = 0; j < ctx->name_count; j++) {
-                                       if (audit_comparator(ctx->names[j].ino, f->op, f->val)) {
+                               list_for_each_entry(n, &ctx->names_list, list) {
+                                       if (audit_comparator(n->ino, f->op, f->val)) {
+                                               ++result;
+                                               break;
+                                       }
+                               }
+                       }
+                       break;
+               case AUDIT_OBJ_UID:
+                       if (name) {
+                               result = audit_comparator(name->uid, f->op, f->val);
+                       } else if (ctx) {
+                               list_for_each_entry(n, &ctx->names_list, list) {
+                                       if (audit_comparator(n->uid, f->op, f->val)) {
+                                               ++result;
+                                               break;
+                                       }
+                               }
+                       }
+                       break;
+               case AUDIT_OBJ_GID:
+                       if (name) {
+                               result = audit_comparator(name->gid, f->op, f->val);
+                       } else if (ctx) {
+                               list_for_each_entry(n, &ctx->names_list, list) {
+                                       if (audit_comparator(n->gid, f->op, f->val)) {
                                                ++result;
                                                break;
                                        }
@@ -607,11 +786,10 @@ static int audit_filter_rules(struct task_struct *tsk,
                                                   name->osid, f->type, f->op,
                                                   f->lsm_rule, ctx);
                                } else if (ctx) {
-                                       for (j = 0; j < ctx->name_count; j++) {
-                                               if (security_audit_rule_match(
-                                                     ctx->names[j].osid,
-                                                     f->type, f->op,
-                                                     f->lsm_rule, ctx)) {
+                                       list_for_each_entry(n, &ctx->names_list, list) {
+                                               if (security_audit_rule_match(n->osid, f->type,
+                                                                             f->op, f->lsm_rule,
+                                                                             ctx)) {
                                                        ++result;
                                                        break;
                                                }
@@ -643,8 +821,10 @@ static int audit_filter_rules(struct task_struct *tsk,
                case AUDIT_FILETYPE:
                        result = audit_match_filetype(ctx, f->val);
                        break;
+               case AUDIT_FIELD_COMPARE:
+                       result = audit_field_compare(tsk, cred, f, ctx, name);
+                       break;
                }
-
                if (!result)
                        return 0;
        }
@@ -722,40 +902,53 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
        return AUDIT_BUILD_CONTEXT;
 }
 
-/* At syscall exit time, this filter is called if any audit_names[] have been
+/*
+ * Given an audit_name check the inode hash table to see if they match.
+ * Called holding the rcu read lock to protect the use of audit_inode_hash
+ */
+static int audit_filter_inode_name(struct task_struct *tsk,
+                                  struct audit_names *n,
+                                  struct audit_context *ctx) {
+       int word, bit;
+       int h = audit_hash_ino((u32)n->ino);
+       struct list_head *list = &audit_inode_hash[h];
+       struct audit_entry *e;
+       enum audit_state state;
+
+       word = AUDIT_WORD(ctx->major);
+       bit  = AUDIT_BIT(ctx->major);
+
+       if (list_empty(list))
+               return 0;
+
+       list_for_each_entry_rcu(e, list, list) {
+               if ((e->rule.mask[word] & bit) == bit &&
+                   audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) {
+                       ctx->current_state = state;
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+/* At syscall exit time, this filter is called if any audit_names have been
  * collected during syscall processing.  We only check rules in sublists at hash
- * buckets applicable to the inode numbers in audit_names[].
+ * buckets applicable to the inode numbers in audit_names.
  * Regarding audit_state, same rules apply as for audit_filter_syscall().
  */
 void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx)
 {
-       int i;
-       struct audit_entry *e;
-       enum audit_state state;
+       struct audit_names *n;
 
        if (audit_pid && tsk->tgid == audit_pid)
                return;
 
        rcu_read_lock();
-       for (i = 0; i < ctx->name_count; i++) {
-               int word = AUDIT_WORD(ctx->major);
-               int bit  = AUDIT_BIT(ctx->major);
-               struct audit_names *n = &ctx->names[i];
-               int h = audit_hash_ino((u32)n->ino);
-               struct list_head *list = &audit_inode_hash[h];
-
-               if (list_empty(list))
-                       continue;
 
-               list_for_each_entry_rcu(e, list, list) {
-                       if ((e->rule.mask[word] & bit) == bit &&
-                           audit_filter_rules(tsk, &e->rule, ctx, n,
-                                              &state, false)) {
-                               rcu_read_unlock();
-                               ctx->current_state = state;
-                               return;
-                       }
-               }
+       list_for_each_entry(n, &ctx->names_list, list) {
+               if (audit_filter_inode_name(tsk, n, ctx))
+                       break;
        }
        rcu_read_unlock();
 }
@@ -766,7 +959,7 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
 {
        struct audit_context *context = tsk->audit_context;
 
-       if (likely(!context))
+       if (!context)
                return NULL;
        context->return_valid = return_valid;
 
@@ -799,7 +992,7 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
 
 static inline void audit_free_names(struct audit_context *context)
 {
-       int i;
+       struct audit_names *n, *next;
 
 #if AUDIT_DEBUG == 2
        if (context->put_count + context->ino_count != context->name_count) {
@@ -810,10 +1003,9 @@ static inline void audit_free_names(struct audit_context *context)
                       context->serial, context->major, context->in_syscall,
                       context->name_count, context->put_count,
                       context->ino_count);
-               for (i = 0; i < context->name_count; i++) {
+               list_for_each_entry(n, &context->names_list, list) {
                        printk(KERN_ERR "names[%d] = %p = %s\n", i,
-                              context->names[i].name,
-                              context->names[i].name ?: "(null)");
+                              n->name, n->name ?: "(null)");
                }
                dump_stack();
                return;
@@ -824,9 +1016,12 @@ static inline void audit_free_names(struct audit_context *context)
        context->ino_count  = 0;
 #endif
 
-       for (i = 0; i < context->name_count; i++) {
-               if (context->names[i].name && context->names[i].name_put)
-                       __putname(context->names[i].name);
+       list_for_each_entry_safe(n, next, &context->names_list, list) {
+               list_del(&n->list);
+               if (n->name && n->name_put)
+                       __putname(n->name);
+               if (n->should_free)
+                       kfree(n);
        }
        context->name_count = 0;
        path_put(&context->pwd);
@@ -864,6 +1059,7 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state)
                return NULL;
        audit_zero_context(context, state);
        INIT_LIST_HEAD(&context->killed_trees);
+       INIT_LIST_HEAD(&context->names_list);
        return context;
 }
 
@@ -886,7 +1082,7 @@ int audit_alloc(struct task_struct *tsk)
                return 0; /* Return if not auditing. */
 
        state = audit_filter_task(tsk, &key);
-       if (likely(state == AUDIT_DISABLED))
+       if (state == AUDIT_DISABLED)
                return 0;
 
        if (!(context = audit_alloc_context(state))) {
@@ -975,7 +1171,7 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk
                while (vma) {
                        if ((vma->vm_flags & VM_EXECUTABLE) &&
                            vma->vm_file) {
-                               audit_log_d_path(ab, "exe=",
+                               audit_log_d_path(ab, " exe=",
                                                 &vma->vm_file->f_path);
                                break;
                        }
@@ -1166,8 +1362,8 @@ static void audit_log_execve_info(struct audit_context *context,
                                  struct audit_buffer **ab,
                                  struct audit_aux_data_execve *axi)
 {
-       int i;
-       size_t len, len_sent = 0;
+       int i, len;
+       size_t len_sent = 0;
        const char __user *p;
        char *buf;
 
@@ -1324,6 +1520,68 @@ static void show_special(struct audit_context *context, int *call_panic)
        audit_log_end(ab);
 }
 
+static void audit_log_name(struct audit_context *context, struct audit_names *n,
+                          int record_num, int *call_panic)
+{
+       struct audit_buffer *ab;
+       ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
+       if (!ab)
+               return; /* audit_panic has been called */
+
+       audit_log_format(ab, "item=%d", record_num);
+
+       if (n->name) {
+               switch (n->name_len) {
+               case AUDIT_NAME_FULL:
+                       /* log the full path */
+                       audit_log_format(ab, " name=");
+                       audit_log_untrustedstring(ab, n->name);
+                       break;
+               case 0:
+                       /* name was specified as a relative path and the
+                        * directory component is the cwd */
+                       audit_log_d_path(ab, " name=", &context->pwd);
+                       break;
+               default:
+                       /* log the name's directory component */
+                       audit_log_format(ab, " name=");
+                       audit_log_n_untrustedstring(ab, n->name,
+                                                   n->name_len);
+               }
+       } else
+               audit_log_format(ab, " name=(null)");
+
+       if (n->ino != (unsigned long)-1) {
+               audit_log_format(ab, " inode=%lu"
+                                " dev=%02x:%02x mode=%#ho"
+                                " ouid=%u ogid=%u rdev=%02x:%02x",
+                                n->ino,
+                                MAJOR(n->dev),
+                                MINOR(n->dev),
+                                n->mode,
+                                n->uid,
+                                n->gid,
+                                MAJOR(n->rdev),
+                                MINOR(n->rdev));
+       }
+       if (n->osid != 0) {
+               char *ctx = NULL;
+               u32 len;
+               if (security_secid_to_secctx(
+                       n->osid, &ctx, &len)) {
+                       audit_log_format(ab, " osid=%u", n->osid);
+                       *call_panic = 2;
+               } else {
+                       audit_log_format(ab, " obj=%s", ctx);
+                       security_release_secctx(ctx, len);
+               }
+       }
+
+       audit_log_fcaps(ab, n);
+
+       audit_log_end(ab);
+}
+
 static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
 {
        const struct cred *cred;
@@ -1331,6 +1589,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
        struct audit_buffer *ab;
        struct audit_aux_data *aux;
        const char *tty;
+       struct audit_names *n;
 
        /* tsk == current */
        context->pid = tsk->pid;
@@ -1466,70 +1725,14 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
        if (context->pwd.dentry && context->pwd.mnt) {
                ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD);
                if (ab) {
-                       audit_log_d_path(ab, "cwd=", &context->pwd);
+                       audit_log_d_path(ab, " cwd=", &context->pwd);
                        audit_log_end(ab);
                }
        }
-       for (i = 0; i < context->name_count; i++) {
-               struct audit_names *n = &context->names[i];
 
-               ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
-               if (!ab)
-                       continue; /* audit_panic has been called */
-
-               audit_log_format(ab, "item=%d", i);
-
-               if (n->name) {
-                       switch(n->name_len) {
-                       case AUDIT_NAME_FULL:
-                               /* log the full path */
-                               audit_log_format(ab, " name=");
-                               audit_log_untrustedstring(ab, n->name);
-                               break;
-                       case 0:
-                               /* name was specified as a relative path and the
-                                * directory component is the cwd */
-                               audit_log_d_path(ab, "name=", &context->pwd);
-                               break;
-                       default:
-                               /* log the name's directory component */
-                               audit_log_format(ab, " name=");
-                               audit_log_n_untrustedstring(ab, n->name,
-                                                           n->name_len);
-                       }
-               } else
-                       audit_log_format(ab, " name=(null)");
-
-               if (n->ino != (unsigned long)-1) {
-                       audit_log_format(ab, " inode=%lu"
-                                        " dev=%02x:%02x mode=%#ho"
-                                        " ouid=%u ogid=%u rdev=%02x:%02x",
-                                        n->ino,
-                                        MAJOR(n->dev),
-                                        MINOR(n->dev),
-                                        n->mode,
-                                        n->uid,
-                                        n->gid,
-                                        MAJOR(n->rdev),
-                                        MINOR(n->rdev));
-               }
-               if (n->osid != 0) {
-                       char *ctx = NULL;
-                       u32 len;
-                       if (security_secid_to_secctx(
-                               n->osid, &ctx, &len)) {
-                               audit_log_format(ab, " osid=%u", n->osid);
-                               call_panic = 2;
-                       } else {
-                               audit_log_format(ab, " obj=%s", ctx);
-                               security_release_secctx(ctx, len);
-                       }
-               }
-
-               audit_log_fcaps(ab, n);
-
-               audit_log_end(ab);
-       }
+       i = 0;
+       list_for_each_entry(n, &context->names_list, list)
+               audit_log_name(context, n, i++, &call_panic);
 
        /* Send end of event record to help user space know we are finished */
        ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
@@ -1545,12 +1748,12 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
  *
  * Called from copy_process and do_exit
  */
-void audit_free(struct task_struct *tsk)
+void __audit_free(struct task_struct *tsk)
 {
        struct audit_context *context;
 
        context = audit_get_context(tsk, 0, 0);
-       if (likely(!context))
+       if (!context)
                return;
 
        /* Check for system calls that do not go through the exit
@@ -1583,7 +1786,7 @@ void audit_free(struct task_struct *tsk)
  * will only be written if another part of the kernel requests that it
  * be written).
  */
-void audit_syscall_entry(int arch, int major,
+void __audit_syscall_entry(int arch, int major,
                         unsigned long a1, unsigned long a2,
                         unsigned long a3, unsigned long a4)
 {
@@ -1591,7 +1794,7 @@ void audit_syscall_entry(int arch, int major,
        struct audit_context *context = tsk->audit_context;
        enum audit_state     state;
 
-       if (unlikely(!context))
+       if (!context)
                return;
 
        /*
@@ -1648,7 +1851,7 @@ void audit_syscall_entry(int arch, int major,
                context->prio = 0;
                state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]);
        }
-       if (likely(state == AUDIT_DISABLED))
+       if (state == AUDIT_DISABLED)
                return;
 
        context->serial     = 0;
@@ -1658,30 +1861,9 @@ void audit_syscall_entry(int arch, int major,
        context->ppid       = 0;
 }
 
-void audit_finish_fork(struct task_struct *child)
-{
-       struct audit_context *ctx = current->audit_context;
-       struct audit_context *p = child->audit_context;
-       if (!p || !ctx)
-               return;
-       if (!ctx->in_syscall || ctx->current_state != AUDIT_RECORD_CONTEXT)
-               return;
-       p->arch = ctx->arch;
-       p->major = ctx->major;
-       memcpy(p->argv, ctx->argv, sizeof(ctx->argv));
-       p->ctime = ctx->ctime;
-       p->dummy = ctx->dummy;
-       p->in_syscall = ctx->in_syscall;
-       p->filterkey = kstrdup(ctx->filterkey, GFP_KERNEL);
-       p->ppid = current->pid;
-       p->prio = ctx->prio;
-       p->current_state = ctx->current_state;
-}
-
 /**
  * audit_syscall_exit - deallocate audit context after a system call
- * @valid: success/failure flag
- * @return_code: syscall return value
+ * @pt_regs: syscall registers
  *
  * Tear down after system call.  If the audit context has been marked as
  * auditable (either because of the AUDIT_RECORD_CONTEXT state from
@@ -1689,14 +1871,18 @@ void audit_finish_fork(struct task_struct *child)
  * message), then write out the syscall information.  In call cases,
  * free the names stored from getname().
  */
-void audit_syscall_exit(int valid, long return_code)
+void __audit_syscall_exit(int success, long return_code)
 {
        struct task_struct *tsk = current;
        struct audit_context *context;
 
-       context = audit_get_context(tsk, valid, return_code);
+       if (success)
+               success = AUDITSC_SUCCESS;
+       else
+               success = AUDITSC_FAILURE;
 
-       if (likely(!context))
+       context = audit_get_context(tsk, success, return_code);
+       if (!context)
                return;
 
        if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT)
@@ -1821,6 +2007,30 @@ retry:
 #endif
 }
 
+static struct audit_names *audit_alloc_name(struct audit_context *context)
+{
+       struct audit_names *aname;
+
+       if (context->name_count < AUDIT_NAMES) {
+               aname = &context->preallocated_names[context->name_count];
+               memset(aname, 0, sizeof(*aname));
+       } else {
+               aname = kzalloc(sizeof(*aname), GFP_NOFS);
+               if (!aname)
+                       return NULL;
+               aname->should_free = true;
+       }
+
+       aname->ino = (unsigned long)-1;
+       list_add_tail(&aname->list, &context->names_list);
+
+       context->name_count++;
+#if AUDIT_DEBUG
+       context->ino_count++;
+#endif
+       return aname;
+}
+
 /**
  * audit_getname - add a name to the list
  * @name: name to add
@@ -1831,9 +2041,7 @@ retry:
 void __audit_getname(const char *name)
 {
        struct audit_context *context = current->audit_context;
-
-       if (IS_ERR(name) || !name)
-               return;
+       struct audit_names *n;
 
        if (!context->in_syscall) {
 #if AUDIT_DEBUG == 2
@@ -1843,13 +2051,15 @@ void __audit_getname(const char *name)
 #endif
                return;
        }
-       BUG_ON(context->name_count >= AUDIT_NAMES);
-       context->names[context->name_count].name = name;
-       context->names[context->name_count].name_len = AUDIT_NAME_FULL;
-       context->names[context->name_count].name_put = 1;
-       context->names[context->name_count].ino  = (unsigned long)-1;
-       context->names[context->name_count].osid = 0;
-       ++context->name_count;
+
+       n = audit_alloc_name(context);
+       if (!n)
+               return;
+
+       n->name = name;
+       n->name_len = AUDIT_NAME_FULL;
+       n->name_put = true;
+
        if (!context->pwd.dentry)
                get_fs_pwd(current->fs, &context->pwd);
 }
@@ -1871,12 +2081,13 @@ void audit_putname(const char *name)
                printk(KERN_ERR "%s:%d(:%d): __putname(%p)\n",
                       __FILE__, __LINE__, context->serial, name);
                if (context->name_count) {
+                       struct audit_names *n;
                        int i;
-                       for (i = 0; i < context->name_count; i++)
+
+                       list_for_each_entry(n, &context->names_list, list)
                                printk(KERN_ERR "name[%d] = %p = %s\n", i,
-                                      context->names[i].name,
-                                      context->names[i].name ?: "(null)");
-               }
+                                      n->name, n->name ?: "(null)");
+                       }
 #endif
                __putname(name);
        }
@@ -1897,39 +2108,11 @@ void audit_putname(const char *name)
 #endif
 }
 
-static int audit_inc_name_count(struct audit_context *context,
-                               const struct inode *inode)
-{
-       if (context->name_count >= AUDIT_NAMES) {
-               if (inode)
-                       printk(KERN_DEBUG "audit: name_count maxed, losing inode data: "
-                              "dev=%02x:%02x, inode=%lu\n",
-                              MAJOR(inode->i_sb->s_dev),
-                              MINOR(inode->i_sb->s_dev),
-                              inode->i_ino);
-
-               else
-                       printk(KERN_DEBUG "name_count maxed, losing inode data\n");
-               return 1;
-       }
-       context->name_count++;
-#if AUDIT_DEBUG
-       context->ino_count++;
-#endif
-       return 0;
-}
-
-
 static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry)
 {
        struct cpu_vfs_cap_data caps;
        int rc;
 
-       memset(&name->fcap.permitted, 0, sizeof(kernel_cap_t));
-       memset(&name->fcap.inheritable, 0, sizeof(kernel_cap_t));
-       name->fcap.fE = 0;
-       name->fcap_ver = 0;
-
        if (!dentry)
                return 0;
 
@@ -1969,30 +2152,25 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent
  */
 void __audit_inode(const char *name, const struct dentry *dentry)
 {
-       int idx;
        struct audit_context *context = current->audit_context;
        const struct inode *inode = dentry->d_inode;
+       struct audit_names *n;
 
        if (!context->in_syscall)
                return;
-       if (context->name_count
-           && context->names[context->name_count-1].name
-           && context->names[context->name_count-1].name == name)
-               idx = context->name_count - 1;
-       else if (context->name_count > 1
-                && context->names[context->name_count-2].name
-                && context->names[context->name_count-2].name == name)
-               idx = context->name_count - 2;
-       else {
-               /* FIXME: how much do we care about inodes that have no
-                * associated name? */
-               if (audit_inc_name_count(context, inode))
-                       return;
-               idx = context->name_count - 1;
-               context->names[idx].name = NULL;
+
+       list_for_each_entry_reverse(n, &context->names_list, list) {
+               if (n->name && (n->name == name))
+                       goto out;
        }
+
+       /* unable to find the name from a previous getname() */
+       n = audit_alloc_name(context);
+       if (!n)
+               return;
+out:
        handle_path(dentry);
-       audit_copy_inode(&context->names[idx], dentry, inode);
+       audit_copy_inode(n, dentry, inode);
 }
 
 /**
@@ -2011,11 +2189,11 @@ void __audit_inode(const char *name, const struct dentry *dentry)
 void __audit_inode_child(const struct dentry *dentry,
                         const struct inode *parent)
 {
-       int idx;
        struct audit_context *context = current->audit_context;
        const char *found_parent = NULL, *found_child = NULL;
        const struct inode *inode = dentry->d_inode;
        const char *dname = dentry->d_name.name;
+       struct audit_names *n;
        int dirlen = 0;
 
        if (!context->in_syscall)
@@ -2025,9 +2203,7 @@ void __audit_inode_child(const struct dentry *dentry,
                handle_one(inode);
 
        /* parent is more likely, look for it first */
-       for (idx = 0; idx < context->name_count; idx++) {
-               struct audit_names *n = &context->names[idx];
-
+       list_for_each_entry(n, &context->names_list, list) {
                if (!n->name)
                        continue;
 
@@ -2040,9 +2216,7 @@ void __audit_inode_child(const struct dentry *dentry,
        }
 
        /* no matching parent, look for matching child */
-       for (idx = 0; idx < context->name_count; idx++) {
-               struct audit_names *n = &context->names[idx];
-
+       list_for_each_entry(n, &context->names_list, list) {
                if (!n->name)
                        continue;
 
@@ -2060,34 +2234,29 @@ void __audit_inode_child(const struct dentry *dentry,
 
 add_names:
        if (!found_parent) {
-               if (audit_inc_name_count(context, parent))
+               n = audit_alloc_name(context);
+               if (!n)
                        return;
-               idx = context->name_count - 1;
-               context->names[idx].name = NULL;
-               audit_copy_inode(&context->names[idx], NULL, parent);
+               audit_copy_inode(n, NULL, parent);
        }
 
        if (!found_child) {
-               if (audit_inc_name_count(context, inode))
+               n = audit_alloc_name(context);
+               if (!n)
                        return;
-               idx = context->name_count - 1;
 
                /* Re-use the name belonging to the slot for a matching parent
                 * directory. All names for this context are relinquished in
                 * audit_free_names() */
                if (found_parent) {
-                       context->names[idx].name = found_parent;
-                       context->names[idx].name_len = AUDIT_NAME_FULL;
+                       n->name = found_parent;
+                       n->name_len = AUDIT_NAME_FULL;
                        /* don't call __putname() */
-                       context->names[idx].name_put = 0;
-               } else {
-                       context->names[idx].name = NULL;
+                       n->name_put = false;
                }
 
                if (inode)
-                       audit_copy_inode(&context->names[idx], NULL, inode);
-               else
-                       context->names[idx].ino = (unsigned long)-1;
+                       audit_copy_inode(n, NULL, inode);
        }
 }
 EXPORT_SYMBOL_GPL(__audit_inode_child);
@@ -2121,19 +2290,28 @@ int auditsc_get_stamp(struct audit_context *ctx,
 static atomic_t session_id = ATOMIC_INIT(0);
 
 /**
- * audit_set_loginuid - set a task's audit_context loginuid
- * @task: task whose audit context is being modified
+ * audit_set_loginuid - set current task's audit_context loginuid
  * @loginuid: loginuid value
  *
  * Returns 0.
  *
  * Called (set) from fs/proc/base.c::proc_loginuid_write().
  */
-int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
+int audit_set_loginuid(uid_t loginuid)
 {
-       unsigned int sessionid = atomic_inc_return(&session_id);
+       struct task_struct *task = current;
        struct audit_context *context = task->audit_context;
+       unsigned int sessionid;
+
+#ifdef CONFIG_AUDIT_LOGINUID_IMMUTABLE
+       if (task->loginuid != -1)
+               return -EPERM;
+#else /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */
+       if (!capable(CAP_AUDIT_CONTROL))
+               return -EPERM;
+#endif  /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */
 
+       sessionid = atomic_inc_return(&session_id);
        if (context && context->in_syscall) {
                struct audit_buffer *ab;
 
@@ -2271,14 +2449,11 @@ void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mo
        context->ipc.has_perm = 1;
 }
 
-int audit_bprm(struct linux_binprm *bprm)
+int __audit_bprm(struct linux_binprm *bprm)
 {
        struct audit_aux_data_execve *ax;
        struct audit_context *context = current->audit_context;
 
-       if (likely(!audit_enabled || !context || context->dummy))
-               return 0;
-
        ax = kmalloc(sizeof(*ax), GFP_KERNEL);
        if (!ax)
                return -ENOMEM;
@@ -2299,13 +2474,10 @@ int audit_bprm(struct linux_binprm *bprm)
  * @args: args array
  *
  */
-void audit_socketcall(int nargs, unsigned long *args)
+void __audit_socketcall(int nargs, unsigned long *args)
 {
        struct audit_context *context = current->audit_context;
 
-       if (likely(!context || context->dummy))
-               return;
-
        context->type = AUDIT_SOCKETCALL;
        context->socketcall.nargs = nargs;
        memcpy(context->socketcall.args, args, nargs * sizeof(unsigned long));
@@ -2331,13 +2503,10 @@ void __audit_fd_pair(int fd1, int fd2)
  *
  * Returns 0 for success or NULL context or < 0 on error.
  */
-int audit_sockaddr(int len, void *a)
+int __audit_sockaddr(int len, void *a)
 {
        struct audit_context *context = current->audit_context;
 
-       if (likely(!context || context->dummy))
-               return 0;
-
        if (!context->sockaddr) {
                void *p = kmalloc(sizeof(struct sockaddr_storage), GFP_KERNEL);
                if (!p)
@@ -2499,6 +2668,25 @@ void __audit_mmap_fd(int fd, int flags)
        context->type = AUDIT_MMAP;
 }
 
+static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr)
+{
+       uid_t auid, uid;
+       gid_t gid;
+       unsigned int sessionid;
+
+       auid = audit_get_loginuid(current);
+       sessionid = audit_get_sessionid(current);
+       current_uid_gid(&uid, &gid);
+
+       audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
+                        auid, uid, gid, sessionid);
+       audit_log_task_context(ab);
+       audit_log_format(ab, " pid=%d comm=", current->pid);
+       audit_log_untrustedstring(ab, current->comm);
+       audit_log_format(ab, " reason=");
+       audit_log_string(ab, reason);
+       audit_log_format(ab, " sig=%ld", signr);
+}
 /**
  * audit_core_dumps - record information about processes that end abnormally
  * @signr: signal value
@@ -2509,10 +2697,6 @@ void __audit_mmap_fd(int fd, int flags)
 void audit_core_dumps(long signr)
 {
        struct audit_buffer *ab;
-       u32 sid;
-       uid_t auid = audit_get_loginuid(current), uid;
-       gid_t gid;
-       unsigned int sessionid = audit_get_sessionid(current);
 
        if (!audit_enabled)
                return;
@@ -2521,24 +2705,17 @@ void audit_core_dumps(long signr)
                return;
 
        ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
-       current_uid_gid(&uid, &gid);
-       audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
-                        auid, uid, gid, sessionid);
-       security_task_getsecid(current, &sid);
-       if (sid) {
-               char *ctx = NULL;
-               u32 len;
+       audit_log_abend(ab, "memory violation", signr);
+       audit_log_end(ab);
+}
 
-               if (security_secid_to_secctx(sid, &ctx, &len))
-                       audit_log_format(ab, " ssid=%u", sid);
-               else {
-                       audit_log_format(ab, " subj=%s", ctx);
-                       security_release_secctx(ctx, len);
-               }
-       }
-       audit_log_format(ab, " pid=%d comm=", current->pid);
-       audit_log_untrustedstring(ab, current->comm);
-       audit_log_format(ab, " sig=%ld", signr);
+void __audit_seccomp(unsigned long syscall)
+{
+       struct audit_buffer *ab;
+
+       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
+       audit_log_abend(ab, "seccomp", SIGKILL);
+       audit_log_format(ab, " syscall=%ld", syscall);
        audit_log_end(ab);
 }
 
index b463871a4e695448d8ec3246e6347e917ae5ac88..3f1adb6c647015d80aa6b5b138f118fde7484d11 100644 (file)
@@ -287,74 +287,84 @@ error:
 }
 
 /**
- * has_capability - Does a task have a capability in init_user_ns
+ * has_ns_capability - Does a task have a capability in a specific user ns
  * @t: The task in question
+ * @ns: target user namespace
  * @cap: The capability to be tested for
  *
  * Return true if the specified task has the given superior capability
- * currently in effect to the initial user namespace, false if not.
+ * currently in effect to the specified user namespace, false if not.
  *
  * Note that this does not set PF_SUPERPRIV on the task.
  */
-bool has_capability(struct task_struct *t, int cap)
+bool has_ns_capability(struct task_struct *t,
+                      struct user_namespace *ns, int cap)
 {
-       int ret = security_real_capable(t, &init_user_ns, cap);
+       int ret;
+
+       rcu_read_lock();
+       ret = security_capable(__task_cred(t), ns, cap);
+       rcu_read_unlock();
 
        return (ret == 0);
 }
 
 /**
- * has_capability - Does a task have a capability in a specific user ns
+ * has_capability - Does a task have a capability in init_user_ns
  * @t: The task in question
- * @ns: target user namespace
  * @cap: The capability to be tested for
  *
  * Return true if the specified task has the given superior capability
- * currently in effect to the specified user namespace, false if not.
+ * currently in effect to the initial user namespace, false if not.
  *
  * Note that this does not set PF_SUPERPRIV on the task.
  */
-bool has_ns_capability(struct task_struct *t,
-                      struct user_namespace *ns, int cap)
+bool has_capability(struct task_struct *t, int cap)
 {
-       int ret = security_real_capable(t, ns, cap);
-
-       return (ret == 0);
+       return has_ns_capability(t, &init_user_ns, cap);
 }
 
 /**
- * has_capability_noaudit - Does a task have a capability (unaudited)
+ * has_ns_capability_noaudit - Does a task have a capability (unaudited)
+ * in a specific user ns.
  * @t: The task in question
+ * @ns: target user namespace
  * @cap: The capability to be tested for
  *
  * Return true if the specified task has the given superior capability
- * currently in effect to init_user_ns, false if not.  Don't write an
- * audit message for the check.
+ * currently in effect to the specified user namespace, false if not.
+ * Do not write an audit message for the check.
  *
  * Note that this does not set PF_SUPERPRIV on the task.
  */
-bool has_capability_noaudit(struct task_struct *t, int cap)
+bool has_ns_capability_noaudit(struct task_struct *t,
+                              struct user_namespace *ns, int cap)
 {
-       int ret = security_real_capable_noaudit(t, &init_user_ns, cap);
+       int ret;
+
+       rcu_read_lock();
+       ret = security_capable_noaudit(__task_cred(t), ns, cap);
+       rcu_read_unlock();
 
        return (ret == 0);
 }
 
 /**
- * capable - Determine if the current task has a superior capability in effect
+ * has_capability_noaudit - Does a task have a capability (unaudited) in the
+ * initial user ns
+ * @t: The task in question
  * @cap: The capability to be tested for
  *
- * Return true if the current task has the given superior capability currently
- * available for use, false if not.
+ * Return true if the specified task has the given superior capability
+ * currently in effect to init_user_ns, false if not.  Don't write an
+ * audit message for the check.
  *
- * This sets PF_SUPERPRIV on the task if the capability is available on the
- * assumption that it's about to be used.
+ * Note that this does not set PF_SUPERPRIV on the task.
  */
-bool capable(int cap)
+bool has_capability_noaudit(struct task_struct *t, int cap)
 {
-       return ns_capable(&init_user_ns, cap);
+       return has_ns_capability_noaudit(t, &init_user_ns, cap);
 }
-EXPORT_SYMBOL(capable);
 
 /**
  * ns_capable - Determine if the current task has a superior capability in effect
@@ -374,7 +384,7 @@ bool ns_capable(struct user_namespace *ns, int cap)
                BUG();
        }
 
-       if (security_capable(ns, current_cred(), cap) == 0) {
+       if (security_capable(current_cred(), ns, cap) == 0) {
                current->flags |= PF_SUPERPRIV;
                return true;
        }
@@ -383,18 +393,20 @@ bool ns_capable(struct user_namespace *ns, int cap)
 EXPORT_SYMBOL(ns_capable);
 
 /**
- * task_ns_capable - Determine whether current task has a superior
- * capability targeted at a specific task's user namespace.
- * @t: The task whose user namespace is targeted.
- * @cap: The capability in question.
+ * capable - Determine if the current task has a superior capability in effect
+ * @cap: The capability to be tested for
+ *
+ * Return true if the current task has the given superior capability currently
+ * available for use, false if not.
  *
- *  Return true if it does, false otherwise.
+ * This sets PF_SUPERPRIV on the task if the capability is available on the
+ * assumption that it's about to be used.
  */
-bool task_ns_capable(struct task_struct *t, int cap)
+bool capable(int cap)
 {
-       return ns_capable(task_cred_xxx(t, user)->user_ns, cap);
+       return ns_capable(&init_user_ns, cap);
 }
-EXPORT_SYMBOL(task_ns_capable);
+EXPORT_SYMBOL(capable);
 
 /**
  * nsown_capable - Check superior capability to one's own user_ns
index 63786e71a3cd9e1003a7a2bb6f399170f773756d..e2ae7349437f2b1a36879be0ca713b9ea4e8948b 100644 (file)
@@ -1982,7 +1982,7 @@ static int kdb_lsmod(int argc, const char **argv)
                kdb_printf("%-20s%8u  0x%p ", mod->name,
                           mod->core_size, (void *)mod);
 #ifdef CONFIG_MODULE_UNLOAD
-               kdb_printf("%4d ", module_refcount(mod));
+               kdb_printf("%4ld ", module_refcount(mod));
 #endif
                if (mod->state == MODULE_STATE_GOING)
                        kdb_printf(" (Unloading)");
index 94ed6e20bb532840e69070f3d623568e17cbe0c1..294b1709170d1e890c80d064c65d38c1b12a88c1 100644 (file)
@@ -887,7 +887,7 @@ static void check_stack_usage(void)
 static inline void check_stack_usage(void) {}
 #endif
 
-NORET_TYPE void do_exit(long code)
+void do_exit(long code)
 {
        struct task_struct *tsk = current;
        int group_dead;
@@ -964,8 +964,7 @@ NORET_TYPE void do_exit(long code)
        acct_collect(code, group_dead);
        if (group_dead)
                tty_audit_exit();
-       if (unlikely(tsk->audit_context))
-               audit_free(tsk);
+       audit_free(tsk);
 
        tsk->exit_code = code;
        taskstats_exit(tsk, group_dead);
@@ -1051,7 +1050,7 @@ NORET_TYPE void do_exit(long code)
 
 EXPORT_SYMBOL_GPL(do_exit);
 
-NORET_TYPE void complete_and_exit(struct completion *comp, long code)
+void complete_and_exit(struct completion *comp, long code)
 {
        if (comp)
                complete(comp);
@@ -1070,7 +1069,7 @@ SYSCALL_DEFINE1(exit, int, error_code)
  * Take down every thread in the group.  This is called by fatal signals
  * as well as by sys_exit_group (below).
  */
-NORET_TYPE void
+void
 do_group_exit(int exit_code)
 {
        struct signal_struct *sig = current->signal;
index 443f5125f11e39435929072e3abbd19d7a408ea9..051f090d40c1230462d4b4d53c05133879805f08 100644 (file)
@@ -873,6 +873,7 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk)
 {
 #ifdef CONFIG_BLOCK
        struct io_context *ioc = current->io_context;
+       struct io_context *new_ioc;
 
        if (!ioc)
                return 0;
@@ -884,11 +885,12 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk)
                if (unlikely(!tsk->io_context))
                        return -ENOMEM;
        } else if (ioprio_valid(ioc->ioprio)) {
-               tsk->io_context = alloc_io_context(GFP_KERNEL, -1);
-               if (unlikely(!tsk->io_context))
+               new_ioc = get_task_io_context(tsk, GFP_KERNEL, NUMA_NO_NODE);
+               if (unlikely(!new_ioc))
                        return -ENOMEM;
 
-               tsk->io_context->ioprio = ioc->ioprio;
+               new_ioc->ioprio = ioc->ioprio;
+               put_io_context(new_ioc, NULL);
        }
 #endif
        return 0;
@@ -1525,8 +1527,6 @@ long do_fork(unsigned long clone_flags,
                        init_completion(&vfork);
                }
 
-               audit_finish_fork(p);
-
                /*
                 * We set PF_STARTING at creation in case tracing wants to
                 * use this to distinguish a fully live task from one that
index a73dd6c7372da3f1d33ccdd0460ee72e667b534e..b7952316016aa8175b6149856ed57eba230007eb 100644 (file)
@@ -15,7 +15,7 @@
 
 #define istate core_internal_state__do_not_mess_with_it
 
-extern int noirqdebug;
+extern bool noirqdebug;
 
 /*
  * Bits used by threaded handlers:
index dc813a948be2379fe20a0218e1d270212b8408d3..611cd6003c453951d82e12d6d03a044f7f285275 100644 (file)
@@ -325,7 +325,7 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
        desc->irqs_unhandled = 0;
 }
 
-int noirqdebug __read_mostly;
+bool noirqdebug __read_mostly;
 
 int noirqdebug_setup(char *str)
 {
index 090ee10d960485c6b9ed1923ef66c467c6fa19ea..7b0886786701b845cfbd8823252392e40b11a1c8 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/console.h>
 #include <linux/vmalloc.h>
 #include <linux/swap.h>
-#include <linux/kmsg_dump.h>
 #include <linux/syscore_ops.h>
 
 #include <asm/page.h>
@@ -1094,8 +1093,6 @@ void crash_kexec(struct pt_regs *regs)
                if (kexec_crash_image) {
                        struct pt_regs fixed_regs;
 
-                       kmsg_dump(KMSG_DUMP_KEXEC);
-
                        crash_setup_regs(&fixed_regs, regs);
                        crash_save_vmcoreinfo();
                        machine_crash_shutdown(&fixed_regs);
@@ -1132,6 +1129,8 @@ int crash_shrink_memory(unsigned long new_size)
 {
        int ret = 0;
        unsigned long start, end;
+       unsigned long old_size;
+       struct resource *ram_res;
 
        mutex_lock(&kexec_mutex);
 
@@ -1141,11 +1140,15 @@ int crash_shrink_memory(unsigned long new_size)
        }
        start = crashk_res.start;
        end = crashk_res.end;
+       old_size = (end == 0) ? 0 : end - start + 1;
+       if (new_size >= old_size) {
+               ret = (new_size == old_size) ? 0 : -EINVAL;
+               goto unlock;
+       }
 
-       if (new_size >= end - start + 1) {
-               ret = -EINVAL;
-               if (new_size == end - start + 1)
-                       ret = 0;
+       ram_res = kzalloc(sizeof(*ram_res), GFP_KERNEL);
+       if (!ram_res) {
+               ret = -ENOMEM;
                goto unlock;
        }
 
@@ -1157,7 +1160,15 @@ int crash_shrink_memory(unsigned long new_size)
 
        if ((start == end) && (crashk_res.parent != NULL))
                release_resource(&crashk_res);
+
+       ram_res->start = end;
+       ram_res->end = crashk_res.end;
+       ram_res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+       ram_res->name = "System RAM";
+
        crashk_res.end = end - 1;
+
+       insert_resource(&iomem_resource, ram_res);
        crash_unmap_reserved_pages();
 
 unlock:
index e5d84644823b4094a4e6c629985daddd753bdd19..95dd7212e610b5a3da4ce97997a88f5c67d89b2d 100644 (file)
@@ -2198,7 +2198,7 @@ static ssize_t write_enabled_file_bool(struct file *file,
               const char __user *user_buf, size_t count, loff_t *ppos)
 {
        char buf[32];
-       int buf_size;
+       size_t buf_size;
 
        buf_size = min(count, (sizeof(buf)-1));
        if (copy_from_user(buf, user_buf, buf_size))
index 178333c48d1e5a60bfac3f3bef928452dd09aca2..2c932760fd33d152016e62431cba5c986f65957f 100644 (file)
 #define CREATE_TRACE_POINTS
 #include <trace/events/module.h>
 
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(fmt , a...)
-#endif
-
 #ifndef ARCH_SHF_SMALL
 #define ARCH_SHF_SMALL 0
 #endif
@@ -138,7 +132,6 @@ struct load_info {
        unsigned long len;
        Elf_Shdr *sechdrs;
        char *secstrings, *strtab;
-       unsigned long *strmap;
        unsigned long symoffs, stroffs;
        struct _ddebug *debug;
        unsigned int num_debug;
@@ -410,7 +403,7 @@ const struct kernel_symbol *find_symbol(const char *name,
                return fsa.sym;
        }
 
-       DEBUGP("Failed to find symbol %s\n", name);
+       pr_debug("Failed to find symbol %s\n", name);
        return NULL;
 }
 EXPORT_SYMBOL_GPL(find_symbol);
@@ -600,11 +593,11 @@ static int already_uses(struct module *a, struct module *b)
 
        list_for_each_entry(use, &b->source_list, source_list) {
                if (use->source == a) {
-                       DEBUGP("%s uses %s!\n", a->name, b->name);
+                       pr_debug("%s uses %s!\n", a->name, b->name);
                        return 1;
                }
        }
-       DEBUGP("%s does not use %s!\n", a->name, b->name);
+       pr_debug("%s does not use %s!\n", a->name, b->name);
        return 0;
 }
 
@@ -619,7 +612,7 @@ static int add_module_usage(struct module *a, struct module *b)
 {
        struct module_use *use;
 
-       DEBUGP("Allocating new usage for %s.\n", a->name);
+       pr_debug("Allocating new usage for %s.\n", a->name);
        use = kmalloc(sizeof(*use), GFP_ATOMIC);
        if (!use) {
                printk(KERN_WARNING "%s: out of memory loading\n", a->name);
@@ -663,7 +656,7 @@ static void module_unload_free(struct module *mod)
        mutex_lock(&module_mutex);
        list_for_each_entry_safe(use, tmp, &mod->target_list, target_list) {
                struct module *i = use->target;
-               DEBUGP("%s unusing %s\n", mod->name, i->name);
+               pr_debug("%s unusing %s\n", mod->name, i->name);
                module_put(i);
                list_del(&use->source_list);
                list_del(&use->target_list);
@@ -726,9 +719,9 @@ static int try_stop_module(struct module *mod, int flags, int *forced)
        }
 }
 
-unsigned int module_refcount(struct module *mod)
+unsigned long module_refcount(struct module *mod)
 {
-       unsigned int incs = 0, decs = 0;
+       unsigned long incs = 0, decs = 0;
        int cpu;
 
        for_each_possible_cpu(cpu)
@@ -761,7 +754,7 @@ static void wait_for_zero_refcount(struct module *mod)
        /* Since we might sleep for some time, release the mutex first */
        mutex_unlock(&module_mutex);
        for (;;) {
-               DEBUGP("Looking at refcount...\n");
+               pr_debug("Looking at refcount...\n");
                set_current_state(TASK_UNINTERRUPTIBLE);
                if (module_refcount(mod) == 0)
                        break;
@@ -804,7 +797,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
        if (mod->state != MODULE_STATE_LIVE) {
                /* FIXME: if (force), slam module count and wake up
                    waiter --RR */
-               DEBUGP("%s already dying\n", mod->name);
+               pr_debug("%s already dying\n", mod->name);
                ret = -EBUSY;
                goto out;
        }
@@ -854,7 +847,7 @@ static inline void print_unload_info(struct seq_file *m, struct module *mod)
        struct module_use *use;
        int printed_something = 0;
 
-       seq_printf(m, " %u ", module_refcount(mod));
+       seq_printf(m, " %lu ", module_refcount(mod));
 
        /* Always include a trailing , so userspace can differentiate
            between this and the old multi-field proc format. */
@@ -904,13 +897,11 @@ EXPORT_SYMBOL_GPL(symbol_put_addr);
 static ssize_t show_refcnt(struct module_attribute *mattr,
                           struct module_kobject *mk, char *buffer)
 {
-       return sprintf(buffer, "%u\n", module_refcount(mk->mod));
+       return sprintf(buffer, "%lu\n", module_refcount(mk->mod));
 }
 
-static struct module_attribute refcnt = {
-       .attr = { .name = "refcnt", .mode = 0444 },
-       .show = show_refcnt,
-};
+static struct module_attribute modinfo_refcnt =
+       __ATTR(refcnt, 0444, show_refcnt, NULL);
 
 void module_put(struct module *module)
 {
@@ -951,6 +942,26 @@ static inline int module_unload_init(struct module *mod)
 }
 #endif /* CONFIG_MODULE_UNLOAD */
 
+static size_t module_flags_taint(struct module *mod, char *buf)
+{
+       size_t l = 0;
+
+       if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE))
+               buf[l++] = 'P';
+       if (mod->taints & (1 << TAINT_OOT_MODULE))
+               buf[l++] = 'O';
+       if (mod->taints & (1 << TAINT_FORCED_MODULE))
+               buf[l++] = 'F';
+       if (mod->taints & (1 << TAINT_CRAP))
+               buf[l++] = 'C';
+       /*
+        * TAINT_FORCED_RMMOD: could be added.
+        * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
+        * apply to modules.
+        */
+       return l;
+}
+
 static ssize_t show_initstate(struct module_attribute *mattr,
                              struct module_kobject *mk, char *buffer)
 {
@@ -970,10 +981,8 @@ static ssize_t show_initstate(struct module_attribute *mattr,
        return sprintf(buffer, "%s\n", state);
 }
 
-static struct module_attribute initstate = {
-       .attr = { .name = "initstate", .mode = 0444 },
-       .show = show_initstate,
-};
+static struct module_attribute modinfo_initstate =
+       __ATTR(initstate, 0444, show_initstate, NULL);
 
 static ssize_t store_uevent(struct module_attribute *mattr,
                            struct module_kobject *mk,
@@ -986,18 +995,50 @@ static ssize_t store_uevent(struct module_attribute *mattr,
        return count;
 }
 
-struct module_attribute module_uevent = {
-       .attr = { .name = "uevent", .mode = 0200 },
-       .store = store_uevent,
-};
+struct module_attribute module_uevent =
+       __ATTR(uevent, 0200, NULL, store_uevent);
+
+static ssize_t show_coresize(struct module_attribute *mattr,
+                            struct module_kobject *mk, char *buffer)
+{
+       return sprintf(buffer, "%u\n", mk->mod->core_size);
+}
+
+static struct module_attribute modinfo_coresize =
+       __ATTR(coresize, 0444, show_coresize, NULL);
+
+static ssize_t show_initsize(struct module_attribute *mattr,
+                            struct module_kobject *mk, char *buffer)
+{
+       return sprintf(buffer, "%u\n", mk->mod->init_size);
+}
+
+static struct module_attribute modinfo_initsize =
+       __ATTR(initsize, 0444, show_initsize, NULL);
+
+static ssize_t show_taint(struct module_attribute *mattr,
+                         struct module_kobject *mk, char *buffer)
+{
+       size_t l;
+
+       l = module_flags_taint(mk->mod, buffer);
+       buffer[l++] = '\n';
+       return l;
+}
+
+static struct module_attribute modinfo_taint =
+       __ATTR(taint, 0444, show_taint, NULL);
 
 static struct module_attribute *modinfo_attrs[] = {
+       &module_uevent,
        &modinfo_version,
        &modinfo_srcversion,
-       &initstate,
-       &module_uevent,
+       &modinfo_initstate,
+       &modinfo_coresize,
+       &modinfo_initsize,
+       &modinfo_taint,
 #ifdef CONFIG_MODULE_UNLOAD
-       &refcnt,
+       &modinfo_refcnt,
 #endif
        NULL,
 };
@@ -1057,7 +1098,7 @@ static int check_version(Elf_Shdr *sechdrs,
 
                if (versions[i].crc == maybe_relocated(*crc, crc_owner))
                        return 1;
-               DEBUGP("Found checksum %lX vs module %lX\n",
+               pr_debug("Found checksum %lX vs module %lX\n",
                       maybe_relocated(*crc, crc_owner), versions[i].crc);
                goto bad_version;
        }
@@ -1834,7 +1875,7 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
                case SHN_COMMON:
                        /* We compiled with -fno-common.  These are not
                           supposed to happen.  */
-                       DEBUGP("Common symbol: %s\n", name);
+                       pr_debug("Common symbol: %s\n", name);
                        printk("%s: please compile with -fno-common\n",
                               mod->name);
                        ret = -ENOEXEC;
@@ -1842,7 +1883,7 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
 
                case SHN_ABS:
                        /* Don't need to do anything */
-                       DEBUGP("Absolute symbol: 0x%08lx\n",
+                       pr_debug("Absolute symbol: 0x%08lx\n",
                               (long)sym[i].st_value);
                        break;
 
@@ -1966,7 +2007,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
        for (i = 0; i < info->hdr->e_shnum; i++)
                info->sechdrs[i].sh_entsize = ~0UL;
 
-       DEBUGP("Core section allocation order:\n");
+       pr_debug("Core section allocation order:\n");
        for (m = 0; m < ARRAY_SIZE(masks); ++m) {
                for (i = 0; i < info->hdr->e_shnum; ++i) {
                        Elf_Shdr *s = &info->sechdrs[i];
@@ -1978,7 +2019,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
                            || strstarts(sname, ".init"))
                                continue;
                        s->sh_entsize = get_offset(mod, &mod->core_size, s, i);
-                       DEBUGP("\t%s\n", name);
+                       pr_debug("\t%s\n", sname);
                }
                switch (m) {
                case 0: /* executable */
@@ -1995,7 +2036,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
                }
        }
 
-       DEBUGP("Init section allocation order:\n");
+       pr_debug("Init section allocation order:\n");
        for (m = 0; m < ARRAY_SIZE(masks); ++m) {
                for (i = 0; i < info->hdr->e_shnum; ++i) {
                        Elf_Shdr *s = &info->sechdrs[i];
@@ -2008,7 +2049,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
                                continue;
                        s->sh_entsize = (get_offset(mod, &mod->init_size, s, i)
                                         | INIT_OFFSET_MASK);
-                       DEBUGP("\t%s\n", sname);
+                       pr_debug("\t%s\n", sname);
                }
                switch (m) {
                case 0: /* executable */
@@ -2178,45 +2219,46 @@ static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
        return true;
 }
 
+/*
+ * We only allocate and copy the strings needed by the parts of symtab
+ * we keep.  This is simple, but has the effect of making multiple
+ * copies of duplicates.  We could be more sophisticated, see
+ * linux-kernel thread starting with
+ * <73defb5e4bca04a6431392cc341112b1@localhost>.
+ */
 static void layout_symtab(struct module *mod, struct load_info *info)
 {
        Elf_Shdr *symsect = info->sechdrs + info->index.sym;
        Elf_Shdr *strsect = info->sechdrs + info->index.str;
        const Elf_Sym *src;
-       unsigned int i, nsrc, ndst;
+       unsigned int i, nsrc, ndst, strtab_size;
 
        /* Put symbol section at end of init part of module. */
        symsect->sh_flags |= SHF_ALLOC;
        symsect->sh_entsize = get_offset(mod, &mod->init_size, symsect,
                                         info->index.sym) | INIT_OFFSET_MASK;
-       DEBUGP("\t%s\n", info->secstrings + symsect->sh_name);
+       pr_debug("\t%s\n", info->secstrings + symsect->sh_name);
 
        src = (void *)info->hdr + symsect->sh_offset;
        nsrc = symsect->sh_size / sizeof(*src);
-       for (ndst = i = 1; i < nsrc; ++i, ++src)
-               if (is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) {
-                       unsigned int j = src->st_name;
 
-                       while (!__test_and_set_bit(j, info->strmap)
-                              && info->strtab[j])
-                               ++j;
-                       ++ndst;
+       /* Compute total space required for the core symbols' strtab. */
+       for (ndst = i = strtab_size = 1; i < nsrc; ++i, ++src)
+               if (is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) {
+                       strtab_size += strlen(&info->strtab[src->st_name]) + 1;
+                       ndst++;
                }
 
        /* Append room for core symbols at end of core part. */
        info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
-       mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym);
+       info->stroffs = mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym);
+       mod->core_size += strtab_size;
 
        /* Put string table section at end of init part of module. */
        strsect->sh_flags |= SHF_ALLOC;
        strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
                                         info->index.str) | INIT_OFFSET_MASK;
-       DEBUGP("\t%s\n", info->secstrings + strsect->sh_name);
-
-       /* Append room for core symbols' strings at end of core part. */
-       info->stroffs = mod->core_size;
-       __set_bit(0, info->strmap);
-       mod->core_size += bitmap_weight(info->strmap, strsect->sh_size);
+       pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
 }
 
 static void add_kallsyms(struct module *mod, const struct load_info *info)
@@ -2237,22 +2279,19 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
                mod->symtab[i].st_info = elf_type(&mod->symtab[i], info);
 
        mod->core_symtab = dst = mod->module_core + info->symoffs;
+       mod->core_strtab = s = mod->module_core + info->stroffs;
        src = mod->symtab;
        *dst = *src;
+       *s++ = 0;
        for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) {
                if (!is_core_symbol(src, info->sechdrs, info->hdr->e_shnum))
                        continue;
+
                dst[ndst] = *src;
-               dst[ndst].st_name = bitmap_weight(info->strmap,
-                                                 dst[ndst].st_name);
-               ++ndst;
+               dst[ndst++].st_name = s - mod->core_strtab;
+               s += strlcpy(s, &mod->strtab[src->st_name], KSYM_NAME_LEN) + 1;
        }
        mod->core_num_syms = ndst;
-
-       mod->core_strtab = s = mod->module_core + info->stroffs;
-       for (*s = 0, i = 1; i < info->sechdrs[info->index.str].sh_size; ++i)
-               if (test_bit(i, info->strmap))
-                       *++s = mod->strtab[i];
 }
 #else
 static inline void layout_symtab(struct module *mod, struct load_info *info)
@@ -2621,7 +2660,7 @@ static int move_module(struct module *mod, struct load_info *info)
        mod->module_init = ptr;
 
        /* Transfer each section which specifies SHF_ALLOC */
-       DEBUGP("final section addresses:\n");
+       pr_debug("final section addresses:\n");
        for (i = 0; i < info->hdr->e_shnum; i++) {
                void *dest;
                Elf_Shdr *shdr = &info->sechdrs[i];
@@ -2639,8 +2678,8 @@ static int move_module(struct module *mod, struct load_info *info)
                        memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size);
                /* Update sh_addr to point to copy in image. */
                shdr->sh_addr = (unsigned long)dest;
-               DEBUGP("\t0x%lx %s\n",
-                      shdr->sh_addr, info->secstrings + shdr->sh_name);
+               pr_debug("\t0x%lx %s\n",
+                        (long)shdr->sh_addr, info->secstrings + shdr->sh_name);
        }
 
        return 0;
@@ -2742,27 +2781,18 @@ static struct module *layout_and_allocate(struct load_info *info)
           this is done generically; there doesn't appear to be any
           special cases for the architectures. */
        layout_sections(mod, info);
-
-       info->strmap = kzalloc(BITS_TO_LONGS(info->sechdrs[info->index.str].sh_size)
-                        * sizeof(long), GFP_KERNEL);
-       if (!info->strmap) {
-               err = -ENOMEM;
-               goto free_percpu;
-       }
        layout_symtab(mod, info);
 
        /* Allocate and move to the final place */
        err = move_module(mod, info);
        if (err)
-               goto free_strmap;
+               goto free_percpu;
 
        /* Module has been copied to its final place now: return it. */
        mod = (void *)info->sechdrs[info->index.mod].sh_addr;
        kmemleak_load_module(mod, info);
        return mod;
 
-free_strmap:
-       kfree(info->strmap);
 free_percpu:
        percpu_modfree(mod);
 out:
@@ -2772,7 +2802,6 @@ out:
 /* mod is no longer valid after this! */
 static void module_deallocate(struct module *mod, struct load_info *info)
 {
-       kfree(info->strmap);
        percpu_modfree(mod);
        module_free(mod, mod->module_init);
        module_free(mod, mod->module_core);
@@ -2811,7 +2840,7 @@ static struct module *load_module(void __user *umod,
        struct module *mod;
        long err;
 
-       DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
+       pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n",
               umod, len, uargs);
 
        /* Copy in the blobs from userspace, check they are vaguely sane. */
@@ -2902,8 +2931,7 @@ static struct module *load_module(void __user *umod,
        if (err < 0)
                goto unlink;
 
-       /* Get rid of temporary copy and strmap. */
-       kfree(info.strmap);
+       /* Get rid of temporary copy. */
        free_copy(&info);
 
        /* Done! */
@@ -3256,20 +3284,7 @@ static char *module_flags(struct module *mod, char *buf)
            mod->state == MODULE_STATE_GOING ||
            mod->state == MODULE_STATE_COMING) {
                buf[bx++] = '(';
-               if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE))
-                       buf[bx++] = 'P';
-               else if (mod->taints & (1 << TAINT_OOT_MODULE))
-                       buf[bx++] = 'O';
-               if (mod->taints & (1 << TAINT_FORCED_MODULE))
-                       buf[bx++] = 'F';
-               if (mod->taints & (1 << TAINT_CRAP))
-                       buf[bx++] = 'C';
-               /*
-                * TAINT_FORCED_RMMOD: could be added.
-                * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
-                * apply to modules.
-                */
-
+               bx += module_flags_taint(mod, buf + bx);
                /* Show a - for module-is-being-unloaded */
                if (mod->state == MODULE_STATE_GOING)
                        buf[bx++] = '-';
index 3458469eb7c3489badf84de6916defa9cd6472a0..80aed44e345abc648f7ac3d0e7560a05e453c7fd 100644 (file)
@@ -49,6 +49,15 @@ static long no_blink(int state)
 long (*panic_blink)(int state);
 EXPORT_SYMBOL(panic_blink);
 
+/*
+ * Stop ourself in panic -- architecture code may override this
+ */
+void __weak panic_smp_self_stop(void)
+{
+       while (1)
+               cpu_relax();
+}
+
 /**
  *     panic - halt the system
  *     @fmt: The text string to print
@@ -57,8 +66,9 @@ EXPORT_SYMBOL(panic_blink);
  *
  *     This function never returns.
  */
-NORET_TYPE void panic(const char * fmt, ...)
+void panic(const char *fmt, ...)
 {
+       static DEFINE_SPINLOCK(panic_lock);
        static char buf[1024];
        va_list args;
        long i, i_next = 0;
@@ -68,8 +78,14 @@ NORET_TYPE void panic(const char * fmt, ...)
         * It's possible to come here directly from a panic-assertion and
         * not have preempt disabled. Some functions called from here want
         * preempt to be disabled. No point enabling it later though...
+        *
+        * Only one CPU is allowed to execute the panic code from here. For
+        * multiple parallel invocations of panic, all other CPUs either
+        * stop themself or will wait until they are stopped by the 1st CPU
+        * with smp_send_stop().
         */
-       preempt_disable();
+       if (!spin_trylock(&panic_lock))
+               panic_smp_self_stop();
 
        console_verbose();
        bust_spinlocks(1);
@@ -78,7 +94,11 @@ NORET_TYPE void panic(const char * fmt, ...)
        va_end(args);
        printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
 #ifdef CONFIG_DEBUG_BUGVERBOSE
-       dump_stack();
+       /*
+        * Avoid nested stack-dumping if a panic occurs during oops processing
+        */
+       if (!oops_in_progress)
+               dump_stack();
 #endif
 
        /*
index 65aae11eb93f1fab5a4673ca9e9d4df9f2582e8e..32ee04308285c051a4521a192d80dc89f34e1d59 100644 (file)
 #include <linux/slab.h>
 #include <linux/ctype.h>
 
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(fmt, a...)
-#endif
-
 /* Protects all parameters, and incidentally kmalloced_param list. */
 static DEFINE_MUTEX(param_lock);
 
@@ -105,7 +99,7 @@ static int parse_one(char *param,
                        /* No one handled NULL, so do it here. */
                        if (!val && params[i].ops->set != param_set_bool)
                                return -EINVAL;
-                       DEBUGP("They are equal!  Calling %p\n",
+                       pr_debug("They are equal!  Calling %p\n",
                               params[i].ops->set);
                        mutex_lock(&param_lock);
                        err = params[i].ops->set(val, &params[i]);
@@ -115,11 +109,11 @@ static int parse_one(char *param,
        }
 
        if (handle_unknown) {
-               DEBUGP("Unknown argument: calling %p\n", handle_unknown);
+               pr_debug("Unknown argument: calling %p\n", handle_unknown);
                return handle_unknown(param, val);
        }
 
-       DEBUGP("Unknown argument `%s'\n", param);
+       pr_debug("Unknown argument `%s'\n", param);
        return -ENOENT;
 }
 
@@ -184,7 +178,7 @@ int parse_args(const char *name,
 {
        char *param, *val;
 
-       DEBUGP("Parsing ARGS: %s\n", args);
+       pr_debug("Parsing ARGS: %s\n", args);
 
        /* Chew leading spaces */
        args = skip_spaces(args);
@@ -369,6 +363,30 @@ struct kernel_param_ops param_ops_invbool = {
 };
 EXPORT_SYMBOL(param_ops_invbool);
 
+int param_set_bint(const char *val, const struct kernel_param *kp)
+{
+       struct kernel_param boolkp;
+       bool v;
+       int ret;
+
+       /* Match bool exactly, by re-using it. */
+       boolkp = *kp;
+       boolkp.arg = &v;
+       boolkp.flags |= KPARAM_ISBOOL;
+
+       ret = param_set_bool(val, &boolkp);
+       if (ret == 0)
+               *(int *)kp->arg = v;
+       return ret;
+}
+EXPORT_SYMBOL(param_set_bint);
+
+struct kernel_param_ops param_ops_bint = {
+       .set = param_set_bint,
+       .get = param_get_int,
+};
+EXPORT_SYMBOL(param_ops_bint);
+
 /* We break the rule and mangle the string. */
 static int param_array(const char *name,
                       const char *val,
index fa5f72227e5f432127c4f3b1383e3c93abcd0eaa..ce8e00deaccb38452188436438dc942313bd6c44 100644 (file)
@@ -137,7 +137,9 @@ static int pid_before(int base, int a, int b)
 }
 
 /*
- * We might be racing with someone else trying to set pid_ns->last_pid.
+ * We might be racing with someone else trying to set pid_ns->last_pid
+ * at the pid allocation time (there's also a sysctl for this, but racing
+ * with this one is OK, see comment in kernel/pid_namespace.c about it).
  * We want the winner to have the "later" value, because if the
  * "earlier" value prevails, then a pid may get reused immediately.
  *
index e9c9adc84ca6e50f5f457e081bb45c36b35bf4d1..a8968396046d3b2f9310c0ca6bd6bb0757c34cca 100644 (file)
@@ -191,9 +191,40 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
        return;
 }
 
+static int pid_ns_ctl_handler(struct ctl_table *table, int write,
+               void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct ctl_table tmp = *table;
+
+       if (write && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       /*
+        * Writing directly to ns' last_pid field is OK, since this field
+        * is volatile in a living namespace anyway and a code writing to
+        * it should synchronize its usage with external means.
+        */
+
+       tmp.data = &current->nsproxy->pid_ns->last_pid;
+       return proc_dointvec(&tmp, write, buffer, lenp, ppos);
+}
+
+static struct ctl_table pid_ns_ctl_table[] = {
+       {
+               .procname = "ns_last_pid",
+               .maxlen = sizeof(int),
+               .mode = 0666, /* permissions are checked in the handler */
+               .proc_handler = pid_ns_ctl_handler,
+       },
+       { }
+};
+
+static struct ctl_path kern_path[] = { { .procname = "kernel", }, { } };
+
 static __init int pid_namespaces_init(void)
 {
        pid_ns_cachep = KMEM_CACHE(pid_namespace, SLAB_PANIC);
+       register_sysctl_paths(kern_path, pid_ns_ctl_table);
        return 0;
 }
 
index 3739ecced085db0141557feec608bb3eccbb0c07..8742fd013a94e3b56efdbf91cf27c709679615e4 100644 (file)
@@ -773,8 +773,7 @@ static int enough_swap(unsigned int nr_pages, unsigned int flags)
 
        pr_debug("PM: Free swap pages: %u\n", free_swap);
 
-       required = PAGES_FOR_IO + ((flags & SF_NOCOMPRESS_MODE) ?
-               nr_pages : (nr_pages * LZO_CMP_PAGES) / LZO_UNC_PAGES + 1);
+       required = PAGES_FOR_IO + nr_pages;
        return free_swap > required;
 }
 
@@ -802,10 +801,12 @@ int swsusp_write(unsigned int flags)
                printk(KERN_ERR "PM: Cannot get swap writer\n");
                return error;
        }
-       if (!enough_swap(pages, flags)) {
-               printk(KERN_ERR "PM: Not enough free swap\n");
-               error = -ENOSPC;
-               goto out_finish;
+       if (flags & SF_NOCOMPRESS_MODE) {
+               if (!enough_swap(pages, flags)) {
+                       printk(KERN_ERR "PM: Not enough free swap\n");
+                       error = -ENOSPC;
+                       goto out_finish;
+               }
        }
        memset(&snapshot, 0, sizeof(struct snapshot_handle));
        error = snapshot_read_next(&snapshot);
index 989e4a52da76e10c6bb43601d1a49931f7bb82ed..13c0a1143f49438f7cc97718e61ecf5bc5b23747 100644 (file)
@@ -521,7 +521,7 @@ static void __call_console_drivers(unsigned start, unsigned end)
        }
 }
 
-static int __read_mostly ignore_loglevel;
+static bool __read_mostly ignore_loglevel;
 
 static int __init ignore_loglevel_setup(char *str)
 {
@@ -532,7 +532,7 @@ static int __init ignore_loglevel_setup(char *str)
 }
 
 early_param("ignore_loglevel", ignore_loglevel_setup);
-module_param_named(ignore_loglevel, ignore_loglevel, bool, S_IRUGO | S_IWUSR);
+module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ignore_loglevel, "ignore loglevel setting, to"
        "print all kernel messages to the console.");
 
@@ -696,9 +696,9 @@ static void zap_locks(void)
 }
 
 #if defined(CONFIG_PRINTK_TIME)
-static int printk_time = 1;
+static bool printk_time = 1;
 #else
-static int printk_time = 0;
+static bool printk_time = 0;
 #endif
 module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
 
@@ -1098,7 +1098,7 @@ int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, cha
        return -1;
 }
 
-int console_suspend_enabled = 1;
+bool console_suspend_enabled = 1;
 EXPORT_SYMBOL(console_suspend_enabled);
 
 static int __init console_suspend_disable(char *str)
index 78ab24a7b0e440e2b44d75cc08bc353ab6f939c2..00ab2ca5ed1179c941d15b9e002d3cacee780414 100644 (file)
@@ -172,6 +172,14 @@ int ptrace_check_attach(struct task_struct *child, bool ignore_state)
        return ret;
 }
 
+static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
+{
+       if (mode & PTRACE_MODE_NOAUDIT)
+               return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE);
+       else
+               return has_ns_capability(current, ns, CAP_SYS_PTRACE);
+}
+
 int __ptrace_may_access(struct task_struct *task, unsigned int mode)
 {
        const struct cred *cred = current_cred(), *tcred;
@@ -198,7 +206,7 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
             cred->gid == tcred->sgid &&
             cred->gid == tcred->gid))
                goto ok;
-       if (ns_capable(tcred->user->user_ns, CAP_SYS_PTRACE))
+       if (ptrace_has_cap(tcred->user->user_ns, mode))
                goto ok;
        rcu_read_unlock();
        return -EPERM;
@@ -207,7 +215,7 @@ ok:
        smp_rmb();
        if (task->mm)
                dumpable = get_dumpable(task->mm);
-       if (!dumpable && !task_ns_capable(task, CAP_SYS_PTRACE))
+       if (!dumpable  && !ptrace_has_cap(task_user_ns(task), mode))
                return -EPERM;
 
        return security_ptrace_access_check(task, mode);
@@ -277,7 +285,7 @@ static int ptrace_attach(struct task_struct *task, long request,
        task->ptrace = PT_PTRACED;
        if (seize)
                task->ptrace |= PT_SEIZED;
-       if (task_ns_capable(task, CAP_SYS_PTRACE))
+       if (ns_capable(task_user_ns(task), CAP_SYS_PTRACE))
                task->ptrace |= PT_PTRACE_CAP;
 
        __ptrace_link(task, current);
index fd7b25e9007933b29d02a71fae7e528deb0248f9..df00cb09263e093b2c0a9c73a20e16b6602a70ea 100644 (file)
@@ -4330,7 +4330,7 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
                goto out_free_cpus_allowed;
        }
        retval = -EPERM;
-       if (!check_same_owner(p) && !task_ns_capable(p, CAP_SYS_NICE))
+       if (!check_same_owner(p) && !ns_capable(task_user_ns(p), CAP_SYS_NICE))
                goto out_unlock;
 
        retval = security_task_setscheduler(p);
index 57d4b13b631de36161349feb99ae6f76a2984b06..e8d76c5895ea15f3bb4867a85f48851dedf90cd4 100644 (file)
@@ -6,6 +6,7 @@
  * This defines a simple but solid secure-computing mode.
  */
 
+#include <linux/audit.h>
 #include <linux/seccomp.h>
 #include <linux/sched.h>
 #include <linux/compat.h>
@@ -54,6 +55,7 @@ void __secure_computing(int this_syscall)
 #ifdef SECCOMP_DEBUG
        dump_stack();
 #endif
+       audit_seccomp(this_syscall);
        do_exit(SIGKILL);
 }
 
index ddf8155bf3f8c09a3745a3cea82ec4e9aef49208..40701538fbd168db2de95315ac5c512a79686f52 100644 (file)
@@ -1692,6 +1692,124 @@ SYSCALL_DEFINE1(umask, int, mask)
        return mask;
 }
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+static int prctl_set_mm(int opt, unsigned long addr,
+                       unsigned long arg4, unsigned long arg5)
+{
+       unsigned long rlim = rlimit(RLIMIT_DATA);
+       unsigned long vm_req_flags;
+       unsigned long vm_bad_flags;
+       struct vm_area_struct *vma;
+       int error = 0;
+       struct mm_struct *mm = current->mm;
+
+       if (arg4 | arg5)
+               return -EINVAL;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (addr >= TASK_SIZE)
+               return -EINVAL;
+
+       down_read(&mm->mmap_sem);
+       vma = find_vma(mm, addr);
+
+       if (opt != PR_SET_MM_START_BRK && opt != PR_SET_MM_BRK) {
+               /* It must be existing VMA */
+               if (!vma || vma->vm_start > addr)
+                       goto out;
+       }
+
+       error = -EINVAL;
+       switch (opt) {
+       case PR_SET_MM_START_CODE:
+       case PR_SET_MM_END_CODE:
+               vm_req_flags = VM_READ | VM_EXEC;
+               vm_bad_flags = VM_WRITE | VM_MAYSHARE;
+
+               if ((vma->vm_flags & vm_req_flags) != vm_req_flags ||
+                   (vma->vm_flags & vm_bad_flags))
+                       goto out;
+
+               if (opt == PR_SET_MM_START_CODE)
+                       mm->start_code = addr;
+               else
+                       mm->end_code = addr;
+               break;
+
+       case PR_SET_MM_START_DATA:
+       case PR_SET_MM_END_DATA:
+               vm_req_flags = VM_READ | VM_WRITE;
+               vm_bad_flags = VM_EXEC | VM_MAYSHARE;
+
+               if ((vma->vm_flags & vm_req_flags) != vm_req_flags ||
+                   (vma->vm_flags & vm_bad_flags))
+                       goto out;
+
+               if (opt == PR_SET_MM_START_DATA)
+                       mm->start_data = addr;
+               else
+                       mm->end_data = addr;
+               break;
+
+       case PR_SET_MM_START_STACK:
+
+#ifdef CONFIG_STACK_GROWSUP
+               vm_req_flags = VM_READ | VM_WRITE | VM_GROWSUP;
+#else
+               vm_req_flags = VM_READ | VM_WRITE | VM_GROWSDOWN;
+#endif
+               if ((vma->vm_flags & vm_req_flags) != vm_req_flags)
+                       goto out;
+
+               mm->start_stack = addr;
+               break;
+
+       case PR_SET_MM_START_BRK:
+               if (addr <= mm->end_data)
+                       goto out;
+
+               if (rlim < RLIM_INFINITY &&
+                   (mm->brk - addr) +
+                   (mm->end_data - mm->start_data) > rlim)
+                       goto out;
+
+               mm->start_brk = addr;
+               break;
+
+       case PR_SET_MM_BRK:
+               if (addr <= mm->end_data)
+                       goto out;
+
+               if (rlim < RLIM_INFINITY &&
+                   (addr - mm->start_brk) +
+                   (mm->end_data - mm->start_data) > rlim)
+                       goto out;
+
+               mm->brk = addr;
+               break;
+
+       default:
+               error = -EINVAL;
+               goto out;
+       }
+
+       error = 0;
+
+out:
+       up_read(&mm->mmap_sem);
+
+       return error;
+}
+#else /* CONFIG_CHECKPOINT_RESTORE */
+static int prctl_set_mm(int opt, unsigned long addr,
+                       unsigned long arg4, unsigned long arg5)
+{
+       return -EINVAL;
+}
+#endif
+
 SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                unsigned long, arg4, unsigned long, arg5)
 {
@@ -1841,6 +1959,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                        else
                                error = PR_MCE_KILL_DEFAULT;
                        break;
+               case PR_SET_MM:
+                       error = prctl_set_mm(arg2, arg3, arg4, arg5);
+                       break;
                default:
                        error = -EINVAL;
                        break;
index b1e8943fed1d3a9fd61916527c59c70d57af7d2c..683d559a0eefef4cc9495c1b97fcbee0836065e1 100644 (file)
 #include <linux/hardirq.h>
 #include <linux/kthread.h>
 #include <linux/uaccess.h>
+#include <linux/bsearch.h>
 #include <linux/module.h>
 #include <linux/ftrace.h>
 #include <linux/sysctl.h>
 #include <linux/slab.h>
 #include <linux/ctype.h>
+#include <linux/sort.h>
 #include <linux/list.h>
 #include <linux/hash.h>
 #include <linux/rcupdate.h>
@@ -947,13 +949,6 @@ struct ftrace_func_probe {
        struct rcu_head         rcu;
 };
 
-enum {
-       FTRACE_ENABLE_CALLS             = (1 << 0),
-       FTRACE_DISABLE_CALLS            = (1 << 1),
-       FTRACE_UPDATE_TRACE_FUNC        = (1 << 2),
-       FTRACE_START_FUNC_RET           = (1 << 3),
-       FTRACE_STOP_FUNC_RET            = (1 << 4),
-};
 struct ftrace_func_entry {
        struct hlist_node hlist;
        unsigned long ip;
@@ -984,18 +979,19 @@ static struct ftrace_ops global_ops = {
        .filter_hash            = EMPTY_HASH,
 };
 
-static struct dyn_ftrace *ftrace_new_addrs;
-
 static DEFINE_MUTEX(ftrace_regex_lock);
 
 struct ftrace_page {
        struct ftrace_page      *next;
+       struct dyn_ftrace       *records;
        int                     index;
-       struct dyn_ftrace       records[];
+       int                     size;
 };
 
-#define ENTRIES_PER_PAGE \
-  ((PAGE_SIZE - sizeof(struct ftrace_page)) / sizeof(struct dyn_ftrace))
+static struct ftrace_page *ftrace_new_pgs;
+
+#define ENTRY_SIZE sizeof(struct dyn_ftrace)
+#define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE)
 
 /* estimate from running different kernels */
 #define NR_TO_INIT             10000
@@ -1003,7 +999,10 @@ struct ftrace_page {
 static struct ftrace_page      *ftrace_pages_start;
 static struct ftrace_page      *ftrace_pages;
 
-static struct dyn_ftrace *ftrace_free_records;
+static bool ftrace_hash_empty(struct ftrace_hash *hash)
+{
+       return !hash || !hash->count;
+}
 
 static struct ftrace_func_entry *
 ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip)
@@ -1013,7 +1012,7 @@ ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip)
        struct hlist_head *hhd;
        struct hlist_node *n;
 
-       if (!hash->count)
+       if (ftrace_hash_empty(hash))
                return NULL;
 
        if (hash->size_bits > 0)
@@ -1157,7 +1156,7 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash)
                return NULL;
 
        /* Empty hash? */
-       if (!hash || !hash->count)
+       if (ftrace_hash_empty(hash))
                return new_hash;
 
        size = 1 << hash->size_bits;
@@ -1282,9 +1281,9 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)
        filter_hash = rcu_dereference_raw(ops->filter_hash);
        notrace_hash = rcu_dereference_raw(ops->notrace_hash);
 
-       if ((!filter_hash || !filter_hash->count ||
+       if ((ftrace_hash_empty(filter_hash) ||
             ftrace_lookup_ip(filter_hash, ip)) &&
-           (!notrace_hash || !notrace_hash->count ||
+           (ftrace_hash_empty(notrace_hash) ||
             !ftrace_lookup_ip(notrace_hash, ip)))
                ret = 1;
        else
@@ -1307,6 +1306,47 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)
                }                               \
        }
 
+
+static int ftrace_cmp_recs(const void *a, const void *b)
+{
+       const struct dyn_ftrace *reca = a;
+       const struct dyn_ftrace *recb = b;
+
+       if (reca->ip > recb->ip)
+               return 1;
+       if (reca->ip < recb->ip)
+               return -1;
+       return 0;
+}
+
+/**
+ * ftrace_location - return true if the ip giving is a traced location
+ * @ip: the instruction pointer to check
+ *
+ * Returns 1 if @ip given is a pointer to a ftrace location.
+ * That is, the instruction that is either a NOP or call to
+ * the function tracer. It checks the ftrace internal tables to
+ * determine if the address belongs or not.
+ */
+int ftrace_location(unsigned long ip)
+{
+       struct ftrace_page *pg;
+       struct dyn_ftrace *rec;
+       struct dyn_ftrace key;
+
+       key.ip = ip;
+
+       for (pg = ftrace_pages_start; pg; pg = pg->next) {
+               rec = bsearch(&key, pg->records, pg->index,
+                             sizeof(struct dyn_ftrace),
+                             ftrace_cmp_recs);
+               if (rec)
+                       return 1;
+       }
+
+       return 0;
+}
+
 static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
                                     int filter_hash,
                                     bool inc)
@@ -1336,7 +1376,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
        if (filter_hash) {
                hash = ops->filter_hash;
                other_hash = ops->notrace_hash;
-               if (!hash || !hash->count)
+               if (ftrace_hash_empty(hash))
                        all = 1;
        } else {
                inc = !inc;
@@ -1346,7 +1386,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
                 * If the notrace hash has no items,
                 * then there's nothing to do.
                 */
-               if (hash && !hash->count)
+               if (ftrace_hash_empty(hash))
                        return;
        }
 
@@ -1363,8 +1403,8 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
                        if (!other_hash || !ftrace_lookup_ip(other_hash, rec->ip))
                                match = 1;
                } else {
-                       in_hash = hash && !!ftrace_lookup_ip(hash, rec->ip);
-                       in_other_hash = other_hash && !!ftrace_lookup_ip(other_hash, rec->ip);
+                       in_hash = !!ftrace_lookup_ip(hash, rec->ip);
+                       in_other_hash = !!ftrace_lookup_ip(other_hash, rec->ip);
 
                        /*
                         *
@@ -1372,7 +1412,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
                        if (filter_hash && in_hash && !in_other_hash)
                                match = 1;
                        else if (!filter_hash && in_hash &&
-                                (in_other_hash || !other_hash->count))
+                                (in_other_hash || ftrace_hash_empty(other_hash)))
                                match = 1;
                }
                if (!match)
@@ -1406,40 +1446,12 @@ static void ftrace_hash_rec_enable(struct ftrace_ops *ops,
        __ftrace_hash_rec_update(ops, filter_hash, 1);
 }
 
-static void ftrace_free_rec(struct dyn_ftrace *rec)
-{
-       rec->freelist = ftrace_free_records;
-       ftrace_free_records = rec;
-       rec->flags |= FTRACE_FL_FREE;
-}
-
 static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
 {
-       struct dyn_ftrace *rec;
-
-       /* First check for freed records */
-       if (ftrace_free_records) {
-               rec = ftrace_free_records;
-
-               if (unlikely(!(rec->flags & FTRACE_FL_FREE))) {
-                       FTRACE_WARN_ON_ONCE(1);
-                       ftrace_free_records = NULL;
+       if (ftrace_pages->index == ftrace_pages->size) {
+               /* We should have allocated enough */
+               if (WARN_ON(!ftrace_pages->next))
                        return NULL;
-               }
-
-               ftrace_free_records = rec->freelist;
-               memset(rec, 0, sizeof(*rec));
-               return rec;
-       }
-
-       if (ftrace_pages->index == ENTRIES_PER_PAGE) {
-               if (!ftrace_pages->next) {
-                       /* allocate another page */
-                       ftrace_pages->next =
-                               (void *)get_zeroed_page(GFP_KERNEL);
-                       if (!ftrace_pages->next)
-                               return NULL;
-               }
                ftrace_pages = ftrace_pages->next;
        }
 
@@ -1459,8 +1471,6 @@ ftrace_record_ip(unsigned long ip)
                return NULL;
 
        rec->ip = ip;
-       rec->newlist = ftrace_new_addrs;
-       ftrace_new_addrs = rec;
 
        return rec;
 }
@@ -1475,7 +1485,19 @@ static void print_ip_ins(const char *fmt, unsigned char *p)
                printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]);
 }
 
-static void ftrace_bug(int failed, unsigned long ip)
+/**
+ * ftrace_bug - report and shutdown function tracer
+ * @failed: The failed type (EFAULT, EINVAL, EPERM)
+ * @ip: The address that failed
+ *
+ * The arch code that enables or disables the function tracing
+ * can call ftrace_bug() when it has detected a problem in
+ * modifying the code. @failed should be one of either:
+ * EFAULT - if the problem happens on reading the @ip address
+ * EINVAL - if what is read at @ip is not what was expected
+ * EPERM - if the problem happens on writting to the @ip address
+ */
+void ftrace_bug(int failed, unsigned long ip)
 {
        switch (failed) {
        case -EFAULT:
@@ -1517,24 +1539,19 @@ int ftrace_text_reserved(void *start, void *end)
        return 0;
 }
 
-
-static int
-__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
+static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
 {
-       unsigned long ftrace_addr;
        unsigned long flag = 0UL;
 
-       ftrace_addr = (unsigned long)FTRACE_ADDR;
-
        /*
-        * If we are enabling tracing:
+        * If we are updating calls:
         *
         *   If the record has a ref count, then we need to enable it
         *   because someone is using it.
         *
         *   Otherwise we make sure its disabled.
         *
-        * If we are disabling tracing, then disable all records that
+        * If we are disabling calls, then disable all records that
         * are enabled.
         */
        if (enable && (rec->flags & ~FTRACE_FL_MASK))
@@ -1542,18 +1559,72 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
 
        /* If the state of this record hasn't changed, then do nothing */
        if ((rec->flags & FTRACE_FL_ENABLED) == flag)
-               return 0;
+               return FTRACE_UPDATE_IGNORE;
 
        if (flag) {
-               rec->flags |= FTRACE_FL_ENABLED;
+               if (update)
+                       rec->flags |= FTRACE_FL_ENABLED;
+               return FTRACE_UPDATE_MAKE_CALL;
+       }
+
+       if (update)
+               rec->flags &= ~FTRACE_FL_ENABLED;
+
+       return FTRACE_UPDATE_MAKE_NOP;
+}
+
+/**
+ * ftrace_update_record, set a record that now is tracing or not
+ * @rec: the record to update
+ * @enable: set to 1 if the record is tracing, zero to force disable
+ *
+ * The records that represent all functions that can be traced need
+ * to be updated when tracing has been enabled.
+ */
+int ftrace_update_record(struct dyn_ftrace *rec, int enable)
+{
+       return ftrace_check_record(rec, enable, 1);
+}
+
+/**
+ * ftrace_test_record, check if the record has been enabled or not
+ * @rec: the record to test
+ * @enable: set to 1 to check if enabled, 0 if it is disabled
+ *
+ * The arch code may need to test if a record is already set to
+ * tracing to determine how to modify the function code that it
+ * represents.
+ */
+int ftrace_test_record(struct dyn_ftrace *rec, int enable)
+{
+       return ftrace_check_record(rec, enable, 0);
+}
+
+static int
+__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
+{
+       unsigned long ftrace_addr;
+       int ret;
+
+       ftrace_addr = (unsigned long)FTRACE_ADDR;
+
+       ret = ftrace_update_record(rec, enable);
+
+       switch (ret) {
+       case FTRACE_UPDATE_IGNORE:
+               return 0;
+
+       case FTRACE_UPDATE_MAKE_CALL:
                return ftrace_make_call(rec, ftrace_addr);
+
+       case FTRACE_UPDATE_MAKE_NOP:
+               return ftrace_make_nop(NULL, rec, ftrace_addr);
        }
 
-       rec->flags &= ~FTRACE_FL_ENABLED;
-       return ftrace_make_nop(NULL, rec, ftrace_addr);
+       return -1; /* unknow ftrace bug */
 }
 
-static void ftrace_replace_code(int enable)
+static void ftrace_replace_code(int update)
 {
        struct dyn_ftrace *rec;
        struct ftrace_page *pg;
@@ -1563,11 +1634,7 @@ static void ftrace_replace_code(int enable)
                return;
 
        do_for_each_ftrace_rec(pg, rec) {
-               /* Skip over free records */
-               if (rec->flags & FTRACE_FL_FREE)
-                       continue;
-
-               failed = __ftrace_replace_code(rec, enable);
+               failed = __ftrace_replace_code(rec, update);
                if (failed) {
                        ftrace_bug(failed, rec->ip);
                        /* Stop processing */
@@ -1576,6 +1643,78 @@ static void ftrace_replace_code(int enable)
        } while_for_each_ftrace_rec();
 }
 
+struct ftrace_rec_iter {
+       struct ftrace_page      *pg;
+       int                     index;
+};
+
+/**
+ * ftrace_rec_iter_start, start up iterating over traced functions
+ *
+ * Returns an iterator handle that is used to iterate over all
+ * the records that represent address locations where functions
+ * are traced.
+ *
+ * May return NULL if no records are available.
+ */
+struct ftrace_rec_iter *ftrace_rec_iter_start(void)
+{
+       /*
+        * We only use a single iterator.
+        * Protected by the ftrace_lock mutex.
+        */
+       static struct ftrace_rec_iter ftrace_rec_iter;
+       struct ftrace_rec_iter *iter = &ftrace_rec_iter;
+
+       iter->pg = ftrace_pages_start;
+       iter->index = 0;
+
+       /* Could have empty pages */
+       while (iter->pg && !iter->pg->index)
+               iter->pg = iter->pg->next;
+
+       if (!iter->pg)
+               return NULL;
+
+       return iter;
+}
+
+/**
+ * ftrace_rec_iter_next, get the next record to process.
+ * @iter: The handle to the iterator.
+ *
+ * Returns the next iterator after the given iterator @iter.
+ */
+struct ftrace_rec_iter *ftrace_rec_iter_next(struct ftrace_rec_iter *iter)
+{
+       iter->index++;
+
+       if (iter->index >= iter->pg->index) {
+               iter->pg = iter->pg->next;
+               iter->index = 0;
+
+               /* Could have empty pages */
+               while (iter->pg && !iter->pg->index)
+                       iter->pg = iter->pg->next;
+       }
+
+       if (!iter->pg)
+               return NULL;
+
+       return iter;
+}
+
+/**
+ * ftrace_rec_iter_record, get the record at the iterator location
+ * @iter: The current iterator location
+ *
+ * Returns the record that the current @iter is at.
+ */
+struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter)
+{
+       return &iter->pg->records[iter->index];
+}
+
 static int
 ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec)
 {
@@ -1617,13 +1756,7 @@ static int __ftrace_modify_code(void *data)
 {
        int *command = data;
 
-       /*
-        * Do not call function tracer while we update the code.
-        * We are in stop machine, no worrying about races.
-        */
-       function_trace_stop++;
-
-       if (*command & FTRACE_ENABLE_CALLS)
+       if (*command & FTRACE_UPDATE_CALLS)
                ftrace_replace_code(1);
        else if (*command & FTRACE_DISABLE_CALLS)
                ftrace_replace_code(0);
@@ -1636,21 +1769,33 @@ static int __ftrace_modify_code(void *data)
        else if (*command & FTRACE_STOP_FUNC_RET)
                ftrace_disable_ftrace_graph_caller();
 
-#ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
-       /*
-        * For archs that call ftrace_test_stop_func(), we must
-        * wait till after we update all the function callers
-        * before we update the callback. This keeps different
-        * ops that record different functions from corrupting
-        * each other.
-        */
-       __ftrace_trace_function = __ftrace_trace_function_delay;
-#endif
-       function_trace_stop--;
-
        return 0;
 }
 
+/**
+ * ftrace_run_stop_machine, go back to the stop machine method
+ * @command: The command to tell ftrace what to do
+ *
+ * If an arch needs to fall back to the stop machine method, the
+ * it can call this function.
+ */
+void ftrace_run_stop_machine(int command)
+{
+       stop_machine(__ftrace_modify_code, &command, NULL);
+}
+
+/**
+ * arch_ftrace_update_code, modify the code to trace or not trace
+ * @command: The command that needs to be done
+ *
+ * Archs can override this function if it does not need to
+ * run stop_machine() to modify code.
+ */
+void __weak arch_ftrace_update_code(int command)
+{
+       ftrace_run_stop_machine(command);
+}
+
 static void ftrace_run_update_code(int command)
 {
        int ret;
@@ -1659,8 +1804,31 @@ static void ftrace_run_update_code(int command)
        FTRACE_WARN_ON(ret);
        if (ret)
                return;
+       /*
+        * Do not call function tracer while we update the code.
+        * We are in stop machine.
+        */
+       function_trace_stop++;
 
-       stop_machine(__ftrace_modify_code, &command, NULL);
+       /*
+        * By default we use stop_machine() to modify the code.
+        * But archs can do what ever they want as long as it
+        * is safe. The stop_machine() is the safest, but also
+        * produces the most overhead.
+        */
+       arch_ftrace_update_code(command);
+
+#ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
+       /*
+        * For archs that call ftrace_test_stop_func(), we must
+        * wait till after we update all the function callers
+        * before we update the callback. This keeps different
+        * ops that record different functions from corrupting
+        * each other.
+        */
+       __ftrace_trace_function = __ftrace_trace_function_delay;
+#endif
+       function_trace_stop--;
 
        ret = ftrace_arch_code_modify_post_process();
        FTRACE_WARN_ON(ret);
@@ -1691,7 +1859,7 @@ static int ftrace_startup(struct ftrace_ops *ops, int command)
                return -ENODEV;
 
        ftrace_start_up++;
-       command |= FTRACE_ENABLE_CALLS;
+       command |= FTRACE_UPDATE_CALLS;
 
        /* ops marked global share the filter hashes */
        if (ops->flags & FTRACE_OPS_FL_GLOBAL) {
@@ -1743,8 +1911,7 @@ static void ftrace_shutdown(struct ftrace_ops *ops, int command)
        if (ops != &global_ops || !global_start_up)
                ops->flags &= ~FTRACE_OPS_FL_ENABLED;
 
-       if (!ftrace_start_up)
-               command |= FTRACE_DISABLE_CALLS;
+       command |= FTRACE_UPDATE_CALLS;
 
        if (saved_ftrace_func != ftrace_trace_function) {
                saved_ftrace_func = ftrace_trace_function;
@@ -1766,7 +1933,7 @@ static void ftrace_startup_sysctl(void)
        saved_ftrace_func = NULL;
        /* ftrace_start_up is true if we want ftrace running */
        if (ftrace_start_up)
-               ftrace_run_update_code(FTRACE_ENABLE_CALLS);
+               ftrace_run_update_code(FTRACE_UPDATE_CALLS);
 }
 
 static void ftrace_shutdown_sysctl(void)
@@ -1788,14 +1955,16 @@ static int ops_traces_mod(struct ftrace_ops *ops)
        struct ftrace_hash *hash;
 
        hash = ops->filter_hash;
-       return !!(!hash || !hash->count);
+       return ftrace_hash_empty(hash);
 }
 
 static int ftrace_update_code(struct module *mod)
 {
+       struct ftrace_page *pg;
        struct dyn_ftrace *p;
        cycle_t start, stop;
        unsigned long ref = 0;
+       int i;
 
        /*
         * When adding a module, we need to check if tracers are
@@ -1817,46 +1986,44 @@ static int ftrace_update_code(struct module *mod)
        start = ftrace_now(raw_smp_processor_id());
        ftrace_update_cnt = 0;
 
-       while (ftrace_new_addrs) {
+       for (pg = ftrace_new_pgs; pg; pg = pg->next) {
 
-               /* If something went wrong, bail without enabling anything */
-               if (unlikely(ftrace_disabled))
-                       return -1;
+               for (i = 0; i < pg->index; i++) {
+                       /* If something went wrong, bail without enabling anything */
+                       if (unlikely(ftrace_disabled))
+                               return -1;
 
-               p = ftrace_new_addrs;
-               ftrace_new_addrs = p->newlist;
-               p->flags = ref;
+                       p = &pg->records[i];
+                       p->flags = ref;
 
-               /*
-                * Do the initial record conversion from mcount jump
-                * to the NOP instructions.
-                */
-               if (!ftrace_code_disable(mod, p)) {
-                       ftrace_free_rec(p);
-                       /* Game over */
-                       break;
-               }
+                       /*
+                        * Do the initial record conversion from mcount jump
+                        * to the NOP instructions.
+                        */
+                       if (!ftrace_code_disable(mod, p))
+                               break;
 
-               ftrace_update_cnt++;
+                       ftrace_update_cnt++;
 
-               /*
-                * If the tracing is enabled, go ahead and enable the record.
-                *
-                * The reason not to enable the record immediatelly is the
-                * inherent check of ftrace_make_nop/ftrace_make_call for
-                * correct previous instructions.  Making first the NOP
-                * conversion puts the module to the correct state, thus
-                * passing the ftrace_make_call check.
-                */
-               if (ftrace_start_up && ref) {
-                       int failed = __ftrace_replace_code(p, 1);
-                       if (failed) {
-                               ftrace_bug(failed, p->ip);
-                               ftrace_free_rec(p);
+                       /*
+                        * If the tracing is enabled, go ahead and enable the record.
+                        *
+                        * The reason not to enable the record immediatelly is the
+                        * inherent check of ftrace_make_nop/ftrace_make_call for
+                        * correct previous instructions.  Making first the NOP
+                        * conversion puts the module to the correct state, thus
+                        * passing the ftrace_make_call check.
+                        */
+                       if (ftrace_start_up && ref) {
+                               int failed = __ftrace_replace_code(p, 1);
+                               if (failed)
+                                       ftrace_bug(failed, p->ip);
                        }
                }
        }
 
+       ftrace_new_pgs = NULL;
+
        stop = ftrace_now(raw_smp_processor_id());
        ftrace_update_time = stop - start;
        ftrace_update_tot_cnt += ftrace_update_cnt;
@@ -1864,57 +2031,108 @@ static int ftrace_update_code(struct module *mod)
        return 0;
 }
 
-static int __init ftrace_dyn_table_alloc(unsigned long num_to_init)
+static int ftrace_allocate_records(struct ftrace_page *pg, int count)
 {
-       struct ftrace_page *pg;
+       int order;
        int cnt;
-       int i;
 
-       /* allocate a few pages */
-       ftrace_pages_start = (void *)get_zeroed_page(GFP_KERNEL);
-       if (!ftrace_pages_start)
-               return -1;
+       if (WARN_ON(!count))
+               return -EINVAL;
+
+       order = get_count_order(DIV_ROUND_UP(count, ENTRIES_PER_PAGE));
 
        /*
-        * Allocate a few more pages.
-        *
-        * TODO: have some parser search vmlinux before
-        *   final linking to find all calls to ftrace.
-        *   Then we can:
-        *    a) know how many pages to allocate.
-        *     and/or
-        *    b) set up the table then.
-        *
-        *  The dynamic code is still necessary for
-        *  modules.
+        * We want to fill as much as possible. No more than a page
+        * may be empty.
         */
+       while ((PAGE_SIZE << order) / ENTRY_SIZE >= count + ENTRIES_PER_PAGE)
+               order--;
 
-       pg = ftrace_pages = ftrace_pages_start;
+ again:
+       pg->records = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
 
-       cnt = num_to_init / ENTRIES_PER_PAGE;
-       pr_info("ftrace: allocating %ld entries in %d pages\n",
-               num_to_init, cnt + 1);
+       if (!pg->records) {
+               /* if we can't allocate this size, try something smaller */
+               if (!order)
+                       return -ENOMEM;
+               order >>= 1;
+               goto again;
+       }
 
-       for (i = 0; i < cnt; i++) {
-               pg->next = (void *)get_zeroed_page(GFP_KERNEL);
+       cnt = (PAGE_SIZE << order) / ENTRY_SIZE;
+       pg->size = cnt;
 
-               /* If we fail, we'll try later anyway */
-               if (!pg->next)
+       if (cnt > count)
+               cnt = count;
+
+       return cnt;
+}
+
+static struct ftrace_page *
+ftrace_allocate_pages(unsigned long num_to_init)
+{
+       struct ftrace_page *start_pg;
+       struct ftrace_page *pg;
+       int order;
+       int cnt;
+
+       if (!num_to_init)
+               return 0;
+
+       start_pg = pg = kzalloc(sizeof(*pg), GFP_KERNEL);
+       if (!pg)
+               return NULL;
+
+       /*
+        * Try to allocate as much as possible in one continues
+        * location that fills in all of the space. We want to
+        * waste as little space as possible.
+        */
+       for (;;) {
+               cnt = ftrace_allocate_records(pg, num_to_init);
+               if (cnt < 0)
+                       goto free_pages;
+
+               num_to_init -= cnt;
+               if (!num_to_init)
                        break;
 
+               pg->next = kzalloc(sizeof(*pg), GFP_KERNEL);
+               if (!pg->next)
+                       goto free_pages;
+
                pg = pg->next;
        }
 
-       return 0;
+       return start_pg;
+
+ free_pages:
+       while (start_pg) {
+               order = get_count_order(pg->size / ENTRIES_PER_PAGE);
+               free_pages((unsigned long)pg->records, order);
+               start_pg = pg->next;
+               kfree(pg);
+               pg = start_pg;
+       }
+       pr_info("ftrace: FAILED to allocate memory for functions\n");
+       return NULL;
 }
 
-enum {
-       FTRACE_ITER_FILTER      = (1 << 0),
-       FTRACE_ITER_NOTRACE     = (1 << 1),
-       FTRACE_ITER_PRINTALL    = (1 << 2),
-       FTRACE_ITER_HASH        = (1 << 3),
-       FTRACE_ITER_ENABLED     = (1 << 4),
-};
+static int __init ftrace_dyn_table_alloc(unsigned long num_to_init)
+{
+       int cnt;
+
+       if (!num_to_init) {
+               pr_info("ftrace: No functions to be traced?\n");
+               return -1;
+       }
+
+       cnt = num_to_init / ENTRIES_PER_PAGE;
+       pr_info("ftrace: allocating %ld entries in %d pages\n",
+               num_to_init, cnt + 1);
+
+       return 0;
+}
 
 #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */
 
@@ -1980,6 +2198,9 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos)
        void *p = NULL;
        loff_t l;
 
+       if (!(iter->flags & FTRACE_ITER_DO_HASH))
+               return NULL;
+
        if (iter->func_pos > *pos)
                return NULL;
 
@@ -2023,7 +2244,7 @@ static void *
 t_next(struct seq_file *m, void *v, loff_t *pos)
 {
        struct ftrace_iterator *iter = m->private;
-       struct ftrace_ops *ops = &global_ops;
+       struct ftrace_ops *ops = iter->ops;
        struct dyn_ftrace *rec = NULL;
 
        if (unlikely(ftrace_disabled))
@@ -2047,9 +2268,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
                }
        } else {
                rec = &iter->pg->records[iter->idx++];
-               if ((rec->flags & FTRACE_FL_FREE) ||
-
-                   ((iter->flags & FTRACE_ITER_FILTER) &&
+               if (((iter->flags & FTRACE_ITER_FILTER) &&
                     !(ftrace_lookup_ip(ops->filter_hash, rec->ip))) ||
 
                    ((iter->flags & FTRACE_ITER_NOTRACE) &&
@@ -2081,7 +2300,7 @@ static void reset_iter_read(struct ftrace_iterator *iter)
 static void *t_start(struct seq_file *m, loff_t *pos)
 {
        struct ftrace_iterator *iter = m->private;
-       struct ftrace_ops *ops = &global_ops;
+       struct ftrace_ops *ops = iter->ops;
        void *p = NULL;
        loff_t l;
 
@@ -2101,7 +2320,8 @@ static void *t_start(struct seq_file *m, loff_t *pos)
         * off, we can short cut and just print out that all
         * functions are enabled.
         */
-       if (iter->flags & FTRACE_ITER_FILTER && !ops->filter_hash->count) {
+       if (iter->flags & FTRACE_ITER_FILTER &&
+           ftrace_hash_empty(ops->filter_hash)) {
                if (*pos > 0)
                        return t_hash_start(m, pos);
                iter->flags |= FTRACE_ITER_PRINTALL;
@@ -2126,12 +2346,8 @@ static void *t_start(struct seq_file *m, loff_t *pos)
                        break;
        }
 
-       if (!p) {
-               if (iter->flags & FTRACE_ITER_FILTER)
-                       return t_hash_start(m, pos);
-
-               return NULL;
-       }
+       if (!p)
+               return t_hash_start(m, pos);
 
        return iter;
 }
@@ -2189,6 +2405,7 @@ ftrace_avail_open(struct inode *inode, struct file *file)
                return -ENOMEM;
 
        iter->pg = ftrace_pages_start;
+       iter->ops = &global_ops;
 
        ret = seq_open(file, &show_ftrace_seq_ops);
        if (!ret) {
@@ -2217,6 +2434,7 @@ ftrace_enabled_open(struct inode *inode, struct file *file)
 
        iter->pg = ftrace_pages_start;
        iter->flags = FTRACE_ITER_ENABLED;
+       iter->ops = &global_ops;
 
        ret = seq_open(file, &show_ftrace_seq_ops);
        if (!ret) {
@@ -2237,7 +2455,23 @@ static void ftrace_filter_reset(struct ftrace_hash *hash)
        mutex_unlock(&ftrace_lock);
 }
 
-static int
+/**
+ * ftrace_regex_open - initialize function tracer filter files
+ * @ops: The ftrace_ops that hold the hash filters
+ * @flag: The type of filter to process
+ * @inode: The inode, usually passed in to your open routine
+ * @file: The file, usually passed in to your open routine
+ *
+ * ftrace_regex_open() initializes the filter files for the
+ * @ops. Depending on @flag it may process the filter hash or
+ * the notrace hash of @ops. With this called from the open
+ * routine, you can use ftrace_filter_write() for the write
+ * routine if @flag has FTRACE_ITER_FILTER set, or
+ * ftrace_notrace_write() if @flag has FTRACE_ITER_NOTRACE set.
+ * ftrace_regex_lseek() should be used as the lseek routine, and
+ * release must call ftrace_regex_release().
+ */
+int
 ftrace_regex_open(struct ftrace_ops *ops, int flag,
                  struct inode *inode, struct file *file)
 {
@@ -2306,8 +2540,9 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
 static int
 ftrace_filter_open(struct inode *inode, struct file *file)
 {
-       return ftrace_regex_open(&global_ops, FTRACE_ITER_FILTER,
-                                inode, file);
+       return ftrace_regex_open(&global_ops,
+                       FTRACE_ITER_FILTER | FTRACE_ITER_DO_HASH,
+                       inode, file);
 }
 
 static int
@@ -2317,7 +2552,7 @@ ftrace_notrace_open(struct inode *inode, struct file *file)
                                 inode, file);
 }
 
-static loff_t
+loff_t
 ftrace_regex_lseek(struct file *file, loff_t offset, int origin)
 {
        loff_t ret;
@@ -2426,7 +2661,6 @@ match_records(struct ftrace_hash *hash, char *buff,
                goto out_unlock;
 
        do_for_each_ftrace_rec(pg, rec) {
-
                if (ftrace_match_record(rec, mod, search, search_len, type)) {
                        ret = enter_record(hash, rec, not);
                        if (ret < 0) {
@@ -2871,14 +3105,14 @@ out_unlock:
        return ret;
 }
 
-static ssize_t
+ssize_t
 ftrace_filter_write(struct file *file, const char __user *ubuf,
                    size_t cnt, loff_t *ppos)
 {
        return ftrace_regex_write(file, ubuf, cnt, ppos, 1);
 }
 
-static ssize_t
+ssize_t
 ftrace_notrace_write(struct file *file, const char __user *ubuf,
                     size_t cnt, loff_t *ppos)
 {
@@ -2919,7 +3153,7 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
        ret = ftrace_hash_move(ops, enable, orig_hash, hash);
        if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED
            && ftrace_enabled)
-               ftrace_run_update_code(FTRACE_ENABLE_CALLS);
+               ftrace_run_update_code(FTRACE_UPDATE_CALLS);
 
        mutex_unlock(&ftrace_lock);
 
@@ -3045,8 +3279,8 @@ static void __init set_ftrace_early_graph(char *buf)
 }
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 
-static void __init
-set_ftrace_early_filter(struct ftrace_ops *ops, char *buf, int enable)
+void __init
+ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable)
 {
        char *func;
 
@@ -3059,17 +3293,16 @@ set_ftrace_early_filter(struct ftrace_ops *ops, char *buf, int enable)
 static void __init set_ftrace_early_filters(void)
 {
        if (ftrace_filter_buf[0])
-               set_ftrace_early_filter(&global_ops, ftrace_filter_buf, 1);
+               ftrace_set_early_filter(&global_ops, ftrace_filter_buf, 1);
        if (ftrace_notrace_buf[0])
-               set_ftrace_early_filter(&global_ops, ftrace_notrace_buf, 0);
+               ftrace_set_early_filter(&global_ops, ftrace_notrace_buf, 0);
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        if (ftrace_graph_buf[0])
                set_ftrace_early_graph(ftrace_graph_buf);
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 }
 
-static int
-ftrace_regex_release(struct inode *inode, struct file *file)
+int ftrace_regex_release(struct inode *inode, struct file *file)
 {
        struct seq_file *m = (struct seq_file *)file->private_data;
        struct ftrace_iterator *iter;
@@ -3107,7 +3340,7 @@ ftrace_regex_release(struct inode *inode, struct file *file)
                                       orig_hash, iter->hash);
                if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED)
                    && ftrace_enabled)
-                       ftrace_run_update_code(FTRACE_ENABLE_CALLS);
+                       ftrace_run_update_code(FTRACE_UPDATE_CALLS);
 
                mutex_unlock(&ftrace_lock);
        }
@@ -3270,9 +3503,6 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer)
 
        do_for_each_ftrace_rec(pg, rec) {
 
-               if (rec->flags & FTRACE_FL_FREE)
-                       continue;
-
                if (ftrace_match_record(rec, NULL, search, search_len, type)) {
                        /* if it is in the array */
                        exists = false;
@@ -3381,15 +3611,62 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer)
        return 0;
 }
 
+static void ftrace_swap_recs(void *a, void *b, int size)
+{
+       struct dyn_ftrace *reca = a;
+       struct dyn_ftrace *recb = b;
+       struct dyn_ftrace t;
+
+       t = *reca;
+       *reca = *recb;
+       *recb = t;
+}
+
 static int ftrace_process_locs(struct module *mod,
                               unsigned long *start,
                               unsigned long *end)
 {
+       struct ftrace_page *pg;
+       unsigned long count;
        unsigned long *p;
        unsigned long addr;
        unsigned long flags = 0; /* Shut up gcc */
+       int ret = -ENOMEM;
+
+       count = end - start;
+
+       if (!count)
+               return 0;
+
+       pg = ftrace_allocate_pages(count);
+       if (!pg)
+               return -ENOMEM;
 
        mutex_lock(&ftrace_lock);
+
+       /*
+        * Core and each module needs their own pages, as
+        * modules will free them when they are removed.
+        * Force a new page to be allocated for modules.
+        */
+       if (!mod) {
+               WARN_ON(ftrace_pages || ftrace_pages_start);
+               /* First initialization */
+               ftrace_pages = ftrace_pages_start = pg;
+       } else {
+               if (!ftrace_pages)
+                       goto out;
+
+               if (WARN_ON(ftrace_pages->next)) {
+                       /* Hmm, we have free pages? */
+                       while (ftrace_pages->next)
+                               ftrace_pages = ftrace_pages->next;
+               }
+
+               ftrace_pages->next = pg;
+               ftrace_pages = pg;
+       }
+
        p = start;
        while (p < end) {
                addr = ftrace_call_adjust(*p++);
@@ -3401,9 +3678,18 @@ static int ftrace_process_locs(struct module *mod,
                 */
                if (!addr)
                        continue;
-               ftrace_record_ip(addr);
+               if (!ftrace_record_ip(addr))
+                       break;
        }
 
+       /* These new locations need to be initialized */
+       ftrace_new_pgs = pg;
+
+       /* Make each individual set of pages sorted by ips */
+       for (; pg; pg = pg->next)
+               sort(pg->records, pg->index, sizeof(struct dyn_ftrace),
+                    ftrace_cmp_recs, ftrace_swap_recs);
+
        /*
         * We only need to disable interrupts on start up
         * because we are modifying code that an interrupt
@@ -3417,32 +3703,55 @@ static int ftrace_process_locs(struct module *mod,
        ftrace_update_code(mod);
        if (!mod)
                local_irq_restore(flags);
+       ret = 0;
+ out:
        mutex_unlock(&ftrace_lock);
 
-       return 0;
+       return ret;
 }
 
 #ifdef CONFIG_MODULES
+
+#define next_to_ftrace_page(p) container_of(p, struct ftrace_page, next)
+
 void ftrace_release_mod(struct module *mod)
 {
        struct dyn_ftrace *rec;
+       struct ftrace_page **last_pg;
        struct ftrace_page *pg;
+       int order;
 
        mutex_lock(&ftrace_lock);
 
        if (ftrace_disabled)
                goto out_unlock;
 
-       do_for_each_ftrace_rec(pg, rec) {
+       /*
+        * Each module has its own ftrace_pages, remove
+        * them from the list.
+        */
+       last_pg = &ftrace_pages_start;
+       for (pg = ftrace_pages_start; pg; pg = *last_pg) {
+               rec = &pg->records[0];
                if (within_module_core(rec->ip, mod)) {
                        /*
-                        * rec->ip is changed in ftrace_free_rec()
-                        * It should not between s and e if record was freed.
+                        * As core pages are first, the first
+                        * page should never be a module page.
                         */
-                       FTRACE_WARN_ON(rec->flags & FTRACE_FL_FREE);
-                       ftrace_free_rec(rec);
-               }
-       } while_for_each_ftrace_rec();
+                       if (WARN_ON(pg == ftrace_pages_start))
+                               goto out_unlock;
+
+                       /* Check if we are deleting the last page */
+                       if (pg == ftrace_pages)
+                               ftrace_pages = next_to_ftrace_page(last_pg);
+
+                       *last_pg = pg->next;
+                       order = get_count_order(pg->size / ENTRIES_PER_PAGE);
+                       free_pages((unsigned long)pg->records, order);
+                       kfree(pg);
+               } else
+                       last_pg = &pg->next;
+       }
  out_unlock:
        mutex_unlock(&ftrace_lock);
 }
index f04cc3136bd370b6fbf9007cb7067ec1476892d4..24aee71274518c6e98867b4b5c008ed6070919d7 100644 (file)
@@ -1738,11 +1738,121 @@ static int replace_system_preds(struct event_subsystem *system,
        return -ENOMEM;
 }
 
+static int create_filter_start(char *filter_str, bool set_str,
+                              struct filter_parse_state **psp,
+                              struct event_filter **filterp)
+{
+       struct event_filter *filter;
+       struct filter_parse_state *ps = NULL;
+       int err = 0;
+
+       WARN_ON_ONCE(*psp || *filterp);
+
+       /* allocate everything, and if any fails, free all and fail */
+       filter = __alloc_filter();
+       if (filter && set_str)
+               err = replace_filter_string(filter, filter_str);
+
+       ps = kzalloc(sizeof(*ps), GFP_KERNEL);
+
+       if (!filter || !ps || err) {
+               kfree(ps);
+               __free_filter(filter);
+               return -ENOMEM;
+       }
+
+       /* we're committed to creating a new filter */
+       *filterp = filter;
+       *psp = ps;
+
+       parse_init(ps, filter_ops, filter_str);
+       err = filter_parse(ps);
+       if (err && set_str)
+               append_filter_err(ps, filter);
+       return err;
+}
+
+static void create_filter_finish(struct filter_parse_state *ps)
+{
+       if (ps) {
+               filter_opstack_clear(ps);
+               postfix_clear(ps);
+               kfree(ps);
+       }
+}
+
+/**
+ * create_filter - create a filter for a ftrace_event_call
+ * @call: ftrace_event_call to create a filter for
+ * @filter_str: filter string
+ * @set_str: remember @filter_str and enable detailed error in filter
+ * @filterp: out param for created filter (always updated on return)
+ *
+ * Creates a filter for @call with @filter_str.  If @set_str is %true,
+ * @filter_str is copied and recorded in the new filter.
+ *
+ * On success, returns 0 and *@filterp points to the new filter.  On
+ * failure, returns -errno and *@filterp may point to %NULL or to a new
+ * filter.  In the latter case, the returned filter contains error
+ * information if @set_str is %true and the caller is responsible for
+ * freeing it.
+ */
+static int create_filter(struct ftrace_event_call *call,
+                        char *filter_str, bool set_str,
+                        struct event_filter **filterp)
+{
+       struct event_filter *filter = NULL;
+       struct filter_parse_state *ps = NULL;
+       int err;
+
+       err = create_filter_start(filter_str, set_str, &ps, &filter);
+       if (!err) {
+               err = replace_preds(call, filter, ps, filter_str, false);
+               if (err && set_str)
+                       append_filter_err(ps, filter);
+       }
+       create_filter_finish(ps);
+
+       *filterp = filter;
+       return err;
+}
+
+/**
+ * create_system_filter - create a filter for an event_subsystem
+ * @system: event_subsystem to create a filter for
+ * @filter_str: filter string
+ * @filterp: out param for created filter (always updated on return)
+ *
+ * Identical to create_filter() except that it creates a subsystem filter
+ * and always remembers @filter_str.
+ */
+static int create_system_filter(struct event_subsystem *system,
+                               char *filter_str, struct event_filter **filterp)
+{
+       struct event_filter *filter = NULL;
+       struct filter_parse_state *ps = NULL;
+       int err;
+
+       err = create_filter_start(filter_str, true, &ps, &filter);
+       if (!err) {
+               err = replace_system_preds(system, ps, filter_str);
+               if (!err) {
+                       /* System filters just show a default message */
+                       kfree(filter->filter_string);
+                       filter->filter_string = NULL;
+               } else {
+                       append_filter_err(ps, filter);
+               }
+       }
+       create_filter_finish(ps);
+
+       *filterp = filter;
+       return err;
+}
+
 int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
 {
-       struct filter_parse_state *ps;
        struct event_filter *filter;
-       struct event_filter *tmp;
        int err = 0;
 
        mutex_lock(&event_mutex);
@@ -1759,49 +1869,30 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
                goto out_unlock;
        }
 
-       err = -ENOMEM;
-       ps = kzalloc(sizeof(*ps), GFP_KERNEL);
-       if (!ps)
-               goto out_unlock;
-
-       filter = __alloc_filter();
-       if (!filter) {
-               kfree(ps);
-               goto out_unlock;
-       }
-
-       replace_filter_string(filter, filter_string);
-
-       parse_init(ps, filter_ops, filter_string);
-       err = filter_parse(ps);
-       if (err) {
-               append_filter_err(ps, filter);
-               goto out;
-       }
+       err = create_filter(call, filter_string, true, &filter);
 
-       err = replace_preds(call, filter, ps, filter_string, false);
-       if (err) {
-               filter_disable(call);
-               append_filter_err(ps, filter);
-       } else
-               call->flags |= TRACE_EVENT_FL_FILTERED;
-out:
        /*
         * Always swap the call filter with the new filter
         * even if there was an error. If there was an error
         * in the filter, we disable the filter and show the error
         * string
         */
-       tmp = call->filter;
-       rcu_assign_pointer(call->filter, filter);
-       if (tmp) {
-               /* Make sure the call is done with the filter */
-               synchronize_sched();
-               __free_filter(tmp);
+       if (filter) {
+               struct event_filter *tmp = call->filter;
+
+               if (!err)
+                       call->flags |= TRACE_EVENT_FL_FILTERED;
+               else
+                       filter_disable(call);
+
+               rcu_assign_pointer(call->filter, filter);
+
+               if (tmp) {
+                       /* Make sure the call is done with the filter */
+                       synchronize_sched();
+                       __free_filter(tmp);
+               }
        }
-       filter_opstack_clear(ps);
-       postfix_clear(ps);
-       kfree(ps);
 out_unlock:
        mutex_unlock(&event_mutex);
 
@@ -1811,7 +1902,6 @@ out_unlock:
 int apply_subsystem_event_filter(struct event_subsystem *system,
                                 char *filter_string)
 {
-       struct filter_parse_state *ps;
        struct event_filter *filter;
        int err = 0;
 
@@ -1835,48 +1925,19 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
                goto out_unlock;
        }
 
-       err = -ENOMEM;
-       ps = kzalloc(sizeof(*ps), GFP_KERNEL);
-       if (!ps)
-               goto out_unlock;
-
-       filter = __alloc_filter();
-       if (!filter)
-               goto out;
-
-       /* System filters just show a default message */
-       kfree(filter->filter_string);
-       filter->filter_string = NULL;
-
-       /*
-        * No event actually uses the system filter
-        * we can free it without synchronize_sched().
-        */
-       __free_filter(system->filter);
-       system->filter = filter;
-
-       parse_init(ps, filter_ops, filter_string);
-       err = filter_parse(ps);
-       if (err)
-               goto err_filter;
-
-       err = replace_system_preds(system, ps, filter_string);
-       if (err)
-               goto err_filter;
-
-out:
-       filter_opstack_clear(ps);
-       postfix_clear(ps);
-       kfree(ps);
+       err = create_system_filter(system, filter_string, &filter);
+       if (filter) {
+               /*
+                * No event actually uses the system filter
+                * we can free it without synchronize_sched().
+                */
+               __free_filter(system->filter);
+               system->filter = filter;
+       }
 out_unlock:
        mutex_unlock(&event_mutex);
 
        return err;
-
-err_filter:
-       replace_filter_string(filter, filter_string);
-       append_filter_err(ps, system->filter);
-       goto out;
 }
 
 #ifdef CONFIG_PERF_EVENTS
@@ -1894,7 +1955,6 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
 {
        int err;
        struct event_filter *filter;
-       struct filter_parse_state *ps;
        struct ftrace_event_call *call;
 
        mutex_lock(&event_mutex);
@@ -1909,33 +1969,10 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
        if (event->filter)
                goto out_unlock;
 
-       filter = __alloc_filter();
-       if (!filter) {
-               err = PTR_ERR(filter);
-               goto out_unlock;
-       }
-
-       err = -ENOMEM;
-       ps = kzalloc(sizeof(*ps), GFP_KERNEL);
-       if (!ps)
-               goto free_filter;
-
-       parse_init(ps, filter_ops, filter_str);
-       err = filter_parse(ps);
-       if (err)
-               goto free_ps;
-
-       err = replace_preds(call, filter, ps, filter_str, false);
+       err = create_filter(call, filter_str, false, &filter);
        if (!err)
                event->filter = filter;
-
-free_ps:
-       filter_opstack_clear(ps);
-       postfix_clear(ps);
-       kfree(ps);
-
-free_filter:
-       if (err)
+       else
                __free_filter(filter);
 
 out_unlock:
@@ -1954,43 +1991,6 @@ out_unlock:
 #define CREATE_TRACE_POINTS
 #include "trace_events_filter_test.h"
 
-static int test_get_filter(char *filter_str, struct ftrace_event_call *call,
-                          struct event_filter **pfilter)
-{
-       struct event_filter *filter;
-       struct filter_parse_state *ps;
-       int err = -ENOMEM;
-
-       filter = __alloc_filter();
-       if (!filter)
-               goto out;
-
-       ps = kzalloc(sizeof(*ps), GFP_KERNEL);
-       if (!ps)
-               goto free_filter;
-
-       parse_init(ps, filter_ops, filter_str);
-       err = filter_parse(ps);
-       if (err)
-               goto free_ps;
-
-       err = replace_preds(call, filter, ps, filter_str, false);
-       if (!err)
-               *pfilter = filter;
-
- free_ps:
-       filter_opstack_clear(ps);
-       postfix_clear(ps);
-       kfree(ps);
-
- free_filter:
-       if (err)
-               __free_filter(filter);
-
- out:
-       return err;
-}
-
 #define DATA_REC(m, va, vb, vc, vd, ve, vf, vg, vh, nvisit) \
 { \
        .filter = FILTER, \
@@ -2109,12 +2109,13 @@ static __init int ftrace_test_event_filter(void)
                struct test_filter_data_t *d = &test_filter_data[i];
                int err;
 
-               err = test_get_filter(d->filter, &event_ftrace_test_filter,
-                                     &filter);
+               err = create_filter(&event_ftrace_test_filter, d->filter,
+                                   false, &filter);
                if (err) {
                        printk(KERN_INFO
                               "Failed to get filter for '%s', err %d\n",
                               d->filter, err);
+                       __free_filter(filter);
                        break;
                }
 
index 77575b386d9743cd337962698d10bdd499d7a8c6..d4545f49242e2baa96a46b01f528f5fe94445742 100644 (file)
@@ -13,6 +13,9 @@
 #include <linux/sysctl.h>
 #include <linux/init.h>
 #include <linux/fs.h>
+
+#include <asm/setup.h>
+
 #include "trace.h"
 
 #define STACK_TRACE_ENTRIES 500
@@ -133,7 +136,6 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip)
 static struct ftrace_ops trace_ops __read_mostly =
 {
        .func = stack_trace_call,
-       .flags = FTRACE_OPS_FL_GLOBAL,
 };
 
 static ssize_t
@@ -311,6 +313,21 @@ static const struct file_operations stack_trace_fops = {
        .release        = seq_release,
 };
 
+static int
+stack_trace_filter_open(struct inode *inode, struct file *file)
+{
+       return ftrace_regex_open(&trace_ops, FTRACE_ITER_FILTER,
+                                inode, file);
+}
+
+static const struct file_operations stack_trace_filter_fops = {
+       .open = stack_trace_filter_open,
+       .read = seq_read,
+       .write = ftrace_filter_write,
+       .llseek = ftrace_regex_lseek,
+       .release = ftrace_regex_release,
+};
+
 int
 stack_trace_sysctl(struct ctl_table *table, int write,
                   void __user *buffer, size_t *lenp,
@@ -338,8 +355,13 @@ stack_trace_sysctl(struct ctl_table *table, int write,
        return ret;
 }
 
+static char stack_trace_filter_buf[COMMAND_LINE_SIZE+1] __initdata;
+
 static __init int enable_stacktrace(char *str)
 {
+       if (strncmp(str, "_filter=", 8) == 0)
+               strncpy(stack_trace_filter_buf, str+8, COMMAND_LINE_SIZE);
+
        stack_tracer_enabled = 1;
        last_stack_tracer_enabled = 1;
        return 1;
@@ -358,6 +380,12 @@ static __init int stack_trace_init(void)
        trace_create_file("stack_trace", 0444, d_tracer,
                        NULL, &stack_trace_fops);
 
+       trace_create_file("stack_trace_filter", 0444, d_tracer,
+                       NULL, &stack_trace_filter_fops);
+
+       if (stack_trace_filter_buf[0])
+               ftrace_set_early_filter(&trace_ops, stack_trace_filter_buf, 1);
+
        if (stack_tracer_enabled)
                register_ftrace_function(&trace_ops);
 
index db110b8ae0309a39cfdef20e75351b989431cf2a..f1539decd99d853d1a5c44fb3296072444aabf1a 100644 (file)
@@ -634,10 +634,11 @@ static int tracepoint_module_coming(struct module *mod)
        int ret = 0;
 
        /*
-        * We skip modules that tain the kernel, especially those with different
-        * module header (for forced load), to make sure we don't cause a crash.
+        * We skip modules that taint the kernel, especially those with different
+        * module headers (for forced load), to make sure we don't cause a crash.
+        * Staging and out-of-tree GPL modules are fine.
         */
-       if (mod->taints)
+       if (mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP)))
                return 0;
        mutex_lock(&tracepoints_mutex);
        tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL);
index 201e1b33d721bf2ff83e6cd5ca817ea243861c39..169eb7c598e54d42a78018ac2b1338811674afd5 100644 (file)
@@ -286,25 +286,24 @@ config CORDIC
          calculations are in fixed point. Module will be called cordic.
 
 config MPILIB
-       tristate "Multiprecision maths library"
+       tristate
        help
          Multiprecision maths library from GnuPG.
          It is used to implement RSA digital signature verification,
          which is used by IMA/EVM digital signature extension.
 
 config MPILIB_EXTRA
-       bool "Multiprecision maths library - additional sources"
+       bool
        depends on MPILIB
        help
-         Multiprecision maths library from GnuPG.
-         It is used to implement RSA digital signature verification,
-         which is used by IMA/EVM digital signature extension.
-         This code in unnecessary for RSA digital signature verification,
-         and can be compiled if needed.
+         Additional sources of multiprecision maths library from GnuPG.
+         This code is unnecessary for RSA digital signature verification,
+         but can be compiled if needed.
 
-config DIGSIG
-       tristate "In-kernel signature checker"
-       depends on KEYS
+config SIGNATURE
+       tristate
+       depends on KEYS && CRYPTO
+       select CRYPTO_SHA1
        select MPILIB
        help
          Digital signature verification. Currently only RSA is supported.
index 82928f5ea0494936e83e9751fb6a1e4107a6efc2..8745ac7d1f7553e9c32e225e160d652a929d9f41 100644 (file)
@@ -414,7 +414,7 @@ config SLUB_STATS
 
 config DEBUG_KMEMLEAK
        bool "Kernel memory leak detector"
-       depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \
+       depends on DEBUG_KERNEL && EXPERIMENTAL && \
                (X86 || ARM || PPC || MIPS || S390 || SPARC64 || SUPERH || MICROBLAZE || TILE)
 
        select DEBUG_FS
index dace162c7e1c2f063498ded701e5576f3c16b75a..d71aae1b01b364d7972837a562e765f6945e1955 100644 (file)
@@ -119,7 +119,7 @@ obj-$(CONFIG_CORDIC) += cordic.o
 obj-$(CONFIG_DQL) += dynamic_queue_limits.o
 
 obj-$(CONFIG_MPILIB) += mpi/
-obj-$(CONFIG_DIGSIG) += digsig.o
+obj-$(CONFIG_SIGNATURE) += digsig.o
 
 hostprogs-y    := gen_crc32table
 clean-files    := crc32table.h
index 5a7a2adf4c4c2aa8d64d881e0ff1739acbe8782c..4531294fa62f2cb5de592178ddca2c0afc223558 100644 (file)
@@ -279,7 +279,7 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
        ret = 0;
 exit_2:
        if (!input)
-               free(in_buf);
+               free(in_buf_save);
 exit_1:
        if (!output)
                free(out_buf);
index fe84bb978e3b5c42befda57c206edd0b68d61684..716802b774ea9a92d58828cb1d7e99356098016b 100644 (file)
@@ -255,6 +255,8 @@ void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign)
        if (!n)
                n++;            /* avoid zero length allocation */
        p = buffer = kmalloc(n, GFP_KERNEL);
+       if (!p)
+               return NULL;
 
        for (i = a->nlimbs - 1; i >= 0; i--) {
                alimb = a->d[i];
index d9df7454519cd546c71aa10adf14204bee86ef7f..dc63d08183945bd25e1c1f854f65cfd75b20b254 100644 (file)
 struct radix_tree_node {
        unsigned int    height;         /* Height from the bottom */
        unsigned int    count;
-       struct rcu_head rcu_head;
+       union {
+               struct radix_tree_node *parent; /* Used when ascending tree */
+               struct rcu_head rcu_head;       /* Used when freeing node */
+       };
        void __rcu      *slots[RADIX_TREE_MAP_SIZE];
        unsigned long   tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
 };
 
-struct radix_tree_path {
-       struct radix_tree_node *node;
-       int offset;
-};
-
 #define RADIX_TREE_INDEX_BITS  (8 /* CHAR_BIT */ * sizeof(unsigned long))
 #define RADIX_TREE_MAX_PATH (DIV_ROUND_UP(RADIX_TREE_INDEX_BITS, \
                                          RADIX_TREE_MAP_SHIFT))
@@ -256,6 +254,7 @@ static inline unsigned long radix_tree_maxindex(unsigned int height)
 static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
 {
        struct radix_tree_node *node;
+       struct radix_tree_node *slot;
        unsigned int height;
        int tag;
 
@@ -274,18 +273,23 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
                if (!(node = radix_tree_node_alloc(root)))
                        return -ENOMEM;
 
-               /* Increase the height.  */
-               node->slots[0] = indirect_to_ptr(root->rnode);
-
                /* Propagate the aggregated tag info into the new root */
                for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
                        if (root_tag_get(root, tag))
                                tag_set(node, tag, 0);
                }
 
+               /* Increase the height.  */
                newheight = root->height+1;
                node->height = newheight;
                node->count = 1;
+               node->parent = NULL;
+               slot = root->rnode;
+               if (newheight > 1) {
+                       slot = indirect_to_ptr(slot);
+                       slot->parent = node;
+               }
+               node->slots[0] = slot;
                node = ptr_to_indirect(node);
                rcu_assign_pointer(root->rnode, node);
                root->height = newheight;
@@ -331,6 +335,7 @@ int radix_tree_insert(struct radix_tree_root *root,
                        if (!(slot = radix_tree_node_alloc(root)))
                                return -ENOMEM;
                        slot->height = height;
+                       slot->parent = node;
                        if (node) {
                                rcu_assign_pointer(node->slots[offset], slot);
                                node->count++;
@@ -504,47 +509,41 @@ EXPORT_SYMBOL(radix_tree_tag_set);
 void *radix_tree_tag_clear(struct radix_tree_root *root,
                        unsigned long index, unsigned int tag)
 {
-       /*
-        * The radix tree path needs to be one longer than the maximum path
-        * since the "list" is null terminated.
-        */
-       struct radix_tree_path path[RADIX_TREE_MAX_PATH + 1], *pathp = path;
+       struct radix_tree_node *node = NULL;
        struct radix_tree_node *slot = NULL;
        unsigned int height, shift;
+       int uninitialized_var(offset);
 
        height = root->height;
        if (index > radix_tree_maxindex(height))
                goto out;
 
-       shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
-       pathp->node = NULL;
+       shift = height * RADIX_TREE_MAP_SHIFT;
        slot = indirect_to_ptr(root->rnode);
 
-       while (height > 0) {
-               int offset;
-
+       while (shift) {
                if (slot == NULL)
                        goto out;
 
+               shift -= RADIX_TREE_MAP_SHIFT;
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
-               pathp[1].offset = offset;
-               pathp[1].node = slot;
+               node = slot;
                slot = slot->slots[offset];
-               pathp++;
-               shift -= RADIX_TREE_MAP_SHIFT;
-               height--;
        }
 
        if (slot == NULL)
                goto out;
 
-       while (pathp->node) {
-               if (!tag_get(pathp->node, tag, pathp->offset))
+       while (node) {
+               if (!tag_get(node, tag, offset))
                        goto out;
-               tag_clear(pathp->node, tag, pathp->offset);
-               if (any_tag_set(pathp->node, tag))
+               tag_clear(node, tag, offset);
+               if (any_tag_set(node, tag))
                        goto out;
-               pathp--;
+
+               index >>= RADIX_TREE_MAP_SHIFT;
+               offset = index & RADIX_TREE_MAP_MASK;
+               node = node->parent;
        }
 
        /* clear the root's tag bit */
@@ -646,8 +645,7 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
                unsigned int iftag, unsigned int settag)
 {
        unsigned int height = root->height;
-       struct radix_tree_path path[height];
-       struct radix_tree_path *pathp = path;
+       struct radix_tree_node *node = NULL;
        struct radix_tree_node *slot;
        unsigned int shift;
        unsigned long tagged = 0;
@@ -671,14 +669,8 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
        slot = indirect_to_ptr(root->rnode);
 
-       /*
-        * we fill the path from (root->height - 2) to 0, leaving the index at
-        * (root->height - 1) as a terminator. Zero the node in the terminator
-        * so that we can use this to end walk loops back up the path.
-        */
-       path[height - 1].node = NULL;
-
        for (;;) {
+               unsigned long upindex;
                int offset;
 
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
@@ -686,12 +678,10 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
                        goto next;
                if (!tag_get(slot, iftag, offset))
                        goto next;
-               if (height > 1) {
+               if (shift) {
                        /* Go down one level */
-                       height--;
                        shift -= RADIX_TREE_MAP_SHIFT;
-                       path[height - 1].node = slot;
-                       path[height - 1].offset = offset;
+                       node = slot;
                        slot = slot->slots[offset];
                        continue;
                }
@@ -701,15 +691,27 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
                tag_set(slot, settag, offset);
 
                /* walk back up the path tagging interior nodes */
-               pathp = &path[0];
-               while (pathp->node) {
+               upindex = index;
+               while (node) {
+                       upindex >>= RADIX_TREE_MAP_SHIFT;
+                       offset = upindex & RADIX_TREE_MAP_MASK;
+
                        /* stop if we find a node with the tag already set */
-                       if (tag_get(pathp->node, settag, pathp->offset))
+                       if (tag_get(node, settag, offset))
                                break;
-                       tag_set(pathp->node, settag, pathp->offset);
-                       pathp++;
+                       tag_set(node, settag, offset);
+                       node = node->parent;
                }
 
+               /*
+                * Small optimization: now clear that node pointer.
+                * Since all of this slot's ancestors now have the tag set
+                * from setting it above, we have no further need to walk
+                * back up the tree setting tags, until we update slot to
+                * point to another radix_tree_node.
+                */
+               node = NULL;
+
 next:
                /* Go to next item at level determined by 'shift' */
                index = ((index >> shift) + 1) << shift;
@@ -724,8 +726,7 @@ next:
                         * last_index is guaranteed to be in the tree, what
                         * we do below cannot wander astray.
                         */
-                       slot = path[height - 1].node;
-                       height++;
+                       slot = slot->parent;
                        shift += RADIX_TREE_MAP_SHIFT;
                }
        }
@@ -1299,7 +1300,7 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
        /* try to shrink tree height */
        while (root->height > 0) {
                struct radix_tree_node *to_free = root->rnode;
-               void *newptr;
+               struct radix_tree_node *slot;
 
                BUG_ON(!radix_tree_is_indirect_ptr(to_free));
                to_free = indirect_to_ptr(to_free);
@@ -1320,10 +1321,12 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
                 * (to_free->slots[0]), it will be safe to dereference the new
                 * one (root->rnode) as far as dependent read barriers go.
                 */
-               newptr = to_free->slots[0];
-               if (root->height > 1)
-                       newptr = ptr_to_indirect(newptr);
-               root->rnode = newptr;
+               slot = to_free->slots[0];
+               if (root->height > 1) {
+                       slot->parent = NULL;
+                       slot = ptr_to_indirect(slot);
+               }
+               root->rnode = slot;
                root->height--;
 
                /*
@@ -1363,16 +1366,12 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
  */
 void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
 {
-       /*
-        * The radix tree path needs to be one longer than the maximum path
-        * since the "list" is null terminated.
-        */
-       struct radix_tree_path path[RADIX_TREE_MAX_PATH + 1], *pathp = path;
+       struct radix_tree_node *node = NULL;
        struct radix_tree_node *slot = NULL;
        struct radix_tree_node *to_free;
        unsigned int height, shift;
        int tag;
-       int offset;
+       int uninitialized_var(offset);
 
        height = root->height;
        if (index > radix_tree_maxindex(height))
@@ -1385,39 +1384,35 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
                goto out;
        }
        slot = indirect_to_ptr(slot);
-
-       shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
-       pathp->node = NULL;
+       shift = height * RADIX_TREE_MAP_SHIFT;
 
        do {
                if (slot == NULL)
                        goto out;
 
-               pathp++;
+               shift -= RADIX_TREE_MAP_SHIFT;
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
-               pathp->offset = offset;
-               pathp->node = slot;
+               node = slot;
                slot = slot->slots[offset];
-               shift -= RADIX_TREE_MAP_SHIFT;
-               height--;
-       } while (height > 0);
+       } while (shift);
 
        if (slot == NULL)
                goto out;
 
        /*
-        * Clear all tags associated with the just-deleted item
+        * Clear all tags associated with the item to be deleted.
+        * This way of doing it would be inefficient, but seldom is any set.
         */
        for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
-               if (tag_get(pathp->node, tag, pathp->offset))
+               if (tag_get(node, tag, offset))
                        radix_tree_tag_clear(root, index, tag);
        }
 
        to_free = NULL;
        /* Now free the nodes we do not need anymore */
-       while (pathp->node) {
-               pathp->node->slots[pathp->offset] = NULL;
-               pathp->node->count--;
+       while (node) {
+               node->slots[offset] = NULL;
+               node->count--;
                /*
                 * Queue the node for deferred freeing after the
                 * last reference to it disappears (set NULL, above).
@@ -1425,17 +1420,20 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
                if (to_free)
                        radix_tree_node_free(to_free);
 
-               if (pathp->node->count) {
-                       if (pathp->node == indirect_to_ptr(root->rnode))
+               if (node->count) {
+                       if (node == indirect_to_ptr(root->rnode))
                                radix_tree_shrink(root);
                        goto out;
                }
 
                /* Node with zero slots in use so free it */
-               to_free = pathp->node;
-               pathp--;
+               to_free = node;
 
+               index >>= RADIX_TREE_MAP_SHIFT;
+               offset = index & RADIX_TREE_MAP_MASK;
+               node = node->parent;
        }
+
        root_tag_clear_all(root);
        root->height = 0;
        root->rnode = NULL;
index e6670c34eb4950b8953eeedbe02fe52f29ec84bf..71a58f67f4817720a4eca34678b2353fa96863e6 100644 (file)
@@ -350,7 +350,7 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
                }
 
                if (!cc->sync)
-                       mode |= ISOLATE_CLEAN;
+                       mode |= ISOLATE_ASYNC_MIGRATE;
 
                /* Try isolate the page */
                if (__isolate_lru_page(page, mode, 0) != 0)
@@ -557,7 +557,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
                nr_migrate = cc->nr_migratepages;
                err = migrate_pages(&cc->migratepages, compaction_alloc,
                                (unsigned long)cc, false,
-                               cc->sync);
+                               cc->sync ? MIGRATE_SYNC_LIGHT : MIGRATE_ASYNC);
                update_nr_listpages(cc);
                nr_remaining = cc->nr_migratepages;
 
@@ -671,6 +671,7 @@ static int compact_node(int nid)
                        .nr_freepages = 0,
                        .nr_migratepages = 0,
                        .order = -1,
+                       .sync = true,
                };
 
                zone = &pgdat->node_zones[zoneid];
index c4ee2e918bea1c0aa140fde22d20164ba8eb357a..97f49ed35bd24fba29677857433814103949dd14 100644 (file)
@@ -393,24 +393,11 @@ EXPORT_SYMBOL(filemap_write_and_wait_range);
 int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
 {
        int error;
-       struct mem_cgroup *memcg = NULL;
 
        VM_BUG_ON(!PageLocked(old));
        VM_BUG_ON(!PageLocked(new));
        VM_BUG_ON(new->mapping);
 
-       /*
-        * This is not page migration, but prepare_migration and
-        * end_migration does enough work for charge replacement.
-        *
-        * In the longer term we probably want a specialized function
-        * for moving the charge from old to new in a more efficient
-        * manner.
-        */
-       error = mem_cgroup_prepare_migration(old, new, &memcg, gfp_mask);
-       if (error)
-               return error;
-
        error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
        if (!error) {
                struct address_space *mapping = old->mapping;
@@ -432,13 +419,12 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
                if (PageSwapBacked(new))
                        __inc_zone_page_state(new, NR_SHMEM);
                spin_unlock_irq(&mapping->tree_lock);
+               /* mem_cgroup codes must not be called under tree_lock */
+               mem_cgroup_replace_page_cache(old, new);
                radix_tree_preload_end();
                if (freepage)
                        freepage(old);
                page_cache_release(old);
-               mem_cgroup_end_migration(memcg, old, new, true);
-       } else {
-               mem_cgroup_end_migration(memcg, old, new, false);
        }
 
        return error;
index 36b3d988b4ef6ac8c263ee0732c1d08513afb04f..b3ffc21ce8010b9de9c92004e2a364326af8dc1b 100644 (file)
@@ -487,41 +487,68 @@ static struct attribute_group khugepaged_attr_group = {
        .attrs = khugepaged_attr,
        .name = "khugepaged",
 };
-#endif /* CONFIG_SYSFS */
 
-static int __init hugepage_init(void)
+static int __init hugepage_init_sysfs(struct kobject **hugepage_kobj)
 {
        int err;
-#ifdef CONFIG_SYSFS
-       static struct kobject *hugepage_kobj;
-#endif
-
-       err = -EINVAL;
-       if (!has_transparent_hugepage()) {
-               transparent_hugepage_flags = 0;
-               goto out;
-       }
 
-#ifdef CONFIG_SYSFS
-       err = -ENOMEM;
-       hugepage_kobj = kobject_create_and_add("transparent_hugepage", mm_kobj);
-       if (unlikely(!hugepage_kobj)) {
+       *hugepage_kobj = kobject_create_and_add("transparent_hugepage", mm_kobj);
+       if (unlikely(!*hugepage_kobj)) {
                printk(KERN_ERR "hugepage: failed kobject create\n");
-               goto out;
+               return -ENOMEM;
        }
 
-       err = sysfs_create_group(hugepage_kobj, &hugepage_attr_group);
+       err = sysfs_create_group(*hugepage_kobj, &hugepage_attr_group);
        if (err) {
                printk(KERN_ERR "hugepage: failed register hugeage group\n");
-               goto out;
+               goto delete_obj;
        }
 
-       err = sysfs_create_group(hugepage_kobj, &khugepaged_attr_group);
+       err = sysfs_create_group(*hugepage_kobj, &khugepaged_attr_group);
        if (err) {
                printk(KERN_ERR "hugepage: failed register hugeage group\n");
-               goto out;
+               goto remove_hp_group;
        }
-#endif
+
+       return 0;
+
+remove_hp_group:
+       sysfs_remove_group(*hugepage_kobj, &hugepage_attr_group);
+delete_obj:
+       kobject_put(*hugepage_kobj);
+       return err;
+}
+
+static void __init hugepage_exit_sysfs(struct kobject *hugepage_kobj)
+{
+       sysfs_remove_group(hugepage_kobj, &khugepaged_attr_group);
+       sysfs_remove_group(hugepage_kobj, &hugepage_attr_group);
+       kobject_put(hugepage_kobj);
+}
+#else
+static inline int hugepage_init_sysfs(struct kobject **hugepage_kobj)
+{
+       return 0;
+}
+
+static inline void hugepage_exit_sysfs(struct kobject *hugepage_kobj)
+{
+}
+#endif /* CONFIG_SYSFS */
+
+static int __init hugepage_init(void)
+{
+       int err;
+       struct kobject *hugepage_kobj;
+
+       if (!has_transparent_hugepage()) {
+               transparent_hugepage_flags = 0;
+               return -EINVAL;
+       }
+
+       err = hugepage_init_sysfs(&hugepage_kobj);
+       if (err)
+               return err;
 
        err = khugepaged_slab_init();
        if (err)
@@ -545,7 +572,9 @@ static int __init hugepage_init(void)
 
        set_recommended_min_free_kbytes();
 
+       return 0;
 out:
+       hugepage_exit_sysfs(hugepage_kobj);
        return err;
 }
 module_init(hugepage_init)
@@ -997,7 +1026,7 @@ out:
 }
 
 int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
-                pmd_t *pmd)
+                pmd_t *pmd, unsigned long addr)
 {
        int ret = 0;
 
@@ -1013,6 +1042,7 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
                        pgtable = get_pmd_huge_pte(tlb->mm);
                        page = pmd_page(*pmd);
                        pmd_clear(pmd);
+                       tlb_remove_pmd_tlb_entry(tlb, pmd, addr);
                        page_remove_rmap(page);
                        VM_BUG_ON(page_mapcount(page) < 0);
                        add_mm_counter(tlb->mm, MM_ANONPAGES, -HPAGE_PMD_NR);
@@ -1116,7 +1146,6 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                        entry = pmd_modify(entry, newprot);
                        set_pmd_at(mm, addr, pmd, entry);
                        spin_unlock(&vma->vm_mm->page_table_lock);
-                       flush_tlb_range(vma, addr, addr + HPAGE_PMD_SIZE);
                        ret = 1;
                }
        } else
@@ -1199,16 +1228,16 @@ static int __split_huge_page_splitting(struct page *page,
 static void __split_huge_page_refcount(struct page *page)
 {
        int i;
-       unsigned long head_index = page->index;
        struct zone *zone = page_zone(page);
-       int zonestat;
        int tail_count = 0;
 
        /* prevent PageLRU to go away from under us, and freeze lru stats */
        spin_lock_irq(&zone->lru_lock);
        compound_lock(page);
+       /* complete memcg works before add pages to LRU */
+       mem_cgroup_split_huge_fixup(page);
 
-       for (i = 1; i < HPAGE_PMD_NR; i++) {
+       for (i = HPAGE_PMD_NR - 1; i >= 1; i--) {
                struct page *page_tail = page + i;
 
                /* tail_page->_mapcount cannot change */
@@ -1271,14 +1300,13 @@ static void __split_huge_page_refcount(struct page *page)
                BUG_ON(page_tail->mapping);
                page_tail->mapping = page->mapping;
 
-               page_tail->index = ++head_index;
+               page_tail->index = page->index + i;
 
                BUG_ON(!PageAnon(page_tail));
                BUG_ON(!PageUptodate(page_tail));
                BUG_ON(!PageDirty(page_tail));
                BUG_ON(!PageSwapBacked(page_tail));
 
-               mem_cgroup_split_huge_fixup(page, page_tail);
 
                lru_add_page_tail(zone, page, page_tail);
        }
@@ -1288,15 +1316,6 @@ static void __split_huge_page_refcount(struct page *page)
        __dec_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES);
        __mod_zone_page_state(zone, NR_ANON_PAGES, HPAGE_PMD_NR);
 
-       /*
-        * A hugepage counts for HPAGE_PMD_NR pages on the LRU statistics,
-        * so adjust those appropriately if this page is on the LRU.
-        */
-       if (PageLRU(page)) {
-               zonestat = NR_LRU_BASE + page_lru(page);
-               __mod_zone_page_state(zone, zonestat, -(HPAGE_PMD_NR-1));
-       }
-
        ClearPageCompound(page);
        compound_unlock(page);
        spin_unlock_irq(&zone->lru_lock);
index f3b2a00fe9c1fa3b0d4d5bb0a419d439f00b6062..c833addd94d74703a90e9bed51d759726e77f280 100644 (file)
 
 #include <linux/kmemcheck.h>
 #include <linux/kmemleak.h>
+#include <linux/memory_hotplug.h>
 
 /*
  * Kmemleak configuration and common defines.
@@ -196,7 +197,9 @@ static atomic_t kmemleak_enabled = ATOMIC_INIT(0);
 static atomic_t kmemleak_initialized = ATOMIC_INIT(0);
 /* enables or disables early logging of the memory operations */
 static atomic_t kmemleak_early_log = ATOMIC_INIT(1);
-/* set if a fata kmemleak error has occurred */
+/* set if a kmemleak warning was issued */
+static atomic_t kmemleak_warning = ATOMIC_INIT(0);
+/* set if a fatal kmemleak error has occurred */
 static atomic_t kmemleak_error = ATOMIC_INIT(0);
 
 /* minimum and maximum address that may be valid pointers */
@@ -228,8 +231,10 @@ static int kmemleak_skip_disable;
 /* kmemleak operation type for early logging */
 enum {
        KMEMLEAK_ALLOC,
+       KMEMLEAK_ALLOC_PERCPU,
        KMEMLEAK_FREE,
        KMEMLEAK_FREE_PART,
+       KMEMLEAK_FREE_PERCPU,
        KMEMLEAK_NOT_LEAK,
        KMEMLEAK_IGNORE,
        KMEMLEAK_SCAN_AREA,
@@ -259,9 +264,10 @@ static void kmemleak_disable(void);
 /*
  * Print a warning and dump the stack trace.
  */
-#define kmemleak_warn(x...)    do {    \
-       pr_warning(x);                  \
-       dump_stack();                   \
+#define kmemleak_warn(x...)    do {            \
+       pr_warning(x);                          \
+       dump_stack();                           \
+       atomic_set(&kmemleak_warning, 1);       \
 } while (0)
 
 /*
@@ -403,8 +409,8 @@ static struct kmemleak_object *lookup_object(unsigned long ptr, int alias)
                object = prio_tree_entry(node, struct kmemleak_object,
                                         tree_node);
                if (!alias && object->pointer != ptr) {
-                       pr_warning("Found object by alias at 0x%08lx\n", ptr);
-                       dump_stack();
+                       kmemleak_warn("Found object by alias at 0x%08lx\n",
+                                     ptr);
                        dump_object_info(object);
                        object = NULL;
                }
@@ -794,9 +800,13 @@ static void __init log_early(int op_type, const void *ptr, size_t size,
        unsigned long flags;
        struct early_log *log;
 
+       if (atomic_read(&kmemleak_error)) {
+               /* kmemleak stopped recording, just count the requests */
+               crt_early_log++;
+               return;
+       }
+
        if (crt_early_log >= ARRAY_SIZE(early_log)) {
-               pr_warning("Early log buffer exceeded, "
-                          "please increase DEBUG_KMEMLEAK_EARLY_LOG_SIZE\n");
                kmemleak_disable();
                return;
        }
@@ -811,8 +821,7 @@ static void __init log_early(int op_type, const void *ptr, size_t size,
        log->ptr = ptr;
        log->size = size;
        log->min_count = min_count;
-       if (op_type == KMEMLEAK_ALLOC)
-               log->trace_len = __save_stack_trace(log->trace);
+       log->trace_len = __save_stack_trace(log->trace);
        crt_early_log++;
        local_irq_restore(flags);
 }
@@ -846,6 +855,20 @@ out:
        rcu_read_unlock();
 }
 
+/*
+ * Log an early allocated block and populate the stack trace.
+ */
+static void early_alloc_percpu(struct early_log *log)
+{
+       unsigned int cpu;
+       const void __percpu *ptr = log->ptr;
+
+       for_each_possible_cpu(cpu) {
+               log->ptr = per_cpu_ptr(ptr, cpu);
+               early_alloc(log);
+       }
+}
+
 /**
  * kmemleak_alloc - register a newly allocated object
  * @ptr:       pointer to beginning of the object
@@ -872,6 +895,34 @@ void __ref kmemleak_alloc(const void *ptr, size_t size, int min_count,
 }
 EXPORT_SYMBOL_GPL(kmemleak_alloc);
 
+/**
+ * kmemleak_alloc_percpu - register a newly allocated __percpu object
+ * @ptr:       __percpu pointer to beginning of the object
+ * @size:      size of the object
+ *
+ * This function is called from the kernel percpu allocator when a new object
+ * (memory block) is allocated (alloc_percpu). It assumes GFP_KERNEL
+ * allocation.
+ */
+void __ref kmemleak_alloc_percpu(const void __percpu *ptr, size_t size)
+{
+       unsigned int cpu;
+
+       pr_debug("%s(0x%p, %zu)\n", __func__, ptr, size);
+
+       /*
+        * Percpu allocations are only scanned and not reported as leaks
+        * (min_count is set to 0).
+        */
+       if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
+               for_each_possible_cpu(cpu)
+                       create_object((unsigned long)per_cpu_ptr(ptr, cpu),
+                                     size, 0, GFP_KERNEL);
+       else if (atomic_read(&kmemleak_early_log))
+               log_early(KMEMLEAK_ALLOC_PERCPU, ptr, size, 0);
+}
+EXPORT_SYMBOL_GPL(kmemleak_alloc_percpu);
+
 /**
  * kmemleak_free - unregister a previously registered object
  * @ptr:       pointer to beginning of the object
@@ -910,6 +961,28 @@ void __ref kmemleak_free_part(const void *ptr, size_t size)
 }
 EXPORT_SYMBOL_GPL(kmemleak_free_part);
 
+/**
+ * kmemleak_free_percpu - unregister a previously registered __percpu object
+ * @ptr:       __percpu pointer to beginning of the object
+ *
+ * This function is called from the kernel percpu allocator when an object
+ * (memory block) is freed (free_percpu).
+ */
+void __ref kmemleak_free_percpu(const void __percpu *ptr)
+{
+       unsigned int cpu;
+
+       pr_debug("%s(0x%p)\n", __func__, ptr);
+
+       if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
+               for_each_possible_cpu(cpu)
+                       delete_object_full((unsigned long)per_cpu_ptr(ptr,
+                                                                     cpu));
+       else if (atomic_read(&kmemleak_early_log))
+               log_early(KMEMLEAK_FREE_PERCPU, ptr, 0, 0);
+}
+EXPORT_SYMBOL_GPL(kmemleak_free_percpu);
+
 /**
  * kmemleak_not_leak - mark an allocated object as false positive
  * @ptr:       pointer to beginning of the object
@@ -1220,9 +1293,9 @@ static void kmemleak_scan(void)
 #endif
 
        /*
-        * Struct page scanning for each node. The code below is not yet safe
-        * with MEMORY_HOTPLUG.
+        * Struct page scanning for each node.
         */
+       lock_memory_hotplug();
        for_each_online_node(i) {
                pg_data_t *pgdat = NODE_DATA(i);
                unsigned long start_pfn = pgdat->node_start_pfn;
@@ -1241,6 +1314,7 @@ static void kmemleak_scan(void)
                        scan_block(page, page + 1, NULL, 1);
                }
        }
+       unlock_memory_hotplug();
 
        /*
         * Scanning the task stacks (may introduce false negatives).
@@ -1467,9 +1541,6 @@ static const struct seq_operations kmemleak_seq_ops = {
 
 static int kmemleak_open(struct inode *inode, struct file *file)
 {
-       if (!atomic_read(&kmemleak_enabled))
-               return -EBUSY;
-
        return seq_open(file, &kmemleak_seq_ops);
 }
 
@@ -1543,6 +1614,9 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
        int buf_size;
        int ret;
 
+       if (!atomic_read(&kmemleak_enabled))
+               return -EBUSY;
+
        buf_size = min(size, (sizeof(buf) - 1));
        if (strncpy_from_user(buf, user_buf, buf_size) < 0)
                return -EFAULT;
@@ -1602,20 +1676,24 @@ static const struct file_operations kmemleak_fops = {
 };
 
 /*
- * Perform the freeing of the kmemleak internal objects after waiting for any
- * current memory scan to complete.
+ * Stop the memory scanning thread and free the kmemleak internal objects if
+ * no previous scan thread (otherwise, kmemleak may still have some useful
+ * information on memory leaks).
  */
 static void kmemleak_do_cleanup(struct work_struct *work)
 {
        struct kmemleak_object *object;
+       bool cleanup = scan_thread == NULL;
 
        mutex_lock(&scan_mutex);
        stop_scan_thread();
 
-       rcu_read_lock();
-       list_for_each_entry_rcu(object, &object_list, object_list)
-               delete_object_full(object->pointer);
-       rcu_read_unlock();
+       if (cleanup) {
+               rcu_read_lock();
+               list_for_each_entry_rcu(object, &object_list, object_list)
+                       delete_object_full(object->pointer);
+               rcu_read_unlock();
+       }
        mutex_unlock(&scan_mutex);
 }
 
@@ -1632,7 +1710,6 @@ static void kmemleak_disable(void)
                return;
 
        /* stop any memory operation tracing */
-       atomic_set(&kmemleak_early_log, 0);
        atomic_set(&kmemleak_enabled, 0);
 
        /* check whether it is too early for a kernel thread */
@@ -1659,6 +1736,17 @@ static int kmemleak_boot_config(char *str)
 }
 early_param("kmemleak", kmemleak_boot_config);
 
+static void __init print_log_trace(struct early_log *log)
+{
+       struct stack_trace trace;
+
+       trace.nr_entries = log->trace_len;
+       trace.entries = log->trace;
+
+       pr_notice("Early log backtrace:\n");
+       print_stack_trace(&trace, 2);
+}
+
 /*
  * Kmemleak initialization.
  */
@@ -1681,12 +1769,18 @@ void __init kmemleak_init(void)
        scan_area_cache = KMEM_CACHE(kmemleak_scan_area, SLAB_NOLEAKTRACE);
        INIT_PRIO_TREE_ROOT(&object_tree_root);
 
+       if (crt_early_log >= ARRAY_SIZE(early_log))
+               pr_warning("Early log buffer exceeded (%d), please increase "
+                          "DEBUG_KMEMLEAK_EARLY_LOG_SIZE\n", crt_early_log);
+
        /* the kernel is still in UP mode, so disabling the IRQs is enough */
        local_irq_save(flags);
-       if (!atomic_read(&kmemleak_error)) {
+       atomic_set(&kmemleak_early_log, 0);
+       if (atomic_read(&kmemleak_error)) {
+               local_irq_restore(flags);
+               return;
+       } else
                atomic_set(&kmemleak_enabled, 1);
-               atomic_set(&kmemleak_early_log, 0);
-       }
        local_irq_restore(flags);
 
        /*
@@ -1701,12 +1795,18 @@ void __init kmemleak_init(void)
                case KMEMLEAK_ALLOC:
                        early_alloc(log);
                        break;
+               case KMEMLEAK_ALLOC_PERCPU:
+                       early_alloc_percpu(log);
+                       break;
                case KMEMLEAK_FREE:
                        kmemleak_free(log->ptr);
                        break;
                case KMEMLEAK_FREE_PART:
                        kmemleak_free_part(log->ptr, log->size);
                        break;
+               case KMEMLEAK_FREE_PERCPU:
+                       kmemleak_free_percpu(log->ptr);
+                       break;
                case KMEMLEAK_NOT_LEAK:
                        kmemleak_not_leak(log->ptr);
                        break;
@@ -1720,7 +1820,13 @@ void __init kmemleak_init(void)
                        kmemleak_no_scan(log->ptr);
                        break;
                default:
-                       WARN_ON(1);
+                       kmemleak_warn("Unknown early log operation: %d\n",
+                                     log->op_type);
+               }
+
+               if (atomic_read(&kmemleak_warning)) {
+                       print_log_trace(log);
+                       atomic_set(&kmemleak_warning, 0);
                }
        }
 }
index 310544a379ae9c7b886b3b50815e5f3d5a991ba8..1925ffbfb27f00ac3d3d262ce0ea1c8aaa3a117f 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -28,6 +28,7 @@
 #include <linux/kthread.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
+#include <linux/memcontrol.h>
 #include <linux/rbtree.h>
 #include <linux/memory.h>
 #include <linux/mmu_notifier.h>
@@ -1571,6 +1572,16 @@ struct page *ksm_does_need_to_copy(struct page *page,
 
        new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
        if (new_page) {
+               /*
+                * The memcg-specific accounting when moving
+                * pages around the LRU lists relies on the
+                * page's owner (memcg) to be valid.  Usually,
+                * pages are assigned to a new owner before
+                * being put on the LRU list, but since this
+                * is not the case here, the stale owner from
+                * a previous allocation cycle must be reset.
+                */
+               mem_cgroup_reset_owner(new_page);
                copy_user_highpage(new_page, page, address, vma);
 
                SetPageDirty(new_page);
index d87aa3510c5e0a0e62e6c97ec6f0a85420c40d9d..3dbff4dcde35191a62b0245ac7ee185bc8fc7084 100644 (file)
@@ -123,16 +123,22 @@ struct mem_cgroup_stat_cpu {
        unsigned long targets[MEM_CGROUP_NTARGETS];
 };
 
+struct mem_cgroup_reclaim_iter {
+       /* css_id of the last scanned hierarchy member */
+       int position;
+       /* scan generation, increased every round-trip */
+       unsigned int generation;
+};
+
 /*
  * per-zone information in memory controller.
  */
 struct mem_cgroup_per_zone {
-       /*
-        * spin_lock to protect the per cgroup LRU
-        */
-       struct list_head        lists[NR_LRU_LISTS];
+       struct lruvec           lruvec;
        unsigned long           count[NR_LRU_LISTS];
 
+       struct mem_cgroup_reclaim_iter reclaim_iter[DEF_PRIORITY + 1];
+
        struct zone_reclaim_stat reclaim_stat;
        struct rb_node          tree_node;      /* RB tree node */
        unsigned long long      usage_in_excess;/* Set to the value by which */
@@ -233,11 +239,6 @@ struct mem_cgroup {
         * per zone LRU lists.
         */
        struct mem_cgroup_lru_info info;
-       /*
-        * While reclaiming in a hierarchy, we cache the last child we
-        * reclaimed from.
-        */
-       int last_scanned_child;
        int last_scanned_node;
 #if MAX_NUMNODES > 1
        nodemask_t      scan_nodes;
@@ -366,15 +367,12 @@ enum charge_type {
 #define MEM_CGROUP_RECLAIM_NOSWAP      (1 << MEM_CGROUP_RECLAIM_NOSWAP_BIT)
 #define MEM_CGROUP_RECLAIM_SHRINK_BIT  0x1
 #define MEM_CGROUP_RECLAIM_SHRINK      (1 << MEM_CGROUP_RECLAIM_SHRINK_BIT)
-#define MEM_CGROUP_RECLAIM_SOFT_BIT    0x2
-#define MEM_CGROUP_RECLAIM_SOFT                (1 << MEM_CGROUP_RECLAIM_SOFT_BIT)
 
 static void mem_cgroup_get(struct mem_cgroup *memcg);
 static void mem_cgroup_put(struct mem_cgroup *memcg);
 
 /* Writing them here to avoid exposing memcg's inner layout */
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
-#ifdef CONFIG_INET
 #include <net/sock.h>
 #include <net/ip.h>
 
@@ -421,6 +419,7 @@ void sock_release_memcg(struct sock *sk)
        }
 }
 
+#ifdef CONFIG_INET
 struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg)
 {
        if (!memcg || mem_cgroup_is_root(memcg))
@@ -566,7 +565,7 @@ static void mem_cgroup_remove_from_trees(struct mem_cgroup *memcg)
        struct mem_cgroup_per_zone *mz;
        struct mem_cgroup_tree_per_zone *mctz;
 
-       for_each_node_state(node, N_POSSIBLE) {
+       for_each_node(node) {
                for (zone = 0; zone < MAX_NR_ZONES; zone++) {
                        mz = mem_cgroup_zoneinfo(memcg, node, zone);
                        mctz = soft_limit_tree_node_zone(node, zone);
@@ -656,16 +655,6 @@ static void mem_cgroup_swap_statistics(struct mem_cgroup *memcg,
        this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_SWAPOUT], val);
 }
 
-void mem_cgroup_pgfault(struct mem_cgroup *memcg, int val)
-{
-       this_cpu_add(memcg->stat->events[MEM_CGROUP_EVENTS_PGFAULT], val);
-}
-
-void mem_cgroup_pgmajfault(struct mem_cgroup *memcg, int val)
-{
-       this_cpu_add(memcg->stat->events[MEM_CGROUP_EVENTS_PGMAJFAULT], val);
-}
-
 static unsigned long mem_cgroup_read_events(struct mem_cgroup *memcg,
                                            enum mem_cgroup_events_index idx)
 {
@@ -749,37 +738,32 @@ static unsigned long mem_cgroup_nr_lru_pages(struct mem_cgroup *memcg,
        return total;
 }
 
-static bool __memcg_event_check(struct mem_cgroup *memcg, int target)
+static bool mem_cgroup_event_ratelimit(struct mem_cgroup *memcg,
+                                      enum mem_cgroup_events_target target)
 {
        unsigned long val, next;
 
        val = __this_cpu_read(memcg->stat->events[MEM_CGROUP_EVENTS_COUNT]);
        next = __this_cpu_read(memcg->stat->targets[target]);
        /* from time_after() in jiffies.h */
-       return ((long)next - (long)val < 0);
-}
-
-static void __mem_cgroup_target_update(struct mem_cgroup *memcg, int target)
-{
-       unsigned long val, next;
-
-       val = __this_cpu_read(memcg->stat->events[MEM_CGROUP_EVENTS_COUNT]);
-
-       switch (target) {
-       case MEM_CGROUP_TARGET_THRESH:
-               next = val + THRESHOLDS_EVENTS_TARGET;
-               break;
-       case MEM_CGROUP_TARGET_SOFTLIMIT:
-               next = val + SOFTLIMIT_EVENTS_TARGET;
-               break;
-       case MEM_CGROUP_TARGET_NUMAINFO:
-               next = val + NUMAINFO_EVENTS_TARGET;
-               break;
-       default:
-               return;
+       if ((long)next - (long)val < 0) {
+               switch (target) {
+               case MEM_CGROUP_TARGET_THRESH:
+                       next = val + THRESHOLDS_EVENTS_TARGET;
+                       break;
+               case MEM_CGROUP_TARGET_SOFTLIMIT:
+                       next = val + SOFTLIMIT_EVENTS_TARGET;
+                       break;
+               case MEM_CGROUP_TARGET_NUMAINFO:
+                       next = val + NUMAINFO_EVENTS_TARGET;
+                       break;
+               default:
+                       break;
+               }
+               __this_cpu_write(memcg->stat->targets[target], next);
+               return true;
        }
-
-       __this_cpu_write(memcg->stat->targets[target], next);
+       return false;
 }
 
 /*
@@ -790,25 +774,27 @@ static void memcg_check_events(struct mem_cgroup *memcg, struct page *page)
 {
        preempt_disable();
        /* threshold event is triggered in finer grain than soft limit */
-       if (unlikely(__memcg_event_check(memcg, MEM_CGROUP_TARGET_THRESH))) {
+       if (unlikely(mem_cgroup_event_ratelimit(memcg,
+                                               MEM_CGROUP_TARGET_THRESH))) {
+               bool do_softlimit, do_numainfo;
+
+               do_softlimit = mem_cgroup_event_ratelimit(memcg,
+                                               MEM_CGROUP_TARGET_SOFTLIMIT);
+#if MAX_NUMNODES > 1
+               do_numainfo = mem_cgroup_event_ratelimit(memcg,
+                                               MEM_CGROUP_TARGET_NUMAINFO);
+#endif
+               preempt_enable();
+
                mem_cgroup_threshold(memcg);
-               __mem_cgroup_target_update(memcg, MEM_CGROUP_TARGET_THRESH);
-               if (unlikely(__memcg_event_check(memcg,
-                            MEM_CGROUP_TARGET_SOFTLIMIT))) {
+               if (unlikely(do_softlimit))
                        mem_cgroup_update_tree(memcg, page);
-                       __mem_cgroup_target_update(memcg,
-                                                  MEM_CGROUP_TARGET_SOFTLIMIT);
-               }
 #if MAX_NUMNODES > 1
-               if (unlikely(__memcg_event_check(memcg,
-                       MEM_CGROUP_TARGET_NUMAINFO))) {
+               if (unlikely(do_numainfo))
                        atomic_inc(&memcg->numainfo_events);
-                       __mem_cgroup_target_update(memcg,
-                               MEM_CGROUP_TARGET_NUMAINFO);
-               }
 #endif
-       }
-       preempt_enable();
+       } else
+               preempt_enable();
 }
 
 struct mem_cgroup *mem_cgroup_from_cont(struct cgroup *cont)
@@ -853,83 +839,116 @@ struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
        return memcg;
 }
 
-/* The caller has to guarantee "mem" exists before calling this */
-static struct mem_cgroup *mem_cgroup_start_loop(struct mem_cgroup *memcg)
+/**
+ * mem_cgroup_iter - iterate over memory cgroup hierarchy
+ * @root: hierarchy root
+ * @prev: previously returned memcg, NULL on first invocation
+ * @reclaim: cookie for shared reclaim walks, NULL for full walks
+ *
+ * Returns references to children of the hierarchy below @root, or
+ * @root itself, or %NULL after a full round-trip.
+ *
+ * Caller must pass the return value in @prev on subsequent
+ * invocations for reference counting, or use mem_cgroup_iter_break()
+ * to cancel a hierarchy walk before the round-trip is complete.
+ *
+ * Reclaimers can specify a zone and a priority level in @reclaim to
+ * divide up the memcgs in the hierarchy among all concurrent
+ * reclaimers operating on the same zone and priority.
+ */
+struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
+                                  struct mem_cgroup *prev,
+                                  struct mem_cgroup_reclaim_cookie *reclaim)
 {
-       struct cgroup_subsys_state *css;
-       int found;
+       struct mem_cgroup *memcg = NULL;
+       int id = 0;
 
-       if (!memcg) /* ROOT cgroup has the smallest ID */
-               return root_mem_cgroup; /*css_put/get against root is ignored*/
-       if (!memcg->use_hierarchy) {
-               if (css_tryget(&memcg->css))
-                       return memcg;
+       if (mem_cgroup_disabled())
                return NULL;
-       }
-       rcu_read_lock();
-       /*
-        * searching a memory cgroup which has the smallest ID under given
-        * ROOT cgroup. (ID >= 1)
-        */
-       css = css_get_next(&mem_cgroup_subsys, 1, &memcg->css, &found);
-       if (css && css_tryget(css))
-               memcg = container_of(css, struct mem_cgroup, css);
-       else
-               memcg = NULL;
-       rcu_read_unlock();
-       return memcg;
-}
 
-static struct mem_cgroup *mem_cgroup_get_next(struct mem_cgroup *iter,
-                                       struct mem_cgroup *root,
-                                       bool cond)
-{
-       int nextid = css_id(&iter->css) + 1;
-       int found;
-       int hierarchy_used;
-       struct cgroup_subsys_state *css;
+       if (!root)
+               root = root_mem_cgroup;
 
-       hierarchy_used = iter->use_hierarchy;
+       if (prev && !reclaim)
+               id = css_id(&prev->css);
 
-       css_put(&iter->css);
-       /* If no ROOT, walk all, ignore hierarchy */
-       if (!cond || (root && !hierarchy_used))
-               return NULL;
+       if (prev && prev != root)
+               css_put(&prev->css);
 
-       if (!root)
-               root = root_mem_cgroup;
+       if (!root->use_hierarchy && root != root_mem_cgroup) {
+               if (prev)
+                       return NULL;
+               return root;
+       }
 
-       do {
-               iter = NULL;
-               rcu_read_lock();
+       while (!memcg) {
+               struct mem_cgroup_reclaim_iter *uninitialized_var(iter);
+               struct cgroup_subsys_state *css;
 
-               css = css_get_next(&mem_cgroup_subsys, nextid,
-                               &root->css, &found);
-               if (css && css_tryget(css))
-                       iter = container_of(css, struct mem_cgroup, css);
+               if (reclaim) {
+                       int nid = zone_to_nid(reclaim->zone);
+                       int zid = zone_idx(reclaim->zone);
+                       struct mem_cgroup_per_zone *mz;
+
+                       mz = mem_cgroup_zoneinfo(root, nid, zid);
+                       iter = &mz->reclaim_iter[reclaim->priority];
+                       if (prev && reclaim->generation != iter->generation)
+                               return NULL;
+                       id = iter->position;
+               }
+
+               rcu_read_lock();
+               css = css_get_next(&mem_cgroup_subsys, id + 1, &root->css, &id);
+               if (css) {
+                       if (css == &root->css || css_tryget(css))
+                               memcg = container_of(css,
+                                                    struct mem_cgroup, css);
+               } else
+                       id = 0;
                rcu_read_unlock();
-               /* If css is NULL, no more cgroups will be found */
-               nextid = found + 1;
-       } while (css && !iter);
 
-       return iter;
+               if (reclaim) {
+                       iter->position = id;
+                       if (!css)
+                               iter->generation++;
+                       else if (!prev && memcg)
+                               reclaim->generation = iter->generation;
+               }
+
+               if (prev && !css)
+                       return NULL;
+       }
+       return memcg;
 }
-/*
- * for_eacn_mem_cgroup_tree() for visiting all cgroup under tree. Please
- * be careful that "break" loop is not allowed. We have reference count.
- * Instead of that modify "cond" to be false and "continue" to exit the loop.
- */
-#define for_each_mem_cgroup_tree_cond(iter, root, cond)        \
-       for (iter = mem_cgroup_start_loop(root);\
-            iter != NULL;\
-            iter = mem_cgroup_get_next(iter, root, cond))
 
-#define for_each_mem_cgroup_tree(iter, root) \
-       for_each_mem_cgroup_tree_cond(iter, root, true)
+/**
+ * mem_cgroup_iter_break - abort a hierarchy walk prematurely
+ * @root: hierarchy root
+ * @prev: last visited hierarchy member as returned by mem_cgroup_iter()
+ */
+void mem_cgroup_iter_break(struct mem_cgroup *root,
+                          struct mem_cgroup *prev)
+{
+       if (!root)
+               root = root_mem_cgroup;
+       if (prev && prev != root)
+               css_put(&prev->css);
+}
 
-#define for_each_mem_cgroup_all(iter) \
-       for_each_mem_cgroup_tree_cond(iter, NULL, true)
+/*
+ * Iteration constructs for visiting all cgroups (under a tree).  If
+ * loops are exited prematurely (break), mem_cgroup_iter_break() must
+ * be used for reference counting.
+ */
+#define for_each_mem_cgroup_tree(iter, root)           \
+       for (iter = mem_cgroup_iter(root, NULL, NULL);  \
+            iter != NULL;                              \
+            iter = mem_cgroup_iter(root, iter, NULL))
 
+#define for_each_mem_cgroup(iter)                      \
+       for (iter = mem_cgroup_iter(NULL, NULL, NULL);  \
+            iter != NULL;                              \
+            iter = mem_cgroup_iter(NULL, iter, NULL))
 
 static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg)
 {
@@ -949,11 +968,11 @@ void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx)
                goto out;
 
        switch (idx) {
-       case PGMAJFAULT:
-               mem_cgroup_pgmajfault(memcg, 1);
-               break;
        case PGFAULT:
-               mem_cgroup_pgfault(memcg, 1);
+               this_cpu_inc(memcg->stat->events[MEM_CGROUP_EVENTS_PGFAULT]);
+               break;
+       case PGMAJFAULT:
+               this_cpu_inc(memcg->stat->events[MEM_CGROUP_EVENTS_PGMAJFAULT]);
                break;
        default:
                BUG();
@@ -963,6 +982,27 @@ out:
 }
 EXPORT_SYMBOL(mem_cgroup_count_vm_event);
 
+/**
+ * mem_cgroup_zone_lruvec - get the lru list vector for a zone and memcg
+ * @zone: zone of the wanted lruvec
+ * @mem: memcg of the wanted lruvec
+ *
+ * Returns the lru list vector holding pages for the given @zone and
+ * @mem.  This can be the global zone lruvec, if the memory controller
+ * is disabled.
+ */
+struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone,
+                                     struct mem_cgroup *memcg)
+{
+       struct mem_cgroup_per_zone *mz;
+
+       if (mem_cgroup_disabled())
+               return &zone->lruvec;
+
+       mz = mem_cgroup_zoneinfo(memcg, zone_to_nid(zone), zone_idx(zone));
+       return &mz->lruvec;
+}
+
 /*
  * Following LRU functions are allowed to be used without PCG_LOCK.
  * Operations are called by routine of global LRU independently from memcg.
@@ -977,180 +1017,91 @@ EXPORT_SYMBOL(mem_cgroup_count_vm_event);
  * When moving account, the page is not on LRU. It's isolated.
  */
 
-void mem_cgroup_del_lru_list(struct page *page, enum lru_list lru)
-{
-       struct page_cgroup *pc;
-       struct mem_cgroup_per_zone *mz;
-
-       if (mem_cgroup_disabled())
-               return;
-       pc = lookup_page_cgroup(page);
-       /* can happen while we handle swapcache. */
-       if (!TestClearPageCgroupAcctLRU(pc))
-               return;
-       VM_BUG_ON(!pc->mem_cgroup);
-       /*
-        * We don't check PCG_USED bit. It's cleared when the "page" is finally
-        * removed from global LRU.
-        */
-       mz = page_cgroup_zoneinfo(pc->mem_cgroup, page);
-       /* huge page split is done under lru_lock. so, we have no races. */
-       MEM_CGROUP_ZSTAT(mz, lru) -= 1 << compound_order(page);
-       if (mem_cgroup_is_root(pc->mem_cgroup))
-               return;
-       VM_BUG_ON(list_empty(&pc->lru));
-       list_del_init(&pc->lru);
-}
-
-void mem_cgroup_del_lru(struct page *page)
-{
-       mem_cgroup_del_lru_list(page, page_lru(page));
-}
-
-/*
- * Writeback is about to end against a page which has been marked for immediate
- * reclaim.  If it still appears to be reclaimable, move it to the tail of the
- * inactive list.
+/**
+ * mem_cgroup_lru_add_list - account for adding an lru page and return lruvec
+ * @zone: zone of the page
+ * @page: the page
+ * @lru: current lru
+ *
+ * This function accounts for @page being added to @lru, and returns
+ * the lruvec for the given @zone and the memcg @page is charged to.
+ *
+ * The callsite is then responsible for physically linking the page to
+ * the returned lruvec->lists[@lru].
  */
-void mem_cgroup_rotate_reclaimable_page(struct page *page)
+struct lruvec *mem_cgroup_lru_add_list(struct zone *zone, struct page *page,
+                                      enum lru_list lru)
 {
        struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup *memcg;
        struct page_cgroup *pc;
-       enum lru_list lru = page_lru(page);
 
        if (mem_cgroup_disabled())
-               return;
+               return &zone->lruvec;
 
        pc = lookup_page_cgroup(page);
-       /* unused or root page is not rotated. */
-       if (!PageCgroupUsed(pc))
-               return;
-       /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
-       smp_rmb();
-       if (mem_cgroup_is_root(pc->mem_cgroup))
-               return;
-       mz = page_cgroup_zoneinfo(pc->mem_cgroup, page);
-       list_move_tail(&pc->lru, &mz->lists[lru]);
+       memcg = pc->mem_cgroup;
+       mz = page_cgroup_zoneinfo(memcg, page);
+       /* compound_order() is stabilized through lru_lock */
+       MEM_CGROUP_ZSTAT(mz, lru) += 1 << compound_order(page);
+       return &mz->lruvec;
 }
 
-void mem_cgroup_rotate_lru_list(struct page *page, enum lru_list lru)
+/**
+ * mem_cgroup_lru_del_list - account for removing an lru page
+ * @page: the page
+ * @lru: target lru
+ *
+ * This function accounts for @page being removed from @lru.
+ *
+ * The callsite is then responsible for physically unlinking
+ * @page->lru.
+ */
+void mem_cgroup_lru_del_list(struct page *page, enum lru_list lru)
 {
        struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup *memcg;
        struct page_cgroup *pc;
 
        if (mem_cgroup_disabled())
                return;
 
        pc = lookup_page_cgroup(page);
-       /* unused or root page is not rotated. */
-       if (!PageCgroupUsed(pc))
-               return;
-       /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
-       smp_rmb();
-       if (mem_cgroup_is_root(pc->mem_cgroup))
-               return;
-       mz = page_cgroup_zoneinfo(pc->mem_cgroup, page);
-       list_move(&pc->lru, &mz->lists[lru]);
-}
-
-void mem_cgroup_add_lru_list(struct page *page, enum lru_list lru)
-{
-       struct page_cgroup *pc;
-       struct mem_cgroup_per_zone *mz;
-
-       if (mem_cgroup_disabled())
-               return;
-       pc = lookup_page_cgroup(page);
-       VM_BUG_ON(PageCgroupAcctLRU(pc));
-       /*
-        * putback:                             charge:
-        * SetPageLRU                           SetPageCgroupUsed
-        * smp_mb                               smp_mb
-        * PageCgroupUsed && add to memcg LRU   PageLRU && add to memcg LRU
-        *
-        * Ensure that one of the two sides adds the page to the memcg
-        * LRU during a race.
-        */
-       smp_mb();
-       if (!PageCgroupUsed(pc))
-               return;
-       /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
-       smp_rmb();
-       mz = page_cgroup_zoneinfo(pc->mem_cgroup, page);
+       memcg = pc->mem_cgroup;
+       VM_BUG_ON(!memcg);
+       mz = page_cgroup_zoneinfo(memcg, page);
        /* huge page split is done under lru_lock. so, we have no races. */
-       MEM_CGROUP_ZSTAT(mz, lru) += 1 << compound_order(page);
-       SetPageCgroupAcctLRU(pc);
-       if (mem_cgroup_is_root(pc->mem_cgroup))
-               return;
-       list_add(&pc->lru, &mz->lists[lru]);
-}
-
-/*
- * At handling SwapCache and other FUSE stuff, pc->mem_cgroup may be changed
- * while it's linked to lru because the page may be reused after it's fully
- * uncharged. To handle that, unlink page_cgroup from LRU when charge it again.
- * It's done under lock_page and expected that zone->lru_lock isnever held.
- */
-static void mem_cgroup_lru_del_before_commit(struct page *page)
-{
-       unsigned long flags;
-       struct zone *zone = page_zone(page);
-       struct page_cgroup *pc = lookup_page_cgroup(page);
-
-       /*
-        * Doing this check without taking ->lru_lock seems wrong but this
-        * is safe. Because if page_cgroup's USED bit is unset, the page
-        * will not be added to any memcg's LRU. If page_cgroup's USED bit is
-        * set, the commit after this will fail, anyway.
-        * This all charge/uncharge is done under some mutual execustion.
-        * So, we don't need to taking care of changes in USED bit.
-        */
-       if (likely(!PageLRU(page)))
-               return;
-
-       spin_lock_irqsave(&zone->lru_lock, flags);
-       /*
-        * Forget old LRU when this page_cgroup is *not* used. This Used bit
-        * is guarded by lock_page() because the page is SwapCache.
-        */
-       if (!PageCgroupUsed(pc))
-               mem_cgroup_del_lru_list(page, page_lru(page));
-       spin_unlock_irqrestore(&zone->lru_lock, flags);
+       VM_BUG_ON(MEM_CGROUP_ZSTAT(mz, lru) < (1 << compound_order(page)));
+       MEM_CGROUP_ZSTAT(mz, lru) -= 1 << compound_order(page);
 }
 
-static void mem_cgroup_lru_add_after_commit(struct page *page)
+void mem_cgroup_lru_del(struct page *page)
 {
-       unsigned long flags;
-       struct zone *zone = page_zone(page);
-       struct page_cgroup *pc = lookup_page_cgroup(page);
-       /*
-        * putback:                             charge:
-        * SetPageLRU                           SetPageCgroupUsed
-        * smp_mb                               smp_mb
-        * PageCgroupUsed && add to memcg LRU   PageLRU && add to memcg LRU
-        *
-        * Ensure that one of the two sides adds the page to the memcg
-        * LRU during a race.
-        */
-       smp_mb();
-       /* taking care of that the page is added to LRU while we commit it */
-       if (likely(!PageLRU(page)))
-               return;
-       spin_lock_irqsave(&zone->lru_lock, flags);
-       /* link when the page is linked to LRU but page_cgroup isn't */
-       if (PageLRU(page) && !PageCgroupAcctLRU(pc))
-               mem_cgroup_add_lru_list(page, page_lru(page));
-       spin_unlock_irqrestore(&zone->lru_lock, flags);
+       mem_cgroup_lru_del_list(page, page_lru(page));
 }
 
-
-void mem_cgroup_move_lists(struct page *page,
-                          enum lru_list from, enum lru_list to)
+/**
+ * mem_cgroup_lru_move_lists - account for moving a page between lrus
+ * @zone: zone of the page
+ * @page: the page
+ * @from: current lru
+ * @to: target lru
+ *
+ * This function accounts for @page being moved between the lrus @from
+ * and @to, and returns the lruvec for the given @zone and the memcg
+ * @page is charged to.
+ *
+ * The callsite is then responsible for physically relinking
+ * @page->lru to the returned lruvec->lists[@to].
+ */
+struct lruvec *mem_cgroup_lru_move_lists(struct zone *zone,
+                                        struct page *page,
+                                        enum lru_list from,
+                                        enum lru_list to)
 {
-       if (mem_cgroup_disabled())
-               return;
-       mem_cgroup_del_lru_list(page, from);
-       mem_cgroup_add_lru_list(page, to);
+       /* XXX: Optimize this, especially for @from == @to */
+       mem_cgroup_lru_del_list(page, from);
+       return mem_cgroup_lru_add_list(zone, page, to);
 }
 
 /*
@@ -1175,10 +1126,21 @@ int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg)
        struct task_struct *p;
 
        p = find_lock_task_mm(task);
-       if (!p)
-               return 0;
-       curr = try_get_mem_cgroup_from_mm(p->mm);
-       task_unlock(p);
+       if (p) {
+               curr = try_get_mem_cgroup_from_mm(p->mm);
+               task_unlock(p);
+       } else {
+               /*
+                * All threads may have already detached their mm's, but the oom
+                * killer still needs to detect if they have already been oom
+                * killed to prevent needlessly killing additional tasks.
+                */
+               task_lock(task);
+               curr = mem_cgroup_from_task(task);
+               if (curr)
+                       css_get(&curr->css);
+               task_unlock(task);
+       }
        if (!curr)
                return 0;
        /*
@@ -1258,68 +1220,6 @@ mem_cgroup_get_reclaim_stat_from_page(struct page *page)
        return &mz->reclaim_stat;
 }
 
-unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
-                                       struct list_head *dst,
-                                       unsigned long *scanned, int order,
-                                       isolate_mode_t mode,
-                                       struct zone *z,
-                                       struct mem_cgroup *mem_cont,
-                                       int active, int file)
-{
-       unsigned long nr_taken = 0;
-       struct page *page;
-       unsigned long scan;
-       LIST_HEAD(pc_list);
-       struct list_head *src;
-       struct page_cgroup *pc, *tmp;
-       int nid = zone_to_nid(z);
-       int zid = zone_idx(z);
-       struct mem_cgroup_per_zone *mz;
-       int lru = LRU_FILE * file + active;
-       int ret;
-
-       BUG_ON(!mem_cont);
-       mz = mem_cgroup_zoneinfo(mem_cont, nid, zid);
-       src = &mz->lists[lru];
-
-       scan = 0;
-       list_for_each_entry_safe_reverse(pc, tmp, src, lru) {
-               if (scan >= nr_to_scan)
-                       break;
-
-               if (unlikely(!PageCgroupUsed(pc)))
-                       continue;
-
-               page = lookup_cgroup_page(pc);
-
-               if (unlikely(!PageLRU(page)))
-                       continue;
-
-               scan++;
-               ret = __isolate_lru_page(page, mode, file);
-               switch (ret) {
-               case 0:
-                       list_move(&page->lru, dst);
-                       mem_cgroup_del_lru(page);
-                       nr_taken += hpage_nr_pages(page);
-                       break;
-               case -EBUSY:
-                       /* we don't affect global LRU but rotate in our LRU */
-                       mem_cgroup_rotate_lru_list(page, page_lru(page));
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       *scanned = scan;
-
-       trace_mm_vmscan_memcg_isolate(0, nr_to_scan, scan, nr_taken,
-                                     0, 0, 0, mode);
-
-       return nr_taken;
-}
-
 #define mem_cgroup_from_res_counter(counter, member)   \
        container_of(counter, struct mem_cgroup, member)
 
@@ -1536,41 +1436,40 @@ u64 mem_cgroup_get_limit(struct mem_cgroup *memcg)
        return min(limit, memsw);
 }
 
-/*
- * Visit the first child (need not be the first child as per the ordering
- * of the cgroup list, since we track last_scanned_child) of @mem and use
- * that to reclaim free pages from.
- */
-static struct mem_cgroup *
-mem_cgroup_select_victim(struct mem_cgroup *root_memcg)
+static unsigned long mem_cgroup_reclaim(struct mem_cgroup *memcg,
+                                       gfp_t gfp_mask,
+                                       unsigned long flags)
 {
-       struct mem_cgroup *ret = NULL;
-       struct cgroup_subsys_state *css;
-       int nextid, found;
+       unsigned long total = 0;
+       bool noswap = false;
+       int loop;
 
-       if (!root_memcg->use_hierarchy) {
-               css_get(&root_memcg->css);
-               ret = root_memcg;
-       }
-
-       while (!ret) {
-               rcu_read_lock();
-               nextid = root_memcg->last_scanned_child + 1;
-               css = css_get_next(&mem_cgroup_subsys, nextid, &root_memcg->css,
-                                  &found);
-               if (css && css_tryget(css))
-                       ret = container_of(css, struct mem_cgroup, css);
+       if (flags & MEM_CGROUP_RECLAIM_NOSWAP)
+               noswap = true;
+       if (!(flags & MEM_CGROUP_RECLAIM_SHRINK) && memcg->memsw_is_minimum)
+               noswap = true;
 
-               rcu_read_unlock();
-               /* Updates scanning parameter */
-               if (!css) {
-                       /* this means start scan from ID:1 */
-                       root_memcg->last_scanned_child = 0;
-               } else
-                       root_memcg->last_scanned_child = found;
+       for (loop = 0; loop < MEM_CGROUP_MAX_RECLAIM_LOOPS; loop++) {
+               if (loop)
+                       drain_all_stock_async(memcg);
+               total += try_to_free_mem_cgroup_pages(memcg, gfp_mask, noswap);
+               /*
+                * Allow limit shrinkers, which are triggered directly
+                * by userspace, to catch signals and stop reclaim
+                * after minimal progress, regardless of the margin.
+                */
+               if (total && (flags & MEM_CGROUP_RECLAIM_SHRINK))
+                       break;
+               if (mem_cgroup_margin(memcg))
+                       break;
+               /*
+                * If nothing was reclaimed after two attempts, there
+                * may be no reclaimable pages in this hierarchy.
+                */
+               if (loop && !total)
+                       break;
        }
-
-       return ret;
+       return total;
 }
 
 /**
@@ -1710,61 +1609,35 @@ bool mem_cgroup_reclaimable(struct mem_cgroup *memcg, bool noswap)
 }
 #endif
 
-/*
- * Scan the hierarchy if needed to reclaim memory. We remember the last child
- * we reclaimed from, so that we don't end up penalizing one child extensively
- * based on its position in the children list.
- *
- * root_memcg is the original ancestor that we've been reclaim from.
- *
- * We give up and return to the caller when we visit root_memcg twice.
- * (other groups can be removed while we're walking....)
- *
- * If shrink==true, for avoiding to free too much, this returns immedieately.
- */
-static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_memcg,
-                                               struct zone *zone,
-                                               gfp_t gfp_mask,
-                                               unsigned long reclaim_options,
-                                               unsigned long *total_scanned)
-{
-       struct mem_cgroup *victim;
-       int ret, total = 0;
+static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
+                                  struct zone *zone,
+                                  gfp_t gfp_mask,
+                                  unsigned long *total_scanned)
+{
+       struct mem_cgroup *victim = NULL;
+       int total = 0;
        int loop = 0;
-       bool noswap = reclaim_options & MEM_CGROUP_RECLAIM_NOSWAP;
-       bool shrink = reclaim_options & MEM_CGROUP_RECLAIM_SHRINK;
-       bool check_soft = reclaim_options & MEM_CGROUP_RECLAIM_SOFT;
        unsigned long excess;
        unsigned long nr_scanned;
+       struct mem_cgroup_reclaim_cookie reclaim = {
+               .zone = zone,
+               .priority = 0,
+       };
 
        excess = res_counter_soft_limit_excess(&root_memcg->res) >> PAGE_SHIFT;
 
-       /* If memsw_is_minimum==1, swap-out is of-no-use. */
-       if (!check_soft && !shrink && root_memcg->memsw_is_minimum)
-               noswap = true;
-
        while (1) {
-               victim = mem_cgroup_select_victim(root_memcg);
-               if (victim == root_memcg) {
+               victim = mem_cgroup_iter(root_memcg, victim, &reclaim);
+               if (!victim) {
                        loop++;
-                       /*
-                        * We are not draining per cpu cached charges during
-                        * soft limit reclaim  because global reclaim doesn't
-                        * care about charges. It tries to free some memory and
-                        * charges will not give any.
-                        */
-                       if (!check_soft && loop >= 1)
-                               drain_all_stock_async(root_memcg);
                        if (loop >= 2) {
                                /*
                                 * If we have not been able to reclaim
                                 * anything, it might because there are
                                 * no reclaimable pages under this hierarchy
                                 */
-                               if (!check_soft || !total) {
-                                       css_put(&victim->css);
+                               if (!total)
                                        break;
-                               }
                                /*
                                 * We want to do more targeted reclaim.
                                 * excess >> 2 is not to excessive so as to
@@ -1772,40 +1645,20 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_memcg,
                                 * coming back to reclaim from this cgroup
                                 */
                                if (total >= (excess >> 2) ||
-                                       (loop > MEM_CGROUP_MAX_RECLAIM_LOOPS)) {
-                                       css_put(&victim->css);
+                                       (loop > MEM_CGROUP_MAX_RECLAIM_LOOPS))
                                        break;
-                               }
                        }
-               }
-               if (!mem_cgroup_reclaimable(victim, noswap)) {
-                       /* this cgroup's local usage == 0 */
-                       css_put(&victim->css);
                        continue;
                }
-               /* we use swappiness of local cgroup */
-               if (check_soft) {
-                       ret = mem_cgroup_shrink_node_zone(victim, gfp_mask,
-                               noswap, zone, &nr_scanned);
-                       *total_scanned += nr_scanned;
-               } else
-                       ret = try_to_free_mem_cgroup_pages(victim, gfp_mask,
-                                               noswap);
-               css_put(&victim->css);
-               /*
-                * At shrinking usage, we can't check we should stop here or
-                * reclaim more. It's depends on callers. last_scanned_child
-                * will work enough for keeping fairness under tree.
-                */
-               if (shrink)
-                       return ret;
-               total += ret;
-               if (check_soft) {
-                       if (!res_counter_soft_limit_excess(&root_memcg->res))
-                               return total;
-               } else if (mem_cgroup_margin(root_memcg))
-                       return total;
+               if (!mem_cgroup_reclaimable(victim, false))
+                       continue;
+               total += mem_cgroup_shrink_node_zone(victim, gfp_mask, false,
+                                                    zone, &nr_scanned);
+               *total_scanned += nr_scanned;
+               if (!res_counter_soft_limit_excess(&root_memcg->res))
+                       break;
        }
+       mem_cgroup_iter_break(root_memcg, victim);
        return total;
 }
 
@@ -1817,16 +1670,16 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_memcg,
 static bool mem_cgroup_oom_lock(struct mem_cgroup *memcg)
 {
        struct mem_cgroup *iter, *failed = NULL;
-       bool cond = true;
 
-       for_each_mem_cgroup_tree_cond(iter, memcg, cond) {
+       for_each_mem_cgroup_tree(iter, memcg) {
                if (iter->oom_lock) {
                        /*
                         * this subtree of our hierarchy is already locked
                         * so we cannot give a lock.
                         */
                        failed = iter;
-                       cond = false;
+                       mem_cgroup_iter_break(memcg, iter);
+                       break;
                } else
                        iter->oom_lock = true;
        }
@@ -1838,11 +1691,10 @@ static bool mem_cgroup_oom_lock(struct mem_cgroup *memcg)
         * OK, we failed to lock the whole subtree so we have to clean up
         * what we set up to the failing subtree
         */
-       cond = true;
-       for_each_mem_cgroup_tree_cond(iter, memcg, cond) {
+       for_each_mem_cgroup_tree(iter, memcg) {
                if (iter == failed) {
-                       cond = false;
-                       continue;
+                       mem_cgroup_iter_break(memcg, iter);
+                       break;
                }
                iter->oom_lock = false;
        }
@@ -2007,7 +1859,7 @@ void mem_cgroup_update_page_stat(struct page *page,
        bool need_unlock = false;
        unsigned long uninitialized_var(flags);
 
-       if (unlikely(!pc))
+       if (mem_cgroup_disabled())
                return;
 
        rcu_read_lock();
@@ -2238,7 +2090,7 @@ static int __cpuinit memcg_cpu_hotplug_callback(struct notifier_block *nb,
        struct mem_cgroup *iter;
 
        if ((action == CPU_ONLINE)) {
-               for_each_mem_cgroup_all(iter)
+               for_each_mem_cgroup(iter)
                        synchronize_mem_cgroup_on_move(iter, cpu);
                return NOTIFY_OK;
        }
@@ -2246,7 +2098,7 @@ static int __cpuinit memcg_cpu_hotplug_callback(struct notifier_block *nb,
        if ((action != CPU_DEAD) || action != CPU_DEAD_FROZEN)
                return NOTIFY_OK;
 
-       for_each_mem_cgroup_all(iter)
+       for_each_mem_cgroup(iter)
                mem_cgroup_drain_pcp_counter(iter, cpu);
 
        stock = &per_cpu(memcg_stock, cpu);
@@ -2300,8 +2152,7 @@ static int mem_cgroup_do_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
        if (!(gfp_mask & __GFP_WAIT))
                return CHARGE_WOULDBLOCK;
 
-       ret = mem_cgroup_hierarchical_reclaim(mem_over_limit, NULL,
-                                             gfp_mask, flags, NULL);
+       ret = mem_cgroup_reclaim(mem_over_limit, gfp_mask, flags);
        if (mem_cgroup_margin(mem_over_limit) >= nr_pages)
                return CHARGE_RETRY;
        /*
@@ -2334,8 +2185,25 @@ static int mem_cgroup_do_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
 }
 
 /*
- * Unlike exported interface, "oom" parameter is added. if oom==true,
- * oom-killer can be invoked.
+ * __mem_cgroup_try_charge() does
+ * 1. detect memcg to be charged against from passed *mm and *ptr,
+ * 2. update res_counter
+ * 3. call memory reclaim if necessary.
+ *
+ * In some special case, if the task is fatal, fatal_signal_pending() or
+ * has TIF_MEMDIE, this function returns -EINTR while writing root_mem_cgroup
+ * to *ptr. There are two reasons for this. 1: fatal threads should quit as soon
+ * as possible without any hazards. 2: all pages should have a valid
+ * pc->mem_cgroup. If mm is NULL and the caller doesn't pass a valid memcg
+ * pointer, that is treated as a charge to root_mem_cgroup.
+ *
+ * So __mem_cgroup_try_charge() will return
+ *  0       ...  on success, filling *ptr with a valid memcg pointer.
+ *  -ENOMEM ...  charge failure because of resource limits.
+ *  -EINTR  ...  if thread is fatal. *ptr is filled with root_mem_cgroup.
+ *
+ * Unlike the exported interface, an "oom" parameter is added. if oom==true,
+ * the oom-killer can be invoked.
  */
 static int __mem_cgroup_try_charge(struct mm_struct *mm,
                                   gfp_t gfp_mask,
@@ -2364,7 +2232,7 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm,
         * set, if so charge the init_mm (happens for pagecache usage).
         */
        if (!*ptr && !mm)
-               goto bypass;
+               *ptr = root_mem_cgroup;
 again:
        if (*ptr) { /* css should be a valid one */
                memcg = *ptr;
@@ -2390,7 +2258,9 @@ again:
                 * task-struct. So, mm->owner can be NULL.
                 */
                memcg = mem_cgroup_from_task(p);
-               if (!memcg || mem_cgroup_is_root(memcg)) {
+               if (!memcg)
+                       memcg = root_mem_cgroup;
+               if (mem_cgroup_is_root(memcg)) {
                        rcu_read_unlock();
                        goto done;
                }
@@ -2465,8 +2335,8 @@ nomem:
        *ptr = NULL;
        return -ENOMEM;
 bypass:
-       *ptr = NULL;
-       return 0;
+       *ptr = root_mem_cgroup;
+       return -EINTR;
 }
 
 /*
@@ -2522,7 +2392,7 @@ struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page)
                        memcg = NULL;
        } else if (PageSwapCache(page)) {
                ent.val = page_private(page);
-               id = lookup_swap_cgroup(ent);
+               id = lookup_swap_cgroup_id(ent);
                rcu_read_lock();
                memcg = mem_cgroup_lookup(id);
                if (memcg && !css_tryget(&memcg->css))
@@ -2574,6 +2444,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
 
        mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), nr_pages);
        unlock_page_cgroup(pc);
+       WARN_ON_ONCE(PageLRU(page));
        /*
         * "charge_statistics" updated event counter. Then, check it.
         * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
@@ -2585,44 +2456,29 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 
 #define PCGF_NOCOPY_AT_SPLIT ((1 << PCG_LOCK) | (1 << PCG_MOVE_LOCK) |\
-                       (1 << PCG_ACCT_LRU) | (1 << PCG_MIGRATION))
+                       (1 << PCG_MIGRATION))
 /*
  * Because tail pages are not marked as "used", set it. We're under
- * zone->lru_lock, 'splitting on pmd' and compund_lock.
+ * zone->lru_lock, 'splitting on pmd' and compound_lock.
+ * charge/uncharge will be never happen and move_account() is done under
+ * compound_lock(), so we don't have to take care of races.
  */
-void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail)
+void mem_cgroup_split_huge_fixup(struct page *head)
 {
        struct page_cgroup *head_pc = lookup_page_cgroup(head);
-       struct page_cgroup *tail_pc = lookup_page_cgroup(tail);
-       unsigned long flags;
+       struct page_cgroup *pc;
+       int i;
 
        if (mem_cgroup_disabled())
                return;
-       /*
-        * We have no races with charge/uncharge but will have races with
-        * page state accounting.
-        */
-       move_lock_page_cgroup(head_pc, &flags);
-
-       tail_pc->mem_cgroup = head_pc->mem_cgroup;
-       smp_wmb(); /* see __commit_charge() */
-       if (PageCgroupAcctLRU(head_pc)) {
-               enum lru_list lru;
-               struct mem_cgroup_per_zone *mz;
-
-               /*
-                * LRU flags cannot be copied because we need to add tail
-                *.page to LRU by generic call and our hook will be called.
-                * We hold lru_lock, then, reduce counter directly.
-                */
-               lru = page_lru(head);
-               mz = page_cgroup_zoneinfo(head_pc->mem_cgroup, head);
-               MEM_CGROUP_ZSTAT(mz, lru) -= 1;
+       for (i = 1; i < HPAGE_PMD_NR; i++) {
+               pc = head_pc + i;
+               pc->mem_cgroup = head_pc->mem_cgroup;
+               smp_wmb();/* see __commit_charge() */
+               pc->flags = head_pc->flags & ~PCGF_NOCOPY_AT_SPLIT;
        }
-       tail_pc->flags = head_pc->flags & ~PCGF_NOCOPY_AT_SPLIT;
-       move_unlock_page_cgroup(head_pc, &flags);
 }
-#endif
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 /**
  * mem_cgroup_move_account - move account of the page
@@ -2737,7 +2593,7 @@ static int mem_cgroup_move_parent(struct page *page,
 
        parent = mem_cgroup_from_cont(pcg);
        ret = __mem_cgroup_try_charge(NULL, gfp_mask, nr_pages, &parent, false);
-       if (ret || !parent)
+       if (ret)
                goto put_back;
 
        if (nr_pages > 1)
@@ -2783,12 +2639,9 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
        }
 
        pc = lookup_page_cgroup(page);
-       BUG_ON(!pc); /* XXX: remove this and move pc lookup into commit */
-
        ret = __mem_cgroup_try_charge(mm, gfp_mask, nr_pages, &memcg, oom);
-       if (ret || !memcg)
+       if (ret == -ENOMEM)
                return ret;
-
        __mem_cgroup_commit_charge(memcg, page, nr_pages, pc, ctype);
        return 0;
 }
@@ -2798,19 +2651,11 @@ int mem_cgroup_newpage_charge(struct page *page,
 {
        if (mem_cgroup_disabled())
                return 0;
-       /*
-        * If already mapped, we don't have to account.
-        * If page cache, page->mapping has address_space.
-        * But page->mapping may have out-of-use anon_vma pointer,
-        * detecit it by PageAnon() check. newly-mapped-anon's page->mapping
-        * is NULL.
-        */
-       if (page_mapped(page) || (page->mapping && !PageAnon(page)))
-               return 0;
-       if (unlikely(!mm))
-               mm = &init_mm;
+       VM_BUG_ON(page_mapped(page));
+       VM_BUG_ON(page->mapping && !PageAnon(page));
+       VM_BUG_ON(!mm);
        return mem_cgroup_charge_common(page, mm, gfp_mask,
-                               MEM_CGROUP_CHARGE_TYPE_MAPPED);
+                                       MEM_CGROUP_CHARGE_TYPE_MAPPED);
 }
 
 static void
@@ -2822,14 +2667,27 @@ __mem_cgroup_commit_charge_lrucare(struct page *page, struct mem_cgroup *memcg,
                                        enum charge_type ctype)
 {
        struct page_cgroup *pc = lookup_page_cgroup(page);
+       struct zone *zone = page_zone(page);
+       unsigned long flags;
+       bool removed = false;
+
        /*
         * In some case, SwapCache, FUSE(splice_buf->radixtree), the page
         * is already on LRU. It means the page may on some other page_cgroup's
         * LRU. Take care of it.
         */
-       mem_cgroup_lru_del_before_commit(page);
+       spin_lock_irqsave(&zone->lru_lock, flags);
+       if (PageLRU(page)) {
+               del_page_from_lru_list(zone, page, page_lru(page));
+               ClearPageLRU(page);
+               removed = true;
+       }
        __mem_cgroup_commit_charge(memcg, page, 1, pc, ctype);
-       mem_cgroup_lru_add_after_commit(page);
+       if (removed) {
+               add_page_to_lru_list(zone, page, page_lru(page));
+               SetPageLRU(page);
+       }
+       spin_unlock_irqrestore(&zone->lru_lock, flags);
        return;
 }
 
@@ -2837,6 +2695,7 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                                gfp_t gfp_mask)
 {
        struct mem_cgroup *memcg = NULL;
+       enum charge_type type = MEM_CGROUP_CHARGE_TYPE_CACHE;
        int ret;
 
        if (mem_cgroup_disabled())
@@ -2846,31 +2705,16 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
 
        if (unlikely(!mm))
                mm = &init_mm;
+       if (!page_is_file_cache(page))
+               type = MEM_CGROUP_CHARGE_TYPE_SHMEM;
 
-       if (page_is_file_cache(page)) {
-               ret = __mem_cgroup_try_charge(mm, gfp_mask, 1, &memcg, true);
-               if (ret || !memcg)
-                       return ret;
-
-               /*
-                * FUSE reuses pages without going through the final
-                * put that would remove them from the LRU list, make
-                * sure that they get relinked properly.
-                */
-               __mem_cgroup_commit_charge_lrucare(page, memcg,
-                                       MEM_CGROUP_CHARGE_TYPE_CACHE);
-               return ret;
-       }
-       /* shmem */
-       if (PageSwapCache(page)) {
+       if (!PageSwapCache(page))
+               ret = mem_cgroup_charge_common(page, mm, gfp_mask, type);
+       else { /* page is swapcache/shmem */
                ret = mem_cgroup_try_charge_swapin(mm, page, gfp_mask, &memcg);
                if (!ret)
-                       __mem_cgroup_commit_charge_swapin(page, memcg,
-                                       MEM_CGROUP_CHARGE_TYPE_SHMEM);
-       } else
-               ret = mem_cgroup_charge_common(page, mm, gfp_mask,
-                                       MEM_CGROUP_CHARGE_TYPE_SHMEM);
-
+                       __mem_cgroup_commit_charge_swapin(page, memcg, type);
+       }
        return ret;
 }
 
@@ -2882,12 +2726,12 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
  */
 int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
                                 struct page *page,
-                                gfp_t mask, struct mem_cgroup **ptr)
+                                gfp_t mask, struct mem_cgroup **memcgp)
 {
        struct mem_cgroup *memcg;
        int ret;
 
-       *ptr = NULL;
+       *memcgp = NULL;
 
        if (mem_cgroup_disabled())
                return 0;
@@ -2905,27 +2749,32 @@ int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
        memcg = try_get_mem_cgroup_from_page(page);
        if (!memcg)
                goto charge_cur_mm;
-       *ptr = memcg;
-       ret = __mem_cgroup_try_charge(NULL, mask, 1, ptr, true);
+       *memcgp = memcg;
+       ret = __mem_cgroup_try_charge(NULL, mask, 1, memcgp, true);
        css_put(&memcg->css);
+       if (ret == -EINTR)
+               ret = 0;
        return ret;
 charge_cur_mm:
        if (unlikely(!mm))
                mm = &init_mm;
-       return __mem_cgroup_try_charge(mm, mask, 1, ptr, true);
+       ret = __mem_cgroup_try_charge(mm, mask, 1, memcgp, true);
+       if (ret == -EINTR)
+               ret = 0;
+       return ret;
 }
 
 static void
-__mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
+__mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *memcg,
                                        enum charge_type ctype)
 {
        if (mem_cgroup_disabled())
                return;
-       if (!ptr)
+       if (!memcg)
                return;
-       cgroup_exclude_rmdir(&ptr->css);
+       cgroup_exclude_rmdir(&memcg->css);
 
-       __mem_cgroup_commit_charge_lrucare(page, ptr, ctype);
+       __mem_cgroup_commit_charge_lrucare(page, memcg, ctype);
        /*
         * Now swap is on-memory. This means this page may be
         * counted both as mem and swap....double count.
@@ -2935,21 +2784,22 @@ __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
         */
        if (do_swap_account && PageSwapCache(page)) {
                swp_entry_t ent = {.val = page_private(page)};
+               struct mem_cgroup *swap_memcg;
                unsigned short id;
-               struct mem_cgroup *memcg;
 
                id = swap_cgroup_record(ent, 0);
                rcu_read_lock();
-               memcg = mem_cgroup_lookup(id);
-               if (memcg) {
+               swap_memcg = mem_cgroup_lookup(id);
+               if (swap_memcg) {
                        /*
                         * This recorded memcg can be obsolete one. So, avoid
                         * calling css_tryget
                         */
-                       if (!mem_cgroup_is_root(memcg))
-                               res_counter_uncharge(&memcg->memsw, PAGE_SIZE);
-                       mem_cgroup_swap_statistics(memcg, false);
-                       mem_cgroup_put(memcg);
+                       if (!mem_cgroup_is_root(swap_memcg))
+                               res_counter_uncharge(&swap_memcg->memsw,
+                                                    PAGE_SIZE);
+                       mem_cgroup_swap_statistics(swap_memcg, false);
+                       mem_cgroup_put(swap_memcg);
                }
                rcu_read_unlock();
        }
@@ -2958,13 +2808,14 @@ __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
         * So, rmdir()->pre_destroy() can be called while we do this charge.
         * In that case, we need to call pre_destroy() again. check it here.
         */
-       cgroup_release_and_wakeup_rmdir(&ptr->css);
+       cgroup_release_and_wakeup_rmdir(&memcg->css);
 }
 
-void mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr)
+void mem_cgroup_commit_charge_swapin(struct page *page,
+                                    struct mem_cgroup *memcg)
 {
-       __mem_cgroup_commit_charge_swapin(page, ptr,
-                                       MEM_CGROUP_CHARGE_TYPE_MAPPED);
+       __mem_cgroup_commit_charge_swapin(page, memcg,
+                                         MEM_CGROUP_CHARGE_TYPE_MAPPED);
 }
 
 void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *memcg)
@@ -3054,7 +2905,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
         * Check if our page_cgroup is valid
         */
        pc = lookup_page_cgroup(page);
-       if (unlikely(!pc || !PageCgroupUsed(pc)))
+       if (unlikely(!PageCgroupUsed(pc)))
                return NULL;
 
        lock_page_cgroup(pc);
@@ -3117,8 +2968,7 @@ void mem_cgroup_uncharge_page(struct page *page)
        /* early check. */
        if (page_mapped(page))
                return;
-       if (page->mapping && !PageAnon(page))
-               return;
+       VM_BUG_ON(page->mapping && !PageAnon(page));
        __mem_cgroup_uncharge_common(page, MEM_CGROUP_CHARGE_TYPE_MAPPED);
 }
 
@@ -3176,6 +3026,23 @@ void mem_cgroup_uncharge_end(void)
        batch->memcg = NULL;
 }
 
+/*
+ * A function for resetting pc->mem_cgroup for newly allocated pages.
+ * This function should be called if the newpage will be added to LRU
+ * before start accounting.
+ */
+void mem_cgroup_reset_owner(struct page *newpage)
+{
+       struct page_cgroup *pc;
+
+       if (mem_cgroup_disabled())
+               return;
+
+       pc = lookup_page_cgroup(newpage);
+       VM_BUG_ON(PageCgroupUsed(pc));
+       pc->mem_cgroup = root_mem_cgroup;
+}
+
 #ifdef CONFIG_SWAP
 /*
  * called after __delete_from_swap_cache() and drop "page" account.
@@ -3293,14 +3160,14 @@ static inline int mem_cgroup_move_swap_account(swp_entry_t entry,
  * page belongs to.
  */
 int mem_cgroup_prepare_migration(struct page *page,
-       struct page *newpage, struct mem_cgroup **ptr, gfp_t gfp_mask)
+       struct page *newpage, struct mem_cgroup **memcgp, gfp_t gfp_mask)
 {
        struct mem_cgroup *memcg = NULL;
        struct page_cgroup *pc;
        enum charge_type ctype;
        int ret = 0;
 
-       *ptr = NULL;
+       *memcgp = NULL;
 
        VM_BUG_ON(PageTransHuge(page));
        if (mem_cgroup_disabled())
@@ -3351,10 +3218,10 @@ int mem_cgroup_prepare_migration(struct page *page,
        if (!memcg)
                return 0;
 
-       *ptr = memcg;
-       ret = __mem_cgroup_try_charge(NULL, gfp_mask, 1, ptr, false);
+       *memcgp = memcg;
+       ret = __mem_cgroup_try_charge(NULL, gfp_mask, 1, memcgp, false);
        css_put(&memcg->css);/* drop extra refcnt */
-       if (ret || *ptr == NULL) {
+       if (ret) {
                if (PageAnon(page)) {
                        lock_page_cgroup(pc);
                        ClearPageCgroupMigration(pc);
@@ -3364,6 +3231,7 @@ int mem_cgroup_prepare_migration(struct page *page,
                         */
                        mem_cgroup_uncharge_page(page);
                }
+               /* we'll need to revisit this error code (we have -EINTR) */
                return -ENOMEM;
        }
        /*
@@ -3432,12 +3300,51 @@ void mem_cgroup_end_migration(struct mem_cgroup *memcg,
        cgroup_release_and_wakeup_rmdir(&memcg->css);
 }
 
+/*
+ * At replace page cache, newpage is not under any memcg but it's on
+ * LRU. So, this function doesn't touch res_counter but handles LRU
+ * in correct way. Both pages are locked so we cannot race with uncharge.
+ */
+void mem_cgroup_replace_page_cache(struct page *oldpage,
+                                 struct page *newpage)
+{
+       struct mem_cgroup *memcg;
+       struct page_cgroup *pc;
+       enum charge_type type = MEM_CGROUP_CHARGE_TYPE_CACHE;
+
+       if (mem_cgroup_disabled())
+               return;
+
+       pc = lookup_page_cgroup(oldpage);
+       /* fix accounting on old pages */
+       lock_page_cgroup(pc);
+       memcg = pc->mem_cgroup;
+       mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), -1);
+       ClearPageCgroupUsed(pc);
+       unlock_page_cgroup(pc);
+
+       if (PageSwapBacked(oldpage))
+               type = MEM_CGROUP_CHARGE_TYPE_SHMEM;
+
+       /*
+        * Even if newpage->mapping was NULL before starting replacement,
+        * the newpage may be on LRU(or pagevec for LRU) already. We lock
+        * LRU while we overwrite pc->mem_cgroup.
+        */
+       __mem_cgroup_commit_charge_lrucare(newpage, memcg, type);
+}
+
 #ifdef CONFIG_DEBUG_VM
 static struct page_cgroup *lookup_page_cgroup_used(struct page *page)
 {
        struct page_cgroup *pc;
 
        pc = lookup_page_cgroup(page);
+       /*
+        * Can be NULL while feeding pages into the page allocator for
+        * the first time, i.e. during boot or memory hotplug;
+        * or when mem_cgroup_disabled().
+        */
        if (likely(pc) && PageCgroupUsed(pc))
                return pc;
        return NULL;
@@ -3457,23 +3364,8 @@ void mem_cgroup_print_bad_page(struct page *page)
 
        pc = lookup_page_cgroup_used(page);
        if (pc) {
-               int ret = -1;
-               char *path;
-
-               printk(KERN_ALERT "pc:%p pc->flags:%lx pc->mem_cgroup:%p",
+               printk(KERN_ALERT "pc:%p pc->flags:%lx pc->mem_cgroup:%p\n",
                       pc, pc->flags, pc->mem_cgroup);
-
-               path = kmalloc(PATH_MAX, GFP_KERNEL);
-               if (path) {
-                       rcu_read_lock();
-                       ret = cgroup_path(pc->mem_cgroup->css.cgroup,
-                                                       path, PATH_MAX);
-                       rcu_read_unlock();
-               }
-
-               printk(KERN_CONT "(%s)\n",
-                               (ret < 0) ? "cannot get the path" : path);
-               kfree(path);
        }
 }
 #endif
@@ -3534,9 +3426,8 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                if (!ret)
                        break;
 
-               mem_cgroup_hierarchical_reclaim(memcg, NULL, GFP_KERNEL,
-                                               MEM_CGROUP_RECLAIM_SHRINK,
-                                               NULL);
+               mem_cgroup_reclaim(memcg, GFP_KERNEL,
+                                  MEM_CGROUP_RECLAIM_SHRINK);
                curusage = res_counter_read_u64(&memcg->res, RES_USAGE);
                /* Usage is reduced ? */
                if (curusage >= oldusage)
@@ -3594,10 +3485,9 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
                if (!ret)
                        break;
 
-               mem_cgroup_hierarchical_reclaim(memcg, NULL, GFP_KERNEL,
-                                               MEM_CGROUP_RECLAIM_NOSWAP |
-                                               MEM_CGROUP_RECLAIM_SHRINK,
-                                               NULL);
+               mem_cgroup_reclaim(memcg, GFP_KERNEL,
+                                  MEM_CGROUP_RECLAIM_NOSWAP |
+                                  MEM_CGROUP_RECLAIM_SHRINK);
                curusage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
                /* Usage is reduced ? */
                if (curusage >= oldusage)
@@ -3640,10 +3530,8 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
                        break;
 
                nr_scanned = 0;
-               reclaimed = mem_cgroup_hierarchical_reclaim(mz->mem, zone,
-                                               gfp_mask,
-                                               MEM_CGROUP_RECLAIM_SOFT,
-                                               &nr_scanned);
+               reclaimed = mem_cgroup_soft_reclaim(mz->mem, zone,
+                                                   gfp_mask, &nr_scanned);
                nr_reclaimed += reclaimed;
                *total_scanned += nr_scanned;
                spin_lock(&mctz->lock);
@@ -3711,22 +3599,23 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
 static int mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
                                int node, int zid, enum lru_list lru)
 {
-       struct zone *zone;
        struct mem_cgroup_per_zone *mz;
-       struct page_cgroup *pc, *busy;
        unsigned long flags, loop;
        struct list_head *list;
+       struct page *busy;
+       struct zone *zone;
        int ret = 0;
 
        zone = &NODE_DATA(node)->node_zones[zid];
        mz = mem_cgroup_zoneinfo(memcg, node, zid);
-       list = &mz->lists[lru];
+       list = &mz->lruvec.lists[lru];
 
        loop = MEM_CGROUP_ZSTAT(mz, lru);
        /* give some margin against EBUSY etc...*/
        loop += 256;
        busy = NULL;
        while (loop--) {
+               struct page_cgroup *pc;
                struct page *page;
 
                ret = 0;
@@ -3735,24 +3624,24 @@ static int mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
                        spin_unlock_irqrestore(&zone->lru_lock, flags);
                        break;
                }
-               pc = list_entry(list->prev, struct page_cgroup, lru);
-               if (busy == pc) {
-                       list_move(&pc->lru, list);
+               page = list_entry(list->prev, struct page, lru);
+               if (busy == page) {
+                       list_move(&page->lru, list);
                        busy = NULL;
                        spin_unlock_irqrestore(&zone->lru_lock, flags);
                        continue;
                }
                spin_unlock_irqrestore(&zone->lru_lock, flags);
 
-               page = lookup_cgroup_page(pc);
+               pc = lookup_page_cgroup(page);
 
                ret = mem_cgroup_move_parent(page, pc, memcg, GFP_KERNEL);
-               if (ret == -ENOMEM)
+               if (ret == -ENOMEM || ret == -EINTR)
                        break;
 
                if (ret == -EBUSY || ret == -EINVAL) {
                        /* found lock contention or "pc" is obsolete. */
-                       busy = pc;
+                       busy = page;
                        cond_resched();
                } else
                        busy = NULL;
@@ -4846,7 +4735,7 @@ static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
        for (zone = 0; zone < MAX_NR_ZONES; zone++) {
                mz = &pn->zoneinfo[zone];
                for_each_lru(l)
-                       INIT_LIST_HEAD(&mz->lists[l]);
+                       INIT_LIST_HEAD(&mz->lruvec.lists[l]);
                mz->usage_in_excess = 0;
                mz->on_tree = false;
                mz->mem = memcg;
@@ -4906,7 +4795,7 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
        mem_cgroup_remove_from_trees(memcg);
        free_css_id(&mem_cgroup_subsys, &memcg->css);
 
-       for_each_node_state(node, N_POSSIBLE)
+       for_each_node(node)
                free_mem_cgroup_per_zone_info(memcg, node);
 
        free_percpu(memcg->stat);
@@ -4965,13 +4854,13 @@ static int mem_cgroup_soft_limit_tree_init(void)
        struct mem_cgroup_tree_per_zone *rtpz;
        int tmp, node, zone;
 
-       for_each_node_state(node, N_POSSIBLE) {
+       for_each_node(node) {
                tmp = node;
                if (!node_state(node, N_NORMAL_MEMORY))
                        tmp = -1;
                rtpn = kzalloc_node(sizeof(*rtpn), GFP_KERNEL, tmp);
                if (!rtpn)
-                       return 1;
+                       goto err_cleanup;
 
                soft_limit_tree.rb_tree_per_node[node] = rtpn;
 
@@ -4982,6 +4871,16 @@ static int mem_cgroup_soft_limit_tree_init(void)
                }
        }
        return 0;
+
+err_cleanup:
+       for_each_node(node) {
+               if (!soft_limit_tree.rb_tree_per_node[node])
+                       break;
+               kfree(soft_limit_tree.rb_tree_per_node[node]);
+               soft_limit_tree.rb_tree_per_node[node] = NULL;
+       }
+       return 1;
+
 }
 
 static struct cgroup_subsys_state * __ref
@@ -4995,7 +4894,7 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
        if (!memcg)
                return ERR_PTR(error);
 
-       for_each_node_state(node, N_POSSIBLE)
+       for_each_node(node)
                if (alloc_mem_cgroup_per_zone_info(memcg, node))
                        goto free_out;
 
@@ -5033,7 +4932,6 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
                res_counter_init(&memcg->res, NULL);
                res_counter_init(&memcg->memsw, NULL);
        }
-       memcg->last_scanned_child = 0;
        memcg->last_scanned_node = MAX_NUMNODES;
        INIT_LIST_HEAD(&memcg->oom_notify);
 
@@ -5129,9 +5027,9 @@ one_by_one:
                }
                ret = __mem_cgroup_try_charge(NULL,
                                        GFP_KERNEL, 1, &memcg, false);
-               if (ret || !memcg)
+               if (ret)
                        /* mem_cgroup_clear_mc() will do uncharge later */
-                       return -ENOMEM;
+                       return ret;
                mc.precharge++;
        }
        return ret;
@@ -5276,7 +5174,7 @@ static int is_target_pte_for_mc(struct vm_area_struct *vma,
        }
        /* There is a swap entry and a page doesn't exist or isn't charged */
        if (ent.val && !ret &&
-                       css_id(&mc.from->css) == lookup_swap_cgroup(ent)) {
+                       css_id(&mc.from->css) == lookup_swap_cgroup_id(ent)) {
                ret = MC_TARGET_SWAP;
                if (target)
                        target->ent = ent;
index 06d3479513aaa2a3eeff26f0bf25e71c13695fdd..56080ea361406090860493861d5253dc314debc1 100644 (file)
@@ -1557,7 +1557,7 @@ int soft_offline_page(struct page *page, int flags)
                                            page_is_file_cache(page));
                list_add(&page->lru, &pagelist);
                ret = migrate_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL,
-                                                               0, true);
+                                                       0, MIGRATE_SYNC);
                if (ret) {
                        putback_lru_pages(&pagelist);
                        pr_info("soft offline: %#lx: migration failed %d, type %lx\n",
index 829d437354022959eeca37082f695e2ee73025ed..5e30583c2605d7b791d907ae8a5e07be2d9ad5b6 100644 (file)
@@ -293,7 +293,7 @@ int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 {
        struct mmu_gather_batch *batch;
 
-       tlb->need_flush = 1;
+       VM_BUG_ON(!tlb->need_flush);
 
        if (tlb_fast_mode(tlb)) {
                free_page_and_swap_cache(page);
@@ -1231,7 +1231,7 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,
                        if (next-addr != HPAGE_PMD_SIZE) {
                                VM_BUG_ON(!rwsem_is_locked(&tlb->mm->mmap_sem));
                                split_huge_page_pmd(vma->vm_mm, pmd);
-                       } else if (zap_huge_pmd(tlb, vma, pmd))
+                       } else if (zap_huge_pmd(tlb, vma, pmd, addr))
                                continue;
                        /* fall through */
                }
index 2168489c0bc9f309ff3347d6dac05a09039ad7d2..6629fafd6ce4a65eae9421dd9d68b25805bca993 100644 (file)
@@ -809,7 +809,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                }
                /* this function returns # of failed pages */
                ret = migrate_pages(&source, hotremove_migrate_alloc, 0,
-                                                               true, true);
+                                                       true, MIGRATE_SYNC);
                if (ret)
                        putback_lru_pages(&source);
        }
index e3d58f088466c3b798f9017b76351295313d2771..06b145fb64ab59a399344bc73ca277be0e39ed7b 100644 (file)
@@ -942,7 +942,7 @@ static int migrate_to_node(struct mm_struct *mm, int source, int dest,
 
        if (!list_empty(&pagelist)) {
                err = migrate_pages(&pagelist, new_node_page, dest,
-                                                               false, true);
+                                                       false, MIGRATE_SYNC);
                if (err)
                        putback_lru_pages(&pagelist);
        }
index 89ea0854332ec3fdf53123bbf7fe5f1de94f6599..9871a56d82c30b1390ea268fddd9b3bc4b83c8da 100644 (file)
@@ -216,6 +216,56 @@ out:
        pte_unmap_unlock(ptep, ptl);
 }
 
+#ifdef CONFIG_BLOCK
+/* Returns true if all buffers are successfully locked */
+static bool buffer_migrate_lock_buffers(struct buffer_head *head,
+                                                       enum migrate_mode mode)
+{
+       struct buffer_head *bh = head;
+
+       /* Simple case, sync compaction */
+       if (mode != MIGRATE_ASYNC) {
+               do {
+                       get_bh(bh);
+                       lock_buffer(bh);
+                       bh = bh->b_this_page;
+
+               } while (bh != head);
+
+               return true;
+       }
+
+       /* async case, we cannot block on lock_buffer so use trylock_buffer */
+       do {
+               get_bh(bh);
+               if (!trylock_buffer(bh)) {
+                       /*
+                        * We failed to lock the buffer and cannot stall in
+                        * async migration. Release the taken locks
+                        */
+                       struct buffer_head *failed_bh = bh;
+                       put_bh(failed_bh);
+                       bh = head;
+                       while (bh != failed_bh) {
+                               unlock_buffer(bh);
+                               put_bh(bh);
+                               bh = bh->b_this_page;
+                       }
+                       return false;
+               }
+
+               bh = bh->b_this_page;
+       } while (bh != head);
+       return true;
+}
+#else
+static inline bool buffer_migrate_lock_buffers(struct buffer_head *head,
+                                                       enum migrate_mode mode)
+{
+       return true;
+}
+#endif /* CONFIG_BLOCK */
+
 /*
  * Replace the page in the mapping.
  *
@@ -225,7 +275,8 @@ out:
  * 3 for pages with a mapping and PagePrivate/PagePrivate2 set.
  */
 static int migrate_page_move_mapping(struct address_space *mapping,
-               struct page *newpage, struct page *page)
+               struct page *newpage, struct page *page,
+               struct buffer_head *head, enum migrate_mode mode)
 {
        int expected_count;
        void **pslot;
@@ -254,6 +305,20 @@ static int migrate_page_move_mapping(struct address_space *mapping,
                return -EAGAIN;
        }
 
+       /*
+        * In the async migration case of moving a page with buffers, lock the
+        * buffers using trylock before the mapping is moved. If the mapping
+        * was moved, we later failed to lock the buffers and could not move
+        * the mapping back due to an elevated page count, we would have to
+        * block waiting on other references to be dropped.
+        */
+       if (mode == MIGRATE_ASYNC && head &&
+                       !buffer_migrate_lock_buffers(head, mode)) {
+               page_unfreeze_refs(page, expected_count);
+               spin_unlock_irq(&mapping->tree_lock);
+               return -EAGAIN;
+       }
+
        /*
         * Now we know that no one else is looking at the page.
         */
@@ -409,13 +474,14 @@ EXPORT_SYMBOL(fail_migrate_page);
  * Pages are locked upon entry and exit.
  */
 int migrate_page(struct address_space *mapping,
-               struct page *newpage, struct page *page)
+               struct page *newpage, struct page *page,
+               enum migrate_mode mode)
 {
        int rc;
 
        BUG_ON(PageWriteback(page));    /* Writeback must be complete */
 
-       rc = migrate_page_move_mapping(mapping, newpage, page);
+       rc = migrate_page_move_mapping(mapping, newpage, page, NULL, mode);
 
        if (rc)
                return rc;
@@ -432,28 +498,28 @@ EXPORT_SYMBOL(migrate_page);
  * exist.
  */
 int buffer_migrate_page(struct address_space *mapping,
-               struct page *newpage, struct page *page)
+               struct page *newpage, struct page *page, enum migrate_mode mode)
 {
        struct buffer_head *bh, *head;
        int rc;
 
        if (!page_has_buffers(page))
-               return migrate_page(mapping, newpage, page);
+               return migrate_page(mapping, newpage, page, mode);
 
        head = page_buffers(page);
 
-       rc = migrate_page_move_mapping(mapping, newpage, page);
+       rc = migrate_page_move_mapping(mapping, newpage, page, head, mode);
 
        if (rc)
                return rc;
 
-       bh = head;
-       do {
-               get_bh(bh);
-               lock_buffer(bh);
-               bh = bh->b_this_page;
-
-       } while (bh != head);
+       /*
+        * In the async case, migrate_page_move_mapping locked the buffers
+        * with an IRQ-safe spinlock held. In the sync case, the buffers
+        * need to be locked now
+        */
+       if (mode != MIGRATE_ASYNC)
+               BUG_ON(!buffer_migrate_lock_buffers(head, mode));
 
        ClearPagePrivate(page);
        set_page_private(newpage, page_private(page));
@@ -530,10 +596,14 @@ static int writeout(struct address_space *mapping, struct page *page)
  * Default handling if a filesystem does not provide a migration function.
  */
 static int fallback_migrate_page(struct address_space *mapping,
-       struct page *newpage, struct page *page)
+       struct page *newpage, struct page *page, enum migrate_mode mode)
 {
-       if (PageDirty(page))
+       if (PageDirty(page)) {
+               /* Only writeback pages in full synchronous migration */
+               if (mode != MIGRATE_SYNC)
+                       return -EBUSY;
                return writeout(mapping, page);
+       }
 
        /*
         * Buffers may be managed in a filesystem specific way.
@@ -543,7 +613,7 @@ static int fallback_migrate_page(struct address_space *mapping,
            !try_to_release_page(page, GFP_KERNEL))
                return -EAGAIN;
 
-       return migrate_page(mapping, newpage, page);
+       return migrate_page(mapping, newpage, page, mode);
 }
 
 /*
@@ -558,7 +628,7 @@ static int fallback_migrate_page(struct address_space *mapping,
  *  == 0 - success
  */
 static int move_to_new_page(struct page *newpage, struct page *page,
-                                       int remap_swapcache, bool sync)
+                               int remap_swapcache, enum migrate_mode mode)
 {
        struct address_space *mapping;
        int rc;
@@ -579,29 +649,18 @@ static int move_to_new_page(struct page *newpage, struct page *page,
 
        mapping = page_mapping(page);
        if (!mapping)
-               rc = migrate_page(mapping, newpage, page);
-       else {
+               rc = migrate_page(mapping, newpage, page, mode);
+       else if (mapping->a_ops->migratepage)
                /*
-                * Do not writeback pages if !sync and migratepage is
-                * not pointing to migrate_page() which is nonblocking
-                * (swapcache/tmpfs uses migratepage = migrate_page).
+                * Most pages have a mapping and most filesystems provide a
+                * migratepage callback. Anonymous pages are part of swap
+                * space which also has its own migratepage callback. This
+                * is the most common path for page migration.
                 */
-               if (PageDirty(page) && !sync &&
-                   mapping->a_ops->migratepage != migrate_page)
-                       rc = -EBUSY;
-               else if (mapping->a_ops->migratepage)
-                       /*
-                        * Most pages have a mapping and most filesystems
-                        * should provide a migration function. Anonymous
-                        * pages are part of swap space which also has its
-                        * own migration function. This is the most common
-                        * path for page migration.
-                        */
-                       rc = mapping->a_ops->migratepage(mapping,
-                                                       newpage, page);
-               else
-                       rc = fallback_migrate_page(mapping, newpage, page);
-       }
+               rc = mapping->a_ops->migratepage(mapping,
+                                               newpage, page, mode);
+       else
+               rc = fallback_migrate_page(mapping, newpage, page, mode);
 
        if (rc) {
                newpage->mapping = NULL;
@@ -616,7 +675,7 @@ static int move_to_new_page(struct page *newpage, struct page *page,
 }
 
 static int __unmap_and_move(struct page *page, struct page *newpage,
-                               int force, bool offlining, bool sync)
+                       int force, bool offlining, enum migrate_mode mode)
 {
        int rc = -EAGAIN;
        int remap_swapcache = 1;
@@ -625,7 +684,7 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
        struct anon_vma *anon_vma = NULL;
 
        if (!trylock_page(page)) {
-               if (!force || !sync)
+               if (!force || mode == MIGRATE_ASYNC)
                        goto out;
 
                /*
@@ -671,10 +730,12 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
 
        if (PageWriteback(page)) {
                /*
-                * For !sync, there is no point retrying as the retry loop
-                * is expected to be too short for PageWriteback to be cleared
+                * Only in the case of a full syncronous migration is it
+                * necessary to wait for PageWriteback. In the async case,
+                * the retry loop is too short and in the sync-light case,
+                * the overhead of stalling is too much
                 */
-               if (!sync) {
+               if (mode != MIGRATE_SYNC) {
                        rc = -EBUSY;
                        goto uncharge;
                }
@@ -745,7 +806,7 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
 
 skip_unmap:
        if (!page_mapped(page))
-               rc = move_to_new_page(newpage, page, remap_swapcache, sync);
+               rc = move_to_new_page(newpage, page, remap_swapcache, mode);
 
        if (rc && remap_swapcache)
                remove_migration_ptes(page, page);
@@ -768,7 +829,8 @@ out:
  * to the newly allocated page in newpage.
  */
 static int unmap_and_move(new_page_t get_new_page, unsigned long private,
-                       struct page *page, int force, bool offlining, bool sync)
+                       struct page *page, int force, bool offlining,
+                       enum migrate_mode mode)
 {
        int rc = 0;
        int *result = NULL;
@@ -777,6 +839,8 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        if (!newpage)
                return -ENOMEM;
 
+       mem_cgroup_reset_owner(newpage);
+
        if (page_count(page) == 1) {
                /* page was freed from under us. So we are done. */
                goto out;
@@ -786,7 +850,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
                if (unlikely(split_huge_page(page)))
                        goto out;
 
-       rc = __unmap_and_move(page, newpage, force, offlining, sync);
+       rc = __unmap_and_move(page, newpage, force, offlining, mode);
 out:
        if (rc != -EAGAIN) {
                /*
@@ -834,7 +898,8 @@ out:
  */
 static int unmap_and_move_huge_page(new_page_t get_new_page,
                                unsigned long private, struct page *hpage,
-                               int force, bool offlining, bool sync)
+                               int force, bool offlining,
+                               enum migrate_mode mode)
 {
        int rc = 0;
        int *result = NULL;
@@ -847,7 +912,7 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
        rc = -EAGAIN;
 
        if (!trylock_page(hpage)) {
-               if (!force || !sync)
+               if (!force || mode != MIGRATE_SYNC)
                        goto out;
                lock_page(hpage);
        }
@@ -858,7 +923,7 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
        try_to_unmap(hpage, TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
 
        if (!page_mapped(hpage))
-               rc = move_to_new_page(new_hpage, hpage, 1, sync);
+               rc = move_to_new_page(new_hpage, hpage, 1, mode);
 
        if (rc)
                remove_migration_ptes(hpage, hpage);
@@ -901,7 +966,7 @@ out:
  */
 int migrate_pages(struct list_head *from,
                new_page_t get_new_page, unsigned long private, bool offlining,
-               bool sync)
+               enum migrate_mode mode)
 {
        int retry = 1;
        int nr_failed = 0;
@@ -922,7 +987,7 @@ int migrate_pages(struct list_head *from,
 
                        rc = unmap_and_move(get_new_page, private,
                                                page, pass > 2, offlining,
-                                               sync);
+                                               mode);
 
                        switch(rc) {
                        case -ENOMEM:
@@ -952,7 +1017,7 @@ out:
 
 int migrate_huge_pages(struct list_head *from,
                new_page_t get_new_page, unsigned long private, bool offlining,
-               bool sync)
+               enum migrate_mode mode)
 {
        int retry = 1;
        int nr_failed = 0;
@@ -969,7 +1034,7 @@ int migrate_huge_pages(struct list_head *from,
 
                        rc = unmap_and_move_huge_page(get_new_page,
                                        private, page, pass > 2, offlining,
-                                       sync);
+                                       mode);
 
                        switch(rc) {
                        case -ENOMEM:
@@ -1098,7 +1163,7 @@ set_status:
        err = 0;
        if (!list_empty(&pagelist)) {
                err = migrate_pages(&pagelist, new_page_node,
-                               (unsigned long)pm, 0, true);
+                               (unsigned long)pm, 0, MIGRATE_SYNC);
                if (err)
                        putback_lru_pages(&pagelist);
        }
index 7c122faa05c5ba07fc11df6f5149909680c14f3c..2958fd8e7c9abcfcf6cc7b38e2dac34133905b22 100644 (file)
@@ -152,7 +152,7 @@ struct task_struct *find_lock_task_mm(struct task_struct *p)
 
 /* return true if the task is not adequate as candidate victim task. */
 static bool oom_unkillable_task(struct task_struct *p,
-               const struct mem_cgroup *mem, const nodemask_t *nodemask)
+               const struct mem_cgroup *memcg, const nodemask_t *nodemask)
 {
        if (is_global_init(p))
                return true;
@@ -160,7 +160,7 @@ static bool oom_unkillable_task(struct task_struct *p,
                return true;
 
        /* When mem_cgroup_out_of_memory() and p is not member of the group */
-       if (mem && !task_in_mem_cgroup(p, mem))
+       if (memcg && !task_in_mem_cgroup(p, memcg))
                return true;
 
        /* p may not have freeable memory in nodemask */
@@ -179,12 +179,12 @@ static bool oom_unkillable_task(struct task_struct *p,
  * predictable as possible.  The goal is to return the highest value for the
  * task consuming the most memory to avoid subsequent oom failures.
  */
-unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
+unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
                      const nodemask_t *nodemask, unsigned long totalpages)
 {
        long points;
 
-       if (oom_unkillable_task(p, mem, nodemask))
+       if (oom_unkillable_task(p, memcg, nodemask))
                return 0;
 
        p = find_lock_task_mm(p);
@@ -308,7 +308,7 @@ static enum oom_constraint constrained_alloc(struct zonelist *zonelist,
  * (not docbooked, we don't want this one cluttering up the manual)
  */
 static struct task_struct *select_bad_process(unsigned int *ppoints,
-               unsigned long totalpages, struct mem_cgroup *mem,
+               unsigned long totalpages, struct mem_cgroup *memcg,
                const nodemask_t *nodemask)
 {
        struct task_struct *g, *p;
@@ -320,7 +320,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
 
                if (p->exit_state)
                        continue;
-               if (oom_unkillable_task(p, mem, nodemask))
+               if (oom_unkillable_task(p, memcg, nodemask))
                        continue;
 
                /*
@@ -364,7 +364,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
                        }
                }
 
-               points = oom_badness(p, mem, nodemask, totalpages);
+               points = oom_badness(p, memcg, nodemask, totalpages);
                if (points > *ppoints) {
                        chosen = p;
                        *ppoints = points;
@@ -387,14 +387,14 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
  *
  * Call with tasklist_lock read-locked.
  */
-static void dump_tasks(const struct mem_cgroup *mem, const nodemask_t *nodemask)
+static void dump_tasks(const struct mem_cgroup *memcg, const nodemask_t *nodemask)
 {
        struct task_struct *p;
        struct task_struct *task;
 
        pr_info("[ pid ]   uid  tgid total_vm      rss cpu oom_adj oom_score_adj name\n");
        for_each_process(p) {
-               if (oom_unkillable_task(p, mem, nodemask))
+               if (oom_unkillable_task(p, memcg, nodemask))
                        continue;
 
                task = find_lock_task_mm(p);
@@ -417,7 +417,7 @@ static void dump_tasks(const struct mem_cgroup *mem, const nodemask_t *nodemask)
 }
 
 static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order,
-                       struct mem_cgroup *mem, const nodemask_t *nodemask)
+                       struct mem_cgroup *memcg, const nodemask_t *nodemask)
 {
        task_lock(current);
        pr_warning("%s invoked oom-killer: gfp_mask=0x%x, order=%d, "
@@ -427,14 +427,14 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order,
        cpuset_print_task_mems_allowed(current);
        task_unlock(current);
        dump_stack();
-       mem_cgroup_print_oom_info(mem, p);
+       mem_cgroup_print_oom_info(memcg, p);
        show_mem(SHOW_MEM_FILTER_NODES);
        if (sysctl_oom_dump_tasks)
-               dump_tasks(mem, nodemask);
+               dump_tasks(memcg, nodemask);
 }
 
 #define K(x) ((x) << (PAGE_SHIFT-10))
-static int oom_kill_task(struct task_struct *p, struct mem_cgroup *mem)
+static int oom_kill_task(struct task_struct *p)
 {
        struct task_struct *q;
        struct mm_struct *mm;
@@ -484,7 +484,7 @@ static int oom_kill_task(struct task_struct *p, struct mem_cgroup *mem)
 
 static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
                            unsigned int points, unsigned long totalpages,
-                           struct mem_cgroup *mem, nodemask_t *nodemask,
+                           struct mem_cgroup *memcg, nodemask_t *nodemask,
                            const char *message)
 {
        struct task_struct *victim = p;
@@ -493,7 +493,7 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
        unsigned int victim_points = 0;
 
        if (printk_ratelimit())
-               dump_header(p, gfp_mask, order, mem, nodemask);
+               dump_header(p, gfp_mask, order, memcg, nodemask);
 
        /*
         * If the task is already exiting, don't alarm the sysadmin or kill
@@ -524,7 +524,7 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
                        /*
                         * oom_badness() returns 0 if the thread is unkillable
                         */
-                       child_points = oom_badness(child, mem, nodemask,
+                       child_points = oom_badness(child, memcg, nodemask,
                                                                totalpages);
                        if (child_points > victim_points) {
                                victim = child;
@@ -533,7 +533,7 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
                }
        } while_each_thread(p, t);
 
-       return oom_kill_task(victim, mem);
+       return oom_kill_task(victim);
 }
 
 /*
@@ -561,7 +561,7 @@ static void check_panic_on_oom(enum oom_constraint constraint, gfp_t gfp_mask,
 }
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
-void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask)
+void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask)
 {
        unsigned long limit;
        unsigned int points = 0;
@@ -578,14 +578,14 @@ void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask)
        }
 
        check_panic_on_oom(CONSTRAINT_MEMCG, gfp_mask, 0, NULL);
-       limit = mem_cgroup_get_limit(mem) >> PAGE_SHIFT;
+       limit = mem_cgroup_get_limit(memcg) >> PAGE_SHIFT;
        read_lock(&tasklist_lock);
 retry:
-       p = select_bad_process(&points, limit, mem, NULL);
+       p = select_bad_process(&points, limit, memcg, NULL);
        if (!p || PTR_ERR(p) == -1UL)
                goto out;
 
-       if (oom_kill_process(p, gfp_mask, 0, points, limit, mem, NULL,
+       if (oom_kill_process(p, gfp_mask, 0, points, limit, memcg, NULL,
                                "Memory cgroup out of memory"))
                goto retry;
 out:
index 794e6715c22682efdf5dbf570e0434a0a5ef5eb0..0027d8f4a1bb8b1423f42e4d52cb3547debc315f 100644 (file)
@@ -1981,14 +1981,20 @@ static struct page *
 __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
        struct zonelist *zonelist, enum zone_type high_zoneidx,
        nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone,
-       int migratetype, unsigned long *did_some_progress,
-       bool sync_migration)
+       int migratetype, bool sync_migration,
+       bool *deferred_compaction,
+       unsigned long *did_some_progress)
 {
        struct page *page;
 
-       if (!order || compaction_deferred(preferred_zone))
+       if (!order)
                return NULL;
 
+       if (compaction_deferred(preferred_zone)) {
+               *deferred_compaction = true;
+               return NULL;
+       }
+
        current->flags |= PF_MEMALLOC;
        *did_some_progress = try_to_compact_pages(zonelist, order, gfp_mask,
                                                nodemask, sync_migration);
@@ -2016,7 +2022,13 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
                 * but not enough to satisfy watermarks.
                 */
                count_vm_event(COMPACTFAIL);
-               defer_compaction(preferred_zone);
+
+               /*
+                * As async compaction considers a subset of pageblocks, only
+                * defer if the failure was a sync compaction failure.
+                */
+               if (sync_migration)
+                       defer_compaction(preferred_zone);
 
                cond_resched();
        }
@@ -2028,8 +2040,9 @@ static inline struct page *
 __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
        struct zonelist *zonelist, enum zone_type high_zoneidx,
        nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone,
-       int migratetype, unsigned long *did_some_progress,
-       bool sync_migration)
+       int migratetype, bool sync_migration,
+       bool *deferred_compaction,
+       unsigned long *did_some_progress)
 {
        return NULL;
 }
@@ -2179,6 +2192,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
        unsigned long pages_reclaimed = 0;
        unsigned long did_some_progress;
        bool sync_migration = false;
+       bool deferred_compaction = false;
 
        /*
         * In the slowpath, we sanity check order to avoid ever trying to
@@ -2259,12 +2273,22 @@ rebalance:
                                        zonelist, high_zoneidx,
                                        nodemask,
                                        alloc_flags, preferred_zone,
-                                       migratetype, &did_some_progress,
-                                       sync_migration);
+                                       migratetype, sync_migration,
+                                       &deferred_compaction,
+                                       &did_some_progress);
        if (page)
                goto got_pg;
        sync_migration = true;
 
+       /*
+        * If compaction is deferred for high-order allocations, it is because
+        * sync compaction recently failed. In this is the case and the caller
+        * has requested the system not be heavily disrupted, fail the
+        * allocation now instead of entering direct reclaim
+        */
+       if (deferred_compaction && (gfp_mask & __GFP_NO_KSWAPD))
+               goto nopage;
+
        /* Try direct reclaim and then allocating */
        page = __alloc_pages_direct_reclaim(gfp_mask, order,
                                        zonelist, high_zoneidx,
@@ -2328,8 +2352,9 @@ rebalance:
                                        zonelist, high_zoneidx,
                                        nodemask,
                                        alloc_flags, preferred_zone,
-                                       migratetype, &did_some_progress,
-                                       sync_migration);
+                                       migratetype, sync_migration,
+                                       &deferred_compaction,
+                                       &did_some_progress);
                if (page)
                        goto got_pg;
        }
@@ -4237,7 +4262,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
        for (j = 0; j < MAX_NR_ZONES; j++) {
                struct zone *zone = pgdat->node_zones + j;
                unsigned long size, realsize, memmap_pages;
-               enum lru_list l;
+               enum lru_list lru;
 
                size = zone_spanned_pages_in_node(nid, j, zones_size);
                realsize = size - zone_absent_pages_in_node(nid, j,
@@ -4287,8 +4312,8 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
                zone->zone_pgdat = pgdat;
 
                zone_pcp_init(zone);
-               for_each_lru(l)
-                       INIT_LIST_HEAD(&zone->lru[l].list);
+               for_each_lru(lru)
+                       INIT_LIST_HEAD(&zone->lruvec.lists[lru]);
                zone->reclaim_stat.recent_rotated[0] = 0;
                zone->reclaim_stat.recent_rotated[1] = 0;
                zone->reclaim_stat.recent_scanned[0] = 0;
@@ -4642,8 +4667,10 @@ static void check_for_regular_memory(pg_data_t *pgdat)
 
        for (zone_type = 0; zone_type <= ZONE_NORMAL; zone_type++) {
                struct zone *zone = &pgdat->node_zones[zone_type];
-               if (zone->present_pages)
+               if (zone->present_pages) {
                        node_set_state(zone_to_nid(zone), N_NORMAL_MEMORY);
+                       break;
+               }
        }
 #endif
 }
index 2d123f94a8df49addd2ee3167d31861073da9f84..de1616aa9b1e2b3fac054ce4077073cbb05a3c62 100644 (file)
 #include <linux/swapops.h>
 #include <linux/kmemleak.h>
 
-static void __meminit init_page_cgroup(struct page_cgroup *pc, unsigned long id)
-{
-       pc->flags = 0;
-       set_page_cgroup_array_id(pc, id);
-       pc->mem_cgroup = NULL;
-       INIT_LIST_HEAD(&pc->lru);
-}
 static unsigned long total_usage;
 
 #if !defined(CONFIG_SPARSEMEM)
@@ -35,35 +28,27 @@ struct page_cgroup *lookup_page_cgroup(struct page *page)
        struct page_cgroup *base;
 
        base = NODE_DATA(page_to_nid(page))->node_page_cgroup;
+#ifdef CONFIG_DEBUG_VM
+       /*
+        * The sanity checks the page allocator does upon freeing a
+        * page can reach here before the page_cgroup arrays are
+        * allocated when feeding a range of pages to the allocator
+        * for the first time during bootup or memory hotplug.
+        */
        if (unlikely(!base))
                return NULL;
-
+#endif
        offset = pfn - NODE_DATA(page_to_nid(page))->node_start_pfn;
        return base + offset;
 }
 
-struct page *lookup_cgroup_page(struct page_cgroup *pc)
-{
-       unsigned long pfn;
-       struct page *page;
-       pg_data_t *pgdat;
-
-       pgdat = NODE_DATA(page_cgroup_array_id(pc));
-       pfn = pc - pgdat->node_page_cgroup + pgdat->node_start_pfn;
-       page = pfn_to_page(pfn);
-       VM_BUG_ON(pc != lookup_page_cgroup(page));
-       return page;
-}
-
 static int __init alloc_node_page_cgroup(int nid)
 {
-       struct page_cgroup *base, *pc;
+       struct page_cgroup *base;
        unsigned long table_size;
-       unsigned long start_pfn, nr_pages, index;
+       unsigned long nr_pages;
 
-       start_pfn = NODE_DATA(nid)->node_start_pfn;
        nr_pages = NODE_DATA(nid)->node_spanned_pages;
-
        if (!nr_pages)
                return 0;
 
@@ -73,10 +58,6 @@ static int __init alloc_node_page_cgroup(int nid)
                        table_size, PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
        if (!base)
                return -ENOMEM;
-       for (index = 0; index < nr_pages; index++) {
-               pc = base + index;
-               init_page_cgroup(pc, nid);
-       }
        NODE_DATA(nid)->node_page_cgroup = base;
        total_usage += table_size;
        return 0;
@@ -111,29 +92,23 @@ struct page_cgroup *lookup_page_cgroup(struct page *page)
 {
        unsigned long pfn = page_to_pfn(page);
        struct mem_section *section = __pfn_to_section(pfn);
-
+#ifdef CONFIG_DEBUG_VM
+       /*
+        * The sanity checks the page allocator does upon freeing a
+        * page can reach here before the page_cgroup arrays are
+        * allocated when feeding a range of pages to the allocator
+        * for the first time during bootup or memory hotplug.
+        */
        if (!section->page_cgroup)
                return NULL;
+#endif
        return section->page_cgroup + pfn;
 }
 
-struct page *lookup_cgroup_page(struct page_cgroup *pc)
-{
-       struct mem_section *section;
-       struct page *page;
-       unsigned long nr;
-
-       nr = page_cgroup_array_id(pc);
-       section = __nr_to_section(nr);
-       page = pfn_to_page(pc - section->page_cgroup);
-       VM_BUG_ON(pc != lookup_page_cgroup(page));
-       return page;
-}
-
 static void *__meminit alloc_page_cgroup(size_t size, int nid)
 {
+       gfp_t flags = GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN;
        void *addr = NULL;
-       gfp_t flags = GFP_KERNEL | __GFP_NOWARN;
 
        addr = alloc_pages_exact_nid(nid, size, flags);
        if (addr) {
@@ -142,39 +117,20 @@ static void *__meminit alloc_page_cgroup(size_t size, int nid)
        }
 
        if (node_state(nid, N_HIGH_MEMORY))
-               addr = vmalloc_node(size, nid);
+               addr = vzalloc_node(size, nid);
        else
-               addr = vmalloc(size);
+               addr = vzalloc(size);
 
        return addr;
 }
 
-#ifdef CONFIG_MEMORY_HOTPLUG
-static void free_page_cgroup(void *addr)
-{
-       if (is_vmalloc_addr(addr)) {
-               vfree(addr);
-       } else {
-               struct page *page = virt_to_page(addr);
-               size_t table_size =
-                       sizeof(struct page_cgroup) * PAGES_PER_SECTION;
-
-               BUG_ON(PageReserved(page));
-               free_pages_exact(addr, table_size);
-       }
-}
-#endif
-
 static int __meminit init_section_page_cgroup(unsigned long pfn, int nid)
 {
-       struct page_cgroup *base, *pc;
        struct mem_section *section;
+       struct page_cgroup *base;
        unsigned long table_size;
-       unsigned long nr;
-       int index;
 
-       nr = pfn_to_section_nr(pfn);
-       section = __nr_to_section(nr);
+       section = __pfn_to_section(pfn);
 
        if (section->page_cgroup)
                return 0;
@@ -194,10 +150,6 @@ static int __meminit init_section_page_cgroup(unsigned long pfn, int nid)
                return -ENOMEM;
        }
 
-       for (index = 0; index < PAGES_PER_SECTION; index++) {
-               pc = base + index;
-               init_page_cgroup(pc, nr);
-       }
        /*
         * The passed "pfn" may not be aligned to SECTION.  For the calculation
         * we need to apply a mask.
@@ -208,6 +160,20 @@ static int __meminit init_section_page_cgroup(unsigned long pfn, int nid)
        return 0;
 }
 #ifdef CONFIG_MEMORY_HOTPLUG
+static void free_page_cgroup(void *addr)
+{
+       if (is_vmalloc_addr(addr)) {
+               vfree(addr);
+       } else {
+               struct page *page = virt_to_page(addr);
+               size_t table_size =
+                       sizeof(struct page_cgroup) * PAGES_PER_SECTION;
+
+               BUG_ON(PageReserved(page));
+               free_pages_exact(addr, table_size);
+       }
+}
+
 void __free_page_cgroup(unsigned long pfn)
 {
        struct mem_section *ms;
@@ -366,7 +332,6 @@ struct swap_cgroup {
        unsigned short          id;
 };
 #define SC_PER_PAGE    (PAGE_SIZE/sizeof(struct swap_cgroup))
-#define SC_POS_MASK    (SC_PER_PAGE - 1)
 
 /*
  * SwapCgroup implements "lookup" and "exchange" operations.
@@ -408,6 +373,21 @@ not_enough_page:
        return -ENOMEM;
 }
 
+static struct swap_cgroup *lookup_swap_cgroup(swp_entry_t ent,
+                                       struct swap_cgroup_ctrl **ctrlp)
+{
+       pgoff_t offset = swp_offset(ent);
+       struct swap_cgroup_ctrl *ctrl;
+       struct page *mappage;
+
+       ctrl = &swap_cgroup_ctrl[swp_type(ent)];
+       if (ctrlp)
+               *ctrlp = ctrl;
+
+       mappage = ctrl->map[offset / SC_PER_PAGE];
+       return page_address(mappage) + offset % SC_PER_PAGE;
+}
+
 /**
  * swap_cgroup_cmpxchg - cmpxchg mem_cgroup's id for this swp_entry.
  * @end: swap entry to be cmpxchged
@@ -420,21 +400,13 @@ not_enough_page:
 unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
                                        unsigned short old, unsigned short new)
 {
-       int type = swp_type(ent);
-       unsigned long offset = swp_offset(ent);
-       unsigned long idx = offset / SC_PER_PAGE;
-       unsigned long pos = offset & SC_POS_MASK;
        struct swap_cgroup_ctrl *ctrl;
-       struct page *mappage;
        struct swap_cgroup *sc;
        unsigned long flags;
        unsigned short retval;
 
-       ctrl = &swap_cgroup_ctrl[type];
+       sc = lookup_swap_cgroup(ent, &ctrl);
 
-       mappage = ctrl->map[idx];
-       sc = page_address(mappage);
-       sc += pos;
        spin_lock_irqsave(&ctrl->lock, flags);
        retval = sc->id;
        if (retval == old)
@@ -455,21 +427,13 @@ unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
  */
 unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
 {
-       int type = swp_type(ent);
-       unsigned long offset = swp_offset(ent);
-       unsigned long idx = offset / SC_PER_PAGE;
-       unsigned long pos = offset & SC_POS_MASK;
        struct swap_cgroup_ctrl *ctrl;
-       struct page *mappage;
        struct swap_cgroup *sc;
        unsigned short old;
        unsigned long flags;
 
-       ctrl = &swap_cgroup_ctrl[type];
+       sc = lookup_swap_cgroup(ent, &ctrl);
 
-       mappage = ctrl->map[idx];
-       sc = page_address(mappage);
-       sc += pos;
        spin_lock_irqsave(&ctrl->lock, flags);
        old = sc->id;
        sc->id = id;
@@ -479,28 +443,14 @@ unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
 }
 
 /**
- * lookup_swap_cgroup - lookup mem_cgroup tied to swap entry
+ * lookup_swap_cgroup_id - lookup mem_cgroup id tied to swap entry
  * @ent: swap entry to be looked up.
  *
  * Returns CSS ID of mem_cgroup at success. 0 at failure. (0 is invalid ID)
  */
-unsigned short lookup_swap_cgroup(swp_entry_t ent)
+unsigned short lookup_swap_cgroup_id(swp_entry_t ent)
 {
-       int type = swp_type(ent);
-       unsigned long offset = swp_offset(ent);
-       unsigned long idx = offset / SC_PER_PAGE;
-       unsigned long pos = offset & SC_POS_MASK;
-       struct swap_cgroup_ctrl *ctrl;
-       struct page *mappage;
-       struct swap_cgroup *sc;
-       unsigned short ret;
-
-       ctrl = &swap_cgroup_ctrl[type];
-       mappage = ctrl->map[idx];
-       sc = page_address(mappage);
-       sc += pos;
-       ret = sc->id;
-       return ret;
+       return lookup_swap_cgroup(ent, NULL)->id;
 }
 
 int swap_cgroup_swapon(int type, unsigned long max_pages)
index 716eb4acf2fc29cf9500ad3972eb00b5413ab446..f47af9123af78e84d37c473a11daf72093c1ce50 100644 (file)
@@ -67,6 +67,7 @@
 #include <linux/spinlock.h>
 #include <linux/vmalloc.h>
 #include <linux/workqueue.h>
+#include <linux/kmemleak.h>
 
 #include <asm/cacheflush.h>
 #include <asm/sections.h>
@@ -710,6 +711,7 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved)
        const char *err;
        int slot, off, new_alloc;
        unsigned long flags;
+       void __percpu *ptr;
 
        if (unlikely(!size || size > PCPU_MIN_UNIT_SIZE || align > PAGE_SIZE)) {
                WARN(true, "illegal size (%zu) or align (%zu) for "
@@ -802,7 +804,9 @@ area_found:
        mutex_unlock(&pcpu_alloc_mutex);
 
        /* return address relative to base address */
-       return __addr_to_pcpu_ptr(chunk->base_addr + off);
+       ptr = __addr_to_pcpu_ptr(chunk->base_addr + off);
+       kmemleak_alloc_percpu(ptr, size);
+       return ptr;
 
 fail_unlock:
        spin_unlock_irqrestore(&pcpu_lock, flags);
@@ -916,6 +920,8 @@ void free_percpu(void __percpu *ptr)
        if (!ptr)
                return;
 
+       kmemleak_free_percpu(ptr);
+
        addr = __pcpu_ptr_to_addr(ptr);
 
        spin_lock_irqsave(&pcpu_lock, flags);
@@ -1639,6 +1645,8 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size,
                        rc = -ENOMEM;
                        goto out_free_areas;
                }
+               /* kmemleak tracks the percpu allocations separately */
+               kmemleak_free(ptr);
                areas[group] = ptr;
 
                base = min(ptr, base);
@@ -1753,6 +1761,8 @@ int __init pcpu_page_first_chunk(size_t reserved_size,
                                           "for cpu%u\n", psize_str, cpu);
                                goto enomem;
                        }
+                       /* kmemleak tracks the percpu allocations separately */
+                       kmemleak_free(ptr);
                        pages[j++] = virt_to_page(ptr);
                }
 
index a2e5ce1fa08142f60a0abba7ea6512fe6713555c..c8454e06b6c84b424de3952c567fbbcc8264ff75 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -773,7 +773,7 @@ out:
 }
 
 static int page_referenced_anon(struct page *page,
-                               struct mem_cgroup *mem_cont,
+                               struct mem_cgroup *memcg,
                                unsigned long *vm_flags)
 {
        unsigned int mapcount;
@@ -796,7 +796,7 @@ static int page_referenced_anon(struct page *page,
                 * counting on behalf of references from different
                 * cgroups
                 */
-               if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont))
+               if (memcg && !mm_match_cgroup(vma->vm_mm, memcg))
                        continue;
                referenced += page_referenced_one(page, vma, address,
                                                  &mapcount, vm_flags);
@@ -811,7 +811,7 @@ static int page_referenced_anon(struct page *page,
 /**
  * page_referenced_file - referenced check for object-based rmap
  * @page: the page we're checking references on.
- * @mem_cont: target memory controller
+ * @memcg: target memory control group
  * @vm_flags: collect encountered vma->vm_flags who actually referenced the page
  *
  * For an object-based mapped page, find all the places it is mapped and
@@ -822,7 +822,7 @@ static int page_referenced_anon(struct page *page,
  * This function is only called from page_referenced for object-based pages.
  */
 static int page_referenced_file(struct page *page,
-                               struct mem_cgroup *mem_cont,
+                               struct mem_cgroup *memcg,
                                unsigned long *vm_flags)
 {
        unsigned int mapcount;
@@ -864,7 +864,7 @@ static int page_referenced_file(struct page *page,
                 * counting on behalf of references from different
                 * cgroups
                 */
-               if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont))
+               if (memcg && !mm_match_cgroup(vma->vm_mm, memcg))
                        continue;
                referenced += page_referenced_one(page, vma, address,
                                                  &mapcount, vm_flags);
@@ -880,7 +880,7 @@ static int page_referenced_file(struct page *page,
  * page_referenced - test if the page was referenced
  * @page: the page to test
  * @is_locked: caller holds lock on the page
- * @mem_cont: target memory controller
+ * @memcg: target memory cgroup
  * @vm_flags: collect encountered vma->vm_flags who actually referenced the page
  *
  * Quick test_and_clear_referenced for all mappings to a page,
@@ -888,7 +888,7 @@ static int page_referenced_file(struct page *page,
  */
 int page_referenced(struct page *page,
                    int is_locked,
-                   struct mem_cgroup *mem_cont,
+                   struct mem_cgroup *memcg,
                    unsigned long *vm_flags)
 {
        int referenced = 0;
@@ -904,13 +904,13 @@ int page_referenced(struct page *page,
                        }
                }
                if (unlikely(PageKsm(page)))
-                       referenced += page_referenced_ksm(page, mem_cont,
+                       referenced += page_referenced_ksm(page, memcg,
                                                                vm_flags);
                else if (PageAnon(page))
-                       referenced += page_referenced_anon(page, mem_cont,
+                       referenced += page_referenced_anon(page, memcg,
                                                                vm_flags);
                else if (page->mapping)
-                       referenced += page_referenced_file(page, mem_cont,
+                       referenced += page_referenced_file(page, memcg,
                                                                vm_flags);
                if (we_locked)
                        unlock_page(page);
index 5d37b5e44140f2cd0884fc1ae7798ec02b0afb12..4907563ef7ff7e199577f5d2ffedda6fa358271e 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -366,7 +366,8 @@ static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page
                const char *n)
 {
        VM_BUG_ON(!irqs_disabled());
-#ifdef CONFIG_CMPXCHG_DOUBLE
+#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
+    defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
        if (s->flags & __CMPXCHG_DOUBLE) {
                if (cmpxchg_double(&page->freelist, &page->counters,
                        freelist_old, counters_old,
@@ -400,7 +401,8 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
                void *freelist_new, unsigned long counters_new,
                const char *n)
 {
-#ifdef CONFIG_CMPXCHG_DOUBLE
+#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
+    defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
        if (s->flags & __CMPXCHG_DOUBLE) {
                if (cmpxchg_double(&page->freelist, &page->counters,
                        freelist_old, counters_old,
@@ -3014,7 +3016,8 @@ static int kmem_cache_open(struct kmem_cache *s,
                }
        }
 
-#ifdef CONFIG_CMPXCHG_DOUBLE
+#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
+    defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
        if (system_has_cmpxchg_double() && (s->flags & SLAB_DEBUG_FLAGS) == 0)
                /* Enable fast mode */
                s->flags |= __CMPXCHG_DOUBLE;
index 67a09a633a09baad606176f0899d94dbeb4d17d4..b0f529b38979447d0ec192f8b6434af5bab28e02 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/export.h>
 #include <linux/mm_inline.h>
-#include <linux/buffer_head.h> /* for try_to_release_page() */
 #include <linux/percpu_counter.h>
 #include <linux/percpu.h>
 #include <linux/cpu.h>
@@ -54,7 +53,7 @@ static void __page_cache_release(struct page *page)
                spin_lock_irqsave(&zone->lru_lock, flags);
                VM_BUG_ON(!PageLRU(page));
                __ClearPageLRU(page);
-               del_page_from_lru(zone, page);
+               del_page_from_lru_list(zone, page, page_off_lru(page));
                spin_unlock_irqrestore(&zone->lru_lock, flags);
        }
 }
@@ -232,12 +231,14 @@ static void pagevec_lru_move_fn(struct pagevec *pvec,
 static void pagevec_move_tail_fn(struct page *page, void *arg)
 {
        int *pgmoved = arg;
-       struct zone *zone = page_zone(page);
 
        if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
                enum lru_list lru = page_lru_base_type(page);
-               list_move_tail(&page->lru, &zone->lru[lru].list);
-               mem_cgroup_rotate_reclaimable_page(page);
+               struct lruvec *lruvec;
+
+               lruvec = mem_cgroup_lru_move_lists(page_zone(page),
+                                                  page, lru, lru);
+               list_move_tail(&page->lru, &lruvec->lists[lru]);
                (*pgmoved)++;
        }
 }
@@ -368,7 +369,6 @@ void mark_page_accessed(struct page *page)
                SetPageReferenced(page);
        }
 }
-
 EXPORT_SYMBOL(mark_page_accessed);
 
 void __lru_cache_add(struct page *page, enum lru_list lru)
@@ -377,7 +377,7 @@ void __lru_cache_add(struct page *page, enum lru_list lru)
 
        page_cache_get(page);
        if (!pagevec_add(pvec, page))
-               ____pagevec_lru_add(pvec, lru);
+               __pagevec_lru_add(pvec, lru);
        put_cpu_var(lru_add_pvecs);
 }
 EXPORT_SYMBOL(__lru_cache_add);
@@ -476,12 +476,13 @@ static void lru_deactivate_fn(struct page *page, void *arg)
                 */
                SetPageReclaim(page);
        } else {
+               struct lruvec *lruvec;
                /*
                 * The page's writeback ends up during pagevec
                 * We moves tha page into tail of inactive.
                 */
-               list_move_tail(&page->lru, &zone->lru[lru].list);
-               mem_cgroup_rotate_reclaimable_page(page);
+               lruvec = mem_cgroup_lru_move_lists(zone, page, lru, lru);
+               list_move_tail(&page->lru, &lruvec->lists[lru]);
                __count_vm_event(PGROTATED);
        }
 
@@ -504,7 +505,7 @@ static void drain_cpu_pagevecs(int cpu)
        for_each_lru(lru) {
                pvec = &pvecs[lru - LRU_BASE];
                if (pagevec_count(pvec))
-                       ____pagevec_lru_add(pvec, lru);
+                       __pagevec_lru_add(pvec, lru);
        }
 
        pvec = &per_cpu(lru_rotate_pvecs, cpu);
@@ -616,7 +617,7 @@ void release_pages(struct page **pages, int nr, int cold)
                        }
                        VM_BUG_ON(!PageLRU(page));
                        __ClearPageLRU(page);
-                       del_page_from_lru(zone, page);
+                       del_page_from_lru_list(zone, page, page_off_lru(page));
                }
 
                list_add(&page->lru, &pages_to_free);
@@ -644,9 +645,9 @@ void __pagevec_release(struct pagevec *pvec)
        release_pages(pvec->pages, pagevec_count(pvec), pvec->cold);
        pagevec_reinit(pvec);
 }
-
 EXPORT_SYMBOL(__pagevec_release);
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 /* used by __split_huge_page_refcount() */
 void lru_add_page_tail(struct zone* zone,
                       struct page *page, struct page *page_tail)
@@ -654,7 +655,6 @@ void lru_add_page_tail(struct zone* zone,
        int active;
        enum lru_list lru;
        const int file = 0;
-       struct list_head *head;
 
        VM_BUG_ON(!PageHead(page));
        VM_BUG_ON(PageCompound(page_tail));
@@ -673,18 +673,30 @@ void lru_add_page_tail(struct zone* zone,
                        lru = LRU_INACTIVE_ANON;
                }
                update_page_reclaim_stat(zone, page_tail, file, active);
-               if (likely(PageLRU(page)))
-                       head = page->lru.prev;
-               else
-                       head = &zone->lru[lru].list;
-               __add_page_to_lru_list(zone, page_tail, lru, head);
        } else {
                SetPageUnevictable(page_tail);
-               add_page_to_lru_list(zone, page_tail, LRU_UNEVICTABLE);
+               lru = LRU_UNEVICTABLE;
+       }
+
+       if (likely(PageLRU(page)))
+               list_add_tail(&page_tail->lru, &page->lru);
+       else {
+               struct list_head *list_head;
+               /*
+                * Head page has not yet been counted, as an hpage,
+                * so we must account for each subpage individually.
+                *
+                * Use the standard add function to put page_tail on the list,
+                * but then correct its position so they all end up in order.
+                */
+               add_page_to_lru_list(zone, page_tail, lru);
+               list_head = page_tail->lru.prev;
+               list_move_tail(&page_tail->lru, list_head);
        }
 }
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
-static void ____pagevec_lru_add_fn(struct page *page, void *arg)
+static void __pagevec_lru_add_fn(struct page *page, void *arg)
 {
        enum lru_list lru = (enum lru_list)arg;
        struct zone *zone = page_zone(page);
@@ -706,32 +718,13 @@ static void ____pagevec_lru_add_fn(struct page *page, void *arg)
  * Add the passed pages to the LRU, then drop the caller's refcount
  * on them.  Reinitialises the caller's pagevec.
  */
-void ____pagevec_lru_add(struct pagevec *pvec, enum lru_list lru)
+void __pagevec_lru_add(struct pagevec *pvec, enum lru_list lru)
 {
        VM_BUG_ON(is_unevictable_lru(lru));
 
-       pagevec_lru_move_fn(pvec, ____pagevec_lru_add_fn, (void *)lru);
-}
-
-EXPORT_SYMBOL(____pagevec_lru_add);
-
-/*
- * Try to drop buffers from the pages in a pagevec
- */
-void pagevec_strip(struct pagevec *pvec)
-{
-       int i;
-
-       for (i = 0; i < pagevec_count(pvec); i++) {
-               struct page *page = pvec->pages[i];
-
-               if (page_has_private(page) && trylock_page(page)) {
-                       if (page_has_private(page))
-                               try_to_release_page(page, 0);
-                       unlock_page(page);
-               }
-       }
+       pagevec_lru_move_fn(pvec, __pagevec_lru_add_fn, (void *)lru);
 }
+EXPORT_SYMBOL(__pagevec_lru_add);
 
 /**
  * pagevec_lookup - gang pagecache lookup
@@ -755,7 +748,6 @@ unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
        pvec->nr = find_get_pages(mapping, start, nr_pages, pvec->pages);
        return pagevec_count(pvec);
 }
-
 EXPORT_SYMBOL(pagevec_lookup);
 
 unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping,
@@ -765,7 +757,6 @@ unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping,
                                        nr_pages, pvec->pages);
        return pagevec_count(pvec);
 }
-
 EXPORT_SYMBOL(pagevec_lookup_tag);
 
 /*
index ea6b32d61873185f59db1eb9ae303488ec6de471..470038a9187383790751817cda61a07cb50f9512 100644 (file)
@@ -300,6 +300,16 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
                        new_page = alloc_page_vma(gfp_mask, vma, addr);
                        if (!new_page)
                                break;          /* Out of memory */
+                       /*
+                        * The memcg-specific accounting when moving
+                        * pages around the LRU lists relies on the
+                        * page's owner (memcg) to be valid.  Usually,
+                        * pages are assigned to a new owner before
+                        * being put on the LRU list, but since this
+                        * is not the case here, the stale owner from
+                        * a previous allocation cycle must be reset.
+                        */
+                       mem_cgroup_reset_owner(new_page);
                }
 
                /*
index 9520592d4231e421ca15b160d8118f4cfa4a4d84..d999f090dfdabb6e5282aaaf3429029c5e3f839d 100644 (file)
@@ -847,12 +847,13 @@ unsigned int count_swap_pages(int type, int free)
 static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
                unsigned long addr, swp_entry_t entry, struct page *page)
 {
-       struct mem_cgroup *ptr;
+       struct mem_cgroup *memcg;
        spinlock_t *ptl;
        pte_t *pte;
        int ret = 1;
 
-       if (mem_cgroup_try_charge_swapin(vma->vm_mm, page, GFP_KERNEL, &ptr)) {
+       if (mem_cgroup_try_charge_swapin(vma->vm_mm, page,
+                                        GFP_KERNEL, &memcg)) {
                ret = -ENOMEM;
                goto out_nolock;
        }
@@ -860,7 +861,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
        pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
        if (unlikely(!pte_same(*pte, swp_entry_to_pte(entry)))) {
                if (ret > 0)
-                       mem_cgroup_cancel_charge_swapin(ptr);
+                       mem_cgroup_cancel_charge_swapin(memcg);
                ret = 0;
                goto out;
        }
@@ -871,7 +872,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
        set_pte_at(vma->vm_mm, addr, pte,
                   pte_mkold(mk_pte(page, vma->vm_page_prot)));
        page_add_anon_rmap(page, vma, addr);
-       mem_cgroup_commit_charge_swapin(page, ptr);
+       mem_cgroup_commit_charge_swapin(page, memcg);
        swap_free(entry);
        /*
         * Move the page to the active list so it is not
index 877ca046f43d0289ab47dd5471c78fbd16c29553..86ce9a526c17f4e752a03358c4bf0c74432fd8e1 100644 (file)
@@ -2378,7 +2378,7 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
        vms = kzalloc(sizeof(vms[0]) * nr_vms, GFP_KERNEL);
        vas = kzalloc(sizeof(vas[0]) * nr_vms, GFP_KERNEL);
        if (!vas || !vms)
-               goto err_free;
+               goto err_free2;
 
        for (area = 0; area < nr_vms; area++) {
                vas[area] = kzalloc(sizeof(struct vmap_area), GFP_KERNEL);
@@ -2476,11 +2476,10 @@ found:
 
 err_free:
        for (area = 0; area < nr_vms; area++) {
-               if (vas)
-                       kfree(vas[area]);
-               if (vms)
-                       kfree(vms[area]);
+               kfree(vas[area]);
+               kfree(vms[area]);
        }
+err_free2:
        kfree(vas);
        kfree(vms);
        return NULL;
index 26f4a8a4e0c75caebff02e582d8b297f4ff2b35d..2880396f7953b03476db86957c66a3787b40cb8c 100644 (file)
@@ -103,8 +103,11 @@ struct scan_control {
         */
        reclaim_mode_t reclaim_mode;
 
-       /* Which cgroup do we reclaim from */
-       struct mem_cgroup *mem_cgroup;
+       /*
+        * The memory cgroup that hit its limit and as a result is the
+        * primary target of this reclaim invocation.
+        */
+       struct mem_cgroup *target_mem_cgroup;
 
        /*
         * Nodemask of nodes allowed by the caller. If NULL, all nodes
@@ -113,6 +116,11 @@ struct scan_control {
        nodemask_t      *nodemask;
 };
 
+struct mem_cgroup_zone {
+       struct mem_cgroup *mem_cgroup;
+       struct zone *zone;
+};
+
 #define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru))
 
 #ifdef ARCH_HAS_PREFETCH
@@ -153,28 +161,45 @@ static LIST_HEAD(shrinker_list);
 static DECLARE_RWSEM(shrinker_rwsem);
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
-#define scanning_global_lru(sc)        (!(sc)->mem_cgroup)
+static bool global_reclaim(struct scan_control *sc)
+{
+       return !sc->target_mem_cgroup;
+}
+
+static bool scanning_global_lru(struct mem_cgroup_zone *mz)
+{
+       return !mz->mem_cgroup;
+}
 #else
-#define scanning_global_lru(sc)        (1)
+static bool global_reclaim(struct scan_control *sc)
+{
+       return true;
+}
+
+static bool scanning_global_lru(struct mem_cgroup_zone *mz)
+{
+       return true;
+}
 #endif
 
-static struct zone_reclaim_stat *get_reclaim_stat(struct zone *zone,
-                                                 struct scan_control *sc)
+static struct zone_reclaim_stat *get_reclaim_stat(struct mem_cgroup_zone *mz)
 {
-       if (!scanning_global_lru(sc))
-               return mem_cgroup_get_reclaim_stat(sc->mem_cgroup, zone);
+       if (!scanning_global_lru(mz))
+               return mem_cgroup_get_reclaim_stat(mz->mem_cgroup, mz->zone);
 
-       return &zone->reclaim_stat;
+       return &mz->zone->reclaim_stat;
 }
 
-static unsigned long zone_nr_lru_pages(struct zone *zone,
-                               struct scan_control *sc, enum lru_list lru)
+static unsigned long zone_nr_lru_pages(struct mem_cgroup_zone *mz,
+                                      enum lru_list lru)
 {
-       if (!scanning_global_lru(sc))
-               return mem_cgroup_zone_nr_lru_pages(sc->mem_cgroup,
-                               zone_to_nid(zone), zone_idx(zone), BIT(lru));
+       if (!scanning_global_lru(mz))
+               return mem_cgroup_zone_nr_lru_pages(mz->mem_cgroup,
+                                                   zone_to_nid(mz->zone),
+                                                   zone_idx(mz->zone),
+                                                   BIT(lru));
 
-       return zone_page_state(zone, NR_LRU_BASE + lru);
+       return zone_page_state(mz->zone, NR_LRU_BASE + lru);
 }
 
 
@@ -677,12 +702,13 @@ enum page_references {
 };
 
 static enum page_references page_check_references(struct page *page,
+                                                 struct mem_cgroup_zone *mz,
                                                  struct scan_control *sc)
 {
        int referenced_ptes, referenced_page;
        unsigned long vm_flags;
 
-       referenced_ptes = page_referenced(page, 1, sc->mem_cgroup, &vm_flags);
+       referenced_ptes = page_referenced(page, 1, mz->mem_cgroup, &vm_flags);
        referenced_page = TestClearPageReferenced(page);
 
        /* Lumpy reclaim - ignore references */
@@ -738,7 +764,7 @@ static enum page_references page_check_references(struct page *page,
  * shrink_page_list() returns the number of reclaimed pages
  */
 static unsigned long shrink_page_list(struct list_head *page_list,
-                                     struct zone *zone,
+                                     struct mem_cgroup_zone *mz,
                                      struct scan_control *sc,
                                      int priority,
                                      unsigned long *ret_nr_dirty,
@@ -769,7 +795,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        goto keep;
 
                VM_BUG_ON(PageActive(page));
-               VM_BUG_ON(page_zone(page) != zone);
+               VM_BUG_ON(page_zone(page) != mz->zone);
 
                sc->nr_scanned++;
 
@@ -803,7 +829,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        }
                }
 
-               references = page_check_references(page, sc);
+               references = page_check_references(page, mz, sc);
                switch (references) {
                case PAGEREF_ACTIVATE:
                        goto activate_locked;
@@ -994,8 +1020,8 @@ keep_lumpy:
         * back off and wait for congestion to clear because further reclaim
         * will encounter the same problem
         */
-       if (nr_dirty && nr_dirty == nr_congested && scanning_global_lru(sc))
-               zone_set_flag(zone, ZONE_CONGESTED);
+       if (nr_dirty && nr_dirty == nr_congested && global_reclaim(sc))
+               zone_set_flag(mz->zone, ZONE_CONGESTED);
 
        free_hot_cold_page_list(&free_pages, 1);
 
@@ -1049,8 +1075,39 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode, int file)
 
        ret = -EBUSY;
 
-       if ((mode & ISOLATE_CLEAN) && (PageDirty(page) || PageWriteback(page)))
-               return ret;
+       /*
+        * To minimise LRU disruption, the caller can indicate that it only
+        * wants to isolate pages it will be able to operate on without
+        * blocking - clean pages for the most part.
+        *
+        * ISOLATE_CLEAN means that only clean pages should be isolated. This
+        * is used by reclaim when it is cannot write to backing storage
+        *
+        * ISOLATE_ASYNC_MIGRATE is used to indicate that it only wants to pages
+        * that it is possible to migrate without blocking
+        */
+       if (mode & (ISOLATE_CLEAN|ISOLATE_ASYNC_MIGRATE)) {
+               /* All the caller can do on PageWriteback is block */
+               if (PageWriteback(page))
+                       return ret;
+
+               if (PageDirty(page)) {
+                       struct address_space *mapping;
+
+                       /* ISOLATE_CLEAN means only clean pages */
+                       if (mode & ISOLATE_CLEAN)
+                               return ret;
+
+                       /*
+                        * Only pages without mappings or that have a
+                        * ->migratepage callback are possible to migrate
+                        * without blocking
+                        */
+                       mapping = page_mapping(page);
+                       if (mapping && !mapping->a_ops->migratepage)
+                               return ret;
+               }
+       }
 
        if ((mode & ISOLATE_UNMAPPED) && page_mapped(page))
                return ret;
@@ -1079,25 +1136,36 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode, int file)
  * Appropriate locks must be held before calling this function.
  *
  * @nr_to_scan:        The number of pages to look through on the list.
- * @src:       The LRU list to pull pages off.
+ * @mz:                The mem_cgroup_zone to pull pages from.
  * @dst:       The temp list to put pages on to.
- * @scanned:   The number of pages that were scanned.
+ * @nr_scanned:        The number of pages that were scanned.
  * @order:     The caller's attempted allocation order
  * @mode:      One of the LRU isolation modes
+ * @active:    True [1] if isolating active pages
  * @file:      True [1] if isolating file [!anon] pages
  *
  * returns how many pages were moved onto *@dst.
  */
 static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
-               struct list_head *src, struct list_head *dst,
-               unsigned long *scanned, int order, isolate_mode_t mode,
-               int file)
+               struct mem_cgroup_zone *mz, struct list_head *dst,
+               unsigned long *nr_scanned, int order, isolate_mode_t mode,
+               int active, int file)
 {
+       struct lruvec *lruvec;
+       struct list_head *src;
        unsigned long nr_taken = 0;
        unsigned long nr_lumpy_taken = 0;
        unsigned long nr_lumpy_dirty = 0;
        unsigned long nr_lumpy_failed = 0;
        unsigned long scan;
+       int lru = LRU_BASE;
+
+       lruvec = mem_cgroup_zone_lruvec(mz->zone, mz->mem_cgroup);
+       if (active)
+               lru += LRU_ACTIVE;
+       if (file)
+               lru += LRU_FILE;
+       src = &lruvec->lists[lru];
 
        for (scan = 0; scan < nr_to_scan && !list_empty(src); scan++) {
                struct page *page;
@@ -1113,15 +1181,14 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
 
                switch (__isolate_lru_page(page, mode, file)) {
                case 0:
+                       mem_cgroup_lru_del(page);
                        list_move(&page->lru, dst);
-                       mem_cgroup_del_lru(page);
                        nr_taken += hpage_nr_pages(page);
                        break;
 
                case -EBUSY:
                        /* else it is being freed elsewhere */
                        list_move(&page->lru, src);
-                       mem_cgroup_rotate_lru_list(page, page_lru(page));
                        continue;
 
                default:
@@ -1171,13 +1238,17 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
                                break;
 
                        if (__isolate_lru_page(cursor_page, mode, file) == 0) {
+                               unsigned int isolated_pages;
+
+                               mem_cgroup_lru_del(cursor_page);
                                list_move(&cursor_page->lru, dst);
-                               mem_cgroup_del_lru(cursor_page);
-                               nr_taken += hpage_nr_pages(cursor_page);
-                               nr_lumpy_taken++;
+                               isolated_pages = hpage_nr_pages(cursor_page);
+                               nr_taken += isolated_pages;
+                               nr_lumpy_taken += isolated_pages;
                                if (PageDirty(cursor_page))
-                                       nr_lumpy_dirty++;
+                                       nr_lumpy_dirty += isolated_pages;
                                scan++;
+                               pfn += isolated_pages - 1;
                        } else {
                                /*
                                 * Check if the page is freed already.
@@ -1203,57 +1274,16 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
                        nr_lumpy_failed++;
        }
 
-       *scanned = scan;
+       *nr_scanned = scan;
 
        trace_mm_vmscan_lru_isolate(order,
                        nr_to_scan, scan,
                        nr_taken,
                        nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed,
-                       mode);
+                       mode, file);
        return nr_taken;
 }
 
-static unsigned long isolate_pages_global(unsigned long nr,
-                                       struct list_head *dst,
-                                       unsigned long *scanned, int order,
-                                       isolate_mode_t mode,
-                                       struct zone *z, int active, int file)
-{
-       int lru = LRU_BASE;
-       if (active)
-               lru += LRU_ACTIVE;
-       if (file)
-               lru += LRU_FILE;
-       return isolate_lru_pages(nr, &z->lru[lru].list, dst, scanned, order,
-                                                               mode, file);
-}
-
-/*
- * clear_active_flags() is a helper for shrink_active_list(), clearing
- * any active bits from the pages in the list.
- */
-static unsigned long clear_active_flags(struct list_head *page_list,
-                                       unsigned int *count)
-{
-       int nr_active = 0;
-       int lru;
-       struct page *page;
-
-       list_for_each_entry(page, page_list, lru) {
-               int numpages = hpage_nr_pages(page);
-               lru = page_lru_base_type(page);
-               if (PageActive(page)) {
-                       lru += LRU_ACTIVE;
-                       ClearPageActive(page);
-                       nr_active += numpages;
-               }
-               if (count)
-                       count[lru] += numpages;
-       }
-
-       return nr_active;
-}
-
 /**
  * isolate_lru_page - tries to isolate a page from its LRU list
  * @page: page to isolate from its LRU list
@@ -1313,7 +1343,7 @@ static int too_many_isolated(struct zone *zone, int file,
        if (current_is_kswapd())
                return 0;
 
-       if (!scanning_global_lru(sc))
+       if (!global_reclaim(sc))
                return 0;
 
        if (file) {
@@ -1327,27 +1357,21 @@ static int too_many_isolated(struct zone *zone, int file,
        return isolated > inactive;
 }
 
-/*
- * TODO: Try merging with migrations version of putback_lru_pages
- */
 static noinline_for_stack void
-putback_lru_pages(struct zone *zone, struct scan_control *sc,
-                               unsigned long nr_anon, unsigned long nr_file,
-                               struct list_head *page_list)
+putback_inactive_pages(struct mem_cgroup_zone *mz,
+                      struct list_head *page_list)
 {
-       struct page *page;
-       struct pagevec pvec;
-       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
-
-       pagevec_init(&pvec, 1);
+       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
+       struct zone *zone = mz->zone;
+       LIST_HEAD(pages_to_free);
 
        /*
         * Put back any unfreeable pages.
         */
-       spin_lock(&zone->lru_lock);
        while (!list_empty(page_list)) {
+               struct page *page = lru_to_page(page_list);
                int lru;
-               page = lru_to_page(page_list);
+
                VM_BUG_ON(PageLRU(page));
                list_del(&page->lru);
                if (unlikely(!page_evictable(page, NULL))) {
@@ -1364,30 +1388,53 @@ putback_lru_pages(struct zone *zone, struct scan_control *sc,
                        int numpages = hpage_nr_pages(page);
                        reclaim_stat->recent_rotated[file] += numpages;
                }
-               if (!pagevec_add(&pvec, page)) {
-                       spin_unlock_irq(&zone->lru_lock);
-                       __pagevec_release(&pvec);
-                       spin_lock_irq(&zone->lru_lock);
+               if (put_page_testzero(page)) {
+                       __ClearPageLRU(page);
+                       __ClearPageActive(page);
+                       del_page_from_lru_list(zone, page, lru);
+
+                       if (unlikely(PageCompound(page))) {
+                               spin_unlock_irq(&zone->lru_lock);
+                               (*get_compound_page_dtor(page))(page);
+                               spin_lock_irq(&zone->lru_lock);
+                       } else
+                               list_add(&page->lru, &pages_to_free);
                }
        }
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON, -nr_anon);
-       __mod_zone_page_state(zone, NR_ISOLATED_FILE, -nr_file);
 
-       spin_unlock_irq(&zone->lru_lock);
-       pagevec_release(&pvec);
+       /*
+        * To save our caller's stack, now use input list for pages to free.
+        */
+       list_splice(&pages_to_free, page_list);
 }
 
-static noinline_for_stack void update_isolated_counts(struct zone *zone,
-                                       struct scan_control *sc,
-                                       unsigned long *nr_anon,
-                                       unsigned long *nr_file,
-                                       struct list_head *isolated_list)
+static noinline_for_stack void
+update_isolated_counts(struct mem_cgroup_zone *mz,
+                      struct list_head *page_list,
+                      unsigned long *nr_anon,
+                      unsigned long *nr_file)
 {
-       unsigned long nr_active;
+       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
+       struct zone *zone = mz->zone;
        unsigned int count[NR_LRU_LISTS] = { 0, };
-       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
+       unsigned long nr_active = 0;
+       struct page *page;
+       int lru;
+
+       /*
+        * Count pages and clear active flags
+        */
+       list_for_each_entry(page, page_list, lru) {
+               int numpages = hpage_nr_pages(page);
+               lru = page_lru_base_type(page);
+               if (PageActive(page)) {
+                       lru += LRU_ACTIVE;
+                       ClearPageActive(page);
+                       nr_active += numpages;
+               }
+               count[lru] += numpages;
+       }
 
-       nr_active = clear_active_flags(isolated_list, count);
        __count_vm_events(PGDEACTIVATE, nr_active);
 
        __mod_zone_page_state(zone, NR_ACTIVE_FILE,
@@ -1401,8 +1448,6 @@ static noinline_for_stack void update_isolated_counts(struct zone *zone,
 
        *nr_anon = count[LRU_ACTIVE_ANON] + count[LRU_INACTIVE_ANON];
        *nr_file = count[LRU_ACTIVE_FILE] + count[LRU_INACTIVE_FILE];
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON, *nr_anon);
-       __mod_zone_page_state(zone, NR_ISOLATED_FILE, *nr_file);
 
        reclaim_stat->recent_scanned[0] += *nr_anon;
        reclaim_stat->recent_scanned[1] += *nr_file;
@@ -1454,8 +1499,8 @@ static inline bool should_reclaim_stall(unsigned long nr_taken,
  * of reclaimed pages
  */
 static noinline_for_stack unsigned long
-shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
-                       struct scan_control *sc, int priority, int file)
+shrink_inactive_list(unsigned long nr_to_scan, struct mem_cgroup_zone *mz,
+                    struct scan_control *sc, int priority, int file)
 {
        LIST_HEAD(page_list);
        unsigned long nr_scanned;
@@ -1466,6 +1511,7 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
        unsigned long nr_dirty = 0;
        unsigned long nr_writeback = 0;
        isolate_mode_t reclaim_mode = ISOLATE_INACTIVE;
+       struct zone *zone = mz->zone;
 
        while (unlikely(too_many_isolated(zone, file, sc))) {
                congestion_wait(BLK_RW_ASYNC, HZ/10);
@@ -1488,9 +1534,10 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
 
        spin_lock_irq(&zone->lru_lock);
 
-       if (scanning_global_lru(sc)) {
-               nr_taken = isolate_pages_global(nr_to_scan, &page_list,
-                       &nr_scanned, sc->order, reclaim_mode, zone, 0, file);
+       nr_taken = isolate_lru_pages(nr_to_scan, mz, &page_list,
+                                    &nr_scanned, sc->order,
+                                    reclaim_mode, 0, file);
+       if (global_reclaim(sc)) {
                zone->pages_scanned += nr_scanned;
                if (current_is_kswapd())
                        __count_zone_vm_events(PGSCAN_KSWAPD, zone,
@@ -1498,14 +1545,6 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
                else
                        __count_zone_vm_events(PGSCAN_DIRECT, zone,
                                               nr_scanned);
-       } else {
-               nr_taken = mem_cgroup_isolate_pages(nr_to_scan, &page_list,
-                       &nr_scanned, sc->order, reclaim_mode, zone,
-                       sc->mem_cgroup, 0, file);
-               /*
-                * mem_cgroup_isolate_pages() keeps track of
-                * scanned pages on its own.
-                */
        }
 
        if (nr_taken == 0) {
@@ -1513,26 +1552,37 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
                return 0;
        }
 
-       update_isolated_counts(zone, sc, &nr_anon, &nr_file, &page_list);
+       update_isolated_counts(mz, &page_list, &nr_anon, &nr_file);
+
+       __mod_zone_page_state(zone, NR_ISOLATED_ANON, nr_anon);
+       __mod_zone_page_state(zone, NR_ISOLATED_FILE, nr_file);
 
        spin_unlock_irq(&zone->lru_lock);
 
-       nr_reclaimed = shrink_page_list(&page_list, zone, sc, priority,
+       nr_reclaimed = shrink_page_list(&page_list, mz, sc, priority,
                                                &nr_dirty, &nr_writeback);
 
        /* Check if we should syncronously wait for writeback */
        if (should_reclaim_stall(nr_taken, nr_reclaimed, priority, sc)) {
                set_reclaim_mode(priority, sc, true);
-               nr_reclaimed += shrink_page_list(&page_list, zone, sc,
+               nr_reclaimed += shrink_page_list(&page_list, mz, sc,
                                        priority, &nr_dirty, &nr_writeback);
        }
 
-       local_irq_disable();
+       spin_lock_irq(&zone->lru_lock);
+
        if (current_is_kswapd())
                __count_vm_events(KSWAPD_STEAL, nr_reclaimed);
        __count_zone_vm_events(PGSTEAL, zone, nr_reclaimed);
 
-       putback_lru_pages(zone, sc, nr_anon, nr_file, &page_list);
+       putback_inactive_pages(mz, &page_list);
+
+       __mod_zone_page_state(zone, NR_ISOLATED_ANON, -nr_anon);
+       __mod_zone_page_state(zone, NR_ISOLATED_FILE, -nr_file);
+
+       spin_unlock_irq(&zone->lru_lock);
+
+       free_hot_cold_page_list(&page_list, 1);
 
        /*
         * If reclaim is isolating dirty pages under writeback, it implies
@@ -1588,30 +1638,47 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
 
 static void move_active_pages_to_lru(struct zone *zone,
                                     struct list_head *list,
+                                    struct list_head *pages_to_free,
                                     enum lru_list lru)
 {
        unsigned long pgmoved = 0;
-       struct pagevec pvec;
        struct page *page;
 
-       pagevec_init(&pvec, 1);
+       if (buffer_heads_over_limit) {
+               spin_unlock_irq(&zone->lru_lock);
+               list_for_each_entry(page, list, lru) {
+                       if (page_has_private(page) && trylock_page(page)) {
+                               if (page_has_private(page))
+                                       try_to_release_page(page, 0);
+                               unlock_page(page);
+                       }
+               }
+               spin_lock_irq(&zone->lru_lock);
+       }
 
        while (!list_empty(list)) {
+               struct lruvec *lruvec;
+
                page = lru_to_page(list);
 
                VM_BUG_ON(PageLRU(page));
                SetPageLRU(page);
 
-               list_move(&page->lru, &zone->lru[lru].list);
-               mem_cgroup_add_lru_list(page, lru);
+               lruvec = mem_cgroup_lru_add_list(zone, page, lru);
+               list_move(&page->lru, &lruvec->lists[lru]);
                pgmoved += hpage_nr_pages(page);
 
-               if (!pagevec_add(&pvec, page) || list_empty(list)) {
-                       spin_unlock_irq(&zone->lru_lock);
-                       if (buffer_heads_over_limit)
-                               pagevec_strip(&pvec);
-                       __pagevec_release(&pvec);
-                       spin_lock_irq(&zone->lru_lock);
+               if (put_page_testzero(page)) {
+                       __ClearPageLRU(page);
+                       __ClearPageActive(page);
+                       del_page_from_lru_list(zone, page, lru);
+
+                       if (unlikely(PageCompound(page))) {
+                               spin_unlock_irq(&zone->lru_lock);
+                               (*get_compound_page_dtor(page))(page);
+                               spin_lock_irq(&zone->lru_lock);
+                       } else
+                               list_add(&page->lru, pages_to_free);
                }
        }
        __mod_zone_page_state(zone, NR_LRU_BASE + lru, pgmoved);
@@ -1619,19 +1686,22 @@ static void move_active_pages_to_lru(struct zone *zone,
                __count_vm_events(PGDEACTIVATE, pgmoved);
 }
 
-static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
-                       struct scan_control *sc, int priority, int file)
+static void shrink_active_list(unsigned long nr_to_scan,
+                              struct mem_cgroup_zone *mz,
+                              struct scan_control *sc,
+                              int priority, int file)
 {
        unsigned long nr_taken;
-       unsigned long pgscanned;
+       unsigned long nr_scanned;
        unsigned long vm_flags;
        LIST_HEAD(l_hold);      /* The pages which were snipped off */
        LIST_HEAD(l_active);
        LIST_HEAD(l_inactive);
        struct page *page;
-       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
+       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
        unsigned long nr_rotated = 0;
        isolate_mode_t reclaim_mode = ISOLATE_ACTIVE;
+       struct zone *zone = mz->zone;
 
        lru_add_drain();
 
@@ -1641,26 +1711,16 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
                reclaim_mode |= ISOLATE_CLEAN;
 
        spin_lock_irq(&zone->lru_lock);
-       if (scanning_global_lru(sc)) {
-               nr_taken = isolate_pages_global(nr_pages, &l_hold,
-                                               &pgscanned, sc->order,
-                                               reclaim_mode, zone,
-                                               1, file);
-               zone->pages_scanned += pgscanned;
-       } else {
-               nr_taken = mem_cgroup_isolate_pages(nr_pages, &l_hold,
-                                               &pgscanned, sc->order,
-                                               reclaim_mode, zone,
-                                               sc->mem_cgroup, 1, file);
-               /*
-                * mem_cgroup_isolate_pages() keeps track of
-                * scanned pages on its own.
-                */
-       }
+
+       nr_taken = isolate_lru_pages(nr_to_scan, mz, &l_hold,
+                                    &nr_scanned, sc->order,
+                                    reclaim_mode, 1, file);
+       if (global_reclaim(sc))
+               zone->pages_scanned += nr_scanned;
 
        reclaim_stat->recent_scanned[file] += nr_taken;
 
-       __count_zone_vm_events(PGREFILL, zone, pgscanned);
+       __count_zone_vm_events(PGREFILL, zone, nr_scanned);
        if (file)
                __mod_zone_page_state(zone, NR_ACTIVE_FILE, -nr_taken);
        else
@@ -1678,7 +1738,7 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
                        continue;
                }
 
-               if (page_referenced(page, 0, sc->mem_cgroup, &vm_flags)) {
+               if (page_referenced(page, 0, mz->mem_cgroup, &vm_flags)) {
                        nr_rotated += hpage_nr_pages(page);
                        /*
                         * Identify referenced, file-backed active pages and
@@ -1711,12 +1771,14 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
         */
        reclaim_stat->recent_rotated[file] += nr_rotated;
 
-       move_active_pages_to_lru(zone, &l_active,
+       move_active_pages_to_lru(zone, &l_active, &l_hold,
                                                LRU_ACTIVE + file * LRU_FILE);
-       move_active_pages_to_lru(zone, &l_inactive,
+       move_active_pages_to_lru(zone, &l_inactive, &l_hold,
                                                LRU_BASE   + file * LRU_FILE);
        __mod_zone_page_state(zone, NR_ISOLATED_ANON + file, -nr_taken);
        spin_unlock_irq(&zone->lru_lock);
+
+       free_hot_cold_page_list(&l_hold, 1);
 }
 
 #ifdef CONFIG_SWAP
@@ -1741,10 +1803,8 @@ static int inactive_anon_is_low_global(struct zone *zone)
  * Returns true if the zone does not have enough inactive anon pages,
  * meaning some active anon pages need to be deactivated.
  */
-static int inactive_anon_is_low(struct zone *zone, struct scan_control *sc)
+static int inactive_anon_is_low(struct mem_cgroup_zone *mz)
 {
-       int low;
-
        /*
         * If we don't have swap space, anonymous page deactivation
         * is pointless.
@@ -1752,15 +1812,14 @@ static int inactive_anon_is_low(struct zone *zone, struct scan_control *sc)
        if (!total_swap_pages)
                return 0;
 
-       if (scanning_global_lru(sc))
-               low = inactive_anon_is_low_global(zone);
-       else
-               low = mem_cgroup_inactive_anon_is_low(sc->mem_cgroup, zone);
-       return low;
+       if (!scanning_global_lru(mz))
+               return mem_cgroup_inactive_anon_is_low(mz->mem_cgroup,
+                                                      mz->zone);
+
+       return inactive_anon_is_low_global(mz->zone);
 }
 #else
-static inline int inactive_anon_is_low(struct zone *zone,
-                                       struct scan_control *sc)
+static inline int inactive_anon_is_low(struct mem_cgroup_zone *mz)
 {
        return 0;
 }
@@ -1778,8 +1837,7 @@ static int inactive_file_is_low_global(struct zone *zone)
 
 /**
  * inactive_file_is_low - check if file pages need to be deactivated
- * @zone: zone to check
- * @sc:   scan control of this context
+ * @mz: memory cgroup and zone to check
  *
  * When the system is doing streaming IO, memory pressure here
  * ensures that active file pages get deactivated, until more
@@ -1791,45 +1849,44 @@ static int inactive_file_is_low_global(struct zone *zone)
  * This uses a different ratio than the anonymous pages, because
  * the page cache uses a use-once replacement algorithm.
  */
-static int inactive_file_is_low(struct zone *zone, struct scan_control *sc)
+static int inactive_file_is_low(struct mem_cgroup_zone *mz)
 {
-       int low;
+       if (!scanning_global_lru(mz))
+               return mem_cgroup_inactive_file_is_low(mz->mem_cgroup,
+                                                      mz->zone);
 
-       if (scanning_global_lru(sc))
-               low = inactive_file_is_low_global(zone);
-       else
-               low = mem_cgroup_inactive_file_is_low(sc->mem_cgroup, zone);
-       return low;
+       return inactive_file_is_low_global(mz->zone);
 }
 
-static int inactive_list_is_low(struct zone *zone, struct scan_control *sc,
-                               int file)
+static int inactive_list_is_low(struct mem_cgroup_zone *mz, int file)
 {
        if (file)
-               return inactive_file_is_low(zone, sc);
+               return inactive_file_is_low(mz);
        else
-               return inactive_anon_is_low(zone, sc);
+               return inactive_anon_is_low(mz);
 }
 
 static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan,
-       struct zone *zone, struct scan_control *sc, int priority)
+                                struct mem_cgroup_zone *mz,
+                                struct scan_control *sc, int priority)
 {
        int file = is_file_lru(lru);
 
        if (is_active_lru(lru)) {
-               if (inactive_list_is_low(zone, sc, file))
-                   shrink_active_list(nr_to_scan, zone, sc, priority, file);
+               if (inactive_list_is_low(mz, file))
+                       shrink_active_list(nr_to_scan, mz, sc, priority, file);
                return 0;
        }
 
-       return shrink_inactive_list(nr_to_scan, zone, sc, priority, file);
+       return shrink_inactive_list(nr_to_scan, mz, sc, priority, file);
 }
 
-static int vmscan_swappiness(struct scan_control *sc)
+static int vmscan_swappiness(struct mem_cgroup_zone *mz,
+                            struct scan_control *sc)
 {
-       if (scanning_global_lru(sc))
+       if (global_reclaim(sc))
                return vm_swappiness;
-       return mem_cgroup_swappiness(sc->mem_cgroup);
+       return mem_cgroup_swappiness(mz->mem_cgroup);
 }
 
 /*
@@ -1840,15 +1897,15 @@ static int vmscan_swappiness(struct scan_control *sc)
  *
  * nr[0] = anon pages to scan; nr[1] = file pages to scan
  */
-static void get_scan_count(struct zone *zone, struct scan_control *sc,
-                                       unsigned long *nr, int priority)
+static void get_scan_count(struct mem_cgroup_zone *mz, struct scan_control *sc,
+                          unsigned long *nr, int priority)
 {
        unsigned long anon, file, free;
        unsigned long anon_prio, file_prio;
        unsigned long ap, fp;
-       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
+       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
        u64 fraction[2], denominator;
-       enum lru_list l;
+       enum lru_list lru;
        int noswap = 0;
        bool force_scan = false;
 
@@ -1862,9 +1919,9 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
         * latencies, so it's better to scan a minimum amount there as
         * well.
         */
-       if (scanning_global_lru(sc) && current_is_kswapd())
+       if (current_is_kswapd() && mz->zone->all_unreclaimable)
                force_scan = true;
-       if (!scanning_global_lru(sc))
+       if (!global_reclaim(sc))
                force_scan = true;
 
        /* If we have no swap space, do not bother scanning anon pages. */
@@ -1876,16 +1933,16 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
                goto out;
        }
 
-       anon  = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_ANON) +
-               zone_nr_lru_pages(zone, sc, LRU_INACTIVE_ANON);
-       file  = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_FILE) +
-               zone_nr_lru_pages(zone, sc, LRU_INACTIVE_FILE);
+       anon  = zone_nr_lru_pages(mz, LRU_ACTIVE_ANON) +
+               zone_nr_lru_pages(mz, LRU_INACTIVE_ANON);
+       file  = zone_nr_lru_pages(mz, LRU_ACTIVE_FILE) +
+               zone_nr_lru_pages(mz, LRU_INACTIVE_FILE);
 
-       if (scanning_global_lru(sc)) {
-               free  = zone_page_state(zone, NR_FREE_PAGES);
+       if (global_reclaim(sc)) {
+               free  = zone_page_state(mz->zone, NR_FREE_PAGES);
                /* If we have very few page cache pages,
                   force-scan anon pages. */
-               if (unlikely(file + free <= high_wmark_pages(zone))) {
+               if (unlikely(file + free <= high_wmark_pages(mz->zone))) {
                        fraction[0] = 1;
                        fraction[1] = 0;
                        denominator = 1;
@@ -1897,8 +1954,8 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
         * With swappiness at 100, anonymous and file have the same priority.
         * This scanning priority is essentially the inverse of IO cost.
         */
-       anon_prio = vmscan_swappiness(sc);
-       file_prio = 200 - vmscan_swappiness(sc);
+       anon_prio = vmscan_swappiness(mz, sc);
+       file_prio = 200 - vmscan_swappiness(mz, sc);
 
        /*
         * OK, so we have swap space and a fair amount of page cache
@@ -1911,7 +1968,7 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
         *
         * anon in [0], file in [1]
         */
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(&mz->zone->lru_lock);
        if (unlikely(reclaim_stat->recent_scanned[0] > anon / 4)) {
                reclaim_stat->recent_scanned[0] /= 2;
                reclaim_stat->recent_rotated[0] /= 2;
@@ -1932,24 +1989,24 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
 
        fp = (file_prio + 1) * (reclaim_stat->recent_scanned[1] + 1);
        fp /= reclaim_stat->recent_rotated[1] + 1;
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(&mz->zone->lru_lock);
 
        fraction[0] = ap;
        fraction[1] = fp;
        denominator = ap + fp + 1;
 out:
-       for_each_evictable_lru(l) {
-               int file = is_file_lru(l);
+       for_each_evictable_lru(lru) {
+               int file = is_file_lru(lru);
                unsigned long scan;
 
-               scan = zone_nr_lru_pages(zone, sc, l);
+               scan = zone_nr_lru_pages(mz, lru);
                if (priority || noswap) {
                        scan >>= priority;
                        if (!scan && force_scan)
                                scan = SWAP_CLUSTER_MAX;
                        scan = div64_u64(scan * fraction[file], denominator);
                }
-               nr[l] = scan;
+               nr[lru] = scan;
        }
 }
 
@@ -1960,7 +2017,7 @@ out:
  * back to the allocator and call try_to_compact_zone(), we ensure that
  * there are enough free pages for it to be likely successful
  */
-static inline bool should_continue_reclaim(struct zone *zone,
+static inline bool should_continue_reclaim(struct mem_cgroup_zone *mz,
                                        unsigned long nr_reclaimed,
                                        unsigned long nr_scanned,
                                        struct scan_control *sc)
@@ -2000,15 +2057,15 @@ static inline bool should_continue_reclaim(struct zone *zone,
         * inactive lists are large enough, continue reclaiming
         */
        pages_for_compaction = (2UL << sc->order);
-       inactive_lru_pages = zone_nr_lru_pages(zone, sc, LRU_INACTIVE_FILE);
+       inactive_lru_pages = zone_nr_lru_pages(mz, LRU_INACTIVE_FILE);
        if (nr_swap_pages > 0)
-               inactive_lru_pages += zone_nr_lru_pages(zone, sc, LRU_INACTIVE_ANON);
+               inactive_lru_pages += zone_nr_lru_pages(mz, LRU_INACTIVE_ANON);
        if (sc->nr_reclaimed < pages_for_compaction &&
                        inactive_lru_pages > pages_for_compaction)
                return true;
 
        /* If compaction would go ahead or the allocation would succeed, stop */
-       switch (compaction_suitable(zone, sc->order)) {
+       switch (compaction_suitable(mz->zone, sc->order)) {
        case COMPACT_PARTIAL:
        case COMPACT_CONTINUE:
                return false;
@@ -2020,12 +2077,12 @@ static inline bool should_continue_reclaim(struct zone *zone,
 /*
  * This is a basic per-zone page freer.  Used by both kswapd and direct reclaim.
  */
-static void shrink_zone(int priority, struct zone *zone,
-                               struct scan_control *sc)
+static void shrink_mem_cgroup_zone(int priority, struct mem_cgroup_zone *mz,
+                                  struct scan_control *sc)
 {
        unsigned long nr[NR_LRU_LISTS];
        unsigned long nr_to_scan;
-       enum lru_list l;
+       enum lru_list lru;
        unsigned long nr_reclaimed, nr_scanned;
        unsigned long nr_to_reclaim = sc->nr_to_reclaim;
        struct blk_plug plug;
@@ -2033,19 +2090,19 @@ static void shrink_zone(int priority, struct zone *zone,
 restart:
        nr_reclaimed = 0;
        nr_scanned = sc->nr_scanned;
-       get_scan_count(zone, sc, nr, priority);
+       get_scan_count(mz, sc, nr, priority);
 
        blk_start_plug(&plug);
        while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
                                        nr[LRU_INACTIVE_FILE]) {
-               for_each_evictable_lru(l) {
-                       if (nr[l]) {
+               for_each_evictable_lru(lru) {
+                       if (nr[lru]) {
                                nr_to_scan = min_t(unsigned long,
-                                                  nr[l], SWAP_CLUSTER_MAX);
-                               nr[l] -= nr_to_scan;
+                                                  nr[lru], SWAP_CLUSTER_MAX);
+                               nr[lru] -= nr_to_scan;
 
-                               nr_reclaimed += shrink_list(l, nr_to_scan,
-                                                           zone, sc, priority);
+                               nr_reclaimed += shrink_list(lru, nr_to_scan,
+                                                           mz, sc, priority);
                        }
                }
                /*
@@ -2066,17 +2123,89 @@ restart:
         * Even if we did not try to evict anon pages at all, we want to
         * rebalance the anon lru active/inactive ratio.
         */
-       if (inactive_anon_is_low(zone, sc))
-               shrink_active_list(SWAP_CLUSTER_MAX, zone, sc, priority, 0);
+       if (inactive_anon_is_low(mz))
+               shrink_active_list(SWAP_CLUSTER_MAX, mz, sc, priority, 0);
 
        /* reclaim/compaction might need reclaim to continue */
-       if (should_continue_reclaim(zone, nr_reclaimed,
+       if (should_continue_reclaim(mz, nr_reclaimed,
                                        sc->nr_scanned - nr_scanned, sc))
                goto restart;
 
        throttle_vm_writeout(sc->gfp_mask);
 }
 
+static void shrink_zone(int priority, struct zone *zone,
+                       struct scan_control *sc)
+{
+       struct mem_cgroup *root = sc->target_mem_cgroup;
+       struct mem_cgroup_reclaim_cookie reclaim = {
+               .zone = zone,
+               .priority = priority,
+       };
+       struct mem_cgroup *memcg;
+
+       memcg = mem_cgroup_iter(root, NULL, &reclaim);
+       do {
+               struct mem_cgroup_zone mz = {
+                       .mem_cgroup = memcg,
+                       .zone = zone,
+               };
+
+               shrink_mem_cgroup_zone(priority, &mz, sc);
+               /*
+                * Limit reclaim has historically picked one memcg and
+                * scanned it with decreasing priority levels until
+                * nr_to_reclaim had been reclaimed.  This priority
+                * cycle is thus over after a single memcg.
+                *
+                * Direct reclaim and kswapd, on the other hand, have
+                * to scan all memory cgroups to fulfill the overall
+                * scan target for the zone.
+                */
+               if (!global_reclaim(sc)) {
+                       mem_cgroup_iter_break(root, memcg);
+                       break;
+               }
+               memcg = mem_cgroup_iter(root, memcg, &reclaim);
+       } while (memcg);
+}
+
+/* Returns true if compaction should go ahead for a high-order request */
+static inline bool compaction_ready(struct zone *zone, struct scan_control *sc)
+{
+       unsigned long balance_gap, watermark;
+       bool watermark_ok;
+
+       /* Do not consider compaction for orders reclaim is meant to satisfy */
+       if (sc->order <= PAGE_ALLOC_COSTLY_ORDER)
+               return false;
+
+       /*
+        * Compaction takes time to run and there are potentially other
+        * callers using the pages just freed. Continue reclaiming until
+        * there is a buffer of free pages available to give compaction
+        * a reasonable chance of completing and allocating the page
+        */
+       balance_gap = min(low_wmark_pages(zone),
+               (zone->present_pages + KSWAPD_ZONE_BALANCE_GAP_RATIO-1) /
+                       KSWAPD_ZONE_BALANCE_GAP_RATIO);
+       watermark = high_wmark_pages(zone) + balance_gap + (2UL << sc->order);
+       watermark_ok = zone_watermark_ok_safe(zone, 0, watermark, 0, 0);
+
+       /*
+        * If compaction is deferred, reclaim up to a point where
+        * compaction will have a chance of success when re-enabled
+        */
+       if (compaction_deferred(zone))
+               return watermark_ok;
+
+       /* If compaction is not ready to start, keep reclaiming */
+       if (!compaction_suitable(zone, sc->order))
+               return false;
+
+       return watermark_ok;
+}
+
 /*
  * This is the direct reclaim path, for page-allocating processes.  We only
  * try to reclaim pages from zones which will satisfy the caller's allocation
@@ -2094,8 +2223,9 @@ restart:
  * scan then give up on it.
  *
  * This function returns true if a zone is being reclaimed for a costly
- * high-order allocation and compaction is either ready to begin or deferred.
- * This indicates to the caller that it should retry the allocation or fail.
+ * high-order allocation and compaction is ready to begin. This indicates to
+ * the caller that it should consider retrying the allocation instead of
+ * further reclaim.
  */
 static bool shrink_zones(int priority, struct zonelist *zonelist,
                                        struct scan_control *sc)
@@ -2104,7 +2234,7 @@ static bool shrink_zones(int priority, struct zonelist *zonelist,
        struct zone *zone;
        unsigned long nr_soft_reclaimed;
        unsigned long nr_soft_scanned;
-       bool should_abort_reclaim = false;
+       bool aborted_reclaim = false;
 
        for_each_zone_zonelist_nodemask(zone, z, zonelist,
                                        gfp_zone(sc->gfp_mask), sc->nodemask) {
@@ -2114,7 +2244,7 @@ static bool shrink_zones(int priority, struct zonelist *zonelist,
                 * Take care memory controller reclaiming has small influence
                 * to global LRU.
                 */
-               if (scanning_global_lru(sc)) {
+               if (global_reclaim(sc)) {
                        if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
                                continue;
                        if (zone->all_unreclaimable && priority != DEF_PRIORITY)
@@ -2129,10 +2259,8 @@ static bool shrink_zones(int priority, struct zonelist *zonelist,
                                 * noticable problem, like transparent huge page
                                 * allocations.
                                 */
-                               if (sc->order > PAGE_ALLOC_COSTLY_ORDER &&
-                                       (compaction_suitable(zone, sc->order) ||
-                                        compaction_deferred(zone))) {
-                                       should_abort_reclaim = true;
+                               if (compaction_ready(zone, sc)) {
+                                       aborted_reclaim = true;
                                        continue;
                                }
                        }
@@ -2154,7 +2282,7 @@ static bool shrink_zones(int priority, struct zonelist *zonelist,
                shrink_zone(priority, zone, sc);
        }
 
-       return should_abort_reclaim;
+       return aborted_reclaim;
 }
 
 static bool zone_reclaimable(struct zone *zone)
@@ -2208,25 +2336,25 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
        struct zoneref *z;
        struct zone *zone;
        unsigned long writeback_threshold;
+       bool aborted_reclaim;
 
        get_mems_allowed();
        delayacct_freepages_start();
 
-       if (scanning_global_lru(sc))
+       if (global_reclaim(sc))
                count_vm_event(ALLOCSTALL);
 
        for (priority = DEF_PRIORITY; priority >= 0; priority--) {
                sc->nr_scanned = 0;
                if (!priority)
-                       disable_swap_token(sc->mem_cgroup);
-               if (shrink_zones(priority, zonelist, sc))
-                       break;
+                       disable_swap_token(sc->target_mem_cgroup);
+               aborted_reclaim = shrink_zones(priority, zonelist, sc);
 
                /*
                 * Don't shrink slabs when reclaiming memory from
                 * over limit cgroups
                 */
-               if (scanning_global_lru(sc)) {
+               if (global_reclaim(sc)) {
                        unsigned long lru_pages = 0;
                        for_each_zone_zonelist(zone, z, zonelist,
                                        gfp_zone(sc->gfp_mask)) {
@@ -2287,8 +2415,12 @@ out:
        if (oom_killer_disabled)
                return 0;
 
+       /* Aborted reclaim to try compaction? don't OOM, then */
+       if (aborted_reclaim)
+               return 1;
+
        /* top priority shrink_zones still had more to do? don't OOM, then */
-       if (scanning_global_lru(sc) && !all_unreclaimable(zonelist, sc))
+       if (global_reclaim(sc) && !all_unreclaimable(zonelist, sc))
                return 1;
 
        return 0;
@@ -2305,7 +2437,7 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
                .may_unmap = 1,
                .may_swap = 1,
                .order = order,
-               .mem_cgroup = NULL,
+               .target_mem_cgroup = NULL,
                .nodemask = nodemask,
        };
        struct shrink_control shrink = {
@@ -2325,7 +2457,7 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
 
-unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
+unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *memcg,
                                                gfp_t gfp_mask, bool noswap,
                                                struct zone *zone,
                                                unsigned long *nr_scanned)
@@ -2337,7 +2469,11 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
                .may_unmap = 1,
                .may_swap = !noswap,
                .order = 0,
-               .mem_cgroup = mem,
+               .target_mem_cgroup = memcg,
+       };
+       struct mem_cgroup_zone mz = {
+               .mem_cgroup = memcg,
+               .zone = zone,
        };
 
        sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
@@ -2354,7 +2490,7 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
         * will pick up pages from other mem cgroup's as well. We hack
         * the priority and make it zero.
         */
-       shrink_zone(0, zone, &sc);
+       shrink_mem_cgroup_zone(0, &mz, &sc);
 
        trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
 
@@ -2362,7 +2498,7 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
        return sc.nr_reclaimed;
 }
 
-unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
+unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                                           gfp_t gfp_mask,
                                           bool noswap)
 {
@@ -2375,7 +2511,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
                .may_swap = !noswap,
                .nr_to_reclaim = SWAP_CLUSTER_MAX,
                .order = 0,
-               .mem_cgroup = mem_cont,
+               .target_mem_cgroup = memcg,
                .nodemask = NULL, /* we don't care the placement */
                .gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
                                (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK),
@@ -2389,7 +2525,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
         * take care of from where we get pages. So the node where we start the
         * scan does not need to be the current node.
         */
-       nid = mem_cgroup_select_victim_node(mem_cont);
+       nid = mem_cgroup_select_victim_node(memcg);
 
        zonelist = NODE_DATA(nid)->node_zonelists;
 
@@ -2405,6 +2541,29 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
 }
 #endif
 
+static void age_active_anon(struct zone *zone, struct scan_control *sc,
+                           int priority)
+{
+       struct mem_cgroup *memcg;
+
+       if (!total_swap_pages)
+               return;
+
+       memcg = mem_cgroup_iter(NULL, NULL, NULL);
+       do {
+               struct mem_cgroup_zone mz = {
+                       .mem_cgroup = memcg,
+                       .zone = zone,
+               };
+
+               if (inactive_anon_is_low(&mz))
+                       shrink_active_list(SWAP_CLUSTER_MAX, &mz,
+                                          sc, priority, 0);
+
+               memcg = mem_cgroup_iter(NULL, memcg, NULL);
+       } while (memcg);
+}
+
 /*
  * pgdat_balanced is used when checking if a node is balanced for high-order
  * allocations. Only zones that meet watermarks and are in a zone allowed
@@ -2525,7 +2684,7 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
                 */
                .nr_to_reclaim = ULONG_MAX,
                .order = order,
-               .mem_cgroup = NULL,
+               .target_mem_cgroup = NULL,
        };
        struct shrink_control shrink = {
                .gfp_mask = sc.gfp_mask,
@@ -2564,9 +2723,7 @@ loop_again:
                         * Do some background aging of the anon list, to give
                         * pages a chance to be referenced before reclaiming.
                         */
-                       if (inactive_anon_is_low(zone, &sc))
-                               shrink_active_list(SWAP_CLUSTER_MAX, zone,
-                                                       &sc, priority, 0);
+                       age_active_anon(zone, &sc, priority);
 
                        if (!zone_watermark_ok_safe(zone, order,
                                        high_wmark_pages(zone), 0, 0)) {
@@ -3355,16 +3512,18 @@ int page_evictable(struct page *page, struct vm_area_struct *vma)
  */
 static void check_move_unevictable_page(struct page *page, struct zone *zone)
 {
-       VM_BUG_ON(PageActive(page));
+       struct lruvec *lruvec;
 
+       VM_BUG_ON(PageActive(page));
 retry:
        ClearPageUnevictable(page);
        if (page_evictable(page, NULL)) {
                enum lru_list l = page_lru_base_type(page);
 
                __dec_zone_state(zone, NR_UNEVICTABLE);
-               list_move(&page->lru, &zone->lru[l].list);
-               mem_cgroup_move_lists(page, LRU_UNEVICTABLE, l);
+               lruvec = mem_cgroup_lru_move_lists(zone, page,
+                                                  LRU_UNEVICTABLE, l);
+               list_move(&page->lru, &lruvec->lists[l]);
                __inc_zone_state(zone, NR_INACTIVE_ANON + l);
                __count_vm_event(UNEVICTABLE_PGRESCUED);
        } else {
@@ -3372,8 +3531,9 @@ retry:
                 * rotate unevictable list
                 */
                SetPageUnevictable(page);
-               list_move(&page->lru, &zone->lru[LRU_UNEVICTABLE].list);
-               mem_cgroup_rotate_lru_list(page, LRU_UNEVICTABLE);
+               lruvec = mem_cgroup_lru_move_lists(zone, page, LRU_UNEVICTABLE,
+                                                  LRU_UNEVICTABLE);
+               list_move(&page->lru, &lruvec->lists[LRU_UNEVICTABLE]);
                if (page_evictable(page, NULL))
                        goto retry;
        }
index 8fd603b1665e5be65bc10c93f146b860f706925d..f600557a76596231ef659fdff0c9f2ea8aed71ae 100644 (file)
@@ -295,7 +295,7 @@ void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
 }
 EXPORT_SYMBOL(__dec_zone_page_state);
 
-#ifdef CONFIG_CMPXCHG_LOCAL
+#ifdef CONFIG_HAVE_CMPXCHG_LOCAL
 /*
  * If we have cmpxchg_local support then we do not need to incur the overhead
  * that comes with local_irq_save/restore if we use this_cpu_cmpxchg.
index 330421e547139db18eef027495cfe2cee9538bc7..3d432068f627ea9407187a00d37113f5baf39b3c 100644 (file)
@@ -272,7 +272,8 @@ req_retry:
        in = pack_sg_list(chan->sg, out,
                          VIRTQUEUE_NUM, req->rc->sdata, req->rc->capacity);
 
-       err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
+       err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc,
+                               GFP_ATOMIC);
        if (err < 0) {
                if (err == -ENOSPC) {
                        chan->ring_bufs_avail = 0;
@@ -414,7 +415,8 @@ req_retry_pinned:
                in += pack_sg_list_p(chan->sg, out + in, VIRTQUEUE_NUM,
                                     in_pages, in_nr_pages, uidata, inlen);
 
-       err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
+       err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc,
+                               GFP_ATOMIC);
        if (err < 0) {
                if (err == -ENOSPC) {
                        chan->ring_bufs_avail = 0;
index cdcfcabb34ab8daf5b2275f52084c055926dac73..ef92864ac6258b32ec600ad5791e19d399d0965b 100644 (file)
@@ -156,17 +156,17 @@ static int bt_sock_create(struct net *net, struct socket *sock, int proto,
 
 void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
 {
-       write_lock_bh(&l->lock);
+       write_lock(&l->lock);
        sk_add_node(sk, &l->head);
-       write_unlock_bh(&l->lock);
+       write_unlock(&l->lock);
 }
 EXPORT_SYMBOL(bt_sock_link);
 
 void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
 {
-       write_lock_bh(&l->lock);
+       write_lock(&l->lock);
        sk_del_node_init(sk);
-       write_unlock_bh(&l->lock);
+       write_unlock(&l->lock);
 }
 EXPORT_SYMBOL(bt_sock_unlink);
 
index 4221bd256bddfd89e147f1605f0dd334aa042ea6..001307f810577111d0bbeea9265e0da37574cb5e 100644 (file)
@@ -711,7 +711,14 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
        if (rp->status)
                return;
 
-       memcpy(hdev->extfeatures, rp->features, 8);
+       switch (rp->page) {
+       case 0:
+               memcpy(hdev->features, rp->features, 8);
+               break;
+       case 1:
+               memcpy(hdev->host_features, rp->features, 8);
+               break;
+       }
 
        hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
 }
@@ -1047,9 +1054,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
        case LE_SCANNING_DISABLED:
                clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
 
-               cancel_delayed_work_sync(&hdev->adv_work);
-               queue_delayed_work(hdev->workqueue, &hdev->adv_work,
-                                                jiffies + ADV_CLEAR_TIMEOUT);
+               schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT);
                break;
 
        default:
@@ -2266,20 +2271,19 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
        struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
        int i;
 
-       skb_pull(skb, sizeof(*ev));
-
-       BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
-
        if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) {
                BT_ERR("Wrong event for mode %d", hdev->flow_ctl_mode);
                return;
        }
 
-       if (skb->len < ev->num_hndl * 4) {
+       if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
+                       ev->num_hndl * sizeof(struct hci_comp_pkts_info)) {
                BT_DBG("%s bad parameters", hdev->name);
                return;
        }
 
+       BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
+
        for (i = 0; i < ev->num_hndl; i++) {
                struct hci_comp_pkts_info *info = &ev->handles[i];
                struct hci_conn *conn;
index 6d94616af3129b3519c914c3458eb30cad40de05..0dcc9626677973d23708b53c7716a126adea107f 100644 (file)
@@ -767,7 +767,6 @@ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event,
                /* Detach sockets from device */
                read_lock(&hci_sk_list.lock);
                sk_for_each(sk, node, &hci_sk_list.head) {
-                       local_bh_disable();
                        bh_lock_sock_nested(sk);
                        if (hci_pi(sk)->hdev == hdev) {
                                hci_pi(sk)->hdev = NULL;
@@ -778,7 +777,6 @@ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event,
                                hci_dev_put(hdev);
                        }
                        bh_unlock_sock(sk);
-                       local_bh_enable();
                }
                read_unlock(&hci_sk_list.lock);
        }
index aa78d8c4b93be75f630e1389b4886ffdd4ab3623..faf0b11ac1d3610805e6d049f4a2e2221c35053a 100644 (file)
@@ -165,7 +165,7 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
 {
        int err;
 
-       write_lock_bh(&chan_list_lock);
+       write_lock(&chan_list_lock);
 
        if (psm && __l2cap_global_chan_by_addr(psm, src)) {
                err = -EADDRINUSE;
@@ -190,17 +190,17 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
        }
 
 done:
-       write_unlock_bh(&chan_list_lock);
+       write_unlock(&chan_list_lock);
        return err;
 }
 
 int l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid)
 {
-       write_lock_bh(&chan_list_lock);
+       write_lock(&chan_list_lock);
 
        chan->scid = scid;
 
-       write_unlock_bh(&chan_list_lock);
+       write_unlock(&chan_list_lock);
 
        return 0;
 }
@@ -289,9 +289,9 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
 
        chan->sk = sk;
 
-       write_lock_bh(&chan_list_lock);
+       write_lock(&chan_list_lock);
        list_add(&chan->global_l, &chan_list);
-       write_unlock_bh(&chan_list_lock);
+       write_unlock(&chan_list_lock);
 
        INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
 
@@ -306,9 +306,9 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
 
 void l2cap_chan_destroy(struct l2cap_chan *chan)
 {
-       write_lock_bh(&chan_list_lock);
+       write_lock(&chan_list_lock);
        list_del(&chan->global_l);
-       write_unlock_bh(&chan_list_lock);
+       write_unlock(&chan_list_lock);
 
        l2cap_chan_put(chan);
 }
@@ -543,14 +543,14 @@ static u8 l2cap_get_ident(struct l2cap_conn *conn)
         *  200 - 254 are used by utilities like l2ping, etc.
         */
 
-       spin_lock_bh(&conn->lock);
+       spin_lock(&conn->lock);
 
        if (++conn->tx_ident > 128)
                conn->tx_ident = 1;
 
        id = conn->tx_ident;
 
-       spin_unlock_bh(&conn->lock);
+       spin_unlock(&conn->lock);
 
        return id;
 }
@@ -1190,7 +1190,7 @@ inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdad
        }
 
        /* Set destination address and psm */
-       bacpy(&bt_sk(sk)->dst, src);
+       bacpy(&bt_sk(sk)->dst, dst);
        chan->psm = psm;
        chan->dcid = cid;
 
@@ -4702,7 +4702,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
 {
        struct l2cap_chan *c;
 
-       read_lock_bh(&chan_list_lock);
+       read_lock(&chan_list_lock);
 
        list_for_each_entry(c, &chan_list, global_l) {
                struct sock *sk = c->sk;
@@ -4715,7 +4715,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
                                        c->sec_level, c->mode);
 }
 
-       read_unlock_bh(&chan_list_lock);
+       read_unlock(&chan_list_lock);
 
        return 0;
 }
index 9ca5616166f7ad911204044b4a0dec80d6b1e099..c61d967012b2008547767dd69cec91be0f97d30d 100644 (file)
@@ -587,6 +587,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                        if (smp_conn_security(conn, sec.level))
                                break;
                        sk->sk_state = BT_CONFIG;
+                       chan->state = BT_CONFIG;
 
                /* or for ACL link, under defer_setup time */
                } else if (sk->sk_state == BT_CONNECT2 &&
@@ -731,6 +732,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
 
        if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
                sk->sk_state = BT_CONFIG;
+               pi->chan->state = BT_CONFIG;
 
                __l2cap_connect_rsp_defer(pi->chan);
                release_sock(sk);
index 2540944d871ffa0946565d78b6d23a9503a7f1c2..bc8e59dda78e2bf72f81c3eeacea748d5cbd78ae 100644 (file)
@@ -291,7 +291,7 @@ static u32 get_current_settings(struct hci_dev *hdev)
        if (!(hdev->features[4] & LMP_NO_BREDR))
                settings |= MGMT_SETTING_BREDR;
 
-       if (hdev->extfeatures[0] & LMP_HOST_LE)
+       if (hdev->host_features[0] & LMP_HOST_LE)
                settings |= MGMT_SETTING_LE;
 
        if (test_bit(HCI_AUTH, &hdev->flags))
@@ -2756,7 +2756,7 @@ int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
        if (!cmd)
                return -ENOENT;
 
-       err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
+       err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
        mgmt_pending_remove(cmd);
 
        return err;
index aea2bdd1510f2b4f083a4581105228b927cde858..f066678faeee838efae16243111a1bb51f47c8f3 100644 (file)
@@ -370,7 +370,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
                goto done;
        }
 
-       write_lock_bh(&rfcomm_sk_list.lock);
+       write_lock(&rfcomm_sk_list.lock);
 
        if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
                err = -EADDRINUSE;
@@ -381,7 +381,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
                sk->sk_state = BT_BOUND;
        }
 
-       write_unlock_bh(&rfcomm_sk_list.lock);
+       write_unlock(&rfcomm_sk_list.lock);
 
 done:
        release_sock(sk);
@@ -455,7 +455,7 @@ static int rfcomm_sock_listen(struct socket *sock, int backlog)
 
                err = -EINVAL;
 
-               write_lock_bh(&rfcomm_sk_list.lock);
+               write_lock(&rfcomm_sk_list.lock);
 
                for (channel = 1; channel < 31; channel++)
                        if (!__rfcomm_get_sock_by_addr(channel, src)) {
@@ -464,7 +464,7 @@ static int rfcomm_sock_listen(struct socket *sock, int backlog)
                                break;
                        }
 
-               write_unlock_bh(&rfcomm_sk_list.lock);
+               write_unlock(&rfcomm_sk_list.lock);
 
                if (err < 0)
                        goto done;
@@ -982,7 +982,7 @@ static int rfcomm_sock_debugfs_show(struct seq_file *f, void *p)
        struct sock *sk;
        struct hlist_node *node;
 
-       read_lock_bh(&rfcomm_sk_list.lock);
+       read_lock(&rfcomm_sk_list.lock);
 
        sk_for_each(sk, node, &rfcomm_sk_list.head) {
                seq_printf(f, "%s %s %d %d\n",
@@ -991,7 +991,7 @@ static int rfcomm_sock_debugfs_show(struct seq_file *f, void *p)
                                sk->sk_state, rfcomm_pi(sk)->channel);
        }
 
-       read_unlock_bh(&rfcomm_sk_list.lock);
+       read_unlock(&rfcomm_sk_list.lock);
 
        return 0;
 }
index fa8f4de53b997213b05a528434bf5ef14374651d..a2d4f5122a6a2030913814a8ebdc0cf6a381e29d 100644 (file)
@@ -76,7 +76,7 @@ struct rfcomm_dev {
 };
 
 static LIST_HEAD(rfcomm_dev_list);
-static DEFINE_RWLOCK(rfcomm_dev_lock);
+static DEFINE_SPINLOCK(rfcomm_dev_lock);
 
 static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
 static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
@@ -146,7 +146,7 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id)
 {
        struct rfcomm_dev *dev;
 
-       read_lock(&rfcomm_dev_lock);
+       spin_lock(&rfcomm_dev_lock);
 
        dev = __rfcomm_dev_get(id);
 
@@ -157,7 +157,7 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id)
                        rfcomm_dev_hold(dev);
        }
 
-       read_unlock(&rfcomm_dev_lock);
+       spin_unlock(&rfcomm_dev_lock);
 
        return dev;
 }
@@ -205,7 +205,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
        if (!dev)
                return -ENOMEM;
 
-       write_lock_bh(&rfcomm_dev_lock);
+       spin_lock(&rfcomm_dev_lock);
 
        if (req->dev_id < 0) {
                dev->id = 0;
@@ -290,7 +290,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
        __module_get(THIS_MODULE);
 
 out:
-       write_unlock_bh(&rfcomm_dev_lock);
+       spin_unlock(&rfcomm_dev_lock);
 
        if (err < 0)
                goto free;
@@ -327,9 +327,9 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev)
        if (atomic_read(&dev->opened) > 0)
                return;
 
-       write_lock_bh(&rfcomm_dev_lock);
+       spin_lock(&rfcomm_dev_lock);
        list_del_init(&dev->list);
-       write_unlock_bh(&rfcomm_dev_lock);
+       spin_unlock(&rfcomm_dev_lock);
 
        rfcomm_dev_put(dev);
 }
@@ -473,7 +473,7 @@ static int rfcomm_get_dev_list(void __user *arg)
 
        di = dl->dev_info;
 
-       read_lock_bh(&rfcomm_dev_lock);
+       spin_lock(&rfcomm_dev_lock);
 
        list_for_each_entry(dev, &rfcomm_dev_list, list) {
                if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
@@ -488,7 +488,7 @@ static int rfcomm_get_dev_list(void __user *arg)
                        break;
        }
 
-       read_unlock_bh(&rfcomm_dev_lock);
+       spin_unlock(&rfcomm_dev_lock);
 
        dl->dev_num = n;
        size = sizeof(*dl) + n * sizeof(*di);
@@ -766,9 +766,9 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
                rfcomm_dlc_unlock(dev->dlc);
 
                if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {
-                       write_lock_bh(&rfcomm_dev_lock);
+                       spin_lock(&rfcomm_dev_lock);
                        list_del_init(&dev->list);
-                       write_unlock_bh(&rfcomm_dev_lock);
+                       spin_unlock(&rfcomm_dev_lock);
 
                        rfcomm_dev_put(dev);
                }
index 5dc2f2126fac669a2f1b961efb8ce665768da2f2..8bf26d1bc5c181e25641622d980c0f812a6780e0 100644 (file)
@@ -482,7 +482,7 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
                goto done;
        }
 
-       write_lock_bh(&sco_sk_list.lock);
+       write_lock(&sco_sk_list.lock);
 
        if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
                err = -EADDRINUSE;
@@ -492,7 +492,7 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
                sk->sk_state = BT_BOUND;
        }
 
-       write_unlock_bh(&sco_sk_list.lock);
+       write_unlock(&sco_sk_list.lock);
 
 done:
        release_sock(sk);
@@ -965,14 +965,14 @@ static int sco_debugfs_show(struct seq_file *f, void *p)
        struct sock *sk;
        struct hlist_node *node;
 
-       read_lock_bh(&sco_sk_list.lock);
+       read_lock(&sco_sk_list.lock);
 
        sk_for_each(sk, node, &sco_sk_list.head) {
                seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src),
                                batostr(&bt_sk(sk)->dst), sk->sk_state);
        }
 
-       read_unlock_bh(&sco_sk_list.lock);
+       read_unlock(&sco_sk_list.lock);
 
        return 0;
 }
index f963f6b1884fd96dc12a96743a2f04669194cb3a..5ba0c844d508cbe549788e2219b4dd9ab1383149 100644 (file)
@@ -146,7 +146,7 @@ void br_fdb_cleanup(unsigned long _data)
        unsigned long next_timer = jiffies + br->ageing_time;
        int i;
 
-       spin_lock_bh(&br->hash_lock);
+       spin_lock(&br->hash_lock);
        for (i = 0; i < BR_HASH_SIZE; i++) {
                struct net_bridge_fdb_entry *f;
                struct hlist_node *h, *n;
@@ -162,7 +162,7 @@ void br_fdb_cleanup(unsigned long _data)
                                next_timer = this_timer;
                }
        }
-       spin_unlock_bh(&br->hash_lock);
+       spin_unlock(&br->hash_lock);
 
        mod_timer(&br->gc_timer, round_jiffies_up(next_timer));
 }
index 61570ee76fe6eca7824431663917a32827c90c9b..673728add60bf878c7b582a770bf2f3a48dc69bf 100644 (file)
@@ -146,15 +146,17 @@ void caif_flow_cb(struct sk_buff *skb)
        spin_lock_bh(&caifd->flow_lock);
        send_xoff = caifd->xoff;
        caifd->xoff = 0;
-       if (!WARN_ON(caifd->xoff_skb_dtor == NULL)) {
-               WARN_ON(caifd->xoff_skb != skb);
-               dtor = caifd->xoff_skb_dtor;
-               caifd->xoff_skb = NULL;
-               caifd->xoff_skb_dtor = NULL;
-       }
+       dtor = caifd->xoff_skb_dtor;
+
+       if (WARN_ON(caifd->xoff_skb != skb))
+               skb = NULL;
+
+       caifd->xoff_skb = NULL;
+       caifd->xoff_skb_dtor = NULL;
+
        spin_unlock_bh(&caifd->flow_lock);
 
-       if (dtor)
+       if (dtor && skb)
                dtor(skb);
 
        if (send_xoff)
index 5fc9eca8cd4149b2cc102ea32b0ae131db4e8452..fd7cbf5aa8956732f51637eeab3f512e00743fcb 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/slab.h>
-#include <linux/netdevice.h>
 #include <linux/mii.h>
 #include <linux/usb.h>
 #include <linux/usb/usbnet.h>
@@ -27,7 +26,7 @@ MODULE_LICENSE("GPL");
 #define CFUSB_ALIGNMENT 4      /* Number of bytes to align. */
 #define CFUSB_MAX_HEADLEN (CFUSB_PAD_DESCR_SZ + CFUSB_ALIGNMENT-1)
 #define STE_USB_VID 0x04cc     /* USB Product ID for ST-Ericsson */
-#define STE_USB_PID_CAIF 0x2306        /* Product id for CAIF Modems */
+#define STE_USB_PID_CAIF 0x230f        /* Product id for CAIF Modems */
 
 struct cfusbl {
        struct cflayer layer;
index 3a94eae7abe924d8d73d454b5a9330ab50bda968..b79747c4b64584cf9674920640ff0cf355efa45b 100644 (file)
@@ -510,10 +510,15 @@ int crush_do_rule(struct crush_map *map,
                switch (rule->steps[step].op) {
                case CRUSH_RULE_TAKE:
                        w[0] = rule->steps[step].arg1;
-                       if (force_pos >= 0) {
-                               BUG_ON(force_context[force_pos] != w[0]);
+
+                       /* find position in force_context/hierarchy */
+                       while (force_pos >= 0 &&
+                              force_context[force_pos] != w[0])
                                force_pos--;
-                       }
+                       /* and move past it */
+                       if (force_pos >= 0)
+                               force_pos--;
+
                        wsize = 1;
                        break;
 
index 85f3bc0a7062ae2d87e3f40bfb8b8f515fb09a66..b780cb7947ddd29f6ae23b11f3b030d22686beda 100644 (file)
@@ -15,10 +15,9 @@ int ceph_crypto_key_clone(struct ceph_crypto_key *dst,
                          const struct ceph_crypto_key *src)
 {
        memcpy(dst, src, sizeof(struct ceph_crypto_key));
-       dst->key = kmalloc(src->len, GFP_NOFS);
+       dst->key = kmemdup(src->key, src->len, GFP_NOFS);
        if (!dst->key)
                return -ENOMEM;
-       memcpy(dst->key, src->key, src->len);
        return 0;
 }
 
index f4f3f58f5234c1a5ce5eb4b54638c730f571ffb9..5e254055c91086287cd0d96091cb2eac50fecc38 100644 (file)
@@ -29,8 +29,8 @@ static void __register_request(struct ceph_osd_client *osdc,
                               struct ceph_osd_request *req);
 static void __unregister_linger_request(struct ceph_osd_client *osdc,
                                        struct ceph_osd_request *req);
-static int __send_request(struct ceph_osd_client *osdc,
-                         struct ceph_osd_request *req);
+static void __send_request(struct ceph_osd_client *osdc,
+                          struct ceph_osd_request *req);
 
 static int op_needs_trail(int op)
 {
@@ -1022,8 +1022,8 @@ out:
 /*
  * caller should hold map_sem (for read) and request_mutex
  */
-static int __send_request(struct ceph_osd_client *osdc,
-                         struct ceph_osd_request *req)
+static void __send_request(struct ceph_osd_client *osdc,
+                          struct ceph_osd_request *req)
 {
        struct ceph_osd_request_head *reqhead;
 
@@ -1041,7 +1041,6 @@ static int __send_request(struct ceph_osd_client *osdc,
        ceph_msg_get(req->r_request); /* send consumes a ref */
        ceph_con_send(&req->r_osd->o_con, req->r_request);
        req->r_sent = req->r_osd->o_incarnation;
-       return 0;
 }
 
 /*
@@ -1726,17 +1725,9 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
                        dout("send_request %p no up osds in pg\n", req);
                        ceph_monc_request_next_osdmap(&osdc->client->monc);
                } else {
-                       rc = __send_request(osdc, req);
-                       if (rc) {
-                               if (nofail) {
-                                       dout("osdc_start_request failed send, "
-                                            " will retry %lld\n", req->r_tid);
-                                       rc = 0;
-                               } else {
-                                       __unregister_request(osdc, req);
-                               }
-                       }
+                       __send_request(osdc, req);
                }
+               rc = 0;
        }
 
 out_unlock:
index f494675471a91b7f093665e6098ee7b3a91e6e4e..115dee1d985d40c5998abd4ddd57ae82123127c3 100644 (file)
@@ -1887,6 +1887,23 @@ void skb_set_dev(struct sk_buff *skb, struct net_device *dev)
 EXPORT_SYMBOL(skb_set_dev);
 #endif /* CONFIG_NET_NS */
 
+static void skb_warn_bad_offload(const struct sk_buff *skb)
+{
+       static const netdev_features_t null_features = 0;
+       struct net_device *dev = skb->dev;
+       const char *driver = "";
+
+       if (dev && dev->dev.parent)
+               driver = dev_driver_string(dev->dev.parent);
+
+       WARN(1, "%s: caps=(%pNF, %pNF) len=%d data_len=%d gso_size=%d "
+            "gso_type=%d ip_summed=%d\n",
+            driver, dev ? &dev->features : &null_features,
+            skb->sk ? &skb->sk->sk_route_caps : &null_features,
+            skb->len, skb->data_len, skb_shinfo(skb)->gso_size,
+            skb_shinfo(skb)->gso_type, skb->ip_summed);
+}
+
 /*
  * Invalidate hardware checksum when packet is to be mangled, and
  * complete checksum manually on outgoing path.
@@ -1900,8 +1917,8 @@ int skb_checksum_help(struct sk_buff *skb)
                goto out_set_summed;
 
        if (unlikely(skb_shinfo(skb)->gso_size)) {
-               /* Let GSO fix up the checksum. */
-               goto out_set_summed;
+               skb_warn_bad_offload(skb);
+               return -EINVAL;
        }
 
        offset = skb_checksum_start_offset(skb);
@@ -1961,16 +1978,7 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb,
        __skb_pull(skb, skb->mac_len);
 
        if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
-               struct net_device *dev = skb->dev;
-               struct ethtool_drvinfo info = {};
-
-               if (dev && dev->ethtool_ops && dev->ethtool_ops->get_drvinfo)
-                       dev->ethtool_ops->get_drvinfo(dev, &info);
-
-               WARN(1, "%s: caps=(%pNF, %pNF) len=%d data_len=%d ip_summed=%d\n",
-                    info.driver, dev ? &dev->features : NULL,
-                    skb->sk ? &skb->sk->sk_route_caps : NULL,
-                    skb->len, skb->data_len, skb->ip_summed);
+               skb_warn_bad_offload(skb);
 
                if (skb_header_cloned(skb) &&
                    (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
index abf4393a77b3b1de706931815a72680bfbd78586..a1727cda03d7bec9b565de4647dd3cff754fcbe8 100644 (file)
@@ -929,7 +929,7 @@ static ssize_t bql_show_inflight(struct netdev_queue *queue,
 }
 
 static struct netdev_queue_attribute bql_inflight_attribute =
-       __ATTR(inflight, S_IRUGO | S_IWUSR, bql_show_inflight, NULL);
+       __ATTR(inflight, S_IRUGO, bql_show_inflight, NULL);
 
 #define BQL_ATTR(NAME, FIELD)                                          \
 static ssize_t bql_show_ ## NAME(struct netdev_queue *queue,           \
@@ -1177,9 +1177,9 @@ static ssize_t store_xps_map(struct netdev_queue *queue,
                        nonempty = 1;
        }
 
-       if (nonempty)
-               RCU_INIT_POINTER(dev->xps_maps, new_dev_maps);
-       else {
+       if (nonempty) {
+               rcu_assign_pointer(dev->xps_maps, new_dev_maps);
+       else {
                kfree(new_dev_maps);
                RCU_INIT_POINTER(dev->xps_maps, NULL);
        }
index 0d38808a2305d06c642f7192ece302c9b2a971c2..556b082986696d8b80b09c4f687cff23bc540a45 100644 (file)
@@ -765,7 +765,7 @@ int __netpoll_setup(struct netpoll *np)
        }
 
        /* last thing to do is link it to the net device structure */
-       RCU_INIT_POINTER(ndev->npinfo, npinfo);
+       rcu_assign_pointer(ndev->npinfo, npinfo);
 
        return 0;
 
index dbf2ddafd52d34952161103c2586931c845926cf..f16444bc6cbb1ca25e57df0d18e7d267ceedf1f9 100644 (file)
@@ -1960,7 +1960,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        sz_idx = type>>2;
        kind = type&3;
 
-       if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN))
+       if (kind != 2 && !capable(CAP_NET_ADMIN))
                return -EPERM;
 
        if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
index 6fd44606fdd130a12712ac3f67ea6f92befab574..99b2596531bbc2a9a714bf262a8c79c61f1726b5 100644 (file)
@@ -46,7 +46,7 @@ __u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
 
        memcpy(hash, saddr, 16);
        for (i = 0; i < 4; i++)
-               secret[i] = net_secret[i] + daddr[i];
+               secret[i] = net_secret[i] + (__force u32)daddr[i];
        secret[4] = net_secret[4] +
                (((__force u16)sport << 16) + (__force u16)dport);
        for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
index 8f16257533779dcda5e5d18c5413d5d35c2d9162..028fc43aacbd3a75e2bd87554aa2f3a582900324 100644 (file)
@@ -49,13 +49,13 @@ static void dccp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
 }
 
 static void dccp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req *r, struct nlattr *bc)
+               struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        inet_diag_dump_icsk(&dccp_hashinfo, skb, cb, r, bc);
 }
 
 static int dccp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
-               struct inet_diag_req *req)
+               struct inet_diag_req_v2 *req)
 {
        return inet_diag_dump_one_icsk(&dccp_hashinfo, in_skb, nlh, req);
 }
index 2ab16e12520c525db2a84f0bb80eb4857f55f217..74d321a60e7b5751901c2a2e7d185e54043185ec 100644 (file)
@@ -388,7 +388,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
        }
 
        ifa->ifa_next = dn_db->ifa_list;
-       RCU_INIT_POINTER(dn_db->ifa_list, ifa);
+       rcu_assign_pointer(dn_db->ifa_list, ifa);
 
        dn_ifaddr_notify(RTM_NEWADDR, ifa);
        blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
@@ -1093,7 +1093,7 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
 
        memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms));
 
-       RCU_INIT_POINTER(dev->dn_ptr, dn_db);
+       rcu_assign_pointer(dev->dn_ptr, dn_db);
        dn_db->dev = dev;
        init_timer(&dn_db->timer);
 
index 69975e0bcdea7a5c1655a9eb0de70011c5325d59..1531135130db0eb096b074e828cae8aab10b13c4 100644 (file)
@@ -108,7 +108,7 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
        if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
                return;
 
-       if (security_netlink_recv(skb, CAP_NET_ADMIN))
+       if (!capable(CAP_NET_ADMIN))
                RCV_SKB_FAIL(-EPERM);
 
        /* Eventually we might send routing messages too */
index 65f01dc47565bcc26282d4472bbd9c3fb2d3712c..e41c40f48cfe053f28baa3fe9dcf4179ce5a1f37 100644 (file)
@@ -258,7 +258,7 @@ static struct in_device *inetdev_init(struct net_device *dev)
                ip_mc_up(in_dev);
 
        /* we can receive as soon as ip_ptr is set -- do this last */
-       RCU_INIT_POINTER(dev->ip_ptr, in_dev);
+       rcu_assign_pointer(dev->ip_ptr, in_dev);
 out:
        return in_dev;
 out_kfree:
index d04b13ae18fecc3b641ecf5a45279a620307f15f..2b555a5521e0b60f8b373b4c72e70d896da15ff0 100644 (file)
@@ -205,7 +205,7 @@ static inline struct tnode *node_parent_rcu(const struct rt_trie_node *node)
        return (struct tnode *)(parent & ~NODE_TYPE_MASK);
 }
 
-/* Same as RCU_INIT_POINTER
+/* Same as rcu_assign_pointer
  * but that macro() assumes that value is a pointer.
  */
 static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr)
@@ -529,7 +529,7 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *
        if (n)
                node_set_parent(n, tn);
 
-       RCU_INIT_POINTER(tn->child[i], n);
+       rcu_assign_pointer(tn->child[i], n);
 }
 
 #define MAX_WORK 10
@@ -1015,7 +1015,7 @@ static void trie_rebalance(struct trie *t, struct tnode *tn)
 
                tp = node_parent((struct rt_trie_node *) tn);
                if (!tp)
-                       RCU_INIT_POINTER(t->trie, (struct rt_trie_node *)tn);
+                       rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
 
                tnode_free_flush();
                if (!tp)
@@ -1027,7 +1027,7 @@ static void trie_rebalance(struct trie *t, struct tnode *tn)
        if (IS_TNODE(tn))
                tn = (struct tnode *)resize(t, (struct tnode *)tn);
 
-       RCU_INIT_POINTER(t->trie, (struct rt_trie_node *)tn);
+       rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
        tnode_free_flush();
 }
 
@@ -1164,7 +1164,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
                        put_child(t, (struct tnode *)tp, cindex,
                                  (struct rt_trie_node *)tn);
                } else {
-                       RCU_INIT_POINTER(t->trie, (struct rt_trie_node *)tn);
+                       rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
                        tp = tn;
                }
        }
index 5104bc0bbdbe73d43f0b92e659e7fb2dda24928f..450e5d21ed2af271574874479bd0c0d341bf6b38 100644 (file)
@@ -1249,7 +1249,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
 
        im->next_rcu = in_dev->mc_list;
        in_dev->mc_count++;
-       RCU_INIT_POINTER(in_dev->mc_list, im);
+       rcu_assign_pointer(in_dev->mc_list, im);
 
 #ifdef CONFIG_IP_MULTICAST
        igmpv3_del_delrec(in_dev, im->multiaddr);
@@ -1821,7 +1821,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
        iml->next_rcu = inet->mc_list;
        iml->sflist = NULL;
        iml->sfmode = MCAST_EXCLUDE;
-       RCU_INIT_POINTER(inet->mc_list, iml);
+       rcu_assign_pointer(inet->mc_list, iml);
        ip_mc_inc_group(in_dev, addr);
        err = 0;
 done:
@@ -2008,7 +2008,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
                        atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
                        kfree_rcu(psl, rcu);
                }
-               RCU_INIT_POINTER(pmc->sflist, newpsl);
+               rcu_assign_pointer(pmc->sflist, newpsl);
                psl = newpsl;
        }
        rv = 1; /* > 0 for insert logic below if sl_count is 0 */
@@ -2111,7 +2111,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
        } else
                (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
                        0, NULL, 0);
-       RCU_INIT_POINTER(pmc->sflist, newpsl);
+       rcu_assign_pointer(pmc->sflist, newpsl);
        pmc->sfmode = msf->imsf_fmode;
        err = 0;
 done:
index 2240a8e8c44dbefaed2a83aa44b6e058970fc65b..fcf281819cd48f51c824674fbb63673922d5cef0 100644 (file)
@@ -71,7 +71,7 @@ static inline void inet_diag_unlock_handler(
 }
 
 int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
-                             struct sk_buff *skb, struct inet_diag_req *req,
+                             struct sk_buff *skb, struct inet_diag_req_v2 *req,
                              u32 pid, u32 seq, u16 nlmsg_flags,
                              const struct nlmsghdr *unlh)
 {
@@ -193,7 +193,7 @@ nlmsg_failure:
 EXPORT_SYMBOL_GPL(inet_sk_diag_fill);
 
 static int inet_csk_diag_fill(struct sock *sk,
-                             struct sk_buff *skb, struct inet_diag_req *req,
+                             struct sk_buff *skb, struct inet_diag_req_v2 *req,
                              u32 pid, u32 seq, u16 nlmsg_flags,
                              const struct nlmsghdr *unlh)
 {
@@ -202,7 +202,7 @@ static int inet_csk_diag_fill(struct sock *sk,
 }
 
 static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
-                              struct sk_buff *skb, struct inet_diag_req *req,
+                              struct sk_buff *skb, struct inet_diag_req_v2 *req,
                               u32 pid, u32 seq, u16 nlmsg_flags,
                               const struct nlmsghdr *unlh)
 {
@@ -253,7 +253,7 @@ nlmsg_failure:
 }
 
 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
-                       struct inet_diag_req *r, u32 pid, u32 seq, u16 nlmsg_flags,
+                       struct inet_diag_req_v2 *r, u32 pid, u32 seq, u16 nlmsg_flags,
                        const struct nlmsghdr *unlh)
 {
        if (sk->sk_state == TCP_TIME_WAIT)
@@ -264,7 +264,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
 }
 
 int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_skb,
-               const struct nlmsghdr *nlh, struct inet_diag_req *req)
+               const struct nlmsghdr *nlh, struct inet_diag_req_v2 *req)
 {
        int err;
        struct sock *sk;
@@ -333,7 +333,7 @@ EXPORT_SYMBOL_GPL(inet_diag_dump_one_icsk);
 
 static int inet_diag_get_exact(struct sk_buff *in_skb,
                               const struct nlmsghdr *nlh,
-                              struct inet_diag_req *req)
+                              struct inet_diag_req_v2 *req)
 {
        const struct inet_diag_handler *handler;
        int err;
@@ -540,7 +540,7 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
 static int inet_csk_diag_dump(struct sock *sk,
                              struct sk_buff *skb,
                              struct netlink_callback *cb,
-                             struct inet_diag_req *r,
+                             struct inet_diag_req_v2 *r,
                              const struct nlattr *bc)
 {
        if (!inet_diag_bc_sk(bc, sk))
@@ -554,7 +554,7 @@ static int inet_csk_diag_dump(struct sock *sk,
 static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
                               struct sk_buff *skb,
                               struct netlink_callback *cb,
-                              struct inet_diag_req *r,
+                              struct inet_diag_req_v2 *r,
                               const struct nlattr *bc)
 {
        if (bc != NULL) {
@@ -639,7 +639,7 @@ nlmsg_failure:
 
 static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
                               struct netlink_callback *cb,
-                              struct inet_diag_req *r,
+                              struct inet_diag_req_v2 *r,
                               const struct nlattr *bc)
 {
        struct inet_diag_entry entry;
@@ -721,7 +721,7 @@ out:
 }
 
 void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
-               struct netlink_callback *cb, struct inet_diag_req *r, struct nlattr *bc)
+               struct netlink_callback *cb, struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        int i, num;
        int s_i, s_num;
@@ -872,7 +872,7 @@ out:
 EXPORT_SYMBOL_GPL(inet_diag_dump_icsk);
 
 static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req *r, struct nlattr *bc)
+               struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        const struct inet_diag_handler *handler;
 
@@ -887,12 +887,12 @@ static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
 static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct nlattr *bc = NULL;
-       int hdrlen = sizeof(struct inet_diag_req);
+       int hdrlen = sizeof(struct inet_diag_req_v2);
 
        if (nlmsg_attrlen(cb->nlh, hdrlen))
                bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE);
 
-       return __inet_diag_dump(skb, cb, (struct inet_diag_req *)NLMSG_DATA(cb->nlh), bc);
+       return __inet_diag_dump(skb, cb, (struct inet_diag_req_v2 *)NLMSG_DATA(cb->nlh), bc);
 }
 
 static inline int inet_diag_type2proto(int type)
@@ -909,10 +909,10 @@ static inline int inet_diag_type2proto(int type)
 
 static int inet_diag_dump_compat(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct inet_diag_req_compat *rc = NLMSG_DATA(cb->nlh);
-       struct inet_diag_req req;
+       struct inet_diag_req *rc = NLMSG_DATA(cb->nlh);
+       struct inet_diag_req_v2 req;
        struct nlattr *bc = NULL;
-       int hdrlen = sizeof(struct inet_diag_req_compat);
+       int hdrlen = sizeof(struct inet_diag_req);
 
        req.sdiag_family = AF_UNSPEC; /* compatibility */
        req.sdiag_protocol = inet_diag_type2proto(cb->nlh->nlmsg_type);
@@ -929,8 +929,8 @@ static int inet_diag_dump_compat(struct sk_buff *skb, struct netlink_callback *c
 static int inet_diag_get_exact_compat(struct sk_buff *in_skb,
                               const struct nlmsghdr *nlh)
 {
-       struct inet_diag_req_compat *rc = NLMSG_DATA(nlh);
-       struct inet_diag_req req;
+       struct inet_diag_req *rc = NLMSG_DATA(nlh);
+       struct inet_diag_req_v2 req;
 
        req.sdiag_family = rc->idiag_family;
        req.sdiag_protocol = inet_diag_type2proto(nlh->nlmsg_type);
@@ -943,7 +943,7 @@ static int inet_diag_get_exact_compat(struct sk_buff *in_skb,
 
 static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-       int hdrlen = sizeof(struct inet_diag_req_compat);
+       int hdrlen = sizeof(struct inet_diag_req);
 
        if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX ||
            nlmsg_len(nlh) < hdrlen)
@@ -970,7 +970,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
 
 static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 {
-       int hdrlen = sizeof(struct inet_diag_req);
+       int hdrlen = sizeof(struct inet_diag_req_v2);
 
        if (nlmsg_len(h) < hdrlen)
                return -EINVAL;
@@ -990,7 +990,7 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
                                          inet_diag_dump, NULL, 0);
        }
 
-       return inet_diag_get_exact(skb, h, (struct inet_diag_req *)NLMSG_DATA(h));
+       return inet_diag_get_exact(skb, h, (struct inet_diag_req_v2 *)NLMSG_DATA(h));
 }
 
 static struct sock_diag_handler inet_diag_handler = {
index 86f13c67ea8579d32a4f076063ea1777c75e166b..bf4a9c4808e1faaa7461a472f224a4d3c8edf379 100644 (file)
@@ -136,7 +136,7 @@ static int addr_compare(const struct inetpeer_addr *a,
        for (i = 0; i < n; i++) {
                if (a->addr.a6[i] == b->addr.a6[i])
                        continue;
-               if (a->addr.a6[i] < b->addr.a6[i])
+               if ((__force u32)a->addr.a6[i] < (__force u32)b->addr.a6[i])
                        return -1;
                return 1;
        }
@@ -447,6 +447,7 @@ relookup:
                p->rate_last = 0;
                p->pmtu_expires = 0;
                p->pmtu_orig = 0;
+               p->redirect_genid = 0;
                memset(&p->redirect_learned, 0, sizeof(p->redirect_learned));
 
 
index 7e4ec9fc2cef3c38bd0e659a8c36548ff25fe429..6e412a60a91f27acb3ea2241a860c6a18401fed8 100644 (file)
@@ -141,7 +141,7 @@ __be32 ic_servaddr = NONE;  /* Boot server IP address */
 __be32 root_server_addr = NONE;        /* Address of NFS server */
 u8 root_server_path[256] = { 0, };     /* Path to mount as root */
 
-u32 ic_dev_xid;                /* Device under configuration */
+__be32 ic_dev_xid;             /* Device under configuration */
 
 /* vendor class identifier */
 static char vendor_class_identifier[253] __initdata;
@@ -859,9 +859,9 @@ static int __init ic_bootp_string(char *dest, char *src, int len, int max)
  */
 static void __init ic_do_bootp_ext(u8 *ext)
 {
-       u8 servers;
-       int i;
-       u16 mtu;
+       u8 servers;
+       int i;
+       __be16 mtu;
 
 #ifdef IPCONFIG_DEBUG
        u8 *c;
index 413ed1ba7a5a16976d80ca39fadad9ec719dd6e5..22a19931530910a4f6eae62fb28889f019b2dc68 100644 (file)
@@ -231,7 +231,7 @@ static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
             (iter = rtnl_dereference(*tp)) != NULL;
             tp = &iter->next) {
                if (t == iter) {
-                       RCU_INIT_POINTER(*tp, t->next);
+                       rcu_assign_pointer(*tp, t->next);
                        break;
                }
        }
@@ -241,8 +241,8 @@ static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
 {
        struct ip_tunnel __rcu **tp = ipip_bucket(ipn, t);
 
-       RCU_INIT_POINTER(t->next, rtnl_dereference(*tp));
-       RCU_INIT_POINTER(*tp, t);
+       rcu_assign_pointer(t->next, rtnl_dereference(*tp));
+       rcu_assign_pointer(*tp, t);
 }
 
 static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
@@ -792,7 +792,7 @@ static int __net_init ipip_fb_tunnel_init(struct net_device *dev)
                return -ENOMEM;
 
        dev_hold(dev);
-       RCU_INIT_POINTER(ipn->tunnels_wc[0], tunnel);
+       rcu_assign_pointer(ipn->tunnels_wc[0], tunnel);
        return 0;
 }
 
index 8e54490ee3f490d6c07c99e87481b3a1dd395744..7bc2db6db8d407987bbd06f59a25cf1b0f488989 100644 (file)
@@ -1225,7 +1225,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
 
                ret = ip_ra_control(sk, 1, mrtsock_destruct);
                if (ret == 0) {
-                       RCU_INIT_POINTER(mrt->mroute_sk, sk);
+                       rcu_assign_pointer(mrt->mroute_sk, sk);
                        IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
                }
                rtnl_unlock();
index a057fe64debde83a8b2fe1d29a78d7eb00954e8b..94d45e1f8882558ae45575ee7723f5aacd6022d9 100644 (file)
@@ -431,7 +431,7 @@ __ipq_rcv_skb(struct sk_buff *skb)
        if (type <= IPQM_BASE)
                return;
 
-       if (security_netlink_recv(skb, CAP_NET_ADMIN))
+       if (!capable(CAP_NET_ADMIN))
                RCV_SKB_FAIL(-EPERM);
 
        spin_lock_bh(&queue_lock);
index 43d4c3b223699aee36de3c3c79c6d82b5236a4c0..aea5a199c37a341be3fab08500f1c35a34cbf215 100644 (file)
@@ -140,13 +140,14 @@ static void ping_v4_unhash(struct sock *sk)
                write_lock_bh(&ping_table.lock);
                hlist_nulls_del(&sk->sk_nulls_node);
                sock_put(sk);
-               isk->inet_num = isk->inet_sport = 0;
+               isk->inet_num = 0;
+               isk->inet_sport = 0;
                sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
                write_unlock_bh(&ping_table.lock);
        }
 }
 
-static struct sock *ping_v4_lookup(struct net *net, u32 saddr, u32 daddr,
+static struct sock *ping_v4_lookup(struct net *net, __be32 saddr, __be32 daddr,
                                   u16 ident, int dif)
 {
        struct hlist_nulls_head *hslot = ping_hashslot(&ping_table, net, ident);
@@ -154,15 +155,15 @@ static struct sock *ping_v4_lookup(struct net *net, u32 saddr, u32 daddr,
        struct inet_sock *isk;
        struct hlist_nulls_node *hnode;
 
-       pr_debug("try to find: num = %d, daddr = %ld, dif = %d\n",
-                        (int)ident, (unsigned long)daddr, dif);
+       pr_debug("try to find: num = %d, daddr = %pI4, dif = %d\n",
+                        (int)ident, &daddr, dif);
        read_lock_bh(&ping_table.lock);
 
        ping_portaddr_for_each_entry(sk, hnode, hslot) {
                isk = inet_sk(sk);
 
-               pr_debug("found: %p: num = %d, daddr = %ld, dif = %d\n", sk,
-                        (int)isk->inet_num, (unsigned long)isk->inet_rcv_saddr,
+               pr_debug("found: %p: num = %d, daddr = %pI4, dif = %d\n", sk,
+                        (int)isk->inet_num, &isk->inet_rcv_saddr,
                         sk->sk_bound_dev_if);
 
                pr_debug("iterate\n");
@@ -254,7 +255,7 @@ static int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                sk, addr->sin_addr.s_addr, ntohs(addr->sin_port));
 
        chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr);
-       if (addr->sin_addr.s_addr == INADDR_ANY)
+       if (addr->sin_addr.s_addr == htonl(INADDR_ANY))
                chk_addr_ret = RTN_LOCAL;
 
        if ((sysctl_ip_nonlocal_bind == 0 &&
@@ -278,9 +279,9 @@ static int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                goto out;
        }
 
-       pr_debug("after bind(): num = %d, daddr = %ld, dif = %d\n",
+       pr_debug("after bind(): num = %d, daddr = %pI4, dif = %d\n",
                (int)isk->inet_num,
-               (unsigned long) isk->inet_rcv_saddr,
+               &isk->inet_rcv_saddr,
                (int)sk->sk_bound_dev_if);
 
        err = 0;
@@ -407,7 +408,7 @@ out:
 struct pingfakehdr {
        struct icmphdr icmph;
        struct iovec *iov;
-       u32 wcheck;
+       __wsum wcheck;
 };
 
 static int ping_getfrag(void *from, char * to,
@@ -459,7 +460,7 @@ static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        struct rtable *rt = NULL;
        struct ip_options_data opt_copy;
        int free = 0;
-       u32 saddr, daddr, faddr;
+       __be32 saddr, daddr, faddr;
        u8  tos;
        int err;
 
@@ -696,8 +697,8 @@ void ping_rcv(struct sk_buff *skb)
        struct net *net = dev_net(skb->dev);
        struct iphdr *iph = ip_hdr(skb);
        struct icmphdr *icmph = icmp_hdr(skb);
-       u32 saddr = iph->saddr;
-       u32 daddr = iph->daddr;
+       __be32 saddr = iph->saddr;
+       __be32 daddr = iph->daddr;
 
        /* We assume the packet has already been checked by icmp_rcv */
 
index 8cd357a8be7990b5212253d95fa72a1f740a3edf..ed3f2ad42e0f0ea881e507d8c91e7962d336d824 100644 (file)
@@ -35,13 +35,13 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
 }
 
 static void tcp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req *r, struct nlattr *bc)
+               struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        inet_diag_dump_icsk(&tcp_hashinfo, skb, cb, r, bc);
 }
 
 static int tcp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
-               struct inet_diag_req *req)
+               struct inet_diag_req_v2 *req)
 {
        return inet_diag_dump_one_icsk(&tcp_hashinfo, in_skb, nlh, req);
 }
index 7fed04f875c1acf4448333d18276c928c3a0180a..49978788a9dc31e13cec48b472c45234343be13a 100644 (file)
@@ -108,7 +108,7 @@ void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
        tcp = tcp_from_cgproto(cg_proto);
        percpu_counter_destroy(&tcp->tcp_sockets_allocated);
 
-       val = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_USAGE);
+       val = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
 
        if (val != RESOURCE_MAX)
                jump_label_dec(&memcg_socket_limit_enabled);
index 69f8a7ca63dd8c65ed6357e28af036d002eb65c5..8a949f19deb6dc93542396138004a5a6b2bfeeab 100644 (file)
 #include <linux/udp.h>
 #include <net/udp.h>
 #include <net/udplite.h>
-#include <linux/inet_diag.h>
 #include <linux/sock_diag.h>
 
 static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
-               struct netlink_callback *cb, struct inet_diag_req *req,
+               struct netlink_callback *cb, struct inet_diag_req_v2 *req,
                struct nlattr *bc)
 {
        if (!inet_diag_bc_sk(bc, sk))
@@ -30,7 +29,7 @@ static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
 }
 
 static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
-               const struct nlmsghdr *nlh, struct inet_diag_req *req)
+               const struct nlmsghdr *nlh, struct inet_diag_req_v2 *req)
 {
        int err = -EINVAL;
        struct sock *sk;
@@ -88,7 +87,7 @@ out_nosk:
 }
 
 static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req *r, struct nlattr *bc)
+               struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        int num, s_num, slot, s_slot;
 
@@ -136,13 +135,13 @@ done:
 }
 
 static void udp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req *r, struct nlattr *bc)
+               struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        udp_dump(&udp_table, skb, cb, r, bc);
 }
 
 static int udp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
-               struct inet_diag_req *req)
+               struct inet_diag_req_v2 *req)
 {
        return udp_dump_one(&udp_table, in_skb, nlh, req);
 }
@@ -154,13 +153,13 @@ static const struct inet_diag_handler udp_diag_handler = {
 };
 
 static void udplite_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req *r, struct nlattr *bc)
+               struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        udp_dump(&udplite_table, skb, cb, r, bc);
 }
 
 static int udplite_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
-               struct inet_diag_req *req)
+               struct inet_diag_req_v2 *req)
 {
        return udp_dump_one(&udplite_table, in_skb, nlh, req);
 }
index 0ba0866230c99367db4f3706b15cb2ed0ff91dbf..a225d5ee3c2fc877f25e7af417c58de124fe8cb9 100644 (file)
@@ -429,7 +429,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
        ndev->tstamp = jiffies;
        addrconf_sysctl_register(ndev);
        /* protected by rtnl_lock */
-       RCU_INIT_POINTER(dev->ip6_ptr, ndev);
+       rcu_assign_pointer(dev->ip6_ptr, ndev);
 
        /* Join all-node multicast group */
        ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes);
index ae08aee1773c678187f8be84414f95ac472aa426..251e7cd75e89787f5346037a278bfd7e5b8c8ced 100644 (file)
@@ -575,7 +575,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
        }
        if (np->rxopt.bits.rxorigdstaddr) {
                struct sockaddr_in6 sin6;
-               u16 *ports = (u16 *) skb_transport_header(skb);
+               __be16 *ports = (__be16 *) skb_transport_header(skb);
 
                if (skb_transport_offset(skb) + 4 <= skb->len) {
                        /* All current transport protocols have the port numbers in the
index e1f7761815f36903687dd45f0da702c86ec4f159..aa21da6a09cd66bc2cad80cb227d8514e5466658 100644 (file)
@@ -218,8 +218,8 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
 {
        struct ip6_tnl __rcu **tp = ip6_tnl_bucket(ip6n, &t->parms);
 
-       RCU_INIT_POINTER(t->next , rtnl_dereference(*tp));
-       RCU_INIT_POINTER(*tp, t);
+       rcu_assign_pointer(t->next , rtnl_dereference(*tp));
+       rcu_assign_pointer(*tp, t);
 }
 
 /**
@@ -237,7 +237,7 @@ ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
             (iter = rtnl_dereference(*tp)) != NULL;
             tp = &iter->next) {
                if (t == iter) {
-                       RCU_INIT_POINTER(*tp, t->next);
+                       rcu_assign_pointer(*tp, t->next);
                        break;
                }
        }
@@ -1450,7 +1450,7 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
 
        t->parms.proto = IPPROTO_IPV6;
        dev_hold(dev);
-       RCU_INIT_POINTER(ip6n->tnls_wc[0], t);
+       rcu_assign_pointer(ip6n->tnls_wc[0], t);
        return 0;
 }
 
index fb80a23c6640a15bd3ee32ef2c29884dea9b0f3d..a34c9e4c792ca1adb3360e67edb5f2b2f64e7cb7 100644 (file)
@@ -432,7 +432,7 @@ __ipq_rcv_skb(struct sk_buff *skb)
        if (type <= IPQM_BASE)
                return;
 
-       if (security_netlink_recv(skb, CAP_NET_ADMIN))
+       if (!capable(CAP_NET_ADMIN))
                RCV_SKB_FAIL(-EPERM);
 
        spin_lock_bh(&queue_lock);
index fdeb6d03da812d136874fccc870b90c69efee7b1..da2e92d05c15a5052ea2cc19ba9bfc5751c23cf6 100644 (file)
@@ -237,8 +237,8 @@ static int snmp6_dev_seq_show(struct seq_file *seq, void *v)
        struct inet6_dev *idev = (struct inet6_dev *)seq->private;
 
        seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex);
-       snmp6_seq_show_item(seq, (void __percpu **)idev->stats.ipv6, NULL,
-                           snmp6_ipstats_list);
+       snmp6_seq_show_item64(seq, (void __percpu **)idev->stats.ipv6,
+                           snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp));
        snmp6_seq_show_item(seq, NULL, idev->stats.icmpv6dev->mibs,
                            snmp6_icmp6_list);
        snmp6_seq_show_icmpv6msg(seq, idev->stats.icmpv6msgdev->mibs);
index a4894f4f1944e600d93a1f2a9cde719cfe528bb0..d02f7e4dd6113c8c23cb8a3f7ee9be9cbae37685 100644 (file)
@@ -131,7 +131,7 @@ static mh_filter_t __rcu *mh_filter __read_mostly;
 
 int rawv6_mh_filter_register(mh_filter_t filter)
 {
-       RCU_INIT_POINTER(mh_filter, filter);
+       rcu_assign_pointer(mh_filter, filter);
        return 0;
 }
 EXPORT_SYMBOL(rawv6_mh_filter_register);
index 07361dfa80852cbbe4db66027f8da5ef13ade4c1..8c2e3ab58f2af211c04f17c337929bd2802cbe27 100644 (file)
@@ -1091,6 +1091,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
        else {
                neigh = ip6_neigh_lookup(&rt->dst, &fl6->daddr);
                if (IS_ERR(neigh)) {
+                       in6_dev_put(idev);
                        dst_free(&rt->dst);
                        return ERR_CAST(neigh);
                }
index 3b6dac956bb09e74cd9119b7763b786b02789743..133768e52912bd561930736f36c0085c594000b4 100644 (file)
@@ -182,7 +182,7 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
             (iter = rtnl_dereference(*tp)) != NULL;
             tp = &iter->next) {
                if (t == iter) {
-                       RCU_INIT_POINTER(*tp, t->next);
+                       rcu_assign_pointer(*tp, t->next);
                        break;
                }
        }
@@ -192,8 +192,8 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
 {
        struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t);
 
-       RCU_INIT_POINTER(t->next, rtnl_dereference(*tp));
-       RCU_INIT_POINTER(*tp, t);
+       rcu_assign_pointer(t->next, rtnl_dereference(*tp));
+       rcu_assign_pointer(*tp, t);
 }
 
 static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
@@ -393,7 +393,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
        p->addr = a->addr;
        p->flags = a->flags;
        t->prl_count++;
-       RCU_INIT_POINTER(t->prl, p);
+       rcu_assign_pointer(t->prl, p);
 out:
        return err;
 }
@@ -1177,7 +1177,7 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)
        if (!dev->tstats)
                return -ENOMEM;
        dev_hold(dev);
-       RCU_INIT_POINTER(sitn->tunnels_wc[0], tunnel);
+       rcu_assign_pointer(sitn->tunnels_wc[0], tunnel);
        return 0;
 }
 
index 96debba2c407bfeeb91d95ce1524521a07745958..1068f668ac4ec3434b1524624df98c5bf08e5074 100644 (file)
@@ -332,7 +332,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
        status = WLAN_STATUS_SUCCESS;
 
        /* activate it for RX */
-       RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
+       rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
 
        if (timeout)
                mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
index 850bb96bd6805204685083dde687b8097bd19b0f..296620d6ca0c0c2388f05ffaffd9c5d832eb3cbd 100644 (file)
@@ -616,7 +616,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
 
        sdata->vif.bss_conf.dtim_period = new->dtim_period;
 
-       RCU_INIT_POINTER(sdata->u.ap.beacon, new);
+       rcu_assign_pointer(sdata->u.ap.beacon, new);
 
        synchronize_rcu();
 
@@ -791,7 +791,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
                        ret = sta_info_move_state_checked(sta,
                                        IEEE80211_STA_AUTHORIZED);
-               else
+               else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
                        ret = sta_info_move_state_checked(sta,
                                        IEEE80211_STA_ASSOC);
                if (ret)
@@ -1033,7 +1033,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                                return -EBUSY;
                        }
 
-                       RCU_INIT_POINTER(vlansdata->u.vlan.sta, sta);
+                       rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
                }
 
                sta->sdata = vlansdata;
index f8a32bf98216c1bb40dadf82bfa67153a349ec9f..b3d76b756cd55e4c8e513bfa506c336ab77e667b 100644 (file)
@@ -207,7 +207,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                *pos++ = 0; /* U-APSD no in use */
        }
 
-       RCU_INIT_POINTER(ifibss->presp, skb);
+       rcu_assign_pointer(ifibss->presp, skb);
 
        sdata->vif.bss_conf.beacon_int = beacon_int;
        sdata->vif.bss_conf.basic_rates = basic_rates;
index f407427c642f4a6fdd1d6b38fb2462b244f00da1..7514091207696b9066e416305da8fb8084f651b0 100644 (file)
@@ -1979,6 +1979,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3,
                                    0, reason, fwd_hdr->addr2, sdata);
                IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
+               kfree_skb(fwd_skb);
                return RX_DROP_MONITOR;
        }
 
index b197136aea2c1d67d5223d58d248e6de7fbccb3f..ff11f6bf8266dc1a01b1b16330b416a054d702de 100644 (file)
@@ -73,7 +73,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
        if (!s)
                return -ENOENT;
        if (s == sta) {
-               RCU_INIT_POINTER(local->sta_hash[STA_HASH(sta->sta.addr)],
+               rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)],
                                   s->hnext);
                return 0;
        }
@@ -83,7 +83,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
                s = rcu_dereference_protected(s->hnext,
                                        lockdep_is_held(&local->sta_mtx));
        if (rcu_access_pointer(s->hnext)) {
-               RCU_INIT_POINTER(s->hnext, sta->hnext);
+               rcu_assign_pointer(s->hnext, sta->hnext);
                return 0;
        }
 
@@ -226,7 +226,7 @@ static void sta_info_hash_add(struct ieee80211_local *local,
 {
        lockdep_assert_held(&local->sta_mtx);
        sta->hnext = local->sta_hash[STA_HASH(sta->sta.addr)];
-       RCU_INIT_POINTER(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
+       rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
 }
 
 static void sta_unblock(struct work_struct *wk)
@@ -238,9 +238,11 @@ static void sta_unblock(struct work_struct *wk)
        if (sta->dead)
                return;
 
-       if (!test_sta_flag(sta, WLAN_STA_PS_STA))
+       if (!test_sta_flag(sta, WLAN_STA_PS_STA)) {
+               local_bh_disable();
                ieee80211_sta_ps_deliver_wakeup(sta);
-       else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) {
+               local_bh_enable();
+       } else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) {
                clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
 
                local_bh_disable();
index edcd1c7ab83f94fcaffdb049a93540bdf77c5baf..e05667cd5e766057c22770670834e6f2b19e3301 100644 (file)
@@ -1001,8 +1001,6 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
 {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
-
        if (!tx->key)
                return TX_CONTINUE;
 
@@ -1017,13 +1015,7 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
        case WLAN_CIPHER_SUITE_AES_CMAC:
                return ieee80211_crypto_aes_cmac_encrypt(tx);
        default:
-               /* handle hw-only algorithm */
-               if (info->control.hw_key) {
-                       ieee80211_tx_set_protected(tx);
-                       return TX_CONTINUE;
-               }
-               break;
-
+               return ieee80211_crypto_hw_encrypt(tx);
        }
 
        return TX_DROP;
index 93aab0715e8ab6f63f4b4f35dde067c0caa023cd..b758350919ff4641e69127a220f3c450fb07fcc9 100644 (file)
@@ -106,7 +106,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
                if (status->flag & RX_FLAG_MMIC_ERROR)
                        goto mic_fail;
 
-               if (!(status->flag & RX_FLAG_IV_STRIPPED))
+               if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key)
                        goto update_iv;
 
                return RX_CONTINUE;
@@ -643,3 +643,22 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
 
        return RX_CONTINUE;
 }
+
+ieee80211_tx_result
+ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
+{
+       struct sk_buff *skb;
+       struct ieee80211_tx_info *info = NULL;
+
+       skb_queue_walk(&tx->skbs, skb) {
+               info  = IEEE80211_SKB_CB(skb);
+
+               /* handle hw-only algorithm */
+               if (!info->control.hw_key)
+                       return TX_DROP;
+       }
+
+       ieee80211_tx_set_protected(tx);
+
+       return TX_CONTINUE;
+}
index baba0608313ef5419cccff809d28166b1178bf7b..07e33f899c71fc52f9ff1771cd283226a8a64084 100644 (file)
@@ -32,5 +32,7 @@ ieee80211_tx_result
 ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx);
 ieee80211_rx_result
 ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx);
+ieee80211_tx_result
+ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx);
 
 #endif /* WPA_H */
index 86137b558f455d9e1740a977aa09ea1e294bb241..32dbf0fa89db7661e1ee22cee519c273a229c9ca 100644 (file)
@@ -77,35 +77,42 @@ find_set_type(const char *name, u8 family, u8 revision)
 }
 
 /* Unlock, try to load a set type module and lock again */
-static int
-try_to_load_type(const char *name)
+static bool
+load_settype(const char *name)
 {
        nfnl_unlock();
        pr_debug("try to load ip_set_%s\n", name);
        if (request_module("ip_set_%s", name) < 0) {
                pr_warning("Can't find ip_set type %s\n", name);
                nfnl_lock();
-               return -IPSET_ERR_FIND_TYPE;
+               return false;
        }
        nfnl_lock();
-       return -EAGAIN;
+       return true;
 }
 
 /* Find a set type and reference it */
+#define find_set_type_get(name, family, revision, found)       \
+       __find_set_type_get(name, family, revision, found, false)
+
 static int
-find_set_type_get(const char *name, u8 family, u8 revision,
-                 struct ip_set_type **found)
+__find_set_type_get(const char *name, u8 family, u8 revision,
+                   struct ip_set_type **found, bool retry)
 {
        struct ip_set_type *type;
        int err;
 
+       if (retry && !load_settype(name))
+               return -IPSET_ERR_FIND_TYPE;
+
        rcu_read_lock();
        *found = find_set_type(name, family, revision);
        if (*found) {
                err = !try_module_get((*found)->me) ? -EFAULT : 0;
                goto unlock;
        }
-       /* Make sure the type is loaded but we don't support the revision */
+       /* Make sure the type is already loaded
+        * but we don't support the revision */
        list_for_each_entry_rcu(type, &ip_set_type_list, list)
                if (STREQ(type->name, name)) {
                        err = -IPSET_ERR_FIND_TYPE;
@@ -113,7 +120,8 @@ find_set_type_get(const char *name, u8 family, u8 revision,
                }
        rcu_read_unlock();
 
-       return try_to_load_type(name);
+       return retry ? -IPSET_ERR_FIND_TYPE :
+               __find_set_type_get(name, family, revision, found, true);
 
 unlock:
        rcu_read_unlock();
@@ -124,12 +132,19 @@ unlock:
  * If we succeeded, the supported minimal and maximum revisions are
  * filled out.
  */
+#define find_set_type_minmax(name, family, min, max) \
+       __find_set_type_minmax(name, family, min, max, false)
+
 static int
-find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max)
+__find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max,
+                      bool retry)
 {
        struct ip_set_type *type;
        bool found = false;
 
+       if (retry && !load_settype(name))
+               return -IPSET_ERR_FIND_TYPE;
+
        *min = 255; *max = 0;
        rcu_read_lock();
        list_for_each_entry_rcu(type, &ip_set_type_list, list)
@@ -145,7 +160,8 @@ find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max)
        if (found)
                return 0;
 
-       return try_to_load_type(name);
+       return retry ? -IPSET_ERR_FIND_TYPE :
+               __find_set_type_minmax(name, family, min, max, true);
 }
 
 #define family_name(f) ((f) == AF_INET ? "inet" : \
@@ -1126,6 +1142,7 @@ release_refcount:
        if (ret || !cb->args[2]) {
                pr_debug("release set %s\n", ip_set_list[index]->name);
                ip_set_put_byindex(index);
+               cb->args[2] = 0;
        }
 out:
        if (nlh) {
index e875f8902db3e7224b566e88e7bb82a73646a24f..76613f5a55c0c557920c1f52f2d67a20c0934eda 100644 (file)
@@ -777,7 +777,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
                if (exp->helper) {
                        help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
                        if (help)
-                               RCU_INIT_POINTER(help->helper, exp->helper);
+                               rcu_assign_pointer(help->helper, exp->helper);
                }
 
 #ifdef CONFIG_NF_CONNTRACK_MARK
index b62c4148b92131444f6e132cb55a058991d68379..14af6329bdda21843ada4be624093e1ac6f980fb 100644 (file)
@@ -91,7 +91,7 @@ int nf_conntrack_register_notifier(struct net *net,
                ret = -EBUSY;
                goto out_unlock;
        }
-       RCU_INIT_POINTER(net->ct.nf_conntrack_event_cb, new);
+       rcu_assign_pointer(net->ct.nf_conntrack_event_cb, new);
        mutex_unlock(&nf_ct_ecache_mutex);
        return ret;
 
@@ -128,7 +128,7 @@ int nf_ct_expect_register_notifier(struct net *net,
                ret = -EBUSY;
                goto out_unlock;
        }
-       RCU_INIT_POINTER(net->ct.nf_expect_event_cb, new);
+       rcu_assign_pointer(net->ct.nf_expect_event_cb, new);
        mutex_unlock(&nf_ct_ecache_mutex);
        return ret;
 
index 4605c947dcc49e751478aaffb816e17470998185..641ff5f967186676a0f99f14b70cb68201038fb9 100644 (file)
@@ -169,7 +169,7 @@ int nf_ct_extend_register(struct nf_ct_ext_type *type)
           before updating alloc_size */
        type->alloc_size = ALIGN(sizeof(struct nf_ct_ext), type->align)
                           + type->len;
-       RCU_INIT_POINTER(nf_ct_ext_types[type->id], type);
+       rcu_assign_pointer(nf_ct_ext_types[type->id], type);
        update_alloc_size(type);
 out:
        mutex_unlock(&nf_ct_ext_type_mutex);
index c9e0de08aa872bcbd61a4bf0b8171669a632a914..bbe23baa19b64f4df7b2532b1471614a5315cc26 100644 (file)
@@ -121,18 +121,6 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
        int ret = 0;
 
        if (tmpl != NULL) {
-               /* we've got a userspace helper. */
-               if (tmpl->status & IPS_USERSPACE_HELPER) {
-                       help = nf_ct_helper_ext_add(ct, flags);
-                       if (help == NULL) {
-                               ret = -ENOMEM;
-                               goto out;
-                       }
-                       rcu_assign_pointer(help->helper, NULL);
-                       __set_bit(IPS_USERSPACE_HELPER_BIT, &ct->status);
-                       ret = 0;
-                       goto out;
-               }
                help = nfct_help(tmpl);
                if (help != NULL)
                        helper = help->helper;
@@ -157,7 +145,7 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
                memset(&help->help, 0, sizeof(help->help));
        }
 
-       RCU_INIT_POINTER(help->helper, helper);
+       rcu_assign_pointer(help->helper, helper);
 out:
        return ret;
 }
index e07dc3ae930ea3a2aa3947eb841e47a3cb23173f..9307b033c0c9d9ff35c60b31755aaceef8d89087 100644 (file)
@@ -1172,7 +1172,7 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[])
                return -EOPNOTSUPP;
        }
 
-       RCU_INIT_POINTER(help->helper, helper);
+       rcu_assign_pointer(help->helper, helper);
 
        return 0;
 }
@@ -2042,10 +2042,6 @@ ctnetlink_create_expect(struct net *net, u16 zone,
        }
        help = nfct_help(ct);
        if (!help) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-       if (test_bit(IPS_USERSPACE_HELPER_BIT, &ct->status)) {
                if (!cda[CTA_EXPECT_TIMEOUT]) {
                        err = -EINVAL;
                        goto out;
index ce0c406f58a8b645cc4500c85dfad2008d0db70d..957374a234d410bbf87bee24f3fee4428a5ff678 100644 (file)
@@ -55,7 +55,7 @@ int nf_log_register(u_int8_t pf, struct nf_logger *logger)
                llog = rcu_dereference_protected(nf_loggers[pf],
                                                 lockdep_is_held(&nf_log_mutex));
                if (llog == NULL)
-                       RCU_INIT_POINTER(nf_loggers[pf], logger);
+                       rcu_assign_pointer(nf_loggers[pf], logger);
        }
 
        mutex_unlock(&nf_log_mutex);
@@ -92,7 +92,7 @@ int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger)
                mutex_unlock(&nf_log_mutex);
                return -ENOENT;
        }
-       RCU_INIT_POINTER(nf_loggers[pf], logger);
+       rcu_assign_pointer(nf_loggers[pf], logger);
        mutex_unlock(&nf_log_mutex);
        return 0;
 }
@@ -250,7 +250,7 @@ static int nf_log_proc_dostring(ctl_table *table, int write,
                        mutex_unlock(&nf_log_mutex);
                        return -ENOENT;
                }
-               RCU_INIT_POINTER(nf_loggers[tindex], logger);
+               rcu_assign_pointer(nf_loggers[tindex], logger);
                mutex_unlock(&nf_log_mutex);
        } else {
                mutex_lock(&nf_log_mutex);
index 99ffd2885088fc3606270984386713b959b75285..b3a7db678b8dddf12e9495630e0e051a0b78cfe9 100644 (file)
@@ -40,7 +40,7 @@ int nf_register_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh)
        else if (old)
                ret = -EBUSY;
        else {
-               RCU_INIT_POINTER(queue_handler[pf], qh);
+               rcu_assign_pointer(queue_handler[pf], qh);
                ret = 0;
        }
        mutex_unlock(&queue_handler_mutex);
index c879c1a2370e46829c442095b98a58ce705d78b3..4d70785b953daad4c1bc7459652427a3ef86e685 100644 (file)
@@ -59,7 +59,7 @@ int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
                nfnl_unlock();
                return -EBUSY;
        }
-       RCU_INIT_POINTER(subsys_table[n->subsys_id], n);
+       rcu_assign_pointer(subsys_table[n->subsys_id], n);
        nfnl_unlock();
 
        return 0;
@@ -130,7 +130,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        const struct nfnetlink_subsystem *ss;
        int type, err;
 
-       if (security_netlink_recv(skb, CAP_NET_ADMIN))
+       if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
        /* All the messages must at least contain nfgenmsg */
@@ -210,7 +210,7 @@ static int __net_init nfnetlink_net_init(struct net *net)
        if (!nfnl)
                return -ENOMEM;
        net->nfnl_stash = nfnl;
-       RCU_INIT_POINTER(net->nfnl, nfnl);
+       rcu_assign_pointer(net->nfnl, nfnl);
        return 0;
 }
 
index 8e87123f1373a1a4a42ddb6211c1737d2346047d..0221d10de75a517dbc4c5e5c7d40b432abef15a3 100644 (file)
@@ -62,8 +62,8 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par)
        int ret = 0;
        u8 proto;
 
-       if (info->flags & ~(XT_CT_NOTRACK | XT_CT_USERSPACE_HELPER))
-               return -EOPNOTSUPP;
+       if (info->flags & ~XT_CT_NOTRACK)
+               return -EINVAL;
 
        if (info->flags & XT_CT_NOTRACK) {
                ct = nf_ct_untracked_get();
@@ -92,9 +92,7 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par)
                                  GFP_KERNEL))
                goto err3;
 
-       if (info->flags & XT_CT_USERSPACE_HELPER) {
-               __set_bit(IPS_USERSPACE_HELPER_BIT, &ct->status);
-       } else if (info->helper[0]) {
+       if (info->helper[0]) {
                ret = -ENOENT;
                proto = xt_ct_find_proto(par);
                if (!proto) {
index 8e4992101875086cd412154d102793c99ffa6bed..d95f9c963cde01cfcd4d6541de352c85f44fc6f8 100644 (file)
@@ -445,7 +445,6 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
 {
        __be16 _ports[2], *ports;
        u8 nexthdr;
-       __be16 frag_off;
        int poff;
 
        memset(dst, 0, sizeof(*dst));
@@ -466,6 +465,9 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
                break;
 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
        case NFPROTO_IPV6:
+       {
+               __be16 frag_off;
+
                if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP) {
                        memcpy(&dst->ip6.dst, &ipv6_hdr(skb)->daddr,
                               sizeof(dst->ip6.dst));
@@ -485,6 +487,7 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
                if ((int)protoff < 0)
                        return -1;
                break;
+       }
 #endif
        default:
                BUG();
index 38204112b9f4a0faec6e629e3431359c17033b38..d8d42433755051023320299f919f69db9e58ec29 100644 (file)
@@ -282,7 +282,7 @@ int __init netlbl_domhsh_init(u32 size)
                INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
 
        spin_lock(&netlbl_domhsh_lock);
-       RCU_INIT_POINTER(netlbl_domhsh, hsh_tbl);
+       rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
        spin_unlock(&netlbl_domhsh_lock);
 
        return 0;
@@ -330,7 +330,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                                    &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
                } else {
                        INIT_LIST_HEAD(&entry->list);
-                       RCU_INIT_POINTER(netlbl_domhsh_def, entry);
+                       rcu_assign_pointer(netlbl_domhsh_def, entry);
                }
 
                if (entry->type == NETLBL_NLTYPE_ADDRSELECT) {
index 4b5fa0fe78fd36a3e4055328535ffa3283eae642..e7ff694f1049be48b3193d4a0b3ffded63aecbcd 100644 (file)
@@ -354,7 +354,7 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex)
                INIT_LIST_HEAD(&iface->list);
                if (netlbl_unlhsh_rcu_deref(netlbl_unlhsh_def) != NULL)
                        goto add_iface_failure;
-               RCU_INIT_POINTER(netlbl_unlhsh_def, iface);
+               rcu_assign_pointer(netlbl_unlhsh_def, iface);
        }
        spin_unlock(&netlbl_unlhsh_lock);
 
@@ -1447,11 +1447,9 @@ int __init netlbl_unlabel_init(u32 size)
        for (iter = 0; iter < hsh_tbl->size; iter++)
                INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
 
-       rcu_read_lock();
        spin_lock(&netlbl_unlhsh_lock);
-       RCU_INIT_POINTER(netlbl_unlhsh, hsh_tbl);
+       rcu_assign_pointer(netlbl_unlhsh, hsh_tbl);
        spin_unlock(&netlbl_unlhsh_lock);
-       rcu_read_unlock();
 
        register_netdevice_notifier(&netlbl_unlhsh_netdev_notifier);
 
index a403b618faa5b80e0ef06abb4e5dc648874f7d34..c29d2568c9e0cc02b75ea4ea8154a37a2a7a8d6d 100644 (file)
@@ -524,7 +524,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                return -EOPNOTSUPP;
 
        if ((ops->flags & GENL_ADMIN_PERM) &&
-           security_netlink_recv(skb, CAP_NET_ADMIN))
+           !capable(CAP_NET_ADMIN))
                return -EPERM;
 
        if (nlh->nlmsg_flags & NLM_F_DUMP) {
index 9a2725114e99bad3a1e69351ac55ec764a295cc6..ce64c18b8c79a99ef4251e7c9d2a752105207725 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2011 Nicira Networks.
+ * Copyright (c) 2007-2012 Nicira Networks.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -36,7 +36,6 @@
 #include <linux/rcupdate.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
-#include <linux/version.h>
 #include <linux/ethtool.h>
 #include <linux/wait.h>
 #include <asm/system.h>
@@ -1397,9 +1396,8 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
        int i = 0;
 
        list_for_each_entry(dp, &dps, list_node) {
-               if (i < skip)
-                       continue;
-               if (ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).pid,
+               if (i >= skip &&
+                   ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).pid,
                                         cb->nlh->nlmsg_seq, NLM_F_MULTI,
                                         OVS_DP_CMD_NEW) < 0)
                        break;
index 5b9f884b7055a6c75205fc00082f2f541202df7f..c73370cc1f02df24d32026c0e775efef72451dfc 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/u64_stats_sync.h>
-#include <linux/version.h>
 
 #include "flow.h"
 
index fe7f020a843efa2519f47c80ca4b340e14299917..1252c3081ef12740a0b818fbd58ae3ab6e9b870e 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/in.h>
 #include <linux/rcupdate.h>
 #include <linux/if_arp.h>
-#include <linux/if_ether.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/tcp.h>
index 8fc28b86f2b3e4666fd2ef18d63ad785aed2c25d..322b8d206693dde98a30f1d36a6db4d800e0f17a 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/skbuff.h>
-#include <linux/version.h>
 
 #include "datapath.h"
 #include "vport-internal_dev.h"
index 7f0ef3794c515064c67d719b8f65c564aa82295d..6c066ba25dc71c24c8a94e4acc50014d610f77a6 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/rcupdate.h>
 #include <linux/rtnetlink.h>
 #include <linux/compat.h>
-#include <linux/version.h>
 
 #include "vport.h"
 #include "vport-internal_dev.h"
index bf10ea8fbbf95bd349d0f69f18527a524d5d3a9c..d65f699fbf343a98d788a8f49286c71dc4f7887f 100644 (file)
@@ -480,7 +480,7 @@ int __init_or_module phonet_proto_register(unsigned int protocol,
        if (proto_tab[protocol])
                err = -EBUSY;
        else
-               RCU_INIT_POINTER(proto_tab[protocol], pp);
+               rcu_assign_pointer(proto_tab[protocol], pp);
        mutex_unlock(&proto_tab_lock);
 
        return err;
index c5827614376bd18c668a99d76b1b61f4b9f57011..9b9a85ecc4c79d70c88db78a12e5d54309e28d43 100644 (file)
@@ -390,7 +390,7 @@ int phonet_route_add(struct net_device *dev, u8 daddr)
        daddr = daddr >> 2;
        mutex_lock(&routes->lock);
        if (routes->table[daddr] == NULL) {
-               RCU_INIT_POINTER(routes->table[daddr], dev);
+               rcu_assign_pointer(routes->table[daddr], dev);
                dev_hold(dev);
                err = 0;
        }
index 3f8d0b1603b98f5c1c2ad5105b6a3226c27df1f3..4c7eff30dfa9e4cc3bb54418e4dda44841b4d9be 100644 (file)
@@ -680,7 +680,7 @@ int pn_sock_bind_res(struct sock *sk, u8 res)
        mutex_lock(&resource_mutex);
        if (pnres.sk[res] == NULL) {
                sock_hold(sk);
-               RCU_INIT_POINTER(pnres.sk[res], sk);
+               rcu_assign_pointer(pnres.sk[res], sk);
                ret = 0;
        }
        mutex_unlock(&resource_mutex);
index 4e1de171866c7ab170297f1fcdf0878c2d8a5f62..a817705ce2d0e9246388c2c65d77b4c486a8feba 100644 (file)
@@ -477,17 +477,6 @@ void rds_iw_sync_mr(void *trans_private, int direction)
        }
 }
 
-static inline unsigned int rds_iw_flush_goal(struct rds_iw_mr_pool *pool, int free_all)
-{
-       unsigned int item_count;
-
-       item_count = atomic_read(&pool->item_count);
-       if (free_all)
-               return item_count;
-
-       return 0;
-}
-
 /*
  * Flush our pool of MRs.
  * At a minimum, all currently unused MRs are unmapped.
@@ -500,7 +489,7 @@ static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
        LIST_HEAD(unmap_list);
        LIST_HEAD(kill_list);
        unsigned long flags;
-       unsigned int nfreed = 0, ncleaned = 0, unpinned = 0, free_goal;
+       unsigned int nfreed = 0, ncleaned = 0, unpinned = 0;
        int ret = 0;
 
        rds_iw_stats_inc(s_iw_rdma_mr_pool_flush);
@@ -514,8 +503,6 @@ static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
                list_splice_init(&pool->clean_list, &kill_list);
        spin_unlock_irqrestore(&pool->list_lock, flags);
 
-       free_goal = rds_iw_flush_goal(pool, free_all);
-
        /* Batched invalidate of dirty MRs.
         * For FMR based MRs, the mappings on the unmap list are
         * actually members of an ibmr (ibmr->mapping). They either
index 0a7964009e8c99af197fb9454cf11e217fdf28bc..67494aef9acf3c230aa80dd4d70d1369a5318c04 100644 (file)
@@ -24,6 +24,7 @@
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
 #include <net/flow_keys.h>
+#include <net/red.h>
 
 
 /*     Stochastic Fairness Queuing algorithm.
@@ -108,24 +109,30 @@ struct sfq_slot {
        struct sfq_head dep; /* anchor in dep[] chains */
        unsigned short  hash; /* hash value (index in ht[]) */
        short           allot; /* credit for this slot */
+
+       unsigned int    backlog;
+       struct red_vars vars;
 };
 
 struct sfq_sched_data {
 /* frequently used fields */
        int             limit;          /* limit of total number of packets in this qdisc */
        unsigned int    divisor;        /* number of slots in hash table */
-       unsigned int    maxflows;       /* number of flows in flows array */
-       int             headdrop;
-       int             maxdepth;       /* limit of packets per flow */
+       u8              headdrop;
+       u8              maxdepth;       /* limit of packets per flow */
 
        u32             perturbation;
-       struct tcf_proto *filter_list;
-       sfq_index       cur_depth;      /* depth of longest slot */
+       u8              cur_depth;      /* depth of longest slot */
+       u8              flags;
        unsigned short  scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */
-       struct sfq_slot *tail;          /* current slot in round */
+       struct tcf_proto *filter_list;
        sfq_index       *ht;            /* Hash table ('divisor' slots) */
        struct sfq_slot *slots;         /* Flows table ('maxflows' entries) */
 
+       struct red_parms *red_parms;
+       struct tc_sfqred_stats stats;
+       struct sfq_slot *tail;          /* current slot in round */
+
        struct sfq_head dep[SFQ_MAX_DEPTH + 1];
                                        /* Linked lists of slots, indexed by depth
                                         * dep[0] : list of unused flows
@@ -133,6 +140,7 @@ struct sfq_sched_data {
                                         * dep[X] : list of flows with X packets
                                         */
 
+       unsigned int    maxflows;       /* number of flows in flows array */
        int             perturb_period;
        unsigned int    quantum;        /* Allotment per round: MUST BE >= MTU */
        struct timer_list perturb_timer;
@@ -321,6 +329,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
 drop:
                skb = q->headdrop ? slot_dequeue_head(slot) : slot_dequeue_tail(slot);
                len = qdisc_pkt_len(skb);
+               slot->backlog -= len;
                sfq_dec(q, x);
                kfree_skb(skb);
                sch->q.qlen--;
@@ -341,6 +350,23 @@ drop:
        return 0;
 }
 
+/* Is ECN parameter configured */
+static int sfq_prob_mark(const struct sfq_sched_data *q)
+{
+       return q->flags & TC_RED_ECN;
+}
+
+/* Should packets over max threshold just be marked */
+static int sfq_hard_mark(const struct sfq_sched_data *q)
+{
+       return (q->flags & (TC_RED_ECN | TC_RED_HARDDROP)) == TC_RED_ECN;
+}
+
+static int sfq_headdrop(const struct sfq_sched_data *q)
+{
+       return q->headdrop;
+}
+
 static int
 sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
@@ -349,6 +375,8 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        sfq_index x, qlen;
        struct sfq_slot *slot;
        int uninitialized_var(ret);
+       struct sk_buff *head;
+       int delta;
 
        hash = sfq_classify(skb, sch, &ret);
        if (hash == 0) {
@@ -368,24 +396,75 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                q->ht[hash] = x;
                slot = &q->slots[x];
                slot->hash = hash;
+               slot->backlog = 0; /* should already be 0 anyway... */
+               red_set_vars(&slot->vars);
+               goto enqueue;
        }
+       if (q->red_parms) {
+               slot->vars.qavg = red_calc_qavg_no_idle_time(q->red_parms,
+                                                       &slot->vars,
+                                                       slot->backlog);
+               switch (red_action(q->red_parms,
+                                  &slot->vars,
+                                  slot->vars.qavg)) {
+               case RED_DONT_MARK:
+                       break;
 
-       if (slot->qlen >= q->maxdepth) {
-               struct sk_buff *head;
+               case RED_PROB_MARK:
+                       sch->qstats.overlimits++;
+                       if (sfq_prob_mark(q)) {
+                               /* We know we have at least one packet in queue */
+                               if (sfq_headdrop(q) &&
+                                   INET_ECN_set_ce(slot->skblist_next)) {
+                                       q->stats.prob_mark_head++;
+                                       break;
+                               }
+                               if (INET_ECN_set_ce(skb)) {
+                                       q->stats.prob_mark++;
+                                       break;
+                               }
+                       }
+                       q->stats.prob_drop++;
+                       goto congestion_drop;
+
+               case RED_HARD_MARK:
+                       sch->qstats.overlimits++;
+                       if (sfq_hard_mark(q)) {
+                               /* We know we have at least one packet in queue */
+                               if (sfq_headdrop(q) &&
+                                   INET_ECN_set_ce(slot->skblist_next)) {
+                                       q->stats.forced_mark_head++;
+                                       break;
+                               }
+                               if (INET_ECN_set_ce(skb)) {
+                                       q->stats.forced_mark++;
+                                       break;
+                               }
+                       }
+                       q->stats.forced_drop++;
+                       goto congestion_drop;
+               }
+       }
 
-               if (!q->headdrop)
+       if (slot->qlen >= q->maxdepth) {
+congestion_drop:
+               if (!sfq_headdrop(q))
                        return qdisc_drop(skb, sch);
 
+               /* We know we have at least one packet in queue */
                head = slot_dequeue_head(slot);
-               sch->qstats.backlog -= qdisc_pkt_len(head);
+               delta = qdisc_pkt_len(head) - qdisc_pkt_len(skb);
+               sch->qstats.backlog -= delta;
+               slot->backlog -= delta;
                qdisc_drop(head, sch);
 
-               sch->qstats.backlog += qdisc_pkt_len(skb);
                slot_queue_add(slot, skb);
                return NET_XMIT_CN;
        }
 
+enqueue:
        sch->qstats.backlog += qdisc_pkt_len(skb);
+       slot->backlog += qdisc_pkt_len(skb);
        slot_queue_add(slot, skb);
        sfq_inc(q, x);
        if (slot->qlen == 1) {          /* The flow is new */
@@ -396,6 +475,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                        slot->next = q->tail->next;
                        q->tail->next = x;
                }
+               /* We could use a bigger initial quantum for new flows */
                slot->allot = q->scaled_quantum;
        }
        if (++sch->q.qlen <= q->limit)
@@ -439,7 +519,7 @@ next_slot:
        qdisc_bstats_update(sch, skb);
        sch->q.qlen--;
        sch->qstats.backlog -= qdisc_pkt_len(skb);
-
+       slot->backlog -= qdisc_pkt_len(skb);
        /* Is the slot empty? */
        if (slot->qlen == 0) {
                q->ht[slot->hash] = SFQ_EMPTY_SLOT;
@@ -490,6 +570,8 @@ static void sfq_rehash(struct Qdisc *sch)
                        sfq_dec(q, i);
                        __skb_queue_tail(&list, skb);
                }
+               slot->backlog = 0;
+               red_set_vars(&slot->vars);
                q->ht[slot->hash] = SFQ_EMPTY_SLOT;
        }
        q->tail = NULL;
@@ -514,6 +596,11 @@ drop:                              sch->qstats.backlog -= qdisc_pkt_len(skb);
                if (slot->qlen >= q->maxdepth)
                        goto drop;
                slot_queue_add(slot, skb);
+               if (q->red_parms)
+                       slot->vars.qavg = red_calc_qavg(q->red_parms,
+                                                       &slot->vars,
+                                                       slot->backlog);
+               slot->backlog += qdisc_pkt_len(skb);
                sfq_inc(q, x);
                if (slot->qlen == 1) {          /* The flow is new */
                        if (q->tail == NULL) {  /* It is the first flow */
@@ -552,6 +639,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
        struct tc_sfq_qopt *ctl = nla_data(opt);
        struct tc_sfq_qopt_v1 *ctl_v1 = NULL;
        unsigned int qlen;
+       struct red_parms *p = NULL;
 
        if (opt->nla_len < nla_attr_size(sizeof(*ctl)))
                return -EINVAL;
@@ -560,7 +648,11 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
        if (ctl->divisor &&
            (!is_power_of_2(ctl->divisor) || ctl->divisor > 65536))
                return -EINVAL;
-
+       if (ctl_v1 && ctl_v1->qth_min) {
+               p = kmalloc(sizeof(*p), GFP_KERNEL);
+               if (!p)
+                       return -ENOMEM;
+       }
        sch_tree_lock(sch);
        if (ctl->quantum) {
                q->quantum = ctl->quantum;
@@ -576,6 +668,16 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
        if (ctl_v1) {
                if (ctl_v1->depth)
                        q->maxdepth = min_t(u32, ctl_v1->depth, SFQ_MAX_DEPTH);
+               if (p) {
+                       swap(q->red_parms, p);
+                       red_set_parms(q->red_parms,
+                                     ctl_v1->qth_min, ctl_v1->qth_max,
+                                     ctl_v1->Wlog,
+                                     ctl_v1->Plog, ctl_v1->Scell_log,
+                                     NULL,
+                                     ctl_v1->max_P);
+               }
+               q->flags = ctl_v1->flags;
                q->headdrop = ctl_v1->headdrop;
        }
        if (ctl->limit) {
@@ -594,6 +696,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
                q->perturbation = net_random();
        }
        sch_tree_unlock(sch);
+       kfree(p);
        return 0;
 }
 
@@ -625,6 +728,7 @@ static void sfq_destroy(struct Qdisc *sch)
        del_timer_sync(&q->perturb_timer);
        sfq_free(q->ht);
        sfq_free(q->slots);
+       kfree(q->red_parms);
 }
 
 static int sfq_init(struct Qdisc *sch, struct nlattr *opt)
@@ -683,6 +787,7 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
        struct sfq_sched_data *q = qdisc_priv(sch);
        unsigned char *b = skb_tail_pointer(skb);
        struct tc_sfq_qopt_v1 opt;
+       struct red_parms *p = q->red_parms;
 
        memset(&opt, 0, sizeof(opt));
        opt.v0.quantum  = q->quantum;
@@ -693,6 +798,17 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
        opt.depth       = q->maxdepth;
        opt.headdrop    = q->headdrop;
 
+       if (p) {
+               opt.qth_min     = p->qth_min >> p->Wlog;
+               opt.qth_max     = p->qth_max >> p->Wlog;
+               opt.Wlog        = p->Wlog;
+               opt.Plog        = p->Plog;
+               opt.Scell_log   = p->Scell_log;
+               opt.max_P       = p->max_P;
+       }
+       memcpy(&opt.stats, &q->stats, sizeof(opt.stats));
+       opt.flags       = q->flags;
+
        NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
 
        return skb->len;
@@ -747,15 +863,13 @@ static int sfq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
        sfq_index idx = q->ht[cl - 1];
        struct gnet_stats_queue qs = { 0 };
        struct tc_sfq_xstats xstats = { 0 };
-       struct sk_buff *skb;
 
        if (idx != SFQ_EMPTY_SLOT) {
                const struct sfq_slot *slot = &q->slots[idx];
 
                xstats.allot = slot->allot << SFQ_ALLOT_SHIFT;
                qs.qlen = slot->qlen;
-               slot_queue_walk(slot, skb)
-                       qs.backlog += qdisc_pkt_len(skb);
+               qs.backlog = slot->backlog;
        }
        if (gnet_stats_copy_queue(d, &qs) < 0)
                return -1;
index e56162cd65b053b7a86119737dd7ca91329573d7..28a96af484b421ee06fffbe87358c1811693c97f 100644 (file)
@@ -2492,7 +2492,7 @@ int sock_register(const struct net_proto_family *ops)
                                      lockdep_is_held(&net_family_lock)))
                err = -EEXIST;
        else {
-               RCU_INIT_POINTER(net_families[ops->family], ops);
+               rcu_assign_pointer(net_families[ops->family], ops);
                err = 0;
        }
        spin_unlock(&net_family_lock);
index 28d72d298735e0f3d72d161220a1241c241fb98d..affa631ac1abe3d42f75635a30e1f066dccbfb44 100644 (file)
@@ -122,7 +122,7 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
        if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
                return;
        gss_get_ctx(ctx);
-       RCU_INIT_POINTER(gss_cred->gc_ctx, ctx);
+       rcu_assign_pointer(gss_cred->gc_ctx, ctx);
        set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
        smp_mb__before_clear_bit();
        clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
index 03b56bc3b659f914041ffd18352f3b43e10480a1..465df9ae1046b7fc12fe99fd0759017be7a7dc2a 100644 (file)
@@ -1641,6 +1641,7 @@ int cache_register_net(struct cache_detail *cd, struct net *net)
                sunrpc_destroy_cache_detail(cd);
        return ret;
 }
+EXPORT_SYMBOL_GPL(cache_register_net);
 
 int cache_register(struct cache_detail *cd)
 {
@@ -1653,6 +1654,7 @@ void cache_unregister_net(struct cache_detail *cd, struct net *net)
        remove_cache_proc_entries(cd, net);
        sunrpc_destroy_cache_detail(cd);
 }
+EXPORT_SYMBOL_GPL(cache_unregister_net);
 
 void cache_unregister(struct cache_detail *cd)
 {
index 9d01d46b05f36785e0612786a2365be80a08dc0d..e4aabc02368b94e0d7b0109ab7906bfbba329b23 100644 (file)
@@ -167,6 +167,7 @@ svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools)
 
 fail_free:
        kfree(m->to_pool);
+       m->to_pool = NULL;
 fail:
        return -ENOMEM;
 }
@@ -285,9 +286,10 @@ svc_pool_map_put(void)
        mutex_lock(&svc_pool_map_mutex);
 
        if (!--m->count) {
-               m->mode = SVC_POOL_DEFAULT;
                kfree(m->to_pool);
+               m->to_pool = NULL;
                kfree(m->pool_to);
+               m->pool_to = NULL;
                m->npools = 0;
        }
 
@@ -527,17 +529,20 @@ svc_destroy(struct svc_serv *serv)
                printk("svc_destroy: no threads for serv=%p!\n", serv);
 
        del_timer_sync(&serv->sv_temptimer);
-
-       svc_close_all(&serv->sv_tempsocks);
+       /*
+        * The set of xprts (contained in the sv_tempsocks and
+        * sv_permsocks lists) is now constant, since it is modified
+        * only by accepting new sockets (done by service threads in
+        * svc_recv) or aging old ones (done by sv_temptimer), or
+        * configuration changes (excluded by whatever locking the
+        * caller is using--nfsd_mutex in the case of nfsd).  So it's
+        * safe to traverse those lists and shut everything down:
+        */
+       svc_close_all(serv);
 
        if (serv->sv_shutdown)
                serv->sv_shutdown(serv);
 
-       svc_close_all(&serv->sv_permsocks);
-
-       BUG_ON(!list_empty(&serv->sv_permsocks));
-       BUG_ON(!list_empty(&serv->sv_tempsocks));
-
        cache_clean_deferred(serv);
 
        if (svc_serv_is_pooled(serv))
@@ -683,8 +688,8 @@ found_pool:
  * Create or destroy enough new threads to make the number
  * of threads the given number.  If `pool' is non-NULL, applies
  * only to threads in that pool, otherwise round-robins between
- * all pools.  Must be called with a svc_get() reference and
- * the BKL or another lock to protect access to svc_serv fields.
+ * all pools.  Caller must ensure that mutual exclusion between this and
+ * server startup or shutdown.
  *
  * Destroying threads relies on the service threads filling in
  * rqstp->rq_task, which only the nfs ones do.  Assumes the serv
index 38649cfa4e81350aed397d3bdeb316556aaf57e6..74cb0d8e9ca1f58aae66b85bee5c313cf3473f18 100644 (file)
@@ -22,6 +22,7 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt);
 static int svc_deferred_recv(struct svc_rqst *rqstp);
 static struct cache_deferred_req *svc_defer(struct cache_req *req);
 static void svc_age_temp_xprts(unsigned long closure);
+static void svc_delete_xprt(struct svc_xprt *xprt);
 
 /* apparently the "standard" is that clients close
  * idle connections after 5 minutes, servers after
@@ -147,8 +148,8 @@ EXPORT_SYMBOL_GPL(svc_xprt_put);
  * Called by transport drivers to initialize the transport independent
  * portion of the transport instance.
  */
-void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
-                  struct svc_serv *serv)
+void svc_xprt_init(struct net *net, struct svc_xprt_class *xcl,
+                  struct svc_xprt *xprt, struct svc_serv *serv)
 {
        memset(xprt, 0, sizeof(*xprt));
        xprt->xpt_class = xcl;
@@ -163,7 +164,7 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
        spin_lock_init(&xprt->xpt_lock);
        set_bit(XPT_BUSY, &xprt->xpt_flags);
        rpc_init_wait_queue(&xprt->xpt_bc_pending, "xpt_bc_pending");
-       xprt->xpt_net = get_net(&init_net);
+       xprt->xpt_net = get_net(net);
 }
 EXPORT_SYMBOL_GPL(svc_xprt_init);
 
@@ -878,7 +879,7 @@ static void call_xpt_users(struct svc_xprt *xprt)
 /*
  * Remove a dead transport
  */
-void svc_delete_xprt(struct svc_xprt *xprt)
+static void svc_delete_xprt(struct svc_xprt *xprt)
 {
        struct svc_serv *serv = xprt->xpt_server;
        struct svc_deferred_req *dr;
@@ -893,14 +894,7 @@ void svc_delete_xprt(struct svc_xprt *xprt)
        spin_lock_bh(&serv->sv_lock);
        if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags))
                list_del_init(&xprt->xpt_list);
-       /*
-        * The only time we're called while xpt_ready is still on a list
-        * is while the list itself is about to be destroyed (in
-        * svc_destroy).  BUT svc_xprt_enqueue could still be attempting
-        * to add new entries to the sp_sockets list, so we can't leave
-        * a freed xprt on it.
-        */
-       list_del_init(&xprt->xpt_ready);
+       BUG_ON(!list_empty(&xprt->xpt_ready));
        if (test_bit(XPT_TEMP, &xprt->xpt_flags))
                serv->sv_tmpcnt--;
        spin_unlock_bh(&serv->sv_lock);
@@ -928,22 +922,48 @@ void svc_close_xprt(struct svc_xprt *xprt)
 }
 EXPORT_SYMBOL_GPL(svc_close_xprt);
 
-void svc_close_all(struct list_head *xprt_list)
+static void svc_close_list(struct list_head *xprt_list)
+{
+       struct svc_xprt *xprt;
+
+       list_for_each_entry(xprt, xprt_list, xpt_list) {
+               set_bit(XPT_CLOSE, &xprt->xpt_flags);
+               set_bit(XPT_BUSY, &xprt->xpt_flags);
+       }
+}
+
+void svc_close_all(struct svc_serv *serv)
 {
+       struct svc_pool *pool;
        struct svc_xprt *xprt;
        struct svc_xprt *tmp;
+       int i;
+
+       svc_close_list(&serv->sv_tempsocks);
+       svc_close_list(&serv->sv_permsocks);
 
+       for (i = 0; i < serv->sv_nrpools; i++) {
+               pool = &serv->sv_pools[i];
+
+               spin_lock_bh(&pool->sp_lock);
+               while (!list_empty(&pool->sp_sockets)) {
+                       xprt = list_first_entry(&pool->sp_sockets, struct svc_xprt, xpt_ready);
+                       list_del_init(&xprt->xpt_ready);
+               }
+               spin_unlock_bh(&pool->sp_lock);
+       }
        /*
-        * The server is shutting down, and no more threads are running.
-        * svc_xprt_enqueue() might still be running, but at worst it
-        * will re-add the xprt to sp_sockets, which will soon get
-        * freed.  So we don't bother with any more locking, and don't
-        * leave the close to the (nonexistent) server threads:
+        * At this point the sp_sockets lists will stay empty, since
+        * svc_enqueue will not add new entries without taking the
+        * sp_lock and checking XPT_BUSY.
         */
-       list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) {
-               set_bit(XPT_CLOSE, &xprt->xpt_flags);
+       list_for_each_entry_safe(xprt, tmp, &serv->sv_tempsocks, xpt_list)
                svc_delete_xprt(xprt);
-       }
+       list_for_each_entry_safe(xprt, tmp, &serv->sv_permsocks, xpt_list)
+               svc_delete_xprt(xprt);
+
+       BUG_ON(!list_empty(&serv->sv_permsocks));
+       BUG_ON(!list_empty(&serv->sv_tempsocks));
 }
 
 /*
index 4653286fcc9e685e1d1999c532325ce48870d4f8..464570906f80c24190260bef957a53128202a486 100644 (file)
@@ -739,7 +739,8 @@ static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
 {
        int err, level, optname, one = 1;
 
-       svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv);
+       svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_udp_class,
+                     &svsk->sk_xprt, serv);
        clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
        svsk->sk_sk->sk_data_ready = svc_udp_data_ready;
        svsk->sk_sk->sk_write_space = svc_write_space;
@@ -1343,7 +1344,8 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
 {
        struct sock     *sk = svsk->sk_sk;
 
-       svc_xprt_init(&svc_tcp_class, &svsk->sk_xprt, serv);
+       svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_tcp_class,
+                     &svsk->sk_xprt, serv);
        set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
        if (sk->sk_state == TCP_LISTEN) {
                dprintk("setting up TCP socket for listening\n");
@@ -1659,7 +1661,7 @@ static struct svc_xprt *svc_bc_create_socket(struct svc_serv *serv,
                return ERR_PTR(-ENOMEM);
 
        xprt = &svsk->sk_xprt;
-       svc_xprt_init(&svc_tcp_bc_class, xprt, serv);
+       svc_xprt_init(net, &svc_tcp_bc_class, xprt, serv);
 
        serv->sv_bc_xprt = xprt;
 
index ba1296d88de0295258281db5d76ac1f2c1f0a34a..894cb42db91d6c9e2cb71a9ae0aa076db4573d96 100644 (file)
@@ -453,7 +453,7 @@ static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
 
        if (!cma_xprt)
                return NULL;
-       svc_xprt_init(&svc_rdma_class, &cma_xprt->sc_xprt, serv);
+       svc_xprt_init(&init_net, &svc_rdma_class, &cma_xprt->sc_xprt, serv);
        INIT_LIST_HEAD(&cma_xprt->sc_accept_q);
        INIT_LIST_HEAD(&cma_xprt->sc_dto_q);
        INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q);
index b3d3cf8931cb9a3c055df2e497943ec2500cfc51..afeea32e04ad9ea1a0caa1adeabe83b940bc0c42 100644 (file)
@@ -2250,6 +2250,7 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
 };
 
 static int parse_station_flags(struct genl_info *info,
+                              enum nl80211_iftype iftype,
                               struct station_parameters *params)
 {
        struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
@@ -2283,8 +2284,33 @@ static int parse_station_flags(struct genl_info *info,
                             nla, sta_flags_policy))
                return -EINVAL;
 
-       params->sta_flags_mask = (1 << __NL80211_STA_FLAG_AFTER_LAST) - 1;
-       params->sta_flags_mask &= ~1;
+       /*
+        * Only allow certain flags for interface types so that
+        * other attributes are silently ignored. Remember that
+        * this is backward compatibility code with old userspace
+        * and shouldn't be hit in other cases anyway.
+        */
+       switch (iftype) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_P2P_GO:
+               params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
+                                        BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
+                                        BIT(NL80211_STA_FLAG_WME) |
+                                        BIT(NL80211_STA_FLAG_MFP);
+               break;
+       case NL80211_IFTYPE_P2P_CLIENT:
+       case NL80211_IFTYPE_STATION:
+               params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
+                                        BIT(NL80211_STA_FLAG_TDLS_PEER);
+               break;
+       case NL80211_IFTYPE_MESH_POINT:
+               params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                                        BIT(NL80211_STA_FLAG_MFP) |
+                                        BIT(NL80211_STA_FLAG_AUTHORIZED);
+       default:
+               return -EINVAL;
+       }
 
        for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
                if (flags[flag])
@@ -2585,7 +2611,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->change_station)
                return -EOPNOTSUPP;
 
-       if (parse_station_flags(info, &params))
+       if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
                return -EINVAL;
 
        if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
@@ -2731,7 +2757,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->add_station)
                return -EOPNOTSUPP;
 
-       if (parse_station_flags(info, &params))
+       if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
                return -EINVAL;
 
        switch (dev->ieee80211_ptr->iftype) {
index e0d747a2e80341eb736c4348212770c3db41c4ad..66b84fbf2746c0d37f2ea74981c33f34d80e6c8d 100644 (file)
@@ -2290,7 +2290,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        link = &xfrm_dispatch[type];
 
        /* All operations require privileges, even GET */
-       if (security_netlink_recv(skb, CAP_NET_ADMIN))
+       if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
        if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
@@ -2927,7 +2927,7 @@ static int __net_init xfrm_user_net_init(struct net *net)
        if (nlsk == NULL)
                return -ENOMEM;
        net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */
-       RCU_INIT_POINTER(net->xfrm.nlsk, nlsk);
+       rcu_assign_pointer(net->xfrm.nlsk, nlsk);
        return 0;
 }
 
index a57f5bd5a13d5b8f14a90b03bf23115e925b4a0a..d3bae5e7b6018d7429c518681a706179e00c6d81 100644 (file)
@@ -4,12 +4,16 @@
 # header-y  - list files to be installed. They are preprocessed
 #             to remove __KERNEL__ section of the file
 # objhdr-y  - Same as header-y but for generated files
+# genhdr-y  - Same as objhdr-y but in a generated/ directory
 #
 # ==========================================================================
 
 # called may set destination dir (when installing to asm/)
 _dst := $(if $(dst),$(dst),$(obj))
 
+# generated header directory
+gen := $(if $(gen),$(gen),$(subst include/,include/generated/,$(obj)))
+
 kbuild-file := $(srctree)/$(obj)/Kbuild
 include $(kbuild-file)
 
@@ -33,9 +37,10 @@ wrapper-files := $(filter $(header-y), $(generic-y))
 
 # all headers files for this dir
 header-y      := $(filter-out $(generic-y), $(header-y))
-all-files     := $(header-y) $(objhdr-y) $(wrapper-files)
+all-files     := $(header-y) $(objhdr-y) $(genhdr-y) $(wrapper-files)
 input-files   := $(addprefix $(srctree)/$(obj)/,$(header-y)) \
-                 $(addprefix $(objtree)/$(obj)/,$(objhdr-y))
+                 $(addprefix $(objtree)/$(obj)/,$(objhdr-y)) \
+                 $(addprefix $(objtree)/$(gen)/,$(genhdr-y))
 output-files  := $(addprefix $(install)/, $(all-files))
 
 # Work out what needs to be removed
@@ -52,6 +57,7 @@ quiet_cmd_install = INSTALL $(printdir) ($(words $(all-files))\
       cmd_install = \
         $(PERL) $< $(srctree)/$(obj) $(install) $(SRCARCH) $(header-y); \
         $(PERL) $< $(objtree)/$(obj) $(install) $(SRCARCH) $(objhdr-y); \
+        $(PERL) $< $(objtree)/$(gen) $(install) $(SRCARCH) $(genhdr-y); \
         for F in $(wrapper-files); do                                   \
                 echo "\#include <asm-generic/$$F>" > $(install)/$$F;    \
         done;                                                           \
index 5d986d9adf1b7977684a1fa1825f5ff25c2816bc..00c368c6e996fb0555f8161b6d3147c554d037e5 100644 (file)
@@ -93,9 +93,9 @@ obj-dirs      := $(addprefix $(obj)/,$(obj-dirs))
 # already
 # $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will 
 # end up in (or would, if it gets compiled in)
-# Note: It's possible that one object gets potentially linked into more
-#       than one module. In that case KBUILD_MODNAME will be set to foo_bar,
-#       where foo and bar are the name of the modules.
+# Note: Files that end up in two or more modules are compiled without the
+#       KBUILD_MODNAME definition. The reason is that any made-up name would
+#       differ in different configs.
 name-fix = $(subst $(comma),_,$(subst -,_,$1))
 basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
 modname_flags  = $(if $(filter 1,$(words $(modname))),\
@@ -264,7 +264,7 @@ $(obj)/%.dtb.S: $(obj)/%.dtb
        $(call cmd,dt_S_dtb)
 
 quiet_cmd_dtc = DTC     $@
-cmd_dtc = $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS) $<
+cmd_dtc = $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS) -d $(depfile) $<
 
 # Bzip2
 # ---------------------------------------------------------------------------
index 3ab316e5231336cd528b1d591c517f42860ad721..d24810fc6af6caf3a15ea3f5a55b33f4f08a667b 100755 (executable)
@@ -198,11 +198,16 @@ EOF
 }
 
 syscall_list() {
-sed -n -e '/^\#define/ s/[^_]*__NR_\([^[:space:]]*\).*/\
-\#if !defined \(__NR_\1\) \&\& !defined \(__IGNORE_\1\)\
-\#warning syscall \1 not implemented\
-\#endif/p' $1
+    grep '^[0-9]' "$1" | sort -n | (
+       while read nr abi name entry ; do
+           echo <<EOF
+#if !defined(__NR_${name}) && !defined(__IGNORE_${name})
+#warning syscall ${name} not implemented
+#endif
+EOF
+       done
+    )
 }
 
-(ignore_list && syscall_list $(dirname $0)/../arch/x86/include/asm/unistd_32.h) | \
+(ignore_list && syscall_list $(dirname $0)/../arch/x86/syscalls/syscall_32.tbl) | \
 $* -E -x c - > /dev/null
index 1bb1a1bd2daa832b234edbec3765861d4f41010d..3c2776466d877325d63b1980b798b8b0f9d6f556 100755 (executable)
@@ -9,14 +9,23 @@ if [ "$C" = "1" -o "$C" = "2" ]; then
 #    FLAGS="-ignore_unknown_options -very_quiet"
 #    OPTIONS=$*
 
-# Workaround for Coccinelle < 0.2.3
-    FLAGS="-I $srctree/include -very_quiet"
-    shift $(( $# - 1 ))
-    OPTIONS=$1
+    if [ "$KBUILD_EXTMOD" = "" ] ; then
+        # Workaround for Coccinelle < 0.2.3
+        FLAGS="-I $srctree/include -very_quiet"
+        shift $(( $# - 1 ))
+        OPTIONS=$1
+    else
+       echo M= is not currently supported when C=1 or C=2
+       exit 1
+    fi
 else
     ONLINE=0
     FLAGS="-very_quiet"
-    OPTIONS="-dir $srctree"
+    if [ "$KBUILD_EXTMOD" = "" ] ; then
+        OPTIONS="-dir $srctree"
+    else
+        OPTIONS="-dir $KBUILD_EXTMOD -patch $srctree -I $srctree/include -I $KBUILD_EXTMOD/include"
+    fi
 fi
 
 if [ ! -x "$SPATCH" ]; then
diff --git a/scripts/coccinelle/api/devm_request_and_ioremap.cocci b/scripts/coccinelle/api/devm_request_and_ioremap.cocci
new file mode 100644 (file)
index 0000000..46beb81
--- /dev/null
@@ -0,0 +1,105 @@
+/// Reimplement a call to devm_request_mem_region followed by a call to ioremap
+/// or ioremap_nocache by a call to devm_request_and_ioremap.
+/// Devm_request_and_ioremap was introduced in
+/// 72f8c0bfa0de64c68ee59f40eb9b2683bffffbb0.  It makes the code much more
+/// concise.
+///
+///
+// Confidence: High
+// Copyright: (C) 2011 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2011 Gilles Muller, INRIA/LiP6.  GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: -no_includes -include_headers
+
+virtual patch
+virtual org
+virtual report
+virtual context
+
+@nm@
+expression myname;
+identifier i;
+@@
+
+struct platform_driver i = { .driver = { .name = myname } };
+
+@depends on patch@
+expression dev,res,size;
+@@
+
+-if (!devm_request_mem_region(dev, res->start, size,
+-                              \(res->name\|dev_name(dev)\))) {
+-   ...
+-   return ...;
+-}
+... when != res->start
+(
+-devm_ioremap(dev,res->start,size)
++devm_request_and_ioremap(dev,res)
+|
+-devm_ioremap_nocache(dev,res->start,size)
++devm_request_and_ioremap(dev,res)
+)
+... when any
+    when != res->start
+
+// this rule is separate from the previous one, because a single file can
+// have multiple values of myname
+@depends on patch@
+expression dev,res,size;
+expression nm.myname;
+@@
+
+-if (!devm_request_mem_region(dev, res->start, size,myname)) {
+-   ...
+-   return ...;
+-}
+... when != res->start
+(
+-devm_ioremap(dev,res->start,size)
++devm_request_and_ioremap(dev,res)
+|
+-devm_ioremap_nocache(dev,res->start,size)
++devm_request_and_ioremap(dev,res)
+)
+... when any
+    when != res->start
+
+
+@pb depends on org || report || context@
+expression dev,res,size;
+expression nm.myname;
+position p1,p2;
+@@
+
+*if
+  (!devm_request_mem_region@p1(dev, res->start, size,
+                              \(res->name\|dev_name(dev)\|myname\))) {
+   ...
+   return ...;
+}
+... when != res->start
+(
+*devm_ioremap@p2(dev,res->start,size)
+|
+*devm_ioremap_nocache@p2(dev,res->start,size)
+)
+... when any
+    when != res->start
+
+@script:python depends on org@
+p1 << pb.p1;
+p2 << pb.p2;
+@@
+
+cocci.print_main("INFO: replace by devm_request_and_ioremap",p1)
+cocci.print_secs("",p2)
+
+@script:python depends on report@
+p1 << pb.p1;
+p2 << pb.p2;
+@@
+
+msg = "INFO: devm_request_mem_region followed by ioremap on line %s can be replaced by devm_request_and_ioremap" % (p2[0].line)
+coccilib.report.print_report(p1[0],msg)
index e0805ad08d39260e03e94759fde73dd85a1121e1..07a74b2c6196c0dc649aaadeee908272ed665d15 100644 (file)
@@ -1,16 +1,19 @@
 /// Use kstrdup rather than duplicating its implementation
 ///
 // Confidence: High
-// Copyright: (C) 2010 Nicolas Palix, DIKU.  GPLv2.
-// Copyright: (C) 2010 Julia Lawall, DIKU.  GPLv2.
-// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
+// Copyright: (C) 2010-2012 Nicolas Palix.  GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
 // Options: -no_includes -include_headers
 
 virtual patch
+virtual context
+virtual org
+virtual report
 
-@@
+@depends on patch@
 expression from,to;
 expression flag,E1,E2;
 statement S;
@@ -23,7 +26,7 @@ statement S;
    ... when != \(from = E2 \| to = E2 \)
 -  strcpy(to, from);
 
-@@
+@depends on patch@
 expression x,from,to;
 expression flag,E1,E2,E3;
 statement S;
@@ -37,3 +40,65 @@ statement S;
     if (to==NULL || ...) S
     ... when != \(x = E3 \| from = E3 \| to = E3 \)
 -   memcpy(to, from, x);
+
+// ---------------------------------------------------------------------
+
+@r1 depends on !patch exists@
+expression from,to;
+expression flag,E1,E2;
+statement S;
+position p1,p2;
+@@
+
+*  to = kmalloc@p1(strlen(from) + 1,flag);
+   ... when != \(from = E1 \| to = E1 \)
+   if (to==NULL || ...) S
+   ... when != \(from = E2 \| to = E2 \)
+*  strcpy@p2(to, from);
+
+@r2 depends on !patch exists@
+expression x,from,to;
+expression flag,E1,E2,E3;
+statement S;
+position p1,p2;
+@@
+
+*   x = strlen(from) + 1;
+    ... when != \( x = E1 \| from = E1 \)
+*   to = \(kmalloc@p1\|kzalloc@p2\)(x,flag);
+    ... when != \(x = E2 \| from = E2 \| to = E2 \)
+    if (to==NULL || ...) S
+    ... when != \(x = E3 \| from = E3 \| to = E3 \)
+*   memcpy@p2(to, from, x);
+
+@script:python depends on org@
+p1 << r1.p1;
+p2 << r1.p2;
+@@
+
+cocci.print_main("WARNING opportunity for kstrdep",p1)
+cocci.print_secs("strcpy",p2)
+
+@script:python depends on org@
+p1 << r2.p1;
+p2 << r2.p2;
+@@
+
+cocci.print_main("WARNING opportunity for kstrdep",p1)
+cocci.print_secs("memcpy",p2)
+
+@script:python depends on report@
+p1 << r1.p1;
+p2 << r1.p2;
+@@
+
+msg = "WARNING opportunity for kstrdep (strcpy on line %s)" % (p2[0].line)
+coccilib.report.print_report(p1[0], msg)
+
+@script:python depends on report@
+p1 << r2.p1;
+p2 << r2.p2;
+@@
+
+msg = "WARNING opportunity for kstrdep (memcpy on line %s)" % (p2[0].line)
+coccilib.report.print_report(p1[0], msg)
index b5d722077dc179fb7ba23c73215cbd701a005886..4dceab6d54de5deabae0ac3eea2aa6d00da275d8 100644 (file)
@@ -1,14 +1,17 @@
 /// Use kmemdup rather than duplicating its implementation
 ///
 // Confidence: High
-// Copyright: (C) 2010 Nicolas Palix, DIKU.  GPLv2.
-// Copyright: (C) 2010 Julia Lawall, DIKU.  GPLv2.
-// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
+// Copyright: (C) 2010-2012 Nicolas Palix.  GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
 // Options: -no_includes -include_headers
 
 virtual patch
+virtual context
+virtual org
+virtual report
 
 @r1@
 expression from,to;
@@ -28,7 +31,7 @@ position p;
     ... when != \( x = E1 \| from = E1 \)
     to = \(kmalloc@p\|kzalloc@p\)(x,flag);
 
-@@
+@depends on patch@
 expression from,to,size,flag;
 position p != {r1.p,r2.p};
 statement S;
@@ -38,3 +41,26 @@ statement S;
 +  to = kmemdup(from,size,flag);
    if (to==NULL || ...) S
 -  memcpy(to, from, size);
+
+@r depends on !patch@
+expression from,to,size,flag;
+position p != {r1.p,r2.p};
+statement S;
+@@
+
+*  to = \(kmalloc@p\|kzalloc@p\)(size,flag);
+   to = kmemdup(from,size,flag);
+   if (to==NULL || ...) S
+*  memcpy(to, from, size);
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for kmemdep")
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for kmemdep")
index 72ce012e878a12bbcdcf83f421ac885751763ddf..2efac289fd59d2beb755593acdd0c6fc39f3ec61 100644 (file)
@@ -1,23 +1,25 @@
-/// Use kmemdup_user rather than duplicating its implementation
+/// Use memdup_user rather than duplicating its implementation
 /// This is a little bit restricted to reduce false positives
 ///
 // Confidence: High
-// Copyright: (C) 2010 Nicolas Palix, DIKU.  GPLv2.
-// Copyright: (C) 2010 Julia Lawall, DIKU.  GPLv2.
-// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
+// Copyright: (C) 2010-2012 Nicolas Palix.  GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
 // Options: -no_includes -include_headers
 
 virtual patch
+virtual context
+virtual org
+virtual report
 
-@@
+@depends on patch@
 expression from,to,size,flag;
-position p;
 identifier l1,l2;
 @@
 
--  to = \(kmalloc@p\|kzalloc@p\)(size,flag);
+-  to = \(kmalloc\|kzalloc\)(size,flag);
 +  to = memdup_user(from,size);
    if (
 -      to==NULL
@@ -33,3 +35,26 @@ identifier l1,l2;
 -    -EFAULT
 -    ...+>
 -  }
+
+@r depends on !patch@
+expression from,to,size,flag;
+position p;
+statement S1,S2;
+@@
+
+*  to = \(kmalloc@p\|kzalloc@p\)(size,flag);
+   if (to==NULL || ...) S1
+   if (copy_from_user(to, from, size) != 0)
+   S2
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for memdep_user")
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for memdep_user")
diff --git a/scripts/coccinelle/free/devm_free.cocci b/scripts/coccinelle/free/devm_free.cocci
new file mode 100644 (file)
index 0000000..0a1e361
--- /dev/null
@@ -0,0 +1,71 @@
+/// Find uses of standard freeing functons on values allocated using devm_
+/// functions.  Values allocated using the devm_functions are freed when
+/// the device is detached, and thus the use of the standard freeing
+/// function would cause a double free.
+/// See Documentation/driver-model/devres.txt for more information.
+///
+/// A difficulty of detecting this problem is that the standard freeing
+/// function might be called from a different function than the one
+/// containing the allocation function.  It is thus necessary to make the
+/// connection between the allocation function and the freeing function.
+/// Here this is done using the specific argument text, which is prone to
+/// false positives.  There is no rule for the request_region and
+/// request_mem_region variants because this heuristic seems to be a bit
+/// less reliable in these cases.
+///
+// Confidence: Moderate
+// Copyright: (C) 2011 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2011 Gilles Muller, INRIA/LiP6.  GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: -no_includes -include_headers
+
+virtual org
+virtual report
+virtual context
+
+@r depends on context || org || report@
+expression x;
+@@
+
+(
+ x = devm_kzalloc(...)
+|
+ x = devm_request_irq(...)
+|
+ x = devm_ioremap(...)
+|
+ x = devm_ioremap_nocache(...)
+|
+ x = devm_ioport_map(...)
+)
+
+@pb@
+expression r.x;
+position p;
+@@
+
+(
+* kfree@p(x)
+|
+* free_irq@p(x)
+|
+* iounmap@p(x)
+|
+* ioport_unmap@p(x)
+)
+
+@script:python depends on org@
+p << pb.p;
+@@
+
+msg="WARNING: invalid free of devm_ allocated data"
+coccilib.org.print_todo(p[0], msg)
+
+@script:python depends on report@
+p << pb.p;
+@@
+
+msg="WARNING: invalid free of devm_ allocated data"
+coccilib.report.print_report(p[0], msg)
+
index f9f79d9245ee9815ef3e244f791553501e1391b2..d9ae6d89c2f57e9db00a856f461b1f968cf07018 100644 (file)
@@ -5,9 +5,9 @@
 //# SCTP_DBG_OBJCNT_DEC that do not actually evaluate their argument
 ///
 // Confidence: Moderate
-// Copyright: (C) 2010 Nicolas Palix, DIKU.  GPLv2.
-// Copyright: (C) 2010 Julia Lawall, DIKU.  GPLv2.
-// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
+// Copyright: (C) 2010-2012 Nicolas Palix.  GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
 // Options: -no_includes -include_headers
@@ -23,7 +23,7 @@ position p1;
 kfree@p1(E)
 
 @print expression@
-constant char *c;
+constant char [] c;
 expression free.E,E2;
 type T;
 position p;
@@ -36,6 +36,10 @@ identifier f;
  E@p == E2
 |
  E@p != E2
+|
+ E2 == E@p
+|
+ E2 != E@p
 |
  !E@p
 |
@@ -113,5 +117,5 @@ p1 << free.p1;
 p2 << r.p2;
 @@
 
-msg = "reference preceded by free on line %s" % (p1[0].line)
+msg = "ERROR: reference preceded by free on line %s" % (p1[0].line)
 coccilib.report.print_report(p2[0],msg)
index 77bc108c3f597b715850465c0a5fa26333132bec..0a40af828c43a4161b94d2b9c85a66830ae60f1b 100644 (file)
@@ -2,16 +2,19 @@
 /// is no point to call of_node_put on the final value.
 ///
 // Confidence: High
-// Copyright: (C) 2010 Nicolas Palix, DIKU.  GPLv2.
-// Copyright: (C) 2010 Julia Lawall, DIKU.  GPLv2.
-// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
+// Copyright: (C) 2010-2012 Nicolas Palix.  GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
 // Options: -no_includes -include_headers
 
 virtual patch
+virtual context
+virtual org
+virtual report
 
-@@
+@depends on patch@
 iterator name for_each_node_by_name;
 expression np,E;
 identifier l;
@@ -24,7 +27,7 @@ for_each_node_by_name(np,...) {
 ... when != np = E
 - of_node_put(np);
 
-@@
+@depends on patch@
 iterator name for_each_node_by_type;
 expression np,E;
 identifier l;
@@ -37,7 +40,7 @@ for_each_node_by_type(np,...) {
 ... when != np = E
 - of_node_put(np);
 
-@@
+@depends on patch@
 iterator name for_each_compatible_node;
 expression np,E;
 identifier l;
@@ -50,7 +53,7 @@ for_each_compatible_node(np,...) {
 ... when != np = E
 - of_node_put(np);
 
-@@
+@depends on patch@
 iterator name for_each_matching_node;
 expression np,E;
 identifier l;
@@ -62,3 +65,59 @@ for_each_matching_node(np,...) {
 }
 ... when != np = E
 - of_node_put(np);
+
+// ----------------------------------------------------------------------
+
+@r depends on !patch forall@
+//iterator name for_each_node_by_name;
+//iterator name for_each_node_by_type;
+//iterator name for_each_compatible_node;
+//iterator name for_each_matching_node;
+expression np,E;
+identifier l;
+position p1,p2;
+@@
+
+(
+*for_each_node_by_name@p1(np,...)
+{
+  ... when != break;
+      when != goto l;
+}
+|
+*for_each_node_by_type@p1(np,...)
+{
+  ... when != break;
+      when != goto l;
+}
+|
+*for_each_compatible_node@p1(np,...)
+{
+  ... when != break;
+      when != goto l;
+}
+|
+*for_each_matching_node@p1(np,...)
+{
+  ... when != break;
+      when != goto l;
+}
+)
+... when != np = E
+* of_node_put@p2(np);
+
+@script:python depends on org@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+cocci.print_main("unneeded of_node_put",p2)
+cocci.print_secs("iterator",p1)
+
+@script:python depends on report@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+msg = "ERROR: of_node_put not needed after iterator on line %s" % (p1[0].line)
+coccilib.report.print_report(p2[0], msg)
index baa4297a4ed18d6ae757b10404dcdcefb88d7892..259899f6838edaa463d16d445e7f7b8f39d132f6 100644 (file)
@@ -1,20 +1,24 @@
 /// Many iterators have the property that the first argument is always bound
-/// to a real list element, never NULL.  False positives arise for some
-/// iterators that do not have this property, or in cases when the loop
-/// cursor is reassigned.  The latter should only happen when the matched
-/// code is on the way to a loop exit (break, goto, or return).
+/// to a real list element, never NULL.
+//# False positives arise for some iterators that do not have this property,
+//# or in cases when the loop cursor is reassigned.  The latter should only
+//# happen when the matched code is on the way to a loop exit (break, goto,
+//# or return).
 ///
 // Confidence: Moderate
-// Copyright: (C) 2010 Nicolas Palix, DIKU.  GPLv2.
-// Copyright: (C) 2010 Julia Lawall, DIKU.  GPLv2.
-// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
+// Copyright: (C) 2010-2012 Nicolas Palix.  GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
 // Options: -no_includes -include_headers
 
 virtual patch
+virtual context
+virtual org
+virtual report
 
-@@
+@depends on patch@
 iterator I;
 expression x,E,E1,E2;
 statement S,S1,S2;
@@ -55,4 +59,36 @@ I(x,...) { <...
   x != NULL
 + )
 )
-  ...> }
\ No newline at end of file
+  ...> }
+
+@r depends on !patch exists@
+iterator I;
+expression x,E;
+position p1,p2;
+@@
+
+*I@p1(x,...)
+{ ... when != x = E
+(
+*  x@p2 == NULL
+|
+*  x@p2 != NULL
+)
+  ... when any
+}
+
+@script:python depends on org@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+cocci.print_main("iterator-bound variable",p1)
+cocci.print_secs("useless NULL test",p2)
+
+@script:python depends on report@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+msg = "ERROR: iterator variable bound on line %s cannot be NULL" % (p1[0].line)
+coccilib.report.print_report(p2[0], msg)
index 00af5344a68f2a1269b85e093bc25ddc56e0f98e..8f10b49603c32e11b9c0aa2845da8f11d7901f5e 100644 (file)
@@ -1,17 +1,20 @@
 /// Find functions that refer to GFP_KERNEL but are called with locks held.
-/// The proposed change of converting the GFP_KERNEL is not necessarily the
-/// correct one.  It may be desired to unlock the lock, or to not call the
-/// function under the lock in the first place.
+//# The proposed change of converting the GFP_KERNEL is not necessarily the
+//# correct one.  It may be desired to unlock the lock, or to not call the
+//# function under the lock in the first place.
 ///
 // Confidence: Moderate
-// Copyright: (C) 2010 Nicolas Palix, DIKU.  GPLv2.
-// Copyright: (C) 2010 Julia Lawall, DIKU.  GPLv2.
-// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
+// Copyright: (C) 2012 Nicolas Palix.  GPLv2.
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
 // Options: -no_includes -include_headers
 
 virtual patch
+virtual context
+virtual org
+virtual report
 
 @gfp exists@
 identifier fn;
@@ -32,28 +35,29 @@ fn(...) {
  ... when any
 }
 
-@locked@
+@locked exists@
 identifier gfp.fn;
+position p1,p2;
 @@
 
 (
-read_lock_irq
+read_lock_irq@p1
 |
-write_lock_irq
+write_lock_irq@p1
 |
-read_lock_irqsave
+read_lock_irqsave@p1
 |
-write_lock_irqsave
+write_lock_irqsave@p1
 |
-spin_lock
+spin_lock@p1
 |
-spin_trylock
+spin_trylock@p1
 |
-spin_lock_irq
+spin_lock_irq@p1
 |
-spin_lock_irqsave
+spin_lock_irqsave@p1
 |
-local_irq_disable
+local_irq_disable@p1
 )
  (...)
 ...  when != read_unlock_irq(...)
@@ -64,11 +68,38 @@ local_irq_disable
      when != spin_unlock_irq(...)
      when != spin_unlock_irqrestore(...)
      when != local_irq_enable(...)
-fn(...)
+fn@p2(...)
 
-@depends on locked@
+@depends on locked && patch@
 position gfp.p;
 @@
 
 - GFP_KERNEL@p
 + GFP_ATOMIC
+
+@depends on locked && !patch@
+position gfp.p;
+@@
+
+* GFP_KERNEL@p
+
+@script:python depends on !patch && org@
+p << gfp.p;
+fn << gfp.fn;
+p1 << locked.p1;
+p2 << locked.p2;
+@@
+
+cocci.print_main("lock",p1)
+cocci.print_secs("call",p2)
+cocci.print_secs("GFP_KERNEL",p)
+
+@script:python depends on !patch && report@
+p << gfp.p;
+fn << gfp.fn;
+p1 << locked.p1;
+p2 << locked.p2;
+@@
+
+msg = "ERROR: function %s called on line %s inside lock on line %s but uses GFP_KERNEL" % (fn,p2[0].line,p1[0].line)
+coccilib.report.print_report(p[0], msg)
index b4344d838097bb4a541fbd15097d7ef81367bc02..1c4ffe6fd846746d64a1a34168fb3864f18b9af8 100644 (file)
@@ -1,9 +1,9 @@
 /// Find nested lock+irqsave functions that use the same flags variables
 ///
 // Confidence: High
-// Copyright: (C) 2010 Nicolas Palix, DIKU.  GPLv2.
-// Copyright: (C) 2010 Julia Lawall, DIKU.  GPLv2.
-// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
+// Copyright: (C) 2010-2012 Nicolas Palix.  GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
 // Options: -no_includes -include_headers
@@ -12,7 +12,7 @@ virtual context
 virtual org
 virtual report
 
-@r@
+@r exists@
 expression lock1,lock2,flags;
 position p1,p2;
 @@
@@ -39,7 +39,7 @@ read_lock_irqsave@p2(lock2,flags)
 write_lock_irqsave@p2(lock2,flags)
 )
 
-@d@
+@d exists@
 expression f <= r.flags;
 expression lock1,lock2,flags;
 position r.p1, r.p2;
@@ -76,5 +76,5 @@ p1 << r.p1;
 p2 << r.p2;
 @@
 
-msg="ERROR: nested lock+irqsave that reuses flags from %s." % (p1[0].line)
+msg="ERROR: nested lock+irqsave that reuses flags from line %s." % (p1[0].line)
 coccilib.report.print_report(p2[0], msg)
index 7641a2925434219ec314d3c3718b80908b77ff5c..3267d7410bd5072aaab32efd8d5e4c4f06205618 100644 (file)
@@ -6,13 +6,14 @@
 /// function call that releases the lock.
 ///
 // Confidence: Moderate
-// Copyright: (C) 2010 Nicolas Palix, DIKU.  GPLv2.
-// Copyright: (C) 2010 Julia Lawall, DIKU.  GPLv2.
-// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
+// Copyright: (C) 2010-2012 Nicolas Palix.  GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
 // Options: -no_includes -include_headers
 
+virtual context
 virtual org
 virtual report
 
@@ -57,7 +58,7 @@ position r;
 
 for(...;...;...) { <+... return@r ...; ...+> }
 
-@err@
+@err exists@
 expression E1;
 position prelocked.p;
 position up != prelocked.p1;
@@ -65,14 +66,14 @@ position r!=looped.r;
 identifier lock,unlock;
 @@
 
-lock(E1@p,...);
+*lock(E1@p,...);
 <+... when != E1
 if (...) {
   ... when != E1
-  return@r ...;
+*  return@r ...;
 }
 ...+>
-unlock@up(E1,...);
+*unlock@up(E1,...);
 
 @script:python depends on org@
 p << prelocked.p1;
index 156b20adb35163a603a533a90d73d7a7cc6c6ad0..cf74a00cf59740d51f828f3140460f77268c1d40 100644 (file)
@@ -3,9 +3,9 @@
 /// initialization.
 ///
 // Confidence: Low
-// Copyright: (C) 2010 Nicolas Palix, DIKU.  GPLv2.
-// Copyright: (C) 2010 Julia Lawall, DIKU.  GPLv2.
-// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
+// Copyright: (C) 2010-2012 Nicolas Palix.  GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments: requires at least Coccinelle 0.2.4, lex or parse error otherwise
 // Options: -no_includes -include_headers
@@ -49,5 +49,5 @@ pr << r.p;
 @@
 
 if int(ps[0].line) < int(pr[0].line) or (int(ps[0].line) == int(pr[0].line) and int(ps[0].column) < int(pr[0].column)):
-  msg = "%s: first occurrence %s, second occurrence %s" % (fld,ps[0].line,pr[0].line)
+  msg = "%s: first occurrence line %s, second occurrence line %s" % (fld,ps[0].line,pr[0].line)
   coccilib.report.print_report(p0[0],msg)
index 4c9c52b9c41331c87d2b532b0439ea316a3cba24..ed961a1f7d11b28c8e9581e4bffa43edaa495a5b 100644 (file)
@@ -1,16 +1,19 @@
 /// The various basic memory allocation functions don't return ERR_PTR
 ///
 // Confidence: High
-// Copyright: (C) 2010 Nicolas Palix, DIKU.  GPLv2.
-// Copyright: (C) 2010 Julia Lawall, DIKU.  GPLv2.
-// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6.  GPLv2.
+// Copyright: (C) 2010-2012 Nicolas Palix.  GPLv2.
+// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Comments:
 // Options: -no_includes -include_headers
 
 virtual patch
+virtual context
+virtual org
+virtual report
 
-@@
+@depends on patch@
 expression x,E;
 @@
 
@@ -18,3 +21,28 @@ x = \(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\|kmem_cache
 ... when != x = E
 - IS_ERR(x)
 + !x
+
+@r depends on !patch exists@
+expression x,E;
+position p1,p2;
+@@
+
+*x = \(kmalloc@p1\|kzalloc@p1\|kcalloc@p1\|kmem_cache_alloc@p1\|kmem_cache_zalloc@p1\|kmem_cache_alloc_node@p1\|kmalloc_node@p1\|kzalloc_node@p1\)(...)
+... when != x = E
+* IS_ERR@p2(x)
+
+@script:python depends on org@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+cocci.print_main("alloc call",p1)
+cocci.print_secs("IS_ERR that should be NULL tests",p2)
+
+@script:python depends on report@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+msg = "ERROR: allocation function on line %s returns NULL not ERR_PTR on failure" % (p1[0].line)
+coccilib.report.print_report(p2[0], msg)
index cbc0193098e4e83ea4628facb1d86dcbcc54be18..451c92d31b196634cfb9ed7b2b15c632efd89691 100644 (file)
@@ -71,6 +71,7 @@ static void  __attribute__ ((noreturn)) usage(void)
        fprintf(stderr, "\t\t\tasm - assembler source\n");
        fprintf(stderr, "\t-V <output version>\n");
        fprintf(stderr, "\t\tBlob version to produce, defaults to %d (relevant for dtb\n\t\tand asm output only)\n", DEFAULT_FDT_VERSION);
+       fprintf(stderr, "\t-d <output dependency file>\n");
        fprintf(stderr, "\t-R <number>\n");
        fprintf(stderr, "\t\tMake space for <number> reserve map entries (relevant for \n\t\tdtb and asm output only)\n");
        fprintf(stderr, "\t-S <bytes>\n");
@@ -99,6 +100,7 @@ int main(int argc, char *argv[])
        const char *inform = "dts";
        const char *outform = "dts";
        const char *outname = "-";
+       const char *depname = NULL;
        int force = 0, check = 0, sort = 0;
        const char *arg;
        int opt;
@@ -111,7 +113,8 @@ int main(int argc, char *argv[])
        minsize    = 0;
        padsize    = 0;
 
-       while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:vH:s")) != EOF) {
+       while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fcqb:vH:s"))
+                       != EOF) {
                switch (opt) {
                case 'I':
                        inform = optarg;
@@ -125,6 +128,9 @@ int main(int argc, char *argv[])
                case 'V':
                        outversion = strtol(optarg, NULL, 0);
                        break;
+               case 'd':
+                       depname = optarg;
+                       break;
                case 'R':
                        reservenum = strtol(optarg, NULL, 0);
                        break;
@@ -188,6 +194,14 @@ int main(int argc, char *argv[])
        fprintf(stderr, "DTC: %s->%s  on file \"%s\"\n",
                inform, outform, arg);
 
+       if (depname) {
+               depfile = fopen(depname, "w");
+               if (!depfile)
+                       die("Couldn't open dependency file %s: %s\n", depname,
+                           strerror(errno));
+               fprintf(depfile, "%s:", outname);
+       }
+
        if (streq(inform, "dts"))
                bi = dt_from_source(arg);
        else if (streq(inform, "fs"))
@@ -197,6 +211,11 @@ int main(int argc, char *argv[])
        else
                die("Unknown input format \"%s\"\n", inform);
 
+       if (depfile) {
+               fputc('\n', depfile);
+               fclose(depfile);
+       }
+
        if (cmdline_boot_cpuid != -1)
                bi->boot_cpuid_phys = cmdline_boot_cpuid;
 
index 2dbc874288ca1b7487dd423d630cb7ac3b63e50f..36a38e9f1a2cb9200ee07bfce22eab489f1f1127 100644 (file)
@@ -40,6 +40,7 @@ static char *dirname(const char *path)
        return NULL;
 }
 
+FILE *depfile; /* = NULL */
 struct srcfile_state *current_srcfile; /* = NULL */
 
 /* Detect infinite include recursion. */
@@ -67,6 +68,9 @@ FILE *srcfile_relative_open(const char *fname, char **fullnamep)
                            strerror(errno));
        }
 
+       if (depfile)
+               fprintf(depfile, " %s", fullname);
+
        if (fullnamep)
                *fullnamep = fullname;
        else
index bd7966e56a53672f8c5c34369067c38696e9e246..ce980cafe58867d64d7a142b00914034f24f0d50 100644 (file)
@@ -30,6 +30,7 @@ struct srcfile_state {
        struct srcfile_state *prev;
 };
 
+extern FILE *depfile; /* = NULL */
 extern struct srcfile_state *current_srcfile; /* = NULL */
 
 FILE *srcfile_relative_open(const char *fname, char **fullnamep);
index a5510903e874a35a5cbb238e1eb50a7b82746fd6..aca33b98bf634b269b9857f5bc08d2e315f5f8d3 100644 (file)
@@ -11,3 +11,4 @@ HOSTCFLAGS_lex.lex.o := -I$(src)
 # dependencies on generated files need to be listed explicitly
 $(obj)/lex.lex.o: $(obj)/keywords.hash.c $(obj)/parse.tab.h
 
+clean-files    := keywords.hash.c lex.lex.c parse.tab.c parse.tab.h
index 914833d99b06f78242fa12584c568ecef6a5e65a..79662658fb9158af1d7b3ee43dba0cfab0aa42cf 100644 (file)
@@ -50,9 +50,8 @@ localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
 
 # Create new linux.pot file
 # Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files
-# The symlink is used to repair a deficiency in arch/um
 update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
-       $(Q)echo "  GEN config"
+       $(Q)echo "  GEN     config.pot"
        $(Q)xgettext --default-domain=linux                         \
            --add-comments --keyword=_ --keyword=N_                 \
            --from-code=UTF-8                                       \
@@ -63,10 +62,11 @@ update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
        $(Q)(for i in `ls $(srctree)/arch/*/Kconfig      \
            $(srctree)/arch/*/um/Kconfig`;               \
            do                                           \
-               echo "  GEN $$i";                        \
+               echo "  GEN     $$i";                    \
                $(obj)/kxgettext $$i                     \
                     >> $(obj)/config.pot;               \
            done )
+       $(Q)echo "  GEN     linux.pot"
        $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
            --output $(obj)/linux.pot
        $(Q)rm -f $(obj)/config.pot
index 5a58965d8800daab99a8bd096262c1f95465482d..7c7a5a6cc3f504bd759dc01019536b2bf804fbbd 100644 (file)
@@ -464,7 +464,7 @@ kconfig_print_comment(FILE *fp, const char *value, void *arg)
                fprintf(fp, "#");
                if (l) {
                        fprintf(fp, " ");
-                       fwrite(p, l, 1, fp);
+                       xfwrite(p, l, 1, fp);
                        p += l;
                }
                fprintf(fp, "\n");
@@ -537,7 +537,7 @@ header_print_comment(FILE *fp, const char *value, void *arg)
                fprintf(fp, " *");
                if (l) {
                        fprintf(fp, " ");
-                       fwrite(p, l, 1, fp);
+                       xfwrite(p, l, 1, fp);
                        p += l;
                }
                fprintf(fp, "\n");
index 80fce57080cc36787e01efc00fe8a111efa3d0ff..d4ecce8bc3a689daa2157e4f47e65e7c62192bd4 100644 (file)
@@ -10,6 +10,7 @@
 extern "C" {
 #endif
 
+#include <assert.h>
 #include <stdio.h>
 #ifndef __cplusplus
 #include <stdbool.h>
index 9f4438027df4201b9fb34d4191cdb3da9ac4994f..adc230638c5b141ceaa2cf9b25d35f99324c19b6 100644 (file)
@@ -683,7 +683,7 @@ void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
        dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
                                        GTK_DIALOG_DESTROY_WITH_PARENT,
                                        GTK_MESSAGE_INFO,
-                                       GTK_BUTTONS_CLOSE, intro_text);
+                                       GTK_BUTTONS_CLOSE, "%s", intro_text);
        g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
                                 G_CALLBACK(gtk_widget_destroy),
                                 GTK_OBJECT(dialog));
@@ -701,7 +701,7 @@ void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
        dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
                                        GTK_DIALOG_DESTROY_WITH_PARENT,
                                        GTK_MESSAGE_INFO,
-                                       GTK_BUTTONS_CLOSE, about_text);
+                                       GTK_BUTTONS_CLOSE, "%s", about_text);
        g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
                                 G_CALLBACK(gtk_widget_destroy),
                                 GTK_OBJECT(dialog));
@@ -720,7 +720,7 @@ void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
        dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
                                        GTK_DIALOG_DESTROY_WITH_PARENT,
                                        GTK_MESSAGE_INFO,
-                                       GTK_BUTTONS_CLOSE, license_text);
+                                       GTK_BUTTONS_CLOSE, "%s", license_text);
        g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
                                 G_CALLBACK(gtk_widget_destroy),
                                 GTK_OBJECT(dialog));
@@ -830,7 +830,7 @@ static void renderer_edited(GtkCellRendererText * cell,
 static void change_sym_value(struct menu *menu, gint col)
 {
        struct symbol *sym = menu->sym;
-       tristate oldval, newval;
+       tristate newval;
 
        if (!sym)
                return;
@@ -847,7 +847,6 @@ static void change_sym_value(struct menu *menu, gint col)
        switch (sym_get_type(sym)) {
        case S_BOOLEAN:
        case S_TRISTATE:
-               oldval = sym_get_tristate_value(sym);
                if (!sym_tristate_within_range(sym, newval))
                        newval = yes;
                sym_set_tristate_value(sym, newval);
@@ -1278,7 +1277,6 @@ static void update_tree(struct menu *src, GtkTreeIter * dst)
        gboolean valid;
        GtkTreeIter *sibling;
        struct symbol *sym;
-       struct property *prop;
        struct menu *menu1, *menu2;
 
        if (src == &rootmenu)
@@ -1287,7 +1285,6 @@ static void update_tree(struct menu *src, GtkTreeIter * dst)
        valid = gtk_tree_model_iter_children(model2, child2, dst);
        for (child1 = src->list; child1; child1 = child1->next) {
 
-               prop = child1->prompt;
                sym = child1->sym;
 
              reparse:
index b633bdb9f3d47c815be8727b155471167135626a..c18f2bd9c095510d1d5e58575b265bd67ae9e781 100644 (file)
@@ -90,8 +90,10 @@ struct conf_printer {
 /* confdata.c and expr.c */
 static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
 {
-       if (fwrite(str, len, count, out) < count)
-               fprintf(stderr, "\nError in writing or end of file.\n");
+       assert(len != 0);
+
+       if (fwrite(str, len, count, out) != count)
+               fprintf(stderr, "Error in writing or end of file.\n");
 }
 
 /* menu.c */
index 19e200d9112091fc3ddfe5aac59f94b32b38c4dc..2c6286c0bc1ac70ef190bdbd031905593070c933 100644 (file)
@@ -830,6 +830,8 @@ static int handle_exit(void)
                fprintf(stderr, _("\n\n"
                                  "Your configuration changes were NOT saved."
                                  "\n\n"));
+               if (res != KEY_ESC)
+                       res = 0;
        }
 
        return res;
diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
new file mode 100644 (file)
index 0000000..ceadf0e
--- /dev/null
@@ -0,0 +1,117 @@
+#!/bin/sh
+#  merge_config.sh - Takes a list of config fragment values, and merges
+#  them one by one. Provides warnings on overridden values, and specified
+#  values that did not make it to the resulting .config file (due to missed
+#  dependencies or config symbol removal).
+#
+#  Portions reused from kconf_check and generate_cfg:
+#  http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/kconf_check
+#  http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/generate_cfg
+#
+#  Copyright (c) 2009-2010 Wind River Systems, Inc.
+#  Copyright 2011 Linaro
+#
+#  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.
+
+clean_up() {
+       rm -f $TMP_FILE
+       exit
+}
+trap clean_up HUP INT TERM
+
+usage() {
+       echo "Usage: $0 [OPTIONS] [CONFIG [...]]"
+       echo "  -h    display this help text"
+       echo "  -m    only merge the fragments, do not execute the make command"
+       echo "  -n    use allnoconfig instead of alldefconfig"
+}
+
+MAKE=true
+ALLTARGET=alldefconfig
+
+while true; do
+       case $1 in
+       "-n")
+               ALLTARGET=allnoconfig
+               shift
+               continue
+               ;;
+       "-m")
+               MAKE=false
+               shift
+               continue
+               ;;
+       "-h")
+               usage
+               exit
+               ;;
+       *)
+               break
+               ;;
+       esac
+done
+
+
+
+MERGE_LIST=$*
+SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p"
+TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
+
+# Merge files, printing warnings on overrided values
+for MERGE_FILE in $MERGE_LIST ; do
+       echo "Merging $MERGE_FILE"
+       CFG_LIST=$(sed -n "$SED_CONFIG_EXP" $MERGE_FILE)
+
+       for CFG in $CFG_LIST ; do
+               grep -q -w $CFG $TMP_FILE
+               if [ $? -eq 0 ] ; then
+                       PREV_VAL=$(grep -w $CFG $TMP_FILE)
+                       NEW_VAL=$(grep -w $CFG $MERGE_FILE)
+                       if [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then
+                       echo Value of $CFG is redefined by fragment $MERGE_FILE:
+                       echo Previous  value: $PREV_VAL
+                       echo New value:       $NEW_VAL
+                       echo
+                       fi
+                       sed -i "/$CFG[ =]/d" $TMP_FILE
+               fi
+       done
+       cat $MERGE_FILE >> $TMP_FILE
+done
+
+if [ "$MAKE" = "false" ]; then
+       cp $TMP_FILE .config
+       echo "#"
+       echo "# merged configuration written to .config (needs make)"
+       echo "#"
+       clean_up
+       exit
+fi
+
+# Use the merged file as the starting point for:
+# alldefconfig: Fills in any missing symbols with Kconfig default
+# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set
+make KCONFIG_ALLCONFIG=$TMP_FILE $ALLTARGET
+
+
+# Check all specified config values took (might have missed-dependency issues)
+for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do
+
+       REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE)
+       ACTUAL_VAL=$(grep -w -e "$CFG" .config)
+       if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then
+               echo "Value requested for $CFG not in final .config"
+               echo "Requested value:  $REQUESTED_VAL"
+               echo "Actual value:     $ACTUAL_VAL"
+               echo ""
+       fi
+done
+
+clean_up
index ec7afce4c88d3155d95c454915b5efb249568548..bccf07ddd0b67a0e2f761fd5721f274a49bf9bbb 100644 (file)
@@ -250,33 +250,61 @@ if ($kconfig) {
     read_kconfig($kconfig);
 }
 
+sub convert_vars {
+    my ($line, %vars) = @_;
+
+    my $process = "";
+
+    while ($line =~ s/^(.*?)(\$\((.*?)\))//) {
+       my $start = $1;
+       my $variable = $2;
+       my $var = $3;
+
+       if (defined($vars{$var})) {
+           $process .= $start . $vars{$var};
+       } else {
+           $process .= $start . $variable;
+       }
+    }
+
+    $process .= $line;
+
+    return $process;
+}
+
 # Read all Makefiles to map the configs to the objects
 foreach my $makefile (@makefiles) {
 
-    my $cont = 0;
+    my $line = "";
+    my %make_vars;
 
     open(MIN,$makefile) || die "Can't open $makefile";
     while (<MIN>) {
+       # if this line ends with a backslash, continue
+       chomp;
+       if (/^(.*)\\$/) {
+           $line .= $1;
+           next;
+       }
+
+       $line .= $_;
+       $_ = $line;
+       $line = "";
+
        my $objs;
 
-       # is this a line after a line with a backslash?
-       if ($cont && /(\S.*)$/) {
-           $objs = $1;
-       }
-       $cont = 0;
+       $_ = convert_vars($_, %make_vars);
 
        # collect objects after obj-$(CONFIG_FOO_BAR)
        if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) {
            $var = $1;
            $objs = $2;
+
+       # check if variables are set
+       } elsif (/^\s*(\S+)\s*[:]?=\s*(.*\S)/) {
+           $make_vars{$1} = $2;
        }
        if (defined($objs)) {
-           # test if the line ends with a backslash
-           if ($objs =~ m,(.*)\\$,) {
-               $objs = $1;
-               $cont = 1;
-           }
-
            foreach my $obj (split /\s+/,$objs) {
                $obj =~ s/-/_/g;
                if ($obj =~ /(.*)\.o$/) {
index 363ab4666b173bbb79f31fbd5e634a6fff342703..c0e14b3f2306f77b6e85d2d6f7f25a70b6b41a22 100644 (file)
@@ -28,6 +28,7 @@ typedef Elf64_Addr    kernel_ulong_t;
 #endif
 
 #include <ctype.h>
+#include <stdbool.h>
 
 typedef uint32_t       __u32;
 typedef uint16_t       __u16;
@@ -38,6 +39,35 @@ typedef unsigned char        __u8;
  * we handle those differences explicitly below */
 #include "../../include/linux/mod_devicetable.h"
 
+/* This array collects all instances that use the generic do_table */
+struct devtable {
+       const char *device_id; /* name of table, __mod_<name>_device_table. */
+       unsigned long id_size;
+       void *function;
+};
+
+/* We construct a table of pointers in an ELF section (pointers generally
+ * go unpadded by gcc).  ld creates boundary syms for us. */
+extern struct devtable *__start___devtable[], *__stop___devtable[];
+#define ___cat(a,b) a ## b
+#define __cat(a,b) ___cat(a,b)
+
+#if __GNUC__ == 3 && __GNUC_MINOR__ < 3
+# define __used                        __attribute__((__unused__))
+#else
+# define __used                        __attribute__((__used__))
+#endif
+
+/* Add a table entry.  We test function type matches while we're here. */
+#define ADD_TO_DEVTABLE(device_id, type, function) \
+       static struct devtable __cat(devtable,__LINE__) = {     \
+               device_id + 0*sizeof((function)((const char *)NULL,     \
+                                               (type *)NULL,           \
+                                               (char *)NULL)),         \
+               sizeof(type), (function) };                             \
+       static struct devtable *__attribute__((section("__devtable"))) \
+               __used __cat(devtable_ptr,__LINE__) = &__cat(devtable,__LINE__)
+
 #define ADD(str, sep, cond, field)                              \
 do {                                                            \
         strcat(str, sep);                                       \
@@ -289,6 +319,7 @@ static int do_hid_entry(const char *filename,
 
        return 1;
 }
+ADD_TO_DEVTABLE("hid", struct hid_device_id, do_hid_entry);
 
 /* Looks like: ieee1394:venNmoNspNverN */
 static int do_ieee1394_entry(const char *filename,
@@ -313,6 +344,7 @@ static int do_ieee1394_entry(const char *filename,
        add_wildcard(alias);
        return 1;
 }
+ADD_TO_DEVTABLE("ieee1394", struct ieee1394_device_id, do_ieee1394_entry);
 
 /* Looks like: pci:vNdNsvNsdNbcNscNiN. */
 static int do_pci_entry(const char *filename,
@@ -356,6 +388,7 @@ static int do_pci_entry(const char *filename,
        add_wildcard(alias);
        return 1;
 }
+ADD_TO_DEVTABLE("pci", struct pci_device_id, do_pci_entry);
 
 /* looks like: "ccw:tNmNdtNdmN" */
 static int do_ccw_entry(const char *filename,
@@ -379,6 +412,7 @@ static int do_ccw_entry(const char *filename,
        add_wildcard(alias);
        return 1;
 }
+ADD_TO_DEVTABLE("ccw", struct ccw_device_id, do_ccw_entry);
 
 /* looks like: "ap:tN" */
 static int do_ap_entry(const char *filename,
@@ -387,6 +421,7 @@ static int do_ap_entry(const char *filename,
        sprintf(alias, "ap:t%02X*", id->dev_type);
        return 1;
 }
+ADD_TO_DEVTABLE("ap", struct ap_device_id, do_ap_entry);
 
 /* looks like: "css:tN" */
 static int do_css_entry(const char *filename,
@@ -395,6 +430,7 @@ static int do_css_entry(const char *filename,
        sprintf(alias, "css:t%01X", id->type);
        return 1;
 }
+ADD_TO_DEVTABLE("css", struct css_device_id, do_css_entry);
 
 /* Looks like: "serio:tyNprNidNexN" */
 static int do_serio_entry(const char *filename,
@@ -414,6 +450,7 @@ static int do_serio_entry(const char *filename,
        add_wildcard(alias);
        return 1;
 }
+ADD_TO_DEVTABLE("serio", struct serio_device_id, do_serio_entry);
 
 /* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */
 static int do_acpi_entry(const char *filename,
@@ -422,6 +459,7 @@ static int do_acpi_entry(const char *filename,
        sprintf(alias, "acpi*:%s:*", id->id);
        return 1;
 }
+ADD_TO_DEVTABLE("acpi", struct acpi_device_id, do_acpi_entry);
 
 /* looks like: "pnp:dD" */
 static void do_pnp_device_entry(void *symval, unsigned long size,
@@ -544,8 +582,7 @@ static int do_pcmcia_entry(const char *filename,
        add_wildcard(alias);
        return 1;
 }
-
-
+ADD_TO_DEVTABLE("pcmcia", struct pcmcia_device_id, do_pcmcia_entry);
 
 static int do_of_entry (const char *filename, struct of_device_id *of, char *alias)
 {
@@ -568,6 +605,7 @@ static int do_of_entry (const char *filename, struct of_device_id *of, char *ali
     add_wildcard(alias);
     return 1;
 }
+ADD_TO_DEVTABLE("of", struct of_device_id, do_of_entry);
 
 static int do_vio_entry(const char *filename, struct vio_device_id *vio,
                char *alias)
@@ -585,6 +623,7 @@ static int do_vio_entry(const char *filename, struct vio_device_id *vio,
        add_wildcard(alias);
        return 1;
 }
+ADD_TO_DEVTABLE("vio", struct vio_device_id, do_vio_entry);
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
@@ -640,6 +679,7 @@ static int do_input_entry(const char *filename, struct input_device_id *id,
                do_input(alias, id->swbit, 0, INPUT_DEVICE_ID_SW_MAX);
        return 1;
 }
+ADD_TO_DEVTABLE("input", struct input_device_id, do_input_entry);
 
 static int do_eisa_entry(const char *filename, struct eisa_device_id *eisa,
                char *alias)
@@ -650,6 +690,7 @@ static int do_eisa_entry(const char *filename, struct eisa_device_id *eisa,
                strcat(alias, "*");
        return 1;
 }
+ADD_TO_DEVTABLE("eisa", struct eisa_device_id, do_eisa_entry);
 
 /* Looks like: parisc:tNhvNrevNsvN */
 static int do_parisc_entry(const char *filename, struct parisc_device_id *id,
@@ -669,6 +710,7 @@ static int do_parisc_entry(const char *filename, struct parisc_device_id *id,
        add_wildcard(alias);
        return 1;
 }
+ADD_TO_DEVTABLE("parisc", struct parisc_device_id, do_parisc_entry);
 
 /* Looks like: sdio:cNvNdN. */
 static int do_sdio_entry(const char *filename,
@@ -685,6 +727,7 @@ static int do_sdio_entry(const char *filename,
        add_wildcard(alias);
        return 1;
 }
+ADD_TO_DEVTABLE("sdio", struct sdio_device_id, do_sdio_entry);
 
 /* Looks like: ssb:vNidNrevN. */
 static int do_ssb_entry(const char *filename,
@@ -701,6 +744,7 @@ static int do_ssb_entry(const char *filename,
        add_wildcard(alias);
        return 1;
 }
+ADD_TO_DEVTABLE("ssb", struct ssb_device_id, do_ssb_entry);
 
 /* Looks like: bcma:mNidNrevNclN. */
 static int do_bcma_entry(const char *filename,
@@ -719,6 +763,7 @@ static int do_bcma_entry(const char *filename,
        add_wildcard(alias);
        return 1;
 }
+ADD_TO_DEVTABLE("bcma", struct bcma_device_id, do_bcma_entry);
 
 /* Looks like: virtio:dNvN */
 static int do_virtio_entry(const char *filename, struct virtio_device_id *id,
@@ -734,6 +779,7 @@ static int do_virtio_entry(const char *filename, struct virtio_device_id *id,
        add_wildcard(alias);
        return 1;
 }
+ADD_TO_DEVTABLE("virtio", struct virtio_device_id, do_virtio_entry);
 
 /*
  * Looks like: vmbus:guid
@@ -755,6 +801,7 @@ static int do_vmbus_entry(const char *filename, struct hv_vmbus_device_id *id,
 
        return 1;
 }
+ADD_TO_DEVTABLE("vmbus", struct hv_vmbus_device_id, do_vmbus_entry);
 
 /* Looks like: i2c:S */
 static int do_i2c_entry(const char *filename, struct i2c_device_id *id,
@@ -764,6 +811,7 @@ static int do_i2c_entry(const char *filename, struct i2c_device_id *id,
 
        return 1;
 }
+ADD_TO_DEVTABLE("i2c", struct i2c_device_id, do_i2c_entry);
 
 /* Looks like: spi:S */
 static int do_spi_entry(const char *filename, struct spi_device_id *id,
@@ -773,6 +821,17 @@ static int do_spi_entry(const char *filename, struct spi_device_id *id,
 
        return 1;
 }
+ADD_TO_DEVTABLE("spi", struct spi_device_id, do_spi_entry);
+
+/* Looks like: mcp:S */
+static int do_mcp_entry(const char *filename, struct mcp_device_id *id,
+                       char *alias)
+{
+       sprintf(alias, MCP_MODULE_PREFIX "%s", id->name);
+
+       return 1;
+}
+ADD_TO_DEVTABLE("mcp", struct mcp_device_id, do_mcp_entry); 
 
 static const struct dmifield {
        const char *prefix;
@@ -827,6 +886,7 @@ static int do_dmi_entry(const char *filename, struct dmi_system_id *id,
        strcat(alias, ":");
        return 1;
 }
+ADD_TO_DEVTABLE("dmi", struct dmi_system_id, do_dmi_entry);
 
 static int do_platform_entry(const char *filename,
                             struct platform_device_id *id, char *alias)
@@ -834,6 +894,7 @@ static int do_platform_entry(const char *filename,
        sprintf(alias, PLATFORM_MODULE_PREFIX "%s", id->name);
        return 1;
 }
+ADD_TO_DEVTABLE("platform", struct platform_device_id, do_platform_entry);
 
 static int do_mdio_entry(const char *filename,
                         struct mdio_device_id *id, char *alias)
@@ -856,6 +917,7 @@ static int do_mdio_entry(const char *filename,
 
        return 1;
 }
+ADD_TO_DEVTABLE("mdio", struct mdio_device_id, do_mdio_entry);
 
 /* Looks like: zorro:iN. */
 static int do_zorro_entry(const char *filename, struct zorro_device_id *id,
@@ -866,6 +928,7 @@ static int do_zorro_entry(const char *filename, struct zorro_device_id *id,
        ADD(alias, "i", id->id != ZORRO_WILDCARD, id->id);
        return 1;
 }
+ADD_TO_DEVTABLE("zorro", struct zorro_device_id, do_zorro_entry);
 
 /* looks like: "pnp:dD" */
 static int do_isapnp_entry(const char *filename,
@@ -879,6 +942,7 @@ static int do_isapnp_entry(const char *filename,
                (id->function >> 12) & 0x0f, (id->function >> 8) & 0x0f);
        return 1;
 }
+ADD_TO_DEVTABLE("isa", struct isapnp_device_id, do_isapnp_entry);
 
 /*
  * Append a match expression for a single masked hex digit.
@@ -947,16 +1011,15 @@ static int do_amba_entry(const char *filename,
 
        return 1;
 }
+ADD_TO_DEVTABLE("amba", struct amba_id, do_amba_entry);
 
-/* Ignore any prefix, eg. some architectures prepend _ */
-static inline int sym_is(const char *symbol, const char *name)
+/* Does namelen bytes of name exactly match the symbol? */
+static bool sym_is(const char *name, unsigned namelen, const char *symbol)
 {
-       const char *match;
+       if (namelen != strlen(symbol))
+               return false;
 
-       match = strstr(symbol, name);
-       if (!match)
-               return 0;
-       return match[strlen(name)] == '\0';
+       return memcmp(name, symbol, namelen) == 0;
 }
 
 static void do_table(void *symval, unsigned long size,
@@ -989,11 +1052,25 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
 {
        void *symval;
        char *zeros = NULL;
+       const char *name;
+       unsigned int namelen;
 
        /* We're looking for a section relative symbol */
        if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections)
                return;
 
+       /* All our symbols are of form <prefix>__mod_XXX_device_table. */
+       name = strstr(symname, "__mod_");
+       if (!name)
+               return;
+       name += strlen("__mod_");
+       namelen = strlen(name);
+       if (namelen < strlen("_device_table"))
+               return;
+       if (strcmp(name + namelen - strlen("_device_table"), "_device_table"))
+               return;
+       namelen -= strlen("_device_table");
+
        /* Handle all-NULL symbols allocated into .bss */
        if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) {
                zeros = calloc(1, sym->st_size);
@@ -1004,121 +1081,24 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                        + sym->st_value;
        }
 
-       if (sym_is(symname, "__mod_pci_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct pci_device_id), "pci",
-                        do_pci_entry, mod);
-       else if (sym_is(symname, "__mod_usb_device_table"))
-               /* special case to handle bcdDevice ranges */
+       /* First handle the "special" cases */
+       if (sym_is(name, namelen, "usb"))
                do_usb_table(symval, sym->st_size, mod);
-       else if (sym_is(symname, "__mod_hid_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct hid_device_id), "hid",
-                        do_hid_entry, mod);
-       else if (sym_is(symname, "__mod_ieee1394_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct ieee1394_device_id), "ieee1394",
-                        do_ieee1394_entry, mod);
-       else if (sym_is(symname, "__mod_ccw_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct ccw_device_id), "ccw",
-                        do_ccw_entry, mod);
-       else if (sym_is(symname, "__mod_ap_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct ap_device_id), "ap",
-                        do_ap_entry, mod);
-       else if (sym_is(symname, "__mod_css_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct css_device_id), "css",
-                        do_css_entry, mod);
-       else if (sym_is(symname, "__mod_serio_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct serio_device_id), "serio",
-                        do_serio_entry, mod);
-       else if (sym_is(symname, "__mod_acpi_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct acpi_device_id), "acpi",
-                        do_acpi_entry, mod);
-       else if (sym_is(symname, "__mod_pnp_device_table"))
+       else if (sym_is(name, namelen, "pnp"))
                do_pnp_device_entry(symval, sym->st_size, mod);
-       else if (sym_is(symname, "__mod_pnp_card_device_table"))
+       else if (sym_is(name, namelen, "pnp_card"))
                do_pnp_card_entries(symval, sym->st_size, mod);
-       else if (sym_is(symname, "__mod_pcmcia_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct pcmcia_device_id), "pcmcia",
-                        do_pcmcia_entry, mod);
-        else if (sym_is(symname, "__mod_of_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct of_device_id), "of",
-                        do_of_entry, mod);
-        else if (sym_is(symname, "__mod_vio_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct vio_device_id), "vio",
-                        do_vio_entry, mod);
-       else if (sym_is(symname, "__mod_input_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct input_device_id), "input",
-                        do_input_entry, mod);
-       else if (sym_is(symname, "__mod_eisa_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct eisa_device_id), "eisa",
-                        do_eisa_entry, mod);
-       else if (sym_is(symname, "__mod_parisc_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct parisc_device_id), "parisc",
-                        do_parisc_entry, mod);
-       else if (sym_is(symname, "__mod_sdio_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct sdio_device_id), "sdio",
-                        do_sdio_entry, mod);
-       else if (sym_is(symname, "__mod_ssb_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct ssb_device_id), "ssb",
-                        do_ssb_entry, mod);
-       else if (sym_is(symname, "__mod_bcma_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct bcma_device_id), "bcma",
-                        do_bcma_entry, mod);
-       else if (sym_is(symname, "__mod_virtio_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct virtio_device_id), "virtio",
-                        do_virtio_entry, mod);
-       else if (sym_is(symname, "__mod_vmbus_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct hv_vmbus_device_id), "vmbus",
-                        do_vmbus_entry, mod);
-       else if (sym_is(symname, "__mod_i2c_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct i2c_device_id), "i2c",
-                        do_i2c_entry, mod);
-       else if (sym_is(symname, "__mod_spi_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct spi_device_id), "spi",
-                        do_spi_entry, mod);
-       else if (sym_is(symname, "__mod_dmi_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct dmi_system_id), "dmi",
-                        do_dmi_entry, mod);
-       else if (sym_is(symname, "__mod_platform_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct platform_device_id), "platform",
-                        do_platform_entry, mod);
-       else if (sym_is(symname, "__mod_mdio_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct mdio_device_id), "mdio",
-                        do_mdio_entry, mod);
-       else if (sym_is(symname, "__mod_zorro_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct zorro_device_id), "zorro",
-                        do_zorro_entry, mod);
-       else if (sym_is(symname, "__mod_isapnp_device_table"))
-               do_table(symval, sym->st_size,
-                       sizeof(struct isapnp_device_id), "isa",
-                       do_isapnp_entry, mod);
-       else if (sym_is(symname, "__mod_amba_device_table"))
-               do_table(symval, sym->st_size,
-                       sizeof(struct amba_id), "amba",
-                       do_amba_entry, mod);
+       else {
+               struct devtable **p;
+
+               for (p = __start___devtable; p < __stop___devtable; p++) {
+                       if (sym_is(name, namelen, (*p)->device_id)) {
+                               do_table(symval, sym->st_size, (*p)->id_size,
+                                        (*p)->device_id, (*p)->function, mod);
+                               break;
+                       }
+               }
+       }
        free(zeros);
 }
 
index f40a6af6bf40068f2a074bf6bff86d68b2a05440..54e35c1e5948c521f9fdebf57c27072b6d844f34 100644 (file)
@@ -462,7 +462,7 @@ __has_rel_mcount(Elf_Shdr const *const relhdr,  /* is SHT_REL or SHT_RELA */
                succeed_file();
        }
        if (w(txthdr->sh_type) != SHT_PROGBITS ||
-           !(w(txthdr->sh_flags) & SHF_EXECINSTR))
+           !(_w(txthdr->sh_flags) & SHF_EXECINSTR))
                return NULL;
        return txtname;
 }
index 38f6617a2cb16c614a2ed0a854eb97b7aa12cdbb..833813a99e7c23a29c4e7147c58ac0ca2c696400 100755 (executable)
@@ -132,7 +132,28 @@ exuberant()
        --regex-asm='/^(ENTRY|_GLOBAL)\(([^)]*)\).*/\2/'        \
        --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \
        --regex-c++='/^TRACE_EVENT\(([^,)]*).*/trace_\1/'               \
-       --regex-c++='/^DEFINE_EVENT\([^,)]*, *([^,)]*).*/trace_\1/'
+       --regex-c++='/^DEFINE_EVENT\([^,)]*, *([^,)]*).*/trace_\1/'     \
+       --regex-c++='/PAGEFLAG\(([^,)]*).*/Page\1/'                     \
+       --regex-c++='/PAGEFLAG\(([^,)]*).*/SetPage\1/'                  \
+       --regex-c++='/PAGEFLAG\(([^,)]*).*/ClearPage\1/'                \
+       --regex-c++='/TESTSETFLAG\(([^,)]*).*/TestSetPage\1/'           \
+       --regex-c++='/TESTPAGEFLAG\(([^,)]*).*/Page\1/'                 \
+       --regex-c++='/SETPAGEFLAG\(([^,)]*).*/SetPage\1/'               \
+       --regex-c++='/__SETPAGEFLAG\(([^,)]*).*/__SetPage\1/'           \
+       --regex-c++='/TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/'       \
+       --regex-c++='/__TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/'     \
+       --regex-c++='/CLEARPAGEFLAG\(([^,)]*).*/ClearPage\1/'           \
+       --regex-c++='/__CLEARPAGEFLAG\(([^,)]*).*/__ClearPage\1/'       \
+       --regex-c++='/__PAGEFLAG\(([^,)]*).*/__SetPage\1/'              \
+       --regex-c++='/__PAGEFLAG\(([^,)]*).*/__ClearPage\1/'            \
+       --regex-c++='/PAGEFLAG_FALSE\(([^,)]*).*/Page\1/'               \
+       --regex-c++='/TESTSCFLAG\(([^,)]*).*/TestSetPage\1/'            \
+       --regex-c++='/TESTSCFLAG\(([^,)]*).*/TestClearPage\1/'          \
+       --regex-c++='/SETPAGEFLAG_NOOP\(([^,)]*).*/SetPage\1/'          \
+       --regex-c++='/CLEARPAGEFLAG_NOOP\(([^,)]*).*/ClearPage\1/'      \
+       --regex-c++='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/'  \
+       --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \
+       --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/'
 
        all_kconfigs | xargs $1 -a                              \
        --langdef=kconfig --language-force=kconfig              \
@@ -146,6 +167,8 @@ exuberant()
        --langdef=dotconfig --language-force=dotconfig          \
        --regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/'
 
+       # Remove structure forward declarations.
+       LANG=C sed -i -e '/^\([a-zA-Z_][a-zA-Z0-9_]*\)\t.*\t\/\^struct \1;.*\$\/;"\tx$/d' tags
 }
 
 emacs()
@@ -154,7 +177,28 @@ emacs()
        --regex='/^(ENTRY|_GLOBAL)(\([^)]*\)).*/\2/'            \
        --regex='/^SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/sys_\1/'   \
        --regex='/^TRACE_EVENT(\([^,)]*\).*/trace_\1/'          \
-       --regex='/^DEFINE_EVENT([^,)]*, *\([^,)]*\).*/trace_\1/'
+       --regex='/^DEFINE_EVENT([^,)]*, *\([^,)]*\).*/trace_\1/' \
+       --regex='/PAGEFLAG\(([^,)]*).*/Page\1/'                 \
+       --regex='/PAGEFLAG\(([^,)]*).*/SetPage\1/'              \
+       --regex='/PAGEFLAG\(([^,)]*).*/ClearPage\1/'            \
+       --regex='/TESTSETFLAG\(([^,)]*).*/TestSetPage\1/'       \
+       --regex='/TESTPAGEFLAG\(([^,)]*).*/Page\1/'             \
+       --regex='/SETPAGEFLAG\(([^,)]*).*/SetPage\1/'           \
+       --regex='/__SETPAGEFLAG\(([^,)]*).*/__SetPage\1/'       \
+       --regex='/TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/'   \
+       --regex='/__TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/' \
+       --regex='/CLEARPAGEFLAG\(([^,)]*).*/ClearPage\1/'       \
+       --regex='/__CLEARPAGEFLAG\(([^,)]*).*/__ClearPage\1/'   \
+       --regex='/__PAGEFLAG\(([^,)]*).*/__SetPage\1/'          \
+       --regex='/__PAGEFLAG\(([^,)]*).*/__ClearPage\1/'        \
+       --regex='/PAGEFLAG_FALSE\(([^,)]*).*/Page\1/'           \
+       --regex='/TESTSCFLAG\(([^,)]*).*/TestSetPage\1/'        \
+       --regex='/TESTSCFLAG\(([^,)]*).*/TestClearPage\1/'      \
+       --regex='/SETPAGEFLAG_NOOP\(([^,)]*).*/SetPage\1/'      \
+       --regex='/CLEARPAGEFLAG_NOOP\(([^,)]*).*/ClearPage\1/'  \
+       --regex='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \
+       --regex='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \
+       --regex='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/'
 
        all_kconfigs | xargs $1 -a                              \
        --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/'
index 38ccaea08204deb64c5f2404e43e0c722826a76a..df364956081867b5d309480788b058db6e6516b3 100644 (file)
 
 /* Control parameters settable through module/boot flags */
 extern enum audit_mode aa_g_audit;
-extern int aa_g_audit_header;
-extern int aa_g_debug;
-extern int aa_g_lock_policy;
-extern int aa_g_logsyscall;
-extern int aa_g_paranoid_load;
+extern bool aa_g_audit_header;
+extern bool aa_g_debug;
+extern bool aa_g_lock_policy;
+extern bool aa_g_logsyscall;
+extern bool aa_g_paranoid_load;
 extern unsigned int aa_g_path_max;
 
 /*
index d7f06f8b283721df6f450bff880aa6d87a40bb50..97ce8fae49b3bd063a78fd5d9a6cc3eb80254cf1 100644 (file)
@@ -136,16 +136,16 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
        return 0;
 }
 
-static int apparmor_capable(struct task_struct *task, const struct cred *cred,
-                           struct user_namespace *ns, int cap, int audit)
+static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
+                           int cap, int audit)
 {
        struct aa_profile *profile;
        /* cap_capable returns 0 on success, else -EPERM */
-       int error = cap_capable(task, cred, ns, cap, audit);
+       int error = cap_capable(cred, ns, cap, audit);
        if (!error) {
                profile = aa_cred_profile(cred);
                if (!unconfined(profile))
-                       error = aa_capable(task, profile, cap, audit);
+                       error = aa_capable(current, profile, cap, audit);
        }
        return error;
 }
@@ -708,7 +708,7 @@ module_param_call(mode, param_set_mode, param_get_mode,
                  &aa_g_profile_mode, S_IRUSR | S_IWUSR);
 
 /* Debug mode */
-int aa_g_debug;
+bool aa_g_debug;
 module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR);
 
 /* Audit mode */
@@ -719,7 +719,7 @@ module_param_call(audit, param_set_audit, param_get_audit,
 /* Determines if audit header is included in audited messages.  This
  * provides more context if the audit daemon is not running
  */
-int aa_g_audit_header = 1;
+bool aa_g_audit_header = 1;
 module_param_named(audit_header, aa_g_audit_header, aabool,
                   S_IRUSR | S_IWUSR);
 
@@ -727,12 +727,12 @@ module_param_named(audit_header, aa_g_audit_header, aabool,
  * TODO: add in at boot loading of policy, which is the only way to
  *       load policy, if lock_policy is set
  */
-int aa_g_lock_policy;
+bool aa_g_lock_policy;
 module_param_named(lock_policy, aa_g_lock_policy, aalockpolicy,
                   S_IRUSR | S_IWUSR);
 
 /* Syscall logging mode */
-int aa_g_logsyscall;
+bool aa_g_logsyscall;
 module_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR);
 
 /* Maximum pathname length before accesses will start getting rejected */
@@ -742,12 +742,12 @@ module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR | S_IWUSR);
 /* Determines how paranoid loading of policy is and how much verification
  * on the loaded policy is done.
  */
-int aa_g_paranoid_load = 1;
+bool aa_g_paranoid_load = 1;
 module_param_named(paranoid_load, aa_g_paranoid_load, aabool,
                   S_IRUSR | S_IWUSR);
 
 /* Boot time disable flag */
-static unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
+static bool apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
 module_param_named(enabled, apparmor_enabled, aabool, S_IRUSR);
 
 static int __init apparmor_enabled_setup(char *str)
index 3b5883b7179f4ca3c848c912f692a5e9bc50dc2b..2f680eb02b59e3f08a437f97d963eac100b3b3ea 100644 (file)
@@ -998,7 +998,6 @@ void __init security_fixup_ops(struct security_operations *ops)
        set_to_cap_if_null(ops, sem_semctl);
        set_to_cap_if_null(ops, sem_semop);
        set_to_cap_if_null(ops, netlink_send);
-       set_to_cap_if_null(ops, netlink_recv);
        set_to_cap_if_null(ops, d_instantiate);
        set_to_cap_if_null(ops, getprocattr);
        set_to_cap_if_null(ops, setprocattr);
index ee4f8486e5f563dff63c13278a1258e43e2b7859..7ce191ea29a0c22cb1eb1549a8358e12bed3e5bb 100644 (file)
@@ -56,17 +56,8 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
        return 0;
 }
 
-int cap_netlink_recv(struct sk_buff *skb, int cap)
-{
-       if (!cap_raised(current_cap(), cap))
-               return -EPERM;
-       return 0;
-}
-EXPORT_SYMBOL(cap_netlink_recv);
-
 /**
  * cap_capable - Determine whether a task has a particular effective capability
- * @tsk: The task to query
  * @cred: The credentials to use
  * @ns:  The user namespace in which we need the capability
  * @cap: The capability to check for
@@ -80,8 +71,8 @@ EXPORT_SYMBOL(cap_netlink_recv);
  * cap_has_capability() returns 0 when a task has a capability, but the
  * kernel's capable() and has_capability() returns 1 for this case.
  */
-int cap_capable(struct task_struct *tsk, const struct cred *cred,
-               struct user_namespace *targ_ns, int cap, int audit)
+int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
+               int cap, int audit)
 {
        for (;;) {
                /* The creator of the user namespace has all caps. */
@@ -222,9 +213,8 @@ static inline int cap_inh_is_capped(void)
        /* they are so limited unless the current task has the CAP_SETPCAP
         * capability
         */
-       if (cap_capable(current, current_cred(),
-                       current_cred()->user->user_ns, CAP_SETPCAP,
-                       SECURITY_CAP_AUDIT) == 0)
+       if (cap_capable(current_cred(), current_cred()->user->user_ns,
+                       CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
                return 0;
        return 1;
 }
@@ -874,7 +864,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
                     & (new->securebits ^ arg2))                        /*[1]*/
                    || ((new->securebits & SECURE_ALL_LOCKS & ~arg2))   /*[2]*/
                    || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS))   /*[3]*/
-                   || (cap_capable(current, current_cred(),
+                   || (cap_capable(current_cred(),
                                    current_cred()->user->user_ns, CAP_SETPCAP,
                                    SECURITY_CAP_AUDIT) != 0)           /*[4]*/
                        /*
@@ -940,7 +930,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
 {
        int cap_sys_admin = 0;
 
-       if (cap_capable(current, current_cred(), &init_user_ns, CAP_SYS_ADMIN,
+       if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
                        SECURITY_CAP_NOAUDIT) == 0)
                cap_sys_admin = 1;
        return __vm_enough_memory(mm, pages, cap_sys_admin);
@@ -967,7 +957,7 @@ int cap_file_mmap(struct file *file, unsigned long reqprot,
        int ret = 0;
 
        if (addr < dac_mmap_min_addr) {
-               ret = cap_capable(current, current_cred(), &init_user_ns, CAP_SYS_RAWIO,
+               ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO,
                                  SECURITY_CAP_AUDIT);
                /* set PF_SUPERPRIV if it turns out we allow the low mmap */
                if (ret == 0)
index d384ea921482088dea0c7c13f54e2d3c57c18f26..5bd1cc1b4a54dcae8681bf7e0c092d374614ab6d 100644 (file)
@@ -3,11 +3,11 @@ config INTEGRITY
        def_bool y
        depends on IMA || EVM
 
-config INTEGRITY_DIGSIG
+config INTEGRITY_SIGNATURE
        boolean "Digital signature verification using multiple keyrings"
        depends on INTEGRITY && KEYS
        default n
-       select DIGSIG
+       select SIGNATURE
        help
          This option enables digital signature verification support
          using multiple keyrings. It defines separate keyrings for each
index bece0563ee5e019bc9fa56bd2dff4e426cf262b7..d43799cc14f69a67da22249d637b5f9d1334b357 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 obj-$(CONFIG_INTEGRITY) += integrity.o
-obj-$(CONFIG_INTEGRITY_DIGSIG) += digsig.o
+obj-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
 
 integrity-y := iint.o
 
index c5c5a72c30be30b0477446cd311e8f329cb7dd30..2ad942fb1e236e694eb50538ac71a33a90e8d40a 100644 (file)
@@ -56,9 +56,11 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
                audit_log_format(ab, " name=");
                audit_log_untrustedstring(ab, fname);
        }
-       if (inode)
-               audit_log_format(ab, " dev=%s ino=%lu",
-                                inode->i_sb->s_id, inode->i_ino);
+       if (inode) {
+               audit_log_format(ab, " dev=");
+               audit_log_untrustedstring(ab, inode->i_sb->s_id);
+               audit_log_format(ab, " ino=%lu", inode->i_ino);
+       }
        audit_log_format(ab, " res=%d", !result ? 0 : 1);
        audit_log_end(ab);
 }
index d661afbe474c2fce8f74907869be0a644c5789c9..d45061d02feec0d8b3e55f356d81df41580ad506 100644 (file)
@@ -99,6 +99,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule,
                            struct inode *inode, enum ima_hooks func, int mask)
 {
        struct task_struct *tsk = current;
+       const struct cred *cred = current_cred();
        int i;
 
        if ((rule->flags & IMA_FUNC) && rule->func != func)
@@ -108,7 +109,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule,
        if ((rule->flags & IMA_FSMAGIC)
            && rule->fsmagic != inode->i_sb->s_magic)
                return false;
-       if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid)
+       if ((rule->flags & IMA_UID) && rule->uid != cred->uid)
                return false;
        for (i = 0; i < MAX_LSM_RULES; i++) {
                int rc = 0;
index 4da6ba81d1532aa4690cc95b99ba682ddb0254b1..7a25ecec5aaac6b8d00c2bf0f926deaeea561163 100644 (file)
@@ -51,7 +51,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 #define INTEGRITY_KEYRING_IMA          2
 #define INTEGRITY_KEYRING_MAX          3
 
-#ifdef CONFIG_INTEGRITY_DIGSIG
+#ifdef CONFIG_INTEGRITY_SIGNATURE
 
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
                                        const char *digest, int digestlen);
@@ -65,7 +65,7 @@ static inline int integrity_digsig_verify(const unsigned int id,
        return -EOPNOTSUPP;
 }
 
-#endif /* CONFIG_INTEGRITY_DIGSIG */
+#endif /* CONFIG_INTEGRITY_SIGNATURE */
 
 /* set during initialization */
 extern int iint_initialized;
index 41144f71d6154f612570f8f2c5243269becf68a4..2d1bb8af7696d5d431394cfbe8ac6d5e40f24da2 100644 (file)
@@ -314,7 +314,7 @@ static struct key *request_user_key(const char *master_desc, u8 **master_key,
                goto error;
 
        down_read(&ukey->sem);
-       upayload = rcu_dereference(ukey->payload.data);
+       upayload = ukey->payload.data;
        *master_key = upayload->data;
        *master_keylen = upayload->datalen;
 error:
@@ -810,7 +810,7 @@ static int encrypted_instantiate(struct key *key, const void *data,
                goto out;
        }
 
-       rcu_assign_pointer(key->payload.data, epayload);
+       rcu_assign_keypointer(key, epayload);
 out:
        kfree(datablob);
        return ret;
@@ -874,7 +874,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen)
        memcpy(new_epayload->payload_data, epayload->payload_data,
               epayload->payload_datalen);
 
-       rcu_assign_pointer(key->payload.data, new_epayload);
+       rcu_assign_keypointer(key, new_epayload);
        call_rcu(&epayload->rcu, encrypted_rcu_free);
 out:
        kfree(buf);
index df87272e3f519ca6909e9f9e4ab8132554ae9abb..013f7e5d3a2fce42d026fd87a4a0d6e94af1d53f 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/module.h>
 #include <linux/err.h>
 #include <keys/trusted-type.h>
+#include <keys/encrypted-type.h>
+#include "encrypted.h"
 
 /*
  * request_trusted_key - request the trusted key
@@ -37,7 +39,7 @@ struct key *request_trusted_key(const char *trusted_desc,
                goto error;
 
        down_read(&tkey->sem);
-       tpayload = rcu_dereference(tkey->payload.data);
+       tpayload = tkey->payload.data;
        *master_key = tpayload->key;
        *master_keylen = tpayload->key_len;
 error:
index bf4d8da5a79502f626a849473e4af18e229eb074..a42b45531aac173a337498cfc26fd09ded18baee 100644 (file)
@@ -145,7 +145,9 @@ static void key_gc_keyring(struct key *keyring, time_t limit)
        if (!klist)
                goto unlock_dont_gc;
 
-       for (loop = klist->nkeys - 1; loop >= 0; loop--) {
+       loop = klist->nkeys;
+       smp_rmb();
+       for (loop--; loop >= 0; loop--) {
                key = klist->keys[loop];
                if (test_bit(KEY_FLAG_DEAD, &key->flags) ||
                    (key->expiry > 0 && key->expiry <= limit))
index 37a7f3b28852e098f57ab1cd98eb2eccdad5c7c5..d605f75292e4390da5d7f8cd763266004288ecf2 100644 (file)
@@ -319,7 +319,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
        struct key *keyring, *key;
        key_ref_t key_ref;
        long err;
-       int sp, kix;
+       int sp, nkeys, kix;
 
        keyring = key_ref_to_ptr(keyring_ref);
        possessed = is_key_possessed(keyring_ref);
@@ -380,7 +380,9 @@ descend:
                goto not_this_keyring;
 
        /* iterate through the keys in this keyring first */
-       for (kix = 0; kix < keylist->nkeys; kix++) {
+       nkeys = keylist->nkeys;
+       smp_rmb();
+       for (kix = 0; kix < nkeys; kix++) {
                key = keylist->keys[kix];
                kflags = key->flags;
 
@@ -421,7 +423,9 @@ descend:
        /* search through the keyrings nested in this one */
        kix = 0;
 ascend:
-       for (; kix < keylist->nkeys; kix++) {
+       nkeys = keylist->nkeys;
+       smp_rmb();
+       for (; kix < nkeys; kix++) {
                key = keylist->keys[kix];
                if (key->type != &key_type_keyring)
                        continue;
@@ -515,7 +519,7 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref,
        struct keyring_list *klist;
        unsigned long possessed;
        struct key *keyring, *key;
-       int loop;
+       int nkeys, loop;
 
        keyring = key_ref_to_ptr(keyring_ref);
        possessed = is_key_possessed(keyring_ref);
@@ -524,7 +528,9 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref,
 
        klist = rcu_dereference(keyring->payload.subscriptions);
        if (klist) {
-               for (loop = 0; loop < klist->nkeys; loop++) {
+               nkeys = klist->nkeys;
+               smp_rmb();
+               for (loop = 0; loop < nkeys ; loop++) {
                        key = klist->keys[loop];
 
                        if (key->type == ktype &&
@@ -622,7 +628,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
 
        struct keyring_list *keylist;
        struct key *subtree, *key;
-       int sp, kix, ret;
+       int sp, nkeys, kix, ret;
 
        rcu_read_lock();
 
@@ -645,7 +651,9 @@ descend:
 
 ascend:
        /* iterate through the remaining keys in this keyring */
-       for (; kix < keylist->nkeys; kix++) {
+       nkeys = keylist->nkeys;
+       smp_rmb();
+       for (; kix < nkeys; kix++) {
                key = keylist->keys[kix];
 
                if (key == A)
index 0ed5fdf238a22c6712e5375207f5bd6d8a168ef6..2d5d041f2049f323e5072c701f068d695f3f2c6c 100644 (file)
@@ -993,7 +993,7 @@ out:
        kfree(datablob);
        kfree(options);
        if (!ret)
-               rcu_assign_pointer(key->payload.data, payload);
+               rcu_assign_keypointer(key, payload);
        else
                kfree(payload);
        return ret;
@@ -1067,7 +1067,7 @@ static int trusted_update(struct key *key, const void *data, size_t datalen)
                        goto out;
                }
        }
-       rcu_assign_pointer(key->payload.data, new_p);
+       rcu_assign_keypointer(key, new_p);
        call_rcu(&p->rcu, trusted_rcu_free);
 out:
        kfree(datablob);
index 6e1a6276649fdbd12289221decdd6ce83d11fb1f..c7660a25a3e4502673714b39553a0d9d00873672 100644 (file)
@@ -79,7 +79,7 @@ int user_instantiate(struct key *key, const void *data, size_t datalen)
        /* attach the data */
        upayload->datalen = datalen;
        memcpy(upayload->data, data, datalen);
-       rcu_assign_pointer(key->payload.data, upayload);
+       rcu_assign_keypointer(key, upayload);
        ret = 0;
 
 error:
@@ -118,7 +118,7 @@ int user_update(struct key *key, const void *data, size_t datalen)
        if (ret == 0) {
                /* attach the new data, displacing the old */
                zap = key->payload.data;
-               rcu_assign_pointer(key->payload.data, upayload);
+               rcu_assign_keypointer(key, upayload);
                key->expiry = 0;
        }
 
@@ -153,7 +153,7 @@ void user_revoke(struct key *key)
        key_payload_reserve(key, 0);
 
        if (upayload) {
-               rcu_assign_pointer(key->payload.data, NULL);
+               rcu_assign_keypointer(key, NULL);
                kfree_rcu(upayload, rcu);
        }
 }
index 7bd6f138236b3a010d457ab473ea73fd02641c8c..293b8c45b1d1bbf9a28edff35001b8c02eb09191 100644 (file)
@@ -232,13 +232,14 @@ static void dump_common_audit_data(struct audit_buffer *ab,
        case LSM_AUDIT_DATA_PATH: {
                struct inode *inode;
 
-               audit_log_d_path(ab, "path=", &a->u.path);
+               audit_log_d_path(ab, " path=", &a->u.path);
 
                inode = a->u.path.dentry->d_inode;
-               if (inode)
-                       audit_log_format(ab, " dev=%s ino=%lu",
-                                       inode->i_sb->s_id,
-                                       inode->i_ino);
+               if (inode) {
+                       audit_log_format(ab, " dev=");
+                       audit_log_untrustedstring(ab, inode->i_sb->s_id);
+                       audit_log_format(ab, " ino=%lu", inode->i_ino);
+               }
                break;
        }
        case LSM_AUDIT_DATA_DENTRY: {
@@ -248,10 +249,11 @@ static void dump_common_audit_data(struct audit_buffer *ab,
                audit_log_untrustedstring(ab, a->u.dentry->d_name.name);
 
                inode = a->u.dentry->d_inode;
-               if (inode)
-                       audit_log_format(ab, " dev=%s ino=%lu",
-                                       inode->i_sb->s_id,
-                                       inode->i_ino);
+               if (inode) {
+                       audit_log_format(ab, " dev=");
+                       audit_log_untrustedstring(ab, inode->i_sb->s_id);
+                       audit_log_format(ab, " ino=%lu", inode->i_ino);
+               }
                break;
        }
        case LSM_AUDIT_DATA_INODE: {
@@ -266,8 +268,9 @@ static void dump_common_audit_data(struct audit_buffer *ab,
                                         dentry->d_name.name);
                        dput(dentry);
                }
-               audit_log_format(ab, " dev=%s ino=%lu", inode->i_sb->s_id,
-                                inode->i_ino);
+               audit_log_format(ab, " dev=");
+               audit_log_untrustedstring(ab, inode->i_sb->s_id);
+               audit_log_format(ab, " ino=%lu", inode->i_ino);
                break;
        }
        case LSM_AUDIT_DATA_TASK:
@@ -315,7 +318,7 @@ static void dump_common_audit_data(struct audit_buffer *ab,
                                                .dentry = u->dentry,
                                                .mnt = u->mnt
                                        };
-                                       audit_log_d_path(ab, "path=", &path);
+                                       audit_log_d_path(ab, " path=", &path);
                                        break;
                                }
                                if (!u->addr)
index 214502c772ab50823f512afade652fea24a6c0af..d7542493454d457ac15118bbd3e126e8b104043f 100644 (file)
@@ -155,35 +155,16 @@ int security_capset(struct cred *new, const struct cred *old,
                                    effective, inheritable, permitted);
 }
 
-int security_capable(struct user_namespace *ns, const struct cred *cred,
+int security_capable(const struct cred *cred, struct user_namespace *ns,
                     int cap)
 {
-       return security_ops->capable(current, cred, ns, cap,
-                                    SECURITY_CAP_AUDIT);
+       return security_ops->capable(cred, ns, cap, SECURITY_CAP_AUDIT);
 }
 
-int security_real_capable(struct task_struct *tsk, struct user_namespace *ns,
-                         int cap)
+int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns,
+                            int cap)
 {
-       const struct cred *cred;
-       int ret;
-
-       cred = get_task_cred(tsk);
-       ret = security_ops->capable(tsk, cred, ns, cap, SECURITY_CAP_AUDIT);
-       put_cred(cred);
-       return ret;
-}
-
-int security_real_capable_noaudit(struct task_struct *tsk,
-                                 struct user_namespace *ns, int cap)
-{
-       const struct cred *cred;
-       int ret;
-
-       cred = get_task_cred(tsk);
-       ret = security_ops->capable(tsk, cred, ns, cap, SECURITY_CAP_NOAUDIT);
-       put_cred(cred);
-       return ret;
+       return security_ops->capable(cred, ns, cap, SECURITY_CAP_NOAUDIT);
 }
 
 int security_quotactl(int cmds, int type, int id, struct super_block *sb)
@@ -994,12 +975,6 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb)
        return security_ops->netlink_send(sk, skb);
 }
 
-int security_netlink_recv(struct sk_buff *skb, int cap)
-{
-       return security_ops->netlink_recv(skb, cap);
-}
-EXPORT_SYMBOL(security_netlink_recv);
-
 int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 {
        return security_ops->secid_to_secctx(secid, secdata, seclen);
index 7cd4c3affac87b236f14fe1b7a570345d7fc38f0..6a3683e28426b132d5890398609710bca7397310 100644 (file)
@@ -1415,8 +1415,7 @@ static int current_has_perm(const struct task_struct *tsk,
 #endif
 
 /* Check whether a task is allowed to use a capability. */
-static int task_has_capability(struct task_struct *tsk,
-                              const struct cred *cred,
+static int cred_has_capability(const struct cred *cred,
                               int cap, int audit)
 {
        struct common_audit_data ad;
@@ -1427,7 +1426,7 @@ static int task_has_capability(struct task_struct *tsk,
        int rc;
 
        COMMON_AUDIT_DATA_INIT(&ad, CAP);
-       ad.tsk = tsk;
+       ad.tsk = current;
        ad.u.cap = cap;
 
        switch (CAP_TO_INDEX(cap)) {
@@ -1811,7 +1810,7 @@ static int selinux_ptrace_access_check(struct task_struct *child,
        if (rc)
                return rc;
 
-       if (mode == PTRACE_MODE_READ) {
+       if (mode & PTRACE_MODE_READ) {
                u32 sid = current_sid();
                u32 csid = task_sid(child);
                return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
@@ -1868,16 +1867,16 @@ static int selinux_capset(struct cred *new, const struct cred *old,
  * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
  */
 
-static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
-                          struct user_namespace *ns, int cap, int audit)
+static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
+                          int cap, int audit)
 {
        int rc;
 
-       rc = cap_capable(tsk, cred, ns, cap, audit);
+       rc = cap_capable(cred, ns, cap, audit);
        if (rc)
                return rc;
 
-       return task_has_capability(tsk, cred, cap, audit);
+       return cred_has_capability(cred, cap, audit);
 }
 
 static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
@@ -1954,8 +1953,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
 {
        int rc, cap_sys_admin = 0;
 
-       rc = selinux_capable(current, current_cred(),
-                            &init_user_ns, CAP_SYS_ADMIN,
+       rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
                             SECURITY_CAP_NOAUDIT);
        if (rc == 0)
                cap_sys_admin = 1;
@@ -2859,8 +2857,7 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
         * and lack of permission just means that we fall back to the
         * in-core context value, not a denial.
         */
-       error = selinux_capable(current, current_cred(),
-                               &init_user_ns, CAP_MAC_ADMIN,
+       error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN,
                                SECURITY_CAP_NOAUDIT);
        if (!error)
                error = security_sid_to_context_force(isec->sid, &context,
@@ -2993,8 +2990,8 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
 
        case KDSKBENT:
        case KDSKBSENT:
-               error = task_has_capability(current, cred, CAP_SYS_TTY_CONFIG,
-                                       SECURITY_CAP_AUDIT);
+               error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
+                                           SECURITY_CAP_AUDIT);
                break;
 
        /* default case assumes that the command will go
@@ -4718,24 +4715,6 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
        return selinux_nlmsg_perm(sk, skb);
 }
 
-static int selinux_netlink_recv(struct sk_buff *skb, int capability)
-{
-       int err;
-       struct common_audit_data ad;
-       u32 sid;
-
-       err = cap_netlink_recv(skb, capability);
-       if (err)
-               return err;
-
-       COMMON_AUDIT_DATA_INIT(&ad, CAP);
-       ad.u.cap = capability;
-
-       security_task_getsecid(current, &sid);
-       return avc_has_perm(sid, sid, SECCLASS_CAPABILITY,
-                           CAP_TO_MASK(capability), &ad);
-}
-
 static int ipc_alloc_security(struct task_struct *task,
                              struct kern_ipc_perm *perm,
                              u16 sclass)
@@ -5464,7 +5443,6 @@ static struct security_operations selinux_ops = {
        .vm_enough_memory =             selinux_vm_enough_memory,
 
        .netlink_send =                 selinux_netlink_send,
-       .netlink_recv =                 selinux_netlink_recv,
 
        .bprm_set_creds =               selinux_bprm_set_creds,
        .bprm_committing_creds =        selinux_bprm_committing_creds,
index 4a9b4b2eb755c0129d408b371ebb3f102b862662..867558c983349d144c5f46a729af55a2a72dbe0a 100644 (file)
@@ -492,13 +492,13 @@ static bool tomoyo_correct_word2(const char *string, size_t len)
                                if (d < '0' || d > '7' || e < '0' || e > '7')
                                        break;
                                c = tomoyo_make_byte(c, d, e);
-                               if (tomoyo_invalid(c))
-                                       continue; /* pattern is not \000 */
+                               if (c <= ' ' || c >= 127)
+                                       continue;
                        }
                        goto out;
                } else if (in_repetition && c == '/') {
                        goto out;
-               } else if (tomoyo_invalid(c)) {
+               } else if (c <= ' ' || c >= 127) {
                        goto out;
                }
        }
index 6fd9391b3a6cd1c4aeb60d791effd9edd985ac18..4fa1dbd8ee8381e1fbc4260c779cfecdea1d1923 100644 (file)
@@ -133,7 +133,7 @@ static int atmel_abdac_prepare_dma(struct atmel_abdac *dac,
        period_len = frames_to_bytes(runtime, runtime->period_size);
 
        cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len,
-                       period_len, DMA_TO_DEVICE);
+                       period_len, DMA_MEM_TO_DEV);
        if (IS_ERR(cdesc)) {
                dev_dbg(&dac->pdev->dev, "could not prepare cyclic DMA\n");
                return PTR_ERR(cdesc);
index 73516f69ac7ca8a33244cb300df8958ac2d77e20..61dade6983582ce415afdbe3cf88d208bb628c46 100644 (file)
@@ -102,7 +102,7 @@ static void atmel_ac97c_dma_capture_period_done(void *arg)
 
 static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip,
                struct snd_pcm_substream *substream,
-               enum dma_data_direction direction)
+               enum dma_transfer_direction direction)
 {
        struct dma_chan                 *chan;
        struct dw_cyclic_desc           *cdesc;
@@ -118,7 +118,7 @@ static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip,
                return -EINVAL;
        }
 
-       if (direction == DMA_TO_DEVICE)
+       if (direction == DMA_MEM_TO_DEV)
                chan = chip->dma.tx_chan;
        else
                chan = chip->dma.rx_chan;
@@ -133,7 +133,7 @@ static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip,
                return PTR_ERR(cdesc);
        }
 
-       if (direction == DMA_TO_DEVICE) {
+       if (direction == DMA_MEM_TO_DEV) {
                cdesc->period_callback = atmel_ac97c_dma_playback_period_done;
                set_bit(DMA_TX_READY, &chip->flags);
        } else {
@@ -393,7 +393,7 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
        if (cpu_is_at32ap7000()) {
                if (!test_bit(DMA_TX_READY, &chip->flags))
                        retval = atmel_ac97c_prepare_dma(chip, substream,
-                                       DMA_TO_DEVICE);
+                                       DMA_MEM_TO_DEV);
        } else {
                /* Initialize and start the PDC */
                writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
@@ -484,7 +484,7 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
        if (cpu_is_at32ap7000()) {
                if (!test_bit(DMA_RX_READY, &chip->flags))
                        retval = atmel_ac97c_prepare_dma(chip, substream,
-                                       DMA_FROM_DEVICE);
+                                       DMA_DEV_TO_MEM);
        } else {
                /* Initialize and start the PDC */
                writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR);
index ad409381f8cca21370f4802b1a5044af2f946b71..b413ed05e74deae78fbd97809c99f0fd68f1ee46 100644 (file)
@@ -12,6 +12,9 @@ config SND_HWDEP
 config SND_RAWMIDI
        tristate
 
+config SND_COMPRESS_OFFLOAD
+       tristate
+
 # To be effective this also requires INPUT - users should say:
 #    select SND_JACK if INPUT=y || INPUT=SND
 # to avoid having to force INPUT on.
@@ -154,16 +157,6 @@ config SND_DYNAMIC_MINORS
 
          If you are unsure about this, say N here.
 
-config SND_COMPRESS_OFFLOAD
-       tristate "ALSA Compressed audio offload support"
-       default n
-       help
-         If you want support for offloading compressed audio and have such
-         a hardware, then you should say Y here and also to the DSP driver
-         of your platform.
-
-         If you are unsure about this, say N here.
-
 config SND_SUPPORT_OLD_API
        bool "Support old ALSA API"
        default y
index 762bb108c51c139b71e93cf8d627ebae858a25d2..f13ad536b2d59fe19ab9826b5abc0c301d5133cf 100644 (file)
@@ -268,8 +268,14 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                card->shortname, chip->io, chip->irq);
 
        // (4) Alloc components.
+       err = snd_vortex_mixer(chip);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
        // ADB pcm.
-       if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_ADB)) < 0) {
+       err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_PCM);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
@@ -299,11 +305,6 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                return err;
        }
 #endif
-       // snd_ac97_mixer and Vortex mixer.
-       if ((err = snd_vortex_mixer(chip)) < 0) {
-               snd_card_free(card);
-               return err;
-       }
        if ((err = snd_vortex_midi(chip)) < 0) {
                snd_card_free(card);
                return err;
index 02f6e08f7592e8bcd6c539598f397ebbf88856aa..bb938153a964811b41f471f064fbd293fb660e77 100644 (file)
 #define MIX_SPDIF(x) (vortex->mixspdif[x])
 
 #define NR_WTPB 0x20           /* WT channels per each bank. */
+#define NR_PCM 0x10
 
 /* Structs */
 typedef struct {
index 0488633ea87474c608591601201030a65a1c91f5..0ef2f97122080f206699a01e32b7f1f1ce7b6825 100644 (file)
@@ -168,6 +168,7 @@ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream)
                        runtime->hw = snd_vortex_playback_hw_adb;
 #ifdef CHIP_AU8830
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+                       VORTEX_IS_QUAD(vortex) &&
                        VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
                        runtime->hw.channels_max = 4;
                        snd_pcm_hw_constraint_list(runtime, 0,
index 0852e204a4c8439e557bd553dcde3aae1f7c173a..fb35474c1203658fb137b650da9dec0b3b1876ad 100644 (file)
@@ -2498,6 +2498,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x10de, 0xcb89, "Macbook Pro 7,1", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
index 87e684fa830f83df49bfec3aa5e894d8c97bfa07..3556408d6ece45236ff5b13217f5f7d29905c6cc 100644 (file)
@@ -1596,7 +1596,7 @@ static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd,
                                "Dell Studio 1557", STAC_DELL_M6_DMIC),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe,
-                               "Dell Studio XPS 1645", STAC_DELL_M6_BOTH),
+                               "Dell Studio XPS 1645", STAC_DELL_M6_DMIC),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413,
                                "Dell Studio 1558", STAC_DELL_M6_DMIC),
        {} /* terminator */
index 40b181bab930bf44963fe639c795784fefce9cb2..9f3b01bb72c85abd7972629eaefe2c4b9402dc63 100644 (file)
@@ -95,13 +95,13 @@ module_param(ac97_quirk, charp, 0444);
 MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
 module_param(buggy_semaphore, bool, 0444);
 MODULE_PARM_DESC(buggy_semaphore, "Enable workaround for hardwares with problematic codec semaphores.");
-module_param(buggy_irq, bool, 0444);
+module_param(buggy_irq, bint, 0444);
 MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards.");
 module_param(xbox, bool, 0444);
 MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection.");
 module_param(spdif_aclink, int, 0444);
 MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
-module_param(inside_vm, bool, 0444);
+module_param(inside_vm, bint, 0444);
 MODULE_PARM_DESC(inside_vm, "KVM/Parallels optimization.");
 
 /* just for backward compatibility */
index 478303e6c2b0801c16c2ae52ee4eff0996fac472..63cff90706bf1749b9b7154f1c6ec81c903f68fd 100644 (file)
@@ -177,6 +177,7 @@ static void wm8776_registers_init(struct oxygen *chip)
        struct xonar_wm87x6 *data = chip->model_data;
 
        wm8776_write(chip, WM8776_RESET, 0);
+       wm8776_write(chip, WM8776_PHASESWAP, WM8776_PH_MASK);
        wm8776_write(chip, WM8776_DACCTRL1, WM8776_DZCEN |
                     WM8776_PL_LEFT_LEFT | WM8776_PL_RIGHT_RIGHT);
        wm8776_write(chip, WM8776_DACMUTE, chip->dac_mute ? WM8776_DMUTE : 0);
index e908a8123110d8011ffa5a3ed8a595a118dd862b..a56104040e83e8f0870d8e8a04db4a1c7a1ec98f 100644 (file)
@@ -1,13 +1,13 @@
 ##
-## Au1200/Au1550 PSC + DBDMA
+## Au1200/Au1550/Au1300 PSC + DBDMA
 ##
 config SND_SOC_AU1XPSC
-       tristate "SoC Audio for Au1200/Au1250/Au1550"
+       tristate "SoC Audio for Au12xx/Au13xx/Au1550"
        depends on MIPS_ALCHEMY
        help
          This option enables support for the Programmable Serial
          Controllers in AC97 and I2S mode, and the Descriptor-Based DMA
-         Controller (DBDMA) as found on the Au1200/Au1250/Au1550 SoC.
+         Controller (DBDMA) as found on the Au12xx/Au13xx/Au1550 SoC.
 
 config SND_SOC_AU1XPSC_I2S
        tristate
@@ -51,12 +51,14 @@ config SND_SOC_DB1000
          of boards (DB1000/DB1500/DB1100).
 
 config SND_SOC_DB1200
-       tristate "DB1200 AC97+I2S audio support"
+       tristate "DB1200/DB1300/DB1550 Audio support"
        depends on SND_SOC_AU1XPSC
        select SND_SOC_AU1XPSC_AC97
        select SND_SOC_AC97_CODEC
+       select SND_SOC_WM9712
        select SND_SOC_AU1XPSC_I2S
        select SND_SOC_WM8731
        help
-         Select this option to enable audio (AC97 or I2S) on the
-         Alchemy/AMD/RMI DB1200 demoboard.
+         Select this option to enable audio (AC97 and I2S) on the
+         Alchemy/AMD/RMI/NetLogic Db1200, Db1550 and Db1300 evaluation boards.
+         If you need Db1300 touchscreen support, you definitely want to say Y.
index 1c629393df782b5d866241ec9c2eded166df2bfe..30ea513d81d730cefa1027be46726a1c69e8df5f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * DB1200 ASoC audio fabric support code.
+ * DB1200/DB1300/DB1550 ASoC audio fabric support code.
  *
  * (c) 2008-2011 Manuel Lauss <manuel.lauss@googlemail.com>
  *
@@ -28,6 +28,18 @@ static struct platform_device_id db1200_pids[] = {
        }, {
                .name           = "db1200-i2s",
                .driver_data    = 1,
+       }, {
+               .name           = "db1300-ac97",
+               .driver_data    = 2,
+       }, {
+               .name           = "db1300-i2s",
+               .driver_data    = 3,
+       }, {
+               .name           = "db1550-ac97",
+               .driver_data    = 4,
+       }, {
+               .name           = "db1550-i2s",
+               .driver_data    = 5,
        },
        {},
 };
@@ -50,6 +62,27 @@ static struct snd_soc_card db1200_ac97_machine = {
        .num_links      = 1,
 };
 
+static struct snd_soc_dai_link db1300_ac97_dai = {
+       .name           = "AC97",
+       .stream_name    = "AC97 HiFi",
+       .codec_dai_name = "wm9712-hifi",
+       .cpu_dai_name   = "au1xpsc_ac97.1",
+       .platform_name  = "au1xpsc-pcm.1",
+       .codec_name     = "wm9712-codec.1",
+};
+
+static struct snd_soc_card db1300_ac97_machine = {
+       .name           = "DB1300_AC97",
+       .dai_link       = &db1300_ac97_dai,
+       .num_links      = 1,
+};
+
+static struct snd_soc_card db1550_ac97_machine = {
+       .name           = "DB1550_AC97",
+       .dai_link       = &db1200_ac97_dai,
+       .num_links      = 1,
+};
+
 /*-------------------------  I2S PART  ---------------------------*/
 
 static int db1200_i2s_startup(struct snd_pcm_substream *substream)
@@ -100,11 +133,47 @@ static struct snd_soc_card db1200_i2s_machine = {
        .num_links      = 1,
 };
 
+static struct snd_soc_dai_link db1300_i2s_dai = {
+       .name           = "WM8731",
+       .stream_name    = "WM8731 PCM",
+       .codec_dai_name = "wm8731-hifi",
+       .cpu_dai_name   = "au1xpsc_i2s.2",
+       .platform_name  = "au1xpsc-pcm.2",
+       .codec_name     = "wm8731.0-001b",
+       .ops            = &db1200_i2s_wm8731_ops,
+};
+
+static struct snd_soc_card db1300_i2s_machine = {
+       .name           = "DB1300_I2S",
+       .dai_link       = &db1300_i2s_dai,
+       .num_links      = 1,
+};
+
+static struct snd_soc_dai_link db1550_i2s_dai = {
+       .name           = "WM8731",
+       .stream_name    = "WM8731 PCM",
+       .codec_dai_name = "wm8731-hifi",
+       .cpu_dai_name   = "au1xpsc_i2s.3",
+       .platform_name  = "au1xpsc-pcm.3",
+       .codec_name     = "wm8731.0-001b",
+       .ops            = &db1200_i2s_wm8731_ops,
+};
+
+static struct snd_soc_card db1550_i2s_machine = {
+       .name           = "DB1550_I2S",
+       .dai_link       = &db1550_i2s_dai,
+       .num_links      = 1,
+};
+
 /*-------------------------  COMMON PART  ---------------------------*/
 
 static struct snd_soc_card *db1200_cards[] __devinitdata = {
        &db1200_ac97_machine,
        &db1200_i2s_machine,
+       &db1300_ac97_machine,
+       &db1300_i2s_machine,
+       &db1550_ac97_machine,
+       &db1550_i2s_machine,
 };
 
 static int __devinit db1200_audio_probe(struct platform_device *pdev)
@@ -138,5 +207,5 @@ static struct platform_driver db1200_audio_driver = {
 module_platform_driver(db1200_audio_driver);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("DB1200 ASoC audio support");
+MODULE_DESCRIPTION("DB1200/DB1300/DB1550 ASoC audio support");
 MODULE_AUTHOR("Manuel Lauss");
index d7bd91831611cb3a7a45395a76a82f34b10177df..f8863ebb4304628ed119b97bfe732c5825430714 100644 (file)
@@ -1457,5 +1457,5 @@ static void __exit sgtl5000_exit(void)
 module_exit(sgtl5000_exit);
 
 MODULE_DESCRIPTION("Freescale SGTL5000 ALSA SoC Codec Driver");
-MODULE_AUTHOR("Zeng Zhaoming <zhaoming.zeng@freescale.com>");
+MODULE_AUTHOR("Zeng Zhaoming <zengzm.kernel@gmail.com>");
 MODULE_LICENSE("GPL");
index 2b40c93601ed493a11bf0222dd5ba0c09754355b..7c7fd925db8da78c1ad6bb08bdde66eb60d7210b 100644 (file)
@@ -444,6 +444,12 @@ static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
        /* Enable the FLL */
        snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA);
 
+       /* Both overestimates */
+       if (Fref < 1000000)
+               msleep(3);
+       else
+               msleep(1);
+
        dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
 
        wm8993->fll_fref = Fref;
index 3fc96130d1a6b0ccb76470e979eb34896682e965..de83904498730dbf43447cdcc4ef42cd34a9d0d7 100644 (file)
@@ -113,9 +113,9 @@ static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
        rtd->dma_data.name = dma_params->name;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               rtd->dma_data.direction = DMA_TO_DEVICE;
+               rtd->dma_data.direction = DMA_MEM_TO_DEV;
        else
-               rtd->dma_data.direction = DMA_FROM_DEVICE;
+               rtd->dma_data.direction = DMA_DEV_TO_MEM;
 
        rtd->dma_chan = dma_request_channel(mask, ep93xx_pcm_dma_filter,
                                            &rtd->dma_data);
index 1cf2fe889f6adaa885c77bf2c74da9dd9f56a3d8..5780c9b9d569cf78f82edb63104322c896b7c234 100644 (file)
@@ -88,11 +88,13 @@ static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream,
        iprtd->dma_data.dma_request = dma_params->dma;
 
        /* Try to grab a DMA channel */
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-       iprtd->dma_chan = dma_request_channel(mask, filter, iprtd);
-       if (!iprtd->dma_chan)
-               return -EINVAL;
+       if (!iprtd->dma_chan) {
+               dma_cap_zero(mask);
+               dma_cap_set(DMA_SLAVE, mask);
+               iprtd->dma_chan = dma_request_channel(mask, filter, iprtd);
+               if (!iprtd->dma_chan)
+                       return -EINVAL;
+       }
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
@@ -107,12 +109,12 @@ static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream,
        }
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               slave_config.direction = DMA_TO_DEVICE;
+               slave_config.direction = DMA_MEM_TO_DEV;
                slave_config.dst_addr = dma_params->dma_addr;
                slave_config.dst_addr_width = buswidth;
                slave_config.dst_maxburst = dma_params->burstsize;
        } else {
-               slave_config.direction = DMA_FROM_DEVICE;
+               slave_config.direction = DMA_DEV_TO_MEM;
                slave_config.src_addr = dma_params->dma_addr;
                slave_config.src_addr_width = buswidth;
                slave_config.src_maxburst = dma_params->burstsize;
@@ -159,7 +161,7 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
                        iprtd->period_bytes * iprtd->periods,
                        iprtd->period_bytes,
                        substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-                       DMA_TO_DEVICE : DMA_FROM_DEVICE);
+                       DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
        if (!iprtd->desc) {
                dev_err(&chan->dev->device, "cannot prepare slave dma\n");
                return -EINVAL;
index 0e12f4e0a76d60ac10dab9b70ad4e12f80e0d0c7..105f42a394df6460e80899f22c567f3ac6192c7f 100644 (file)
@@ -136,7 +136,7 @@ static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream,
                        iprtd->period_bytes * iprtd->periods,
                        iprtd->period_bytes,
                        substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-                       DMA_TO_DEVICE : DMA_FROM_DEVICE);
+                       DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
        if (!iprtd->desc) {
                dev_err(&chan->dev->device, "cannot prepare slave dma\n");
                return -EINVAL;
index 45d11ddaeea9110a66182eaaa18047c8465ff90b..946020a647db2e1d5eec71f82fb9a3c936ced546 100644 (file)
@@ -366,7 +366,7 @@ static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
                goto out3;
 
        /* enbale ac97 multifunction pin */
-       mfp_set_groupg(nuc900_audio->dev, "nuc900-audio");
+       mfp_set_groupg(nuc900_audio->dev, NULL);
 
        return 0;
 
index 427ae0d9817bb95cb09fbab000d6a2d0a35d32c8..e4ba17ce6b32cf3c8d3d3a0762d70c7b7c969b3c 100644 (file)
@@ -86,7 +86,7 @@ static void dma_enqueue(struct snd_pcm_substream *substream)
        dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE);
        dma_info.direction =
                (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
-               ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
        dma_info.fp = audio_buffdone;
        dma_info.fp_param = substream;
        dma_info.period = prtd->dma_period;
@@ -171,7 +171,7 @@ static int dma_hw_params(struct snd_pcm_substream *substream,
                dma_info.client = prtd->params->client;
                dma_info.direction =
                        (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
-                       ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+                       ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
                dma_info.width = prtd->params->dma_size;
                dma_info.fifo = prtd->params->dma_addr;
                prtd->params->ch = prtd->params->ops->request(
index f8f681690a712d6c978ec607196fdd956c6fca2a..0193e595d415da8b82e7bf383b243dbdba25f88e 100644 (file)
@@ -131,7 +131,7 @@ static int siu_pcm_wr_set(struct siu_port *port_info,
        sg_dma_address(&sg) = buff;
 
        desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
-               &sg, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               &sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc) {
                dev_err(dev, "Failed to allocate a dma descriptor\n");
                return -ENOMEM;
@@ -181,7 +181,7 @@ static int siu_pcm_rd_set(struct siu_port *port_info,
        sg_dma_address(&sg) = buff;
 
        desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
-               &sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               &sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc) {
                dev_err(dev, "Failed to allocate dma descriptor\n");
                return -ENOMEM;
index 3986520b4677244b9bd592b85f2350889bda5cdf..b5ecf6d2321446198551c6d2cc6d7728c81be07a 100644 (file)
@@ -907,6 +907,10 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
                        if (err < 0)
                                printk(KERN_ERR "asoc: failed to remove %s\n", platform->name);
                }
+
+               /* Make sure all DAPM widgets are freed */
+               snd_soc_dapm_free(&platform->dapm);
+
                platform->probed = 0;
                list_del(&platform->card_list);
                module_put(platform->dev->driver->owner);
index 3ad1f59b80281cfc7c9ace89ae8a30d34317fe7a..1f55ded4047f03b9a538af971c01018f0fb5df10 100644 (file)
@@ -1426,7 +1426,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
                        dapm->target_bias_level = SND_SOC_BIAS_ON;
                        break;
                case SND_SOC_DAPM_STREAM_STOP:
-                       if (dapm->codec->active)
+                       if (dapm->codec && dapm->codec->active)
                                dapm->target_bias_level = SND_SOC_BIAS_ON;
                        else
                                dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
index 93931def0dce62b3a5e162d7c759ac82f33745f2..21554611557c380ca391a9c384407a9744a056a1 100644 (file)
@@ -134,7 +134,7 @@ txx9aclc_dma_submit(struct txx9aclc_dmadata *dmadata, dma_addr_t buf_dma_addr)
        sg_dma_address(&sg) = buf_dma_addr;
        desc = chan->device->device_prep_slave_sg(chan, &sg, 1,
                dmadata->substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
-               DMA_TO_DEVICE : DMA_FROM_DEVICE,
+               DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
                DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc) {
                dev_err(&chan->dev->device, "cannot prepare slave dma\n");
similarity index 99%
rename from Documentation/virtual/lguest/lguest.c
rename to tools/lguest/lguest.c
index c095d79cae73d1acf8d2ae9991661be35be008bd..f759f4f097c7f5ea2693a0257b914e78fea113bb 100644 (file)
@@ -49,7 +49,7 @@
 #include <linux/virtio_rng.h>
 #include <linux/virtio_ring.h>
 #include <asm/bootparam.h>
-#include "../../../include/linux/lguest_launcher.h"
+#include "../../include/linux/lguest_launcher.h"
 /*L:110
  * We can ignore the 43 include files we need for this program, but I do want
  * to draw attention to the use of kernel-style types.
diff --git a/tools/nfsd/inject_fault.sh b/tools/nfsd/inject_fault.sh
new file mode 100755 (executable)
index 0000000..06a399a
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/bash
+#
+# Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
+#
+# Script for easier NFSD fault injection
+
+# Check that debugfs has been mounted
+DEBUGFS=`cat /proc/mounts | grep debugfs`
+if [ "$DEBUGFS" == "" ]; then
+       echo "debugfs does not appear to be mounted!"
+       echo "Please mount debugfs and try again"
+       exit 1
+fi
+
+# Check that the fault injection directory exists
+DEBUGDIR=`echo $DEBUGFS | awk '{print $2}'`/nfsd
+if [ ! -d "$DEBUGDIR" ]; then
+       echo "$DEBUGDIR does not exist"
+       echo "Check that your .config selects CONFIG_NFSD_FAULT_INJECTION"
+       exit 1
+fi
+
+function help()
+{
+       echo "Usage $0 injection_type [count]"
+       echo ""
+       echo "Injection types are:"
+       ls $DEBUGDIR
+       exit 1
+}
+
+if [ $# == 0 ]; then
+       help
+elif [ ! -f $DEBUGDIR/$1 ]; then
+       help
+elif [ $# != 2 ]; then
+       COUNT=0
+else
+       COUNT=$2
+fi
+
+BEFORE=`mktemp`
+AFTER=`mktemp`
+dmesg > $BEFORE
+echo $COUNT > $DEBUGDIR/$1
+dmesg > $AFTER
+# Capture lines that only exist in the $AFTER file
+diff $BEFORE $AFTER | grep ">"
+rm -f $BEFORE $AFTER
index 7a527f7e9da9933823eefc1b7d4c173c5085ede0..ddc22525228da27db7964a0bbfbf5bf4ced41f55 100644 (file)
@@ -21,6 +21,8 @@ EVENT MODIFIERS
 Events can optionally have a modifer by appending a colon and one or
 more modifiers.  Modifiers allow the user to restrict when events are
 counted with 'u' for user-space, 'k' for kernel, 'h' for hypervisor.
+Additional modifiers are 'G' for guest counting (in KVM guests) and 'H'
+for host counting (not in KVM guests).
 
 The 'p' modifier can be used for specifying how precise the instruction
 address should be. The 'p' modifier is currently only implemented for
index c12659d8cb26fcefd8449581921aef2962cb651c..1078c5fadd5bfcb26e83755bb924eb377681d048 100644 (file)
@@ -1,4 +1,5 @@
 tools/perf
+include/linux/const.h
 include/linux/perf_event.h
 include/linux/rbtree.h
 include/linux/list.h
index 214ba7f9f57759afe6aaa08720b045681d467cdd..806e0a286634a6bd7b7a766706c32426730c7727 100644 (file)
@@ -235,7 +235,7 @@ out_delete:
 }
 
 static const char * const annotate_usage[] = {
-       "perf annotate [<options>] <command>",
+       "perf annotate [<options>]",
        NULL
 };
 
@@ -313,10 +313,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
                annotate.sym_hist_filter = argv[0];
        }
 
-       if (field_sep && *field_sep == '.') {
-               pr_err("'.' is the only non valid --field-separator argument\n");
-               return -1;
-       }
-
        return __cmd_annotate(&annotate);
 }
index fe1ad8f21961512a6a81e5f5670de71fcc9a2279..39104c0beea37990bd1775c0592179dda9a57140 100644 (file)
@@ -108,7 +108,9 @@ static void setup_cpunode_map(void)
                                continue;
                        cpunode_map[cpu] = mem;
                }
+               closedir(dir2);
        }
+       closedir(dir1);
 }
 
 static void insert_alloc_stat(unsigned long call_site, unsigned long ptr,
@@ -645,6 +647,7 @@ static int setup_sorting(struct list_head *sort_list, const char *arg)
                        break;
                if (sort_dimension__add(tok, sort_list) < 0) {
                        error("Unknown --sort key: '%s'", tok);
+                       free(str);
                        return -1;
                }
        }
index 032324a76b877bb69dcf4f3cdb7505719bb04b6d..9fc6e0fa3dce22f838324da57b3e2929892ed70a 100644 (file)
@@ -22,9 +22,6 @@
 static const char              *file_name;
 static char                    name_buffer[256];
 
-bool                           perf_host = 1;
-bool                           perf_guest;
-
 static const char * const kvm_usage[] = {
        "perf kvm [<options>] {top|record|report|diff|buildid-list}",
        NULL
@@ -107,7 +104,8 @@ static int __cmd_buildid_list(int argc, const char **argv)
 
 int cmd_kvm(int argc, const char **argv, const char *prefix __used)
 {
-       perf_host = perf_guest = 0;
+       perf_host  = 0;
+       perf_guest = 1;
 
        argc = parse_options(argc, argv, kvm_options, kvm_usage,
                        PARSE_OPT_STOP_AT_NON_OPTION);
index fd1909afcfd62f29757151261e65e7b8419da79e..bb68ddf257b7d77667ef9731ffb68c1494e0f239 100644 (file)
@@ -1018,13 +1018,17 @@ static char *get_script_path(const char *script_root, const char *suffix)
                        __script_root = get_script_root(&script_dirent, suffix);
                        if (__script_root && !strcmp(script_root, __script_root)) {
                                free(__script_root);
+                               closedir(lang_dir);
+                               closedir(scripts_dir);
                                snprintf(script_path, MAXPATHLEN, "%s/%s",
                                         lang_path, script_dirent.d_name);
                                return strdup(script_path);
                        }
                        free(__script_root);
                }
+               closedir(lang_dir);
        }
+       closedir(scripts_dir);
 
        return NULL;
 }
index 2b9a7f497a20b77015225127eb3e5df698e5b8b1..3854e869dce10f95181375f5f5d51262bfb2dcdf 100644 (file)
@@ -1396,7 +1396,7 @@ int cmd_test(int argc, const char **argv, const char *prefix __used)
        NULL,
        };
        const struct option test_options[] = {
-       OPT_INTEGER('v', "verbose", &verbose,
+       OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show symbol address, etc)"),
        OPT_END()
        };
index 4f81eeb998755a992f184104dd5390ffbc49d7b5..8f80df89603822e5431f45f1374cf926208f23ed 100644 (file)
@@ -235,7 +235,6 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
        if (he == NULL)
                return NULL;
 
-       evsel->hists.stats.total_period += sample->period;
        hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
        return he;
 }
@@ -889,6 +888,10 @@ try_again:
                                ui__warning("The %s event is not supported.\n",
                                            event_name(counter));
                                goto out_err;
+                       } else if (err == EMFILE) {
+                               ui__warning("Too many events are opened.\n"
+                                           "Try again after reducing the number of events\n");
+                               goto out_err;
                        }
 
                        ui__warning("The sys_perf_event_open() syscall "
index fa1837088ca880ca5968709326e94f22fa436db4..3f16e08a5c8de740a3149879274dd69af720c97e 100644 (file)
@@ -111,8 +111,11 @@ int perf_evlist__add_default(struct perf_evlist *evlist)
                .type = PERF_TYPE_HARDWARE,
                .config = PERF_COUNT_HW_CPU_CYCLES,
        };
-       struct perf_evsel *evsel = perf_evsel__new(&attr, 0);
+       struct perf_evsel *evsel;
+
+       event_attr_init(&attr);
 
+       evsel = perf_evsel__new(&attr, 0);
        if (evsel == NULL)
                goto error;
 
index abef2703cd242eb8b8e5f1763cadd50286bdc8be..6f505d1abac72e493043e87f029ea9c0d9d4cea5 100644 (file)
@@ -76,21 +76,21 @@ static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
        }
 }
 
-static void hist_entry__add_cpumode_period(struct hist_entry *self,
+static void hist_entry__add_cpumode_period(struct hist_entry *he,
                                           unsigned int cpumode, u64 period)
 {
        switch (cpumode) {
        case PERF_RECORD_MISC_KERNEL:
-               self->period_sys += period;
+               he->period_sys += period;
                break;
        case PERF_RECORD_MISC_USER:
-               self->period_us += period;
+               he->period_us += period;
                break;
        case PERF_RECORD_MISC_GUEST_KERNEL:
-               self->period_guest_sys += period;
+               he->period_guest_sys += period;
                break;
        case PERF_RECORD_MISC_GUEST_USER:
-               self->period_guest_us += period;
+               he->period_guest_us += period;
                break;
        default:
                break;
@@ -165,18 +165,18 @@ void hists__decay_entries_threaded(struct hists *hists,
 static struct hist_entry *hist_entry__new(struct hist_entry *template)
 {
        size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
-       struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
+       struct hist_entry *he = malloc(sizeof(*he) + callchain_size);
 
-       if (self != NULL) {
-               *self = *template;
-               self->nr_events = 1;
-               if (self->ms.map)
-                       self->ms.map->referenced = true;
+       if (he != NULL) {
+               *he = *template;
+               he->nr_events = 1;
+               if (he->ms.map)
+                       he->ms.map->referenced = true;
                if (symbol_conf.use_callchain)
-                       callchain_init(self->callchain);
+                       callchain_init(he->callchain);
        }
 
-       return self;
+       return he;
 }
 
 static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
@@ -677,15 +677,16 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
        return ret;
 }
 
-static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
-                                           u64 total_samples, int left_margin)
+static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
+                                           u64 total_samples, int left_margin,
+                                           FILE *fp)
 {
        struct rb_node *rb_node;
        struct callchain_node *chain;
        size_t ret = 0;
        u32 entries_printed = 0;
 
-       rb_node = rb_first(&self->sorted_chain);
+       rb_node = rb_first(&he->sorted_chain);
        while (rb_node) {
                double percent;
 
@@ -730,35 +731,35 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows)
        }
 }
 
-static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s,
+static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
                                     size_t size, struct hists *pair_hists,
                                     bool show_displacement, long displacement,
-                                    bool color, u64 session_total)
+                                    bool color, u64 total_period)
 {
        u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
        u64 nr_events;
        const char *sep = symbol_conf.field_sep;
        int ret;
 
-       if (symbol_conf.exclude_other && !self->parent)
+       if (symbol_conf.exclude_other && !he->parent)
                return 0;
 
        if (pair_hists) {
-               period = self->pair ? self->pair->period : 0;
-               nr_events = self->pair ? self->pair->nr_events : 0;
+               period = he->pair ? he->pair->period : 0;
+               nr_events = he->pair ? he->pair->nr_events : 0;
                total = pair_hists->stats.total_period;
-               period_sys = self->pair ? self->pair->period_sys : 0;
-               period_us = self->pair ? self->pair->period_us : 0;
-               period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
-               period_guest_us = self->pair ? self->pair->period_guest_us : 0;
+               period_sys = he->pair ? he->pair->period_sys : 0;
+               period_us = he->pair ? he->pair->period_us : 0;
+               period_guest_sys = he->pair ? he->pair->period_guest_sys : 0;
+               period_guest_us = he->pair ? he->pair->period_guest_us : 0;
        } else {
-               period = self->period;
-               nr_events = self->nr_events;
-               total = session_total;
-               period_sys = self->period_sys;
-               period_us = self->period_us;
-               period_guest_sys = self->period_guest_sys;
-               period_guest_us = self->period_guest_us;
+               period = he->period;
+               nr_events = he->nr_events;
+               total = total_period;
+               period_sys = he->period_sys;
+               period_us = he->period_us;
+               period_guest_sys = he->period_guest_sys;
+               period_guest_us = he->period_guest_us;
        }
 
        if (total) {
@@ -812,8 +813,8 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s,
 
                if (total > 0)
                        old_percent = (period * 100.0) / total;
-               if (session_total > 0)
-                       new_percent = (self->period * 100.0) / session_total;
+               if (total_period > 0)
+                       new_percent = (he->period * 100.0) / total_period;
 
                diff = new_percent - old_percent;
 
@@ -862,9 +863,10 @@ int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size,
        return ret;
 }
 
-int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
-                       struct hists *pair_hists, bool show_displacement,
-                       long displacement, FILE *fp, u64 session_total)
+static int hist_entry__fprintf(struct hist_entry *he, size_t size,
+                              struct hists *hists, struct hists *pair_hists,
+                              bool show_displacement, long displacement,
+                              u64 total_period, FILE *fp)
 {
        char bf[512];
        int ret;
@@ -874,14 +876,14 @@ int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
 
        ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists,
                                        show_displacement, displacement,
-                                       true, session_total);
+                                       true, total_period);
        hist_entry__snprintf(he, bf + ret, size - ret, hists);
        return fprintf(fp, "%s\n", bf);
 }
 
-static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
-                                           struct hists *hists, FILE *fp,
-                                           u64 session_total)
+static size_t hist_entry__fprintf_callchain(struct hist_entry *he,
+                                           struct hists *hists,
+                                           u64 total_period, FILE *fp)
 {
        int left_margin = 0;
 
@@ -889,11 +891,10 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
                struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
                                                         typeof(*se), list);
                left_margin = hists__col_len(hists, se->se_width_idx);
-               left_margin -= thread__comm_len(self->thread);
+               left_margin -= thread__comm_len(he->thread);
        }
 
-       return hist_entry_callchain__fprintf(fp, self, session_total,
-                                            left_margin);
+       return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
 }
 
 size_t hists__fprintf(struct hists *hists, struct hists *pair,
@@ -903,6 +904,7 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
        struct sort_entry *se;
        struct rb_node *nd;
        size_t ret = 0;
+       u64 total_period;
        unsigned long position = 1;
        long displacement = 0;
        unsigned int width;
@@ -917,20 +919,6 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
 
        fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
 
-       if (symbol_conf.show_nr_samples) {
-               if (sep)
-                       fprintf(fp, "%cSamples", *sep);
-               else
-                       fputs("  Samples  ", fp);
-       }
-
-       if (symbol_conf.show_total_period) {
-               if (sep)
-                       ret += fprintf(fp, "%cPeriod", *sep);
-               else
-                       ret += fprintf(fp, "   Period    ");
-       }
-
        if (symbol_conf.show_cpu_utilization) {
                if (sep) {
                        ret += fprintf(fp, "%csys", *sep);
@@ -940,8 +928,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
                                ret += fprintf(fp, "%cguest us", *sep);
                        }
                } else {
-                       ret += fprintf(fp, "  sys  ");
-                       ret += fprintf(fp, "  us  ");
+                       ret += fprintf(fp, "     sys  ");
+                       ret += fprintf(fp, "      us  ");
                        if (perf_guest) {
                                ret += fprintf(fp, "  guest sys  ");
                                ret += fprintf(fp, "  guest us  ");
@@ -949,6 +937,20 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
                }
        }
 
+       if (symbol_conf.show_nr_samples) {
+               if (sep)
+                       fprintf(fp, "%cSamples", *sep);
+               else
+                       fputs("  Samples  ", fp);
+       }
+
+       if (symbol_conf.show_total_period) {
+               if (sep)
+                       ret += fprintf(fp, "%cPeriod", *sep);
+               else
+                       ret += fprintf(fp, "   Period    ");
+       }
+
        if (pair) {
                if (sep)
                        ret += fprintf(fp, "%cDelta", *sep);
@@ -993,6 +995,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
                goto print_entries;
 
        fprintf(fp, "# ........");
+       if (symbol_conf.show_cpu_utilization)
+               fprintf(fp, "   .......   .......");
        if (symbol_conf.show_nr_samples)
                fprintf(fp, " ..........");
        if (symbol_conf.show_total_period)
@@ -1025,6 +1029,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
                goto out;
 
 print_entries:
+       total_period = hists->stats.total_period;
+
        for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
 
@@ -1040,11 +1046,10 @@ print_entries:
                        ++position;
                }
                ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
-                                          displacement, fp, hists->stats.total_period);
+                                          displacement, total_period, fp);
 
                if (symbol_conf.use_callchain)
-                       ret += hist_entry__fprintf_callchain(h, hists, fp,
-                                                            hists->stats.total_period);
+                       ret += hist_entry__fprintf_callchain(h, hists, total_period, fp);
                if (max_rows && ++nr_rows >= max_rows)
                        goto out;
 
index ff6f9d56ea4192531241474bf07e09a78dcf5695..f55f0a8d1f816d57cf2a7ee44677894dc5287e78 100644 (file)
@@ -66,11 +66,8 @@ struct hists {
 struct hist_entry *__hists__add_entry(struct hists *self,
                                      struct addr_location *al,
                                      struct symbol *parent, u64 period);
-extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
-extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
-int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
-                       struct hists *pair_hists, bool show_displacement,
-                       long displacement, FILE *fp, u64 session_total);
+int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
+int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
 int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
                         struct hists *hists);
 void hist_entry__free(struct hist_entry *);
index 531c283fc0c503566cf00afdc675e074c88d41d0..b029296d20d9dfc3c8bd85fb563d7d404c9cb5a1 100644 (file)
@@ -735,8 +735,8 @@ static int
 parse_event_modifier(const char **strp, struct perf_event_attr *attr)
 {
        const char *str = *strp;
-       int exclude = 0;
-       int eu = 0, ek = 0, eh = 0, precise = 0;
+       int exclude = 0, exclude_GH = 0;
+       int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0;
 
        if (!*str)
                return 0;
@@ -760,6 +760,14 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
                        if (!exclude)
                                exclude = eu = ek = eh = 1;
                        eh = 0;
+               } else if (*str == 'G') {
+                       if (!exclude_GH)
+                               exclude_GH = eG = eH = 1;
+                       eG = 0;
+               } else if (*str == 'H') {
+                       if (!exclude_GH)
+                               exclude_GH = eG = eH = 1;
+                       eH = 0;
                } else if (*str == 'p') {
                        precise++;
                } else
@@ -776,6 +784,8 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
        attr->exclude_kernel = ek;
        attr->exclude_hv     = eh;
        attr->precise_ip     = precise;
+       attr->exclude_host   = eH;
+       attr->exclude_guest  = eG;
 
        return 0;
 }
@@ -838,6 +848,7 @@ int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
        for (;;) {
                ostr = str;
                memset(&attr, 0, sizeof(attr));
+               event_attr_init(&attr);
                ret = parse_event_symbols(evlist, &str, &attr);
                if (ret == EVT_FAILED)
                        return -1;
index ac6830d8292b221f9676f5d3b15b0efdf9658642..fc22cf5c605f38bf079751ca82c469a5a1448e96 100644 (file)
@@ -18,7 +18,6 @@
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
-#include <ctype.h>
 #include "util.h"
 #include <dirent.h>
 #include <mntent.h>
index 5b3ea49aa63ea1ff35b7d949b49a661187aa16e6..813141047fc22fcfd61ae377444f7ff2a97f06eb 100644 (file)
@@ -1,6 +1,21 @@
+#include "../perf.h"
 #include "util.h"
 #include <sys/mman.h>
 
+/*
+ * XXX We need to find a better place for these things...
+ */
+bool perf_host  = true;
+bool perf_guest = true;
+
+void event_attr_init(struct perf_event_attr *attr)
+{
+       if (!perf_host)
+               attr->exclude_host  = 1;
+       if (!perf_guest)
+               attr->exclude_guest = 1;
+}
+
 int mkdir_p(char *path, mode_t mode)
 {
        struct stat st;
index 37be34dff7983c2834b051bc8cc3347ab213383b..b9c530cce79a793657778dcc5a1ce2c5dd2215da 100644 (file)
@@ -242,6 +242,10 @@ int strtailcmp(const char *s1, const char *s2);
 unsigned long convert_unit(unsigned long value, char *unit);
 int readn(int fd, void *buf, size_t size);
 
+struct perf_event_attr;
+
+void event_attr_init(struct perf_event_attr *attr);
+
 #define _STR(x) #x
 #define STR(x) _STR(x)
 
index 3c6f7808efae53b84cab8926f87b3a5f37ea60ee..310d3dd5e547023ea375f933cb2ad7ca61aee081 100644 (file)
@@ -811,6 +811,8 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
        case 0x2C:      /* Westmere EP - Gulftown */
        case 0x2A:      /* SNB */
        case 0x2D:      /* SNB Xeon */
+       case 0x3A:      /* IVB */
+       case 0x3D:      /* IVB Xeon */
                return 1;
        case 0x2E:      /* Nehalem-EX Xeon - Beckton */
        case 0x2F:      /* Westmere-EX Xeon - Eagleton */
index 9a571e71683c2dfea90ddcf03911d93abee75081..a373a5bfff683cc4b395588af358a2aa92b2171d 100755 (executable)
@@ -2,7 +2,9 @@
 
 open (IN,"ktest.pl");
 while (<IN>) {
+    # hashes are now used
     if (/\$opt\{"?([A-Z].*?)(\[.*\])?"?\}/ ||
+       /^\s*"?([A-Z].*?)"?\s*=>\s*/ ||
        /set_test_option\("(.*?)"/) {
        $opt{$1} = 1;
     }
@@ -11,7 +13,7 @@ close IN;
 
 open (IN, "sample.conf");
 while (<IN>) {
-    if (/^\s*#?\s*(\S+)\s*=/) {
+    if (/^\s*#?\s*([A-Z]\S*)\s*=/) {
        $samp{$1} = 1;
     }
 }
index 8b4c2535b266a2abe17d3ad495b3a0fdfa8855a9..62a134dc421ae37d14307a44f09abc9c0d0c197a 100755 (executable)
@@ -18,40 +18,50 @@ $| = 1;
 my %opt;
 my %repeat_tests;
 my %repeats;
-my %default;
 
 #default opts
-$default{"NUM_TESTS"}          = 1;
-$default{"REBOOT_TYPE"}                = "grub";
-$default{"TEST_TYPE"}          = "test";
-$default{"BUILD_TYPE"}         = "randconfig";
-$default{"MAKE_CMD"}           = "make";
-$default{"TIMEOUT"}            = 120;
-$default{"TMP_DIR"}            = "/tmp/ktest/\${MACHINE}";
-$default{"SLEEP_TIME"}         = 60;   # sleep time between tests
-$default{"BUILD_NOCLEAN"}      = 0;
-$default{"REBOOT_ON_ERROR"}    = 0;
-$default{"POWEROFF_ON_ERROR"}  = 0;
-$default{"REBOOT_ON_SUCCESS"}  = 1;
-$default{"POWEROFF_ON_SUCCESS"}        = 0;
-$default{"BUILD_OPTIONS"}      = "";
-$default{"BISECT_SLEEP_TIME"}  = 60;   # sleep time between bisects
-$default{"PATCHCHECK_SLEEP_TIME"} = 60; # sleep time between patch checks
-$default{"CLEAR_LOG"}          = 0;
-$default{"BISECT_MANUAL"}      = 0;
-$default{"BISECT_SKIP"}                = 1;
-$default{"SUCCESS_LINE"}       = "login:";
-$default{"DETECT_TRIPLE_FAULT"} = 1;
-$default{"NO_INSTALL"}         = 0;
-$default{"BOOTED_TIMEOUT"}     = 1;
-$default{"DIE_ON_FAILURE"}     = 1;
-$default{"SSH_EXEC"}           = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND";
-$default{"SCP_TO_TARGET"}      = "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE";
-$default{"REBOOT"}             = "ssh \$SSH_USER\@\$MACHINE reboot";
-$default{"STOP_AFTER_SUCCESS"} = 10;
-$default{"STOP_AFTER_FAILURE"} = 60;
-$default{"STOP_TEST_AFTER"}    = 600;
-$default{"LOCALVERSION"}       = "-test";
+my %default = (
+    "NUM_TESTS"                        => 1,
+    "TEST_TYPE"                        => "build",
+    "BUILD_TYPE"               => "randconfig",
+    "MAKE_CMD"                 => "make",
+    "TIMEOUT"                  => 120,
+    "TMP_DIR"                  => "/tmp/ktest/\${MACHINE}",
+    "SLEEP_TIME"               => 60,  # sleep time between tests
+    "BUILD_NOCLEAN"            => 0,
+    "REBOOT_ON_ERROR"          => 0,
+    "POWEROFF_ON_ERROR"                => 0,
+    "REBOOT_ON_SUCCESS"                => 1,
+    "POWEROFF_ON_SUCCESS"      => 0,
+    "BUILD_OPTIONS"            => "",
+    "BISECT_SLEEP_TIME"                => 60,   # sleep time between bisects
+    "PATCHCHECK_SLEEP_TIME"    => 60, # sleep time between patch checks
+    "CLEAR_LOG"                        => 0,
+    "BISECT_MANUAL"            => 0,
+    "BISECT_SKIP"              => 1,
+    "SUCCESS_LINE"             => "login:",
+    "DETECT_TRIPLE_FAULT"      => 1,
+    "NO_INSTALL"               => 0,
+    "BOOTED_TIMEOUT"           => 1,
+    "DIE_ON_FAILURE"           => 1,
+    "SSH_EXEC"                 => "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND",
+    "SCP_TO_TARGET"            => "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE",
+    "REBOOT"                   => "ssh \$SSH_USER\@\$MACHINE reboot",
+    "STOP_AFTER_SUCCESS"       => 10,
+    "STOP_AFTER_FAILURE"       => 60,
+    "STOP_TEST_AFTER"          => 600,
+
+# required, and we will ask users if they don't have them but we keep the default
+# value something that is common.
+    "REBOOT_TYPE"              => "grub",
+    "LOCALVERSION"             => "-test",
+    "SSH_USER"                 => "root",
+    "BUILD_TARGET"             => "arch/x86/boot/bzImage",
+    "TARGET_IMAGE"             => "/boot/vmlinuz-test",
+
+    "LOG_FILE"                 => undef,
+    "IGNORE_UNUSED"            => 0,
+);
 
 my $ktest_config;
 my $version;
@@ -73,6 +83,8 @@ my $reboot_script;
 my $power_cycle;
 my $reboot;
 my $reboot_on_error;
+my $switch_to_good;
+my $switch_to_test;
 my $poweroff_on_error;
 my $die_on_failure;
 my $powercycle_after_reboot;
@@ -92,17 +104,24 @@ my $start_minconfig;
 my $start_minconfig_defined;
 my $output_minconfig;
 my $ignore_config;
+my $ignore_errors;
 my $addconfig;
 my $in_bisect = 0;
-my $bisect_bad = "";
+my $bisect_bad_commit = "";
 my $reverse_bisect;
 my $bisect_manual;
 my $bisect_skip;
 my $config_bisect_good;
+my $bisect_ret_good;
+my $bisect_ret_bad;
+my $bisect_ret_skip;
+my $bisect_ret_abort;
+my $bisect_ret_default;
 my $in_patchcheck = 0;
 my $run_test;
 my $redirect;
 my $buildlog;
+my $testlog;
 my $dmesg;
 my $monitor_fp;
 my $monitor_pid;
@@ -112,6 +131,7 @@ my $bisect_sleep_time;
 my $patchcheck_sleep_time;
 my $ignore_warnings;
 my $store_failures;
+my $store_successes;
 my $test_name;
 my $timeout;
 my $booted_timeout;
@@ -124,10 +144,34 @@ my $stop_after_failure;
 my $stop_test_after;
 my $build_target;
 my $target_image;
+my $checkout;
 my $localversion;
 my $iteration = 0;
 my $successes = 0;
 
+my $bisect_good;
+my $bisect_bad;
+my $bisect_type;
+my $bisect_start;
+my $bisect_replay;
+my $bisect_files;
+my $bisect_reverse;
+my $bisect_check;
+
+my $config_bisect;
+my $config_bisect_type;
+
+my $patchcheck_type;
+my $patchcheck_start;
+my $patchcheck_end;
+
+# set when a test is something other that just building or install
+# which would require more options.
+my $buildonly = 1;
+
+# set when creating a new config
+my $newconfig = 0;
+
 my %entered_configs;
 my %config_help;
 my %variable;
@@ -136,11 +180,99 @@ my %force_config;
 # do not force reboots on config problems
 my $no_reboot = 1;
 
+my %option_map = (
+    "MACHINE"                  => \$machine,
+    "SSH_USER"                 => \$ssh_user,
+    "TMP_DIR"                  => \$tmpdir,
+    "OUTPUT_DIR"               => \$outputdir,
+    "BUILD_DIR"                        => \$builddir,
+    "TEST_TYPE"                        => \$test_type,
+    "BUILD_TYPE"               => \$build_type,
+    "BUILD_OPTIONS"            => \$build_options,
+    "PRE_BUILD"                        => \$pre_build,
+    "POST_BUILD"               => \$post_build,
+    "PRE_BUILD_DIE"            => \$pre_build_die,
+    "POST_BUILD_DIE"           => \$post_build_die,
+    "POWER_CYCLE"              => \$power_cycle,
+    "REBOOT"                   => \$reboot,
+    "BUILD_NOCLEAN"            => \$noclean,
+    "MIN_CONFIG"               => \$minconfig,
+    "OUTPUT_MIN_CONFIG"                => \$output_minconfig,
+    "START_MIN_CONFIG"         => \$start_minconfig,
+    "IGNORE_CONFIG"            => \$ignore_config,
+    "TEST"                     => \$run_test,
+    "ADD_CONFIG"               => \$addconfig,
+    "REBOOT_TYPE"              => \$reboot_type,
+    "GRUB_MENU"                        => \$grub_menu,
+    "POST_INSTALL"             => \$post_install,
+    "NO_INSTALL"               => \$no_install,
+    "REBOOT_SCRIPT"            => \$reboot_script,
+    "REBOOT_ON_ERROR"          => \$reboot_on_error,
+    "SWITCH_TO_GOOD"           => \$switch_to_good,
+    "SWITCH_TO_TEST"           => \$switch_to_test,
+    "POWEROFF_ON_ERROR"                => \$poweroff_on_error,
+    "DIE_ON_FAILURE"           => \$die_on_failure,
+    "POWER_OFF"                        => \$power_off,
+    "POWERCYCLE_AFTER_REBOOT"  => \$powercycle_after_reboot,
+    "POWEROFF_AFTER_HALT"      => \$poweroff_after_halt,
+    "SLEEP_TIME"               => \$sleep_time,
+    "BISECT_SLEEP_TIME"                => \$bisect_sleep_time,
+    "PATCHCHECK_SLEEP_TIME"    => \$patchcheck_sleep_time,
+    "IGNORE_WARNINGS"          => \$ignore_warnings,
+    "IGNORE_ERRORS"            => \$ignore_errors,
+    "BISECT_MANUAL"            => \$bisect_manual,
+    "BISECT_SKIP"              => \$bisect_skip,
+    "CONFIG_BISECT_GOOD"       => \$config_bisect_good,
+    "BISECT_RET_GOOD"          => \$bisect_ret_good,
+    "BISECT_RET_BAD"           => \$bisect_ret_bad,
+    "BISECT_RET_SKIP"          => \$bisect_ret_skip,
+    "BISECT_RET_ABORT"         => \$bisect_ret_abort,
+    "BISECT_RET_DEFAULT"       => \$bisect_ret_default,
+    "STORE_FAILURES"           => \$store_failures,
+    "STORE_SUCCESSES"          => \$store_successes,
+    "TEST_NAME"                        => \$test_name,
+    "TIMEOUT"                  => \$timeout,
+    "BOOTED_TIMEOUT"           => \$booted_timeout,
+    "CONSOLE"                  => \$console,
+    "DETECT_TRIPLE_FAULT"      => \$detect_triplefault,
+    "SUCCESS_LINE"             => \$success_line,
+    "REBOOT_SUCCESS_LINE"      => \$reboot_success_line,
+    "STOP_AFTER_SUCCESS"       => \$stop_after_success,
+    "STOP_AFTER_FAILURE"       => \$stop_after_failure,
+    "STOP_TEST_AFTER"          => \$stop_test_after,
+    "BUILD_TARGET"             => \$build_target,
+    "SSH_EXEC"                 => \$ssh_exec,
+    "SCP_TO_TARGET"            => \$scp_to_target,
+    "CHECKOUT"                 => \$checkout,
+    "TARGET_IMAGE"             => \$target_image,
+    "LOCALVERSION"             => \$localversion,
+
+    "BISECT_GOOD"              => \$bisect_good,
+    "BISECT_BAD"               => \$bisect_bad,
+    "BISECT_TYPE"              => \$bisect_type,
+    "BISECT_START"             => \$bisect_start,
+    "BISECT_REPLAY"            => \$bisect_replay,
+    "BISECT_FILES"             => \$bisect_files,
+    "BISECT_REVERSE"           => \$bisect_reverse,
+    "BISECT_CHECK"             => \$bisect_check,
+
+    "CONFIG_BISECT"            => \$config_bisect,
+    "CONFIG_BISECT_TYPE"       => \$config_bisect_type,
+
+    "PATCHCHECK_TYPE"          => \$patchcheck_type,
+    "PATCHCHECK_START"         => \$patchcheck_start,
+    "PATCHCHECK_END"           => \$patchcheck_end,
+);
+
+# Options may be used by other options, record them.
+my %used_options;
+
 # default variables that can be used
 chomp ($variable{"PWD"} = `pwd`);
 
 $config_help{"MACHINE"} = << "EOF"
  The machine hostname that you will test.
+ For build only tests, it is still needed to differentiate log files.
 EOF
     ;
 $config_help{"SSH_USER"} = << "EOF"
@@ -150,11 +282,15 @@ EOF
     ;
 $config_help{"BUILD_DIR"} = << "EOF"
  The directory that contains the Linux source code (full path).
+ You can use \${PWD} that will be the path where ktest.pl is run, or use
+ \${THIS_DIR} which is assigned \${PWD} but may be changed later.
 EOF
     ;
 $config_help{"OUTPUT_DIR"} = << "EOF"
  The directory that the objects will be built (full path).
  (can not be same as BUILD_DIR)
+ You can use \${PWD} that will be the path where ktest.pl is run, or use
+ \${THIS_DIR} which is assigned \${PWD} but may be changed later.
 EOF
     ;
 $config_help{"BUILD_TARGET"} = << "EOF"
@@ -162,6 +298,11 @@ $config_help{"BUILD_TARGET"} = << "EOF"
  (relative to OUTPUT_DIR)
 EOF
     ;
+$config_help{"BUILD_OPTIONS"} = << "EOF"
+ Options to add to \"make\" when building.
+ i.e.  -j20
+EOF
+    ;
 $config_help{"TARGET_IMAGE"} = << "EOF"
  The place to put your image on the test machine.
 EOF
@@ -227,20 +368,36 @@ $config_help{"REBOOT_SCRIPT"} = << "EOF"
 EOF
     ;
 
-sub read_yn {
-    my ($prompt) = @_;
+sub read_prompt {
+    my ($cancel, $prompt) = @_;
 
     my $ans;
 
     for (;;) {
-       print "$prompt [Y/n] ";
+       if ($cancel) {
+           print "$prompt [y/n/C] ";
+       } else {
+           print "$prompt [Y/n] ";
+       }
        $ans = <STDIN>;
        chomp $ans;
        if ($ans =~ /^\s*$/) {
-           $ans = "y";
+           if ($cancel) {
+               $ans = "c";
+           } else {
+               $ans = "y";
+           }
        }
        last if ($ans =~ /^y$/i || $ans =~ /^n$/i);
-       print "Please answer either 'y' or 'n'.\n";
+       if ($cancel) {
+           last if ($ans =~ /^c$/i);
+           print "Please answer either 'y', 'n' or 'c'.\n";
+       } else {
+           print "Please answer either 'y' or 'n'.\n";
+       }
+    }
+    if ($ans =~ /^c/i) {
+       exit;
     }
     if ($ans !~ /^y$/i) {
        return 0;
@@ -248,6 +405,18 @@ sub read_yn {
     return 1;
 }
 
+sub read_yn {
+    my ($prompt) = @_;
+
+    return read_prompt 0, $prompt;
+}
+
+sub read_ync {
+    my ($prompt) = @_;
+
+    return read_prompt 1, $prompt;
+}
+
 sub get_ktest_config {
     my ($config) = @_;
     my $ans;
@@ -261,7 +430,7 @@ sub get_ktest_config {
 
     for (;;) {
        print "$config = ";
-       if (defined($default{$config})) {
+       if (defined($default{$config}) && length($default{$config})) {
            print "\[$default{$config}\] ";
        }
        $ans = <STDIN>;
@@ -274,22 +443,37 @@ sub get_ktest_config {
                next;
            }
        }
-       $entered_configs{$config} = process_variables($ans);
+       $entered_configs{$config} = ${ans};
        last;
     }
 }
 
 sub get_ktest_configs {
     get_ktest_config("MACHINE");
-    get_ktest_config("SSH_USER");
     get_ktest_config("BUILD_DIR");
     get_ktest_config("OUTPUT_DIR");
-    get_ktest_config("BUILD_TARGET");
-    get_ktest_config("TARGET_IMAGE");
-    get_ktest_config("POWER_CYCLE");
-    get_ktest_config("CONSOLE");
+
+    if ($newconfig) {
+       get_ktest_config("BUILD_OPTIONS");
+    }
+
+    # options required for other than just building a kernel
+    if (!$buildonly) {
+       get_ktest_config("POWER_CYCLE");
+       get_ktest_config("CONSOLE");
+    }
+
+    # options required for install and more
+    if ($buildonly != 1) {
+       get_ktest_config("SSH_USER");
+       get_ktest_config("BUILD_TARGET");
+       get_ktest_config("TARGET_IMAGE");
+    }
+
     get_ktest_config("LOCALVERSION");
 
+    return if ($buildonly);
+
     my $rtype = $opt{"REBOOT_TYPE"};
 
     if (!defined($rtype)) {
@@ -303,8 +487,6 @@ sub get_ktest_configs {
 
     if ($rtype eq "grub") {
        get_ktest_config("GRUB_MENU");
-    } else {
-       get_ktest_config("REBOOT_SCRIPT");
     }
 }
 
@@ -334,6 +516,10 @@ sub process_variables {
        } else {
            # put back the origin piece.
            $retval = "$retval\$\{$var\}";
+           # This could be an option that is used later, save
+           # it so we don't warn if this option is not one of
+           # ktests options.
+           $used_options{$var} = 1;
        }
        $value = $end;
     }
@@ -348,6 +534,19 @@ sub process_variables {
 sub set_value {
     my ($lvalue, $rvalue, $override, $overrides, $name) = @_;
 
+    my $prvalue = process_variables($rvalue);
+
+    if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $prvalue ne "build") {
+       # Note if a test is something other than build, then we
+       # will need other manditory options.
+       if ($prvalue ne "install") {
+           $buildonly = 0;
+       } else {
+           # install still limits some manditory options.
+           $buildonly = 2;
+       }
+    }
+
     if (defined($opt{$lvalue})) {
        if (!$override || defined(${$overrides}{$lvalue})) {
            my $extra = "";
@@ -356,13 +555,12 @@ sub set_value {
            }
            die "$name: $.: Option $lvalue defined more than once!\n$extra";
        }
-       ${$overrides}{$lvalue} = $rvalue;
+       ${$overrides}{$lvalue} = $prvalue;
     }
     if ($rvalue =~ /^\s*$/) {
        delete $opt{$lvalue};
     } else {
-       $rvalue = process_variables($rvalue);
-       $opt{$lvalue} = $rvalue;
+       $opt{$lvalue} = $prvalue;
     }
 }
 
@@ -712,6 +910,15 @@ sub __read_config {
     return $test_case;
 }
 
+sub get_test_case {
+       print "What test case would you like to run?\n";
+       print " (build, install or boot)\n";
+       print " Other tests are available but require editing the config file\n";
+       my $ans = <STDIN>;
+       chomp $ans;
+       $default{"TEST_TYPE"} = $ans;
+}
+
 sub read_config {
     my ($config) = @_;
 
@@ -726,10 +933,7 @@ sub read_config {
     # was a test specified?
     if (!$test_case) {
        print "No test case specified.\n";
-       print "What test case would you like to run?\n";
-       my $ans = <STDIN>;
-       chomp $ans;
-       $default{"TEST_TYPE"} = $ans;
+       get_test_case;
     }
 
     # set any defaults
@@ -739,6 +943,37 @@ sub read_config {
            $opt{$default} = $default{$default};
        }
     }
+
+    if ($opt{"IGNORE_UNUSED"} == 1) {
+       return;
+    }
+
+    my %not_used;
+
+    # check if there are any stragglers (typos?)
+    foreach my $option (keys %opt) {
+       my $op = $option;
+       # remove per test labels.
+       $op =~ s/\[.*\]//;
+       if (!exists($option_map{$op}) &&
+           !exists($default{$op}) &&
+           !exists($used_options{$op})) {
+           $not_used{$op} = 1;
+       }
+    }
+
+    if (%not_used) {
+       my $s = "s are";
+       $s = " is" if (keys %not_used == 1);
+       print "The following option$s not used; could be a typo:\n";
+       foreach my $option (keys %not_used) {
+           print "$option\n";
+       }
+       print "Set IGRNORE_UNUSED = 1 to have ktest ignore unused variables\n";
+       if (!read_yn "Do you want to continue?") {
+           exit -1;
+       }
+    }
 }
 
 sub __eval_option {
@@ -873,6 +1108,17 @@ sub reboot {
     }
 }
 
+sub reboot_to_good {
+    my ($time) = @_;
+
+    if (defined($switch_to_good)) {
+       run_command $switch_to_good;
+       return;
+    }
+
+    reboot $time;
+}
+
 sub do_not_reboot {
     my $i = $iteration;
 
@@ -889,7 +1135,7 @@ sub dodie {
     if ($reboot_on_error && !do_not_reboot) {
 
        doprint "REBOOTING\n";
-       reboot;
+       reboot_to_good;
 
     } elsif ($poweroff_on_error && defined($power_off)) {
        doprint "POWERING OFF\n";
@@ -975,6 +1221,43 @@ sub wait_for_monitor {
     print "** Monitor flushed **\n";
 }
 
+sub save_logs {
+       my ($result, $basedir) = @_;
+       my @t = localtime;
+       my $date = sprintf "%04d%02d%02d%02d%02d%02d",
+               1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0];
+
+       my $type = $build_type;
+       if ($type =~ /useconfig/) {
+           $type = "useconfig";
+       }
+
+       my $dir = "$machine-$test_type-$type-$result-$date";
+
+       $dir = "$basedir/$dir";
+
+       if (!-d $dir) {
+           mkpath($dir) or
+               die "can't create $dir";
+       }
+
+       my %files = (
+               "config" => $output_config,
+               "buildlog" => $buildlog,
+               "dmesg" => $dmesg,
+               "testlog" => $testlog,
+       );
+
+       while (my ($name, $source) = each(%files)) {
+               if (-f "$source") {
+                       cp "$source", "$dir/$name" or
+                               die "failed to copy $source";
+               }
+       }
+
+       doprint "*** Saved info to $dir ***\n";
+}
+
 sub fail {
 
        if ($die_on_failure) {
@@ -988,7 +1271,7 @@ sub fail {
        # no need to reboot for just building.
        if (!do_not_reboot) {
            doprint "REBOOTING\n";
-           reboot $sleep_time;
+           reboot_to_good $sleep_time;
        }
 
        my $name = "";
@@ -1003,38 +1286,9 @@ sub fail {
        doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
        doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
 
-       return 1 if (!defined($store_failures));
-
-       my @t = localtime;
-       my $date = sprintf "%04d%02d%02d%02d%02d%02d",
-               1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0];
-
-       my $type = $build_type;
-       if ($type =~ /useconfig/) {
-           $type = "useconfig";
-       }
-
-       my $dir = "$machine-$test_type-$type-fail-$date";
-       my $faildir = "$store_failures/$dir";
-
-       if (!-d $faildir) {
-           mkpath($faildir) or
-               die "can't create $faildir";
-       }
-       if (-f "$output_config") {
-           cp "$output_config", "$faildir/config" or
-               die "failed to copy .config";
-       }
-       if (-f $buildlog) {
-           cp $buildlog, "$faildir/buildlog" or
-               die "failed to move $buildlog";
-       }
-       if (-f $dmesg) {
-           cp $dmesg, "$faildir/dmesg" or
-               die "failed to move $dmesg";
-       }
-
-       doprint "*** Saved info to $faildir ***\n";
+       if (defined($store_failures)) {
+           save_logs "fail", $store_failures;
+        }
 
        return 1;
 }
@@ -1170,13 +1424,16 @@ sub wait_for_input
 }
 
 sub reboot_to {
+    if (defined($switch_to_test)) {
+       run_command $switch_to_test;
+    }
+
     if ($reboot_type eq "grub") {
        run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'";
-       reboot;
-       return;
+    } elsif (defined $reboot_script) {
+       run_command "$reboot_script";
     }
-
-    run_command "$reboot_script";
+    reboot;
 }
 
 sub get_sha1 {
@@ -1274,7 +1531,7 @@ sub monitor {
        }
 
        if ($full_line =~ /call trace:/i) {
-           if (!$bug && !$skip_call_trace) {
+           if (!$ignore_errors && !$bug && !$skip_call_trace) {
                $bug = 1;
                $failure_start = time;
            }
@@ -1341,12 +1598,19 @@ sub monitor {
     return 1;
 }
 
+sub eval_kernel_version {
+    my ($option) = @_;
+
+    $option =~ s/\$KERNEL_VERSION/$version/g;
+
+    return $option;
+}
+
 sub do_post_install {
 
     return if (!defined($post_install));
 
-    my $cp_post_install = $post_install;
-    $cp_post_install =~ s/\$KERNEL_VERSION/$version/g;
+    my $cp_post_install = eval_kernel_version $post_install;
     run_command "$cp_post_install" or
        dodie "Failed to run post install";
 }
@@ -1355,7 +1619,9 @@ sub install {
 
     return if ($no_install);
 
-    run_scp "$outputdir/$build_target", "$target_image" or
+    my $cp_target = eval_kernel_version $target_image;
+
+    run_scp "$outputdir/$build_target", "$cp_target" or
        dodie "failed to copy image";
 
     my $install_mods = 0;
@@ -1640,9 +1906,13 @@ sub success {
     doprint     "*******************************************\n";
     doprint     "*******************************************\n";
 
+    if (defined($store_successes)) {
+        save_logs "success", $store_successes;
+    }
+
     if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) {
        doprint "Reboot and wait $sleep_time seconds\n";
-       reboot $sleep_time;
+       reboot_to_good $sleep_time;
     }
 }
 
@@ -1669,7 +1939,10 @@ sub child_run_test {
     $poweroff_on_error = 0;
     $die_on_failure = 1;
 
+    $redirect = "$testlog";
     run_command $run_test or $failed = 1;
+    undef $redirect;
+
     exit $failed;
 }
 
@@ -1744,6 +2017,43 @@ sub do_run_test {
     waitpid $child_pid, 0;
     $child_exit = $?;
 
+    if (!$bug && $in_bisect) {
+       if (defined($bisect_ret_good)) {
+           if ($child_exit == $bisect_ret_good) {
+               return 1;
+           }
+       }
+       if (defined($bisect_ret_skip)) {
+           if ($child_exit == $bisect_ret_skip) {
+               return -1;
+           }
+       }
+       if (defined($bisect_ret_abort)) {
+           if ($child_exit == $bisect_ret_abort) {
+               fail "test abort" and return -2;
+           }
+       }
+       if (defined($bisect_ret_bad)) {
+           if ($child_exit == $bisect_ret_skip) {
+               return 0;
+           }
+       }
+       if (defined($bisect_ret_default)) {
+           if ($bisect_ret_default eq "good") {
+               return 1;
+           } elsif ($bisect_ret_default eq "bad") {
+               return 0;
+           } elsif ($bisect_ret_default eq "skip") {
+               return -1;
+           } elsif ($bisect_ret_default eq "abort") {
+               return -2;
+           } else {
+               fail "unknown default action: $bisect_ret_default"
+                   and return -2;
+           }
+       }
+    }
+
     if ($bug || $child_exit) {
        return 0 if $in_bisect;
        fail "test failed" and return 0;
@@ -1770,7 +2080,7 @@ sub run_git_bisect {
     if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) {
        doprint "$1 [$2]\n";
     } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) {
-       $bisect_bad = $1;
+       $bisect_bad_commit = $1;
        doprint "Found bad commit... $1\n";
        return 0;
     } else {
@@ -1783,7 +2093,7 @@ sub run_git_bisect {
 
 sub bisect_reboot {
     doprint "Reboot and sleep $bisect_sleep_time seconds\n";
-    reboot $bisect_sleep_time;
+    reboot_to_good $bisect_sleep_time;
 }
 
 # returns 1 on success, 0 on failure, -1 on skip
@@ -1868,21 +2178,28 @@ sub run_bisect {
     }
 }
 
+sub update_bisect_replay {
+    my $tmp_log = "$tmpdir/ktest_bisect_log";
+    run_command "git bisect log > $tmp_log" or
+       die "can't create bisect log";
+    return $tmp_log;
+}
+
 sub bisect {
     my ($i) = @_;
 
     my $result;
 
-    die "BISECT_GOOD[$i] not defined\n"        if (!defined($opt{"BISECT_GOOD[$i]"}));
-    die "BISECT_BAD[$i] not defined\n" if (!defined($opt{"BISECT_BAD[$i]"}));
-    die "BISECT_TYPE[$i] not defined\n"        if (!defined($opt{"BISECT_TYPE[$i]"}));
+    die "BISECT_GOOD[$i] not defined\n"        if (!defined($bisect_good));
+    die "BISECT_BAD[$i] not defined\n" if (!defined($bisect_bad));
+    die "BISECT_TYPE[$i] not defined\n"        if (!defined($bisect_type));
 
-    my $good = $opt{"BISECT_GOOD[$i]"};
-    my $bad = $opt{"BISECT_BAD[$i]"};
-    my $type = $opt{"BISECT_TYPE[$i]"};
-    my $start = $opt{"BISECT_START[$i]"};
-    my $replay = $opt{"BISECT_REPLAY[$i]"};
-    my $start_files = $opt{"BISECT_FILES[$i]"};
+    my $good = $bisect_good;
+    my $bad = $bisect_bad;
+    my $type = $bisect_type;
+    my $start = $bisect_start;
+    my $replay = $bisect_replay;
+    my $start_files = $bisect_files;
 
     if (defined($start_files)) {
        $start_files = " -- " . $start_files;
@@ -1894,8 +2211,7 @@ sub bisect {
     $good = get_sha1($good);
     $bad = get_sha1($bad);
 
-    if (defined($opt{"BISECT_REVERSE[$i]"}) &&
-       $opt{"BISECT_REVERSE[$i]"} == 1) {
+    if (defined($bisect_reverse) && $bisect_reverse == 1) {
        doprint "Performing a reverse bisect (bad is good, good is bad!)\n";
        $reverse_bisect = 1;
     } else {
@@ -1907,8 +2223,31 @@ sub bisect {
        $type = "boot";
     }
 
-    my $check = $opt{"BISECT_CHECK[$i]"};
-    if (defined($check) && $check ne "0") {
+    # Check if a bisect was running
+    my $bisect_start_file = "$builddir/.git/BISECT_START";
+
+    my $check = $bisect_check;
+    my $do_check = defined($check) && $check ne "0";
+
+    if ( -f $bisect_start_file ) {
+       print "Bisect in progress found\n";
+       if ($do_check) {
+           print " If you say yes, then no checks of good or bad will be done\n";
+       }
+       if (defined($replay)) {
+           print "** BISECT_REPLAY is defined in config file **";
+           print " Ignore config option and perform new git bisect log?\n";
+           if (read_ync " (yes, no, or cancel) ") {
+               $replay = update_bisect_replay;
+               $do_check = 0;
+           }
+       } elsif (read_yn "read git log and continue?") {
+           $replay = update_bisect_replay;
+           $do_check = 0;
+       }
+    }
+
+    if ($do_check) {
 
        # get current HEAD
        my $head = get_sha1("HEAD");
@@ -1973,7 +2312,7 @@ sub bisect {
     run_command "git bisect reset" or
        dodie "could not reset git bisect";
 
-    doprint "Bad commit was [$bisect_bad]\n";
+    doprint "Bad commit was [$bisect_bad_commit]\n";
 
     success $i;
 }
@@ -2129,7 +2468,7 @@ sub run_config_bisect {
     }
 
     doprint "***** RUN TEST ***\n";
-    my $type = $opt{"CONFIG_BISECT_TYPE[$iteration]"};
+    my $type = $config_bisect_type;
     my $ret;
     my %current_config;
 
@@ -2233,7 +2572,7 @@ sub run_config_bisect {
 sub config_bisect {
     my ($i) = @_;
 
-    my $start_config = $opt{"CONFIG_BISECT[$i]"};
+    my $start_config = $config_bisect;
 
     my $tmpconfig = "$tmpdir/use_config";
 
@@ -2346,29 +2685,29 @@ sub config_bisect {
 
 sub patchcheck_reboot {
     doprint "Reboot and sleep $patchcheck_sleep_time seconds\n";
-    reboot $patchcheck_sleep_time;
+    reboot_to_good $patchcheck_sleep_time;
 }
 
 sub patchcheck {
     my ($i) = @_;
 
     die "PATCHCHECK_START[$i] not defined\n"
-       if (!defined($opt{"PATCHCHECK_START[$i]"}));
+       if (!defined($patchcheck_start));
     die "PATCHCHECK_TYPE[$i] not defined\n"
-       if (!defined($opt{"PATCHCHECK_TYPE[$i]"}));
+       if (!defined($patchcheck_type));
 
-    my $start = $opt{"PATCHCHECK_START[$i]"};
+    my $start = $patchcheck_start;
 
     my $end = "HEAD";
-    if (defined($opt{"PATCHCHECK_END[$i]"})) {
-       $end = $opt{"PATCHCHECK_END[$i]"};
+    if (defined($patchcheck_end)) {
+       $end = $patchcheck_end;
     }
 
     # Get the true sha1's since we can use things like HEAD~3
     $start = get_sha1($start);
     $end = get_sha1($end);
 
-    my $type = $opt{"PATCHCHECK_TYPE[$i]"};
+    my $type = $patchcheck_type;
 
     # Can't have a test without having a test to run
     if ($type eq "test" && !defined($run_test)) {
@@ -2963,7 +3302,7 @@ sub make_min_config {
        }
 
        doprint "Reboot and wait $sleep_time seconds\n";
-       reboot $sleep_time;
+       reboot_to_good $sleep_time;
     }
 
     success $i;
@@ -2985,13 +3324,27 @@ if ($#ARGV == 0) {
 }
 
 if (! -f $ktest_config) {
+    $newconfig = 1;
+    get_test_case;
     open(OUT, ">$ktest_config") or die "Can not create $ktest_config";
     print OUT << "EOF"
 # Generated by ktest.pl
 #
+
+# PWD is a ktest.pl variable that will result in the process working
+# directory that ktest.pl is executed in.
+
+# THIS_DIR is automatically assigned the PWD of the path that generated
+# the config file. It is best to use this variable when assigning other
+# directory paths within this directory. This allows you to easily
+# move the test cases to other locations or to other machines.
+#
+THIS_DIR := $variable{"PWD"}
+
 # Define each test with TEST_START
 # The config options below it will override the defaults
 TEST_START
+TEST_TYPE = $default{"TEST_TYPE"}
 
 DEFAULTS
 EOF
@@ -3011,7 +3364,7 @@ if ($#new_configs >= 0) {
     open(OUT, ">>$ktest_config") or die "Can not append to $ktest_config";
     foreach my $config (@new_configs) {
        print OUT "$config = $entered_configs{$config}\n";
-       $opt{$config} = $entered_configs{$config};
+       $opt{$config} = process_variables($entered_configs{$config});
     }
 }
 
@@ -3091,61 +3444,10 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
 
     my $makecmd = set_test_option("MAKE_CMD", $i);
 
-    $machine = set_test_option("MACHINE", $i);
-    $ssh_user = set_test_option("SSH_USER", $i);
-    $tmpdir = set_test_option("TMP_DIR", $i);
-    $outputdir = set_test_option("OUTPUT_DIR", $i);
-    $builddir = set_test_option("BUILD_DIR", $i);
-    $test_type = set_test_option("TEST_TYPE", $i);
-    $build_type = set_test_option("BUILD_TYPE", $i);
-    $build_options = set_test_option("BUILD_OPTIONS", $i);
-    $pre_build = set_test_option("PRE_BUILD", $i);
-    $post_build = set_test_option("POST_BUILD", $i);
-    $pre_build_die = set_test_option("PRE_BUILD_DIE", $i);
-    $post_build_die = set_test_option("POST_BUILD_DIE", $i);
-    $power_cycle = set_test_option("POWER_CYCLE", $i);
-    $reboot = set_test_option("REBOOT", $i);
-    $noclean = set_test_option("BUILD_NOCLEAN", $i);
-    $minconfig = set_test_option("MIN_CONFIG", $i);
-    $output_minconfig = set_test_option("OUTPUT_MIN_CONFIG", $i);
-    $start_minconfig = set_test_option("START_MIN_CONFIG", $i);
-    $ignore_config = set_test_option("IGNORE_CONFIG", $i);
-    $run_test = set_test_option("TEST", $i);
-    $addconfig = set_test_option("ADD_CONFIG", $i);
-    $reboot_type = set_test_option("REBOOT_TYPE", $i);
-    $grub_menu = set_test_option("GRUB_MENU", $i);
-    $post_install = set_test_option("POST_INSTALL", $i);
-    $no_install = set_test_option("NO_INSTALL", $i);
-    $reboot_script = set_test_option("REBOOT_SCRIPT", $i);
-    $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i);
-    $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i);
-    $die_on_failure = set_test_option("DIE_ON_FAILURE", $i);
-    $power_off = set_test_option("POWER_OFF", $i);
-    $powercycle_after_reboot = set_test_option("POWERCYCLE_AFTER_REBOOT", $i);
-    $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i);
-    $sleep_time = set_test_option("SLEEP_TIME", $i);
-    $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i);
-    $patchcheck_sleep_time = set_test_option("PATCHCHECK_SLEEP_TIME", $i);
-    $ignore_warnings = set_test_option("IGNORE_WARNINGS", $i);
-    $bisect_manual = set_test_option("BISECT_MANUAL", $i);
-    $bisect_skip = set_test_option("BISECT_SKIP", $i);
-    $config_bisect_good = set_test_option("CONFIG_BISECT_GOOD", $i);
-    $store_failures = set_test_option("STORE_FAILURES", $i);
-    $test_name = set_test_option("TEST_NAME", $i);
-    $timeout = set_test_option("TIMEOUT", $i);
-    $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i);
-    $console = set_test_option("CONSOLE", $i);
-    $detect_triplefault = set_test_option("DETECT_TRIPLE_FAULT", $i);
-    $success_line = set_test_option("SUCCESS_LINE", $i);
-    $reboot_success_line = set_test_option("REBOOT_SUCCESS_LINE", $i);
-    $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i);
-    $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i);
-    $stop_test_after = set_test_option("STOP_TEST_AFTER", $i);
-    $build_target = set_test_option("BUILD_TARGET", $i);
-    $ssh_exec = set_test_option("SSH_EXEC", $i);
-    $scp_to_target = set_test_option("SCP_TO_TARGET", $i);
-    $target_image = set_test_option("TARGET_IMAGE", $i);
-    $localversion = set_test_option("LOCALVERSION", $i);
+    # Load all the options into their mapped variable names
+    foreach my $opt (keys %option_map) {
+       ${$option_map{$opt}} = set_test_option($opt, $i);
+    }
 
     $start_minconfig_defined = 1;
 
@@ -3166,26 +3468,26 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
     $ENV{"SSH_USER"} = $ssh_user;
     $ENV{"MACHINE"} = $machine;
 
-    $target = "$ssh_user\@$machine";
-
     $buildlog = "$tmpdir/buildlog-$machine";
+    $testlog = "$tmpdir/testlog-$machine";
     $dmesg = "$tmpdir/dmesg-$machine";
     $make = "$makecmd O=$outputdir";
     $output_config = "$outputdir/.config";
 
-    if ($reboot_type eq "grub") {
-       dodie "GRUB_MENU not defined" if (!defined($grub_menu));
-    } elsif (!defined($reboot_script)) {
-       dodie "REBOOT_SCRIPT not defined"
+    if (!$buildonly) {
+       $target = "$ssh_user\@$machine";
+       if ($reboot_type eq "grub") {
+           dodie "GRUB_MENU not defined" if (!defined($grub_menu));
+       }
     }
 
     my $run_type = $build_type;
     if ($test_type eq "patchcheck") {
-       $run_type = $opt{"PATCHCHECK_TYPE[$i]"};
+       $run_type = $patchcheck_type;
     } elsif ($test_type eq "bisect") {
-       $run_type = $opt{"BISECT_TYPE[$i]"};
+       $run_type = $bisect_type;
     } elsif ($test_type eq "config_bisect") {
-       $run_type = $opt{"CONFIG_BISECT_TYPE[$i]"};
+       $run_type = $config_bisect_type;
     }
 
     if ($test_type eq "make_min_config") {
@@ -3205,6 +3507,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
 
     unlink $dmesg;
     unlink $buildlog;
+    unlink $testlog;
 
     if (defined($addconfig)) {
        my $min = $minconfig;
@@ -3216,7 +3519,6 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
        $minconfig = "$tmpdir/add_config";
     }
 
-    my $checkout = $opt{"CHECKOUT[$i]"};
     if (defined($checkout)) {
        run_command "git checkout $checkout" or
            die "failed to checkout $checkout";
@@ -3267,7 +3569,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
 if ($opt{"POWEROFF_ON_SUCCESS"}) {
     halt;
 } elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot) {
-    reboot;
+    reboot_to_good;
 }
 
 doprint "\n    $successes of $opt{NUM_TESTS} tests were successful\n\n";
index 553c06b7d6f27ad8e72f8e8e943321271099a237..5ea04c6a71bfc830feca1c10c144264ba97a5db3 100644 (file)
 #GRUB_MENU = Test Kernel
 
 # A script to reboot the target into the test kernel
-# (Only mandatory if REBOOT_TYPE = script)
+# This and SWITCH_TO_TEST are about the same, except
+# SWITCH_TO_TEST is run even for REBOOT_TYPE = grub.
+# This may be left undefined.
+# (default undefined)
 #REBOOT_SCRIPT =
 
 #### Optional Config Options (all have defaults) ####
 # The test will not modify that file.
 #REBOOT_TYPE = grub
 
+# If you are using a machine that doesn't boot with grub, and
+# perhaps gets its kernel from a remote server (tftp), then
+# you can use this option to update the target image with the
+# test image.
+#
+# You could also do the same with POST_INSTALL, but the difference
+# between that option and this option is that POST_INSTALL runs
+# after the install, where this one runs just before a reboot.
+# (default undefined)
+#SWITCH_TO_TEST = cp ${OUTPUT_DIR}/${BUILD_TARGET} ${TARGET_IMAGE}
+
+# If you are using a machine that doesn't boot with grub, and
+# perhaps gets its kernel from a remote server (tftp), then
+# you can use this option to update the target image with the
+# the known good image to reboot safely back into.
+#
+# This option holds a command that will execute before needing
+# to reboot to a good known image.
+# (default undefined)
+#SWITCH_TO_GOOD = ssh ${SSH_USER}/${MACHINE} cp good_image ${TARGET_IMAGE}
+
 # The min config that is needed to build for the machine
 # A nice way to create this is with the following:
 #
 # (default undefined)
 #STORE_FAILURES = /home/test/failures
 
+# Directory to store success directories on success. If this is not
+# set, the .config, dmesg and bootlog will not be saved if a
+# test succeeds.
+# (default undefined)
+#STORE_SUCCESSES = /home/test/successes
+
 # Build without doing a make mrproper, or removing .config
 # (default 0)
 #BUILD_NOCLEAN = 0
 # (default 1)
 #DETECT_TRIPLE_FAULT = 0
 
+# All options in the config file should be either used by ktest
+# or could be used within a value of another option. If an option
+# in the config file is not used, ktest will warn about it and ask
+# if you want to continue.
+#
+# If you don't care if there are non-used options, enable this
+# option. Be careful though, a non-used option is usually a sign
+# of an option name being typed incorrectly.
+# (default 0)
+#IGNORE_UNUSED = 1
+
+# When testing a kernel that happens to have WARNINGs, and call
+# traces, ktest.pl will detect these and fail a boot or test run
+# due to warnings. By setting this option, ktest will ignore
+# call traces, and will not fail a test if the kernel produces
+# an oops. Use this option with care.
+# (default 0)
+#IGNORE_ERRORS = 1
+
 #### Per test run options ####
 # The following options are only allowed in TEST_START sections.
 # They are ignored in the DEFAULTS sections.
 #   BISECT_BAD with BISECT_CHECK = good or
 #   BISECT_CHECK = bad, respectively.
 #
+# BISECT_RET_GOOD = 0 (optional, default undefined)
+#
+#   In case the specificed test returns something other than just
+#   0 for good, and non-zero for bad, you can override 0 being
+#   good by defining BISECT_RET_GOOD.
+#
+# BISECT_RET_BAD = 1 (optional, default undefined)
+#
+#   In case the specificed test returns something other than just
+#   0 for good, and non-zero for bad, you can override non-zero being
+#   bad by defining BISECT_RET_BAD.
+#
+# BISECT_RET_ABORT = 255 (optional, default undefined)
+#
+#   If you need to abort the bisect if the test discovers something
+#   that was wrong, you can define BISECT_RET_ABORT to be the error
+#   code returned by the test in order to abort the bisect.
+#
+# BISECT_RET_SKIP = 2 (optional, default undefined)
+#
+#   If the test detects that the current commit is neither good
+#   nor bad, but something else happened (another bug detected)
+#   you can specify BISECT_RET_SKIP to an error code that the
+#   test returns when it should skip the current commit.
+#
+# BISECT_RET_DEFAULT = good (optional, default undefined)
+#
+#   You can override the default of what to do when the above
+#   options are not hit. This may be one of, "good", "bad",
+#   "abort" or "skip" (without the quotes).
+#
+#   Note, if you do not define any of the previous BISECT_RET_*
+#   and define BISECT_RET_DEFAULT, all bisects results will do
+#   what the BISECT_RET_DEFAULT has.
+#
+#
 # Example:
 #   TEST_START
 #   TEST_TYPE = bisect
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
new file mode 100644 (file)
index 0000000..4ec8401
--- /dev/null
@@ -0,0 +1,11 @@
+TARGETS = breakpoints
+
+all:
+       for TARGET in $(TARGETS); do \
+               make -C $$TARGET; \
+       done;
+
+clean:
+       for TARGET in $(TARGETS); do \
+               make -C $$TARGET clean; \
+       done;
diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile
new file mode 100644 (file)
index 0000000..f362722
--- /dev/null
@@ -0,0 +1,20 @@
+# Taken from perf makefile
+uname_M := $(shell uname -m 2>/dev/null || echo not)
+ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
+ifeq ($(ARCH),i386)
+        ARCH := x86
+endif
+ifeq ($(ARCH),x86_64)
+       ARCH := x86
+endif
+
+
+all:
+ifeq ($(ARCH),x86)
+       gcc breakpoint_test.c -o run_test
+else
+       echo "Not an x86 target, can't build breakpoints selftests"
+endif
+
+clean:
+       rm -fr run_test
diff --git a/tools/testing/selftests/breakpoints/breakpoint_test.c b/tools/testing/selftests/breakpoints/breakpoint_test.c
new file mode 100644 (file)
index 0000000..a0743f3
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
+ *
+ * Licensed under the terms of the GNU GPL License version 2
+ *
+ * Selftests for breakpoints (and more generally the do_debug() path) in x86.
+ */
+
+
+#include <sys/ptrace.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/user.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+
+/* Breakpoint access modes */
+enum {
+       BP_X = 1,
+       BP_RW = 2,
+       BP_W = 4,
+};
+
+static pid_t child_pid;
+
+/*
+ * Ensures the child and parent are always "talking" about
+ * the same test sequence. (ie: that we haven't forgotten
+ * to call check_trapped() somewhere).
+ */
+static int nr_tests;
+
+static void set_breakpoint_addr(void *addr, int n)
+{
+       int ret;
+
+       ret = ptrace(PTRACE_POKEUSER, child_pid,
+                    offsetof(struct user, u_debugreg[n]), addr);
+       if (ret) {
+               perror("Can't set breakpoint addr\n");
+               exit(-1);
+       }
+}
+
+static void toggle_breakpoint(int n, int type, int len,
+                             int local, int global, int set)
+{
+       int ret;
+
+       int xtype, xlen;
+       unsigned long vdr7, dr7;
+
+       switch (type) {
+       case BP_X:
+               xtype = 0;
+               break;
+       case BP_W:
+               xtype = 1;
+               break;
+       case BP_RW:
+               xtype = 3;
+               break;
+       }
+
+       switch (len) {
+       case 1:
+               xlen = 0;
+               break;
+       case 2:
+               xlen = 4;
+               break;
+       case 4:
+               xlen = 0xc;
+               break;
+       case 8:
+               xlen = 8;
+               break;
+       }
+
+       dr7 = ptrace(PTRACE_PEEKUSER, child_pid,
+                    offsetof(struct user, u_debugreg[7]), 0);
+
+       vdr7 = (xlen | xtype) << 16;
+       vdr7 <<= 4 * n;
+
+       if (local) {
+               vdr7 |= 1 << (2 * n);
+               vdr7 |= 1 << 8;
+       }
+       if (global) {
+               vdr7 |= 2 << (2 * n);
+               vdr7 |= 1 << 9;
+       }
+
+       if (set)
+               dr7 |= vdr7;
+       else
+               dr7 &= ~vdr7;
+
+       ret = ptrace(PTRACE_POKEUSER, child_pid,
+                    offsetof(struct user, u_debugreg[7]), dr7);
+       if (ret) {
+               perror("Can't set dr7");
+               exit(-1);
+       }
+}
+
+/* Dummy variables to test read/write accesses */
+static unsigned long long dummy_var[4];
+
+/* Dummy functions to test execution accesses */
+static void dummy_func(void) { }
+static void dummy_func1(void) { }
+static void dummy_func2(void) { }
+static void dummy_func3(void) { }
+
+static void (*dummy_funcs[])(void) = {
+       dummy_func,
+       dummy_func1,
+       dummy_func2,
+       dummy_func3,
+};
+
+static int trapped;
+
+static void check_trapped(void)
+{
+       /*
+        * If we haven't trapped, wake up the parent
+        * so that it notices the failure.
+        */
+       if (!trapped)
+               kill(getpid(), SIGUSR1);
+       trapped = 0;
+
+       nr_tests++;
+}
+
+static void write_var(int len)
+{
+       char *pcval; short *psval; int *pival; long long *plval;
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               switch (len) {
+               case 1:
+                       pcval = (char *)&dummy_var[i];
+                       *pcval = 0xff;
+                       break;
+               case 2:
+                       psval = (short *)&dummy_var[i];
+                       *psval = 0xffff;
+                       break;
+               case 4:
+                       pival = (int *)&dummy_var[i];
+                       *pival = 0xffffffff;
+                       break;
+               case 8:
+                       plval = (long long *)&dummy_var[i];
+                       *plval = 0xffffffffffffffffLL;
+                       break;
+               }
+               check_trapped();
+       }
+}
+
+static void read_var(int len)
+{
+       char cval; short sval; int ival; long long lval;
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               switch (len) {
+               case 1:
+                       cval = *(char *)&dummy_var[i];
+                       break;
+               case 2:
+                       sval = *(short *)&dummy_var[i];
+                       break;
+               case 4:
+                       ival = *(int *)&dummy_var[i];
+                       break;
+               case 8:
+                       lval = *(long long *)&dummy_var[i];
+                       break;
+               }
+               check_trapped();
+       }
+}
+
+/*
+ * Do the r/w/x accesses to trigger the breakpoints. And run
+ * the usual traps.
+ */
+static void trigger_tests(void)
+{
+       int len, local, global, i;
+       char val;
+       int ret;
+
+       ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
+       if (ret) {
+               perror("Can't be traced?\n");
+               return;
+       }
+
+       /* Wake up father so that it sets up the first test */
+       kill(getpid(), SIGUSR1);
+
+       /* Test instruction breakpoints */
+       for (local = 0; local < 2; local++) {
+               for (global = 0; global < 2; global++) {
+                       if (!local && !global)
+                               continue;
+
+                       for (i = 0; i < 4; i++) {
+                               dummy_funcs[i]();
+                               check_trapped();
+                       }
+               }
+       }
+
+       /* Test write watchpoints */
+       for (len = 1; len <= sizeof(long); len <<= 1) {
+               for (local = 0; local < 2; local++) {
+                       for (global = 0; global < 2; global++) {
+                               if (!local && !global)
+                                       continue;
+                               write_var(len);
+                       }
+               }
+       }
+
+       /* Test read/write watchpoints (on read accesses) */
+       for (len = 1; len <= sizeof(long); len <<= 1) {
+               for (local = 0; local < 2; local++) {
+                       for (global = 0; global < 2; global++) {
+                               if (!local && !global)
+                                       continue;
+                               read_var(len);
+                       }
+               }
+       }
+
+       /* Icebp trap */
+       asm(".byte 0xf1\n");
+       check_trapped();
+
+       /* Int 3 trap */
+       asm("int $3\n");
+       check_trapped();
+
+       kill(getpid(), SIGUSR1);
+}
+
+static void check_success(const char *msg)
+{
+       const char *msg2;
+       int child_nr_tests;
+       int status;
+
+       /* Wait for the child to SIGTRAP */
+       wait(&status);
+
+       msg2 = "Failed";
+
+       if (WSTOPSIG(status) == SIGTRAP) {
+               child_nr_tests = ptrace(PTRACE_PEEKDATA, child_pid,
+                                       &nr_tests, 0);
+               if (child_nr_tests == nr_tests)
+                       msg2 = "Ok";
+               if (ptrace(PTRACE_POKEDATA, child_pid, &trapped, 1)) {
+                       perror("Can't poke\n");
+                       exit(-1);
+               }
+       }
+
+       nr_tests++;
+
+       printf("%s [%s]\n", msg, msg2);
+}
+
+static void launch_instruction_breakpoints(char *buf, int local, int global)
+{
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               set_breakpoint_addr(dummy_funcs[i], i);
+               toggle_breakpoint(i, BP_X, 1, local, global, 1);
+               ptrace(PTRACE_CONT, child_pid, NULL, 0);
+               sprintf(buf, "Test breakpoint %d with local: %d global: %d",
+                       i, local, global);
+               check_success(buf);
+               toggle_breakpoint(i, BP_X, 1, local, global, 0);
+       }
+}
+
+static void launch_watchpoints(char *buf, int mode, int len,
+                              int local, int global)
+{
+       const char *mode_str;
+       int i;
+
+       if (mode == BP_W)
+               mode_str = "write";
+       else
+               mode_str = "read";
+
+       for (i = 0; i < 4; i++) {
+               set_breakpoint_addr(&dummy_var[i], i);
+               toggle_breakpoint(i, mode, len, local, global, 1);
+               ptrace(PTRACE_CONT, child_pid, NULL, 0);
+               sprintf(buf, "Test %s watchpoint %d with len: %d local: "
+                       "%d global: %d", mode_str, i, len, local, global);
+               check_success(buf);
+               toggle_breakpoint(i, mode, len, local, global, 0);
+       }
+}
+
+/* Set the breakpoints and check the child successfully trigger them */
+static void launch_tests(void)
+{
+       char buf[1024];
+       int len, local, global, i;
+
+       /* Instruction breakpoints */
+       for (local = 0; local < 2; local++) {
+               for (global = 0; global < 2; global++) {
+                       if (!local && !global)
+                               continue;
+                       launch_instruction_breakpoints(buf, local, global);
+               }
+       }
+
+       /* Write watchpoint */
+       for (len = 1; len <= sizeof(long); len <<= 1) {
+               for (local = 0; local < 2; local++) {
+                       for (global = 0; global < 2; global++) {
+                               if (!local && !global)
+                                       continue;
+                               launch_watchpoints(buf, BP_W, len,
+                                                  local, global);
+                       }
+               }
+       }
+
+       /* Read-Write watchpoint */
+       for (len = 1; len <= sizeof(long); len <<= 1) {
+               for (local = 0; local < 2; local++) {
+                       for (global = 0; global < 2; global++) {
+                               if (!local && !global)
+                                       continue;
+                               launch_watchpoints(buf, BP_RW, len,
+                                                  local, global);
+                       }
+               }
+       }
+
+       /* Icebp traps */
+       ptrace(PTRACE_CONT, child_pid, NULL, 0);
+       check_success("Test icebp");
+
+       /* Int 3 traps */
+       ptrace(PTRACE_CONT, child_pid, NULL, 0);
+       check_success("Test int 3 trap");
+
+       ptrace(PTRACE_CONT, child_pid, NULL, 0);
+}
+
+int main(int argc, char **argv)
+{
+       pid_t pid;
+       int ret;
+
+       pid = fork();
+       if (!pid) {
+               trigger_tests();
+               return 0;
+       }
+
+       child_pid = pid;
+
+       wait(NULL);
+
+       launch_tests();
+
+       wait(NULL);
+
+       return 0;
+}
diff --git a/tools/testing/selftests/run_tests b/tools/testing/selftests/run_tests
new file mode 100644 (file)
index 0000000..320718a
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+TARGETS=breakpoints
+
+for TARGET in $TARGETS
+do
+       $TARGET/run_test
+done
index 669bcdd45805a7039473d1acd425effd6d77797c..b4fbc91c41b47dd4ab2a06157594c32b14bdd2aa 100644 (file)
@@ -186,21 +186,12 @@ struct virtqueue {
 #endif
 
 /* Interfaces exported by virtio_ring. */
-int virtqueue_add_buf_gfp(struct virtqueue *vq,
-                         struct scatterlist sg[],
-                         unsigned int out_num,
-                         unsigned int in_num,
-                         void *data,
-                         gfp_t gfp);
-
-static inline int virtqueue_add_buf(struct virtqueue *vq,
-                                   struct scatterlist sg[],
-                                   unsigned int out_num,
-                                   unsigned int in_num,
-                                   void *data)
-{
-       return virtqueue_add_buf_gfp(vq, sg, out_num, in_num, data, GFP_ATOMIC);
-}
+int virtqueue_add_buf(struct virtqueue *vq,
+                     struct scatterlist sg[],
+                     unsigned int out_num,
+                     unsigned int in_num,
+                     void *data,
+                     gfp_t gfp);
 
 void virtqueue_kick(struct virtqueue *vq);
 
@@ -214,6 +205,7 @@ void *virtqueue_detach_unused_buf(struct virtqueue *vq);
 struct virtqueue *vring_new_virtqueue(unsigned int num,
                                      unsigned int vring_align,
                                      struct virtio_device *vdev,
+                                     bool weak_barriers,
                                      void *pages,
                                      void (*notify)(struct virtqueue *vq),
                                      void (*callback)(struct virtqueue *vq),
index 74d3331bdaf992b10bdf38d630d0dca00cc08360..6bf95f9953640c4671f94be6316383dabb9c5bc8 100644 (file)
@@ -92,7 +92,8 @@ static void vq_info_add(struct vdev_info *dev, int num)
        assert(r >= 0);
        memset(info->ring, 0, vring_size(num, 4096));
        vring_init(&info->vring, num, info->ring, 4096);
-       info->vq = vring_new_virtqueue(info->vring.num, 4096, &dev->vdev, info->ring,
+       info->vq = vring_new_virtqueue(info->vring.num, 4096, &dev->vdev,
+                                      true, info->ring,
                                       vq_notify, vq_callback, "test");
        assert(info->vq);
        info->vq->priv = info;
@@ -160,7 +161,8 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, int bufs)
                        if (started < bufs) {
                                sg_init_one(&sl, dev->buf, dev->buf_size);
                                r = virtqueue_add_buf(vq->vq, &sl, 1, 0,
-                                                     dev->buf + started);
+                                                     dev->buf + started,
+                                                     GFP_ATOMIC);
                                if (likely(r >= 0)) {
                                        ++started;
                                        virtqueue_kick(vq->vq);
index 0fb448e6a1a33288694e78ae764540df7e7a80bb..a457d2138f49ac8ed860507de8c9068566368889 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/iommu.h>
 #include <linux/intel-iommu.h>
 
-static int allow_unsafe_assigned_interrupts;
+static bool allow_unsafe_assigned_interrupts;
 module_param_named(allow_unsafe_assigned_interrupts,
                   allow_unsafe_assigned_interrupts, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(allow_unsafe_assigned_interrupts,